Add code to properly scale glyphs not handled by the autohinter.
[ttfautohint.git] / src / tahints.c
blob81b3e3096caeea2df3629fd1dc45b56993ea08bc
1 /* tahints.c */
3 /* originally file `afhints.c' (2011-Mar-28) from FreeType */
5 /* heavily modified 2011 by Werner Lemberg <wl@gnu.org> */
7 #include <string.h>
8 #include <stdlib.h>
9 #include "tahints.h"
12 /* get new segment for given axis */
14 FT_Error
15 ta_axis_hints_new_segment(TA_AxisHints axis,
16 TA_Segment* asegment)
18 FT_Error error = FT_Err_Ok;
19 TA_Segment segment = NULL;
22 if (axis->num_segments >= axis->max_segments)
24 TA_Segment segments_new;
26 FT_Int old_max = axis->max_segments;
27 FT_Int new_max = old_max;
28 FT_Int big_max = (FT_Int)(FT_INT_MAX / sizeof (*segment));
31 if (old_max >= big_max)
33 error = FT_Err_Out_Of_Memory;
34 goto Exit;
37 new_max += (new_max >> 2) + 4;
38 if (new_max < old_max
39 || new_max > big_max)
40 new_max = big_max;
42 segments_new = (TA_Segment)realloc(axis->segments,
43 new_max * sizeof (TA_SegmentRec));
44 if (!segments_new)
45 return FT_Err_Out_Of_Memory;
47 axis->segments = segments_new;
48 axis->max_segments = new_max;
51 segment = axis->segments + axis->num_segments++;
53 Exit:
54 *asegment = segment;
55 return error;
59 /* get new edge for given axis, direction, and position */
61 FT_Error
62 ta_axis_hints_new_edge(TA_AxisHints axis,
63 FT_Int fpos,
64 TA_Direction dir,
65 TA_Edge* anedge)
67 FT_Error error = FT_Err_Ok;
68 TA_Edge edge = NULL;
69 TA_Edge edges;
72 if (axis->num_edges >= axis->max_edges)
74 TA_Edge edges_new;
76 FT_Int old_max = axis->max_edges;
77 FT_Int new_max = old_max;
78 FT_Int big_max = (FT_Int)(FT_INT_MAX / sizeof (*edge));
81 if (old_max >= big_max)
83 error = FT_Err_Out_Of_Memory;
84 goto Exit;
87 new_max += (new_max >> 2) + 4;
88 if (new_max < old_max
89 || new_max > big_max)
90 new_max = big_max;
92 edges_new = (TA_Edge)realloc(axis->edges,
93 new_max * sizeof (TA_EdgeRec));
94 if (!edges_new)
95 return FT_Err_Out_Of_Memory;
97 axis->edges = edges_new;
98 axis->max_edges = new_max;
101 edges = axis->edges;
102 edge = edges + axis->num_edges;
104 while (edge > edges)
106 if (edge[-1].fpos < fpos)
107 break;
109 /* we want the edge with same position and minor direction */
110 /* to appear before those in the major one in the list */
111 if (edge[-1].fpos == fpos
112 && dir == axis->major_dir)
113 break;
115 edge[0] = edge[-1];
116 edge--;
119 axis->num_edges++;
121 memset(edge, 0, sizeof (TA_EdgeRec));
122 edge->fpos = (FT_Short)fpos;
123 edge->dir = (FT_Char)dir;
125 Exit:
126 *anedge = edge;
127 return error;
131 #ifdef TA_DEBUG
133 #include <stdlib.h>
135 static const char*
136 ta_dir_str(TA_Direction dir)
138 const char* result;
141 switch (dir)
143 case TA_DIR_UP:
144 result = "up";
145 break;
146 case TA_DIR_DOWN:
147 result = "down";
148 break;
149 case TA_DIR_LEFT:
150 result = "left";
151 break;
152 case TA_DIR_RIGHT:
153 result = "right";
154 break;
155 default:
156 result = "none";
159 return result;
163 #define TA_INDEX_NUM(ptr, base) \
164 ((ptr) ? ((ptr) - (base)) \
165 : -1)
168 void
169 ta_glyph_hints_dump_points(TA_GlyphHints hints)
171 TA_Point points = hints->points;
172 TA_Point limit = points + hints->num_points;
173 TA_Point point;
176 printf("Table of points:\n");
177 printf(" [ index | xorg | yorg | xscale | yscale"
178 " | xfit | yfit | flags ]\n");
180 for (point = points; point < limit; point++)
182 printf(" [ %5d | %5d | %5d | %6.2f | %6.2f"
183 " | %5.2f | %5.2f | %c%c%c%c%c%c ]\n",
184 point - points,
185 point->fx,
186 point->fy,
187 point->ox / 64.0,
188 point->oy / 64.0,
189 point->x / 64.0,
190 point->y / 64.0,
191 (point->flags & TA_FLAG_WEAK_INTERPOLATION) ? 'w' : ' ',
192 (point->flags & TA_FLAG_INFLECTION) ? 'i' : ' ',
193 (point->flags & TA_FLAG_EXTREMA_X) ? '<' : ' ',
194 (point->flags & TA_FLAG_EXTREMA_Y) ? 'v' : ' ',
195 (point->flags & TA_FLAG_ROUND_X) ? '(' : ' ',
196 (point->flags & TA_FLAG_ROUND_Y) ? 'u' : ' ');
198 printf("\n");
202 static const char*
203 ta_edge_flags_to_string(FT_Byte flags)
205 static char temp[32];
206 int pos = 0;
209 if (flags & TA_EDGE_ROUND)
211 memcpy(temp + pos, "round", 5);
212 pos += 5;
214 if (flags & TA_EDGE_SERIF)
216 if (pos > 0)
217 temp[pos++] = ' ';
218 memcpy(temp + pos, "serif", 5);
219 pos += 5;
221 if (pos == 0)
222 return "normal";
224 temp[pos] = '\0';
226 return temp;
230 /* dump the array of linked segments */
232 void
233 ta_glyph_hints_dump_segments(TA_GlyphHints hints)
235 FT_Int dimension;
238 for (dimension = 1; dimension >= 0; dimension--)
240 TA_AxisHints axis = &hints->axis[dimension];
241 TA_Point points = hints->points;
242 TA_Edge edges = axis->edges;
243 TA_Segment segments = axis->segments;
244 TA_Segment limit = segments + axis->num_segments;
245 TA_Segment seg;
248 printf("Table of %s segments:\n",
249 dimension == TA_DIMENSION_HORZ ? "vertical"
250 : "horizontal");
251 printf(" [ index | pos | dir | from | to | link | serif | edge |"
252 " height | extra | flags ]\n");
254 for (seg = segments; seg < limit; seg++)
256 printf(" [ %5d | %5.2g | %5s | %4d | %4d | %4d | %5d | %4d |"
257 " %6d | %5d | %11s ]\n",
258 seg - segments,
259 dimension == TA_DIMENSION_HORZ ? (int)seg->first->ox / 64.0
260 : (int)seg->first->oy / 64.0,
261 ta_dir_str((TA_Direction)seg->dir),
262 TA_INDEX_NUM(seg->first, points),
263 TA_INDEX_NUM(seg->last, points),
264 TA_INDEX_NUM(seg->link, segments),
265 TA_INDEX_NUM(seg->serif, segments),
266 TA_INDEX_NUM(seg->edge, edges),
267 seg->height,
268 seg->height - (seg->max_coord - seg->min_coord),
269 ta_edge_flags_to_string(seg->flags));
271 printf("\n");
276 /* dump the array of linked edges */
278 void
279 ta_glyph_hints_dump_edges(TA_GlyphHints hints)
281 FT_Int dimension;
284 for (dimension = 1; dimension >= 0; dimension--)
286 TA_AxisHints axis = &hints->axis[dimension];
287 TA_Edge edges = axis->edges;
288 TA_Edge limit = edges + axis->num_edges;
289 TA_Edge edge;
292 /* note that TA_DIMENSION_HORZ corresponds to _vertical_ edges */
293 /* since they have a constant X coordinate */
294 printf("Table of %s edges:\n",
295 dimension == TA_DIMENSION_HORZ ? "vertical"
296 : "horizontal");
297 printf(" [ index | pos | dir | link |"
298 " serif | blue | opos | pos | flags ]\n");
300 for (edge = edges; edge < limit; edge++)
302 printf(" [ %5d | %5.2g | %5s | %4d |"
303 " %5d | %c | %5.2f | %5.2f | %11s ]\n",
304 edge - edges,
305 (int)edge->opos / 64.0,
306 ta_dir_str((TA_Direction)edge->dir),
307 TA_INDEX_NUM(edge->link, edges),
308 TA_INDEX_NUM(edge->serif, edges),
309 edge->blue_edge ? 'y' : 'n',
310 edge->opos / 64.0,
311 edge->pos / 64.0,
312 ta_edge_flags_to_string(edge->flags));
314 printf("\n");
319 void
320 ta_glyph_hints_dump_edge_links(TA_GlyphHints hints)
322 FT_Int dimension;
325 for (dimension = 1; dimension >= 0; dimension--)
327 TA_AxisHints axis = &hints->axis[dimension];
328 TA_Segment segments = axis->segments;
329 TA_Edge edges = axis->edges;
330 TA_Edge limit = edges + axis->num_edges;
332 TA_Edge edge;
333 TA_Segment seg;
336 printf("%s edges consist of the following segments:\n",
337 dimension == TA_DIMENSION_HORZ ? "Vertical"
338 : "Horizontal");
339 for (edge = edges; edge < limit; edge++)
341 printf(" %2d:", edge - edges);
343 seg = edge->first;
346 printf(" %d", seg - segments);
347 seg = seg->edge_next;
348 } while (seg != edge->first);
350 printf("\n");
352 printf("\n");
356 #endif /* TA_DEBUG */
359 /* compute the direction value of a given vector */
361 TA_Direction
362 ta_direction_compute(FT_Pos dx,
363 FT_Pos dy)
365 FT_Pos ll, ss; /* long and short arm lengths */
366 TA_Direction dir; /* candidate direction */
369 if (dy >= dx)
371 if (dy >= -dx)
373 dir = TA_DIR_UP;
374 ll = dy;
375 ss = dx;
377 else
379 dir = TA_DIR_LEFT;
380 ll = -dx;
381 ss = dy;
384 else /* dy < dx */
386 if (dy >= -dx)
388 dir = TA_DIR_RIGHT;
389 ll = dx;
390 ss = dy;
392 else
394 dir = TA_DIR_DOWN;
395 ll = dy;
396 ss = dx;
400 /* return no direction if arm lengths differ too much */
401 /* (value 14 is heuristic) */
402 ss *= 14;
403 if (TA_ABS(ll) <= TA_ABS(ss))
404 dir = TA_DIR_NONE;
406 return dir;
410 void
411 ta_glyph_hints_init(TA_GlyphHints hints)
413 memset(hints, 0, sizeof (TA_GlyphHintsRec));
417 void
418 ta_glyph_hints_done(TA_GlyphHints hints)
420 int dim;
423 if (!hints)
424 return;
426 /* we don't need to free the segment and edge buffers */
427 /* since they are really within the hints->points array */
428 for (dim = 0; dim < TA_DIMENSION_MAX; dim++)
430 TA_AxisHints axis = &hints->axis[dim];
433 axis->num_segments = 0;
434 axis->max_segments = 0;
435 free(axis->segments);
436 axis->segments = NULL;
438 axis->num_edges = 0;
439 axis->max_edges = 0;
440 free(axis->edges);
441 axis->edges = NULL;
444 free(hints->contours);
445 hints->contours = NULL;
446 hints->max_contours = 0;
447 hints->num_contours = 0;
449 free(hints->points);
450 hints->points = NULL;
451 hints->num_points = 0;
452 hints->max_points = 0;
456 /* reset metrics */
458 void
459 ta_glyph_hints_rescale(TA_GlyphHints hints,
460 TA_ScriptMetrics metrics)
462 hints->metrics = metrics;
463 hints->scaler_flags = metrics->scaler.flags;
467 /* from FreeType's ftcalc.c */
469 static FT_Int
470 ta_corner_is_flat(FT_Pos in_x,
471 FT_Pos in_y,
472 FT_Pos out_x,
473 FT_Pos out_y)
475 FT_Pos ax = in_x;
476 FT_Pos ay = in_y;
478 FT_Pos d_in, d_out, d_corner;
481 if (ax < 0)
482 ax = -ax;
483 if (ay < 0)
484 ay = -ay;
485 d_in = ax + ay;
487 ax = out_x;
488 if (ax < 0)
489 ax = -ax;
490 ay = out_y;
491 if (ay < 0)
492 ay = -ay;
493 d_out = ax + ay;
495 ax = out_x + in_x;
496 if (ax < 0)
497 ax = -ax;
498 ay = out_y + in_y;
499 if (ay < 0)
500 ay = -ay;
501 d_corner = ax + ay;
503 return (d_in + d_out - d_corner) < (d_corner >> 4);
507 /* recompute all TA_Point in TA_GlyphHints */
508 /* from the definitions in a source outline */
510 FT_Error
511 ta_glyph_hints_reload(TA_GlyphHints hints,
512 FT_Outline* outline)
514 FT_Error error = FT_Err_Ok;
515 TA_Point points;
516 FT_UInt old_max, new_max;
518 FT_Fixed x_scale = hints->x_scale;
519 FT_Fixed y_scale = hints->y_scale;
520 FT_Pos x_delta = hints->x_delta;
521 FT_Pos y_delta = hints->y_delta;
524 hints->num_points = 0;
525 hints->num_contours = 0;
527 hints->axis[0].num_segments = 0;
528 hints->axis[0].num_edges = 0;
529 hints->axis[1].num_segments = 0;
530 hints->axis[1].num_edges = 0;
532 /* first of all, reallocate the contours array if necessary */
533 new_max = (FT_UInt)outline->n_contours;
534 old_max = hints->max_contours;
535 if (new_max > old_max)
537 TA_Point* contours_new;
540 new_max = (new_max + 3) & ~3; /* round up to a multiple of 4 */
542 contours_new = (TA_Point*)realloc(hints->contours,
543 new_max * sizeof (TA_Point));
544 if (!contours_new)
545 return FT_Err_Out_Of_Memory;
547 hints->contours = contours_new;
548 hints->max_contours = new_max;
551 /* reallocate the points arrays if necessary -- we reserve */
552 /* two additional point positions, used to hint metrics appropriately */
553 new_max = (FT_UInt)(outline->n_points + 2);
554 old_max = hints->max_points;
555 if (new_max > old_max)
557 TA_Point points_new;
560 new_max = (new_max + 2 + 7) & ~7; /* round up to a multiple of 8 */
562 points_new = (TA_Point)realloc(hints->points,
563 new_max * sizeof (TA_PointRec));
564 if (!points_new)
565 return FT_Err_Out_Of_Memory;
567 hints->points = points_new;
568 hints->max_points = new_max;
571 hints->num_points = outline->n_points;
572 hints->num_contours = outline->n_contours;
574 /* we can't rely on the value of `FT_Outline.flags' to know the fill */
575 /* direction used for a glyph, given that some fonts are broken */
576 /* (e.g. the Arphic ones); we thus recompute it each time we need to */
578 hints->axis[TA_DIMENSION_HORZ].major_dir = TA_DIR_UP;
579 hints->axis[TA_DIMENSION_VERT].major_dir = TA_DIR_LEFT;
581 if (FT_Outline_Get_Orientation(outline) == FT_ORIENTATION_POSTSCRIPT)
583 hints->axis[TA_DIMENSION_HORZ].major_dir = TA_DIR_DOWN;
584 hints->axis[TA_DIMENSION_VERT].major_dir = TA_DIR_RIGHT;
587 hints->x_scale = x_scale;
588 hints->y_scale = y_scale;
589 hints->x_delta = x_delta;
590 hints->y_delta = y_delta;
592 hints->xmin_delta = 0;
593 hints->xmax_delta = 0;
595 points = hints->points;
596 if (hints->num_points == 0)
597 goto Exit;
600 TA_Point point;
601 TA_Point point_limit = points + hints->num_points;
604 /* compute coordinates & Bezier flags, next and prev */
606 FT_Vector* vec = outline->points;
607 char* tag = outline->tags;
609 TA_Point end = points + outline->contours[0];
610 TA_Point prev = end;
612 FT_Int contour_index = 0;
615 for (point = points; point < point_limit; point++, vec++, tag++)
617 point->fx = (FT_Short)vec->x;
618 point->fy = (FT_Short)vec->y;
619 point->ox = point->x = FT_MulFix(vec->x, x_scale) + x_delta;
620 point->oy = point->y = FT_MulFix(vec->y, y_scale) + y_delta;
622 switch (FT_CURVE_TAG(*tag))
624 case FT_CURVE_TAG_CONIC:
625 point->flags = TA_FLAG_CONIC;
626 break;
627 case FT_CURVE_TAG_CUBIC:
628 point->flags = TA_FLAG_CUBIC;
629 break;
630 default:
631 point->flags = TA_FLAG_NONE;
634 point->prev = prev;
635 prev->next = point;
636 prev = point;
638 if (point == end)
640 if (++contour_index < outline->n_contours)
642 end = points + outline->contours[contour_index];
643 prev = end;
649 /* set up the contours array */
651 TA_Point* contour = hints->contours;
652 TA_Point* contour_limit = contour + hints->num_contours;
654 short* end = outline->contours;
655 short idx = 0;
658 for (; contour < contour_limit; contour++, end++)
660 contour[0] = points + idx;
661 idx = (short)(end[0] + 1);
665 /* compute directions of in & out vectors */
667 TA_Point first = points;
668 TA_Point prev = NULL;
670 FT_Pos in_x = 0;
671 FT_Pos in_y = 0;
673 TA_Direction in_dir = TA_DIR_NONE;
676 for (point = points; point < point_limit; point++)
678 TA_Point next;
679 FT_Pos out_x, out_y;
682 if (point == first)
684 prev = first->prev;
685 in_x = first->fx - prev->fx;
686 in_y = first->fy - prev->fy;
687 in_dir = ta_direction_compute(in_x, in_y);
688 first = prev + 1;
691 point->in_dir = (FT_Char)in_dir;
693 next = point->next;
694 out_x = next->fx - point->fx;
695 out_y = next->fy - point->fy;
697 in_dir = ta_direction_compute(out_x, out_y);
698 point->out_dir = (FT_Char)in_dir;
700 /* check for weak points */
702 if (point->flags & TA_FLAG_CONTROL)
704 Is_Weak_Point:
705 point->flags |= TA_FLAG_WEAK_INTERPOLATION;
707 else if (point->out_dir == point->in_dir)
709 if (point->out_dir != TA_DIR_NONE)
710 goto Is_Weak_Point;
712 if (ta_corner_is_flat(in_x, in_y, out_x, out_y))
713 goto Is_Weak_Point;
715 else if (point->in_dir == -point->out_dir)
716 goto Is_Weak_Point;
718 in_x = out_x;
719 in_y = out_y;
720 prev = point;
725 Exit:
726 return error;
730 /* store the hinted outline in an FT_Outline structure */
732 void
733 ta_glyph_hints_save(TA_GlyphHints hints,
734 FT_Outline* outline)
736 TA_Point point = hints->points;
737 TA_Point limit = point + hints->num_points;
739 FT_Vector* vec = outline->points;
740 char* tag = outline->tags;
743 for (; point < limit; point++, vec++, tag++)
745 vec->x = point->x;
746 vec->y = point->y;
748 if (point->flags & TA_FLAG_CONIC)
749 tag[0] = FT_CURVE_TAG_CONIC;
750 else if (point->flags & TA_FLAG_CUBIC)
751 tag[0] = FT_CURVE_TAG_CUBIC;
752 else
753 tag[0] = FT_CURVE_TAG_ON;
758 /****************************************************************
760 * EDGE POINT GRID-FITTING
762 ****************************************************************/
765 /* align all points of an edge to the same coordinate value, */
766 /* either horizontally or vertically */
768 void
769 ta_glyph_hints_align_edge_points(TA_GlyphHints hints,
770 TA_Dimension dim)
772 TA_AxisHints axis = &hints->axis[dim];
773 TA_Segment segments = axis->segments;
774 TA_Segment segment_limit = segments + axis->num_segments;
775 TA_Segment seg;
778 if (dim == TA_DIMENSION_HORZ)
780 for (seg = segments; seg < segment_limit; seg++)
782 TA_Edge edge = seg->edge;
783 TA_Point point, first, last;
786 if (edge == NULL)
787 continue;
789 first = seg->first;
790 last = seg->last;
791 point = first;
792 for (;;)
794 point->x = edge->pos;
795 point->flags |= TA_FLAG_TOUCH_X;
797 if (point == last)
798 break;
800 point = point->next;
804 else
806 for (seg = segments; seg < segment_limit; seg++)
808 TA_Edge edge = seg->edge;
809 TA_Point point, first, last;
812 if (edge == NULL)
813 continue;
815 first = seg->first;
816 last = seg->last;
817 point = first;
818 for (;;)
820 point->y = edge->pos;
821 point->flags |= TA_FLAG_TOUCH_Y;
823 if (point == last)
824 break;
826 point = point->next;
833 /****************************************************************
835 * STRONG POINT INTERPOLATION
837 ****************************************************************/
840 /* hint the strong points -- */
841 /* this is equivalent to the TrueType `IP' hinting instruction */
843 void
844 ta_glyph_hints_align_strong_points(TA_GlyphHints hints,
845 TA_Dimension dim)
847 TA_Point points = hints->points;
848 TA_Point point_limit = points + hints->num_points;
850 TA_AxisHints axis = &hints->axis[dim];
852 TA_Edge edges = axis->edges;
853 TA_Edge edge_limit = edges + axis->num_edges;
855 FT_UShort touch_flag;
858 if (dim == TA_DIMENSION_HORZ)
859 touch_flag = TA_FLAG_TOUCH_X;
860 else
861 touch_flag = TA_FLAG_TOUCH_Y;
863 if (edges < edge_limit)
865 TA_Point point;
866 TA_Edge edge;
869 for (point = points; point < point_limit; point++)
871 FT_Pos u, ou, fu; /* point position */
872 FT_Pos delta;
875 if (point->flags & touch_flag)
876 continue;
878 /* if this point is candidate to weak interpolation, we */
879 /* interpolate it after all strong points have been processed */
881 if ((point->flags & TA_FLAG_WEAK_INTERPOLATION)
882 && !(point->flags & TA_FLAG_INFLECTION))
883 continue;
885 if (dim == TA_DIMENSION_VERT)
887 u = point->fy;
888 ou = point->oy;
890 else
892 u = point->fx;
893 ou = point->ox;
896 fu = u;
898 /* is the point before the first edge? */
899 edge = edges;
900 delta = edge->fpos - u;
901 if (delta >= 0)
903 u = edge->pos - (edge->opos - ou);
905 if (hints->recorder)
906 hints->recorder(ta_ip_before, hints, dim,
907 point, NULL, NULL, NULL, NULL);
909 goto Store_Point;
912 /* is the point after the last edge? */
913 edge = edge_limit - 1;
914 delta = u - edge->fpos;
915 if (delta >= 0)
917 u = edge->pos + (ou - edge->opos);
919 if (hints->recorder)
920 hints->recorder(ta_ip_after, hints, dim,
921 point, NULL, NULL, NULL, NULL);
923 goto Store_Point;
927 FT_PtrDist min, max, mid;
928 FT_Pos fpos;
931 /* find enclosing edges */
932 min = 0;
933 max = edge_limit - edges;
935 /* for a small number of edges, a linear search is better */
936 if (max <= 8)
938 FT_PtrDist nn;
941 for (nn = 0; nn < max; nn++)
942 if (edges[nn].fpos >= u)
943 break;
945 if (edges[nn].fpos == u)
947 u = edges[nn].pos;
949 if (hints->recorder)
950 hints->recorder(ta_ip_on, hints, dim,
951 point, &edges[nn], NULL, NULL, NULL);
953 goto Store_Point;
955 min = nn;
957 else
958 while (min < max)
960 mid = (max + min) >> 1;
961 edge = edges + mid;
962 fpos = edge->fpos;
964 if (u < fpos)
965 max = mid;
966 else if (u > fpos)
967 min = mid + 1;
968 else
970 /* we are on the edge */
971 u = edge->pos;
973 if (hints->recorder)
974 hints->recorder(ta_ip_on, hints, dim,
975 point, edge, NULL, NULL, NULL);
977 goto Store_Point;
981 /* point is not on an edge */
983 TA_Edge before = edges + min - 1;
984 TA_Edge after = edges + min + 0;
987 /* assert(before && after && before != after) */
988 if (before->scale == 0)
989 before->scale = FT_DivFix(after->pos - before->pos,
990 after->fpos - before->fpos);
992 u = before->pos + FT_MulFix(fu - before->fpos,
993 before->scale);
995 if (hints->recorder)
996 hints->recorder(ta_ip_between, hints, dim,
997 point, before, after, NULL, NULL);
1001 Store_Point:
1002 /* save the point position */
1003 if (dim == TA_DIMENSION_HORZ)
1004 point->x = u;
1005 else
1006 point->y = u;
1008 point->flags |= touch_flag;
1014 /****************************************************************
1016 * WEAK POINT INTERPOLATION
1018 ****************************************************************/
1021 /* shift the original coordinates of all points between `p1' and */
1022 /* `p2' to get hinted coordinates, using the same difference as */
1023 /* given by `ref' */
1025 static void
1026 ta_iup_shift(TA_Point p1,
1027 TA_Point p2,
1028 TA_Point ref)
1030 TA_Point p;
1031 FT_Pos delta = ref->u - ref->v;
1034 if (delta == 0)
1035 return;
1037 for (p = p1; p < ref; p++)
1038 p->u = p->v + delta;
1040 for (p = ref + 1; p <= p2; p++)
1041 p->u = p->v + delta;
1045 /* interpolate the original coordinates of all points between `p1' and */
1046 /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */
1047 /* reference points; the `u' and `v' members are the current and */
1048 /* original coordinate values, respectively. */
1050 /* details can be found in the TrueType bytecode specification */
1052 static void
1053 ta_iup_interp(TA_Point p1,
1054 TA_Point p2,
1055 TA_Point ref1,
1056 TA_Point ref2)
1058 TA_Point p;
1059 FT_Pos u;
1060 FT_Pos v1 = ref1->v;
1061 FT_Pos v2 = ref2->v;
1062 FT_Pos d1 = ref1->u - v1;
1063 FT_Pos d2 = ref2->u - v2;
1066 if (p1 > p2)
1067 return;
1069 if (v1 == v2)
1071 for (p = p1; p <= p2; p++)
1073 u = p->v;
1075 if (u <= v1)
1076 u += d1;
1077 else
1078 u += d2;
1080 p->u = u;
1082 return;
1085 if (v1 < v2)
1087 for (p = p1; p <= p2; p++)
1089 u = p->v;
1091 if (u <= v1)
1092 u += d1;
1093 else if (u >= v2)
1094 u += d2;
1095 else
1096 u = ref1->u + FT_MulDiv(u - v1, ref2->u - ref1->u, v2 - v1);
1098 p->u = u;
1101 else
1103 for (p = p1; p <= p2; p++)
1105 u = p->v;
1107 if (u <= v2)
1108 u += d2;
1109 else if (u >= v1)
1110 u += d1;
1111 else
1112 u = ref1->u + FT_MulDiv(u - v1, ref2->u - ref1->u, v2 - v1);
1114 p->u = u;
1120 /* hint the weak points -- */
1121 /* this is equivalent to the TrueType `IUP' hinting instruction */
1123 void
1124 ta_glyph_hints_align_weak_points(TA_GlyphHints hints,
1125 TA_Dimension dim)
1127 TA_Point points = hints->points;
1128 TA_Point point_limit = points + hints->num_points;
1130 TA_Point* contour = hints->contours;
1131 TA_Point* contour_limit = contour + hints->num_contours;
1133 FT_UShort touch_flag;
1134 TA_Point point;
1135 TA_Point end_point;
1136 TA_Point first_point;
1139 /* pass 1: move segment points to edge positions */
1141 if (dim == TA_DIMENSION_HORZ)
1143 touch_flag = TA_FLAG_TOUCH_X;
1145 for (point = points; point < point_limit; point++)
1147 point->u = point->x;
1148 point->v = point->ox;
1151 else
1153 touch_flag = TA_FLAG_TOUCH_Y;
1155 for (point = points; point < point_limit; point++)
1157 point->u = point->y;
1158 point->v = point->oy;
1162 point = points;
1164 for (; contour < contour_limit; contour++)
1166 TA_Point first_touched, last_touched;
1169 point = *contour;
1170 end_point = point->prev;
1171 first_point = point;
1173 /* find first touched point */
1174 for (;;)
1176 if (point > end_point) /* no touched point in contour */
1177 goto NextContour;
1179 if (point->flags & touch_flag)
1180 break;
1182 point++;
1185 first_touched = point;
1186 last_touched = point;
1188 for (;;)
1190 /* skip any touched neighbours */
1191 while (point < end_point
1192 && (point[1].flags & touch_flag) != 0)
1193 point++;
1195 last_touched = point;
1197 /* find the next touched point, if any */
1198 point++;
1199 for (;;)
1201 if (point > end_point)
1202 goto EndContour;
1204 if ((point->flags & touch_flag) != 0)
1205 break;
1207 point++;
1210 /* interpolate between last_touched and point */
1211 ta_iup_interp(last_touched + 1, point - 1,
1212 last_touched, point);
1215 EndContour:
1216 /* special case: only one point was touched */
1217 if (last_touched == first_touched)
1218 ta_iup_shift(first_point, end_point, first_touched);
1220 else /* interpolate the last part */
1222 if (last_touched < end_point)
1223 ta_iup_interp(last_touched + 1, end_point,
1224 last_touched, first_touched);
1226 if (first_touched > points)
1227 ta_iup_interp(first_point, first_touched - 1,
1228 last_touched, first_touched);
1231 NextContour:
1235 /* now save the interpolated values back to x/y */
1236 if (dim == TA_DIMENSION_HORZ)
1238 for (point = points; point < point_limit; point++)
1239 point->x = point->u;
1241 else
1243 for (point = points; point < point_limit; point++)
1244 point->y = point->u;
1249 #ifdef TA_CONFIG_OPTION_USE_WARPER
1251 /* apply (small) warp scale and warp delta for given dimension */
1253 static void
1254 ta_glyph_hints_scale_dim(TA_GlyphHints hints,
1255 TA_Dimension dim,
1256 FT_Fixed scale,
1257 FT_Pos delta)
1259 TA_Point points = hints->points;
1260 TA_Point points_limit = points + hints->num_points;
1261 TA_Point point;
1264 if (dim == TA_DIMENSION_HORZ)
1266 for (point = points; point < points_limit; point++)
1267 point->x = FT_MulFix(point->fx, scale) + delta;
1269 else
1271 for (point = points; point < points_limit; point++)
1272 point->y = FT_MulFix(point->fy, scale) + delta;
1276 #endif /* TA_CONFIG_OPTION_USE_WARPER */
1278 /* end of tahints.c */