Mention GPL-only files.
[ttfautohint.git] / src / tahints.c
blob08ae1f83bf4f10dc9863d5f7a13681f245e7a2a2
1 /* tahints.c */
3 /*
4 * Copyright (C) 2011-2012 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 /* originally file `afhints.c' (2011-Mar-28) from FreeType */
18 /* heavily modified 2011 by Werner Lemberg <wl@gnu.org> */
20 #include <string.h>
21 #include <stdlib.h>
22 #include "tahints.h"
25 /* get new segment for given axis */
27 FT_Error
28 ta_axis_hints_new_segment(TA_AxisHints axis,
29 TA_Segment* asegment)
31 FT_Error error = FT_Err_Ok;
32 TA_Segment segment = NULL;
35 if (axis->num_segments >= axis->max_segments)
37 TA_Segment segments_new;
39 FT_Int old_max = axis->max_segments;
40 FT_Int new_max = old_max;
41 FT_Int big_max = (FT_Int)(FT_INT_MAX / sizeof (*segment));
44 if (old_max >= big_max)
46 error = FT_Err_Out_Of_Memory;
47 goto Exit;
50 new_max += (new_max >> 2) + 4;
51 if (new_max < old_max
52 || new_max > big_max)
53 new_max = big_max;
55 segments_new = (TA_Segment)realloc(axis->segments,
56 new_max * sizeof (TA_SegmentRec));
57 if (!segments_new)
58 return FT_Err_Out_Of_Memory;
60 axis->segments = segments_new;
61 axis->max_segments = new_max;
64 segment = axis->segments + axis->num_segments++;
66 Exit:
67 *asegment = segment;
68 return error;
72 /* get new edge for given axis, direction, and position */
74 FT_Error
75 ta_axis_hints_new_edge(TA_AxisHints axis,
76 FT_Int fpos,
77 TA_Direction dir,
78 TA_Edge* anedge)
80 FT_Error error = FT_Err_Ok;
81 TA_Edge edge = NULL;
82 TA_Edge edges;
85 if (axis->num_edges >= axis->max_edges)
87 TA_Edge edges_new;
89 FT_Int old_max = axis->max_edges;
90 FT_Int new_max = old_max;
91 FT_Int big_max = (FT_Int)(FT_INT_MAX / sizeof (*edge));
94 if (old_max >= big_max)
96 error = FT_Err_Out_Of_Memory;
97 goto Exit;
100 new_max += (new_max >> 2) + 4;
101 if (new_max < old_max
102 || new_max > big_max)
103 new_max = big_max;
105 edges_new = (TA_Edge)realloc(axis->edges,
106 new_max * sizeof (TA_EdgeRec));
107 if (!edges_new)
108 return FT_Err_Out_Of_Memory;
110 axis->edges = edges_new;
111 axis->max_edges = new_max;
114 edges = axis->edges;
115 edge = edges + axis->num_edges;
117 while (edge > edges)
119 if (edge[-1].fpos < fpos)
120 break;
122 /* we want the edge with same position and minor direction */
123 /* to appear before those in the major one in the list */
124 if (edge[-1].fpos == fpos
125 && dir == axis->major_dir)
126 break;
128 edge[0] = edge[-1];
129 edge--;
132 axis->num_edges++;
134 memset(edge, 0, sizeof (TA_EdgeRec));
135 edge->fpos = (FT_Short)fpos;
136 edge->dir = (FT_Char)dir;
138 Exit:
139 *anedge = edge;
140 return error;
144 #ifdef TA_DEBUG
146 #include <stdlib.h>
148 static const char*
149 ta_dir_str(TA_Direction dir)
151 const char* result;
154 switch (dir)
156 case TA_DIR_UP:
157 result = "up";
158 break;
159 case TA_DIR_DOWN:
160 result = "down";
161 break;
162 case TA_DIR_LEFT:
163 result = "left";
164 break;
165 case TA_DIR_RIGHT:
166 result = "right";
167 break;
168 default:
169 result = "none";
172 return result;
176 #define TA_INDEX_NUM(ptr, base) \
177 ((ptr) ? ((ptr) - (base)) \
178 : -1)
181 void
182 ta_glyph_hints_dump_points(TA_GlyphHints hints)
184 TA_Point points = hints->points;
185 TA_Point limit = points + hints->num_points;
186 TA_Point point;
189 printf("Table of points:\n");
190 printf(" [ index | xorg | yorg | xscale | yscale"
191 " | xfit | yfit | flags ]\n");
193 for (point = points; point < limit; point++)
195 printf(" [ %5d | %5d | %5d | %6.2f | %6.2f"
196 " | %5.2f | %5.2f | %c%c%c%c%c%c ]\n",
197 point - points,
198 point->fx,
199 point->fy,
200 point->ox / 64.0,
201 point->oy / 64.0,
202 point->x / 64.0,
203 point->y / 64.0,
204 (point->flags & TA_FLAG_WEAK_INTERPOLATION) ? 'w' : ' ',
205 (point->flags & TA_FLAG_INFLECTION) ? 'i' : ' ',
206 (point->flags & TA_FLAG_EXTREMA_X) ? '<' : ' ',
207 (point->flags & TA_FLAG_EXTREMA_Y) ? 'v' : ' ',
208 (point->flags & TA_FLAG_ROUND_X) ? '(' : ' ',
209 (point->flags & TA_FLAG_ROUND_Y) ? 'u' : ' ');
211 printf("\n");
215 static const char*
216 ta_edge_flags_to_string(FT_Byte flags)
218 static char temp[32];
219 int pos = 0;
222 if (flags & TA_EDGE_ROUND)
224 memcpy(temp + pos, "round", 5);
225 pos += 5;
227 if (flags & TA_EDGE_SERIF)
229 if (pos > 0)
230 temp[pos++] = ' ';
231 memcpy(temp + pos, "serif", 5);
232 pos += 5;
234 if (pos == 0)
235 return "normal";
237 temp[pos] = '\0';
239 return temp;
243 /* dump the array of linked segments */
245 void
246 ta_glyph_hints_dump_segments(TA_GlyphHints hints)
248 FT_Int dimension;
251 for (dimension = 1; dimension >= 0; dimension--)
253 TA_AxisHints axis = &hints->axis[dimension];
254 TA_Point points = hints->points;
255 TA_Edge edges = axis->edges;
256 TA_Segment segments = axis->segments;
257 TA_Segment limit = segments + axis->num_segments;
258 TA_Segment seg;
261 printf("Table of %s segments:\n",
262 dimension == TA_DIMENSION_HORZ ? "vertical"
263 : "horizontal");
264 printf(" [ index | pos | dir | from | to | link | serif | edge |"
265 " height | extra | flags ]\n");
267 for (seg = segments; seg < limit; seg++)
269 printf(" [ %5d | %5.2g | %5s | %4d | %4d | %4d | %5d | %4d |"
270 " %6d | %5d | %11s ]\n",
271 seg - segments,
272 dimension == TA_DIMENSION_HORZ ? (int)seg->first->ox / 64.0
273 : (int)seg->first->oy / 64.0,
274 ta_dir_str((TA_Direction)seg->dir),
275 TA_INDEX_NUM(seg->first, points),
276 TA_INDEX_NUM(seg->last, points),
277 TA_INDEX_NUM(seg->link, segments),
278 TA_INDEX_NUM(seg->serif, segments),
279 TA_INDEX_NUM(seg->edge, edges),
280 seg->height,
281 seg->height - (seg->max_coord - seg->min_coord),
282 ta_edge_flags_to_string(seg->flags));
284 printf("\n");
289 /* dump the array of linked edges */
291 void
292 ta_glyph_hints_dump_edges(TA_GlyphHints hints)
294 FT_Int dimension;
297 for (dimension = 1; dimension >= 0; dimension--)
299 TA_AxisHints axis = &hints->axis[dimension];
300 TA_Edge edges = axis->edges;
301 TA_Edge limit = edges + axis->num_edges;
302 TA_Edge edge;
305 /* note that TA_DIMENSION_HORZ corresponds to _vertical_ edges */
306 /* since they have a constant X coordinate */
307 printf("Table of %s edges:\n",
308 dimension == TA_DIMENSION_HORZ ? "vertical"
309 : "horizontal");
310 printf(" [ index | pos | dir | link |"
311 " serif | blue | opos | pos | flags ]\n");
313 for (edge = edges; edge < limit; edge++)
315 printf(" [ %5d | %5.2g | %5s | %4d |"
316 " %5d | %c | %5.2f | %5.2f | %11s ]\n",
317 edge - edges,
318 (int)edge->opos / 64.0,
319 ta_dir_str((TA_Direction)edge->dir),
320 TA_INDEX_NUM(edge->link, edges),
321 TA_INDEX_NUM(edge->serif, edges),
322 edge->blue_edge ? 'y' : 'n',
323 edge->opos / 64.0,
324 edge->pos / 64.0,
325 ta_edge_flags_to_string(edge->flags));
327 printf("\n");
332 void
333 ta_glyph_hints_dump_edge_links(TA_GlyphHints hints)
335 FT_Int dimension;
338 for (dimension = 1; dimension >= 0; dimension--)
340 TA_AxisHints axis = &hints->axis[dimension];
341 TA_Segment segments = axis->segments;
342 TA_Edge edges = axis->edges;
343 TA_Edge limit = edges + axis->num_edges;
345 TA_Edge edge;
346 TA_Segment seg;
349 printf("%s edges consist of the following segments:\n",
350 dimension == TA_DIMENSION_HORZ ? "Vertical"
351 : "Horizontal");
352 for (edge = edges; edge < limit; edge++)
354 printf(" %2d:", edge - edges);
356 seg = edge->first;
359 printf(" %d", seg - segments);
360 seg = seg->edge_next;
361 } while (seg != edge->first);
363 printf("\n");
365 printf("\n");
369 #endif /* TA_DEBUG */
372 /* compute the direction value of a given vector */
374 TA_Direction
375 ta_direction_compute(FT_Pos dx,
376 FT_Pos dy)
378 FT_Pos ll, ss; /* long and short arm lengths */
379 TA_Direction dir; /* candidate direction */
382 if (dy >= dx)
384 if (dy >= -dx)
386 dir = TA_DIR_UP;
387 ll = dy;
388 ss = dx;
390 else
392 dir = TA_DIR_LEFT;
393 ll = -dx;
394 ss = dy;
397 else /* dy < dx */
399 if (dy >= -dx)
401 dir = TA_DIR_RIGHT;
402 ll = dx;
403 ss = dy;
405 else
407 dir = TA_DIR_DOWN;
408 ll = dy;
409 ss = dx;
413 /* return no direction if arm lengths differ too much */
414 /* (value 14 is heuristic) */
415 ss *= 14;
416 if (TA_ABS(ll) <= TA_ABS(ss))
417 dir = TA_DIR_NONE;
419 return dir;
423 void
424 ta_glyph_hints_init(TA_GlyphHints hints)
426 memset(hints, 0, sizeof (TA_GlyphHintsRec));
430 void
431 ta_glyph_hints_done(TA_GlyphHints hints)
433 int dim;
436 if (!hints)
437 return;
439 /* we don't need to free the segment and edge buffers */
440 /* since they are really within the hints->points array */
441 for (dim = 0; dim < TA_DIMENSION_MAX; dim++)
443 TA_AxisHints axis = &hints->axis[dim];
446 axis->num_segments = 0;
447 axis->max_segments = 0;
448 free(axis->segments);
449 axis->segments = NULL;
451 axis->num_edges = 0;
452 axis->max_edges = 0;
453 free(axis->edges);
454 axis->edges = NULL;
457 free(hints->contours);
458 hints->contours = NULL;
459 hints->max_contours = 0;
460 hints->num_contours = 0;
462 free(hints->points);
463 hints->points = NULL;
464 hints->num_points = 0;
465 hints->max_points = 0;
469 /* reset metrics */
471 void
472 ta_glyph_hints_rescale(TA_GlyphHints hints,
473 TA_ScriptMetrics metrics)
475 hints->metrics = metrics;
476 hints->scaler_flags = metrics->scaler.flags;
480 /* from FreeType's ftcalc.c */
482 static FT_Int
483 ta_corner_is_flat(FT_Pos in_x,
484 FT_Pos in_y,
485 FT_Pos out_x,
486 FT_Pos out_y)
488 FT_Pos ax = in_x;
489 FT_Pos ay = in_y;
491 FT_Pos d_in, d_out, d_corner;
494 if (ax < 0)
495 ax = -ax;
496 if (ay < 0)
497 ay = -ay;
498 d_in = ax + ay;
500 ax = out_x;
501 if (ax < 0)
502 ax = -ax;
503 ay = out_y;
504 if (ay < 0)
505 ay = -ay;
506 d_out = ax + ay;
508 ax = out_x + in_x;
509 if (ax < 0)
510 ax = -ax;
511 ay = out_y + in_y;
512 if (ay < 0)
513 ay = -ay;
514 d_corner = ax + ay;
516 return (d_in + d_out - d_corner) < (d_corner >> 4);
520 /* recompute all TA_Point in TA_GlyphHints */
521 /* from the definitions in a source outline */
523 FT_Error
524 ta_glyph_hints_reload(TA_GlyphHints hints,
525 FT_Outline* outline)
527 FT_Error error = FT_Err_Ok;
528 TA_Point points;
529 FT_UInt old_max, new_max;
531 FT_Fixed x_scale = hints->x_scale;
532 FT_Fixed y_scale = hints->y_scale;
533 FT_Pos x_delta = hints->x_delta;
534 FT_Pos y_delta = hints->y_delta;
537 hints->num_points = 0;
538 hints->num_contours = 0;
540 hints->axis[0].num_segments = 0;
541 hints->axis[0].num_edges = 0;
542 hints->axis[1].num_segments = 0;
543 hints->axis[1].num_edges = 0;
545 /* first of all, reallocate the contours array if necessary */
546 new_max = (FT_UInt)outline->n_contours;
547 old_max = hints->max_contours;
548 if (new_max > old_max)
550 TA_Point* contours_new;
553 new_max = (new_max + 3) & ~3; /* round up to a multiple of 4 */
555 contours_new = (TA_Point*)realloc(hints->contours,
556 new_max * sizeof (TA_Point));
557 if (!contours_new)
558 return FT_Err_Out_Of_Memory;
560 hints->contours = contours_new;
561 hints->max_contours = new_max;
564 /* reallocate the points arrays if necessary -- we reserve */
565 /* two additional point positions, used to hint metrics appropriately */
566 new_max = (FT_UInt)(outline->n_points + 2);
567 old_max = hints->max_points;
568 if (new_max > old_max)
570 TA_Point points_new;
573 new_max = (new_max + 2 + 7) & ~7; /* round up to a multiple of 8 */
575 points_new = (TA_Point)realloc(hints->points,
576 new_max * sizeof (TA_PointRec));
577 if (!points_new)
578 return FT_Err_Out_Of_Memory;
580 hints->points = points_new;
581 hints->max_points = new_max;
584 hints->num_points = outline->n_points;
585 hints->num_contours = outline->n_contours;
587 /* we can't rely on the value of `FT_Outline.flags' to know the fill */
588 /* direction used for a glyph, given that some fonts are broken */
589 /* (e.g. the Arphic ones); we thus recompute it each time we need to */
591 hints->axis[TA_DIMENSION_HORZ].major_dir = TA_DIR_UP;
592 hints->axis[TA_DIMENSION_VERT].major_dir = TA_DIR_LEFT;
594 if (FT_Outline_Get_Orientation(outline) == FT_ORIENTATION_POSTSCRIPT)
596 hints->axis[TA_DIMENSION_HORZ].major_dir = TA_DIR_DOWN;
597 hints->axis[TA_DIMENSION_VERT].major_dir = TA_DIR_RIGHT;
600 hints->x_scale = x_scale;
601 hints->y_scale = y_scale;
602 hints->x_delta = x_delta;
603 hints->y_delta = y_delta;
605 hints->xmin_delta = 0;
606 hints->xmax_delta = 0;
608 points = hints->points;
609 if (hints->num_points == 0)
610 goto Exit;
613 TA_Point point;
614 TA_Point point_limit = points + hints->num_points;
617 /* compute coordinates & Bezier flags, next and prev */
619 FT_Vector* vec = outline->points;
620 char* tag = outline->tags;
622 TA_Point end = points + outline->contours[0];
623 TA_Point prev = end;
625 FT_Int contour_index = 0;
628 for (point = points; point < point_limit; point++, vec++, tag++)
630 point->fx = (FT_Short)vec->x;
631 point->fy = (FT_Short)vec->y;
632 point->ox = point->x = FT_MulFix(vec->x, x_scale) + x_delta;
633 point->oy = point->y = FT_MulFix(vec->y, y_scale) + y_delta;
635 switch (FT_CURVE_TAG(*tag))
637 case FT_CURVE_TAG_CONIC:
638 point->flags = TA_FLAG_CONIC;
639 break;
640 case FT_CURVE_TAG_CUBIC:
641 point->flags = TA_FLAG_CUBIC;
642 break;
643 default:
644 point->flags = TA_FLAG_NONE;
647 point->prev = prev;
648 prev->next = point;
649 prev = point;
651 if (point == end)
653 if (++contour_index < outline->n_contours)
655 end = points + outline->contours[contour_index];
656 prev = end;
662 /* set up the contours array */
664 TA_Point* contour = hints->contours;
665 TA_Point* contour_limit = contour + hints->num_contours;
667 short* end = outline->contours;
668 short idx = 0;
671 for (; contour < contour_limit; contour++, end++)
673 contour[0] = points + idx;
674 idx = (short)(end[0] + 1);
678 /* compute directions of in & out vectors */
680 TA_Point first = points;
681 TA_Point prev = NULL;
683 FT_Pos in_x = 0;
684 FT_Pos in_y = 0;
686 TA_Direction in_dir = TA_DIR_NONE;
689 for (point = points; point < point_limit; point++)
691 TA_Point next;
692 FT_Pos out_x, out_y;
695 if (point == first)
697 prev = first->prev;
698 in_x = first->fx - prev->fx;
699 in_y = first->fy - prev->fy;
700 in_dir = ta_direction_compute(in_x, in_y);
701 first = prev + 1;
704 point->in_dir = (FT_Char)in_dir;
706 next = point->next;
707 out_x = next->fx - point->fx;
708 out_y = next->fy - point->fy;
710 in_dir = ta_direction_compute(out_x, out_y);
711 point->out_dir = (FT_Char)in_dir;
713 /* check for weak points */
715 if (point->flags & TA_FLAG_CONTROL)
717 Is_Weak_Point:
718 point->flags |= TA_FLAG_WEAK_INTERPOLATION;
720 else if (point->out_dir == point->in_dir)
722 if (point->out_dir != TA_DIR_NONE)
723 goto Is_Weak_Point;
725 if (ta_corner_is_flat(in_x, in_y, out_x, out_y))
726 goto Is_Weak_Point;
728 else if (point->in_dir == -point->out_dir)
729 goto Is_Weak_Point;
731 in_x = out_x;
732 in_y = out_y;
733 prev = point;
738 Exit:
739 return error;
743 /* store the hinted outline in an FT_Outline structure */
745 void
746 ta_glyph_hints_save(TA_GlyphHints hints,
747 FT_Outline* outline)
749 TA_Point point = hints->points;
750 TA_Point limit = point + hints->num_points;
752 FT_Vector* vec = outline->points;
753 char* tag = outline->tags;
756 for (; point < limit; point++, vec++, tag++)
758 vec->x = point->x;
759 vec->y = point->y;
761 if (point->flags & TA_FLAG_CONIC)
762 tag[0] = FT_CURVE_TAG_CONIC;
763 else if (point->flags & TA_FLAG_CUBIC)
764 tag[0] = FT_CURVE_TAG_CUBIC;
765 else
766 tag[0] = FT_CURVE_TAG_ON;
771 /****************************************************************
773 * EDGE POINT GRID-FITTING
775 ****************************************************************/
778 /* align all points of an edge to the same coordinate value, */
779 /* either horizontally or vertically */
781 void
782 ta_glyph_hints_align_edge_points(TA_GlyphHints hints,
783 TA_Dimension dim)
785 TA_AxisHints axis = &hints->axis[dim];
786 TA_Segment segments = axis->segments;
787 TA_Segment segment_limit = segments + axis->num_segments;
788 TA_Segment seg;
791 if (dim == TA_DIMENSION_HORZ)
793 for (seg = segments; seg < segment_limit; seg++)
795 TA_Edge edge = seg->edge;
796 TA_Point point, first, last;
799 if (edge == NULL)
800 continue;
802 first = seg->first;
803 last = seg->last;
804 point = first;
805 for (;;)
807 point->x = edge->pos;
808 point->flags |= TA_FLAG_TOUCH_X;
810 if (point == last)
811 break;
813 point = point->next;
817 else
819 for (seg = segments; seg < segment_limit; seg++)
821 TA_Edge edge = seg->edge;
822 TA_Point point, first, last;
825 if (edge == NULL)
826 continue;
828 first = seg->first;
829 last = seg->last;
830 point = first;
831 for (;;)
833 point->y = edge->pos;
834 point->flags |= TA_FLAG_TOUCH_Y;
836 if (point == last)
837 break;
839 point = point->next;
846 /****************************************************************
848 * STRONG POINT INTERPOLATION
850 ****************************************************************/
853 /* hint the strong points -- */
854 /* this is equivalent to the TrueType `IP' hinting instruction */
856 void
857 ta_glyph_hints_align_strong_points(TA_GlyphHints hints,
858 TA_Dimension dim)
860 TA_Point points = hints->points;
861 TA_Point point_limit = points + hints->num_points;
863 TA_AxisHints axis = &hints->axis[dim];
865 TA_Edge edges = axis->edges;
866 TA_Edge edge_limit = edges + axis->num_edges;
868 FT_UShort touch_flag;
871 if (dim == TA_DIMENSION_HORZ)
872 touch_flag = TA_FLAG_TOUCH_X;
873 else
874 touch_flag = TA_FLAG_TOUCH_Y;
876 if (edges < edge_limit)
878 TA_Point point;
879 TA_Edge edge;
882 for (point = points; point < point_limit; point++)
884 FT_Pos u, ou, fu; /* point position */
885 FT_Pos delta;
888 if (point->flags & touch_flag)
889 continue;
891 /* if this point is candidate to weak interpolation, we */
892 /* interpolate it after all strong points have been processed */
894 if ((point->flags & TA_FLAG_WEAK_INTERPOLATION)
895 && !(point->flags & TA_FLAG_INFLECTION))
896 continue;
898 if (dim == TA_DIMENSION_VERT)
900 u = point->fy;
901 ou = point->oy;
903 else
905 u = point->fx;
906 ou = point->ox;
909 fu = u;
911 /* is the point before the first edge? */
912 edge = edges;
913 delta = edge->fpos - u;
914 if (delta >= 0)
916 u = edge->pos - (edge->opos - ou);
918 if (hints->recorder)
919 hints->recorder(ta_ip_before, hints, dim,
920 point, NULL, NULL, NULL, NULL);
922 goto Store_Point;
925 /* is the point after the last edge? */
926 edge = edge_limit - 1;
927 delta = u - edge->fpos;
928 if (delta >= 0)
930 u = edge->pos + (ou - edge->opos);
932 if (hints->recorder)
933 hints->recorder(ta_ip_after, hints, dim,
934 point, NULL, NULL, NULL, NULL);
936 goto Store_Point;
940 FT_PtrDist min, max, mid;
941 FT_Pos fpos;
944 /* find enclosing edges */
945 min = 0;
946 max = edge_limit - edges;
948 /* for a small number of edges, a linear search is better */
949 if (max <= 8)
951 FT_PtrDist nn;
954 for (nn = 0; nn < max; nn++)
955 if (edges[nn].fpos >= u)
956 break;
958 if (edges[nn].fpos == u)
960 u = edges[nn].pos;
962 if (hints->recorder)
963 hints->recorder(ta_ip_on, hints, dim,
964 point, &edges[nn], NULL, NULL, NULL);
966 goto Store_Point;
968 min = nn;
970 else
971 while (min < max)
973 mid = (max + min) >> 1;
974 edge = edges + mid;
975 fpos = edge->fpos;
977 if (u < fpos)
978 max = mid;
979 else if (u > fpos)
980 min = mid + 1;
981 else
983 /* we are on the edge */
984 u = edge->pos;
986 if (hints->recorder)
987 hints->recorder(ta_ip_on, hints, dim,
988 point, edge, NULL, NULL, NULL);
990 goto Store_Point;
994 /* point is not on an edge */
996 TA_Edge before = edges + min - 1;
997 TA_Edge after = edges + min + 0;
1000 /* assert(before && after && before != after) */
1001 if (before->scale == 0)
1002 before->scale = FT_DivFix(after->pos - before->pos,
1003 after->fpos - before->fpos);
1005 u = before->pos + FT_MulFix(fu - before->fpos,
1006 before->scale);
1008 if (hints->recorder)
1009 hints->recorder(ta_ip_between, hints, dim,
1010 point, before, after, NULL, NULL);
1014 Store_Point:
1015 /* save the point position */
1016 if (dim == TA_DIMENSION_HORZ)
1017 point->x = u;
1018 else
1019 point->y = u;
1021 point->flags |= touch_flag;
1027 /****************************************************************
1029 * WEAK POINT INTERPOLATION
1031 ****************************************************************/
1034 /* shift the original coordinates of all points between `p1' and */
1035 /* `p2' to get hinted coordinates, using the same difference as */
1036 /* given by `ref' */
1038 static void
1039 ta_iup_shift(TA_Point p1,
1040 TA_Point p2,
1041 TA_Point ref)
1043 TA_Point p;
1044 FT_Pos delta = ref->u - ref->v;
1047 if (delta == 0)
1048 return;
1050 for (p = p1; p < ref; p++)
1051 p->u = p->v + delta;
1053 for (p = ref + 1; p <= p2; p++)
1054 p->u = p->v + delta;
1058 /* interpolate the original coordinates of all points between `p1' and */
1059 /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */
1060 /* reference points; the `u' and `v' members are the current and */
1061 /* original coordinate values, respectively. */
1063 /* details can be found in the TrueType bytecode specification */
1065 static void
1066 ta_iup_interp(TA_Point p1,
1067 TA_Point p2,
1068 TA_Point ref1,
1069 TA_Point ref2)
1071 TA_Point p;
1072 FT_Pos u;
1073 FT_Pos v1 = ref1->v;
1074 FT_Pos v2 = ref2->v;
1075 FT_Pos d1 = ref1->u - v1;
1076 FT_Pos d2 = ref2->u - v2;
1079 if (p1 > p2)
1080 return;
1082 if (v1 == v2)
1084 for (p = p1; p <= p2; p++)
1086 u = p->v;
1088 if (u <= v1)
1089 u += d1;
1090 else
1091 u += d2;
1093 p->u = u;
1095 return;
1098 if (v1 < v2)
1100 for (p = p1; p <= p2; p++)
1102 u = p->v;
1104 if (u <= v1)
1105 u += d1;
1106 else if (u >= v2)
1107 u += d2;
1108 else
1109 u = ref1->u + FT_MulDiv(u - v1, ref2->u - ref1->u, v2 - v1);
1111 p->u = u;
1114 else
1116 for (p = p1; p <= p2; p++)
1118 u = p->v;
1120 if (u <= v2)
1121 u += d2;
1122 else if (u >= v1)
1123 u += d1;
1124 else
1125 u = ref1->u + FT_MulDiv(u - v1, ref2->u - ref1->u, v2 - v1);
1127 p->u = u;
1133 /* hint the weak points -- */
1134 /* this is equivalent to the TrueType `IUP' hinting instruction */
1136 void
1137 ta_glyph_hints_align_weak_points(TA_GlyphHints hints,
1138 TA_Dimension dim)
1140 TA_Point points = hints->points;
1141 TA_Point point_limit = points + hints->num_points;
1143 TA_Point* contour = hints->contours;
1144 TA_Point* contour_limit = contour + hints->num_contours;
1146 FT_UShort touch_flag;
1147 TA_Point point;
1148 TA_Point end_point;
1149 TA_Point first_point;
1152 /* pass 1: move segment points to edge positions */
1154 if (dim == TA_DIMENSION_HORZ)
1156 touch_flag = TA_FLAG_TOUCH_X;
1158 for (point = points; point < point_limit; point++)
1160 point->u = point->x;
1161 point->v = point->ox;
1164 else
1166 touch_flag = TA_FLAG_TOUCH_Y;
1168 for (point = points; point < point_limit; point++)
1170 point->u = point->y;
1171 point->v = point->oy;
1175 point = points;
1177 for (; contour < contour_limit; contour++)
1179 TA_Point first_touched, last_touched;
1182 point = *contour;
1183 end_point = point->prev;
1184 first_point = point;
1186 /* find first touched point */
1187 for (;;)
1189 if (point > end_point) /* no touched point in contour */
1190 goto NextContour;
1192 if (point->flags & touch_flag)
1193 break;
1195 point++;
1198 first_touched = point;
1199 last_touched = point;
1201 for (;;)
1203 /* skip any touched neighbours */
1204 while (point < end_point
1205 && (point[1].flags & touch_flag) != 0)
1206 point++;
1208 last_touched = point;
1210 /* find the next touched point, if any */
1211 point++;
1212 for (;;)
1214 if (point > end_point)
1215 goto EndContour;
1217 if ((point->flags & touch_flag) != 0)
1218 break;
1220 point++;
1223 /* interpolate between last_touched and point */
1224 ta_iup_interp(last_touched + 1, point - 1,
1225 last_touched, point);
1228 EndContour:
1229 /* special case: only one point was touched */
1230 if (last_touched == first_touched)
1231 ta_iup_shift(first_point, end_point, first_touched);
1233 else /* interpolate the last part */
1235 if (last_touched < end_point)
1236 ta_iup_interp(last_touched + 1, end_point,
1237 last_touched, first_touched);
1239 if (first_touched > points)
1240 ta_iup_interp(first_point, first_touched - 1,
1241 last_touched, first_touched);
1244 NextContour:
1248 /* now save the interpolated values back to x/y */
1249 if (dim == TA_DIMENSION_HORZ)
1251 for (point = points; point < point_limit; point++)
1252 point->x = point->u;
1254 else
1256 for (point = points; point < point_limit; point++)
1257 point->y = point->u;
1262 #ifdef TA_CONFIG_OPTION_USE_WARPER
1264 /* apply (small) warp scale and warp delta for given dimension */
1266 static void
1267 ta_glyph_hints_scale_dim(TA_GlyphHints hints,
1268 TA_Dimension dim,
1269 FT_Fixed scale,
1270 FT_Pos delta)
1272 TA_Point points = hints->points;
1273 TA_Point points_limit = points + hints->num_points;
1274 TA_Point point;
1277 if (dim == TA_DIMENSION_HORZ)
1279 for (point = points; point < points_limit; point++)
1280 point->x = FT_MulFix(point->fx, scale) + delta;
1282 else
1284 for (point = points; point < points_limit; point++)
1285 point->y = FT_MulFix(point->fy, scale) + delta;
1289 #endif /* TA_CONFIG_OPTION_USE_WARPER */
1291 /* end of tahints.c */