PageRenderTime 56ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/src/compiler/android-ndk/jni/freetype/src/autofit/aflatin2.c

http://ftk.googlecode.com/
C | 2219 lines | 1493 code | 457 blank | 269 comment | 377 complexity | 0a31662f8c7a95080fd23b9882d4941f MD5 | raw file
Possible License(s): LGPL-3.0
  1. /***************************************************************************/
  2. /* */
  3. /* aflatin.c */
  4. /* */
  5. /* Auto-fitter hinting routines for latin script (body). */
  6. /* */
  7. /* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. #include FT_ADVANCES_H
  18. #include "aflatin.h"
  19. #include "aflatin2.h"
  20. #include "aferrors.h"
  21. #ifdef AF_USE_WARPER
  22. #include "afwarp.h"
  23. #endif
  24. FT_LOCAL_DEF( FT_Error )
  25. af_latin2_hints_compute_segments( AF_GlyphHints hints,
  26. AF_Dimension dim );
  27. FT_LOCAL_DEF( void )
  28. af_latin2_hints_link_segments( AF_GlyphHints hints,
  29. AF_Dimension dim );
  30. /*************************************************************************/
  31. /*************************************************************************/
  32. /***** *****/
  33. /***** L A T I N G L O B A L M E T R I C S *****/
  34. /***** *****/
  35. /*************************************************************************/
  36. /*************************************************************************/
  37. FT_LOCAL_DEF( void )
  38. af_latin2_metrics_init_widths( AF_LatinMetrics metrics,
  39. FT_Face face,
  40. FT_ULong charcode )
  41. {
  42. /* scan the array of segments in each direction */
  43. AF_GlyphHintsRec hints[1];
  44. af_glyph_hints_init( hints, face->memory );
  45. metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
  46. metrics->axis[AF_DIMENSION_VERT].width_count = 0;
  47. {
  48. FT_Error error;
  49. FT_UInt glyph_index;
  50. int dim;
  51. AF_LatinMetricsRec dummy[1];
  52. AF_Scaler scaler = &dummy->root.scaler;
  53. glyph_index = FT_Get_Char_Index( face, charcode );
  54. if ( glyph_index == 0 )
  55. goto Exit;
  56. error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
  57. if ( error || face->glyph->outline.n_points <= 0 )
  58. goto Exit;
  59. FT_ZERO( dummy );
  60. dummy->units_per_em = metrics->units_per_em;
  61. scaler->x_scale = scaler->y_scale = 0x10000L;
  62. scaler->x_delta = scaler->y_delta = 0;
  63. scaler->face = face;
  64. scaler->render_mode = FT_RENDER_MODE_NORMAL;
  65. scaler->flags = 0;
  66. af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy );
  67. error = af_glyph_hints_reload( hints, &face->glyph->outline, 0 );
  68. if ( error )
  69. goto Exit;
  70. for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
  71. {
  72. AF_LatinAxis axis = &metrics->axis[dim];
  73. AF_AxisHints axhints = &hints->axis[dim];
  74. AF_Segment seg, limit, link;
  75. FT_UInt num_widths = 0;
  76. error = af_latin2_hints_compute_segments( hints,
  77. (AF_Dimension)dim );
  78. if ( error )
  79. goto Exit;
  80. af_latin2_hints_link_segments( hints,
  81. (AF_Dimension)dim );
  82. seg = axhints->segments;
  83. limit = seg + axhints->num_segments;
  84. for ( ; seg < limit; seg++ )
  85. {
  86. link = seg->link;
  87. /* we only consider stem segments there! */
  88. if ( link && link->link == seg && link > seg )
  89. {
  90. FT_Pos dist;
  91. dist = seg->pos - link->pos;
  92. if ( dist < 0 )
  93. dist = -dist;
  94. if ( num_widths < AF_LATIN_MAX_WIDTHS )
  95. axis->widths[ num_widths++ ].org = dist;
  96. }
  97. }
  98. af_sort_widths( num_widths, axis->widths );
  99. axis->width_count = num_widths;
  100. }
  101. Exit:
  102. for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
  103. {
  104. AF_LatinAxis axis = &metrics->axis[dim];
  105. FT_Pos stdw;
  106. stdw = ( axis->width_count > 0 )
  107. ? axis->widths[0].org
  108. : AF_LATIN_CONSTANT( metrics, 50 );
  109. /* let's try 20% of the smallest width */
  110. axis->edge_distance_threshold = stdw / 5;
  111. axis->standard_width = stdw;
  112. axis->extra_light = 0;
  113. }
  114. }
  115. af_glyph_hints_done( hints );
  116. }
  117. #define AF_LATIN_MAX_TEST_CHARACTERS 12
  118. static const char af_latin2_blue_chars[AF_LATIN_MAX_BLUES][AF_LATIN_MAX_TEST_CHARACTERS+1] =
  119. {
  120. "THEZOCQS",
  121. "HEZLOCUS",
  122. "fijkdbh",
  123. "xzroesc",
  124. "xzroesc",
  125. "pqgjy"
  126. };
  127. static void
  128. af_latin2_metrics_init_blues( AF_LatinMetrics metrics,
  129. FT_Face face )
  130. {
  131. FT_Pos flats [AF_LATIN_MAX_TEST_CHARACTERS];
  132. FT_Pos rounds[AF_LATIN_MAX_TEST_CHARACTERS];
  133. FT_Int num_flats;
  134. FT_Int num_rounds;
  135. FT_Int bb;
  136. AF_LatinBlue blue;
  137. FT_Error error;
  138. AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
  139. FT_GlyphSlot glyph = face->glyph;
  140. /* we compute the blues simply by loading each character from the */
  141. /* 'af_latin2_blue_chars[blues]' string, then compute its top-most or */
  142. /* bottom-most points (depending on `AF_IS_TOP_BLUE') */
  143. AF_LOG(( "blue zones computation\n" ));
  144. AF_LOG(( "------------------------------------------------\n" ));
  145. for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
  146. {
  147. const char* p = af_latin2_blue_chars[bb];
  148. const char* limit = p + AF_LATIN_MAX_TEST_CHARACTERS;
  149. FT_Pos* blue_ref;
  150. FT_Pos* blue_shoot;
  151. AF_LOG(( "blue %3d: ", bb ));
  152. num_flats = 0;
  153. num_rounds = 0;
  154. for ( ; p < limit && *p; p++ )
  155. {
  156. FT_UInt glyph_index;
  157. FT_Int best_point, best_y, best_first, best_last;
  158. FT_Vector* points;
  159. FT_Bool round;
  160. AF_LOG(( "'%c'", *p ));
  161. /* load the character in the face -- skip unknown or empty ones */
  162. glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
  163. if ( glyph_index == 0 )
  164. continue;
  165. error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
  166. if ( error || glyph->outline.n_points <= 0 )
  167. continue;
  168. /* now compute min or max point indices and coordinates */
  169. points = glyph->outline.points;
  170. best_point = -1;
  171. best_y = 0; /* make compiler happy */
  172. best_first = 0; /* ditto */
  173. best_last = 0; /* ditto */
  174. {
  175. FT_Int nn;
  176. FT_Int first = 0;
  177. FT_Int last = -1;
  178. for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ )
  179. {
  180. FT_Int old_best_point = best_point;
  181. FT_Int pp;
  182. last = glyph->outline.contours[nn];
  183. /* Avoid single-point contours since they are never rasterized. */
  184. /* In some fonts, they correspond to mark attachment points */
  185. /* which are way outside of the glyph's real outline. */
  186. if ( last == first )
  187. continue;
  188. if ( AF_LATIN_IS_TOP_BLUE( bb ) )
  189. {
  190. for ( pp = first; pp <= last; pp++ )
  191. if ( best_point < 0 || points[pp].y > best_y )
  192. {
  193. best_point = pp;
  194. best_y = points[pp].y;
  195. }
  196. }
  197. else
  198. {
  199. for ( pp = first; pp <= last; pp++ )
  200. if ( best_point < 0 || points[pp].y < best_y )
  201. {
  202. best_point = pp;
  203. best_y = points[pp].y;
  204. }
  205. }
  206. if ( best_point != old_best_point )
  207. {
  208. best_first = first;
  209. best_last = last;
  210. }
  211. }
  212. AF_LOG(( "%5d", best_y ));
  213. }
  214. /* now check whether the point belongs to a straight or round */
  215. /* segment; we first need to find in which contour the extremum */
  216. /* lies, then inspect its previous and next points */
  217. {
  218. FT_Int start, end, prev, next;
  219. FT_Pos dist;
  220. /* now look for the previous and next points that are not on the */
  221. /* same Y coordinate. Threshold the `closeness'... */
  222. start = end = best_point;
  223. do
  224. {
  225. prev = start-1;
  226. if ( prev < best_first )
  227. prev = best_last;
  228. dist = points[prev].y - best_y;
  229. if ( dist < -5 || dist > 5 )
  230. break;
  231. start = prev;
  232. } while ( start != best_point );
  233. do
  234. {
  235. next = end+1;
  236. if ( next > best_last )
  237. next = best_first;
  238. dist = points[next].y - best_y;
  239. if ( dist < -5 || dist > 5 )
  240. break;
  241. end = next;
  242. } while ( end != best_point );
  243. /* now, set the `round' flag depending on the segment's kind */
  244. round = FT_BOOL(
  245. FT_CURVE_TAG( glyph->outline.tags[start] ) != FT_CURVE_TAG_ON ||
  246. FT_CURVE_TAG( glyph->outline.tags[ end ] ) != FT_CURVE_TAG_ON );
  247. AF_LOG(( "%c ", round ? 'r' : 'f' ));
  248. }
  249. if ( round )
  250. rounds[num_rounds++] = best_y;
  251. else
  252. flats[num_flats++] = best_y;
  253. }
  254. AF_LOG(( "\n" ));
  255. if ( num_flats == 0 && num_rounds == 0 )
  256. {
  257. /*
  258. * we couldn't find a single glyph to compute this blue zone,
  259. * we will simply ignore it then
  260. */
  261. AF_LOG(( "empty\n" ));
  262. continue;
  263. }
  264. /* we have computed the contents of the `rounds' and `flats' tables, */
  265. /* now determine the reference and overshoot position of the blue -- */
  266. /* we simply take the median value after a simple sort */
  267. af_sort_pos( num_rounds, rounds );
  268. af_sort_pos( num_flats, flats );
  269. blue = & axis->blues[axis->blue_count];
  270. blue_ref = & blue->ref.org;
  271. blue_shoot = & blue->shoot.org;
  272. axis->blue_count++;
  273. if ( num_flats == 0 )
  274. {
  275. *blue_ref =
  276. *blue_shoot = rounds[num_rounds / 2];
  277. }
  278. else if ( num_rounds == 0 )
  279. {
  280. *blue_ref =
  281. *blue_shoot = flats[num_flats / 2];
  282. }
  283. else
  284. {
  285. *blue_ref = flats[num_flats / 2];
  286. *blue_shoot = rounds[num_rounds / 2];
  287. }
  288. /* there are sometimes problems: if the overshoot position of top */
  289. /* zones is under its reference position, or the opposite for bottom */
  290. /* zones. We must thus check everything there and correct the errors */
  291. if ( *blue_shoot != *blue_ref )
  292. {
  293. FT_Pos ref = *blue_ref;
  294. FT_Pos shoot = *blue_shoot;
  295. FT_Bool over_ref = FT_BOOL( shoot > ref );
  296. if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref )
  297. *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
  298. }
  299. blue->flags = 0;
  300. if ( AF_LATIN_IS_TOP_BLUE( bb ) )
  301. blue->flags |= AF_LATIN_BLUE_TOP;
  302. /*
  303. * The following flags is used later to adjust the y and x scales
  304. * in order to optimize the pixel grid alignment of the top of small
  305. * letters.
  306. */
  307. if ( bb == AF_LATIN_BLUE_SMALL_TOP )
  308. blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;
  309. AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
  310. }
  311. return;
  312. }
  313. FT_LOCAL_DEF( void )
  314. af_latin2_metrics_check_digits( AF_LatinMetrics metrics,
  315. FT_Face face )
  316. {
  317. FT_UInt i;
  318. FT_Bool started = 0, same_width = 1;
  319. FT_Fixed advance, old_advance = 0;
  320. /* check whether all ASCII digits have the same advance width; */
  321. /* digit `0' is 0x30 in all supported charmaps */
  322. for ( i = 0x30; i <= 0x39; i++ )
  323. {
  324. FT_UInt glyph_index;
  325. glyph_index = FT_Get_Char_Index( face, i );
  326. if ( glyph_index == 0 )
  327. continue;
  328. if ( FT_Get_Advance( face, glyph_index,
  329. FT_LOAD_NO_SCALE |
  330. FT_LOAD_NO_HINTING |
  331. FT_LOAD_IGNORE_TRANSFORM,
  332. &advance ) )
  333. continue;
  334. if ( started )
  335. {
  336. if ( advance != old_advance )
  337. {
  338. same_width = 0;
  339. break;
  340. }
  341. }
  342. else
  343. {
  344. old_advance = advance;
  345. started = 1;
  346. }
  347. }
  348. metrics->root.digits_have_same_width = same_width;
  349. }
  350. FT_LOCAL_DEF( FT_Error )
  351. af_latin2_metrics_init( AF_LatinMetrics metrics,
  352. FT_Face face )
  353. {
  354. FT_Error error = AF_Err_Ok;
  355. FT_CharMap oldmap = face->charmap;
  356. FT_UInt ee;
  357. static const FT_Encoding latin_encodings[] =
  358. {
  359. FT_ENCODING_UNICODE,
  360. FT_ENCODING_APPLE_ROMAN,
  361. FT_ENCODING_ADOBE_STANDARD,
  362. FT_ENCODING_ADOBE_LATIN_1,
  363. FT_ENCODING_NONE /* end of list */
  364. };
  365. metrics->units_per_em = face->units_per_EM;
  366. /* do we have a latin charmap in there? */
  367. for ( ee = 0; latin_encodings[ee] != FT_ENCODING_NONE; ee++ )
  368. {
  369. error = FT_Select_Charmap( face, latin_encodings[ee] );
  370. if ( !error )
  371. break;
  372. }
  373. if ( !error )
  374. {
  375. /* For now, compute the standard width and height from the `o'. */
  376. af_latin2_metrics_init_widths( metrics, face, 'o' );
  377. af_latin2_metrics_init_blues( metrics, face );
  378. af_latin2_metrics_check_digits( metrics, face );
  379. }
  380. FT_Set_Charmap( face, oldmap );
  381. return AF_Err_Ok;
  382. }
  383. static void
  384. af_latin2_metrics_scale_dim( AF_LatinMetrics metrics,
  385. AF_Scaler scaler,
  386. AF_Dimension dim )
  387. {
  388. FT_Fixed scale;
  389. FT_Pos delta;
  390. AF_LatinAxis axis;
  391. FT_UInt nn;
  392. if ( dim == AF_DIMENSION_HORZ )
  393. {
  394. scale = scaler->x_scale;
  395. delta = scaler->x_delta;
  396. }
  397. else
  398. {
  399. scale = scaler->y_scale;
  400. delta = scaler->y_delta;
  401. }
  402. axis = &metrics->axis[dim];
  403. if ( axis->org_scale == scale && axis->org_delta == delta )
  404. return;
  405. axis->org_scale = scale;
  406. axis->org_delta = delta;
  407. /*
  408. * correct Y scale to optimize the alignment of the top of small
  409. * letters to the pixel grid
  410. */
  411. if ( dim == AF_DIMENSION_VERT )
  412. {
  413. AF_LatinAxis vaxis = &metrics->axis[AF_DIMENSION_VERT];
  414. AF_LatinBlue blue = NULL;
  415. for ( nn = 0; nn < vaxis->blue_count; nn++ )
  416. {
  417. if ( vaxis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
  418. {
  419. blue = &vaxis->blues[nn];
  420. break;
  421. }
  422. }
  423. if ( blue )
  424. {
  425. FT_Pos scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
  426. FT_Pos fitted = ( scaled + 40 ) & ~63;
  427. #if 1
  428. if ( scaled != fitted ) {
  429. scale = FT_MulDiv( scale, fitted, scaled );
  430. AF_LOG(( "== scaled x-top = %.2g fitted = %.2g, scaling = %.4g\n", scaled/64.0, fitted/64.0, (fitted*1.0)/scaled ));
  431. }
  432. #endif
  433. }
  434. }
  435. axis->scale = scale;
  436. axis->delta = delta;
  437. if ( dim == AF_DIMENSION_HORZ )
  438. {
  439. metrics->root.scaler.x_scale = scale;
  440. metrics->root.scaler.x_delta = delta;
  441. }
  442. else
  443. {
  444. metrics->root.scaler.y_scale = scale;
  445. metrics->root.scaler.y_delta = delta;
  446. }
  447. /* scale the standard widths */
  448. for ( nn = 0; nn < axis->width_count; nn++ )
  449. {
  450. AF_Width width = axis->widths + nn;
  451. width->cur = FT_MulFix( width->org, scale );
  452. width->fit = width->cur;
  453. }
  454. /* an extra-light axis corresponds to a standard width that is */
  455. /* smaller than 0.75 pixels */
  456. axis->extra_light =
  457. (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
  458. if ( dim == AF_DIMENSION_VERT )
  459. {
  460. /* scale the blue zones */
  461. for ( nn = 0; nn < axis->blue_count; nn++ )
  462. {
  463. AF_LatinBlue blue = &axis->blues[nn];
  464. FT_Pos dist;
  465. blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
  466. blue->ref.fit = blue->ref.cur;
  467. blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
  468. blue->shoot.fit = blue->shoot.cur;
  469. blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
  470. /* a blue zone is only active if it is less than 3/4 pixels tall */
  471. dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
  472. if ( dist <= 48 && dist >= -48 )
  473. {
  474. FT_Pos delta1, delta2;
  475. delta1 = blue->shoot.org - blue->ref.org;
  476. delta2 = delta1;
  477. if ( delta1 < 0 )
  478. delta2 = -delta2;
  479. delta2 = FT_MulFix( delta2, scale );
  480. if ( delta2 < 32 )
  481. delta2 = 0;
  482. else if ( delta2 < 64 )
  483. delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
  484. else
  485. delta2 = FT_PIX_ROUND( delta2 );
  486. if ( delta1 < 0 )
  487. delta2 = -delta2;
  488. blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
  489. blue->shoot.fit = blue->ref.fit + delta2;
  490. AF_LOG(( ">> activating blue zone %d: ref.cur=%.2g ref.fit=%.2g shoot.cur=%.2g shoot.fit=%.2g\n",
  491. nn, blue->ref.cur/64.0, blue->ref.fit/64.0,
  492. blue->shoot.cur/64.0, blue->shoot.fit/64.0 ));
  493. blue->flags |= AF_LATIN_BLUE_ACTIVE;
  494. }
  495. }
  496. }
  497. }
  498. FT_LOCAL_DEF( void )
  499. af_latin2_metrics_scale( AF_LatinMetrics metrics,
  500. AF_Scaler scaler )
  501. {
  502. metrics->root.scaler.render_mode = scaler->render_mode;
  503. metrics->root.scaler.face = scaler->face;
  504. af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
  505. af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
  506. }
  507. /*************************************************************************/
  508. /*************************************************************************/
  509. /***** *****/
  510. /***** L A T I N G L Y P H A N A L Y S I S *****/
  511. /***** *****/
  512. /*************************************************************************/
  513. /*************************************************************************/
  514. #define SORT_SEGMENTS
  515. FT_LOCAL_DEF( FT_Error )
  516. af_latin2_hints_compute_segments( AF_GlyphHints hints,
  517. AF_Dimension dim )
  518. {
  519. AF_AxisHints axis = &hints->axis[dim];
  520. FT_Memory memory = hints->memory;
  521. FT_Error error = AF_Err_Ok;
  522. AF_Segment segment = NULL;
  523. AF_SegmentRec seg0;
  524. AF_Point* contour = hints->contours;
  525. AF_Point* contour_limit = contour + hints->num_contours;
  526. AF_Direction major_dir, segment_dir;
  527. FT_ZERO( &seg0 );
  528. seg0.score = 32000;
  529. seg0.flags = AF_EDGE_NORMAL;
  530. major_dir = (AF_Direction)FT_ABS( axis->major_dir );
  531. segment_dir = major_dir;
  532. axis->num_segments = 0;
  533. /* set up (u,v) in each point */
  534. if ( dim == AF_DIMENSION_HORZ )
  535. {
  536. AF_Point point = hints->points;
  537. AF_Point limit = point + hints->num_points;
  538. for ( ; point < limit; point++ )
  539. {
  540. point->u = point->fx;
  541. point->v = point->fy;
  542. }
  543. }
  544. else
  545. {
  546. AF_Point point = hints->points;
  547. AF_Point limit = point + hints->num_points;
  548. for ( ; point < limit; point++ )
  549. {
  550. point->u = point->fy;
  551. point->v = point->fx;
  552. }
  553. }
  554. /* do each contour separately */
  555. for ( ; contour < contour_limit; contour++ )
  556. {
  557. AF_Point point = contour[0];
  558. AF_Point start = point;
  559. AF_Point last = point->prev;
  560. if ( point == last ) /* skip singletons -- just in case */
  561. continue;
  562. /* already on an edge ?, backtrack to find its start */
  563. if ( FT_ABS( point->in_dir ) == major_dir )
  564. {
  565. point = point->prev;
  566. while ( point->in_dir == start->in_dir )
  567. point = point->prev;
  568. }
  569. else /* otherwise, find first segment start, if any */
  570. {
  571. while ( FT_ABS( point->out_dir ) != major_dir )
  572. {
  573. point = point->next;
  574. if ( point == start )
  575. goto NextContour;
  576. }
  577. }
  578. start = point;
  579. for (;;)
  580. {
  581. AF_Point first;
  582. FT_Pos min_u, min_v, max_u, max_v;
  583. /* we're at the start of a new segment */
  584. FT_ASSERT( FT_ABS( point->out_dir ) == major_dir &&
  585. point->in_dir != point->out_dir );
  586. first = point;
  587. min_u = max_u = point->u;
  588. min_v = max_v = point->v;
  589. point = point->next;
  590. while ( point->out_dir == first->out_dir )
  591. {
  592. point = point->next;
  593. if ( point->u < min_u )
  594. min_u = point->u;
  595. if ( point->u > max_u )
  596. max_u = point->u;
  597. }
  598. if ( point->v < min_v )
  599. min_v = point->v;
  600. if ( point->v > max_v )
  601. max_v = point->v;
  602. /* record new segment */
  603. error = af_axis_hints_new_segment( axis, memory, &segment );
  604. if ( error )
  605. goto Exit;
  606. segment[0] = seg0;
  607. segment->dir = first->out_dir;
  608. segment->first = first;
  609. segment->last = point;
  610. segment->contour = contour;
  611. segment->pos = (FT_Short)(( min_u + max_u ) >> 1);
  612. segment->min_coord = (FT_Short) min_v;
  613. segment->max_coord = (FT_Short) max_v;
  614. segment->height = (FT_Short)(max_v - min_v);
  615. /* a segment is round if it doesn't have successive */
  616. /* on-curve points. */
  617. {
  618. AF_Point pt = first;
  619. AF_Point last = point;
  620. AF_Flags f0 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
  621. AF_Flags f1;
  622. segment->flags &= ~AF_EDGE_ROUND;
  623. for ( ; pt != last; f0 = f1 )
  624. {
  625. pt = pt->next;
  626. f1 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
  627. if ( !f0 && !f1 )
  628. break;
  629. if ( pt == last )
  630. segment->flags |= AF_EDGE_ROUND;
  631. }
  632. }
  633. /* this can happen in the case of a degenerate contour
  634. * e.g. a 2-point vertical contour
  635. */
  636. if ( point == start )
  637. break;
  638. /* jump to the start of the next segment, if any */
  639. while ( FT_ABS(point->out_dir) != major_dir )
  640. {
  641. point = point->next;
  642. if ( point == start )
  643. goto NextContour;
  644. }
  645. }
  646. NextContour:
  647. ;
  648. } /* contours */
  649. /* now slightly increase the height of segments when this makes */
  650. /* sense -- this is used to better detect and ignore serifs */
  651. {
  652. AF_Segment segments = axis->segments;
  653. AF_Segment segments_end = segments + axis->num_segments;
  654. for ( segment = segments; segment < segments_end; segment++ )
  655. {
  656. AF_Point first = segment->first;
  657. AF_Point last = segment->last;
  658. AF_Point p;
  659. FT_Pos first_v = first->v;
  660. FT_Pos last_v = last->v;
  661. if ( first == last )
  662. continue;
  663. if ( first_v < last_v )
  664. {
  665. p = first->prev;
  666. if ( p->v < first_v )
  667. segment->height = (FT_Short)( segment->height +
  668. ( ( first_v - p->v ) >> 1 ) );
  669. p = last->next;
  670. if ( p->v > last_v )
  671. segment->height = (FT_Short)( segment->height +
  672. ( ( p->v - last_v ) >> 1 ) );
  673. }
  674. else
  675. {
  676. p = first->prev;
  677. if ( p->v > first_v )
  678. segment->height = (FT_Short)( segment->height +
  679. ( ( p->v - first_v ) >> 1 ) );
  680. p = last->next;
  681. if ( p->v < last_v )
  682. segment->height = (FT_Short)( segment->height +
  683. ( ( last_v - p->v ) >> 1 ) );
  684. }
  685. }
  686. }
  687. #ifdef AF_SORT_SEGMENTS
  688. /* place all segments with a negative direction to the start
  689. * of the array, used to speed up segment linking later...
  690. */
  691. {
  692. AF_Segment segments = axis->segments;
  693. FT_UInt count = axis->num_segments;
  694. FT_UInt ii, jj;
  695. for (ii = 0; ii < count; ii++)
  696. {
  697. if ( segments[ii].dir > 0 )
  698. {
  699. for (jj = ii+1; jj < count; jj++)
  700. {
  701. if ( segments[jj].dir < 0 )
  702. {
  703. AF_SegmentRec tmp;
  704. tmp = segments[ii];
  705. segments[ii] = segments[jj];
  706. segments[jj] = tmp;
  707. break;
  708. }
  709. }
  710. if ( jj == count )
  711. break;
  712. }
  713. }
  714. axis->mid_segments = ii;
  715. }
  716. #endif
  717. Exit:
  718. return error;
  719. }
  720. FT_LOCAL_DEF( void )
  721. af_latin2_hints_link_segments( AF_GlyphHints hints,
  722. AF_Dimension dim )
  723. {
  724. AF_AxisHints axis = &hints->axis[dim];
  725. AF_Segment segments = axis->segments;
  726. AF_Segment segment_limit = segments + axis->num_segments;
  727. #ifdef AF_SORT_SEGMENTS
  728. AF_Segment segment_mid = segments + axis->mid_segments;
  729. #endif
  730. FT_Pos len_threshold, len_score;
  731. AF_Segment seg1, seg2;
  732. len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
  733. if ( len_threshold == 0 )
  734. len_threshold = 1;
  735. len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
  736. #ifdef AF_SORT_SEGMENTS
  737. for ( seg1 = segments; seg1 < segment_mid; seg1++ )
  738. {
  739. if ( seg1->dir != axis->major_dir || seg1->first == seg1->last )
  740. continue;
  741. for ( seg2 = segment_mid; seg2 < segment_limit; seg2++ )
  742. #else
  743. /* now compare each segment to the others */
  744. for ( seg1 = segments; seg1 < segment_limit; seg1++ )
  745. {
  746. /* the fake segments are introduced to hint the metrics -- */
  747. /* we must never link them to anything */
  748. if ( seg1->dir != axis->major_dir || seg1->first == seg1->last )
  749. continue;
  750. for ( seg2 = segments; seg2 < segment_limit; seg2++ )
  751. if ( seg1->dir + seg2->dir == 0 && seg2->pos > seg1->pos )
  752. #endif
  753. {
  754. FT_Pos pos1 = seg1->pos;
  755. FT_Pos pos2 = seg2->pos;
  756. FT_Pos dist = pos2 - pos1;
  757. if ( dist < 0 )
  758. continue;
  759. {
  760. FT_Pos min = seg1->min_coord;
  761. FT_Pos max = seg1->max_coord;
  762. FT_Pos len, score;
  763. if ( min < seg2->min_coord )
  764. min = seg2->min_coord;
  765. if ( max > seg2->max_coord )
  766. max = seg2->max_coord;
  767. len = max - min;
  768. if ( len >= len_threshold )
  769. {
  770. score = dist + len_score / len;
  771. if ( score < seg1->score )
  772. {
  773. seg1->score = score;
  774. seg1->link = seg2;
  775. }
  776. if ( score < seg2->score )
  777. {
  778. seg2->score = score;
  779. seg2->link = seg1;
  780. }
  781. }
  782. }
  783. }
  784. }
  785. #if 0
  786. }
  787. #endif
  788. /* now, compute the `serif' segments */
  789. for ( seg1 = segments; seg1 < segment_limit; seg1++ )
  790. {
  791. seg2 = seg1->link;
  792. if ( seg2 )
  793. {
  794. if ( seg2->link != seg1 )
  795. {
  796. seg1->link = 0;
  797. seg1->serif = seg2->link;
  798. }
  799. }
  800. }
  801. }
  802. FT_LOCAL_DEF( FT_Error )
  803. af_latin2_hints_compute_edges( AF_GlyphHints hints,
  804. AF_Dimension dim )
  805. {
  806. AF_AxisHints axis = &hints->axis[dim];
  807. FT_Error error = AF_Err_Ok;
  808. FT_Memory memory = hints->memory;
  809. AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
  810. AF_Segment segments = axis->segments;
  811. AF_Segment segment_limit = segments + axis->num_segments;
  812. AF_Segment seg;
  813. AF_Direction up_dir;
  814. FT_Fixed scale;
  815. FT_Pos edge_distance_threshold;
  816. FT_Pos segment_length_threshold;
  817. axis->num_edges = 0;
  818. scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
  819. : hints->y_scale;
  820. up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
  821. : AF_DIR_RIGHT;
  822. /*
  823. * We want to ignore very small (mostly serif) segments, we do that
  824. * by ignoring those that whose length is less than a given fraction
  825. * of the standard width. If there is no standard width, we ignore
  826. * those that are less than a given size in pixels
  827. *
  828. * also, unlink serif segments that are linked to segments farther
  829. * than 50% of the standard width
  830. */
  831. if ( dim == AF_DIMENSION_HORZ )
  832. {
  833. if ( laxis->width_count > 0 )
  834. segment_length_threshold = (laxis->standard_width * 10 ) >> 4;
  835. else
  836. segment_length_threshold = FT_DivFix( 64, hints->y_scale );
  837. }
  838. else
  839. segment_length_threshold = 0;
  840. /*********************************************************************/
  841. /* */
  842. /* We will begin by generating a sorted table of edges for the */
  843. /* current direction. To do so, we simply scan each segment and try */
  844. /* to find an edge in our table that corresponds to its position. */
  845. /* */
  846. /* If no edge is found, we create and insert a new edge in the */
  847. /* sorted table. Otherwise, we simply add the segment to the edge's */
  848. /* list which will be processed in the second step to compute the */
  849. /* edge's properties. */
  850. /* */
  851. /* Note that the edges table is sorted along the segment/edge */
  852. /* position. */
  853. /* */
  854. /*********************************************************************/
  855. edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
  856. scale );
  857. if ( edge_distance_threshold > 64 / 4 )
  858. edge_distance_threshold = 64 / 4;
  859. edge_distance_threshold = FT_DivFix( edge_distance_threshold,
  860. scale );
  861. for ( seg = segments; seg < segment_limit; seg++ )
  862. {
  863. AF_Edge found = 0;
  864. FT_Int ee;
  865. if ( seg->height < segment_length_threshold )
  866. continue;
  867. /* A special case for serif edges: If they are smaller than */
  868. /* 1.5 pixels we ignore them. */
  869. if ( seg->serif )
  870. {
  871. FT_Pos dist = seg->serif->pos - seg->pos;
  872. if (dist < 0)
  873. dist = -dist;
  874. if (dist >= laxis->standard_width >> 1)
  875. {
  876. /* unlink this serif, it is too distant from its reference stem */
  877. seg->serif = NULL;
  878. }
  879. else if ( 2*seg->height < 3 * segment_length_threshold )
  880. continue;
  881. }
  882. /* look for an edge corresponding to the segment */
  883. for ( ee = 0; ee < axis->num_edges; ee++ )
  884. {
  885. AF_Edge edge = axis->edges + ee;
  886. FT_Pos dist;
  887. dist = seg->pos - edge->fpos;
  888. if ( dist < 0 )
  889. dist = -dist;
  890. if ( dist < edge_distance_threshold && edge->dir == seg->dir )
  891. {
  892. found = edge;
  893. break;
  894. }
  895. }
  896. if ( !found )
  897. {
  898. AF_Edge edge;
  899. /* insert a new edge in the list and */
  900. /* sort according to the position */
  901. error = af_axis_hints_new_edge( axis, seg->pos, seg->dir, memory, &edge );
  902. if ( error )
  903. goto Exit;
  904. /* add the segment to the new edge's list */
  905. FT_ZERO( edge );
  906. edge->first = seg;
  907. edge->last = seg;
  908. edge->fpos = seg->pos;
  909. edge->dir = seg->dir;
  910. edge->opos = edge->pos = FT_MulFix( seg->pos, scale );
  911. seg->edge_next = seg;
  912. }
  913. else
  914. {
  915. /* if an edge was found, simply add the segment to the edge's */
  916. /* list */
  917. seg->edge_next = found->first;
  918. found->last->edge_next = seg;
  919. found->last = seg;
  920. }
  921. }
  922. /*********************************************************************/
  923. /* */
  924. /* Good, we will now compute each edge's properties according to */
  925. /* segments found on its position. Basically, these are: */
  926. /* */
  927. /* - edge's main direction */
  928. /* - stem edge, serif edge or both (which defaults to stem then) */
  929. /* - rounded edge, straight or both (which defaults to straight) */
  930. /* - link for edge */
  931. /* */
  932. /*********************************************************************/
  933. /* first of all, set the `edge' field in each segment -- this is */
  934. /* required in order to compute edge links */
  935. /*
  936. * Note that removing this loop and setting the `edge' field of each
  937. * segment directly in the code above slows down execution speed for
  938. * some reasons on platforms like the Sun.
  939. */
  940. {
  941. AF_Edge edges = axis->edges;
  942. AF_Edge edge_limit = edges + axis->num_edges;
  943. AF_Edge edge;
  944. for ( edge = edges; edge < edge_limit; edge++ )
  945. {
  946. seg = edge->first;
  947. if ( seg )
  948. do
  949. {
  950. seg->edge = edge;
  951. seg = seg->edge_next;
  952. } while ( seg != edge->first );
  953. }
  954. /* now, compute each edge properties */
  955. for ( edge = edges; edge < edge_limit; edge++ )
  956. {
  957. FT_Int is_round = 0; /* does it contain round segments? */
  958. FT_Int is_straight = 0; /* does it contain straight segments? */
  959. FT_Pos ups = 0; /* number of upwards segments */
  960. FT_Pos downs = 0; /* number of downwards segments */
  961. seg = edge->first;
  962. do
  963. {
  964. FT_Bool is_serif;
  965. /* check for roundness of segment */
  966. if ( seg->flags & AF_EDGE_ROUND )
  967. is_round++;
  968. else
  969. is_straight++;
  970. /* check for segment direction */
  971. if ( seg->dir == up_dir )
  972. ups += seg->max_coord-seg->min_coord;
  973. else
  974. downs += seg->max_coord-seg->min_coord;
  975. /* check for links -- if seg->serif is set, then seg->link must */
  976. /* be ignored */
  977. is_serif = (FT_Bool)( seg->serif &&
  978. seg->serif->edge &&
  979. seg->serif->edge != edge );
  980. if ( ( seg->link && seg->link->edge != NULL ) || is_serif )
  981. {
  982. AF_Edge edge2;
  983. AF_Segment seg2;
  984. edge2 = edge->link;
  985. seg2 = seg->link;
  986. if ( is_serif )
  987. {
  988. seg2 = seg->serif;
  989. edge2 = edge->serif;
  990. }
  991. if ( edge2 )
  992. {
  993. FT_Pos edge_delta;
  994. FT_Pos seg_delta;
  995. edge_delta = edge->fpos - edge2->fpos;
  996. if ( edge_delta < 0 )
  997. edge_delta = -edge_delta;
  998. seg_delta = seg->pos - seg2->pos;
  999. if ( seg_delta < 0 )
  1000. seg_delta = -seg_delta;
  1001. if ( seg_delta < edge_delta )
  1002. edge2 = seg2->edge;
  1003. }
  1004. else
  1005. edge2 = seg2->edge;
  1006. if ( is_serif )
  1007. {
  1008. edge->serif = edge2;
  1009. edge2->flags |= AF_EDGE_SERIF;
  1010. }
  1011. else
  1012. edge->link = edge2;
  1013. }
  1014. seg = seg->edge_next;
  1015. } while ( seg != edge->first );
  1016. /* set the round/straight flags */
  1017. edge->flags = AF_EDGE_NORMAL;
  1018. if ( is_round > 0 && is_round >= is_straight )
  1019. edge->flags |= AF_EDGE_ROUND;
  1020. #if 0
  1021. /* set the edge's main direction */
  1022. edge->dir = AF_DIR_NONE;
  1023. if ( ups > downs )
  1024. edge->dir = (FT_Char)up_dir;
  1025. else if ( ups < downs )
  1026. edge->dir = (FT_Char)-up_dir;
  1027. else if ( ups == downs )
  1028. edge->dir = 0; /* both up and down! */
  1029. #endif
  1030. /* gets rid of serifs if link is set */
  1031. /* XXX: This gets rid of many unpleasant artefacts! */
  1032. /* Example: the `c' in cour.pfa at size 13 */
  1033. if ( edge->serif && edge->link )
  1034. edge->serif = 0;
  1035. }
  1036. }
  1037. Exit:
  1038. return error;
  1039. }
  1040. FT_LOCAL_DEF( FT_Error )
  1041. af_latin2_hints_detect_features( AF_GlyphHints hints,
  1042. AF_Dimension dim )
  1043. {
  1044. FT_Error error;
  1045. error = af_latin2_hints_compute_segments( hints, dim );
  1046. if ( !error )
  1047. {
  1048. af_latin2_hints_link_segments( hints, dim );
  1049. error = af_latin2_hints_compute_edges( hints, dim );
  1050. }
  1051. return error;
  1052. }
  1053. FT_LOCAL_DEF( void )
  1054. af_latin2_hints_compute_blue_edges( AF_GlyphHints hints,
  1055. AF_LatinMetrics metrics )
  1056. {
  1057. AF_AxisHints axis = &hints->axis[ AF_DIMENSION_VERT ];
  1058. AF_Edge edge = axis->edges;
  1059. AF_Edge edge_limit = edge + axis->num_edges;
  1060. AF_LatinAxis latin = &metrics->axis[ AF_DIMENSION_VERT ];
  1061. FT_Fixed scale = latin->scale;
  1062. FT_Pos best_dist0; /* initial threshold */
  1063. /* compute the initial threshold as a fraction of the EM size */
  1064. best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale );
  1065. if ( best_dist0 > 64 / 2 )
  1066. best_dist0 = 64 / 2;
  1067. /* compute which blue zones are active, i.e. have their scaled */
  1068. /* size < 3/4 pixels */
  1069. /* for each horizontal edge search the blue zone which is closest */
  1070. for ( ; edge < edge_limit; edge++ )
  1071. {
  1072. FT_Int bb;
  1073. AF_Width best_blue = NULL;
  1074. FT_Pos best_dist = best_dist0;
  1075. for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
  1076. {
  1077. AF_LatinBlue blue = latin->blues + bb;
  1078. FT_Bool is_top_blue, is_major_dir;
  1079. /* skip inactive blue zones (i.e., those that are too small) */
  1080. if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
  1081. continue;
  1082. /* if it is a top zone, check for right edges -- if it is a bottom */
  1083. /* zone, check for left edges */
  1084. /* */
  1085. /* of course, that's for TrueType */
  1086. is_top_blue = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 );
  1087. is_major_dir = FT_BOOL( edge->dir == axis->major_dir );
  1088. /* if it is a top zone, the edge must be against the major */
  1089. /* direction; if it is a bottom zone, it must be in the major */
  1090. /* direction */
  1091. if ( is_top_blue ^ is_major_dir )
  1092. {
  1093. FT_Pos dist;
  1094. AF_Width compare;
  1095. /* if it's a rounded edge, compare it to the overshoot position */
  1096. /* if it's a flat edge, compare it to the reference position */
  1097. if ( edge->flags & AF_EDGE_ROUND )
  1098. compare = &blue->shoot;
  1099. else
  1100. compare = &blue->ref;
  1101. dist = edge->fpos - compare->org;
  1102. if (dist < 0)
  1103. dist = -dist;
  1104. dist = FT_MulFix( dist, scale );
  1105. if ( dist < best_dist )
  1106. {
  1107. best_dist = dist;
  1108. best_blue = compare;
  1109. }
  1110. #if 0
  1111. /* now, compare it to the overshoot position if the edge is */
  1112. /* rounded, and if the edge is over the reference position of a */
  1113. /* top zone, or under the reference position of a bottom zone */
  1114. if ( edge->flags & AF_EDGE_ROUND && dist != 0 )
  1115. {
  1116. FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
  1117. if ( is_top_blue ^ is_under_ref )
  1118. {
  1119. blue = latin->blues + bb;
  1120. dist = edge->fpos - blue->shoot.org;
  1121. if ( dist < 0 )
  1122. dist = -dist;
  1123. dist = FT_MulFix( dist, scale );
  1124. if ( dist < best_dist )
  1125. {
  1126. best_dist = dist;
  1127. best_blue = & blue->shoot;
  1128. }
  1129. }
  1130. }
  1131. #endif
  1132. }
  1133. }
  1134. if ( best_blue )
  1135. edge->blue_edge = best_blue;
  1136. }
  1137. }
  1138. static FT_Error
  1139. af_latin2_hints_init( AF_GlyphHints hints,
  1140. AF_LatinMetrics metrics )
  1141. {
  1142. FT_Render_Mode mode;
  1143. FT_UInt32 scaler_flags, other_flags;
  1144. FT_Face face = metrics->root.scaler.face;
  1145. af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics );
  1146. /*
  1147. * correct x_scale and y_scale if needed, since they may have
  1148. * been modified `af_latin2_metrics_scale_dim' above
  1149. */
  1150. hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
  1151. hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
  1152. hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
  1153. hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
  1154. /* compute flags depending on render mode, etc. */
  1155. mode = metrics->root.scaler.render_mode;
  1156. #if 0 /* #ifdef AF_USE_WARPER */
  1157. if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
  1158. {
  1159. metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
  1160. }
  1161. #endif
  1162. scaler_flags = hints->scaler_flags;
  1163. other_flags = 0;
  1164. /*
  1165. * We snap the width of vertical stems for the monochrome and
  1166. * horizontal LCD rendering targets only.
  1167. */
  1168. if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
  1169. other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
  1170. /*
  1171. * We snap the width of horizontal stems for the monochrome and
  1172. * vertical LCD rendering targets only.
  1173. */
  1174. if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
  1175. other_flags |= AF_LATIN_HINTS_VERT_SNAP;
  1176. /*
  1177. * We adjust stems to full pixels only if we don't use the `light' mode.
  1178. */
  1179. if ( mode != FT_RENDER_MODE_LIGHT )
  1180. other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
  1181. if ( mode == FT_RENDER_MODE_MONO )
  1182. other_flags |= AF_LATIN_HINTS_MONO;
  1183. /*
  1184. * In `light' hinting mode we disable horizontal hinting completely.
  1185. * We also do it if the face is italic.
  1186. */
  1187. if ( mode == FT_RENDER_MODE_LIGHT ||
  1188. (face->style_flags & FT_STYLE_FLAG_ITALIC) != 0 )
  1189. scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
  1190. hints->scaler_flags = scaler_flags;
  1191. hints->other_flags = other_flags;
  1192. return 0;
  1193. }
  1194. /*************************************************************************/
  1195. /*************************************************************************/
  1196. /***** *****/
  1197. /***** L A T I N G L Y P H G R I D - F I T T I N G *****/
  1198. /***** *****/
  1199. /*************************************************************************/
  1200. /*************************************************************************/
  1201. /* snap a given width in scaled coordinates to one of the */
  1202. /* current standard widths */
  1203. static FT_Pos
  1204. af_latin2_snap_width( AF_Width widths,
  1205. FT_Int count,
  1206. FT_Pos width )
  1207. {
  1208. int n;
  1209. FT_Pos best = 64 + 32 + 2;
  1210. FT_Pos reference = width;
  1211. FT_Pos scaled;
  1212. for ( n = 0; n < count; n++ )
  1213. {
  1214. FT_Pos w;
  1215. FT_Pos dist;
  1216. w = widths[n].cur;
  1217. dist = width - w;
  1218. if ( dist < 0 )
  1219. dist = -dist;
  1220. if ( dist < best )
  1221. {
  1222. best = dist;
  1223. reference = w;
  1224. }
  1225. }
  1226. scaled = FT_PIX_ROUND( reference );
  1227. if ( width >= reference )
  1228. {
  1229. if ( width < scaled + 48 )
  1230. width = reference;
  1231. }
  1232. else
  1233. {
  1234. if ( width > scaled - 48 )
  1235. width = reference;
  1236. }
  1237. return width;
  1238. }
  1239. /* compute the snapped width of a given stem */
  1240. static FT_Pos
  1241. af_latin2_compute_stem_width( AF_GlyphHints hints,
  1242. AF_Dimension dim,
  1243. FT_Pos width,
  1244. AF_Edge_Flags base_flags,
  1245. AF_Edge_Flags stem_flags )
  1246. {
  1247. AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics;
  1248. AF_LatinAxis axis = & metrics->axis[dim];
  1249. FT_Pos dist = width;
  1250. FT_Int sign = 0;
  1251. FT_Int vertical = ( dim == AF_DIMENSION_VERT );
  1252. FT_UNUSED(base_flags);
  1253. if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
  1254. axis->extra_light )
  1255. return width;
  1256. if ( dist < 0 )
  1257. {
  1258. dist = -width;
  1259. sign = 1;
  1260. }
  1261. if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
  1262. ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
  1263. {
  1264. /* smooth hinting process: very lightly quantize the stem width */
  1265. /* leave the widths of serifs alone */
  1266. if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) )
  1267. goto Done_Width;
  1268. #if 0
  1269. else if ( ( base_flags & AF_EDGE_ROUND ) )
  1270. {
  1271. if ( dist < 80 )
  1272. dist = 64;
  1273. }
  1274. else if ( dist < 56 )
  1275. dist = 56;
  1276. #endif
  1277. if ( axis->width_count > 0 )
  1278. {
  1279. FT_Pos delta;
  1280. /* compare to standard width */
  1281. if ( axis->width_count > 0 )
  1282. {
  1283. delta = dist - axis->widths[0].cur;
  1284. if ( delta < 0 )
  1285. delta = -delta;
  1286. if ( delta < 40 )
  1287. {
  1288. dist = axis->widths[0].cur;
  1289. if ( dist < 48 )
  1290. dist = 48;
  1291. goto Done_Width;
  1292. }
  1293. }
  1294. if ( dist < 3 * 64 )
  1295. {
  1296. delta = dist & 63;
  1297. dist &= -64;
  1298. if ( delta < 10 )
  1299. dist += delta;
  1300. else if ( delta < 32 )
  1301. dist += 10;
  1302. else if ( delta < 54 )
  1303. dist += 54;
  1304. else
  1305. dist += delta;
  1306. }
  1307. else
  1308. dist = ( dist + 32 ) & ~63;
  1309. }
  1310. }
  1311. else
  1312. {
  1313. /* strong hinting process: snap the stem width to integer pixels */
  1314. FT_Pos org_dist = dist;
  1315. dist = af_latin2_snap_width( axis->widths, axis->width_count, dist );
  1316. if ( vertical )
  1317. {
  1318. /* in the case of vertical hinting, always round */
  1319. /* the stem heights to integer pixels */
  1320. if ( dist >= 64 )
  1321. dist = ( dist + 16 ) & ~63;
  1322. else
  1323. dist = 64;
  1324. }
  1325. else
  1326. {
  1327. if ( AF_LATIN_HINTS_DO_MONO( hints ) )
  1328. {
  1329. /* monochrome horizontal hinting: snap widths to integer pixels */
  1330. /* with a different threshold */
  1331. if ( dist < 64 )
  1332. dist = 64;
  1333. else
  1334. dist = ( dist + 32 ) & ~63;
  1335. }
  1336. else
  1337. {
  1338. /* for horizontal anti-aliased hinting, we adopt a more subtle */
  1339. /* approach: we strengthen small stems, round stems whose size */
  1340. /* is between 1 and 2 pixels to an integer, otherwise nothing */
  1341. if ( dist < 48 )
  1342. dist = ( dist + 64 ) >> 1;
  1343. else if ( dist < 128 )
  1344. {
  1345. /* We only round to an integer width if the corresponding */
  1346. /* distortion is less than 1/4 pixel. Otherwise this */
  1347. /* makes everything worse since the diagonals, which are */
  1348. /* not hinted, appear a lot bolder or thinner than the */
  1349. /* vertical stems. */
  1350. FT_Int delta;
  1351. dist = ( dist + 22 ) & ~63;
  1352. delta = dist - org_dist;
  1353. if ( delta < 0 )
  1354. delta = -delta;
  1355. if (delta >= 16)
  1356. {
  1357. dist = org_dist;
  1358. if ( dist < 48 )
  1359. dist = ( dist + 64 ) >> 1;
  1360. }
  1361. }
  1362. else
  1363. /* round otherwise to prevent color fringes in LCD mode */
  1364. dist = ( dist + 32 ) & ~63;
  1365. }
  1366. }
  1367. }
  1368. Done_Width:
  1369. if ( sign )
  1370. dist = -dist;
  1371. return dist;
  1372. }
  1373. /* align one stem edge relative to the previous stem edge */
  1374. static void
  1375. af_latin2_align_linked_edge( AF_GlyphHints hints,
  1376. AF_Dimension dim,
  1377. AF_Edge base_edge,
  1378. AF_Edge stem_edge )
  1379. {
  1380. FT_Pos dist = stem_edge->opos - base_edge->opos;
  1381. FT_Pos fitted_width = af_latin2_compute_stem_width(
  1382. hints, dim, dist,
  1383. (AF_Edge_Flags)base_edge->flags,
  1384. (AF_Edge_Flags)stem_edge->flags );
  1385. stem_edge->pos = base_edge->pos + fitted_width;
  1386. AF_LOG(( "LINK: edge %d (opos=%.2f) linked to (%.2f), "
  1387. "dist was %.2f, now %.2f\n",
  1388. stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0,
  1389. stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
  1390. }
  1391. static void
  1392. af_latin2_align_serif_edge( AF_GlyphHints hints,
  1393. AF_Edge base,
  1394. AF_Edge serif )
  1395. {
  1396. FT_UNUSED( hints );
  1397. serif->pos = base->pos + (serif->opos - base->opos);
  1398. }
  1399. /*************************************************************************/
  1400. /*************************************************************************/
  1401. /*************************************************************************/
  1402. /**** ****/
  1403. /**** E D G E H I N T I N G ****/
  1404. /**** ****/
  1405. /*************************************************************************/
  1406. /*************************************************************************/
  1407. /*************************************************************************/
  1408. FT_LOCAL_DEF( void )
  1409. af_latin2_hint_edges( AF_GlyphHints hints,
  1410. AF_Dimension dim )
  1411. {
  1412. AF_AxisHints axis = &hints->axis[dim];
  1413. AF_Edge edges = axis->edges;
  1414. AF_Edge edge_limit = edges + axis->num_edges;
  1415. AF_Edge edge;
  1416. AF_Edge anchor = 0;
  1417. FT_Int has_serifs = 0;
  1418. FT_Pos anchor_drift = 0;
  1419. AF_LOG(( "==== hinting %s edges =====\n", dim == AF_DIMENSION_HORZ ? "vertical" : "horizontal" ));
  1420. /* we begin by aligning all stems relative to the blue zone */
  1421. /* if needed -- that's only for horizontal edges */
  1422. if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
  1423. {
  1424. for ( edge = edges; edge < edge_limit; edge++ )
  1425. {
  1426. AF_Width blue;
  1427. AF_Edge edge1, edge2;
  1428. if ( edge->flags & AF_EDGE_DONE )
  1429. continue;
  1430. blue = edge->blue_edge;
  1431. edge1 = NULL;
  1432. edge2 = edge->link;
  1433. if ( blue )
  1434. {
  1435. edge1 = edge;
  1436. }
  1437. else if ( edge2 && edge2->blue_edge )
  1438. {
  1439. blue = edge2->blue_edge;
  1440. edge1 = edge2;
  1441. edge2 = edge;
  1442. }
  1443. if ( !edge1 )
  1444. continue;
  1445. AF_LOG(( "BLUE: edge %d (opos=%.2f) snapped to (%.2f), "
  1446. "was (%.2f)\n",
  1447. edge1-edges, edge1->opos / 64.0, blue->fit / 64.0,
  1448. edge1->pos / 64.0 ));
  1449. edge1->pos = blue->fit;
  1450. edge1->flags |= AF_EDGE_DONE;
  1451. if ( edge2 && !edge2->blue_edge )
  1452. {
  1453. af_latin2_align_linked_edge( hints, dim, edge1, edge2 );
  1454. edge2->flags |= AF_EDGE_DONE;
  1455. }
  1456. if ( !anchor )
  1457. {
  1458. anchor = edge;
  1459. anchor_drift = (anchor->pos - anchor->opos);
  1460. if (edge2)
  1461. anchor_drift = (anchor_drift + (edge2->pos - edge2->opos)) >> 1;
  1462. }
  1463. }
  1464. }
  1465. /* now we will align all stem edges, trying to maintain the */
  1466. /* relative order of stems in the glyph */
  1467. for ( edge = edges; edge < edge_limit; edge++ )
  1468. {
  1469. AF_Edge edge2;
  1470. if ( edge->flags & AF_EDGE_DONE )
  1471. continue;
  1472. /* skip all non-stem edges */
  1473. edge2 = edge->link;
  1474. if ( !edge2 )
  1475. {
  1476. has_serifs++;
  1477. continue;
  1478. }
  1479. /* now align the stem */
  1480. /* this should not happen, but it's better to be safe */
  1481. if ( edge2->blue_edge )
  1482. {
  1483. AF_LOG(( "ASSERTION FAILED for edge %d\n", edge2-edges ));
  1484. af_latin2_align_linked_edge( hints, dim, edge2, edge );
  1485. edge->flags |= AF_EDGE_DONE;
  1486. continue;
  1487. }
  1488. if ( !anchor )
  1489. {
  1490. FT_Pos org_len, org_center, cur_len;
  1491. FT_Pos cur_pos1, error1, error2, u_off, d_off;
  1492. org_len = edge2->opos - edge->opos;
  1493. cur_len = af_latin2_compute_stem_width(
  1494. hints, dim, org_len,
  1495. (AF_Edge_Flags)edge->flags,
  1496. (AF_Edge_Flags)edge2->flags );
  1497. if ( cur_len <= 64 )
  1498. u_off = d_off = 32;
  1499. else
  1500. {
  1501. u_off = 38;
  1502. d_off = 26;
  1503. }
  1504. if ( cur_len < 96 )
  1505. {
  1506. org_center = edge->opos + ( org_len >> 1 );
  1507. cur_pos1 = FT_PIX_ROUND( org_center );
  1508. error1 = org_center - ( cur_pos1 - u_off );
  1509. if ( error1 < 0 )
  1510. error1 = -error1;
  1511. error2 = org_center - ( cur_pos1 + d_off );
  1512. if ( error2 < 0 )
  1513. error2 = -error2;
  1514. if ( error1 < error2 )
  1515. cur_pos1 -= u_off;
  1516. else
  1517. cur_pos1 += d_off;
  1518. edge->pos = cur_pos1 - cur_len / 2;
  1519. edge2->pos = edge->pos + cur_len;
  1520. }
  1521. else
  1522. edge->pos = FT_PIX_ROUND( edge->opos );
  1523. AF_LOG(( "ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f) "
  1524. "snapped to (%.2f) (%.2f)\n",
  1525. edge-edges, edge->opos / 64.0,
  1526. edge2-edges, edge2->opos / 64.0,
  1527. edge->pos / 64.0, edge2->pos / 64.0 ));
  1528. anchor = edge;
  1529. edge->flags |= AF_EDGE_DONE;
  1530. af_latin2_align_linked_edge( hints, dim, edge, edge2 );
  1531. edge2->flags |= AF_EDGE_DONE;
  1532. anchor_drift = ( (anchor->pos - anchor->opos) +
  1533. (edge2->pos - edge2->opos)) >> 1;
  1534. AF_LOG(( "DRIFT: %.2f\n", anchor_drift/64.0 ));
  1535. }
  1536. else
  1537. {
  1538. FT_Pos org_pos, org_len, org_center, cur_center, cur_len;
  1539. FT_Pos org_left, org_right;
  1540. org_pos = edge->opos + anchor_drift;
  1541. org_len = edge2->opos - edge->opos;
  1542. org_center = org_pos + ( org_len >> 1 );
  1543. cur_len = af_latin2_compute_stem_width(
  1544. hints, dim, org_len,
  1545. (AF_Edge_Flags)edge->flags,
  1546. (AF_Edge_Flags)edge2->flags );
  1547. org_left = org_pos + ((org_len - cur_len) >> 1);
  1548. org_right = org_pos + ((org_len + cur_len) >> 1);
  1549. AF_LOG(( "ALIGN: left=%.2f right=%.2f ", org_left/64.0, org_right/64.0 ));
  1550. cur_center = org_center;
  1551. if ( edge2->flags & AF_EDGE_DONE )
  1552. {
  1553. AF_LOG(( "\n" ));
  1554. edge->pos = edge2->pos - cur_len;
  1555. }
  1556. else
  1557. {
  1558. /* we want to compare several displacement, and choose
  1559. * the one that increases fitness while minimizing
  1560. * distortion as well
  1561. */
  1562. FT_Pos displacements[6], scores[6], org, fit, delta;
  1563. FT_UInt count = 0;
  1564. /* note: don't even try to fit tiny stems */
  1565. if ( cur_len < 32 )
  1566. {
  1567. AF_LOG(( "tiny stem\n" ));
  1568. goto AlignStem;
  1569. }
  1570. /* if the span is within a single pixel, don't touch it */
  1571. if ( FT_PIX_FLOOR(org_left) == FT_PIX_CEIL(org_right) )
  1572. {
  1573. AF_LOG(( "single pixel stem\n" ));
  1574. goto AlignStem;
  1575. }
  1576. if (cur_len <= 96)
  1577. {
  1578. /* we want to avoid the absolute worst case which is
  1579. * when the left and right edges of the span each represent
  1580. * about 50% of the gray. we'd better want to change this
  1581. * to 25/75%, since this is much more pleasant to the eye with
  1582. * very acceptable distortion
  1583. */
  1584. FT_Pos frac_left = (org_left) & 63;
  1585. FT_Pos frac_right = (org_right) & 63;
  1586. if ( frac_left >= 22 && frac_left <= 42 &&
  1587. frac_right >= 22 && frac_right <= 42 )
  1588. {
  1589. org = frac_left;
  1590. fit = (org <= 32) ? 16 : 48;
  1591. delta = FT_ABS(fit - org);
  1592. displacements[count] = fit - org;
  1593. scores[count++] = delta;
  1594. AF_LOG(( "dispA=%.2f (%d) ", (fit - org)/64.0, delta ));
  1595. org = frac_right;
  1596. fit = (org <= 32) ? 16 : 48;
  1597. delta = FT_ABS(fit - org);
  1598. displacements[count] = fit - org;
  1599. scores[count++] = delta;
  1600. AF_LOG(( "dispB=%.2f (%d) ", (fit - org)/64.0, delta ));
  1601. }
  1602. }
  1603. /* snapping the left edge to the grid */
  1604. org = org_left;
  1605. fit = FT_PIX_ROUND(org);
  1606. delta = FT_ABS(fit - org);
  1607. displacements[count] = fit - org;
  1608. scores[count++] = delta;
  1609. AF_LOG(( "dispC=%.2f (%d) ", (fit - org)/64.0, delta ));
  1610. /* snapping the right edge to the grid */
  1611. org = org_right;
  1612. fit = FT_PIX_ROUND(org);
  1613. delta = FT_ABS(fit - org);
  1614. displacements[count] = fit - org;
  1615. scores[count++] = delta;
  1616. AF_LOG(( "dispD=%.2f (%d) ", (fit - org)/64.0, delta ));
  1617. /* now find the best displacement */
  1618. {
  1619. FT_Pos best_score = scores[0];
  1620. FT_Pos best_disp = displacements[0];
  1621. FT_UInt nn;
  1622. for (nn = 1; nn < count; nn++)
  1623. {
  1624. if (scores[nn] < best_score)
  1625. {
  1626. best_score = scores[nn];
  1627. best_disp = displacements[nn];
  1628. }
  1629. }
  1630. cur_center = org_center + best_disp;
  1631. }
  1632. AF_LOG(( "\n" ));
  1633. }
  1634. AlignStem:
  1635. edge->pos = cur_center - (cur_len >> 1);
  1636. edge2->pos = edge->pos + cur_len;
  1637. AF_LOG(( "STEM1: %d (opos=%.2f) to %d (opos=%.2f) "
  1638. "snapped to (%.2f) and (%.2f), org_len = %.2f cur_len=%.2f\n",
  1639. edge-edges, edge->opos / 64.0,
  1640. edge2-edges, edge2->opos / 64.0,
  1641. edge->pos / 64.0, edge2->pos / 64.0,
  1642. org_len / 64.0, cur_len / 64.0 ));
  1643. edge->flags |= AF_EDGE_DONE;
  1644. edge2->flags |= AF_EDGE_DONE;
  1645. if ( edge > edges && edge->pos < edge[-1].pos )
  1646. {
  1647. AF_LOG(( "BOUND: %d (pos=%.2f) to (%.2f)\n",
  1648. edge-edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
  1649. edge->pos = edge[-1].pos;
  1650. }
  1651. }
  1652. }
  1653. /* make sure that lowercase m's maintain their symmetry */
  1654. /* In general, lowercase m's have six vertical edges if they are sans */
  1655. /* serif, or twelve if they are with serifs. This implementation is */
  1656. /* based on that assumption, and seems to work very well with most */
  1657. /* faces. However, if for a certain face this assumption is not */
  1658. /* true, the m is just rendered like before. In addition, any stem */
  1659. /* correction will only be applied to symmetrical glyphs (even if the */
  1660. /* glyph is not an m), so the potential for unwanted distortion is */
  1661. /* relatively low. */
  1662. /* We don't handle horizontal edges since we can't easily assure that */
  1663. /* the third (lowest) stem aligns with the base line; it might end up */
  1664. /* one pixel higher or lower. */
  1665. #if 0
  1666. {
  1667. FT_Int n_edges = edge_limit - edges;
  1668. if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
  1669. {
  1670. AF_Edge edge1, edge2, edge3;
  1671. FT_Pos dist1, dist2, span, delta;
  1672. if ( n_edges == 6 )
  1673. {
  1674. edge1 = edges;
  1675. edge2 = edges + 2;
  1676. edge3 = edges + 4;
  1677. }
  1678. else
  1679. {
  1680. edge1 = edges + 1;
  1681. edge2 = edges + 5;
  1682. edge3 = edges + 9;
  1683. }
  1684. dist1 = edge2->opos - edge1->opos;
  1685. dist2 = edge3->opos - edge2->opos;
  1686. span = dist1 - dist2;
  1687. if ( span < 0 )
  1688. span = -span;
  1689. if ( span < 8 )
  1690. {
  1691. delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
  1692. edge3->pos -= delta;
  1693. if ( edge3->link )
  1694. edge3->link->pos -= delta;
  1695. /* move the serifs along with the stem */
  1696. if ( n_edges == 12 )
  1697. {
  1698. ( edges + 8 )->pos -= delta;
  1699. ( edges + 11 )->pos -= delta;
  1700. }
  1701. edge3->flags |= AF_EDGE_DONE;
  1702. if ( edge3->link )
  1703. edge3->link->flags |= AF_EDGE_DONE;
  1704. }
  1705. }
  1706. }
  1707. #endif
  1708. if ( has_serifs || !anchor )
  1709. {
  1710. /*
  1711. * now hint the remaining edges (serifs and single) in order
  1712. * to complete our processing
  1713. */
  1714. for ( edge = edges; edge < edge_limit; edge++ )
  1715. {
  1716. FT_Pos delta;
  1717. if ( edge->flags & AF_EDGE_DONE )
  1718. continue;
  1719. delta = 1000;
  1720. if ( edge->serif )
  1721. {
  1722. delta = edge->serif->opos - edge->opos;
  1723. if ( delta < 0 )
  1724. delta = -delta;
  1725. }
  1726. if ( delta < 64 + 16 )
  1727. {
  1728. af_latin2_align_serif_edge( hints, edge->serif, edge );
  1729. AF_LOG(( "SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f) "
  1730. "aligned to (%.2f)\n",
  1731. edge-edges, edge->opos / 64.0,
  1732. edge->serif - edges, edge->serif->opos / 64.0,
  1733. edge->pos / 64.0 ));
  1734. }
  1735. else if ( !anchor )
  1736. {
  1737. AF_LOG(( "SERIF_ANCHOR: edge %d (opos=%.2f) snapped to (%.2f)\n",
  1738. edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
  1739. edge->pos = FT_PIX_ROUND( edge->opos );
  1740. anchor = edge;
  1741. }
  1742. else
  1743. {
  1744. AF_Edge before, after;
  1745. for ( before = edge - 1; before >= edges; before-- )
  1746. if ( before->flags & AF_EDGE_DONE )
  1747. break;
  1748. for ( after = edge + 1; after < edge_limit; after++ )
  1749. if ( after->flags & AF_EDGE_DONE )
  1750. break;
  1751. if ( before >= edges && before < edge &&
  1752. after < edge_limit && after > edge )
  1753. {
  1754. if ( after->opos == before->opos )
  1755. edge->pos = before->pos;
  1756. else
  1757. edge->pos = before->pos +
  1758. FT_MulDiv( edge->opos - before->opos,
  1759. after->pos - before->pos,
  1760. after->opos - before->opos );
  1761. AF_LOG(( "SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f) from %d (opos=%.2f)\n",
  1762. edge-edges, edge->opos / 64.0, edge->pos / 64.0, before - edges, before->opos / 64.0 ));