/src/freetype/src/autofit/afhints.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 1299 lines · 918 code · 277 blank · 104 comment · 159 complexity · bdbe3667f07748a90d3e59ed985ac1c3 MD5 · raw file

  1. /***************************************************************************/
  2. /* */
  3. /* afhints.c */
  4. /* */
  5. /* Auto-fitter hinting routines (body). */
  6. /* */
  7. /* Copyright 2003-2007, 2009-2011 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 "afhints.h"
  18. #include "aferrors.h"
  19. #include FT_INTERNAL_CALC_H
  20. /* Get new segment for given axis. */
  21. FT_LOCAL_DEF( FT_Error )
  22. af_axis_hints_new_segment( AF_AxisHints axis,
  23. FT_Memory memory,
  24. AF_Segment *asegment )
  25. {
  26. FT_Error error = AF_Err_Ok;
  27. AF_Segment segment = NULL;
  28. if ( axis->num_segments >= axis->max_segments )
  29. {
  30. FT_Int old_max = axis->max_segments;
  31. FT_Int new_max = old_max;
  32. FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *segment ) );
  33. if ( old_max >= big_max )
  34. {
  35. error = AF_Err_Out_Of_Memory;
  36. goto Exit;
  37. }
  38. new_max += ( new_max >> 2 ) + 4;
  39. if ( new_max < old_max || new_max > big_max )
  40. new_max = big_max;
  41. if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
  42. goto Exit;
  43. axis->max_segments = new_max;
  44. }
  45. segment = axis->segments + axis->num_segments++;
  46. Exit:
  47. *asegment = segment;
  48. return error;
  49. }
  50. /* Get new edge for given axis, direction, and position. */
  51. FT_LOCAL( FT_Error )
  52. af_axis_hints_new_edge( AF_AxisHints axis,
  53. FT_Int fpos,
  54. AF_Direction dir,
  55. FT_Memory memory,
  56. AF_Edge *aedge )
  57. {
  58. FT_Error error = AF_Err_Ok;
  59. AF_Edge edge = NULL;
  60. AF_Edge edges;
  61. if ( axis->num_edges >= axis->max_edges )
  62. {
  63. FT_Int old_max = axis->max_edges;
  64. FT_Int new_max = old_max;
  65. FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *edge ) );
  66. if ( old_max >= big_max )
  67. {
  68. error = AF_Err_Out_Of_Memory;
  69. goto Exit;
  70. }
  71. new_max += ( new_max >> 2 ) + 4;
  72. if ( new_max < old_max || new_max > big_max )
  73. new_max = big_max;
  74. if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
  75. goto Exit;
  76. axis->max_edges = new_max;
  77. }
  78. edges = axis->edges;
  79. edge = edges + axis->num_edges;
  80. while ( edge > edges )
  81. {
  82. if ( edge[-1].fpos < fpos )
  83. break;
  84. /* we want the edge with same position and minor direction */
  85. /* to appear before those in the major one in the list */
  86. if ( edge[-1].fpos == fpos && dir == axis->major_dir )
  87. break;
  88. edge[0] = edge[-1];
  89. edge--;
  90. }
  91. axis->num_edges++;
  92. FT_ZERO( edge );
  93. edge->fpos = (FT_Short)fpos;
  94. edge->dir = (FT_Char)dir;
  95. Exit:
  96. *aedge = edge;
  97. return error;
  98. }
  99. #ifdef FT_DEBUG_AUTOFIT
  100. #include FT_CONFIG_STANDARD_LIBRARY_H
  101. static const char*
  102. af_dir_str( AF_Direction dir )
  103. {
  104. const char* result;
  105. switch ( dir )
  106. {
  107. case AF_DIR_UP:
  108. result = "up";
  109. break;
  110. case AF_DIR_DOWN:
  111. result = "down";
  112. break;
  113. case AF_DIR_LEFT:
  114. result = "left";
  115. break;
  116. case AF_DIR_RIGHT:
  117. result = "right";
  118. break;
  119. default:
  120. result = "none";
  121. }
  122. return result;
  123. }
  124. #define AF_INDEX_NUM( ptr, base ) ( (ptr) ? ( (ptr) - (base) ) : -1 )
  125. #ifdef __cplusplus
  126. extern "C" {
  127. #endif
  128. void
  129. af_glyph_hints_dump_points( AF_GlyphHints hints )
  130. {
  131. AF_Point points = hints->points;
  132. AF_Point limit = points + hints->num_points;
  133. AF_Point point;
  134. printf( "Table of points:\n" );
  135. printf( " [ index | xorg | yorg | xscale | yscale"
  136. " | xfit | yfit | flags ]\n" );
  137. for ( point = points; point < limit; point++ )
  138. {
  139. printf( " [ %5d | %5d | %5d | %6.2f | %6.2f"
  140. " | %5.2f | %5.2f | %c%c%c%c%c%c ]\n",
  141. point - points,
  142. point->fx,
  143. point->fy,
  144. point->ox / 64.0,
  145. point->oy / 64.0,
  146. point->x / 64.0,
  147. point->y / 64.0,
  148. ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' ',
  149. ( point->flags & AF_FLAG_INFLECTION ) ? 'i' : ' ',
  150. ( point->flags & AF_FLAG_EXTREMA_X ) ? '<' : ' ',
  151. ( point->flags & AF_FLAG_EXTREMA_Y ) ? 'v' : ' ',
  152. ( point->flags & AF_FLAG_ROUND_X ) ? '(' : ' ',
  153. ( point->flags & AF_FLAG_ROUND_Y ) ? 'u' : ' ');
  154. }
  155. printf( "\n" );
  156. }
  157. #ifdef __cplusplus
  158. }
  159. #endif
  160. static const char*
  161. af_edge_flags_to_string( AF_Edge_Flags flags )
  162. {
  163. static char temp[32];
  164. int pos = 0;
  165. if ( flags & AF_EDGE_ROUND )
  166. {
  167. ft_memcpy( temp + pos, "round", 5 );
  168. pos += 5;
  169. }
  170. if ( flags & AF_EDGE_SERIF )
  171. {
  172. if ( pos > 0 )
  173. temp[pos++] = ' ';
  174. ft_memcpy( temp + pos, "serif", 5 );
  175. pos += 5;
  176. }
  177. if ( pos == 0 )
  178. return "normal";
  179. temp[pos] = 0;
  180. return temp;
  181. }
  182. /* Dump the array of linked segments. */
  183. #ifdef __cplusplus
  184. extern "C" {
  185. #endif
  186. void
  187. af_glyph_hints_dump_segments( AF_GlyphHints hints )
  188. {
  189. FT_Int dimension;
  190. for ( dimension = 1; dimension >= 0; dimension-- )
  191. {
  192. AF_AxisHints axis = &hints->axis[dimension];
  193. AF_Segment segments = axis->segments;
  194. AF_Segment limit = segments + axis->num_segments;
  195. AF_Segment seg;
  196. printf ( "Table of %s segments:\n",
  197. dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
  198. printf ( " [ index | pos | dir | link | serif |"
  199. " height | extra | flags ]\n" );
  200. for ( seg = segments; seg < limit; seg++ )
  201. {
  202. printf ( " [ %5d | %5.2g | %5s | %4d | %5d | %6d | %5d | %11s ]\n",
  203. seg - segments,
  204. dimension == AF_DIMENSION_HORZ ? (int)seg->first->ox / 64.0
  205. : (int)seg->first->oy / 64.0,
  206. af_dir_str( (AF_Direction)seg->dir ),
  207. AF_INDEX_NUM( seg->link, segments ),
  208. AF_INDEX_NUM( seg->serif, segments ),
  209. seg->height,
  210. seg->height - ( seg->max_coord - seg->min_coord ),
  211. af_edge_flags_to_string( (AF_Edge_Flags)seg->flags ) );
  212. }
  213. printf( "\n" );
  214. }
  215. }
  216. #ifdef __cplusplus
  217. }
  218. #endif
  219. /* Fetch number of segments. */
  220. #ifdef __cplusplus
  221. extern "C" {
  222. #endif
  223. FT_Error
  224. af_glyph_hints_get_num_segments( AF_GlyphHints hints,
  225. FT_Int dimension,
  226. FT_Int* num_segments )
  227. {
  228. AF_Dimension dim;
  229. AF_AxisHints axis;
  230. dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
  231. axis = &hints->axis[dim];
  232. *num_segments = axis->num_segments;
  233. return AF_Err_Ok;
  234. }
  235. #ifdef __cplusplus
  236. }
  237. #endif
  238. /* Fetch offset of segments into user supplied offset array. */
  239. #ifdef __cplusplus
  240. extern "C" {
  241. #endif
  242. FT_Error
  243. af_glyph_hints_get_segment_offset( AF_GlyphHints hints,
  244. FT_Int dimension,
  245. FT_Int idx,
  246. FT_Pos* offset )
  247. {
  248. AF_Dimension dim;
  249. AF_AxisHints axis;
  250. AF_Segment seg;
  251. if ( !offset )
  252. return AF_Err_Invalid_Argument;
  253. dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
  254. axis = &hints->axis[dim];
  255. if ( idx < 0 || idx >= axis->num_segments )
  256. return AF_Err_Invalid_Argument;
  257. seg = &axis->segments[idx];
  258. *offset = (dim == AF_DIMENSION_HORZ) ? seg->first->ox
  259. : seg->first->oy;
  260. return AF_Err_Ok;
  261. }
  262. #ifdef __cplusplus
  263. }
  264. #endif
  265. /* Dump the array of linked edges. */
  266. #ifdef __cplusplus
  267. extern "C" {
  268. #endif
  269. void
  270. af_glyph_hints_dump_edges( AF_GlyphHints hints )
  271. {
  272. FT_Int dimension;
  273. for ( dimension = 1; dimension >= 0; dimension-- )
  274. {
  275. AF_AxisHints axis = &hints->axis[dimension];
  276. AF_Edge edges = axis->edges;
  277. AF_Edge limit = edges + axis->num_edges;
  278. AF_Edge edge;
  279. /*
  280. * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
  281. * since they have a constant X coordinate.
  282. */
  283. printf ( "Table of %s edges:\n",
  284. dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
  285. printf ( " [ index | pos | dir | link |"
  286. " serif | blue | opos | pos | flags ]\n" );
  287. for ( edge = edges; edge < limit; edge++ )
  288. {
  289. printf ( " [ %5d | %5.2g | %5s | %4d |"
  290. " %5d | %c | %5.2f | %5.2f | %11s ]\n",
  291. edge - edges,
  292. (int)edge->opos / 64.0,
  293. af_dir_str( (AF_Direction)edge->dir ),
  294. AF_INDEX_NUM( edge->link, edges ),
  295. AF_INDEX_NUM( edge->serif, edges ),
  296. edge->blue_edge ? 'y' : 'n',
  297. edge->opos / 64.0,
  298. edge->pos / 64.0,
  299. af_edge_flags_to_string( (AF_Edge_Flags)edge->flags ) );
  300. }
  301. printf( "\n" );
  302. }
  303. }
  304. #ifdef __cplusplus
  305. }
  306. #endif
  307. #else /* !FT_DEBUG_AUTOFIT */
  308. /* these empty stubs are only used to link the `ftgrid' test program */
  309. /* if debugging is disabled */
  310. #ifdef __cplusplus
  311. extern "C" {
  312. #endif
  313. void
  314. af_glyph_hints_dump_points( AF_GlyphHints hints )
  315. {
  316. FT_UNUSED( hints );
  317. }
  318. void
  319. af_glyph_hints_dump_segments( AF_GlyphHints hints )
  320. {
  321. FT_UNUSED( hints );
  322. }
  323. FT_Error
  324. af_glyph_hints_get_num_segments( AF_GlyphHints hints,
  325. FT_Int dimension,
  326. FT_Int* num_segments )
  327. {
  328. FT_UNUSED( hints );
  329. FT_UNUSED( dimension );
  330. FT_UNUSED( num_segments );
  331. return 0;
  332. }
  333. FT_Error
  334. af_glyph_hints_get_segment_offset( AF_GlyphHints hints,
  335. FT_Int dimension,
  336. FT_Int idx,
  337. FT_Pos* offset )
  338. {
  339. FT_UNUSED( hints );
  340. FT_UNUSED( dimension );
  341. FT_UNUSED( idx );
  342. FT_UNUSED( offset );
  343. return 0;
  344. }
  345. void
  346. af_glyph_hints_dump_edges( AF_GlyphHints hints )
  347. {
  348. FT_UNUSED( hints );
  349. }
  350. #ifdef __cplusplus
  351. }
  352. #endif
  353. #endif /* !FT_DEBUG_AUTOFIT */
  354. /* Compute the direction value of a given vector. */
  355. FT_LOCAL_DEF( AF_Direction )
  356. af_direction_compute( FT_Pos dx,
  357. FT_Pos dy )
  358. {
  359. FT_Pos ll, ss; /* long and short arm lengths */
  360. AF_Direction dir; /* candidate direction */
  361. if ( dy >= dx )
  362. {
  363. if ( dy >= -dx )
  364. {
  365. dir = AF_DIR_UP;
  366. ll = dy;
  367. ss = dx;
  368. }
  369. else
  370. {
  371. dir = AF_DIR_LEFT;
  372. ll = -dx;
  373. ss = dy;
  374. }
  375. }
  376. else /* dy < dx */
  377. {
  378. if ( dy >= -dx )
  379. {
  380. dir = AF_DIR_RIGHT;
  381. ll = dx;
  382. ss = dy;
  383. }
  384. else
  385. {
  386. dir = AF_DIR_DOWN;
  387. ll = dy;
  388. ss = dx;
  389. }
  390. }
  391. /* return no direction if arm lengths differ too much */
  392. /* (value 14 is heuristic) */
  393. ss *= 14;
  394. if ( FT_ABS( ll ) <= FT_ABS( ss ) )
  395. dir = AF_DIR_NONE;
  396. return dir;
  397. }
  398. FT_LOCAL_DEF( void )
  399. af_glyph_hints_init( AF_GlyphHints hints,
  400. FT_Memory memory )
  401. {
  402. FT_ZERO( hints );
  403. hints->memory = memory;
  404. }
  405. FT_LOCAL_DEF( void )
  406. af_glyph_hints_done( AF_GlyphHints hints )
  407. {
  408. if ( hints && hints->memory )
  409. {
  410. FT_Memory memory = hints->memory;
  411. int dim;
  412. /*
  413. * note that we don't need to free the segment and edge
  414. * buffers since they are really within the hints->points array
  415. */
  416. for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
  417. {
  418. AF_AxisHints axis = &hints->axis[dim];
  419. axis->num_segments = 0;
  420. axis->max_segments = 0;
  421. FT_FREE( axis->segments );
  422. axis->num_edges = 0;
  423. axis->max_edges = 0;
  424. FT_FREE( axis->edges );
  425. }
  426. FT_FREE( hints->contours );
  427. hints->max_contours = 0;
  428. hints->num_contours = 0;
  429. FT_FREE( hints->points );
  430. hints->num_points = 0;
  431. hints->max_points = 0;
  432. hints->memory = NULL;
  433. }
  434. }
  435. /* Reset metrics. */
  436. FT_LOCAL_DEF( void )
  437. af_glyph_hints_rescale( AF_GlyphHints hints,
  438. AF_ScriptMetrics metrics )
  439. {
  440. hints->metrics = metrics;
  441. hints->scaler_flags = metrics->scaler.flags;
  442. }
  443. /* Recompute all AF_Point in AF_GlyphHints from the definitions */
  444. /* in a source outline. */
  445. FT_LOCAL_DEF( FT_Error )
  446. af_glyph_hints_reload( AF_GlyphHints hints,
  447. FT_Outline* outline )
  448. {
  449. FT_Error error = AF_Err_Ok;
  450. AF_Point points;
  451. FT_UInt old_max, new_max;
  452. FT_Fixed x_scale = hints->x_scale;
  453. FT_Fixed y_scale = hints->y_scale;
  454. FT_Pos x_delta = hints->x_delta;
  455. FT_Pos y_delta = hints->y_delta;
  456. FT_Memory memory = hints->memory;
  457. hints->num_points = 0;
  458. hints->num_contours = 0;
  459. hints->axis[0].num_segments = 0;
  460. hints->axis[0].num_edges = 0;
  461. hints->axis[1].num_segments = 0;
  462. hints->axis[1].num_edges = 0;
  463. /* first of all, reallocate the contours array if necessary */
  464. new_max = (FT_UInt)outline->n_contours;
  465. old_max = hints->max_contours;
  466. if ( new_max > old_max )
  467. {
  468. new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */
  469. if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
  470. goto Exit;
  471. hints->max_contours = new_max;
  472. }
  473. /*
  474. * then reallocate the points arrays if necessary --
  475. * note that we reserve two additional point positions, used to
  476. * hint metrics appropriately
  477. */
  478. new_max = (FT_UInt)( outline->n_points + 2 );
  479. old_max = hints->max_points;
  480. if ( new_max > old_max )
  481. {
  482. new_max = ( new_max + 2 + 7 ) & ~7; /* round up to a multiple of 8 */
  483. if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
  484. goto Exit;
  485. hints->max_points = new_max;
  486. }
  487. hints->num_points = outline->n_points;
  488. hints->num_contours = outline->n_contours;
  489. /* We can't rely on the value of `FT_Outline.flags' to know the fill */
  490. /* direction used for a glyph, given that some fonts are broken (e.g., */
  491. /* the Arphic ones). We thus recompute it each time we need to. */
  492. /* */
  493. hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP;
  494. hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT;
  495. if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
  496. {
  497. hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN;
  498. hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT;
  499. }
  500. hints->x_scale = x_scale;
  501. hints->y_scale = y_scale;
  502. hints->x_delta = x_delta;
  503. hints->y_delta = y_delta;
  504. hints->xmin_delta = 0;
  505. hints->xmax_delta = 0;
  506. points = hints->points;
  507. if ( hints->num_points == 0 )
  508. goto Exit;
  509. {
  510. AF_Point point;
  511. AF_Point point_limit = points + hints->num_points;
  512. /* compute coordinates & Bezier flags, next and prev */
  513. {
  514. FT_Vector* vec = outline->points;
  515. char* tag = outline->tags;
  516. AF_Point end = points + outline->contours[0];
  517. AF_Point prev = end;
  518. FT_Int contour_index = 0;
  519. for ( point = points; point < point_limit; point++, vec++, tag++ )
  520. {
  521. point->fx = (FT_Short)vec->x;
  522. point->fy = (FT_Short)vec->y;
  523. point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
  524. point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
  525. switch ( FT_CURVE_TAG( *tag ) )
  526. {
  527. case FT_CURVE_TAG_CONIC:
  528. point->flags = AF_FLAG_CONIC;
  529. break;
  530. case FT_CURVE_TAG_CUBIC:
  531. point->flags = AF_FLAG_CUBIC;
  532. break;
  533. default:
  534. point->flags = AF_FLAG_NONE;
  535. }
  536. point->prev = prev;
  537. prev->next = point;
  538. prev = point;
  539. if ( point == end )
  540. {
  541. if ( ++contour_index < outline->n_contours )
  542. {
  543. end = points + outline->contours[contour_index];
  544. prev = end;
  545. }
  546. }
  547. }
  548. }
  549. /* set up the contours array */
  550. {
  551. AF_Point* contour = hints->contours;
  552. AF_Point* contour_limit = contour + hints->num_contours;
  553. short* end = outline->contours;
  554. short idx = 0;
  555. for ( ; contour < contour_limit; contour++, end++ )
  556. {
  557. contour[0] = points + idx;
  558. idx = (short)( end[0] + 1 );
  559. }
  560. }
  561. /* compute directions of in & out vectors */
  562. {
  563. AF_Point first = points;
  564. AF_Point prev = NULL;
  565. FT_Pos in_x = 0;
  566. FT_Pos in_y = 0;
  567. AF_Direction in_dir = AF_DIR_NONE;
  568. for ( point = points; point < point_limit; point++ )
  569. {
  570. AF_Point next;
  571. FT_Pos out_x, out_y;
  572. if ( point == first )
  573. {
  574. prev = first->prev;
  575. in_x = first->fx - prev->fx;
  576. in_y = first->fy - prev->fy;
  577. in_dir = af_direction_compute( in_x, in_y );
  578. first = prev + 1;
  579. }
  580. point->in_dir = (FT_Char)in_dir;
  581. next = point->next;
  582. out_x = next->fx - point->fx;
  583. out_y = next->fy - point->fy;
  584. in_dir = af_direction_compute( out_x, out_y );
  585. point->out_dir = (FT_Char)in_dir;
  586. /* check for weak points */
  587. if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) )
  588. {
  589. Is_Weak_Point:
  590. point->flags |= AF_FLAG_WEAK_INTERPOLATION;
  591. }
  592. else if ( point->out_dir == point->in_dir )
  593. {
  594. if ( point->out_dir != AF_DIR_NONE )
  595. goto Is_Weak_Point;
  596. if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) )
  597. goto Is_Weak_Point;
  598. }
  599. else if ( point->in_dir == -point->out_dir )
  600. goto Is_Weak_Point;
  601. in_x = out_x;
  602. in_y = out_y;
  603. prev = point;
  604. }
  605. }
  606. }
  607. Exit:
  608. return error;
  609. }
  610. /* Store the hinted outline in an FT_Outline structure. */
  611. FT_LOCAL_DEF( void )
  612. af_glyph_hints_save( AF_GlyphHints hints,
  613. FT_Outline* outline )
  614. {
  615. AF_Point point = hints->points;
  616. AF_Point limit = point + hints->num_points;
  617. FT_Vector* vec = outline->points;
  618. char* tag = outline->tags;
  619. for ( ; point < limit; point++, vec++, tag++ )
  620. {
  621. vec->x = point->x;
  622. vec->y = point->y;
  623. if ( point->flags & AF_FLAG_CONIC )
  624. tag[0] = FT_CURVE_TAG_CONIC;
  625. else if ( point->flags & AF_FLAG_CUBIC )
  626. tag[0] = FT_CURVE_TAG_CUBIC;
  627. else
  628. tag[0] = FT_CURVE_TAG_ON;
  629. }
  630. }
  631. /****************************************************************
  632. *
  633. * EDGE POINT GRID-FITTING
  634. *
  635. ****************************************************************/
  636. /* Align all points of an edge to the same coordinate value, */
  637. /* either horizontally or vertically. */
  638. FT_LOCAL_DEF( void )
  639. af_glyph_hints_align_edge_points( AF_GlyphHints hints,
  640. AF_Dimension dim )
  641. {
  642. AF_AxisHints axis = & hints->axis[dim];
  643. AF_Segment segments = axis->segments;
  644. AF_Segment segment_limit = segments + axis->num_segments;
  645. AF_Segment seg;
  646. if ( dim == AF_DIMENSION_HORZ )
  647. {
  648. for ( seg = segments; seg < segment_limit; seg++ )
  649. {
  650. AF_Edge edge = seg->edge;
  651. AF_Point point, first, last;
  652. if ( edge == NULL )
  653. continue;
  654. first = seg->first;
  655. last = seg->last;
  656. point = first;
  657. for (;;)
  658. {
  659. point->x = edge->pos;
  660. point->flags |= AF_FLAG_TOUCH_X;
  661. if ( point == last )
  662. break;
  663. point = point->next;
  664. }
  665. }
  666. }
  667. else
  668. {
  669. for ( seg = segments; seg < segment_limit; seg++ )
  670. {
  671. AF_Edge edge = seg->edge;
  672. AF_Point point, first, last;
  673. if ( edge == NULL )
  674. continue;
  675. first = seg->first;
  676. last = seg->last;
  677. point = first;
  678. for (;;)
  679. {
  680. point->y = edge->pos;
  681. point->flags |= AF_FLAG_TOUCH_Y;
  682. if ( point == last )
  683. break;
  684. point = point->next;
  685. }
  686. }
  687. }
  688. }
  689. /****************************************************************
  690. *
  691. * STRONG POINT INTERPOLATION
  692. *
  693. ****************************************************************/
  694. /* Hint the strong points -- this is equivalent to the TrueType `IP' */
  695. /* hinting instruction. */
  696. FT_LOCAL_DEF( void )
  697. af_glyph_hints_align_strong_points( AF_GlyphHints hints,
  698. AF_Dimension dim )
  699. {
  700. AF_Point points = hints->points;
  701. AF_Point point_limit = points + hints->num_points;
  702. AF_AxisHints axis = &hints->axis[dim];
  703. AF_Edge edges = axis->edges;
  704. AF_Edge edge_limit = edges + axis->num_edges;
  705. AF_Flags touch_flag;
  706. if ( dim == AF_DIMENSION_HORZ )
  707. touch_flag = AF_FLAG_TOUCH_X;
  708. else
  709. touch_flag = AF_FLAG_TOUCH_Y;
  710. if ( edges < edge_limit )
  711. {
  712. AF_Point point;
  713. AF_Edge edge;
  714. for ( point = points; point < point_limit; point++ )
  715. {
  716. FT_Pos u, ou, fu; /* point position */
  717. FT_Pos delta;
  718. if ( point->flags & touch_flag )
  719. continue;
  720. /* if this point is candidate to weak interpolation, we */
  721. /* interpolate it after all strong points have been processed */
  722. if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) &&
  723. !( point->flags & AF_FLAG_INFLECTION ) )
  724. continue;
  725. if ( dim == AF_DIMENSION_VERT )
  726. {
  727. u = point->fy;
  728. ou = point->oy;
  729. }
  730. else
  731. {
  732. u = point->fx;
  733. ou = point->ox;
  734. }
  735. fu = u;
  736. /* is the point before the first edge? */
  737. edge = edges;
  738. delta = edge->fpos - u;
  739. if ( delta >= 0 )
  740. {
  741. u = edge->pos - ( edge->opos - ou );
  742. goto Store_Point;
  743. }
  744. /* is the point after the last edge? */
  745. edge = edge_limit - 1;
  746. delta = u - edge->fpos;
  747. if ( delta >= 0 )
  748. {
  749. u = edge->pos + ( ou - edge->opos );
  750. goto Store_Point;
  751. }
  752. {
  753. FT_PtrDist min, max, mid;
  754. FT_Pos fpos;
  755. /* find enclosing edges */
  756. min = 0;
  757. max = edge_limit - edges;
  758. #if 1
  759. /* for a small number of edges, a linear search is better */
  760. if ( max <= 8 )
  761. {
  762. FT_PtrDist nn;
  763. for ( nn = 0; nn < max; nn++ )
  764. if ( edges[nn].fpos >= u )
  765. break;
  766. if ( edges[nn].fpos == u )
  767. {
  768. u = edges[nn].pos;
  769. goto Store_Point;
  770. }
  771. min = nn;
  772. }
  773. else
  774. #endif
  775. while ( min < max )
  776. {
  777. mid = ( max + min ) >> 1;
  778. edge = edges + mid;
  779. fpos = edge->fpos;
  780. if ( u < fpos )
  781. max = mid;
  782. else if ( u > fpos )
  783. min = mid + 1;
  784. else
  785. {
  786. /* we are on the edge */
  787. u = edge->pos;
  788. goto Store_Point;
  789. }
  790. }
  791. /* point is not on an edge */
  792. {
  793. AF_Edge before = edges + min - 1;
  794. AF_Edge after = edges + min + 0;
  795. /* assert( before && after && before != after ) */
  796. if ( before->scale == 0 )
  797. before->scale = FT_DivFix( after->pos - before->pos,
  798. after->fpos - before->fpos );
  799. u = before->pos + FT_MulFix( fu - before->fpos,
  800. before->scale );
  801. }
  802. }
  803. Store_Point:
  804. /* save the point position */
  805. if ( dim == AF_DIMENSION_HORZ )
  806. point->x = u;
  807. else
  808. point->y = u;
  809. point->flags |= touch_flag;
  810. }
  811. }
  812. }
  813. /****************************************************************
  814. *
  815. * WEAK POINT INTERPOLATION
  816. *
  817. ****************************************************************/
  818. /* Shift the original coordinates of all points between `p1' and */
  819. /* `p2' to get hinted coordinates, using the same difference as */
  820. /* given by `ref'. */
  821. static void
  822. af_iup_shift( AF_Point p1,
  823. AF_Point p2,
  824. AF_Point ref )
  825. {
  826. AF_Point p;
  827. FT_Pos delta = ref->u - ref->v;
  828. if ( delta == 0 )
  829. return;
  830. for ( p = p1; p < ref; p++ )
  831. p->u = p->v + delta;
  832. for ( p = ref + 1; p <= p2; p++ )
  833. p->u = p->v + delta;
  834. }
  835. /* Interpolate the original coordinates of all points between `p1' and */
  836. /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */
  837. /* reference points. The `u' and `v' members are the current and */
  838. /* original coordinate values, respectively. */
  839. /* */
  840. /* Details can be found in the TrueType bytecode specification. */
  841. static void
  842. af_iup_interp( AF_Point p1,
  843. AF_Point p2,
  844. AF_Point ref1,
  845. AF_Point ref2 )
  846. {
  847. AF_Point p;
  848. FT_Pos u;
  849. FT_Pos v1 = ref1->v;
  850. FT_Pos v2 = ref2->v;
  851. FT_Pos d1 = ref1->u - v1;
  852. FT_Pos d2 = ref2->u - v2;
  853. if ( p1 > p2 )
  854. return;
  855. if ( v1 == v2 )
  856. {
  857. for ( p = p1; p <= p2; p++ )
  858. {
  859. u = p->v;
  860. if ( u <= v1 )
  861. u += d1;
  862. else
  863. u += d2;
  864. p->u = u;
  865. }
  866. return;
  867. }
  868. if ( v1 < v2 )
  869. {
  870. for ( p = p1; p <= p2; p++ )
  871. {
  872. u = p->v;
  873. if ( u <= v1 )
  874. u += d1;
  875. else if ( u >= v2 )
  876. u += d2;
  877. else
  878. u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
  879. p->u = u;
  880. }
  881. }
  882. else
  883. {
  884. for ( p = p1; p <= p2; p++ )
  885. {
  886. u = p->v;
  887. if ( u <= v2 )
  888. u += d2;
  889. else if ( u >= v1 )
  890. u += d1;
  891. else
  892. u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
  893. p->u = u;
  894. }
  895. }
  896. }
  897. /* Hint the weak points -- this is equivalent to the TrueType `IUP' */
  898. /* hinting instruction. */
  899. FT_LOCAL_DEF( void )
  900. af_glyph_hints_align_weak_points( AF_GlyphHints hints,
  901. AF_Dimension dim )
  902. {
  903. AF_Point points = hints->points;
  904. AF_Point point_limit = points + hints->num_points;
  905. AF_Point* contour = hints->contours;
  906. AF_Point* contour_limit = contour + hints->num_contours;
  907. AF_Flags touch_flag;
  908. AF_Point point;
  909. AF_Point end_point;
  910. AF_Point first_point;
  911. /* PASS 1: Move segment points to edge positions */
  912. if ( dim == AF_DIMENSION_HORZ )
  913. {
  914. touch_flag = AF_FLAG_TOUCH_X;
  915. for ( point = points; point < point_limit; point++ )
  916. {
  917. point->u = point->x;
  918. point->v = point->ox;
  919. }
  920. }
  921. else
  922. {
  923. touch_flag = AF_FLAG_TOUCH_Y;
  924. for ( point = points; point < point_limit; point++ )
  925. {
  926. point->u = point->y;
  927. point->v = point->oy;
  928. }
  929. }
  930. point = points;
  931. for ( ; contour < contour_limit; contour++ )
  932. {
  933. AF_Point first_touched, last_touched;
  934. point = *contour;
  935. end_point = point->prev;
  936. first_point = point;
  937. /* find first touched point */
  938. for (;;)
  939. {
  940. if ( point > end_point ) /* no touched point in contour */
  941. goto NextContour;
  942. if ( point->flags & touch_flag )
  943. break;
  944. point++;
  945. }
  946. first_touched = point;
  947. last_touched = point;
  948. for (;;)
  949. {
  950. FT_ASSERT( point <= end_point &&
  951. ( point->flags & touch_flag ) != 0 );
  952. /* skip any touched neighbours */
  953. while ( point < end_point &&
  954. ( point[1].flags & touch_flag ) != 0 )
  955. point++;
  956. last_touched = point;
  957. /* find the next touched point, if any */
  958. point++;
  959. for (;;)
  960. {
  961. if ( point > end_point )
  962. goto EndContour;
  963. if ( ( point->flags & touch_flag ) != 0 )
  964. break;
  965. point++;
  966. }
  967. /* interpolate between last_touched and point */
  968. af_iup_interp( last_touched + 1, point - 1,
  969. last_touched, point );
  970. }
  971. EndContour:
  972. /* special case: only one point was touched */
  973. if ( last_touched == first_touched )
  974. af_iup_shift( first_point, end_point, first_touched );
  975. else /* interpolate the last part */
  976. {
  977. if ( last_touched < end_point )
  978. af_iup_interp( last_touched + 1, end_point,
  979. last_touched, first_touched );
  980. if ( first_touched > points )
  981. af_iup_interp( first_point, first_touched - 1,
  982. last_touched, first_touched );
  983. }
  984. NextContour:
  985. ;
  986. }
  987. /* now save the interpolated values back to x/y */
  988. if ( dim == AF_DIMENSION_HORZ )
  989. {
  990. for ( point = points; point < point_limit; point++ )
  991. point->x = point->u;
  992. }
  993. else
  994. {
  995. for ( point = points; point < point_limit; point++ )
  996. point->y = point->u;
  997. }
  998. }
  999. #ifdef AF_CONFIG_OPTION_USE_WARPER
  1000. /* Apply (small) warp scale and warp delta for given dimension. */
  1001. FT_LOCAL_DEF( void )
  1002. af_glyph_hints_scale_dim( AF_GlyphHints hints,
  1003. AF_Dimension dim,
  1004. FT_Fixed scale,
  1005. FT_Pos delta )
  1006. {
  1007. AF_Point points = hints->points;
  1008. AF_Point points_limit = points + hints->num_points;
  1009. AF_Point point;
  1010. if ( dim == AF_DIMENSION_HORZ )
  1011. {
  1012. for ( point = points; point < points_limit; point++ )
  1013. point->x = FT_MulFix( point->fx, scale ) + delta;
  1014. }
  1015. else
  1016. {
  1017. for ( point = points; point < points_limit; point++ )
  1018. point->y = FT_MulFix( point->fy, scale ) + delta;
  1019. }
  1020. }
  1021. #endif /* AF_CONFIG_OPTION_USE_WARPER */
  1022. /* END */