ReactOS  0.4.14-dev-115-g4576127
aflatin.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* */
3 /* aflatin.c */
4 /* */
5 /* Auto-fitter hinting routines for latin writing system (body). */
6 /* */
7 /* Copyright 2003-2018 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 /* */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
15 /* */
16 /***************************************************************************/
17 
18 
19 #include <ft2build.h>
20 #include FT_ADVANCES_H
21 #include FT_INTERNAL_DEBUG_H
22 
23 #include "afglobal.h"
24 #include "afpic.h"
25 #include "aflatin.h"
26 #include "aferrors.h"
27 
28 
29 #ifdef AF_CONFIG_OPTION_USE_WARPER
30 #include "afwarp.h"
31 #endif
32 
33 
34  /*************************************************************************/
35  /* */
36  /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
37  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
38  /* messages during execution. */
39  /* */
40 #undef FT_COMPONENT
41 #define FT_COMPONENT trace_aflatin
42 
43 
44  /* needed for computation of round vs. flat segments */
45 #define FLAT_THRESHOLD( x ) ( x / 14 )
46 
47 
48  /*************************************************************************/
49  /*************************************************************************/
50  /***** *****/
51  /***** L A T I N G L O B A L M E T R I C S *****/
52  /***** *****/
53  /*************************************************************************/
54  /*************************************************************************/
55 
56 
57  /* Find segments and links, compute all stem widths, and initialize */
58  /* standard width and height for the glyph with given charcode. */
59 
60  FT_LOCAL_DEF( void )
62  FT_Face face )
63  {
64  /* scan the array of segments in each direction */
65 #ifdef __REACTOS__
67  if (!hints) return;
68 #else
70 #endif
71 
72 
73  FT_TRACE5(( "\n"
74  "latin standard widths computation (style `%s')\n"
75  "=====================================================\n"
76  "\n",
77  af_style_names[metrics->root.style_class->style] ));
78 
79  af_glyph_hints_init( hints, face->memory );
80 
81  metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
82  metrics->axis[AF_DIMENSION_VERT].width_count = 0;
83 
84  {
86  FT_ULong glyph_index;
87  int dim;
88 #ifdef __REACTOS__
90  if (!dummy)
91  goto Exit;
92  {
93 #else
95 #endif
96  AF_Scaler scaler = &dummy->root.scaler;
97 
98 #ifdef FT_CONFIG_OPTION_PIC
99  AF_FaceGlobals globals = metrics->root.globals;
100 #endif
101 
102  AF_StyleClass style_class = metrics->root.style_class;
104  [style_class->script];
105 
106  void* shaper_buf;
107  const char* p;
108 
109 #ifdef FT_DEBUG_LEVEL_TRACE
110  FT_ULong ch = 0;
111 #endif
112 
113  p = script_class->standard_charstring;
114  shaper_buf = af_shaper_buf_create( face );
115 
116  /*
117  * We check a list of standard characters to catch features like
118  * `c2sc' (small caps from caps) that don't contain lowercase letters
119  * by definition, or other features that mainly operate on numerals.
120  * The first match wins.
121  */
122 
123  glyph_index = 0;
124  while ( *p )
125  {
126  unsigned int num_idx;
127 
128 #ifdef FT_DEBUG_LEVEL_TRACE
129  const char* p_old;
130 #endif
131 
132 
133  while ( *p == ' ' )
134  p++;
135 
136 #ifdef FT_DEBUG_LEVEL_TRACE
137  p_old = p;
138  GET_UTF8_CHAR( ch, p_old );
139 #endif
140 
141  /* reject input that maps to more than a single glyph */
142  p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
143  if ( num_idx > 1 )
144  continue;
145 
146  /* otherwise exit loop if we have a result */
147  glyph_index = af_shaper_get_elem( &metrics->root,
148  shaper_buf,
149  0,
150  NULL,
151  NULL );
152  if ( glyph_index )
153  break;
154  }
155 
156  af_shaper_buf_destroy( face, shaper_buf );
157 
158  if ( !glyph_index )
159  goto Exit;
160 
161  FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n",
162  ch, glyph_index ));
163 
164  error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
165  if ( error || face->glyph->outline.n_points <= 0 )
166  goto Exit;
167 
168  FT_ZERO( dummy );
169 
170  dummy->units_per_em = metrics->units_per_em;
171 
172  scaler->x_scale = 0x10000L;
173  scaler->y_scale = 0x10000L;
174  scaler->x_delta = 0;
175  scaler->y_delta = 0;
176 
177  scaler->face = face;
179  scaler->flags = 0;
180 
182 
183  error = af_glyph_hints_reload( hints, &face->glyph->outline );
184  if ( error )
185  goto Exit;
186 
187  for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
188  {
189  AF_LatinAxis axis = &metrics->axis[dim];
190  AF_AxisHints axhints = &hints->axis[dim];
192  FT_UInt num_widths = 0;
193 
194 
196  (AF_Dimension)dim );
197  if ( error )
198  goto Exit;
199 
200  /*
201  * We assume that the glyphs selected for the stem width
202  * computation are `featureless' enough so that the linking
203  * algorithm works fine without adjustments of its scoring
204  * function.
205  */
207  0,
208  NULL,
209  (AF_Dimension)dim );
210 
211  seg = axhints->segments;
212  limit = seg + axhints->num_segments;
213 
214  for ( ; seg < limit; seg++ )
215  {
216  link = seg->link;
217 
218  /* we only consider stem segments there! */
219  if ( link && link->link == seg && link > seg )
220  {
221  FT_Pos dist;
222 
223 
224  dist = seg->pos - link->pos;
225  if ( dist < 0 )
226  dist = -dist;
227 
228  if ( num_widths < AF_LATIN_MAX_WIDTHS )
229  axis->widths[num_widths++].org = dist;
230  }
231  }
232 
233  /* this also replaces multiple almost identical stem widths */
234  /* with a single one (the value 100 is heuristic) */
235  af_sort_and_quantize_widths( &num_widths, axis->widths,
236  dummy->units_per_em / 100 );
237  axis->width_count = num_widths;
238  }
239 
240  Exit:
241  for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
242  {
243  AF_LatinAxis axis = &metrics->axis[dim];
244  FT_Pos stdw;
245 
246 
247  stdw = ( axis->width_count > 0 ) ? axis->widths[0].org
248  : AF_LATIN_CONSTANT( metrics, 50 );
249 
250  /* let's try 20% of the smallest width */
251  axis->edge_distance_threshold = stdw / 5;
252  axis->standard_width = stdw;
253  axis->extra_light = 0;
254 
255 #ifdef FT_DEBUG_LEVEL_TRACE
256  {
257  FT_UInt i;
258 
259 
260  FT_TRACE5(( "%s widths:\n",
261  dim == AF_DIMENSION_VERT ? "horizontal"
262  : "vertical" ));
263 
264  FT_TRACE5(( " %d (standard)", axis->standard_width ));
265  for ( i = 1; i < axis->width_count; i++ )
266  FT_TRACE5(( " %d", axis->widths[i].org ));
267 
268  FT_TRACE5(( "\n" ));
269  }
270 #endif
271  }
272 #ifdef __REACTOS__
273  free(dummy);
274  }
275 #endif
276  }
277 
278  FT_TRACE5(( "\n" ));
279 
281 
282 #ifdef __REACTOS__
283  free(hints);
284 #endif
285 
286  }
287 
288 
289  static void
292  {
293  FT_UInt i, j;
295 
296 
297  /* we sort from bottom to top */
298  for ( i = 1; i < count; i++ )
299  {
300  for ( j = i; j > 0; j-- )
301  {
302  FT_Pos a, b;
303 
304 
305  if ( table[j - 1]->flags & ( AF_LATIN_BLUE_TOP |
307  a = table[j - 1]->ref.org;
308  else
309  a = table[j - 1]->shoot.org;
310 
311  if ( table[j]->flags & ( AF_LATIN_BLUE_TOP |
313  b = table[j]->ref.org;
314  else
315  b = table[j]->shoot.org;
316 
317  if ( b >= a )
318  break;
319 
320  swap = table[j];
321  table[j] = table[j - 1];
322  table[j - 1] = swap;
323  }
324  }
325  }
326 
327 
328  /* Find all blue zones. Flat segments give the reference points, */
329  /* round segments the overshoot positions. */
330 
331  static void
333  FT_Face face )
334  {
337 
338  FT_UInt num_flats;
339  FT_UInt num_rounds;
340 
342  FT_Error error;
343  AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
345 
346  AF_StyleClass sc = metrics->root.style_class;
347 
349  const AF_Blue_StringRec* bs = &af_blue_stringsets[bss];
350 
351  FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
352 
353  void* shaper_buf;
354 
355 
356  /* we walk over the blue character strings as specified in the */
357  /* style's entry in the `af_blue_stringset' array */
358 
359  FT_TRACE5(( "latin blue zones computation\n"
360  "============================\n"
361  "\n" ));
362 
363  shaper_buf = af_shaper_buf_create( face );
364 
365  for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
366  {
367  const char* p = &af_blue_strings[bs->string];
368  FT_Pos* blue_ref;
369  FT_Pos* blue_shoot;
370  FT_Pos ascender;
371  FT_Pos descender;
372 
373 
374 #ifdef FT_DEBUG_LEVEL_TRACE
375  {
376  FT_Bool have_flag = 0;
377 
378 
379  FT_TRACE5(( "blue zone %d", axis->blue_count ));
380 
381  if ( bs->properties )
382  {
383  FT_TRACE5(( " (" ));
384 
385  if ( AF_LATIN_IS_TOP_BLUE( bs ) )
386  {
387  FT_TRACE5(( "top" ));
388  have_flag = 1;
389  }
390  else if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
391  {
392  FT_TRACE5(( "sub top" ));
393  have_flag = 1;
394  }
395 
396  if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
397  {
398  if ( have_flag )
399  FT_TRACE5(( ", " ));
400  FT_TRACE5(( "neutral" ));
401  have_flag = 1;
402  }
403 
404  if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) )
405  {
406  if ( have_flag )
407  FT_TRACE5(( ", " ));
408  FT_TRACE5(( "small top" ));
409  have_flag = 1;
410  }
411 
412  if ( AF_LATIN_IS_LONG_BLUE( bs ) )
413  {
414  if ( have_flag )
415  FT_TRACE5(( ", " ));
416  FT_TRACE5(( "long" ));
417  }
418 
419  FT_TRACE5(( ")" ));
420  }
421 
422  FT_TRACE5(( ":\n" ));
423  }
424 #endif /* FT_DEBUG_LEVEL_TRACE */
425 
426  num_flats = 0;
427  num_rounds = 0;
428  ascender = 0;
429  descender = 0;
430 
431  while ( *p )
432  {
433  FT_ULong glyph_index;
434  FT_Long y_offset;
435  FT_Int best_point, best_contour_first, best_contour_last;
436  FT_Vector* points;
437 
438  FT_Pos best_y_extremum; /* same as points.y */
439  FT_Bool best_round = 0;
440 
441  unsigned int i, num_idx;
442 
443 #ifdef FT_DEBUG_LEVEL_TRACE
444  const char* p_old;
445  FT_ULong ch;
446 #endif
447 
448 
449  while ( *p == ' ' )
450  p++;
451 
452 #ifdef FT_DEBUG_LEVEL_TRACE
453  p_old = p;
454  GET_UTF8_CHAR( ch, p_old );
455 #endif
456 
457  p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
458 
459  if ( !num_idx )
460  {
461  FT_TRACE5(( " U+%04lX unavailable\n", ch ));
462  continue;
463  }
464 
465  if ( AF_LATIN_IS_TOP_BLUE( bs ) )
466  best_y_extremum = FT_INT_MIN;
467  else
468  best_y_extremum = FT_INT_MAX;
469 
470  /* iterate over all glyph elements of the character cluster */
471  /* and get the data of the `biggest' one */
472  for ( i = 0; i < num_idx; i++ )
473  {
474  FT_Pos best_y;
475  FT_Bool round = 0;
476 
477 
478  /* load the character in the face -- skip unknown or empty ones */
479  glyph_index = af_shaper_get_elem( &metrics->root,
480  shaper_buf,
481  i,
482  NULL,
483  &y_offset );
484  if ( glyph_index == 0 )
485  {
486  FT_TRACE5(( " U+%04lX unavailable\n", ch ));
487  continue;
488  }
489 
490  error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
491  outline = face->glyph->outline;
492  /* reject glyphs that don't produce any rendering */
493  if ( error || outline.n_points <= 2 )
494  {
495 #ifdef FT_DEBUG_LEVEL_TRACE
496  if ( num_idx == 1 )
497  FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch ));
498  else
499  FT_TRACE5(( " component %d of cluster starting with U+%04lX"
500  " contains no (usable) outlines\n", i, ch ));
501 #endif
502  continue;
503  }
504 
505  /* now compute min or max point indices and coordinates */
506  points = outline.points;
507  best_point = -1;
508  best_y = 0; /* make compiler happy */
509  best_contour_first = 0; /* ditto */
510  best_contour_last = 0; /* ditto */
511 
512  {
513  FT_Int nn;
514  FT_Int first = 0;
515  FT_Int last = -1;
516 
517 
518  for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
519  {
520  FT_Int old_best_point = best_point;
521  FT_Int pp;
522 
523 
524  last = outline.contours[nn];
525 
526  /* Avoid single-point contours since they are never */
527  /* rasterized. In some fonts, they correspond to mark */
528  /* attachment points that are way outside of the glyph's */
529  /* real outline. */
530  if ( last <= first )
531  continue;
532 
533  if ( AF_LATIN_IS_TOP_BLUE( bs ) ||
535  {
536  for ( pp = first; pp <= last; pp++ )
537  {
538  if ( best_point < 0 || points[pp].y > best_y )
539  {
540  best_point = pp;
541  best_y = points[pp].y;
542  ascender = FT_MAX( ascender, best_y + y_offset );
543  }
544  else
545  descender = FT_MIN( descender, points[pp].y + y_offset );
546  }
547  }
548  else
549  {
550  for ( pp = first; pp <= last; pp++ )
551  {
552  if ( best_point < 0 || points[pp].y < best_y )
553  {
554  best_point = pp;
555  best_y = points[pp].y;
556  descender = FT_MIN( descender, best_y + y_offset );
557  }
558  else
559  ascender = FT_MAX( ascender, points[pp].y + y_offset );
560  }
561  }
562 
563  if ( best_point != old_best_point )
564  {
565  best_contour_first = first;
566  best_contour_last = last;
567  }
568  }
569  }
570 
571  /* now check whether the point belongs to a straight or round */
572  /* segment; we first need to find in which contour the extremum */
573  /* lies, then inspect its previous and next points */
574  if ( best_point >= 0 )
575  {
576  FT_Pos best_x = points[best_point].x;
577  FT_Int prev, next;
578  FT_Int best_segment_first, best_segment_last;
579  FT_Int best_on_point_first, best_on_point_last;
580  FT_Pos dist;
581 
582 
583  best_segment_first = best_point;
584  best_segment_last = best_point;
585 
586  if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON )
587  {
588  best_on_point_first = best_point;
589  best_on_point_last = best_point;
590  }
591  else
592  {
593  best_on_point_first = -1;
594  best_on_point_last = -1;
595  }
596 
597  /* look for the previous and next points on the contour */
598  /* that are not on the same Y coordinate, then threshold */
599  /* the `closeness'... */
600  prev = best_point;
601  next = prev;
602 
603  do
604  {
605  if ( prev > best_contour_first )
606  prev--;
607  else
608  prev = best_contour_last;
609 
610  dist = FT_ABS( points[prev].y - best_y );
611  /* accept a small distance or a small angle (both values are */
612  /* heuristic; value 20 corresponds to approx. 2.9 degrees) */
613  if ( dist > 5 )
614  if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist )
615  break;
616 
617  best_segment_first = prev;
618 
619  if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON )
620  {
621  best_on_point_first = prev;
622  if ( best_on_point_last < 0 )
623  best_on_point_last = prev;
624  }
625 
626  } while ( prev != best_point );
627 
628  do
629  {
630  if ( next < best_contour_last )
631  next++;
632  else
633  next = best_contour_first;
634 
635  dist = FT_ABS( points[next].y - best_y );
636  if ( dist > 5 )
637  if ( FT_ABS( points[next].x - best_x ) <= 20 * dist )
638  break;
639 
640  best_segment_last = next;
641 
642  if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON )
643  {
644  best_on_point_last = next;
645  if ( best_on_point_first < 0 )
646  best_on_point_first = next;
647  }
648 
649  } while ( next != best_point );
650 
651  if ( AF_LATIN_IS_LONG_BLUE( bs ) )
652  {
653  /* If this flag is set, we have an additional constraint to */
654  /* get the blue zone distance: Find a segment of the topmost */
655  /* (or bottommost) contour that is longer than a heuristic */
656  /* threshold. This ensures that small bumps in the outline */
657  /* are ignored (for example, the `vertical serifs' found in */
658  /* many Hebrew glyph designs). */
659 
660  /* If this segment is long enough, we are done. Otherwise, */
661  /* search the segment next to the extremum that is long */
662  /* enough, has the same direction, and a not too large */
663  /* vertical distance from the extremum. Note that the */
664  /* algorithm doesn't check whether the found segment is */
665  /* actually the one (vertically) nearest to the extremum. */
666 
667  /* heuristic threshold value */
668  FT_Pos length_threshold = metrics->units_per_em / 25;
669 
670 
671  dist = FT_ABS( points[best_segment_last].x -
672  points[best_segment_first].x );
673 
674  if ( dist < length_threshold &&
675  best_segment_last - best_segment_first + 2 <=
676  best_contour_last - best_contour_first )
677  {
678  /* heuristic threshold value */
679  FT_Pos height_threshold = metrics->units_per_em / 4;
680 
681  FT_Int first;
682  FT_Int last;
683  FT_Bool hit;
684 
685  /* we intentionally declare these two variables */
686  /* outside of the loop since various compilers emit */
687  /* incorrect warning messages otherwise, talking about */
688  /* `possibly uninitialized variables' */
689  FT_Int p_first = 0; /* make compiler happy */
690  FT_Int p_last = 0;
691 
692  FT_Bool left2right;
693 
694 
695  /* compute direction */
696  prev = best_point;
697 
698  do
699  {
700  if ( prev > best_contour_first )
701  prev--;
702  else
703  prev = best_contour_last;
704 
705  if ( points[prev].x != best_x )
706  break;
707 
708  } while ( prev != best_point );
709 
710  /* skip glyph for the degenerate case */
711  if ( prev == best_point )
712  continue;
713 
714  left2right = FT_BOOL( points[prev].x < points[best_point].x );
715 
716  first = best_segment_last;
717  last = first;
718  hit = 0;
719 
720  do
721  {
722  FT_Bool l2r;
723  FT_Pos d;
724 
725 
726  if ( !hit )
727  {
728  /* no hit; adjust first point */
729  first = last;
730 
731  /* also adjust first and last on point */
732  if ( FT_CURVE_TAG( outline.tags[first] ) ==
734  {
735  p_first = first;
736  p_last = first;
737  }
738  else
739  {
740  p_first = -1;
741  p_last = -1;
742  }
743 
744  hit = 1;
745  }
746 
747  if ( last < best_contour_last )
748  last++;
749  else
750  last = best_contour_first;
751 
752  if ( FT_ABS( best_y - points[first].y ) > height_threshold )
753  {
754  /* vertical distance too large */
755  hit = 0;
756  continue;
757  }
758 
759  /* same test as above */
760  dist = FT_ABS( points[last].y - points[first].y );
761  if ( dist > 5 )
762  if ( FT_ABS( points[last].x - points[first].x ) <=
763  20 * dist )
764  {
765  hit = 0;
766  continue;
767  }
768 
769  if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON )
770  {
771  p_last = last;
772  if ( p_first < 0 )
773  p_first = last;
774  }
775 
776  l2r = FT_BOOL( points[first].x < points[last].x );
777  d = FT_ABS( points[last].x - points[first].x );
778 
779  if ( l2r == left2right &&
780  d >= length_threshold )
781  {
782  /* all constraints are met; update segment after */
783  /* finding its end */
784  do
785  {
786  if ( last < best_contour_last )
787  last++;
788  else
789  last = best_contour_first;
790 
791  d = FT_ABS( points[last].y - points[first].y );
792  if ( d > 5 )
793  if ( FT_ABS( points[next].x - points[first].x ) <=
794  20 * dist )
795  {
796  if ( last > best_contour_first )
797  last--;
798  else
799  last = best_contour_last;
800  break;
801  }
802 
803  p_last = last;
804 
805  if ( FT_CURVE_TAG( outline.tags[last] ) ==
807  {
808  p_last = last;
809  if ( p_first < 0 )
810  p_first = last;
811  }
812 
813  } while ( last != best_segment_first );
814 
815  best_y = points[first].y;
816 
817  best_segment_first = first;
818  best_segment_last = last;
819 
820  best_on_point_first = p_first;
821  best_on_point_last = p_last;
822 
823  break;
824  }
825 
826  } while ( last != best_segment_first );
827  }
828  }
829 
830  /* for computing blue zones, we add the y offset as returned */
831  /* by the currently used OpenType feature -- for example, */
832  /* superscript glyphs might be identical to subscript glyphs */
833  /* with a vertical shift */
834  best_y += y_offset;
835 
836 #ifdef FT_DEBUG_LEVEL_TRACE
837  if ( num_idx == 1 )
838  FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y ));
839  else
840  FT_TRACE5(( " component %d of cluster starting with U+%04lX:"
841  " best_y = %5ld", i, ch, best_y ));
842 #endif
843 
844  /* now set the `round' flag depending on the segment's kind: */
845  /* */
846  /* - if the horizontal distance between the first and last */
847  /* `on' point is larger than a heuristic threshold */
848  /* we have a flat segment */
849  /* - if either the first or the last point of the segment is */
850  /* an `off' point, the segment is round, otherwise it is */
851  /* flat */
852  if ( best_on_point_first >= 0 &&
853  best_on_point_last >= 0 &&
854  ( FT_ABS( points[best_on_point_last].x -
855  points[best_on_point_first].x ) ) >
856  flat_threshold )
857  round = 0;
858  else
859  round = FT_BOOL(
860  FT_CURVE_TAG( outline.tags[best_segment_first] ) !=
861  FT_CURVE_TAG_ON ||
862  FT_CURVE_TAG( outline.tags[best_segment_last] ) !=
863  FT_CURVE_TAG_ON );
864 
865  if ( round && AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
866  {
867  /* only use flat segments for a neutral blue zone */
868  FT_TRACE5(( " (round, skipped)\n" ));
869  continue;
870  }
871 
872  FT_TRACE5(( " (%s)\n", round ? "round" : "flat" ));
873  }
874 
875  if ( AF_LATIN_IS_TOP_BLUE( bs ) )
876  {
877  if ( best_y > best_y_extremum )
878  {
879  best_y_extremum = best_y;
880  best_round = round;
881  }
882  }
883  else
884  {
885  if ( best_y < best_y_extremum )
886  {
887  best_y_extremum = best_y;
888  best_round = round;
889  }
890  }
891 
892  } /* end for loop */
893 
894  if ( !( best_y_extremum == FT_INT_MIN ||
895  best_y_extremum == FT_INT_MAX ) )
896  {
897  if ( best_round )
898  rounds[num_rounds++] = best_y_extremum;
899  else
900  flats[num_flats++] = best_y_extremum;
901  }
902 
903  } /* end while loop */
904 
905  if ( num_flats == 0 && num_rounds == 0 )
906  {
907  /*
908  * we couldn't find a single glyph to compute this blue zone,
909  * we will simply ignore it then
910  */
911  FT_TRACE5(( " empty\n" ));
912  continue;
913  }
914 
915  /* we have computed the contents of the `rounds' and `flats' tables, */
916  /* now determine the reference and overshoot position of the blue -- */
917  /* we simply take the median value after a simple sort */
918  af_sort_pos( num_rounds, rounds );
919  af_sort_pos( num_flats, flats );
920 
921  blue = &axis->blues[axis->blue_count];
922  blue_ref = &blue->ref.org;
923  blue_shoot = &blue->shoot.org;
924 
925  axis->blue_count++;
926 
927  if ( num_flats == 0 )
928  {
929  *blue_ref =
930  *blue_shoot = rounds[num_rounds / 2];
931  }
932  else if ( num_rounds == 0 )
933  {
934  *blue_ref =
935  *blue_shoot = flats[num_flats / 2];
936  }
937  else
938  {
939  *blue_ref = flats [num_flats / 2];
940  *blue_shoot = rounds[num_rounds / 2];
941  }
942 
943  /* there are sometimes problems: if the overshoot position of top */
944  /* zones is under its reference position, or the opposite for bottom */
945  /* zones. We must thus check everything there and correct the errors */
946  if ( *blue_shoot != *blue_ref )
947  {
948  FT_Pos ref = *blue_ref;
949  FT_Pos shoot = *blue_shoot;
950  FT_Bool over_ref = FT_BOOL( shoot > ref );
951 
952 
953  if ( ( AF_LATIN_IS_TOP_BLUE( bs ) ||
954  AF_LATIN_IS_SUB_TOP_BLUE( bs) ) ^ over_ref )
955  {
956  *blue_ref =
957  *blue_shoot = ( shoot + ref ) / 2;
958 
959  FT_TRACE5(( " [overshoot smaller than reference,"
960  " taking mean value]\n" ));
961  }
962  }
963 
964  blue->ascender = ascender;
965  blue->descender = descender;
966 
967  blue->flags = 0;
968  if ( AF_LATIN_IS_TOP_BLUE( bs ) )
969  blue->flags |= AF_LATIN_BLUE_TOP;
970  if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
971  blue->flags |= AF_LATIN_BLUE_SUB_TOP;
972  if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
973  blue->flags |= AF_LATIN_BLUE_NEUTRAL;
974 
975  /*
976  * The following flag is used later to adjust the y and x scales
977  * in order to optimize the pixel grid alignment of the top of small
978  * letters.
979  */
980  if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) )
981  blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;
982 
983  FT_TRACE5(( " -> reference = %ld\n"
984  " overshoot = %ld\n",
985  *blue_ref, *blue_shoot ));
986 
987  } /* end for loop */
988 
989  af_shaper_buf_destroy( face, shaper_buf );
990 
991  /* we finally check whether blue zones are ordered; */
992  /* `ref' and `shoot' values of two blue zones must not overlap */
993  if ( axis->blue_count )
994  {
995  FT_UInt i;
996  AF_LatinBlue blue_sorted[AF_BLUE_STRINGSET_MAX_LEN + 2];
997 
998 
999  for ( i = 0; i < axis->blue_count; i++ )
1000  blue_sorted[i] = &axis->blues[i];
1001 
1002  /* sort bottoms of blue zones... */
1003  af_latin_sort_blue( axis->blue_count, blue_sorted );
1004 
1005  /* ...and adjust top values if necessary */
1006  for ( i = 0; i < axis->blue_count - 1; i++ )
1007  {
1008  FT_Pos* a;
1009  FT_Pos* b;
1010 
1011 #ifdef FT_DEBUG_LEVEL_TRACE
1012  FT_Bool a_is_top = 0;
1013 #endif
1014 
1015 
1016  if ( blue_sorted[i]->flags & ( AF_LATIN_BLUE_TOP |
1018  {
1019  a = &blue_sorted[i]->shoot.org;
1020 #ifdef FT_DEBUG_LEVEL_TRACE
1021  a_is_top = 1;
1022 #endif
1023  }
1024  else
1025  a = &blue_sorted[i]->ref.org;
1026 
1027  if ( blue_sorted[i + 1]->flags & ( AF_LATIN_BLUE_TOP |
1029  b = &blue_sorted[i + 1]->shoot.org;
1030  else
1031  b = &blue_sorted[i + 1]->ref.org;
1032 
1033  if ( *a > *b )
1034  {
1035  *a = *b;
1036  FT_TRACE5(( "blue zone overlap:"
1037  " adjusting %s %d to %ld\n",
1038  a_is_top ? "overshoot" : "reference",
1039  blue_sorted[i] - axis->blues,
1040  *a ));
1041  }
1042  }
1043  }
1044 
1045  FT_TRACE5(( "\n" ));
1046 
1047  return;
1048  }
1049 
1050 
1051  /* Check whether all ASCII digits have the same advance width. */
1052 
1053  FT_LOCAL_DEF( void )
1055  FT_Face face )
1056  {
1057  FT_Bool started = 0, same_width = 1;
1058  FT_Fixed advance = 0, old_advance = 0;
1059 
1060  void* shaper_buf;
1061 
1062  /* in all supported charmaps, digits have character codes 0x30-0x39 */
1063  const char digits[] = "0 1 2 3 4 5 6 7 8 9";
1064  const char* p;
1065 
1066 
1067  p = digits;
1068  shaper_buf = af_shaper_buf_create( face );
1069 
1070  while ( *p )
1071  {
1072  FT_ULong glyph_index;
1073  unsigned int num_idx;
1074 
1075 
1076  /* reject input that maps to more than a single glyph */
1077  p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
1078  if ( num_idx > 1 )
1079  continue;
1080 
1081  glyph_index = af_shaper_get_elem( &metrics->root,
1082  shaper_buf,
1083  0,
1084  &advance,
1085  NULL );
1086  if ( !glyph_index )
1087  continue;
1088 
1089  if ( started )
1090  {
1091  if ( advance != old_advance )
1092  {
1093  same_width = 0;
1094  break;
1095  }
1096  }
1097  else
1098  {
1099  old_advance = advance;
1100  started = 1;
1101  }
1102  }
1103 
1104  af_shaper_buf_destroy( face, shaper_buf );
1105 
1106  metrics->root.digits_have_same_width = same_width;
1107  }
1108 
1109 
1110  /* Initialize global metrics. */
1111 
1114  FT_Face face )
1115  {
1116  FT_CharMap oldmap = face->charmap;
1117 
1118 
1119  metrics->units_per_em = face->units_per_EM;
1120 
1121  if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
1122  {
1126  }
1127 
1128  FT_Set_Charmap( face, oldmap );
1129  return FT_Err_Ok;
1130  }
1131 
1132 
1133  /* Adjust scaling value, then scale and shift widths */
1134  /* and blue zones (if applicable) for given dimension. */
1135 
1136  static void
1138  AF_Scaler scaler,
1139  AF_Dimension dim )
1140  {
1141  FT_Fixed scale;
1142  FT_Pos delta;
1143  AF_LatinAxis axis;
1144  FT_UInt nn;
1145 
1146 
1147  if ( dim == AF_DIMENSION_HORZ )
1148  {
1149  scale = scaler->x_scale;
1150  delta = scaler->x_delta;
1151  }
1152  else
1153  {
1154  scale = scaler->y_scale;
1155  delta = scaler->y_delta;
1156  }
1157 
1158  axis = &metrics->axis[dim];
1159 
1160  if ( axis->org_scale == scale && axis->org_delta == delta )
1161  return;
1162 
1163  axis->org_scale = scale;
1164  axis->org_delta = delta;
1165 
1166  /*
1167  * correct X and Y scale to optimize the alignment of the top of small
1168  * letters to the pixel grid
1169  */
1170  {
1171  AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT];
1173 
1174 
1175  for ( nn = 0; nn < Axis->blue_count; nn++ )
1176  {
1177  if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
1178  {
1179  blue = &Axis->blues[nn];
1180  break;
1181  }
1182  }
1183 
1184  if ( blue )
1185  {
1186  FT_Pos scaled;
1187  FT_Pos threshold;
1188  FT_Pos fitted;
1189  FT_UInt limit;
1190  FT_UInt ppem;
1191 
1192 
1193  scaled = FT_MulFix( blue->shoot.org, scale );
1194  ppem = metrics->root.scaler.face->size->metrics.x_ppem;
1195  limit = metrics->root.globals->increase_x_height;
1196  threshold = 40;
1197 
1198  /* if the `increase-x-height' property is active, */
1199  /* we round up much more often */
1200  if ( limit &&
1201  ppem <= limit &&
1203  threshold = 52;
1204 
1205  fitted = ( scaled + threshold ) & ~63;
1206 
1207  if ( scaled != fitted )
1208  {
1209 #if 0
1210  if ( dim == AF_DIMENSION_HORZ )
1211  {
1212  if ( fitted < scaled )
1213  scale -= scale / 50; /* scale *= 0.98 */
1214  }
1215  else
1216 #endif
1217  if ( dim == AF_DIMENSION_VERT )
1218  {
1219  FT_Pos max_height;
1220  FT_Pos dist;
1221  FT_Fixed new_scale;
1222 
1223 
1224  new_scale = FT_MulDiv( scale, fitted, scaled );
1225 
1226  /* the scaling should not change the result by more than two pixels */
1227  max_height = metrics->units_per_em;
1228 
1229  for ( nn = 0; nn < Axis->blue_count; nn++ )
1230  {
1231  max_height = FT_MAX( max_height, Axis->blues[nn].ascender );
1232  max_height = FT_MAX( max_height, -Axis->blues[nn].descender );
1233  }
1234 
1235  dist = FT_ABS( FT_MulFix( max_height, new_scale - scale ) );
1236  dist &= ~127;
1237 
1238  if ( dist == 0 )
1239  {
1240  FT_TRACE5((
1241  "af_latin_metrics_scale_dim:"
1242  " x height alignment (style `%s'):\n"
1243  " "
1244  " vertical scaling changed from %.5f to %.5f (by %d%%)\n"
1245  "\n",
1246  af_style_names[metrics->root.style_class->style],
1247  scale / 65536.0,
1248  new_scale / 65536.0,
1249  ( fitted - scaled ) * 100 / scaled ));
1250 
1251  scale = new_scale;
1252  }
1253 #ifdef FT_DEBUG_LEVEL_TRACE
1254  else
1255  {
1256  FT_TRACE5((
1257  "af_latin_metrics_scale_dim:"
1258  " x height alignment (style `%s'):\n"
1259  " "
1260  " excessive vertical scaling abandoned\n"
1261  "\n",
1262  af_style_names[metrics->root.style_class->style] ));
1263  }
1264 #endif
1265  }
1266  }
1267  }
1268  }
1269 
1270  axis->scale = scale;
1271  axis->delta = delta;
1272 
1273  if ( dim == AF_DIMENSION_HORZ )
1274  {
1275  metrics->root.scaler.x_scale = scale;
1276  metrics->root.scaler.x_delta = delta;
1277  }
1278  else
1279  {
1280  metrics->root.scaler.y_scale = scale;
1281  metrics->root.scaler.y_delta = delta;
1282  }
1283 
1284  FT_TRACE5(( "%s widths (style `%s')\n",
1285  dim == AF_DIMENSION_HORZ ? "horizontal" : "vertical",
1286  af_style_names[metrics->root.style_class->style] ));
1287 
1288  /* scale the widths */
1289  for ( nn = 0; nn < axis->width_count; nn++ )
1290  {
1291  AF_Width width = axis->widths + nn;
1292 
1293 
1294  width->cur = FT_MulFix( width->org, scale );
1295  width->fit = width->cur;
1296 
1297  FT_TRACE5(( " %d scaled to %.2f\n",
1298  width->org,
1299  width->cur / 64.0 ));
1300  }
1301 
1302  FT_TRACE5(( "\n" ));
1303 
1304  /* an extra-light axis corresponds to a standard width that is */
1305  /* smaller than 5/8 pixels */
1306  axis->extra_light =
1307  (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
1308 
1309 #ifdef FT_DEBUG_LEVEL_TRACE
1310  if ( axis->extra_light )
1311  FT_TRACE5(( "`%s' style is extra light (at current resolution)\n"
1312  "\n",
1313  af_style_names[metrics->root.style_class->style] ));
1314 #endif
1315 
1316  if ( dim == AF_DIMENSION_VERT )
1317  {
1318 #ifdef FT_DEBUG_LEVEL_TRACE
1319  if ( axis->blue_count )
1320  FT_TRACE5(( "blue zones (style `%s')\n",
1321  af_style_names[metrics->root.style_class->style] ));
1322 #endif
1323 
1324  /* scale the blue zones */
1325  for ( nn = 0; nn < axis->blue_count; nn++ )
1326  {
1327  AF_LatinBlue blue = &axis->blues[nn];
1328  FT_Pos dist;
1329 
1330 
1331  blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
1332  blue->ref.fit = blue->ref.cur;
1333  blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
1334  blue->shoot.fit = blue->shoot.cur;
1335  blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
1336 
1337  /* a blue zone is only active if it is less than 3/4 pixels tall */
1338  dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
1339  if ( dist <= 48 && dist >= -48 )
1340  {
1341 #if 0
1342  FT_Pos delta1;
1343 #endif
1344  FT_Pos delta2;
1345 
1346 
1347  /* use discrete values for blue zone widths */
1348 
1349 #if 0
1350 
1351  /* generic, original code */
1352  delta1 = blue->shoot.org - blue->ref.org;
1353  delta2 = delta1;
1354  if ( delta1 < 0 )
1355  delta2 = -delta2;
1356 
1357  delta2 = FT_MulFix( delta2, scale );
1358 
1359  if ( delta2 < 32 )
1360  delta2 = 0;
1361  else if ( delta2 < 64 )
1362  delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
1363  else
1364  delta2 = FT_PIX_ROUND( delta2 );
1365 
1366  if ( delta1 < 0 )
1367  delta2 = -delta2;
1368 
1369  blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
1370  blue->shoot.fit = blue->ref.fit + delta2;
1371 
1372 #else
1373 
1374  /* simplified version due to abs(dist) <= 48 */
1375  delta2 = dist;
1376  if ( dist < 0 )
1377  delta2 = -delta2;
1378 
1379  if ( delta2 < 32 )
1380  delta2 = 0;
1381  else if ( delta2 < 48 )
1382  delta2 = 32;
1383  else
1384  delta2 = 64;
1385 
1386  if ( dist < 0 )
1387  delta2 = -delta2;
1388 
1389  blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
1390  blue->shoot.fit = blue->ref.fit - delta2;
1391 
1392 #endif
1393 
1394  blue->flags |= AF_LATIN_BLUE_ACTIVE;
1395  }
1396  }
1397 
1398  /* use sub-top blue zone only if it doesn't overlap with */
1399  /* another (non-sup-top) blue zone; otherwise, the */
1400  /* effect would be similar to a neutral blue zone, which */
1401  /* is not desired here */
1402  for ( nn = 0; nn < axis->blue_count; nn++ )
1403  {
1404  AF_LatinBlue blue = &axis->blues[nn];
1405  FT_UInt i;
1406 
1407 
1408  if ( !( blue->flags & AF_LATIN_BLUE_SUB_TOP ) )
1409  continue;
1410  if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
1411  continue;
1412 
1413  for ( i = 0; i < axis->blue_count; i++ )
1414  {
1415  AF_LatinBlue b = &axis->blues[i];
1416 
1417 
1418  if ( b->flags & AF_LATIN_BLUE_SUB_TOP )
1419  continue;
1420  if ( !( b->flags & AF_LATIN_BLUE_ACTIVE ) )
1421  continue;
1422 
1423  if ( b->ref.fit <= blue->shoot.fit &&
1424  b->shoot.fit >= blue->ref.fit )
1425  {
1427  break;
1428  }
1429  }
1430  }
1431 
1432 #ifdef FT_DEBUG_LEVEL_TRACE
1433  for ( nn = 0; nn < axis->blue_count; nn++ )
1434  {
1435  AF_LatinBlue blue = &axis->blues[nn];
1436 
1437 
1438  FT_TRACE5(( " reference %d: %d scaled to %.2f%s\n"
1439  " overshoot %d: %d scaled to %.2f%s\n",
1440  nn,
1441  blue->ref.org,
1442  blue->ref.fit / 64.0,
1443  blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
1444  : " (inactive)",
1445  nn,
1446  blue->shoot.org,
1447  blue->shoot.fit / 64.0,
1448  blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
1449  : " (inactive)" ));
1450  }
1451 #endif
1452  }
1453  }
1454 
1455 
1456  /* Scale global values in both directions. */
1457 
1458  FT_LOCAL_DEF( void )
1460  AF_Scaler scaler )
1461  {
1462  metrics->root.scaler.render_mode = scaler->render_mode;
1463  metrics->root.scaler.face = scaler->face;
1464  metrics->root.scaler.flags = scaler->flags;
1465 
1468  }
1469 
1470 
1471  /* Extract standard_width from writing system/script specific */
1472  /* metrics class. */
1473 
1474  FT_LOCAL_DEF( void )
1476  FT_Pos* stdHW,
1477  FT_Pos* stdVW )
1478  {
1479  if ( stdHW )
1480  *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
1481 
1482  if ( stdVW )
1483  *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
1484  }
1485 
1486 
1487  /*************************************************************************/
1488  /*************************************************************************/
1489  /***** *****/
1490  /***** L A T I N G L Y P H A N A L Y S I S *****/
1491  /***** *****/
1492  /*************************************************************************/
1493  /*************************************************************************/
1494 
1495 
1496  /* Walk over all contours and compute its segments. */
1497 
1500  AF_Dimension dim )
1501  {
1503  AF_AxisHints axis = &hints->axis[dim];
1504  FT_Memory memory = hints->memory;
1506  AF_Segment segment = NULL;
1507  AF_SegmentRec seg0;
1508  AF_Point* contour = hints->contours;
1509  AF_Point* contour_limit = contour + hints->num_contours;
1510  AF_Direction major_dir, segment_dir;
1511 
1512  FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
1513 
1514 
1515  FT_ZERO( &seg0 );
1516  seg0.score = 32000;
1517  seg0.flags = AF_EDGE_NORMAL;
1518 
1519  major_dir = (AF_Direction)FT_ABS( axis->major_dir );
1520  segment_dir = major_dir;
1521 
1522  axis->num_segments = 0;
1523 
1524  /* set up (u,v) in each point */
1525  if ( dim == AF_DIMENSION_HORZ )
1526  {
1527  AF_Point point = hints->points;
1528  AF_Point limit = point + hints->num_points;
1529 
1530 
1531  for ( ; point < limit; point++ )
1532  {
1533  point->u = point->fx;
1534  point->v = point->fy;
1535  }
1536  }
1537  else
1538  {
1539  AF_Point point = hints->points;
1540  AF_Point limit = point + hints->num_points;
1541 
1542 
1543  for ( ; point < limit; point++ )
1544  {
1545  point->u = point->fy;
1546  point->v = point->fx;
1547  }
1548  }
1549 
1550  /* do each contour separately */
1551  for ( ; contour < contour_limit; contour++ )
1552  {
1553  AF_Point point = contour[0];
1554  AF_Point last = point->prev;
1555  int on_edge = 0;
1556 
1557  /* we call values measured along a segment (point->v) */
1558  /* `coordinates', and values orthogonal to it (point->u) */
1559  /* `positions' */
1560  FT_Pos min_pos = 32000;
1561  FT_Pos max_pos = -32000;
1562  FT_Pos min_coord = 32000;
1563  FT_Pos max_coord = -32000;
1564  FT_UShort min_flags = AF_FLAG_NONE;
1565  FT_UShort max_flags = AF_FLAG_NONE;
1566  FT_Pos min_on_coord = 32000;
1567  FT_Pos max_on_coord = -32000;
1568 
1569  FT_Bool passed;
1570 
1571  AF_Segment prev_segment = NULL;
1572 
1573  FT_Pos prev_min_pos = min_pos;
1574  FT_Pos prev_max_pos = max_pos;
1575  FT_Pos prev_min_coord = min_coord;
1576  FT_Pos prev_max_coord = max_coord;
1577  FT_UShort prev_min_flags = min_flags;
1578  FT_UShort prev_max_flags = max_flags;
1579  FT_Pos prev_min_on_coord = min_on_coord;
1580  FT_Pos prev_max_on_coord = max_on_coord;
1581 
1582 
1583  if ( FT_ABS( last->out_dir ) == major_dir &&
1584  FT_ABS( point->out_dir ) == major_dir )
1585  {
1586  /* we are already on an edge, try to locate its start */
1587  last = point;
1588 
1589  for (;;)
1590  {
1591  point = point->prev;
1592  if ( FT_ABS( point->out_dir ) != major_dir )
1593  {
1594  point = point->next;
1595  break;
1596  }
1597  if ( point == last )
1598  break;
1599  }
1600  }
1601 
1602  last = point;
1603  passed = 0;
1604 
1605  for (;;)
1606  {
1607  FT_Pos u, v;
1608 
1609 
1610  if ( on_edge )
1611  {
1612  /* get minimum and maximum position */
1613  u = point->u;
1614  if ( u < min_pos )
1615  min_pos = u;
1616  if ( u > max_pos )
1617  max_pos = u;
1618 
1619  /* get minimum and maximum coordinate together with flags */
1620  v = point->v;
1621  if ( v < min_coord )
1622  {
1623  min_coord = v;
1624  min_flags = point->flags;
1625  }
1626  if ( v > max_coord )
1627  {
1628  max_coord = v;
1629  max_flags = point->flags;
1630  }
1631 
1632  /* get minimum and maximum coordinate of `on' points */
1633  if ( !( point->flags & AF_FLAG_CONTROL ) )
1634  {
1635  v = point->v;
1636  if ( v < min_on_coord )
1637  min_on_coord = v;
1638  if ( v > max_on_coord )
1639  max_on_coord = v;
1640  }
1641 
1642  if ( point->out_dir != segment_dir || point == last )
1643  {
1644  /* check whether the new segment's start point is identical to */
1645  /* the previous segment's end point; for example, this might */
1646  /* happen for spikes */
1647 
1648  if ( !prev_segment || segment->first != prev_segment->last )
1649  {
1650  /* points are different: we are just leaving an edge, thus */
1651  /* record a new segment */
1652 
1653  segment->last = point;
1654  segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 );
1655  segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 );
1656 
1657  /* a segment is round if either its first or last point */
1658  /* is a control point, and the length of the on points */
1659  /* inbetween doesn't exceed a heuristic limit */
1660  if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1661  ( max_on_coord - min_on_coord ) < flat_threshold )
1662  segment->flags |= AF_EDGE_ROUND;
1663 
1664  segment->min_coord = (FT_Short)min_coord;
1665  segment->max_coord = (FT_Short)max_coord;
1666  segment->height = segment->max_coord - segment->min_coord;
1667 
1668  prev_segment = segment;
1669  prev_min_pos = min_pos;
1670  prev_max_pos = max_pos;
1671  prev_min_coord = min_coord;
1672  prev_max_coord = max_coord;
1673  prev_min_flags = min_flags;
1674  prev_max_flags = max_flags;
1675  prev_min_on_coord = min_on_coord;
1676  prev_max_on_coord = max_on_coord;
1677  }
1678  else
1679  {
1680  /* points are the same: we don't create a new segment but */
1681  /* merge the current segment with the previous one */
1682 
1683  if ( prev_segment->last->in_dir == point->in_dir )
1684  {
1685  /* we have identical directions (this can happen for */
1686  /* degenerate outlines that move zig-zag along the main */
1687  /* axis without changing the coordinate value of the other */
1688  /* axis, and where the segments have just been merged): */
1689  /* unify segments */
1690 
1691  /* update constraints */
1692 
1693  if ( prev_min_pos < min_pos )
1694  min_pos = prev_min_pos;
1695  if ( prev_max_pos > max_pos )
1696  max_pos = prev_max_pos;
1697 
1698  if ( prev_min_coord < min_coord )
1699  {
1700  min_coord = prev_min_coord;
1701  min_flags = prev_min_flags;
1702  }
1703  if ( prev_max_coord > max_coord )
1704  {
1705  max_coord = prev_max_coord;
1706  max_flags = prev_max_flags;
1707  }
1708 
1709  if ( prev_min_on_coord < min_on_coord )
1710  min_on_coord = prev_min_on_coord;
1711  if ( prev_max_on_coord > max_on_coord )
1712  max_on_coord = prev_max_on_coord;
1713 
1714  prev_segment->last = point;
1715  prev_segment->pos = (FT_Short)( ( min_pos +
1716  max_pos ) >> 1 );
1717  prev_segment->delta = (FT_Short)( ( max_pos -
1718  min_pos ) >> 1 );
1719 
1720  if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1721  ( max_on_coord - min_on_coord ) < flat_threshold )
1722  prev_segment->flags |= AF_EDGE_ROUND;
1723  else
1724  prev_segment->flags &= ~AF_EDGE_ROUND;
1725 
1726  prev_segment->min_coord = (FT_Short)min_coord;
1727  prev_segment->max_coord = (FT_Short)max_coord;
1728  prev_segment->height = prev_segment->max_coord -
1729  prev_segment->min_coord;
1730  }
1731  else
1732  {
1733  /* we have different directions; use the properties of the */
1734  /* longer segment and discard the other one */
1735 
1736  if ( FT_ABS( prev_max_coord - prev_min_coord ) >
1737  FT_ABS( max_coord - min_coord ) )
1738  {
1739  /* discard current segment */
1740 
1741  if ( min_pos < prev_min_pos )
1742  prev_min_pos = min_pos;
1743  if ( max_pos > prev_max_pos )
1744  prev_max_pos = max_pos;
1745 
1746  prev_segment->last = point;
1747  prev_segment->pos = (FT_Short)( ( prev_min_pos +
1748  prev_max_pos ) >> 1 );
1749  prev_segment->delta = (FT_Short)( ( prev_max_pos -
1750  prev_min_pos ) >> 1 );
1751  }
1752  else
1753  {
1754  /* discard previous segment */
1755 
1756  if ( prev_min_pos < min_pos )
1757  min_pos = prev_min_pos;
1758  if ( prev_max_pos > max_pos )
1759  max_pos = prev_max_pos;
1760 
1761  segment->last = point;
1762  segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 );
1763  segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 );
1764 
1765  if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1766  ( max_on_coord - min_on_coord ) < flat_threshold )
1767  segment->flags |= AF_EDGE_ROUND;
1768 
1769  segment->min_coord = (FT_Short)min_coord;
1770  segment->max_coord = (FT_Short)max_coord;
1771  segment->height = segment->max_coord -
1772  segment->min_coord;
1773 
1774  *prev_segment = *segment;
1775 
1776  prev_min_pos = min_pos;
1777  prev_max_pos = max_pos;
1778  prev_min_coord = min_coord;
1779  prev_max_coord = max_coord;
1780  prev_min_flags = min_flags;
1781  prev_max_flags = max_flags;
1782  prev_min_on_coord = min_on_coord;
1783  prev_max_on_coord = max_on_coord;
1784  }
1785  }
1786 
1787  axis->num_segments--;
1788  }
1789 
1790  on_edge = 0;
1791  segment = NULL;
1792 
1793  /* fall through */
1794  }
1795  }
1796 
1797  /* now exit if we are at the start/end point */
1798  if ( point == last )
1799  {
1800  if ( passed )
1801  break;
1802  passed = 1;
1803  }
1804 
1805  /* if we are not on an edge, check whether the major direction */
1806  /* coincides with the current point's `out' direction, or */
1807  /* whether we have a single-point contour */
1808  if ( !on_edge &&
1809  ( FT_ABS( point->out_dir ) == major_dir ||
1810  point == point->prev ) )
1811  {
1812  /* this is the start of a new segment! */
1813  segment_dir = (AF_Direction)point->out_dir;
1814 
1815  error = af_axis_hints_new_segment( axis, memory, &segment );
1816  if ( error )
1817  goto Exit;
1818 
1819  /* clear all segment fields */
1820  segment[0] = seg0;
1821 
1822  segment->dir = (FT_Char)segment_dir;
1823  segment->first = point;
1824  segment->last = point;
1825 
1826  /* `af_axis_hints_new_segment' reallocates memory, */
1827  /* thus we have to refresh the `prev_segment' pointer */
1828  if ( prev_segment )
1829  prev_segment = segment - 1;
1830 
1831  min_pos = max_pos = point->u;
1832  min_coord = max_coord = point->v;
1833  min_flags = max_flags = point->flags;
1834 
1835  if ( point->flags & AF_FLAG_CONTROL )
1836  {
1837  min_on_coord = 32000;
1838  max_on_coord = -32000;
1839  }
1840  else
1841  min_on_coord = max_on_coord = point->v;
1842 
1843  on_edge = 1;
1844 
1845  if ( point == point->prev )
1846  {
1847  /* we have a one-point segment: this is a one-point */
1848  /* contour with `in' and `out' direction set to */
1849  /* AF_DIR_NONE */
1850  segment->pos = (FT_Short)min_pos;
1851 
1852  if (point->flags & AF_FLAG_CONTROL)
1853  segment->flags |= AF_EDGE_ROUND;
1854 
1855  segment->min_coord = (FT_Short)point->v;
1856  segment->max_coord = (FT_Short)point->v;
1857  segment->height = 0;
1858 
1859  on_edge = 0;
1860  segment = NULL;
1861  }
1862  }
1863 
1864  point = point->next;
1865  }
1866 
1867  } /* contours */
1868 
1869 
1870  /* now slightly increase the height of segments if this makes */
1871  /* sense -- this is used to better detect and ignore serifs */
1872  {
1873  AF_Segment segments = axis->segments;
1874  AF_Segment segments_end = segments + axis->num_segments;
1875 
1876 
1877  for ( segment = segments; segment < segments_end; segment++ )
1878  {
1879  AF_Point first = segment->first;
1880  AF_Point last = segment->last;
1881  FT_Pos first_v = first->v;
1882  FT_Pos last_v = last->v;
1883 
1884 
1885  if ( first_v < last_v )
1886  {
1887  AF_Point p;
1888 
1889 
1890  p = first->prev;
1891  if ( p->v < first_v )
1892  segment->height = (FT_Short)( segment->height +
1893  ( ( first_v - p->v ) >> 1 ) );
1894 
1895  p = last->next;
1896  if ( p->v > last_v )
1897  segment->height = (FT_Short)( segment->height +
1898  ( ( p->v - last_v ) >> 1 ) );
1899  }
1900  else
1901  {
1902  AF_Point p;
1903 
1904 
1905  p = first->prev;
1906  if ( p->v > first_v )
1907  segment->height = (FT_Short)( segment->height +
1908  ( ( p->v - first_v ) >> 1 ) );
1909 
1910  p = last->next;
1911  if ( p->v < last_v )
1912  segment->height = (FT_Short)( segment->height +
1913  ( ( last_v - p->v ) >> 1 ) );
1914  }
1915  }
1916  }
1917 
1918  Exit:
1919  return error;
1920  }
1921 
1922 
1923  /* Link segments to form stems and serifs. If `width_count' and */
1924  /* `widths' are non-zero, use them to fine-tune the scoring function. */
1925 
1926  FT_LOCAL_DEF( void )
1928  FT_UInt width_count,
1929  AF_WidthRec* widths,
1930  AF_Dimension dim )
1931  {
1932  AF_AxisHints axis = &hints->axis[dim];
1933  AF_Segment segments = axis->segments;
1934  AF_Segment segment_limit = segments + axis->num_segments;
1935  FT_Pos len_threshold, len_score, dist_score, max_width;
1936  AF_Segment seg1, seg2;
1937 
1938 
1939  if ( width_count )
1940  max_width = widths[width_count - 1].org;
1941  else
1942  max_width = 0;
1943 
1944  /* a heuristic value to set up a minimum value for overlapping */
1945  len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
1946  if ( len_threshold == 0 )
1947  len_threshold = 1;
1948 
1949  /* a heuristic value to weight lengths */
1950  len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
1951 
1952  /* a heuristic value to weight distances (no call to */
1953  /* AF_LATIN_CONSTANT needed, since we work on multiples */
1954  /* of the stem width) */
1955  dist_score = 3000;
1956 
1957  /* now compare each segment to the others */
1958  for ( seg1 = segments; seg1 < segment_limit; seg1++ )
1959  {
1960  if ( seg1->dir != axis->major_dir )
1961  continue;
1962 
1963  /* search for stems having opposite directions, */
1964  /* with seg1 to the `left' of seg2 */
1965  for ( seg2 = segments; seg2 < segment_limit; seg2++ )
1966  {
1967  FT_Pos pos1 = seg1->pos;
1968  FT_Pos pos2 = seg2->pos;
1969 
1970 
1971  if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 )
1972  {
1973  /* compute distance between the two segments */
1974  FT_Pos min = seg1->min_coord;
1975  FT_Pos max = seg1->max_coord;
1976  FT_Pos len;
1977 
1978 
1979  if ( min < seg2->min_coord )
1980  min = seg2->min_coord;
1981 
1982  if ( max > seg2->max_coord )
1983  max = seg2->max_coord;
1984 
1985  /* compute maximum coordinate difference of the two segments */
1986  /* (this is, how much they overlap) */
1987  len = max - min;
1988  if ( len >= len_threshold )
1989  {
1990  /*
1991  * The score is the sum of two demerits indicating the
1992  * `badness' of a fit, measured along the segments' main axis
1993  * and orthogonal to it, respectively.
1994  *
1995  * o The less overlapping along the main axis, the worse it
1996  * is, causing a larger demerit.
1997  *
1998  * o The nearer the orthogonal distance to a stem width, the
1999  * better it is, causing a smaller demerit. For simplicity,
2000  * however, we only increase the demerit for values that
2001  * exceed the largest stem width.
2002  */
2003 
2004  FT_Pos dist = pos2 - pos1;
2005 
2006  FT_Pos dist_demerit, score;
2007 
2008 
2009  if ( max_width )
2010  {
2011  /* distance demerits are based on multiples of `max_width'; */
2012  /* we scale by 1024 for getting more precision */
2013  FT_Pos delta = ( dist << 10 ) / max_width - ( 1 << 10 );
2014 
2015 
2016  if ( delta > 10000 )
2017  dist_demerit = 32000;
2018  else if ( delta > 0 )
2019  dist_demerit = delta * delta / dist_score;
2020  else
2021  dist_demerit = 0;
2022  }
2023  else
2024  dist_demerit = dist; /* default if no widths available */
2025 
2026  score = dist_demerit + len_score / len;
2027 
2028  /* and we search for the smallest score */
2029  if ( score < seg1->score )
2030  {
2031  seg1->score = score;
2032  seg1->link = seg2;
2033  }
2034 
2035  if ( score < seg2->score )
2036  {
2037  seg2->score = score;
2038  seg2->link = seg1;
2039  }
2040  }
2041  }
2042  }
2043  }
2044 
2045  /* now compute the `serif' segments, cf. explanations in `afhints.h' */
2046  for ( seg1 = segments; seg1 < segment_limit; seg1++ )
2047  {
2048  seg2 = seg1->link;
2049 
2050  if ( seg2 )
2051  {
2052  if ( seg2->link != seg1 )
2053  {
2054  seg1->link = 0;
2055  seg1->serif = seg2->link;
2056  }
2057  }
2058  }
2059  }
2060 
2061 
2062  /* Link segments to edges, using feature analysis for selection. */
2063 
2066  AF_Dimension dim )
2067  {
2068  AF_AxisHints axis = &hints->axis[dim];
2070  FT_Memory memory = hints->memory;
2071  AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
2072 
2073 #ifdef FT_CONFIG_OPTION_PIC
2074  AF_FaceGlobals globals = hints->metrics->globals;
2075 #endif
2076 
2077  AF_StyleClass style_class = hints->metrics->style_class;
2078  AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET
2079  [style_class->script];
2080 
2081  FT_Bool top_to_bottom_hinting = 0;
2082 
2083  AF_Segment segments = axis->segments;
2084  AF_Segment segment_limit = segments + axis->num_segments;
2085  AF_Segment seg;
2086 
2087 #if 0
2088  AF_Direction up_dir;
2089 #endif
2090  FT_Fixed scale;
2091  FT_Pos edge_distance_threshold;
2092  FT_Pos segment_length_threshold;
2093  FT_Pos segment_width_threshold;
2094 
2095 
2096  axis->num_edges = 0;
2097 
2098  scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
2099  : hints->y_scale;
2100 
2101 #if 0
2102  up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
2103  : AF_DIR_RIGHT;
2104 #endif
2105 
2106  if ( dim == AF_DIMENSION_VERT )
2107  top_to_bottom_hinting = script_class->top_to_bottom_hinting;
2108 
2109  /*
2110  * We ignore all segments that are less than 1 pixel in length
2111  * to avoid many problems with serif fonts. We compute the
2112  * corresponding threshold in font units.
2113  */
2114  if ( dim == AF_DIMENSION_HORZ )
2115  segment_length_threshold = FT_DivFix( 64, hints->y_scale );
2116  else
2117  segment_length_threshold = 0;
2118 
2119  /*
2120  * Similarly, we ignore segments that have a width delta
2121  * larger than 0.5px (i.e., a width larger than 1px).
2122  */
2123  segment_width_threshold = FT_DivFix( 32, scale );
2124 
2125  /*********************************************************************/
2126  /* */
2127  /* We begin by generating a sorted table of edges for the current */
2128  /* direction. To do so, we simply scan each segment and try to find */
2129  /* an edge in our table that corresponds to its position. */
2130  /* */
2131  /* If no edge is found, we create and insert a new edge in the */
2132  /* sorted table. Otherwise, we simply add the segment to the edge's */
2133  /* list which gets processed in the second step to compute the */
2134  /* edge's properties. */
2135  /* */
2136  /* Note that the table of edges is sorted along the segment/edge */
2137  /* position. */
2138  /* */
2139  /*********************************************************************/
2140 
2141  /* assure that edge distance threshold is at most 0.25px */
2142  edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
2143  scale );
2144  if ( edge_distance_threshold > 64 / 4 )
2145  edge_distance_threshold = 64 / 4;
2146 
2147  edge_distance_threshold = FT_DivFix( edge_distance_threshold,
2148  scale );
2149 
2150  for ( seg = segments; seg < segment_limit; seg++ )
2151  {
2152  AF_Edge found = NULL;
2153  FT_Int ee;
2154 
2155 
2156  /* ignore too short segments, too wide ones, and, in this loop, */
2157  /* one-point segments without a direction */
2158  if ( seg->height < segment_length_threshold ||
2159  seg->delta > segment_width_threshold ||
2160  seg->dir == AF_DIR_NONE )
2161  continue;
2162 
2163  /* A special case for serif edges: If they are smaller than */
2164  /* 1.5 pixels we ignore them. */
2165  if ( seg->serif &&
2166  2 * seg->height < 3 * segment_length_threshold )
2167  continue;
2168 
2169  /* look for an edge corresponding to the segment */
2170  for ( ee = 0; ee < axis->num_edges; ee++ )
2171  {
2172  AF_Edge edge = axis->edges + ee;
2173  FT_Pos dist;
2174 
2175 
2176  dist = seg->pos - edge->fpos;
2177  if ( dist < 0 )
2178  dist = -dist;
2179 
2180  if ( dist < edge_distance_threshold && edge->dir == seg->dir )
2181  {
2182  found = edge;
2183  break;
2184  }
2185  }
2186 
2187  if ( !found )
2188  {
2189  AF_Edge edge;
2190 
2191 
2192  /* insert a new edge in the list and */
2193  /* sort according to the position */
2194  error = af_axis_hints_new_edge( axis, seg->pos,
2195  (AF_Direction)seg->dir,
2196  top_to_bottom_hinting,
2197  memory, &edge );
2198  if ( error )
2199  goto Exit;
2200 
2201  /* add the segment to the new edge's list */
2202  FT_ZERO( edge );
2203 
2204  edge->first = seg;
2205  edge->last = seg;
2206  edge->dir = seg->dir;
2207  edge->fpos = seg->pos;
2208  edge->opos = FT_MulFix( seg->pos, scale );
2209  edge->pos = edge->opos;
2210  seg->edge_next = seg;
2211  }
2212  else
2213  {
2214  /* if an edge was found, simply add the segment to the edge's */
2215  /* list */
2216  seg->edge_next = found->first;
2217  found->last->edge_next = seg;
2218  found->last = seg;
2219  }
2220  }
2221 
2222  /* we loop again over all segments to catch one-point segments */
2223  /* without a direction: if possible, link them to existing edges */
2224  for ( seg = segments; seg < segment_limit; seg++ )
2225  {
2226  AF_Edge found = NULL;
2227  FT_Int ee;
2228 
2229 
2230  if ( seg->dir != AF_DIR_NONE )
2231  continue;
2232 
2233  /* look for an edge corresponding to the segment */
2234  for ( ee = 0; ee < axis->num_edges; ee++ )
2235  {
2236  AF_Edge edge = axis->edges + ee;
2237  FT_Pos dist;
2238 
2239 
2240  dist = seg->pos - edge->fpos;
2241  if ( dist < 0 )
2242  dist = -dist;
2243 
2244  if ( dist < edge_distance_threshold )
2245  {
2246  found = edge;
2247  break;
2248  }
2249  }
2250 
2251  /* one-point segments without a match are ignored */
2252  if ( found )
2253  {
2254  seg->edge_next = found->first;
2255  found->last->edge_next = seg;
2256  found->last = seg;
2257  }
2258  }
2259 
2260 
2261  /******************************************************************/
2262  /* */
2263  /* Good, we now compute each edge's properties according to the */
2264  /* segments found on its position. Basically, these are */
2265  /* */
2266  /* - the edge's main direction */
2267  /* - stem edge, serif edge or both (which defaults to stem then) */
2268  /* - rounded edge, straight or both (which defaults to straight) */
2269  /* - link for edge */
2270  /* */
2271  /******************************************************************/
2272 
2273  /* first of all, set the `edge' field in each segment -- this is */
2274  /* required in order to compute edge links */
2275 
2276  /*
2277  * Note that removing this loop and setting the `edge' field of each
2278  * segment directly in the code above slows down execution speed for
2279  * some reasons on platforms like the Sun.
2280  */
2281  {
2282  AF_Edge edges = axis->edges;
2283  AF_Edge edge_limit = edges + axis->num_edges;
2284  AF_Edge edge;
2285 
2286 
2287  for ( edge = edges; edge < edge_limit; edge++ )
2288  {
2289  seg = edge->first;
2290  if ( seg )
2291  do
2292  {
2293  seg->edge = edge;
2294  seg = seg->edge_next;
2295 
2296  } while ( seg != edge->first );
2297  }
2298 
2299  /* now compute each edge properties */
2300  for ( edge = edges; edge < edge_limit; edge++ )
2301  {
2302  FT_Int is_round = 0; /* does it contain round segments? */
2303  FT_Int is_straight = 0; /* does it contain straight segments? */
2304 #if 0
2305  FT_Pos ups = 0; /* number of upwards segments */
2306  FT_Pos downs = 0; /* number of downwards segments */
2307 #endif
2308 
2309 
2310  seg = edge->first;
2311 
2312  do
2313  {
2314  FT_Bool is_serif;
2315 
2316 
2317  /* check for roundness of segment */
2318  if ( seg->flags & AF_EDGE_ROUND )
2319  is_round++;
2320  else
2321  is_straight++;
2322 
2323 #if 0
2324  /* check for segment direction */
2325  if ( seg->dir == up_dir )
2326  ups += seg->max_coord - seg->min_coord;
2327  else
2328  downs += seg->max_coord - seg->min_coord;
2329 #endif
2330 
2331  /* check for links -- if seg->serif is set, then seg->link must */
2332  /* be ignored */
2333  is_serif = (FT_Bool)( seg->serif &&
2334  seg->serif->edge &&
2335  seg->serif->edge != edge );
2336 
2337  if ( ( seg->link && seg->link->edge ) || is_serif )
2338  {
2339  AF_Edge edge2;
2340  AF_Segment seg2;
2341 
2342 
2343  edge2 = edge->link;
2344  seg2 = seg->link;
2345 
2346  if ( is_serif )
2347  {
2348  seg2 = seg->serif;
2349  edge2 = edge->serif;
2350  }
2351 
2352  if ( edge2 )
2353  {
2354  FT_Pos edge_delta;
2355  FT_Pos seg_delta;
2356 
2357 
2358  edge_delta = edge->fpos - edge2->fpos;
2359  if ( edge_delta < 0 )
2360  edge_delta = -edge_delta;
2361 
2362  seg_delta = seg->pos - seg2->pos;
2363  if ( seg_delta < 0 )
2364  seg_delta = -seg_delta;
2365 
2366  if ( seg_delta < edge_delta )
2367  edge2 = seg2->edge;
2368  }
2369  else
2370  edge2 = seg2->edge;
2371 
2372  if ( is_serif )
2373  {
2374  edge->serif = edge2;
2375  edge2->flags |= AF_EDGE_SERIF;
2376  }
2377  else
2378  edge->link = edge2;
2379  }
2380 
2381  seg = seg->edge_next;
2382 
2383  } while ( seg != edge->first );
2384 
2385  /* set the round/straight flags */
2386  edge->flags = AF_EDGE_NORMAL;
2387 
2388  if ( is_round > 0 && is_round >= is_straight )
2389  edge->flags |= AF_EDGE_ROUND;
2390 
2391 #if 0
2392  /* set the edge's main direction */
2393  edge->dir = AF_DIR_NONE;
2394 
2395  if ( ups > downs )
2396  edge->dir = (FT_Char)up_dir;
2397 
2398  else if ( ups < downs )
2399  edge->dir = (FT_Char)-up_dir;
2400 
2401  else if ( ups == downs )
2402  edge->dir = 0; /* both up and down! */
2403 #endif
2404 
2405  /* get rid of serifs if link is set */
2406  /* XXX: This gets rid of many unpleasant artefacts! */
2407  /* Example: the `c' in cour.pfa at size 13 */
2408 
2409  if ( edge->serif && edge->link )
2410  edge->serif = NULL;
2411  }
2412  }
2413 
2414  Exit:
2415  return error;
2416  }
2417 
2418 
2419  /* Detect segments and edges for given dimension. */
2420 
2423  FT_UInt width_count,
2424  AF_WidthRec* widths,
2425  AF_Dimension dim )
2426  {
2427  FT_Error error;
2428 
2429 
2431  if ( !error )
2432  {
2433  af_latin_hints_link_segments( hints, width_count, widths, dim );
2434 
2436  }
2437 
2438  return error;
2439  }
2440 
2441 
2442  /* Compute all edges which lie within blue zones. */
2443 
2444  static void
2447  {
2448  AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT];
2449  AF_Edge edge = axis->edges;
2450  AF_Edge edge_limit = edge + axis->num_edges;
2451  AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT];
2452  FT_Fixed scale = latin->scale;
2453 
2454 
2455  /* compute which blue zones are active, i.e. have their scaled */
2456  /* size < 3/4 pixels */
2457 
2458  /* for each horizontal edge search the blue zone which is closest */
2459  for ( ; edge < edge_limit; edge++ )
2460  {
2461  FT_UInt bb;
2462  AF_Width best_blue = NULL;
2463  FT_Bool best_blue_is_neutral = 0;
2464  FT_Pos best_dist; /* initial threshold */
2465 
2466 
2467  /* compute the initial threshold as a fraction of the EM size */
2468  /* (the value 40 is heuristic) */
2469  best_dist = FT_MulFix( metrics->units_per_em / 40, scale );
2470 
2471  /* assure a minimum distance of 0.5px */
2472  if ( best_dist > 64 / 2 )
2473  best_dist = 64 / 2;
2474 
2475  for ( bb = 0; bb < latin->blue_count; bb++ )
2476  {
2477  AF_LatinBlue blue = latin->blues + bb;
2478  FT_Bool is_top_blue, is_neutral_blue, is_major_dir;
2479 
2480 
2481  /* skip inactive blue zones (i.e., those that are too large) */
2482  if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
2483  continue;
2484 
2485  /* if it is a top zone, check for right edges (against the major */
2486  /* direction); if it is a bottom zone, check for left edges (in */
2487  /* the major direction) -- this assumes the TrueType convention */
2488  /* for the orientation of contours */
2489  is_top_blue =
2490  (FT_Byte)( ( blue->flags & ( AF_LATIN_BLUE_TOP |
2491  AF_LATIN_BLUE_SUB_TOP ) ) != 0 );
2492  is_neutral_blue =
2493  (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_NEUTRAL ) != 0);
2494  is_major_dir =
2495  FT_BOOL( edge->dir == axis->major_dir );
2496 
2497  /* neutral blue zones are handled for both directions */
2498  if ( is_top_blue ^ is_major_dir || is_neutral_blue )
2499  {
2500  FT_Pos dist;
2501 
2502 
2503  /* first of all, compare it to the reference position */
2504  dist = edge->fpos - blue->ref.org;
2505  if ( dist < 0 )
2506  dist = -dist;
2507 
2508  dist = FT_MulFix( dist, scale );
2509  if ( dist < best_dist )
2510  {
2511  best_dist = dist;
2512  best_blue = &blue->ref;
2513  best_blue_is_neutral = is_neutral_blue;
2514  }
2515 
2516  /* now compare it to the overshoot position and check whether */
2517  /* the edge is rounded, and whether the edge is over the */
2518  /* reference position of a top zone, or under the reference */
2519  /* position of a bottom zone (provided we don't have a */
2520  /* neutral blue zone) */
2521  if ( edge->flags & AF_EDGE_ROUND &&
2522  dist != 0 &&
2523  !is_neutral_blue )
2524  {
2525  FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
2526 
2527 
2528  if ( is_top_blue ^ is_under_ref )
2529  {
2530  dist = edge->fpos - blue->shoot.org;
2531  if ( dist < 0 )
2532  dist = -dist;
2533 
2534  dist = FT_MulFix( dist, scale );
2535  if ( dist < best_dist )
2536  {
2537  best_dist = dist;
2538  best_blue = &blue->shoot;
2539  best_blue_is_neutral = is_neutral_blue;
2540  }
2541  }
2542  }
2543  }
2544  }
2545 
2546  if ( best_blue )
2547  {
2548  edge->blue_edge = best_blue;
2549  if ( best_blue_is_neutral )
2550  edge->flags |= AF_EDGE_NEUTRAL;
2551  }
2552  }
2553  }
2554 
2555 
2556  /* Initalize hinting engine. */
2557 
2558  static FT_Error
2561  {
2563  FT_UInt32 scaler_flags, other_flags;
2564  FT_Face face = metrics->root.scaler.face;
2565 
2566 
2568 
2569  /*
2570  * correct x_scale and y_scale if needed, since they may have
2571  * been modified by `af_latin_metrics_scale_dim' above
2572  */
2573  hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
2574  hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
2575  hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
2576  hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
2577 
2578  /* compute flags depending on render mode, etc. */
2579  mode = metrics->root.scaler.render_mode;
2580 
2581 #if 0 /* #ifdef AF_CONFIG_OPTION_USE_WARPER */
2583  metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
2584 #endif
2585 
2586  scaler_flags = hints->scaler_flags;
2587  other_flags = 0;
2588 
2589  /*
2590  * We snap the width of vertical stems for the monochrome and
2591  * horizontal LCD rendering targets only.
2592  */
2594  other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
2595 
2596  /*
2597  * We snap the width of horizontal stems for the monochrome and
2598  * vertical LCD rendering targets only.
2599  */
2601  other_flags |= AF_LATIN_HINTS_VERT_SNAP;
2602 
2603  /*
2604  * We adjust stems to full pixels unless in `light' or `lcd' mode.
2605  */
2607  other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
2608 
2609  if ( mode == FT_RENDER_MODE_MONO )
2610  other_flags |= AF_LATIN_HINTS_MONO;
2611 
2612  /*
2613  * In `light' or `lcd' mode we disable horizontal hinting completely.
2614  * We also do it if the face is italic.
2615  *
2616  * However, if warping is enabled (which only works in `light' hinting
2617  * mode), advance widths get adjusted, too.
2618  */
2620  ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 )
2621  scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
2622 
2623 #ifdef AF_CONFIG_OPTION_USE_WARPER
2624  /* get (global) warper flag */
2625  if ( !metrics->root.globals->module->warping )
2626  scaler_flags |= AF_SCALER_FLAG_NO_WARPER;
2627 #endif
2628 
2629  hints->scaler_flags = scaler_flags;
2630  hints->other_flags = other_flags;
2631 
2632  return FT_Err_Ok;
2633  }
2634 
2635 
2636  /*************************************************************************/
2637  /*************************************************************************/
2638  /***** *****/
2639  /***** L A T I N G L Y P H G R I D - F I T T I N G *****/
2640  /***** *****/
2641  /*************************************************************************/
2642  /*************************************************************************/
2643 
2644  /* Snap a given width in scaled coordinates to one of the */
2645  /* current standard widths. */
2646 
2647  static FT_Pos
2649  FT_UInt count,
2650  FT_Pos width )
2651  {
2652  FT_UInt n;
2653  FT_Pos best = 64 + 32 + 2;
2655  FT_Pos scaled;
2656 
2657 
2658  for ( n = 0; n < count; n++ )
2659  {
2660  FT_Pos w;
2661  FT_Pos dist;
2662 
2663 
2664  w = widths[n].cur;
2665  dist = width - w;
2666  if ( dist < 0 )
2667  dist = -dist;
2668  if ( dist < best )
2669  {
2670  best = dist;
2671  reference = w;
2672  }
2673  }
2674 
2675  scaled = FT_PIX_ROUND( reference );
2676 
2677  if ( width >= reference )
2678  {
2679  if ( width < scaled + 48 )
2680  width = reference;
2681  }
2682  else
2683  {
2684  if ( width > scaled - 48 )
2685  width = reference;
2686  }
2687 
2688  return width;
2689  }
2690 
2691 
2692  /* Compute the snapped width of a given stem, ignoring very thin ones. */
2693  /* There is a lot of voodoo in this function; changing the hard-coded */
2694  /* parameters influence the whole hinting process. */
2695 
2696  static FT_Pos
2698  AF_Dimension dim,
2699  FT_Pos width,
2700  FT_Pos base_delta,
2701  FT_UInt base_flags,
2702  FT_UInt stem_flags )
2703  {
2705  AF_LatinAxis axis = &metrics->axis[dim];
2706  FT_Pos dist = width;
2707  FT_Int sign = 0;
2708  FT_Int vertical = ( dim == AF_DIMENSION_VERT );
2709 
2710 
2712  axis->extra_light )
2713  return width;
2714 
2715  if ( dist < 0 )
2716  {
2717  dist = -width;
2718  sign = 1;
2719  }
2720 
2721  if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
2722  ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
2723  {
2724  /* smooth hinting process: very lightly quantize the stem width */
2725 
2726  /* leave the widths of serifs alone */
2727  if ( ( stem_flags & AF_EDGE_SERIF ) &&
2728  vertical &&
2729  ( dist < 3 * 64 ) )
2730  goto Done_Width;
2731 
2732  else if ( base_flags & AF_EDGE_ROUND )
2733  {
2734  if ( dist < 80 )
2735  dist = 64;
2736  }
2737  else if ( dist < 56 )
2738  dist = 56;
2739 
2740  if ( axis->width_count > 0 )
2741  {
2742  FT_Pos delta;
2743 
2744 
2745  /* compare to standard width */
2746  delta = dist - axis->widths[0].cur;
2747 
2748  if ( delta < 0 )
2749  delta = -delta;
2750 
2751  if ( delta < 40 )
2752  {
2753  dist = axis->widths[0].cur;
2754  if ( dist < 48 )
2755  dist = 48;
2756 
2757  goto Done_Width;
2758  }
2759 
2760  if ( dist < 3 * 64 )
2761  {
2762  delta = dist & 63;
2763  dist &= -64;
2764 
2765  if ( delta < 10 )
2766  dist += delta;
2767 
2768  else if ( delta < 32 )
2769  dist += 10;
2770 
2771  else if ( delta < 54 )
2772  dist += 54;
2773 
2774  else
2775  dist += delta;
2776  }
2777  else
2778  {
2779  /* A stem's end position depends on two values: the start */
2780  /* position and the stem length. The former gets usually */
2781  /* rounded to the grid, while the latter gets rounded also if it */
2782  /* exceeds a certain length (see below in this function). This */
2783  /* `double rounding' can lead to a great difference to the */
2784  /* original, unhinted position; this normally doesn't matter for */
2785  /* large PPEM values, but for small sizes it can easily make */
2786  /* outlines collide. For this reason, we adjust the stem length */
2787  /* by a small amount depending on the PPEM value in case the */
2788  /* former and latter rounding both point into the same */
2789  /* direction. */
2790 
2791  FT_Pos bdelta = 0;
2792 
2793 
2794  if ( ( ( width > 0 ) && ( base_delta > 0 ) ) ||
2795  ( ( width < 0 ) && ( base_delta < 0 ) ) )
2796  {
2797  FT_UInt ppem = metrics->root.scaler.face->size->metrics.x_ppem;
2798 
2799 
2800  if ( ppem < 10 )
2801  bdelta = base_delta;
2802  else if ( ppem < 30 )
2803  bdelta = ( base_delta * (FT_Pos)( 30 - ppem ) ) / 20;
2804 
2805  if ( bdelta < 0 )
2806  bdelta = -bdelta;
2807  }
2808 
2809  dist = ( dist - bdelta + 32 ) & ~63;
2810  }
2811  }
2812  }
2813  else
2814  {
2815  /* strong hinting process: snap the stem width to integer pixels */
2816 
2817  FT_Pos org_dist = dist;
2818 
2819 
2820  dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
2821 
2822  if ( vertical )
2823  {
2824  /* in the case of vertical hinting, always round */
2825  /* the stem heights to integer pixels */
2826 
2827  if ( dist >= 64 )
2828  dist = ( dist + 16 ) & ~63;
2829  else
2830  dist = 64;
2831  }
2832  else
2833  {
2834  if ( AF_LATIN_HINTS_DO_MONO( hints ) )
2835  {
2836  /* monochrome horizontal hinting: snap widths to integer pixels */
2837  /* with a different threshold */
2838 
2839  if ( dist < 64 )
2840  dist = 64;
2841  else
2842  dist = ( dist + 32 ) & ~63;
2843  }
2844  else
2845  {
2846  /* for horizontal anti-aliased hinting, we adopt a more subtle */
2847  /* approach: we strengthen small stems, round stems whose size */
2848  /* is between 1 and 2 pixels to an integer, otherwise nothing */
2849 
2850  if ( dist < 48 )
2851  dist = ( dist + 64 ) >> 1;
2852 
2853  else if ( dist < 128 )
2854  {
2855  /* We only round to an integer width if the corresponding */
2856  /* distortion is less than 1/4 pixel. Otherwise this */
2857  /* makes everything worse since the diagonals, which are */
2858  /* not hinted, appear a lot bolder or thinner than the */
2859  /* vertical stems. */
2860 
2861  FT_Pos delta;
2862 
2863 
2864  dist = ( dist + 22 ) & ~63;
2865  delta = dist - org_dist;
2866  if ( delta < 0 )
2867  delta = -delta;
2868 
2869  if ( delta >= 16 )
2870  {
2871  dist = org_dist;
2872  if ( dist < 48 )
2873  dist = ( dist + 64 ) >> 1;
2874  }
2875  }
2876  else
2877  /* round otherwise to prevent color fringes in LCD mode */
2878  dist = ( dist + 32 ) & ~63;
2879  }
2880  }
2881  }
2882 
2883  Done_Width:
2884  if ( sign )
2885  dist = -dist;
2886 
2887  return dist;
2888  }
2889 
2890 
2891  /* Align one stem edge relative to the previous stem edge. */
2892 
2893  static void
2895  AF_Dimension dim,
2896  AF_Edge base_edge,
2897  AF_Edge stem_edge )
2898  {
2899  FT_Pos dist, base_delta;
2900  FT_Pos fitted_width;
2901 
2902 
2903  dist = stem_edge->opos - base_edge->opos;
2904  base_delta = base_edge->pos - base_edge->opos;
2905 
2906  fitted_width = af_latin_compute_stem_width( hints, dim,
2907  dist, base_delta,
2908  base_edge->flags,
2909  stem_edge->flags );
2910 
2911 
2912  stem_edge->pos = base_edge->pos + fitted_width;
2913 
2914  FT_TRACE5(( " LINK: edge %d (opos=%.2f) linked to %.2f,"
2915  " dist was %.2f, now %.2f\n",
2916  stem_edge - hints->axis[dim].edges, stem_edge->opos / 64.0,
2917  stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
2918  }
2919 
2920 
2921  /* Shift the coordinates of the `serif' edge by the same amount */
2922  /* as the corresponding `base' edge has been moved already. */
2923 
2924  static void
2926  AF_Edge base,
2927  AF_Edge serif )
2928  {
2929  FT_UNUSED( hints );
2930 
2931  serif->pos = base->pos + ( serif->opos - base->opos );
2932  }
2933 
2934 
2935  /*************************************************************************/
2936  /*************************************************************************/
2937  /*************************************************************************/
2938  /**** ****/
2939  /**** E D G E H I N T I N G ****/
2940  /**** ****/
2941  /*************************************************************************/
2942  /*************************************************************************/
2943  /*************************************************************************/
2944 
2945 
2946  /* The main grid-fitting routine. */
2947 
2948  static void
2950  AF_Dimension dim )
2951  {
2952  AF_AxisHints axis = &hints->axis[dim];
2953  AF_Edge edges = axis->edges;
2954  AF_Edge edge_limit = edges + axis->num_edges;
2955  FT_PtrDist n_edges;
2956  AF_Edge edge;
2957  AF_Edge anchor = NULL;
2958  FT_Int has_serifs = 0;
2959 
2960 #ifdef FT_CONFIG_OPTION_PIC
2961  AF_FaceGlobals globals = hints->metrics->globals;
2962 #endif
2963 
2964  AF_StyleClass style_class = hints->metrics->style_class;
2965  AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET
2966  [style_class->script];
2967 
2968  FT_Bool top_to_bottom_hinting = 0;
2969 
2970 #ifdef FT_DEBUG_LEVEL_TRACE
2971  FT_UInt num_actions = 0;
2972 #endif
2973 
2974 
2975  FT_TRACE5(( "latin %s edge hinting (style `%s')\n",
2976  dim == AF_DIMENSION_VERT ? "horizontal" : "vertical",
2977  af_style_names[hints->metrics->style_class->style] ));
2978 
2979  if ( dim == AF_DIMENSION_VERT )
2980  top_to_bottom_hinting = script_class->top_to_bottom_hinting;
2981 
2982  /* we begin by aligning all stems relative to the blue zone */
2983  /* if needed -- that's only for horizontal edges */
2984 
2985  if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
2986  {
2987  for ( edge = edges; edge < edge_limit; edge++ )
2988  {
2989  AF_Width blue;
2990  AF_Edge edge1, edge2; /* these edges form the stem to check */
2991 
2992 
2993  if ( edge->flags & AF_EDGE_DONE )
2994  continue;
2995 
2996  edge1 = NULL;
2997  edge2 = edge->link;
2998 
2999  /*
3000  * If a stem contains both a neutral and a non-neutral blue zone,
3001  * skip the neutral one. Otherwise, outlines with different
3002  * directions might be incorrectly aligned at the same vertical
3003  * position.
3004  *
3005  * If we have two neutral blue zones, skip one of them.
3006  *
3007  */
3008  if ( edge->blue_edge && edge2 && edge2->blue_edge )
3009  {
3010  FT_Byte neutral = edge->flags & AF_EDGE_NEUTRAL;
3011  FT_Byte neutral2 = edge2->flags & AF_EDGE_NEUTRAL;
3012 
3013 
3014  if ( neutral2 )
3015  {
3016  edge2->blue_edge = NULL;
3017  edge2->flags &= ~AF_EDGE_NEUTRAL;
3018  }
3019  else if ( neutral )
3020  {
3021  edge->blue_edge = NULL;
3022  edge->flags &= ~AF_EDGE_NEUTRAL;
3023  }
3024  }
3025 
3026  blue = edge->blue_edge;
3027  if ( blue )
3028  edge1 = edge;
3029 
3030  /* flip edges if the other edge is aligned to a blue zone */
3031  else if ( edge2 && edge2->blue_edge )
3032  {
3033  blue = edge2->blue_edge;
3034  edge1 = edge2;
3035  edge2 = edge;
3036  }
3037 
3038  if ( !edge1 )
3039  continue;
3040 
3041 #ifdef FT_DEBUG_LEVEL_TRACE
3042  if ( !anchor )
3043  FT_TRACE5(( " BLUE_ANCHOR: edge %d (opos=%.2f) snapped to %.2f,"
3044  " was %.2f (anchor=edge %d)\n",
3045  edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
3046  edge1->pos / 64.0, edge - edges ));
3047  else
3048  FT_TRACE5(( " BLUE: edge %d (opos=%.2f) snapped to %.2f,"
3049  " was %.2f\n",
3050  edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
3051  edge1->pos / 64.0 ));
3052 
3053  num_actions++;
3054 #endif
3055 
3056  edge1->pos = blue->fit;
3057  edge1->flags |= AF_EDGE_DONE;
3058 
3059  if ( edge2 && !edge2->blue_edge )
3060  {
3061  af_latin_align_linked_edge( hints, dim, edge1, edge2 );
3062  edge2->flags |= AF_EDGE_DONE;
3063 
3064 #ifdef FT_DEBUG_LEVEL_TRACE
3065  num_actions++;
3066 #endif
3067  }
3068 
3069  if ( !anchor )
3070  anchor = edge;
3071  }
3072  }
3073 
3074  /* now we align all other stem edges, trying to maintain the */
3075  /* relative order of stems in the glyph */
3076  for ( edge = edges; edge < edge_limit; edge++ )
3077  {
3078  AF_Edge edge2;
3079 
3080 
3081  if ( edge->flags & AF_EDGE_DONE )
3082  continue;
3083 
3084  /* skip all non-stem edges */
3085  edge2 = edge->link;
3086  if ( !edge2 )
3087  {
3088  has_serifs++;
3089  continue;
3090  }
3091 
3092  /* now align the stem */
3093 
3094  /* this should not happen, but it's better to be safe */
3095  if ( edge2->blue_edge )
3096  {
3097  FT_TRACE5(( " ASSERTION FAILED for edge %d\n", edge2 - edges ));
3098 
3099  af_latin_align_linked_edge( hints, dim, edge2, edge );
3100  edge->flags |= AF_EDGE_DONE;
3101 
3102 #ifdef FT_DEBUG_LEVEL_TRACE
3103  num_actions++;
3104 #endif
3105  continue;
3106  }
3107 
3108  if ( !anchor )
3109  {
3110  /* if we reach this if clause, no stem has been aligned yet */
3111 
3112  FT_Pos org_len, org_center, cur_len;
3113  FT_Pos cur_pos1, error1, error2, u_off, d_off;
3114 
3115 
3116  org_len = edge2->opos - edge->opos;
3117  cur_len = af_latin_compute_stem_width( hints, dim,
3118  org_len, 0,
3119  edge->flags,
3120  edge2->flags );
3121 
3122  /* some voodoo to specially round edges for small stem widths; */
3123  /* the idea is to align the center of a stem, then shifting */
3124  /* the stem edges to suitable positions */
3125  if ( cur_len <= 64 )
3126  {
3127  /* width <= 1px */
3128  u_off = 32;
3129  d_off = 32;
3130  }
3131  else
3132  {
3133  /* 1px < width < 1.5px */
3134  u_off = 38;
3135  d_off = 26;
3136  }
3137 
3138  if ( cur_len < 96 )
3139  {
3140  org_center = edge->opos + ( org_len >> 1 );
3141  cur_pos1 = FT_PIX_ROUND( org_center );
3142 
3143  error1 = org_center - ( cur_pos1 - u_off );
3144  if ( error1 < 0 )
3145  error1 = -error1;
3146 
3147  error2 = org_center - ( cur_pos1 + d_off );
3148  if ( error2 < 0 )
3149  error2 = -error2;
3150 
3151  if ( error1 < error2 )
3152  cur_pos1 -= u_off;
3153  else
3154  cur_pos1 += d_off;
3155 
3156  edge->pos = cur_pos1 - cur_len / 2;
3157  edge2->pos = edge->pos + cur_len;
3158  }
3159  else
3160  edge->pos = FT_PIX_ROUND( edge->opos );
3161 
3162  anchor = edge;
3163  edge->flags |= AF_EDGE_DONE;
3164 
3165  FT_TRACE5(( " ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)"
3166  " snapped to %.2f and %.2f\n",
3167  edge - edges, edge->opos / 64.0,
3168  edge2 - edges, edge2->opos / 64.0,
3169  edge->pos / 64.0, edge2->pos / 64.0 ));
3170 
3171  af_latin_align_linked_edge( hints, dim, edge, edge2 );
3172 
3173 #ifdef FT_DEBUG_LEVEL_TRACE
3174  num_actions += 2;
3175 #endif
3176  }
3177  else
3178  {
3179  FT_Pos org_pos, org_len, org_center, cur_len;
3180  FT_Pos cur_pos1, cur_pos2, delta1, delta2;
3181 
3182 
3183  org_pos = anchor->pos + ( edge->opos - anchor->opos );
3184  org_len = edge2->opos - edge->opos;
3185  org_center = org_pos + ( org_len >> 1 );
3186 
3187  cur_len = af_latin_compute_stem_width( hints, dim,
3188  org_len, 0,
3189  edge->flags,
3190  edge2->flags );
3191 
3192  if ( edge2->flags & AF_EDGE_DONE )
3193  {
3194  FT_TRACE5(( " ADJUST: edge %d (pos=%.2f) moved to %.2f\n",
3195  edge - edges, edge->pos / 64.0,
3196  ( edge2->pos - cur_len ) / 64.0 ));
3197 
3198  edge->pos = edge2->pos - cur_len;
3199  }
3200 
3201  else if ( cur_len < 96 )
3202  {
3203  FT_Pos u_off, d_off;
3204 
3205 
3206  cur_pos1 = FT_PIX_ROUND( org_center );
3207 
3208  if ( cur_len <= 64 )
3209  {
3210  u_off = 32;
3211  d_off = 32;
3212  }
3213  else
3214  {
3215  u_off = 38;
3216  d_off = 26;
3217  }
3218 
3219  delta1 = org_center - ( cur_pos1 - u_off );
3220  if ( delta1 < 0 )
3221  delta1 = -delta1;
3222 
3223  delta2 = org_center - ( cur_pos1 + d_off );
3224  if ( delta2 < 0 )
3225  delta2 = -delta2;
3226 
3227  if ( delta1 < delta2 )
3228  cur_pos1 -= u_off;
3229  else
3230  cur_pos1 += d_off;
3231 
3232  edge->pos = cur_pos1 - cur_len / 2;
3233  edge2->pos = cur_pos1 + cur_len / 2;
3234 
3235  FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)"
3236  " snapped to %.2f and %.2f\n",
3237  edge - edges, edge->opos / 64.0,
3238  edge2 - edges, edge2->opos / 64.0,
3239  edge->pos / 64.0, edge2->pos / 64.0 ));
3240  }
3241 
3242  else
3243  {
3244  org_pos = anchor->pos + ( edge->opos - anchor->opos );
3245  org_len = edge2->opos - edge->opos;
3246  org_center = org_pos + ( org_len >> 1 );
3247 
3248  cur_len = af_latin_compute_stem_width( hints, dim,
3249  org_len, 0,
3250  edge->flags,
3251  edge2->flags );
3252 
3253  cur_pos1 = FT_PIX_ROUND( org_pos );
3254  delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center;
3255  if ( delta1 < 0 )
3256  delta1 = -delta1;
3257 
3258  cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
3259  delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center;
3260  if ( delta2 < 0 )
3261  delta2 = -delta2;
3262 
3263  edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
3264  edge2->pos = edge->pos + cur_len;
3265 
3266  FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)"
3267  " snapped to %.2f and %.2f\n",
3268  edge - edges, edge->opos / 64.0,
3269  edge2 - edges, edge2->opos / 64.0,
3270  edge->pos / 64.0, edge2->pos / 64.0 ));
3271  }
3272 
3273 #ifdef FT_DEBUG_LEVEL_TRACE
3274  num_actions++;
3275 #endif
3276 
3277  edge->flags |= AF_EDGE_DONE;
3278  edge2->flags |= AF_EDGE_DONE;
3279 
3280  if ( edge > edges &&
3281  ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos )
3282  : ( edge->pos < edge[-1].pos ) ) )
3283  {
3284  /* don't move if stem would (almost) disappear otherwise; */
3285  /* the ad-hoc value 16 corresponds to 1/4px */
3286  if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
3287  {
3288 #ifdef FT_DEBUG_LEVEL_TRACE
3289  FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
3290  edge - edges,
3291  edge->pos / 64.0,
3292  edge[-1].pos / 64.0 ));
3293 
3294  num_actions++;
3295 #endif
3296 
3297  edge->pos = edge[-1].pos;
3298  }
3299  }
3300  }
3301  }
3302 
3303  /* make sure that lowercase m's maintain their symmetry */
3304 
3305  /* In general, lowercase m's have six vertical edges if they are sans */
3306  /* serif, or twelve if they are with serifs. This implementation is */
3307  /* based on that assumption, and seems to work very well with most */
3308  /* faces. However, if for a certain face this assumption is not */
3309  /* true, the m is just rendered like before. In addition, any stem */
3310  /* correction will only be applied to symmetrical glyphs (even if the */
3311  /* glyph is not an m), so the potential for unwanted distortion is */
3312  /* relatively low. */
3313 
3314  /* We don't handle horizontal edges since we can't easily assure that */
3315  /* the third (lowest) stem aligns with the base line; it might end up */
3316  /* one pixel higher or lower. */
3317 
3318  n_edges = edge_limit - edges;
3319  if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
3320  {
3321  AF_Edge edge1, edge2, edge3;
3322  FT_Pos dist1, dist2, span, delta;
3323 
3324 
3325  if ( n_edges == 6 )
3326  {
3327  edge1 = edges;
3328  edge2 = edges + 2;
3329  edge3 = edges + 4;
3330  }
3331  else
3332  {
3333  edge1 = edges + 1;
3334  edge2 = edges + 5;
3335  edge3 = edges + 9;
3336  }
3337 
3338  dist1 = edge2->opos - edge1->opos;
3339  dist2 = edge3->opos - edge2->opos;
3340 
3341  span = dist1 - dist2;
3342  if ( span < 0 )
3343  span = -span;
3344 
3345  if ( span < 8 )
3346  {
3347  delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
3348  edge3->pos -= delta;
3349  if ( edge3->link )
3350  edge3->link->pos -= delta;
3351 
3352  /* move the serifs along with the stem */
3353  if ( n_edges == 12 )
3354  {
3355  ( edges + 8 )->pos -= delta;
3356  ( edges + 11 )->pos -= delta;
3357  }
3358 
3359  edge3->flags |= AF_EDGE_DONE;
3360  if ( edge3->link )
3361  edge3->link->flags |= AF_EDGE_DONE;
3362  }
3363  }
3364 
3365  if ( has_serifs || !anchor )
3366  {
3367  /*
3368  * now hint the remaining edges (serifs and single) in order
3369  * to complete our processing
3370  */
3371  for ( edge = edges; edge < edge_limit; edge++ )
3372  {
3373  FT_Pos delta;
3374 
3375 
3376  if ( edge->flags & AF_EDGE_DONE )
3377  continue;
3378 
3379  delta = 1000;
3380 
3381  if ( edge->serif )
3382  {
3383  delta = edge->serif->opos - edge->opos;
3384  if ( delta < 0 )
3385  delta = -delta;
3386  }
3387 
3388  if ( delta < 64 + 16 )
3389  {
3390  af_latin_align_serif_edge( hints, edge->serif, edge );
3391  FT_TRACE5(( " SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)"
3392  " aligned to %.2f\n",
3393  edge - edges, edge->opos / 64.0,
3394  edge->serif - edges, edge->serif->opos / 64.0,
3395  edge->pos / 64.0 ));
3396  }
3397  else if ( !anchor )
3398  {
3399  edge->pos = FT_PIX_ROUND( edge->opos );
3400  anchor = edge;
3401  FT_TRACE5(( " SERIF_ANCHOR: edge %d (opos=%.2f)"
3402  " snapped to %.2f\n",
3403  edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
3404  }
3405  else
3406  {
3407  AF_Edge before, after;
3408 
3409 
3410  for ( before = edge - 1; before >= edges; before-- )
3411  if ( before->flags & AF_EDGE_DONE )
3412  break;
3413 
3414  for ( after = edge + 1; after < edge_limit; after++ )
3415  if ( after->flags & AF_EDGE_DONE )
3416  break;
3417 
3418  if ( before >= edges && before < edge &&
3419  after < edge_limit && after > edge )
3420  {
3421  if ( after->opos == before->opos )
3422  edge->pos = before->pos;
3423  else
3424  edge->pos = before->pos +
3425  FT_MulDiv( edge->opos - before->opos,
3426  after->pos - before->pos,
3427  after->opos - before->opos );
3428 
3429  FT_TRACE5(( " SERIF_LINK1: edge %d (opos=%.2f) snapped to %.2f"
3430  " from %d (opos=%.2f)\n",
3431  edge - edges, edge->opos / 64.0,
3432  edge->pos / 64.0,
3433  before - edges, before->opos / 64.0 ));
3434  }
3435  else
3436  {
3437  edge->pos = anchor->pos +
3438  ( ( edge->opos - anchor->opos + 16 ) & ~31 );
3439  FT_TRACE5(( " SERIF_LINK2: edge %d (opos=%.2f)"
3440  " snapped to %.2f\n",
3441  edge - edges, edge->opos / 64.0, edge->pos / 64.0 ));
3442  }
3443  }
3444 
3445 #ifdef FT_DEBUG_LEVEL_TRACE
3446  num_actions++;
3447 #endif
3448  edge->flags |= AF_EDGE_DONE;
3449 
3450  if ( edge > edges &&
3451  ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos )
3452  : ( edge->pos < edge[-1].pos ) ) )
3453  {
3454  /* don't move if stem would (almost) disappear otherwise; */
3455  /* the ad-hoc value 16 corresponds to 1/4px */
3456  if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
3457  {
3458 #ifdef FT_DEBUG_LEVEL_TRACE
3459  FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
3460  edge - edges,
3461  edge->pos / 64.0,
3462  edge[-1].pos / 64.0 ));
3463 
3464  num_actions++;
3465 #endif
3466  edge->pos = edge[-1].pos;
3467  }
3468  }
3469 
3470  if ( edge + 1 < edge_limit &&
3471  edge[1].flags & AF_EDGE_DONE &&
3472  ( top_to_bottom_hinting ? ( edge->pos < edge[1].pos )
3473  : ( edge->pos > edge[1].pos ) ) )
3474  {
3475  /* don't move if stem would (almost) disappear otherwise; */
3476  /* the ad-hoc value 16 corresponds to 1/4px */
3477  if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
3478  {
3479 #ifdef FT_DEBUG_LEVEL_TRACE
3480  FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n",
3481  edge - edges,
3482  edge->pos / 64.0,
3483  edge[1].pos / 64.0 ));
3484 
3485  num_actions++;
3486 #endif
3487 
3488  edge->pos = edge[1].pos;
3489  }
3490  }
3491  }
3492  }
3493 
3494 #ifdef FT_DEBUG_LEVEL_TRACE
3495  if ( !num_actions )
3496  FT_TRACE5(( " (none)\n" ));
3497  FT_TRACE5(( "\n" ));
3498 #endif
3499  }
3500 
3501 
3502  /* Apply the complete hinting algorithm to a latin glyph. */
3503 
3504  static FT_Error
3509  {
3510  FT_Error error;
3511  int dim;
3512 
3513  AF_LatinAxis axis;
3514 
3515 
3517  if ( error )
3518  goto Exit;
3519 
3520  /* analyze glyph outline */
3521  if ( AF_HINTS_DO_HORIZONTAL( hints ) )
3522  {
3523  axis = &metrics->axis[AF_DIMENSION_HORZ];
3525  axis->width_count,
3526  axis->widths,
3528  if ( error )
3529  goto Exit;
3530  }
3531 
3532  if ( AF_HINTS_DO_VERTICAL( hints ) )
3533  {
3534  axis = &metrics->axis[AF_DIMENSION_VERT];
3536  axis->width_count,
3537  axis->widths,
3539  if ( error )
3540  goto Exit;
3541 
3542  /* apply blue zones to base characters only */
3543  if ( !( metrics->root.globals->glyph_styles[glyph_index] & AF_NONBASE ) )
3545  }
3546 
3547  /* grid-fit the outline */
3548  for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
3549  {
3550 #ifdef AF_CONFIG_OPTION_USE_WARPER
3551  if ( dim == AF_DIMENSION_HORZ &&
3552  metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL &&
3553  AF_HINTS_DO_WARP( hints ) )
3554  {
3555  AF_WarperRec warper;
3556  FT_Fixed scale;
3557  FT_Pos delta;
3558 
3559 
3560  af_warper_compute( &warper, hints, (AF_Dimension)dim,
3561  &scale, &delta );
3562  af_glyph_hints_scale_dim( hints, (AF_Dimension)dim,
3563  scale, delta );
3564  continue;
3565  }
3566 #endif /* AF_CONFIG_OPTION_USE_WARPER */
3567 
3568  if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
3569  ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) )
3570  {
3575  }
3576  }
3577 
3579 
3580  Exit:
3581  return error;
3582  }
3583 
3584 
3585  /*************************************************************************/
3586  /*************************************************************************/
3587  /***** *****/
3588  /***** L A T I N S C R I P T C L A S S *****/
3589  /***** *****/
3590  /*************************************************************************/
3591  /*************************************************************************/
3592 
3593 
3595  af_latin_writing_system_class,
3596 
3598 
3599  sizeof ( AF_LatinMetricsRec ),
3600 
3601  (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init, /* style_metrics_init */
3602  (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale, /* style_metrics_scale */
3603  (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */
3605 
3606  (AF_WritingSystem_InitHintsFunc) af_latin_hints_init, /* style_hints_init */
3607  (AF_WritingSystem_ApplyHintsFunc) af_latin_hints_apply /* style_hints_apply */
3608  )
3609 
3610 
3611 /* END */
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
static size_t double int int int * sign
Definition: printf.c:64
#define AF_LATIN_HINTS_VERT_SNAP
namespace GUID const ADDRINFOEXW * hints
Definition: sock.c:80
#define AF_SCALER_FLAG_NO_HORIZONTAL
af_glyph_hints_save(AF_GlyphHints hints, FT_Outline *outline)
Definition: afhints.c:1146
int FT_Error
Definition: fttypes.h:300
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:608
#define AF_LATIN_BLUE_TOP
GLint GLint GLsizei width
Definition: gl.h:1546
AF_Script script
Definition: aftypes.h:450
#define max(a, b)
Definition: svc.c:63
ft_ptrdiff_t FT_PtrDist
Definition: fttypes.h:337
signed long FT_Long
Definition: fttypes.h:242
FT_Char dir
Definition: afhints.h:261
af_glyph_hints_align_edge_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1181
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
unsigned long FT_ULong
Definition: fttypes.h:253
#define FLAT_THRESHOLD(x)
Definition: aflatin.c:45
af_glyph_hints_done(AF_GlyphHints hints)
Definition: afhints.c:672
FT_BEGIN_HEADER typedef signed long FT_Pos
Definition: ftimage.h:58
#define swap(a, b)
Definition: qsort.c:63
long y
Definition: polytest.cpp:48
AF_Segment edge_next
Definition: afhints.h:269
#define error(str)
Definition: mkdosfs.c:1605
FT_Pos standard_width
Definition: aflatin.h:96
FT_Face face
Definition: aftypes.h:180
GLsizei GLenum const GLvoid GLuint GLsizei GLfloat * metrics
Definition: glext.h:11745
static void af_latin_sort_blue(FT_UInt count, AF_LatinBlue *table)
Definition: aflatin.c:290
POINT last
Definition: font.c:46
#define error1(s, a)
Definition: debug.h:109
AF_Point first
Definition: afhints.h:276
signed int FT_Int
Definition: fttypes.h:220
FT_Short min_coord
Definition: afhints.h:264
FT_Bool extra_light
Definition: aflatin.h:97
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define FT_ABS(a)
Definition: ftobjs.h:74
#define free
Definition: debug_ros.c:5
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:9032
AF_WidthRec shoot
Definition: aflatin.h:80
af_glyph_hints_init(AF_GlyphHints hints, FT_Memory memory)
Definition: afhints.c:662
const GLint * first
Definition: glext.h:5794
enum FT_Render_Mode_ FT_Render_Mode
#define AF_LATIN_IS_SUB_TOP_BLUE(b)
AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX]
Definition: aflatin.h:101
FT_Fixed scale
Definition: aflatin.h:90
#define AF_EDGE_DONE
GLdouble n
Definition: glext.h:7729
AF_WidthRec widths[AF_LATIN_MAX_WIDTHS]
Definition: aflatin.h:94
#define FT_MIN(a, b)
Definition: ftobjs.h:71
af_latin_metrics_init_widths(AF_LatinMetrics metrics, FT_Face face)
Definition: aflatin.c:61
af_latin_metrics_check_digits(AF_LatinMetrics metrics, FT_Face face)
Definition: aflatin.c:1054
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
__inline int before(__u32 seq1, __u32 seq2)
Definition: tcpcore.h:2414
signed char FT_Char
Definition: fttypes.h:143
#define AF_LATIN_BLUE_NEUTRAL
FT_Short max_coord
Definition: afhints.h:265
FT_UInt blue_count
Definition: aflatin.h:100
af_latin_hints_compute_segments(AF_GlyphHints hints, AF_Dimension dim)
Definition: aflatin.c:1499
#define AF_EDGE_NEUTRAL
struct AF_LatinMetricsRec_ * AF_LatinMetrics
void(* AF_WritingSystem_DoneMetricsFunc)(AF_StyleMetrics metrics)
Definition: aftypes.h:212
enum AF_Direction_ AF_Direction
FT_UInt32 flags
Definition: aftypes.h:186
AF_Edge link
Definition: afhints.h:293
FT_Pos org_delta
Definition: aflatin.h:104
AF_Segment last
Definition: afhints.h:298
WORD face[3]
Definition: mesh.c:4747
const char * af_shaper_get_cluster(const char *p, AF_StyleMetrics metrics, void *buf_, unsigned int *count)
Definition: afshaper.c:617
return FT_Err_Ok
Definition: ftbbox.c:511
static char memory[1024 *256]
Definition: process.c:116
Definition: send.c:47
FT_Pos ascender
Definition: aflatin.h:81
af_glyph_hints_reload(AF_GlyphHints hints, FT_Outline *outline)
Definition: afhints.c:732
POINTL point
Definition: edittest.c:50
FT_Fixed org_scale
Definition: aflatin.h:103
#define AF_LATIN_HINTS_DO_VERT_SNAP(h)
static void af_latin_hints_compute_blue_edges(AF_GlyphHints hints, AF_LatinMetrics metrics)
Definition: aflatin.c:2445
FT_Byte flags
Definition: afhints.h:260
GLint limit
Definition: glext.h:10326
#define AF_LATIN_BLUE_ADJUSTMENT
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:108
#define FT_LOAD_NO_SCALE
Definition: freetype.h:3009
af_axis_hints_new_edge(AF_AxisHints axis, FT_Int fpos, AF_Direction dir, FT_Bool top_to_bottom_hinting, FT_Memory memory, AF_Edge *anedge)
Definition: afhints.c:99
FT_Byte flags
Definition: afhints.h:288
af_sort_and_quantize_widths(FT_UInt *count, AF_Width table, FT_Pos threshold)
Definition: afangles.c:210
FT_Error(* AF_WritingSystem_InitMetricsFunc)(AF_StyleMetrics metrics, FT_Face face)
Definition: aftypes.h:204
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
AF_Segment link
Definition: afhints.h:271
FT_Fixed y_scale
Definition: aftypes.h:182
#define AF_FLAG_CONTROL
#define AF_SCALER_FLAG_NO_WARPER
FT_Error(* AF_WritingSystem_InitHintsFunc)(AF_GlyphHints hints, AF_StyleMetrics metrics)
Definition: aftypes.h:221
FT_Char in_dir
Definition: afhints.h:244
#define AF_LATIN_IS_LONG_BLUE(b)
unsigned char FT_Byte
Definition: fttypes.h:154
#define a
Definition: ke_i.h:78
#define AF_SCRIPT_CLASSES_GET
Definition: afpic.h:32
static FT_Pos af_latin_compute_stem_width(AF_GlyphHints hints, AF_Dimension dim, FT_Pos width, FT_Pos base_delta, FT_UInt base_flags, FT_UInt stem_flags)
Definition: aflatin.c:2697
FT_Bool top_to_bottom_hinting
Definition: aftypes.h:346
FT_Load_Glyph(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags)
Definition: ftobjs.c:760
af_latin_metrics_scale(AF_LatinMetrics metrics, AF_Scaler scaler)
Definition: aflatin.c:1459
GLenum GLint ref
Definition: glext.h:6028
af_latin_get_standard_widths(AF_LatinMetrics metrics, FT_Pos *stdHW, FT_Pos *stdVW)
Definition: aflatin.c:1475
#define pp
Definition: hlsl.yy.c:978
#define AF_BLUE_STRINGSET_MAX_LEN
Definition: afblue.h:314
#define AF_LATIN_HINTS_DO_STEM_ADJUST(h)
af_latin_metrics_init(AF_LatinMetrics metrics, FT_Face face)
Definition: aflatin.c:1113
#define AF_LATIN_BLUE_SUB_TOP
smooth NULL
Definition: ftsmooth.c:416
af_warper_compute(AF_Warper warper, AF_GlyphHints hints, AF_Dimension dim, FT_Fixed *a_scale, FT_Fixed *a_delta)
void(* AF_WritingSystem_ScaleMetricsFunc)(AF_StyleMetrics metrics, AF_Scaler scaler)
Definition: aftypes.h:208
af_latin_hints_link_segments(AF_GlyphHints hints, FT_UInt width_count, AF_WidthRec *widths, AF_Dimension dim)
Definition: aflatin.c:1927
#define AF_LATIN_IS_X_HEIGHT_BLUE(b)
FT_Char dir
Definition: afhints.h:289
unsigned int dir
Definition: maze.c:112
#define AF_LATIN_MAX_WIDTHS
af_glyph_hints_rescale(AF_GlyphHints hints, AF_StyleMetrics metrics)
Definition: afhints.c:720
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:388
GLclampf GLclampf blue
Definition: gl.h:1740
#define b
Definition: ke_i.h:79
FT_Pos score
Definition: afhints.h:273
#define error2(s, a, b)
Definition: debug.h:110
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
FT_Short delta
Definition: afhints.h:263
FT_UInt width_count
Definition: aflatin.h:93
void(* AF_WritingSystem_GetStdWidthsFunc)(AF_StyleMetrics metrics, FT_Pos *stdHW, FT_Pos *stdVW)
Definition: aftypes.h:215
af_glyph_hints_align_strong_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1256
FT_MulDiv(FT_Long a, FT_Long b, FT_Long c)
Definition: ftcalc.c:416
FT_Int num_edges
Definition: afhints.h:314
FT_Pos descender
Definition: aflatin.h:82
af_blue_stringsets[]
Definition: afblue.c:439
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
#define FT_ZERO(p)
Definition: ftmemory.h:237
#define d
Definition: ke_i.h:81
FT_Select_Charmap(FT_Face face, FT_Encoding encoding)
Definition: ftobjs.c:3457
#define AF_DEFINE_WRITING_SYSTEM_CLASS( writing_system_class, system, m_size, m_init, m_scale, m_done, m_stdw, h_init, h_apply)
#define AF_EDGE_SERIF
#define FT_INT_MIN
Definition: ftstdlib.h:64
static void Exit(void)
Definition: sock.c:1331
#define FT_MAX(a, b)
Definition: ftobjs.h:72
FT_Pos pos
Definition: afhints.h:286
AF_Segment segments
Definition: afhints.h:309
#define round(x)
Definition: opentype.c:47
AF_Segment serif
Definition: afhints.h:272
FT_Render_Mode render_mode
Definition: aftypes.h:185
FT_Short fpos
Definition: afhints.h:284
AF_WidthRec ref
Definition: aflatin.h:79
#define AF_HINTS_DO_HORIZONTAL(h)
#define GET_UTF8_CHAR(ch, p)
Definition: afblue.h:31
static void af_latin_align_serif_edge(AF_GlyphHints hints, AF_Edge base, AF_Edge serif)
Definition: aflatin.c:2925
GLbitfield flags
Definition: glext.h:7161
FT_Pos x_delta
Definition: aftypes.h:183
#define AF_LATIN_IS_TOP_BLUE(b)
GLsizei const GLfloat * points
Definition: glext.h:8112
#define AF_LATIN_HINTS_STEM_ADJUST
static const WCHAR L[]
Definition: oid.c:1250
FT_Set_Charmap(FT_Face face, FT_CharMap charmap)
Definition: ftobjs.c:3499
GLint reference
Definition: glext.h:11729
signed short FT_Short
Definition: fttypes.h:198
#define AF_LATIN_HINTS_DO_MONO(h)
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:66
#define AF_HINTS_DO_VERTICAL(h)
GLenum GLsizei len
Definition: glext.h:6722
AF_Direction major_dir
Definition: afhints.h:318
#define AF_PROP_INCREASE_X_HEIGHT_MIN
Definition: afglobal.h:87
#define FT_BOOL(x)
Definition: fttypes.h:578
_STLP_MOVE_TO_STD_NAMESPACE void _STLP_CALL advance(_InputIterator &__i, _Distance __n)
__inline int after(__u32 seq1, __u32 seq2)
Definition: tcpcore.h:2419
seg
Definition: i386-dis.c:3857
AF_Edge edge
Definition: afhints.h:268
FT_Int num_segments
Definition: afhints.h:307
GLenum mode
Definition: glext.h:6217
Definition: mesh.c:5329
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:509
af_axis_hints_new_segment(AF_AxisHints axis, FT_Memory memory, AF_Segment *asegment)
Definition: afhints.c:38
static void af_latin_metrics_init_blues(AF_LatinMetrics metrics, FT_Face face)
Definition: aflatin.c:332
static FT_Error af_latin_hints_init(AF_GlyphHints hints, AF_LatinMetrics metrics)
Definition: aflatin.c:2559
FT_Short height
Definition: afhints.h:266
FT_Pos edge_distance_threshold
Definition: aflatin.h:95
FT_Short pos
Definition: afhints.h:262
Arabic default AF_WRITING_SYSTEM_LATIN
Definition: afstyles.h:93
FT_BEGIN_HEADER enum AF_Dimension_ AF_Dimension
signed long FT_Fixed
Definition: fttypes.h:288
static unsigned __int64 next
Definition: rand_nt.c:6
enum AF_Blue_Stringset_ AF_Blue_Stringset
static void af_latin_align_linked_edge(AF_GlyphHints hints, AF_Dimension dim, AF_Edge base_edge, AF_Edge stem_edge)
Definition: aflatin.c:2894
const GLdouble * v
Definition: gl.h:2040
FT_UInt flags
Definition: aflatin.h:83
FT_BEGIN_HEADER struct AF_WidthRec_ * AF_Width
void af_shaper_buf_destroy(FT_Face face, void *buf)
Definition: afshaper.c:606
#define AF_HINTS_DO_WARP(h)
unsigned int FT_UInt
Definition: fttypes.h:231
#define AF_FLAG_NONE
static void af_latin_metrics_scale_dim(AF_LatinMetrics metrics, AF_Scaler scaler, AF_Dimension dim)
Definition: aflatin.c:1137
af_blue_strings[]
Definition: afblue.c:26
#define AF_NONBASE
Definition: afglobal.h:84
#define AF_LATIN_CONSTANT(metrics, c)
#define min(a, b)
Definition: monoChain.cc:55
FT_BEGIN_HEADER struct AF_WidthRec_ AF_WidthRec
#define FT_TRACE5(varformat)
Definition: ftdebug.h:162
FT_Error(* AF_WritingSystem_ApplyHintsFunc)(FT_UInt glyph_index, AF_GlyphHints hints, FT_Outline *outline, AF_StyleMetrics metrics)
Definition: aftypes.h:225
static void af_latin_hint_edges(AF_GlyphHints hints, AF_Dimension dim)
Definition: aflatin.c:2949
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
FT_Fixed x_scale
Definition: aftypes.h:181
FT_Pos y_delta
Definition: aftypes.h:184
#define FT_CURVE_TAG_ON
Definition: ftimage.h:453
#define FT_INT_MAX
Definition: ftstdlib.h:63
#define AF_LATIN_HINTS_HORZ_SNAP
af_glyph_hints_align_weak_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1507
AF_Segment first
Definition: afhints.h:297
#define AF_LATIN_HINTS_DO_HORZ_SNAP(h)
#define AF_LATIN_HINTS_MONO
AF_Edge serif
Definition: afhints.h:294
const char * standard_charstring
Definition: aftypes.h:348
#define malloc
Definition: debug_ros.c:4
FT_Pos delta
Definition: aflatin.h:91
#define FT_CURVE_TAG(flag)
Definition: ftimage.h:451
const WCHAR * link
Definition: db.cpp:988
#define AF_BLUE_STRING_MAX_LEN
Definition: afblue.h:73
GLenum GLenum GLvoid GLvoid GLvoid * span
Definition: glext.h:5664
#define AF_EDGE_ROUND
af_sort_pos(FT_UInt count, FT_Pos *table)
Definition: afangles.c:187
#define FT_STYLE_FLAG_ITALIC
Definition: freetype.h:1517
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
void * af_shaper_buf_create(FT_Face face)
Definition: afshaper.c:592
static FT_Pos af_latin_snap_width(AF_Width widths, FT_UInt count, FT_Pos width)
Definition: aflatin.c:2648
static FT_Error af_latin_hints_apply(FT_UInt glyph_index, AF_GlyphHints hints, FT_Outline *outline, AF_LatinMetrics metrics)
Definition: aflatin.c:3505
GLfloat GLfloat p
Definition: glext.h:8902
af_latin_hints_detect_features(AF_GlyphHints hints, FT_UInt width_count, AF_WidthRec *widths, AF_Dimension dim)
Definition: aflatin.c:2422
unsigned short FT_UShort
Definition: fttypes.h:209
AF_Width blue_edge
Definition: afhints.h:292
#define AF_EDGE_NORMAL
static struct msdos_boot_sector bs
Definition: mkdosfs.c:539
#define AF_LATIN_BLUE_ACTIVE
#define AF_LATIN_IS_NEUTRAL_BLUE(b)
#define FT_UNUSED(arg)
Definition: ftconfig.h:101
FT_Pos opos
Definition: afhints.h:285
static const int digits[]
Definition: decode.c:71
#define FT_PIX_ROUND(x)
Definition: ftobjs.h:93
FT_ULong af_shaper_get_elem(AF_StyleMetrics metrics, void *buf_, unsigned int idx, FT_Long *advance, FT_Long *y_offset)
Definition: afshaper.c:653
GLenum GLuint GLint GLenum face
Definition: glext.h:7025
#define AF_HINTS_DO_BLUES(h)
af_latin_hints_compute_edges(AF_GlyphHints hints, AF_Dimension dim)
Definition: aflatin.c:2065
AF_Blue_Stringset blue_stringset
Definition: aftypes.h:451
AF_Point last
Definition: afhints.h:277
AF_Edge edges
Definition: afhints.h:316