mirror of https://github.com/freetype/freetype
[autofit] Implement vertical separation adjustment.
* src/autofit/aflatin.c: Include `afadjust.h`. (af_latin_metrics_init): Call `af_reverse_character_map_new`. (af_latin_metrics_done): New function. (af_move_contour_vertically, af_check_contour_horizontal_overlap, af_glyph_hints_apply_vertical_separation_adjustments): New functions. (af_latin_hints_apply): Call `af_glyph_hints_apply_vertical_separation_adjustments`. (af_latin_writing_system_class): Updated. * src/autofit/aftypes.h (AF_StyleMetricsRec): Add `reverse_charmap` field.
This commit is contained in:
parent
c70b3d9484
commit
1e5e193adb
|
@ -22,6 +22,7 @@
|
|||
#include "afglobal.h"
|
||||
#include "aflatin.h"
|
||||
#include "aferrors.h"
|
||||
#include "afadjust.h"
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -1155,6 +1156,9 @@
|
|||
af_latin_metrics_check_digits( metrics, face );
|
||||
}
|
||||
|
||||
af_reverse_character_map_new( &metrics->root.reverse_charmap,
|
||||
metrics->root.globals );
|
||||
|
||||
Exit:
|
||||
face->charmap = oldmap;
|
||||
return error;
|
||||
|
@ -1484,6 +1488,17 @@
|
|||
}
|
||||
|
||||
|
||||
FT_CALLBACK_DEF( void )
|
||||
af_latin_metrics_done( AF_StyleMetrics metrics_ )
|
||||
{
|
||||
AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
|
||||
|
||||
|
||||
af_reverse_character_map_done( metrics->root.reverse_charmap,
|
||||
metrics->root.globals->face->memory );
|
||||
}
|
||||
|
||||
|
||||
/* Scale global values in both directions. */
|
||||
|
||||
FT_LOCAL_DEF( void )
|
||||
|
@ -2737,6 +2752,304 @@
|
|||
}
|
||||
|
||||
|
||||
#undef FT_COMPONENT
|
||||
#define FT_COMPONENT afadjust
|
||||
|
||||
|
||||
static void
|
||||
af_move_contour_vertically( AF_Point contour,
|
||||
FT_Int movement )
|
||||
{
|
||||
AF_Point point = contour;
|
||||
AF_Point first_point = point;
|
||||
|
||||
|
||||
if ( point )
|
||||
{
|
||||
do
|
||||
{
|
||||
point->y += movement;
|
||||
point = point->next;
|
||||
|
||||
} while ( point != first_point );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return 1 if the given contour overlaps horizontally with the bounding */
|
||||
/* box of all other contours combined. This is a helper for function */
|
||||
/* `af_glyph_hints_apply_vertical_separation_adjustments`. */
|
||||
static FT_Bool
|
||||
af_check_contour_horizontal_overlap( AF_GlyphHints hints,
|
||||
FT_Int contour_index )
|
||||
{
|
||||
FT_Pos contour_max_x = -32000;
|
||||
FT_Pos contour_min_x = 32000;
|
||||
FT_Pos others_max_x = -32000;
|
||||
FT_Pos others_min_x = 32000;
|
||||
|
||||
FT_Int contour;
|
||||
|
||||
FT_Bool horizontal_overlap;
|
||||
|
||||
|
||||
for ( contour = 0; contour < hints->num_contours; contour++ )
|
||||
{
|
||||
AF_Point first_point = hints->contours[contour];
|
||||
AF_Point p = first_point;
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
p = p->next;
|
||||
|
||||
if ( contour == contour_index )
|
||||
{
|
||||
if ( p->x < contour_min_x )
|
||||
contour_min_x = p->x;
|
||||
if ( p->x > contour_max_x )
|
||||
contour_max_x = p->x;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( p->x < others_min_x )
|
||||
others_min_x = p->x;
|
||||
if ( p->x > others_max_x )
|
||||
others_max_x = p->x;
|
||||
}
|
||||
} while ( p != first_point );
|
||||
}
|
||||
|
||||
horizontal_overlap =
|
||||
( others_min_x <= contour_max_x && contour_max_x <= others_max_x ) ||
|
||||
( others_min_x <= contour_min_x && contour_min_x <= others_max_x ) ||
|
||||
( contour_max_x >= others_max_x && contour_min_x <= others_min_x );
|
||||
|
||||
return horizontal_overlap;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
af_glyph_hints_apply_vertical_separation_adjustments(
|
||||
AF_GlyphHints hints,
|
||||
AF_Dimension dim,
|
||||
FT_Int glyph_index,
|
||||
AF_ReverseCharacterMap reverse_charmap )
|
||||
{
|
||||
FT_TRACE4(( "Entering"
|
||||
" af_glyph_hints_apply_vertical_separation_adjustments\n" ));
|
||||
|
||||
if ( dim != AF_DIMENSION_VERT )
|
||||
return;
|
||||
|
||||
if ( af_lookup_vertical_separation_type( reverse_charmap,
|
||||
glyph_index ) ==
|
||||
AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP &&
|
||||
hints->num_contours >= 2 )
|
||||
{
|
||||
FT_Int highest_contour = -1;
|
||||
FT_Pos highest_min_y = 0;
|
||||
FT_Pos current_min_y = 0;
|
||||
|
||||
FT_Int contour;
|
||||
FT_Bool horizontal_overlap;
|
||||
FT_Int adjustment_amount;
|
||||
|
||||
FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
|
||||
" Applying vertical adjustment:"
|
||||
" AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP\n" ));
|
||||
|
||||
/* Figure out which contour is the higher one by finding the one */
|
||||
/* with the highest minimum y value. */
|
||||
for ( contour = 0; contour < hints->num_contours; contour++ )
|
||||
{
|
||||
AF_Point point = hints->contours[contour];
|
||||
AF_Point first_point = point;
|
||||
|
||||
|
||||
if ( !point )
|
||||
continue;
|
||||
|
||||
current_min_y = point->y;
|
||||
|
||||
do
|
||||
{
|
||||
if ( point->y < current_min_y )
|
||||
current_min_y = point->y;
|
||||
point = point->next;
|
||||
|
||||
} while ( point != first_point );
|
||||
|
||||
if ( highest_contour == -1 || current_min_y > highest_min_y )
|
||||
{
|
||||
highest_min_y = current_min_y;
|
||||
highest_contour = contour;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for a horizontal overlap between the top contour and the */
|
||||
/* rest. If there is no overlap, do not adjust. */
|
||||
horizontal_overlap =
|
||||
af_check_contour_horizontal_overlap( hints, highest_contour );
|
||||
if ( !horizontal_overlap )
|
||||
{
|
||||
FT_TRACE4(( " Top contour does not horizontally overlap"
|
||||
" with other contours.\n"
|
||||
" Skipping adjustment.\n" ));
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there are any contours that have a maximum y coordinate */
|
||||
/* greater than or equal to the minimum y coordinate of the */
|
||||
/* previously found highest contour, bump the high contour up until */
|
||||
/* the distance is one pixel. */
|
||||
adjustment_amount = 0;
|
||||
|
||||
for ( contour = 0; contour < hints->num_contours; contour++ )
|
||||
{
|
||||
AF_Point point;
|
||||
AF_Point first_point;
|
||||
|
||||
FT_Pos max_y;
|
||||
|
||||
|
||||
if ( contour == highest_contour )
|
||||
continue;
|
||||
|
||||
point = hints->contours[contour];
|
||||
first_point = point;
|
||||
if ( !point )
|
||||
continue;
|
||||
|
||||
max_y = point->y;
|
||||
do
|
||||
{
|
||||
if ( point->y > max_y )
|
||||
max_y = point->y;
|
||||
point = point->next;
|
||||
|
||||
} while ( point != first_point );
|
||||
|
||||
if ( max_y >= highest_min_y - 64 )
|
||||
adjustment_amount = 64 - ( highest_min_y - max_y );
|
||||
}
|
||||
|
||||
if ( adjustment_amount > 64 )
|
||||
FT_TRACE4(( " Calculated adjustment amount %d"
|
||||
" was more than threshold of 64. Not adjusting\n",
|
||||
adjustment_amount ));
|
||||
else if ( adjustment_amount > 0 )
|
||||
{
|
||||
FT_TRACE4(( " Pushing top contour %d units up\n",
|
||||
adjustment_amount ));
|
||||
|
||||
af_move_contour_vertically( hints->contours[highest_contour],
|
||||
adjustment_amount );
|
||||
}
|
||||
}
|
||||
|
||||
else if ( af_lookup_vertical_separation_type( reverse_charmap,
|
||||
glyph_index ) ==
|
||||
AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN &&
|
||||
hints->num_contours >= 2 )
|
||||
{
|
||||
FT_Int lowest_contour = -1;
|
||||
FT_Pos lowest_max_y = 0;
|
||||
FT_Pos current_max_y = 0;
|
||||
|
||||
FT_Int contour;
|
||||
FT_Int adjustment_amount;
|
||||
|
||||
|
||||
FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
|
||||
" Applying vertical adjustment:"
|
||||
" AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN\n" ));
|
||||
|
||||
/* Find lowest contour. */
|
||||
for ( contour = 0; contour < hints->num_contours; contour++ )
|
||||
{
|
||||
AF_Point point = hints->contours[contour];
|
||||
AF_Point first_point = point;
|
||||
|
||||
|
||||
if ( !point )
|
||||
continue;
|
||||
|
||||
current_max_y = point->y;
|
||||
|
||||
do
|
||||
{
|
||||
if ( point->y > current_max_y )
|
||||
current_max_y = point->y;
|
||||
point = point->next;
|
||||
|
||||
} while ( point != first_point );
|
||||
|
||||
if ( lowest_contour == -1 || current_max_y < lowest_max_y )
|
||||
{
|
||||
lowest_max_y = current_max_y;
|
||||
lowest_contour = contour;
|
||||
}
|
||||
}
|
||||
|
||||
adjustment_amount = 0;
|
||||
|
||||
for ( contour = 0; contour < hints->num_contours; contour++ )
|
||||
{
|
||||
AF_Point point;
|
||||
AF_Point first_point;
|
||||
|
||||
FT_Pos min_y;
|
||||
|
||||
|
||||
if ( contour == lowest_contour )
|
||||
continue;
|
||||
|
||||
point = hints->contours[contour];
|
||||
first_point = point;
|
||||
if ( !point )
|
||||
continue;
|
||||
|
||||
min_y = point->y;
|
||||
do
|
||||
{
|
||||
if ( point->y < min_y )
|
||||
min_y = point->y;
|
||||
point = point->next;
|
||||
|
||||
} while ( point != first_point );
|
||||
|
||||
if ( min_y <= lowest_max_y - 64 )
|
||||
adjustment_amount = 64 - ( min_y - lowest_max_y );
|
||||
}
|
||||
|
||||
if ( adjustment_amount > 64 )
|
||||
FT_TRACE4(( " Calculated adjustment amount %d"
|
||||
" was more than threshold of 64. Not adjusting\n",
|
||||
adjustment_amount ));
|
||||
else if ( adjustment_amount > 0 )
|
||||
{
|
||||
FT_TRACE4(( " Pushing bottom contour %d units down\n",
|
||||
adjustment_amount ));
|
||||
|
||||
af_move_contour_vertically( hints->contours[lowest_contour],
|
||||
-adjustment_amount );
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
|
||||
" No vertical adjustment needed\n" ));
|
||||
|
||||
FT_TRACE4(( "Exiting"
|
||||
" af_glyph_hints_apply_vertical_separation_adjustments\n" ));
|
||||
}
|
||||
|
||||
|
||||
#undef FT_COMPONENT
|
||||
#define FT_COMPONENT aflatin
|
||||
|
||||
|
||||
/* Compute the snapped width of a given stem, ignoring very thin ones. */
|
||||
/* There is a lot of voodoo in this function; changing the hard-coded */
|
||||
/* parameters influence the whole hinting process. */
|
||||
|
@ -3604,6 +3917,11 @@
|
|||
af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim );
|
||||
af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
|
||||
af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
|
||||
af_glyph_hints_apply_vertical_separation_adjustments(
|
||||
hints,
|
||||
(AF_Dimension)dim,
|
||||
glyph_index,
|
||||
metrics->root.reverse_charmap );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3632,7 +3950,7 @@
|
|||
|
||||
(AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init, /* style_metrics_init */
|
||||
(AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale, /* style_metrics_scale */
|
||||
(AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */
|
||||
(AF_WritingSystem_DoneMetricsFunc) af_latin_metrics_done, /* style_metrics_done */
|
||||
(AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths, /* style_metrics_getstdw */
|
||||
|
||||
(AF_WritingSystem_InitHintsFunc) af_latin_hints_init, /* style_hints_init */
|
||||
|
|
|
@ -439,6 +439,8 @@ extern void* af_debug_hints_;
|
|||
|
||||
AF_FaceGlobals globals; /* to access properties */
|
||||
|
||||
AF_ReverseCharacterMap reverse_charmap;
|
||||
|
||||
} AF_StyleMetricsRec;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue