From 6f9faffcd6cb87c63c29d8d6cbaf87f44e33eb99 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Thu, 2 Oct 2014 22:48:37 +0200 Subject: [PATCH] Make one-point segments have an optional width. We extend `TA_Point' with two fields to hold those values. This also introduces a new error value `TA_Err_Control_Invalid_Offset'. --- doc/ttfautohint-1.pandoc | 2 +- lib/tacontrol.bison | 68 +++++++++++++++++++++++++++++++++++++++++++----- lib/tacontrol.c | 55 +++++++++++++++++++++++++++++---------- lib/tacontrol.flex | 2 +- lib/tacontrol.h | 21 ++++++++------- lib/tahints.c | 7 ++++- lib/tahints.h | 3 +++ lib/talatin.c | 5 ++-- lib/ttfautohint-errors.h | 16 +++++++----- lib/ttfautohint.h | 37 ++++++++++++++++---------- 10 files changed, 160 insertions(+), 56 deletions(-) diff --git a/doc/ttfautohint-1.pandoc b/doc/ttfautohint-1.pandoc index 12cfdd4..2fe0c5e 100644 --- a/doc/ttfautohint-1.pandoc +++ b/doc/ttfautohint-1.pandoc @@ -539,7 +539,7 @@ bytecode larger. Parameter '`p`' makes ttfautohint apply delta exceptions for the given points, shifting the points by the given values. Note that those delta - exceptions are applied *after* the final `IP` instructions in the + exceptions are applied *after* the final `IUP` instructions in the bytecode; as a consequence, they are (partially) ignored by rasterizers if in ClearType mode. diff --git a/lib/tacontrol.bison b/lib/tacontrol.bison index a9ef049..c7ff6d9 100644 --- a/lib/tacontrol.bison +++ b/lib/tacontrol.bison @@ -59,6 +59,7 @@ } %{ +#include #include "tacontrol-flex.h" void @@ -94,6 +95,7 @@ store_error_data(const YYLTYPE *locp, %type left_limited %type none_dir_set %type number_set +%type offset %type point_set %type ppem_set %type range @@ -103,6 +105,7 @@ store_error_data(const YYLTYPE *locp, %type right_dir_set %type right_limited %type shift +%type signed_integer %type unlimited %type x_shift %type y_shift @@ -185,6 +188,21 @@ entry: YYABORT; } } +| font_idx glyph_idx left_dir_set '(' offset[left] ',' offset[right] ')' EOE + { + $entry = TA_control_new(Control_Segment_Left, + $font_idx, + $glyph_idx, + $left_dir_set, + $left, + $right, + NULL); + if (!$entry) + { + store_error_data(&@$, context, TA_Err_Control_Allocation_Error); + YYABORT; + } + } | font_idx glyph_idx right_dir_set EOE { $entry = TA_control_new(Control_Segment_Right, @@ -200,6 +218,21 @@ entry: YYABORT; } } +| font_idx glyph_idx right_dir_set '(' offset[left] ',' offset[right] ')' EOE + { + $entry = TA_control_new(Control_Segment_Right, + $font_idx, + $glyph_idx, + $right_dir_set, + $left, + $right, + NULL); + if (!$entry) + { + store_error_data(&@$, context, TA_Err_Control_Allocation_Error); + YYABORT; + } + } | font_idx glyph_idx none_dir_set EOE { $entry = TA_control_new(Control_Segment_None, @@ -469,6 +502,18 @@ shift: } ; +offset: + signed_integer + { + if ($signed_integer < SHRT_MIN || $signed_integer > SHRT_MAX) + { + store_error_data(&@$, context, TA_Err_Control_Invalid_Offset); + YYABORT; + } + $offset = $signed_integer; + } +; + ppem_set: '@' { @@ -495,9 +540,18 @@ integer: } ; -real[result]: +signed_integer: integer - { $result = $integer; } + { $signed_integer = $integer; } +| '+' integer + { $signed_integer = $integer; } +| '-' integer + { $signed_integer = -$integer; } +; + +real: + signed_integer + { $real = $signed_integer; } | REAL { if (context->error) @@ -507,12 +561,12 @@ real[result]: YYABORT; } - $result = $REAL; + $real = $REAL; } -| '+' real[unsigned] - { $result = $unsigned; } -| '-' real[unsigned] - { $result = -$unsigned; } +| '+' REAL + { $real = $REAL; } +| '-' REAL + { $real = -$REAL; } ; number_set: diff --git a/lib/tacontrol.c b/lib/tacontrol.c index 0286109..61dc4dc 100644 --- a/lib/tacontrol.c +++ b/lib/tacontrol.c @@ -15,6 +15,7 @@ #include "ta.h" #include +#include #include #include #include @@ -50,14 +51,19 @@ TA_control_new(Control_Type type, case Control_Delta_before_IUP: case Control_Delta_after_IUP: /* we round shift values to multiples of 1/(2^CONTROL_DELTA_SHIFT) */ - control->x_shift = (char)(x_shift * CONTROL_DELTA_FACTOR - + (x_shift > 0 ? 0.5 : -0.5)); - control->y_shift = (char)(y_shift * CONTROL_DELTA_FACTOR - + (y_shift > 0 ? 0.5 : -0.5)); + control->x_shift = (int)(x_shift * CONTROL_DELTA_FACTOR + + (x_shift > 0 ? 0.5 : -0.5)); + control->y_shift = (int)(y_shift * CONTROL_DELTA_FACTOR + + (y_shift > 0 ? 0.5 : -0.5)); break; case Control_Segment_Left: case Control_Segment_Right: + /* offsets */ + control->x_shift = x_shift; + control->y_shift = y_shift; + break; + case Control_Segment_None: control->x_shift = 0; control->y_shift = 0; @@ -187,23 +193,35 @@ control_show_line(FONT* font, case Control_Segment_Left: case Control_Segment_Right: - case Control_Segment_None: /* display glyph index if we don't have a glyph name */ if (*glyph_name_buf) s = sdscatprintf(s, "%ld %s %c %s", control->font_idx, glyph_name_buf, - control->type == Control_Segment_Left ? 'l' - : control->type == Control_Segment_Right ? 'r' - : 'n', + control->type == Control_Segment_Left ? 'l' : 'r', points_buf); else s = sdscatprintf(s, "%ld %ld %c %s", control->font_idx, control->glyph_idx, - control->type == Control_Segment_Left ? 'l' - : control->type == Control_Segment_Right ? 'r' - : 'n', + control->type == Control_Segment_Left ? 'l' : 'r', + points_buf); + + if (control->x_shift || control->y_shift) + s = sdscatprintf(s, " (%d,%d)", control->x_shift, control->y_shift); + break; + + case Control_Segment_None: + /* display glyph index if we don't have a glyph name */ + if (*glyph_name_buf) + s = sdscatprintf(s, "%ld %s n %s", + control->font_idx, + glyph_name_buf, + points_buf); + else + s = sdscatprintf(s, "%ld %ld n %s", + control->font_idx, + control->glyph_idx, points_buf); break; } @@ -359,6 +377,10 @@ Fail: sprintf(auxbuf, " (valid interval is [%g;%g])", CONTROL_DELTA_SHIFT_MIN, CONTROL_DELTA_SHIFT_MAX); + else if (context.error == TA_Err_Control_Invalid_Offset) + sprintf(auxbuf, " (valid interval is [%d;%d])", + SHRT_MIN, + SHRT_MAX); else if (context.error == TA_Err_Control_Invalid_Range) sprintf(auxbuf, " (values must be within [%ld;%ld])", context.number_set_min, @@ -497,8 +519,8 @@ TA_control_build_tree(FONT* font) Control_Type type = control->type; long font_idx = control->font_idx; long glyph_idx = control->glyph_idx; - char x_shift = control->x_shift; - char y_shift = control->y_shift; + int x_shift = control->x_shift; + int y_shift = control->y_shift; number_set_iter ppems_iter; int ppem; @@ -507,6 +529,7 @@ TA_control_build_tree(FONT* font) ppems_iter.range = control->ppems; ppem = number_set_get_first(&ppems_iter); + /* ppem is always zero for one-point segments */ if (type == Control_Segment_Left || type == Control_Segment_Right || type == Control_Segment_None) @@ -704,7 +727,9 @@ TA_control_segment_dir_collect(FONT* font, int TA_control_segment_dir_get_next(FONT* font, int* point_idx, - TA_Direction* dir) + TA_Direction* dir, + int* left_offset, + int* right_offset) { Control* control_segment_dirs_head = (Control*)font->control_segment_dirs_head; Control* control_segment_dirs_cur = (Control*)font->control_segment_dirs_cur; @@ -727,6 +752,8 @@ TA_control_segment_dir_get_next(FONT* font, : control_segment_dirs_cur->type == Control_Segment_Right ? TA_DIR_RIGHT : TA_DIR_NONE; + *left_offset = control_segment_dirs_cur->x_shift; + *right_offset = control_segment_dirs_cur->y_shift; font->control_segment_dirs_cur = control_segment_dirs_cur->next; diff --git a/lib/tacontrol.flex b/lib/tacontrol.flex index a60f3bd..5f1dcb1 100644 --- a/lib/tacontrol.flex +++ b/lib/tacontrol.flex @@ -164,7 +164,7 @@ TA_control_scanner_fatal_error(const char* msg, } -(?x: [lnprxy@,] +(?x: [lnprxy@,()] ) { /* delimiters */ return yytext[0]; diff --git a/lib/tacontrol.h b/lib/tacontrol.h index b323c07..f3b3b86 100644 --- a/lib/tacontrol.h +++ b/lib/tacontrol.h @@ -70,7 +70,8 @@ typedef enum Control_Type_ * gets allocated by a successful call to `TA_control_parse_buffer'. Use * `TA_control_free' to deallocate the list. * - * `x_shift' and `y_shift' are always in the range [-8;8]. + * `x_shift' and `y_shift' are in the range [-8;8] for delta exceptions + * and in the range [SHRT_MIN;SHRT_MAX] for one-point segment offsets. * * The `Control' typedef is in `ta.h'. */ @@ -82,8 +83,8 @@ struct Control_ long font_idx; long glyph_idx; number_range* points; - char x_shift; - char y_shift; + int x_shift; + int y_shift; number_range* ppems; struct Control_* next; @@ -103,8 +104,8 @@ typedef struct Ctrl_ int ppem; int point_idx; - char x_shift; - char y_shift; + int x_shift; + int y_shift; } Ctrl; @@ -316,7 +317,7 @@ TA_control_get_ctrl(FONT* font); /* - * Collect one-point segment directions and store them in + * Collect one-point segment data for a given glyph index and store them in * `font->control_segment_dirs'. */ @@ -326,15 +327,17 @@ TA_control_segment_dir_collect(FONT* font, long glyph_idx); /* - * Access next one-point segment direction. Returns 1 on success or 0 if no - * more data. In the latter case, it resets the internal iterator so that + * Access next one-point segment data. Returns 1 on success or 0 if no more + * data. In the latter case, it resets the internal iterator so that * calling this function another time starts at the beginning again. */ int TA_control_segment_dir_get_next(FONT* font, int* point_idx, - TA_Direction* dir); + TA_Direction* dir, + int* left_offset, + int* right_offset); #ifdef __cplusplus diff --git a/lib/tahints.c b/lib/tahints.c index 5cd3712..d52a63a 100644 --- a/lib/tahints.c +++ b/lib/tahints.c @@ -888,6 +888,8 @@ ta_glyph_hints_reload(TA_GlyphHints hints, FONT* font; FT_Int idx; TA_Direction dir; + int left_offset; + int right_offset; /* `globals' is not set up while initializing metrics, */ @@ -898,7 +900,8 @@ ta_glyph_hints_reload(TA_GlyphHints hints, font = hints->metrics->globals->font; /* start conditions are set with `TA_control_segment_dir_collect' */ - while (TA_control_segment_dir_get_next(font, &idx, &dir)) + while (TA_control_segment_dir_get_next(font, &idx, &dir, + &left_offset, &right_offset)) { TA_Point point = &points[idx]; @@ -908,6 +911,8 @@ ta_glyph_hints_reload(TA_GlyphHints hints, point->flags |= TA_FLAG_WEAK_INTERPOLATION; else point->flags &= ~TA_FLAG_WEAK_INTERPOLATION; + point->left_offset = (FT_Short)left_offset; + point->right_offset = (FT_Short)right_offset; } } diff --git a/lib/tahints.h b/lib/tahints.h index b0f5901..3bfa95d 100644 --- a/lib/tahints.h +++ b/lib/tahints.h @@ -244,6 +244,9 @@ typedef struct TA_PointRec_ FT_Pos x, y; /* current position */ FT_Pos u, v; /* current (x,y) or (y,x) depending on context */ + FT_Short left_offset; /* left offset in one-point segments */ + FT_Short right_offset; /* right offset in one-point segments */ + TA_Point next; /* next point in contour */ TA_Point prev; /* previous point in contour */ } TA_PointRec; diff --git a/lib/talatin.c b/lib/talatin.c index caa0ae1..3cce63a 100644 --- a/lib/talatin.c +++ b/lib/talatin.c @@ -1384,8 +1384,9 @@ ta_latin_hints_compute_segments(TA_GlyphHints hints, if (point->flags & TA_FLAG_CONTROL) segment->flags |= TA_EDGE_ROUND; - segment->min_coord = (FT_Short)point->v; - segment->max_coord = (FT_Short)point->v; + /* artificially extend the horizontal size if requested */ + segment->min_coord = (FT_Short)point->v + point->left_offset; + segment->max_coord = (FT_Short)point->v + point->right_offset; segment->height = 0; on_edge = 0; diff --git a/lib/ttfautohint-errors.h b/lib/ttfautohint-errors.h index 8547221..557bec9 100644 --- a/lib/ttfautohint-errors.h +++ b/lib/ttfautohint-errors.h @@ -95,19 +95,21 @@ TA_ERRORDEF_(Control_Invalid_Character, 0x205, "invalid character") TA_ERRORDEF_(Control_Invalid_Shift, 0x206, "invalid shift") -TA_ERRORDEF_(Control_Invalid_Range, 0x207, +TA_ERRORDEF_(Control_Invalid_Offset, 0x207, + "invalid offset") +TA_ERRORDEF_(Control_Invalid_Range, 0x208, "invalid range") -TA_ERRORDEF_(Control_Invalid_Glyph, 0x208, +TA_ERRORDEF_(Control_Invalid_Glyph, 0x209, "invalid glyph") -TA_ERRORDEF_(Control_Overflow, 0x209, +TA_ERRORDEF_(Control_Overflow, 0x20A, "overflow") -TA_ERRORDEF_(Control_Overlapping_Ranges, 0x20A, +TA_ERRORDEF_(Control_Overlapping_Ranges, 0x20B, "overlapping ranges") -TA_ERRORDEF_(Control_Ranges_Not_Ascending, 0x20B, +TA_ERRORDEF_(Control_Ranges_Not_Ascending, 0x20C, "ranges not ascending") -TA_ERRORDEF_(Control_Allocation_Error, 0x20C, +TA_ERRORDEF_(Control_Allocation_Error, 0x20D, "allocation error") -TA_ERRORDEF_(Control_Flex_Error, 0x20D, +TA_ERRORDEF_(Control_Flex_Error, 0x20E, "internal flex error") #ifdef TA_ERROR_END_LIST diff --git a/lib/ttfautohint.h b/lib/ttfautohint.h index 0f9b10c..43b9d1e 100644 --- a/lib/ttfautohint.h +++ b/lib/ttfautohint.h @@ -256,7 +256,8 @@ typedef int * An entry in a control instructions file or buffer has one of the * following syntax forms: * - * > *\[* font-idx *\]*\ \ glyph-id\ \ *`l`|`r`|`n`* points\ + * > *\[* font-idx *\]*\ \ glyph-id\ \ *`l`|`r`* points\ \ *\[* *`(`* left-offset *`,`* right-offset *`)`* *\]*\ + * > *\[* font-idx *\]*\ \ glyph-id\ \ *`n`* points\ * > *\[* font-idx *\]*\ \ glyph-id\ \ *`p`* points\ \ *\[* *`x`* x-shift *\]*\ \ *\[* *`y`* y-shift *\]*\ \ *`@`* ppems * * *font-idx* gives the index of the font in a TrueType Collection. If @@ -272,22 +273,30 @@ typedef int * can be specified in decimal, octal, or hexadecimal format, the latter * two indicated by the prefixes `0` and `0x`, respectively. * - * The mutually exclusive parameters '`l`', '`r`', or\ '`n`' indicate - * that the following points have left, right, or no direction, - * respectively, overriding ttfautohint's algorithm for setting point - * directions. The 'direction of a point' is the direction of the - * outline controlled by this point. By changing a point's direction - * from 'no direction' to either left or right, you can create a - * one-point segment with the given direction so that ttfautohint - * handles the point similar to other segments. Setting a point's - * direction to 'no direction', ttfautohint no longer considers it as - * part of a segment, thus treating it as a 'weak' point. Changed point - * directions don't directly modify the outlines; they only influence - * the hinting process. + * The mutually exclusive parameters '`l`' and '`r`' indicate that the + * following points have left or right 'out' direction, respectively, + * overriding ttfautohint's algorithm for setting point directions. The + * 'out direction' of a point is the direction of the outline *leaving* + * the point (or passing the control point). If the specified direction + * is identical to what ttfautohint computes, nothing special happens. + * Otherwise, a one-point segment with the specified direction gets + * created. By default, its length is zero. Setting *left-offset* and + * *right-offset*, you can change the segment's horizontal start and end + * position relative to the point position. *left-offset* and + * *right-offset* are integers measured in font units. + * + * Parameter '`n`' sets the 'out' direction of the following points to + * 'no direction'. If the specified direction is identical to what + * ttfautohint computes, nothing special happens. Otherwise, + * ttfautohint no longer considers those points as part of horizontal + * segments, thus treating them as 'weak' points. + * + * Modifying or adding segments don't directly modify the outlines; it + * only influences the hinting process. * * Parameter '`p`' makes ttfautohint apply delta exceptions for the * given points, shifting the points by the given values. Note that - * those delta exceptions are applied *after* the final `IP` + * those delta exceptions are applied *after* the final `IUP` * instructions in the bytecode; as a consequence, they are (partially) * ignored by rasterizers if in ClearType mode. * -- 2.11.4.GIT