7
static const char* af_dir_str( AF_Direction dir )
13
case AF_DIR_UP: result = "up"; break;
14
case AF_DIR_DOWN: result = "down"; break;
15
case AF_DIR_LEFT: result = "left"; break;
16
case AF_DIR_RIGHT: result = "right"; break;
17
default: result = "none";
22
#define AF_INDEX_NUM(ptr,base) ( (ptr) ? ((ptr)-(base)) : -1 )
25
af_glyph_hints_dump_points( AF_GlyphHints hints )
27
AF_Point points = hints->points;
28
AF_Point limit = points + hints->num_points;
31
printf( "Table of points:\n" );
32
printf( " [ index | xorg | yorg | xscale | yscale | xfit | yfit | flags ]\n" );
33
for ( point = points; point < limit; point++ )
35
printf( " [ %5d | %5d | %5d | %-5.2f | %-5.2f | %-5.2f | %-5.2f | %c%c%c%c%c%c ]\n",
43
(point->flags & AF_FLAG_WEAK_INTERPOLATION) ? 'w' : ' ',
44
(point->flags & AF_FLAG_INFLECTION) ? 'i' : ' ',
45
(point->flags & AF_FLAG_EXTREMA_X) ? '<' : ' ',
46
(point->flags & AF_FLAG_EXTREMA_Y) ? 'v' : ' ',
47
(point->flags & AF_FLAG_ROUND_X) ? '(' : ' ',
48
(point->flags & AF_FLAG_ROUND_Y) ? 'u' : ' '
55
/* A function used to dump the array of linked segments */
57
af_glyph_hints_dump_segments( AF_GlyphHints hints )
59
AF_Point points = hints->points;
62
for ( dimension = 1; dimension >= 0; dimension-- )
64
AF_AxisHints axis = &hints->axis[dimension];
65
AF_Segment segments = axis->segments;
66
AF_Segment limit = segments + axis->num_segments;
70
printf ( "Table of %s segments:\n",
71
dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
72
printf ( " [ index | pos | dir | link | serif |"
73
" numl | first | start ]\n" );
75
for ( seg = segments; seg < limit; seg++ )
77
printf ( " [ %5d | %4d | %5s | %4d | %5d | %4d | %5d | %5d ]\n",
80
af_dir_str( seg->dir ),
81
AF_INDEX_NUM( seg->link, segments ),
82
AF_INDEX_NUM( seg->serif, segments ),
93
af_glyph_hints_dump_edges( AF_GlyphHints hints )
97
for ( dimension = 1; dimension >= 0; dimension-- )
99
AF_AxisHints axis = &hints->axis[ dimension ];
100
AF_Edge edges = axis->edges;
101
AF_Edge limit = edges + axis->num_edges;
104
/* note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
105
* since they have constant X coordinate
107
printf ( "Table of %s edges:\n",
108
dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
109
printf ( " [ index | pos | dir | link |"
110
" serif | blue | opos | pos ]\n" );
112
for ( edge = edges; edge < limit; edge++ )
114
printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n",
117
af_dir_str( edge->dir ),
118
AF_INDEX_NUM( edge->link, edges ),
119
AF_INDEX_NUM( edge->serif, edges ),
120
edge->blue_edge ? 'y' : 'n',
131
#endif /* AF_DEBUG */
134
/* compute the direction value of a given vector */
135
FT_LOCAL_DEF( AF_Direction )
136
af_direction_compute( FT_Pos dx,
140
FT_Pos ax = FT_ABS( dx );
141
FT_Pos ay = FT_ABS( dy );
146
/* atan(1/12) == 4.7 degrees */
148
/* test for vertical direction */
151
dir = dy > 0 ? AF_DIR_UP : AF_DIR_DOWN;
153
/* test for horizontal direction */
154
else if ( ay * 12 < ax )
156
dir = dx > 0 ? AF_DIR_RIGHT : AF_DIR_LEFT;
163
/* compute all inflex points in a given glyph */
165
af_glyph_hints_compute_inflections( AF_GlyphHints hints )
167
AF_Point* contour = hints->contours;
168
AF_Point* contour_limit = contour + hints->num_contours;
171
/* do each contour separately */
172
for ( ; contour < contour_limit; contour++ )
174
AF_Point point = contour[0];
175
AF_Point first = point;
176
AF_Point start = point;
177
AF_Point end = point;
180
AF_Angle angle_in, angle_seg, angle_out;
181
AF_Angle diff_in, diff_out;
185
/* compute first segment in contour */
195
} while ( end->fx == first->fx && end->fy == first->fy );
197
angle_seg = af_angle_atan( end->fx - start->fx,
198
end->fy - start->fy );
200
/* extend the segment start whenever possible */
207
before = before->prev;
208
if ( before == first )
211
} while ( before->fx == start->fx && before->fy == start->fy );
213
angle_in = af_angle_atan( start->fx - before->fx,
214
start->fy - before->fy );
216
} while ( angle_in == angle_seg );
219
diff_in = af_angle_diff( angle_in, angle_seg );
221
/* now, process all segments in the contour */
224
/* first, extend current segment's end whenever possible */
232
if ( after == first )
235
} while ( end->fx == after->fx && end->fy == after->fy );
237
angle_out = af_angle_atan( after->fx - end->fx,
238
after->fy - end->fy );
240
} while ( angle_out == angle_seg );
242
diff_out = af_angle_diff( angle_seg, angle_out );
244
if ( ( diff_in ^ diff_out ) < 0 )
246
/* diff_in and diff_out have different signs, we have */
247
/* inflection points here... */
250
start->flags |= AF_FLAG_INFLECTION;
253
} while ( start != end );
255
start->flags |= AF_FLAG_INFLECTION;
260
angle_seg = angle_out;
263
} while ( !finished );
273
af_glyph_hints_init( AF_GlyphHints hints,
277
hints->memory = memory;
283
af_glyph_hints_done( AF_GlyphHints hints )
285
if ( hints && hints->memory )
287
FT_Memory memory = hints->memory;
290
/* note that we don't need to free the segment and edge
291
* buffers, since they're really within the hints->points array
293
for ( dim = 0; dim < 2; dim++ )
295
AF_AxisHints axis = &hints->axis[ dim ];
297
axis->num_segments = 0;
299
axis->segments = NULL;
303
FT_FREE( hints->contours );
304
hints->max_contours = 0;
305
hints->num_contours = 0;
307
FT_FREE( hints->points );
308
hints->num_points = 0;
309
hints->max_points = 0;
311
hints->memory = NULL;
318
af_glyph_hints_rescale( AF_GlyphHints hints,
319
AF_ScriptMetrics metrics )
321
hints->metrics = metrics;
325
FT_LOCAL_DEF( FT_Error )
326
af_glyph_hints_reload( AF_GlyphHints hints,
327
FT_Outline* outline )
329
FT_Error error = FT_Err_Ok;
331
FT_UInt old_max, new_max;
332
AF_Scaler scaler = &hints->metrics->scaler;
333
FT_Fixed x_scale = hints->x_scale;
334
FT_Fixed y_scale = hints->y_scale;
335
FT_Pos x_delta = hints->x_delta;
336
FT_Pos y_delta = hints->y_delta;
337
FT_Memory memory = hints->memory;
339
hints->scaler_flags = scaler->flags;
340
hints->num_points = 0;
341
hints->num_contours = 0;
343
hints->axis[0].num_segments = 0;
344
hints->axis[0].num_edges = 0;
345
hints->axis[1].num_segments = 0;
346
hints->axis[1].num_edges = 0;
348
/* first of all, reallocate the contours array when necessary
350
new_max = (FT_UInt) outline->n_contours;
351
old_max = hints->max_contours;
352
if ( new_max > old_max )
354
new_max = (new_max + 3) & ~3;
356
if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
359
hints->max_contours = new_max;
362
/* then, reallocate the points, segments & edges arrays if needed --
363
* note that we reserved two additional point positions, used to
364
* hint metrics appropriately
366
new_max = (FT_UInt)( outline->n_points + 2 );
367
old_max = hints->max_points;
368
if ( new_max > old_max )
371
FT_ULong off1, off2, off3;
373
/* we store in a single buffer the following arrays:
375
* - an array of N AF_PointRec items
376
* - an array of 2*N AF_SegmentRec items
377
* - an array of 2*N AF_EdgeRec items
381
new_max = ( new_max + 2 + 7 ) & ~7;
383
#define OFF_PAD2(x,y) (((x)+(y)-1) & ~((y)-1))
384
#define OFF_PADX(x,y) ((((x)+(y)-1)/(y))*(y))
385
#define OFF_PAD(x,y) ( ((y) & ((y)-1)) ? OFF_PADX(x,y) : OFF_PAD2(x,y) )
388
#define OFF_INCREMENT( _off, _type, _count ) \
389
( OFF_PAD( _off, sizeof(_type) ) + (_count)*sizeof(_type))
391
off1 = OFF_INCREMENT( 0, AF_PointRec, new_max );
392
off2 = OFF_INCREMENT( off1, AF_SegmentRec, new_max*2 );
393
off3 = OFF_INCREMENT( off2, AF_EdgeRec, new_max*2 );
395
FT_FREE( hints->points );
397
if ( FT_ALLOC( items, off3 ) )
399
hints->max_points = 0;
400
hints->axis[0].segments = NULL;
401
hints->axis[0].edges = NULL;
402
hints->axis[1].segments = NULL;
403
hints->axis[1].edges = NULL;
407
/* readjust some pointers
409
hints->max_points = new_max;
410
hints->points = (AF_Point) items;
412
hints->axis[0].segments = (AF_Segment)( items + off1 );
413
hints->axis[1].segments = hints->axis[0].segments + new_max;
415
hints->axis[0].edges = (AF_Edge) ( items + off2 );
416
hints->axis[1].edges = hints->axis[0].edges + new_max;
419
hints->num_points = outline->n_points;
420
hints->num_contours = outline->n_contours;
423
/* We can't rely on the value of `FT_Outline.flags' to know the fill */
424
/* direction used for a glyph, given that some fonts are broken (e.g. */
425
/* the Arphic ones). We thus recompute it each time we need to. */
427
hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_UP;
428
hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_LEFT;
430
if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
432
hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_DOWN;
433
hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_RIGHT;
436
hints->x_scale = x_scale;
437
hints->y_scale = y_scale;
438
hints->x_delta = x_delta;
439
hints->y_delta = y_delta;
441
points = hints->points;
442
if ( hints->num_points == 0 )
447
AF_Point point_limit = points + hints->num_points;
450
/* compute coordinates & bezier flags */
452
FT_Vector* vec = outline->points;
453
char* tag = outline->tags;
456
for ( point = points; point < point_limit; point++, vec++, tag++ )
460
point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
461
point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
463
switch ( FT_CURVE_TAG( *tag ) )
465
case FT_CURVE_TAG_CONIC:
466
point->flags = AF_FLAG_CONIC;
468
case FT_CURVE_TAG_CUBIC:
469
point->flags = AF_FLAG_CUBIC;
478
/* compute `next' and `prev' */
480
FT_Int contour_index;
489
end = points + outline->contours[0];
492
for ( point = points; point < point_limit; point++ )
497
point->next = point + 1;
504
if ( point + 1 < point_limit )
506
end = points + outline->contours[contour_index];
514
/* set-up the contours array */
516
AF_Point* contour = hints->contours;
517
AF_Point* contour_limit = contour + hints->num_contours;
518
short* end = outline->contours;
522
for ( ; contour < contour_limit; contour++, end++ )
524
contour[0] = points + idx;
525
idx = (short)( end[0] + 1 );
529
/* compute directions of in & out vectors */
531
for ( point = points; point < point_limit; point++ )
535
FT_Pos in_x, in_y, out_x, out_y;
539
in_x = point->fx - prev->fx;
540
in_y = point->fy - prev->fy;
542
point->in_dir = af_direction_compute( in_x, in_y );
545
out_x = next->fx - point->fx;
546
out_y = next->fy - point->fy;
548
point->out_dir = af_direction_compute( out_x, out_y );
550
if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) )
553
point->flags |= AF_FLAG_WEAK_INTERPOLATION;
555
else if ( point->out_dir == point->in_dir )
557
AF_Angle angle_in, angle_out, delta;
560
if ( point->out_dir != AF_DIR_NONE )
563
angle_in = af_angle_atan( in_x, in_y );
564
angle_out = af_angle_atan( out_x, out_y );
565
delta = af_angle_diff( angle_in, angle_out );
567
if ( delta < 2 && delta > -2 )
570
else if ( point->in_dir == -point->out_dir )
576
/* compute inflection points
578
af_glyph_hints_compute_inflections( hints );
586
af_glyph_hints_save( AF_GlyphHints hints,
587
FT_Outline* outline )
589
AF_Point point = hints->points;
590
AF_Point limit = point + hints->num_points;
591
FT_Vector* vec = outline->points;
592
char* tag = outline->tags;
594
for ( ; point < limit; point++, vec++, tag++ )
596
vec->x = (FT_Pos) point->x;
597
vec->y = (FT_Pos) point->y;
599
if ( point->flags & AF_FLAG_CONIC )
600
tag[0] = FT_CURVE_TAG_CONIC;
601
else if ( point->flags & AF_FLAG_CUBIC )
602
tag[0] = FT_CURVE_TAG_CUBIC;
604
tag[0] = FT_CURVE_TAG_ON;
611
* E D G E P O I N T G R I D - F I T T I N G
617
af_glyph_hints_align_edge_points( AF_GlyphHints hints,
620
AF_AxisHints axis = & hints->axis[ dim ];
621
AF_Edge edges = axis->edges;
622
AF_Edge edge_limit = edges + axis->num_edges;
625
for ( edge = edges; edge < edge_limit; edge++ )
627
/* move the points of each segment */
628
/* in each edge to the edge's position */
629
AF_Segment seg = edge->first;
634
AF_Point point = seg->first;
639
if ( dim == AF_DIMENSION_HORZ )
641
point->x = edge->pos;
642
point->flags |= AF_FLAG_TOUCH_X;
646
point->y = edge->pos;
647
point->flags |= AF_FLAG_TOUCH_Y;
650
if ( point == seg->last )
656
seg = seg->edge_next;
658
} while ( seg != edge->first );
665
* S T R O N G P O I N T I N T E R P O L A T I O N
670
/* hint the strong points -- this is equivalent to the TrueType `IP' */
671
/* hinting instruction */
673
af_glyph_hints_align_strong_points( AF_GlyphHints hints,
676
AF_Point points = hints->points;
677
AF_Point point_limit = points + hints->num_points;
678
AF_AxisHints axis = &hints->axis[dim];
679
AF_Edge edges = axis->edges;
680
AF_Edge edge_limit = edges + axis->num_edges;
684
if ( dim == AF_DIMENSION_HORZ )
685
touch_flag = AF_FLAG_TOUCH_X;
687
touch_flag = AF_FLAG_TOUCH_Y;
689
if ( edges < edge_limit )
694
for ( point = points; point < point_limit; point++ )
696
FT_Pos u, ou, fu; /* point position */
700
if ( point->flags & touch_flag )
703
/* if this point is candidate to weak interpolation, we will */
704
/* interpolate it after all strong points have been processed */
705
if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) &&
706
!( point->flags & AF_FLAG_INFLECTION ) )
709
if ( dim == AF_DIMENSION_VERT )
722
/* is the point before the first edge? */
724
delta = edge->fpos - u;
727
u = edge->pos - ( edge->opos - ou );
731
/* is the point after the last edge? */
732
edge = edge_limit - 1;
733
delta = u - edge->fpos;
736
u = edge->pos + ( ou - edge->opos );
741
FT_UInt min, max, mid;
745
/* find enclosing edges */
747
max = edge_limit - edges;
751
mid = ( max + min ) >> 1;
761
/* we are on the edge */
768
AF_Edge before = edges + min - 1;
769
AF_Edge after = edges + min + 0;
772
/* assert( before && after && before != after ) */
773
if ( before->scale == 0 )
774
before->scale = FT_DivFix( after->pos - before->pos,
775
after->fpos - before->fpos );
777
u = before->pos + FT_MulFix( fu - before->fpos,
785
/* save the point position */
786
if ( dim == AF_DIMENSION_HORZ )
791
point->flags |= touch_flag;
799
* W E A K P O I N T I N T E R P O L A T I O N
804
af_iup_shift( AF_Point p1,
809
FT_Pos delta = ref->u - ref->v;
812
for ( p = p1; p < ref; p++ )
815
for ( p = ref + 1; p <= p2; p++ )
821
af_iup_interp( AF_Point p1,
830
FT_Pos d1 = ref1->u - v1;
831
FT_Pos d2 = ref2->u - v2;
839
for ( p = p1; p <= p2; p++ )
855
for ( p = p1; p <= p2; p++ )
864
u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
871
for ( p = p1; p <= p2; p++ )
880
u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
889
af_glyph_hints_align_weak_points( AF_GlyphHints hints,
892
AF_Point points = hints->points;
893
AF_Point point_limit = points + hints->num_points;
894
AF_Point* contour = hints->contours;
895
AF_Point* contour_limit = contour + hints->num_contours;
899
AF_Point first_point;
902
/* PASS 1: Move segment points to edge positions */
904
if ( dim == AF_DIMENSION_HORZ )
906
touch_flag = AF_FLAG_TOUCH_X;
908
for ( point = points; point < point_limit; point++ )
911
point->v = point->ox;
916
touch_flag = AF_FLAG_TOUCH_Y;
918
for ( point = points; point < point_limit; point++ )
921
point->v = point->oy;
927
for ( ; contour < contour_limit; contour++ )
930
end_point = point->prev;
933
while ( point <= end_point && !( point->flags & touch_flag ) )
936
if ( point <= end_point )
938
AF_Point first_touched = point;
939
AF_Point cur_touched = point;
943
while ( point <= end_point )
945
if ( point->flags & touch_flag )
947
/* we found two successive touched points; we interpolate */
948
/* all contour points between them */
949
af_iup_interp( cur_touched + 1, point - 1,
950
cur_touched, point );
956
if ( cur_touched == first_touched )
958
/* this is a special case: only one point was touched in the */
959
/* contour; we thus simply shift the whole contour */
960
af_iup_shift( first_point, end_point, cur_touched );
964
/* now interpolate after the last touched point to the end */
966
af_iup_interp( cur_touched + 1, end_point,
967
cur_touched, first_touched );
969
/* if the first contour point isn't touched, interpolate */
970
/* from the contour start to the first touched point */
971
if ( first_touched > points )
972
af_iup_interp( first_point, first_touched - 1,
973
cur_touched, first_touched );
978
/* now save the interpolated values back to x/y */
979
if ( dim == AF_DIMENSION_HORZ )
981
for ( point = points; point < point_limit; point++ )
986
for ( point = points; point < point_limit; point++ )