pshalgo1.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. /***************************************************************************/
  2. /* */
  3. /* pshalgo1.c */
  4. /* */
  5. /* PostScript hinting algorithm 1 (body). */
  6. /* */
  7. /* Copyright 2001, 2002 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 <ft2build.h>
  18. #include FT_INTERNAL_OBJECTS_H
  19. #include FT_INTERNAL_DEBUG_H
  20. #include "pshalgo1.h"
  21. #undef FT_COMPONENT
  22. #define FT_COMPONENT trace_pshalgo1
  23. #ifdef DEBUG_HINTER
  24. PSH1_Hint_Table ps1_debug_hint_table = 0;
  25. PSH1_HintFunc ps1_debug_hint_func = 0;
  26. #endif
  27. /************************************************************************/
  28. /************************************************************************/
  29. /***** *****/
  30. /***** BASIC HINTS RECORDINGS *****/
  31. /***** *****/
  32. /************************************************************************/
  33. /************************************************************************/
  34. /* return true iff two stem hints overlap */
  35. static FT_Int
  36. psh1_hint_overlap( PSH1_Hint hint1,
  37. PSH1_Hint hint2 )
  38. {
  39. return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
  40. hint2->org_pos + hint2->org_len >= hint1->org_pos );
  41. }
  42. /* destroy hints table */
  43. static void
  44. psh1_hint_table_done( PSH1_Hint_Table table,
  45. FT_Memory memory )
  46. {
  47. FT_FREE( table->zones );
  48. table->num_zones = 0;
  49. table->zone = 0;
  50. FT_FREE( table->sort );
  51. FT_FREE( table->hints );
  52. table->num_hints = 0;
  53. table->max_hints = 0;
  54. table->sort_global = 0;
  55. }
  56. /* deactivate all hints in a table */
  57. static void
  58. psh1_hint_table_deactivate( PSH1_Hint_Table table )
  59. {
  60. FT_UInt count = table->max_hints;
  61. PSH1_Hint hint = table->hints;
  62. for ( ; count > 0; count--, hint++ )
  63. {
  64. psh1_hint_deactivate( hint );
  65. hint->order = -1;
  66. }
  67. }
  68. /* internal function used to record a new hint */
  69. static void
  70. psh1_hint_table_record( PSH1_Hint_Table table,
  71. FT_UInt idx )
  72. {
  73. PSH1_Hint hint = table->hints + idx;
  74. if ( idx >= table->max_hints )
  75. {
  76. FT_ERROR(( "%s.activate: invalid hint index %d\n", idx ));
  77. return;
  78. }
  79. /* ignore active hints */
  80. if ( psh1_hint_is_active( hint ) )
  81. return;
  82. psh1_hint_activate( hint );
  83. /* now scan the current active hint set in order to determine */
  84. /* if we are overlapping with another segment */
  85. {
  86. PSH1_Hint* sorted = table->sort_global;
  87. FT_UInt count = table->num_hints;
  88. PSH1_Hint hint2;
  89. hint->parent = 0;
  90. for ( ; count > 0; count--, sorted++ )
  91. {
  92. hint2 = sorted[0];
  93. if ( psh1_hint_overlap( hint, hint2 ) )
  94. {
  95. hint->parent = hint2;
  96. break;
  97. }
  98. }
  99. }
  100. if ( table->num_hints < table->max_hints )
  101. table->sort_global[table->num_hints++] = hint;
  102. else
  103. FT_ERROR(( "%s.activate: too many sorted hints! BUG!\n",
  104. "ps.fitter" ));
  105. }
  106. static void
  107. psh1_hint_table_record_mask( PSH1_Hint_Table table,
  108. PS_Mask hint_mask )
  109. {
  110. FT_Int mask = 0, val = 0;
  111. FT_Byte* cursor = hint_mask->bytes;
  112. FT_UInt idx, limit;
  113. limit = hint_mask->num_bits;
  114. if ( limit != table->max_hints )
  115. FT_ERROR(( "%s.activate_mask: invalid bit count (%d instead of %d)\n",
  116. "ps.fitter", hint_mask->num_bits, table->max_hints ));
  117. for ( idx = 0; idx < limit; idx++ )
  118. {
  119. if ( mask == 0 )
  120. {
  121. val = *cursor++;
  122. mask = 0x80;
  123. }
  124. if ( val & mask )
  125. psh1_hint_table_record( table, idx );
  126. mask >>= 1;
  127. }
  128. }
  129. /* create hints table */
  130. static FT_Error
  131. psh1_hint_table_init( PSH1_Hint_Table table,
  132. PS_Hint_Table hints,
  133. PS_Mask_Table hint_masks,
  134. PS_Mask_Table counter_masks,
  135. FT_Memory memory )
  136. {
  137. FT_UInt count = hints->num_hints;
  138. FT_Error error;
  139. FT_UNUSED( counter_masks );
  140. /* allocate our tables */
  141. if ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
  142. FT_NEW_ARRAY( table->hints, count ) ||
  143. FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
  144. goto Exit;
  145. table->max_hints = count;
  146. table->sort_global = table->sort + count;
  147. table->num_hints = 0;
  148. table->num_zones = 0;
  149. table->zone = 0;
  150. /* now, initialize the "hints" array */
  151. {
  152. PSH1_Hint write = table->hints;
  153. PS_Hint read = hints->hints;
  154. for ( ; count > 0; count--, write++, read++ )
  155. {
  156. write->org_pos = read->pos;
  157. write->org_len = read->len;
  158. write->flags = read->flags;
  159. }
  160. }
  161. /* we now need to determine the initial "parent" stems; first */
  162. /* activate the hints that are given by the initial hint masks */
  163. if ( hint_masks )
  164. {
  165. FT_UInt Count = hint_masks->num_masks;
  166. PS_Mask Mask = hint_masks->masks;
  167. table->hint_masks = hint_masks;
  168. for ( ; Count > 0; Count--, Mask++ )
  169. psh1_hint_table_record_mask( table, Mask );
  170. }
  171. /* now, do a linear parse in case some hints were left alone */
  172. if ( table->num_hints != table->max_hints )
  173. {
  174. FT_UInt Index, Count;
  175. FT_ERROR(( "%s.init: missing/incorrect hint masks!\n" ));
  176. Count = table->max_hints;
  177. for ( Index = 0; Index < Count; Index++ )
  178. psh1_hint_table_record( table, Index );
  179. }
  180. Exit:
  181. return error;
  182. }
  183. static void
  184. psh1_hint_table_activate_mask( PSH1_Hint_Table table,
  185. PS_Mask hint_mask )
  186. {
  187. FT_Int mask = 0, val = 0;
  188. FT_Byte* cursor = hint_mask->bytes;
  189. FT_UInt idx, limit, count;
  190. limit = hint_mask->num_bits;
  191. count = 0;
  192. psh1_hint_table_deactivate( table );
  193. for ( idx = 0; idx < limit; idx++ )
  194. {
  195. if ( mask == 0 )
  196. {
  197. val = *cursor++;
  198. mask = 0x80;
  199. }
  200. if ( val & mask )
  201. {
  202. PSH1_Hint hint = &table->hints[idx];
  203. if ( !psh1_hint_is_active( hint ) )
  204. {
  205. PSH1_Hint* sort = table->sort;
  206. FT_UInt count2;
  207. PSH1_Hint hint2;
  208. for ( count2 = count; count2 > 0; count2--, sort++ )
  209. {
  210. hint2 = sort[0];
  211. if ( psh1_hint_overlap( hint, hint2 ) )
  212. {
  213. FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
  214. "psf.hint" ));
  215. break;
  216. }
  217. }
  218. if ( count2 == 0 )
  219. {
  220. psh1_hint_activate( hint );
  221. if ( count < table->max_hints )
  222. table->sort[count++] = hint;
  223. else
  224. FT_ERROR(( "%s.activate_mask: too many active hints\n",
  225. "psf.hint" ));
  226. }
  227. }
  228. }
  229. mask >>= 1;
  230. }
  231. table->num_hints = count;
  232. /* now, sort the hints; they are guaranteed to not overlap */
  233. /* so we can compare their "org_pos" field directly */
  234. {
  235. FT_Int i1, i2;
  236. PSH1_Hint hint1, hint2;
  237. PSH1_Hint* sort = table->sort;
  238. /* a simple bubble sort will do, since in 99% of cases, the hints */
  239. /* will be already sorted; and the sort will be linear */
  240. for ( i1 = 1; i1 < (FT_Int)count; i1++ )
  241. {
  242. hint1 = sort[i1];
  243. for ( i2 = i1 - 1; i2 >= 0; i2-- )
  244. {
  245. hint2 = sort[i2];
  246. if ( hint2->org_pos < hint1->org_pos )
  247. break;
  248. sort[i2 + 1] = hint2;
  249. sort[i2] = hint1;
  250. }
  251. }
  252. }
  253. }
  254. /*************************************************************************/
  255. /*************************************************************************/
  256. /***** *****/
  257. /***** HINTS GRID-FITTING AND OPTIMIZATION *****/
  258. /***** *****/
  259. /*************************************************************************/
  260. /*************************************************************************/
  261. #ifdef DEBUG_HINTER
  262. void
  263. ps_simple_scale( PSH1_Hint_Table table,
  264. FT_Fixed scale,
  265. FT_Fixed delta,
  266. FT_Int vertical )
  267. {
  268. PSH1_Hint hint;
  269. FT_UInt count;
  270. for ( count = 0; count < table->num_hints; count++ )
  271. {
  272. hint = table->sort[count];
  273. if ( psh1_hint_is_active( hint ) )
  274. {
  275. hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
  276. hint->cur_len = FT_MulFix( hint->org_len, scale );
  277. if ( ps1_debug_hint_func )
  278. ps1_debug_hint_func( hint, vertical );
  279. }
  280. }
  281. }
  282. #endif
  283. FT_LOCAL_DEF( FT_Error )
  284. psh1_hint_table_optimize( PSH1_Hint_Table table,
  285. PSH_Globals globals,
  286. FT_Outline* outline,
  287. FT_Int vertical )
  288. {
  289. PSH_Dimension dim = &globals->dimension[vertical];
  290. FT_Fixed scale = dim->scale_mult;
  291. FT_Fixed delta = dim->scale_delta;
  292. FT_UNUSED( outline );
  293. #ifdef DEBUG_HINTER
  294. if ( ps_debug_no_vert_hints && vertical )
  295. {
  296. ps_simple_scale( table, scale, delta, vertical );
  297. return 0;
  298. }
  299. if ( ps_debug_no_horz_hints && !vertical )
  300. {
  301. ps_simple_scale( table, scale, delta, vertical );
  302. return 0;
  303. }
  304. #endif
  305. /* XXXX: for now, we only scale the hints to test all other aspects */
  306. /* of the PostScript hinter */
  307. {
  308. PSH1_Hint hint;
  309. FT_UInt count;
  310. for ( count = 0; count < table->num_hints; count++ )
  311. {
  312. hint = table->sort[count];
  313. if ( psh1_hint_is_active( hint ) )
  314. {
  315. #if 1
  316. FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
  317. FT_Pos len = FT_MulFix( hint->org_len, scale );
  318. FT_Pos fit_center;
  319. FT_Pos fit_len;
  320. PSH_AlignmentRec align;
  321. /* compute fitted width/height */
  322. fit_len = psh_dimension_snap_width( dim, hint->org_len );
  323. if ( fit_len < 64 )
  324. fit_len = 64;
  325. else
  326. fit_len = ( fit_len + 32 ) & -64;
  327. hint->cur_len = fit_len;
  328. /* check blue zones for horizontal stems */
  329. align.align = PSH_BLUE_ALIGN_NONE;
  330. align.align_bot = align.align_top = 0;
  331. if ( !vertical )
  332. {
  333. psh_blues_snap_stem( &globals->blues,
  334. hint->org_pos + hint->org_len,
  335. hint->org_pos,
  336. &align );
  337. }
  338. switch ( align.align )
  339. {
  340. case PSH_BLUE_ALIGN_TOP:
  341. /* the top of the stem is aligned against a blue zone */
  342. hint->cur_pos = align.align_top - fit_len;
  343. break;
  344. case PSH_BLUE_ALIGN_BOT:
  345. /* the bottom of the stem is aligned against a blue zone */
  346. hint->cur_pos = align.align_bot;
  347. break;
  348. case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
  349. /* both edges of the stem are aligned against blue zones */
  350. hint->cur_pos = align.align_bot;
  351. hint->cur_len = align.align_top - align.align_bot;
  352. break;
  353. default:
  354. /* normal processing */
  355. if ( ( fit_len / 64 ) & 1 )
  356. {
  357. /* odd number of pixels */
  358. fit_center = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
  359. }
  360. else
  361. {
  362. /* even number of pixels */
  363. fit_center = ( pos + ( len >> 1 ) + 32 ) & -64;
  364. }
  365. hint->cur_pos = fit_center - ( fit_len >> 1 );
  366. }
  367. # else
  368. hint->cur_pos = ( FT_MulFix( hint->org_pos, scale ) + delta + 32 )
  369. & -64;
  370. hint->cur_len = FT_MulFix( hint->org_len, scale );
  371. # endif
  372. #ifdef DEBUG_HINTER
  373. if ( ps1_debug_hint_func )
  374. ps1_debug_hint_func( hint, vertical );
  375. #endif
  376. }
  377. }
  378. }
  379. return 0;
  380. }
  381. /*************************************************************************/
  382. /*************************************************************************/
  383. /***** *****/
  384. /***** POINTS INTERPOLATION ROUTINES *****/
  385. /***** *****/
  386. /*************************************************************************/
  387. /*************************************************************************/
  388. #define PSH1_ZONE_MIN -3200000
  389. #define PSH1_ZONE_MAX +3200000
  390. #define xxDEBUG_ZONES
  391. #ifdef DEBUG_ZONES
  392. #include <stdio.h>
  393. static void
  394. psh1_print_zone( PSH1_Zone zone )
  395. {
  396. printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
  397. zone->scale / 65536.0,
  398. zone->delta / 64.0,
  399. zone->min,
  400. zone->max );
  401. }
  402. #else
  403. #define psh1_print_zone( x ) do { } while ( 0 )
  404. #endif
  405. /* setup interpolation zones once the hints have been grid-fitted */
  406. /* by the optimizer */
  407. static void
  408. psh1_hint_table_setup_zones( PSH1_Hint_Table table,
  409. FT_Fixed scale,
  410. FT_Fixed delta )
  411. {
  412. FT_UInt count;
  413. PSH1_Zone zone;
  414. PSH1_Hint *sort, hint, hint2;
  415. zone = table->zones;
  416. /* special case, no hints defined */
  417. if ( table->num_hints == 0 )
  418. {
  419. zone->scale = scale;
  420. zone->delta = delta;
  421. zone->min = PSH1_ZONE_MIN;
  422. zone->max = PSH1_ZONE_MAX;
  423. table->num_zones = 1;
  424. table->zone = zone;
  425. return;
  426. }
  427. /* the first zone is before the first hint */
  428. /* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
  429. sort = table->sort;
  430. hint = sort[0];
  431. zone->scale = scale;
  432. zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
  433. zone->min = PSH1_ZONE_MIN;
  434. zone->max = hint->org_pos;
  435. psh1_print_zone( zone );
  436. zone++;
  437. for ( count = table->num_hints; count > 0; count-- )
  438. {
  439. FT_Fixed scale2;
  440. if ( hint->org_len > 0 )
  441. {
  442. /* setup a zone for inner-stem interpolation */
  443. /* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0) */
  444. /* x' = x*s2 + x0' - x0*s2 */
  445. scale2 = FT_DivFix( hint->cur_len, hint->org_len );
  446. zone->scale = scale2;
  447. zone->min = hint->org_pos;
  448. zone->max = hint->org_pos + hint->org_len;
  449. zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
  450. psh1_print_zone( zone );
  451. zone++;
  452. }
  453. if ( count == 1 )
  454. break;
  455. sort++;
  456. hint2 = sort[0];
  457. /* setup zone for inter-stem interpolation */
  458. /* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1) */
  459. /* x' = x*s3 + x1' - x1*s3 */
  460. scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
  461. hint2->org_pos - (hint->org_pos + hint->org_len) );
  462. zone->scale = scale2;
  463. zone->min = hint->org_pos + hint->org_len;
  464. zone->max = hint2->org_pos;
  465. zone->delta = hint->cur_pos + hint->cur_len -
  466. FT_MulFix( zone->min, scale2 );
  467. psh1_print_zone( zone );
  468. zone++;
  469. hint = hint2;
  470. }
  471. /* the last zone */
  472. zone->scale = scale;
  473. zone->min = hint->org_pos + hint->org_len;
  474. zone->max = PSH1_ZONE_MAX;
  475. zone->delta = hint->cur_pos + hint->cur_len -
  476. FT_MulFix( zone->min, scale );
  477. psh1_print_zone( zone );
  478. zone++;
  479. table->num_zones = zone - table->zones;
  480. table->zone = table->zones;
  481. }
  482. /* tune a single coordinate with the current interpolation zones */
  483. static FT_Pos
  484. psh1_hint_table_tune_coord( PSH1_Hint_Table table,
  485. FT_Int coord )
  486. {
  487. PSH1_Zone zone;
  488. zone = table->zone;
  489. if ( coord < zone->min )
  490. {
  491. do
  492. {
  493. if ( zone == table->zones )
  494. break;
  495. zone--;
  496. } while ( coord < zone->min );
  497. table->zone = zone;
  498. }
  499. else if ( coord > zone->max )
  500. {
  501. do
  502. {
  503. if ( zone == table->zones + table->num_zones - 1 )
  504. break;
  505. zone++;
  506. } while ( coord > zone->max );
  507. table->zone = zone;
  508. }
  509. return FT_MulFix( coord, zone->scale ) + zone->delta;
  510. }
  511. /* tune a given outline with current interpolation zones. */
  512. /* The function only works in a single dimension. */
  513. static void
  514. psh1_hint_table_tune_outline( PSH1_Hint_Table table,
  515. FT_Outline* outline,
  516. PSH_Globals globals,
  517. FT_Int vertical )
  518. {
  519. FT_UInt count, first, last;
  520. PS_Mask_Table hint_masks = table->hint_masks;
  521. PS_Mask mask;
  522. PSH_Dimension dim = &globals->dimension[vertical];
  523. FT_Fixed scale = dim->scale_mult;
  524. FT_Fixed delta = dim->scale_delta;
  525. if ( hint_masks && hint_masks->num_masks > 0 )
  526. {
  527. first = 0;
  528. mask = hint_masks->masks;
  529. count = hint_masks->num_masks;
  530. for ( ; count > 0; count--, mask++ )
  531. {
  532. last = mask->end_point;
  533. if ( last > first )
  534. {
  535. FT_Vector* vec;
  536. FT_Int count2;
  537. psh1_hint_table_activate_mask( table, mask );
  538. psh1_hint_table_optimize( table, globals, outline, vertical );
  539. psh1_hint_table_setup_zones( table, scale, delta );
  540. last = mask->end_point;
  541. vec = outline->points + first;
  542. count2 = last - first;
  543. for ( ; count2 > 0; count2--, vec++ )
  544. {
  545. FT_Pos x, *px;
  546. px = vertical ? &vec->x : &vec->y;
  547. x = *px;
  548. *px = psh1_hint_table_tune_coord( table, (FT_Int)x );
  549. }
  550. }
  551. first = last;
  552. }
  553. }
  554. else /* no hints in this glyph, simply scale the outline */
  555. {
  556. FT_Vector* vec;
  557. vec = outline->points;
  558. count = outline->n_points;
  559. if ( vertical )
  560. {
  561. for ( ; count > 0; count--, vec++ )
  562. vec->x = FT_MulFix( vec->x, scale ) + delta;
  563. }
  564. else
  565. {
  566. for ( ; count > 0; count--, vec++ )
  567. vec->y = FT_MulFix( vec->y, scale ) + delta;
  568. }
  569. }
  570. }
  571. /*************************************************************************/
  572. /*************************************************************************/
  573. /***** *****/
  574. /***** HIGH-LEVEL INTERFACE *****/
  575. /***** *****/
  576. /*************************************************************************/
  577. /*************************************************************************/
  578. FT_Error
  579. ps1_hints_apply( PS_Hints ps_hints,
  580. FT_Outline* outline,
  581. PSH_Globals globals,
  582. FT_Render_Mode hint_mode )
  583. {
  584. PSH1_Hint_TableRec hints;
  585. FT_Error error = 0;
  586. FT_Int dimension;
  587. FT_UNUSED( hint_mode );
  588. for ( dimension = 1; dimension >= 0; dimension-- )
  589. {
  590. PS_Dimension dim = &ps_hints->dimension[dimension];
  591. /* initialize hints table */
  592. FT_MEM_ZERO( &hints, sizeof ( hints ) );
  593. error = psh1_hint_table_init( &hints,
  594. &dim->hints,
  595. &dim->masks,
  596. &dim->counters,
  597. ps_hints->memory );
  598. if ( error )
  599. goto Exit;
  600. psh1_hint_table_tune_outline( &hints,
  601. outline,
  602. globals,
  603. dimension );
  604. psh1_hint_table_done( &hints, ps_hints->memory );
  605. }
  606. Exit:
  607. return error;
  608. }
  609. /* END */