ahhint.c 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493
  1. /***************************************************************************/
  2. /* */
  3. /* ahhint.c */
  4. /* */
  5. /* Glyph hinter (body). */
  6. /* */
  7. /* Copyright 2000-2001, 2002 Catharon Productions Inc. */
  8. /* Author: David Turner */
  9. /* */
  10. /* This file is part of the Catharon Typography Project and shall only */
  11. /* be used, modified, and distributed under the terms of the Catharon */
  12. /* Open Source License that should come with this file under the name */
  13. /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
  14. /* this file you indicate that you have read the license and */
  15. /* understand and accept it fully. */
  16. /* */
  17. /* Note that this license is compatible with the FreeType license. */
  18. /* */
  19. /***************************************************************************/
  20. #include <ft2build.h>
  21. #include "ahhint.h"
  22. #include "ahglyph.h"
  23. #include "ahangles.h"
  24. #include "aherrors.h"
  25. #include FT_OUTLINE_H
  26. #define FACE_GLOBALS( face ) ((AH_Face_Globals)(face)->autohint.data)
  27. #define AH_USE_IUP
  28. #define OPTIM_STEM_SNAP
  29. /*************************************************************************/
  30. /*************************************************************************/
  31. /**** ****/
  32. /**** Hinting routines ****/
  33. /**** ****/
  34. /*************************************************************************/
  35. /*************************************************************************/
  36. /* snap a given width in scaled coordinates to one of the */
  37. /* current standard widths */
  38. static FT_Pos
  39. ah_snap_width( FT_Pos* widths,
  40. FT_Int count,
  41. FT_Pos width )
  42. {
  43. int n;
  44. FT_Pos best = 64 + 32 + 2;
  45. FT_Pos reference = width;
  46. FT_Pos scaled;
  47. for ( n = 0; n < count; n++ )
  48. {
  49. FT_Pos w;
  50. FT_Pos dist;
  51. w = widths[n];
  52. dist = width - w;
  53. if ( dist < 0 )
  54. dist = -dist;
  55. if ( dist < best )
  56. {
  57. best = dist;
  58. reference = w;
  59. }
  60. }
  61. scaled = (reference+32) & -64;
  62. if ( width >= reference )
  63. {
  64. if ( width < scaled + 48 )
  65. width = reference;
  66. }
  67. else
  68. {
  69. if ( width > scaled - 48 )
  70. width = reference;
  71. }
  72. return width;
  73. }
  74. /* compute the snapped width of a given stem */
  75. static FT_Pos
  76. ah_compute_stem_width( AH_Hinter hinter,
  77. int vertical,
  78. FT_Pos width )
  79. {
  80. AH_Globals globals = &hinter->globals->scaled;
  81. FT_Pos dist = width;
  82. FT_Int sign = 0;
  83. if ( dist < 0 )
  84. {
  85. dist = -width;
  86. sign = 1;
  87. }
  88. if ( ( vertical && !hinter->do_vert_snapping ) ||
  89. ( !vertical && !hinter->do_horz_snapping ) )
  90. {
  91. /* smooth hinting process, very lightly quantize the stem width */
  92. /* */
  93. if ( dist < 64 )
  94. dist = 64;
  95. {
  96. FT_Pos delta = dist - globals->stds[vertical];
  97. if ( delta < 0 )
  98. delta = -delta;
  99. if ( delta < 40 )
  100. {
  101. dist = globals->stds[vertical];
  102. if ( dist < 48 )
  103. dist = 48;
  104. }
  105. if ( dist < 3 * 64 )
  106. {
  107. delta = ( dist & 63 );
  108. dist &= -64;
  109. if ( delta < 10 )
  110. dist += delta;
  111. else if ( delta < 32 )
  112. dist += 10;
  113. else if ( delta < 54 )
  114. dist += 54;
  115. else
  116. dist += delta;
  117. }
  118. else
  119. dist = ( dist + 32 ) & -64;
  120. }
  121. }
  122. else
  123. {
  124. /* strong hinting process, snap the stem width to integer pixels */
  125. /* */
  126. if ( vertical )
  127. {
  128. dist = ah_snap_width( globals->heights, globals->num_heights, dist );
  129. /* in the case of vertical hinting, always round */
  130. /* the stem heights to integer pixels */
  131. if ( dist >= 64 )
  132. dist = ( dist + 16 ) & -64;
  133. else
  134. dist = 64;
  135. }
  136. else
  137. {
  138. dist = ah_snap_width( globals->widths, globals->num_widths, dist );
  139. if ( hinter->flags & AH_HINTER_MONOCHROME )
  140. {
  141. /* monochrome horizontal hinting: snap widths to integer pixels */
  142. /* with a different threshold */
  143. if ( dist < 64 )
  144. dist = 64;
  145. else
  146. dist = ( dist + 32 ) & -64;
  147. }
  148. else
  149. {
  150. /* for horizontal anti-aliased hinting, we adopt a more subtle */
  151. /* approach: we strengthen small stems, round stems whose size */
  152. /* is between 1 and 2 pixels to an integer, otherwise nothing */
  153. if ( dist < 48 )
  154. dist = ( dist + 64 ) >> 1;
  155. else if ( dist < 128 )
  156. dist = ( dist + 22 ) & -64;
  157. else
  158. /* XXX: round otherwise, prevent color fringes in LCD mode */
  159. dist = ( dist + 32 ) & -64;
  160. }
  161. }
  162. }
  163. if ( sign )
  164. dist = -dist;
  165. return dist;
  166. }
  167. /* align one stem edge relative to the previous stem edge */
  168. static void
  169. ah_align_linked_edge( AH_Hinter hinter,
  170. AH_Edge base_edge,
  171. AH_Edge stem_edge,
  172. int vertical )
  173. {
  174. FT_Pos dist = stem_edge->opos - base_edge->opos;
  175. stem_edge->pos = base_edge->pos +
  176. ah_compute_stem_width( hinter, vertical, dist );
  177. }
  178. static void
  179. ah_align_serif_edge( AH_Hinter hinter,
  180. AH_Edge base,
  181. AH_Edge serif,
  182. int vertical )
  183. {
  184. FT_Pos dist;
  185. FT_Pos sign = 1;
  186. FT_UNUSED( hinter );
  187. dist = serif->opos - base->opos;
  188. if ( dist < 0 )
  189. {
  190. dist = -dist;
  191. sign = -1;
  192. }
  193. /* do not touch serifs widths !! */
  194. #if 0
  195. if ( base->flags & AH_EDGE_DONE )
  196. {
  197. if ( dist >= 64 )
  198. dist = (dist+8) & -64;
  199. else if ( dist <= 32 && !vertical )
  200. dist = ( dist + 33 ) >> 1;
  201. else
  202. dist = 0;
  203. }
  204. #endif
  205. serif->pos = base->pos + sign * dist;
  206. }
  207. /*************************************************************************/
  208. /*************************************************************************/
  209. /*************************************************************************/
  210. /**** ****/
  211. /**** E D G E H I N T I N G ****/
  212. /**** ****/
  213. /*************************************************************************/
  214. /*************************************************************************/
  215. /*************************************************************************/
  216. /* Another alternative edge hinting algorithm */
  217. static void
  218. ah_hint_edges_3( AH_Hinter hinter )
  219. {
  220. AH_Edge edges;
  221. AH_Edge edge_limit;
  222. AH_Outline outline = hinter->glyph;
  223. FT_Int dimension;
  224. edges = outline->horz_edges;
  225. edge_limit = edges + outline->num_hedges;
  226. for ( dimension = 1; dimension >= 0; dimension-- )
  227. {
  228. AH_Edge edge;
  229. AH_Edge anchor = 0;
  230. int has_serifs = 0;
  231. if ( !hinter->do_horz_hints && !dimension )
  232. goto Next_Dimension;
  233. if ( !hinter->do_vert_hints && dimension )
  234. goto Next_Dimension;
  235. /* we begin by aligning all stems relative to the blue zone */
  236. /* if needed -- that's only for horizontal edges */
  237. if ( dimension )
  238. {
  239. for ( edge = edges; edge < edge_limit; edge++ )
  240. {
  241. FT_Pos* blue;
  242. AH_EdgeRec *edge1, *edge2;
  243. if ( edge->flags & AH_EDGE_DONE )
  244. continue;
  245. blue = edge->blue_edge;
  246. edge1 = 0;
  247. edge2 = edge->link;
  248. if ( blue )
  249. {
  250. edge1 = edge;
  251. }
  252. else if (edge2 && edge2->blue_edge)
  253. {
  254. blue = edge2->blue_edge;
  255. edge1 = edge2;
  256. edge2 = edge;
  257. }
  258. if ( !edge1 )
  259. continue;
  260. edge1->pos = blue[0];
  261. edge1->flags |= AH_EDGE_DONE;
  262. if ( edge2 && !edge2->blue_edge )
  263. {
  264. ah_align_linked_edge( hinter, edge1, edge2, dimension );
  265. edge2->flags |= AH_EDGE_DONE;
  266. }
  267. if ( !anchor )
  268. anchor = edge;
  269. }
  270. }
  271. /* now, we will align all stem edges, trying to maintain the */
  272. /* relative order of stems in the glyph.. */
  273. for ( edge = edges; edge < edge_limit; edge++ )
  274. {
  275. AH_EdgeRec* edge2;
  276. if ( edge->flags & AH_EDGE_DONE )
  277. continue;
  278. /* skip all non-stem edges */
  279. edge2 = edge->link;
  280. if ( !edge2 )
  281. {
  282. has_serifs++;
  283. continue;
  284. }
  285. /* now, align the stem */
  286. /* this should not happen, but it's better to be safe. */
  287. if ( edge2->blue_edge || edge2 < edge )
  288. {
  289. ah_align_linked_edge( hinter, edge2, edge, dimension );
  290. edge->flags |= AH_EDGE_DONE;
  291. continue;
  292. }
  293. if ( !anchor )
  294. {
  295. edge->pos = ( edge->opos + 32 ) & -64;
  296. anchor = edge;
  297. edge->flags |= AH_EDGE_DONE;
  298. ah_align_linked_edge( hinter, edge, edge2, dimension );
  299. }
  300. else
  301. {
  302. FT_Pos org_pos, org_len, org_center, cur_len;
  303. FT_Pos cur_pos1, cur_pos2, delta1, delta2;
  304. org_pos = anchor->pos + (edge->opos - anchor->opos);
  305. org_len = edge2->opos - edge->opos;
  306. org_center = org_pos + ( org_len >> 1 );
  307. cur_len = ah_compute_stem_width( hinter, dimension, org_len );
  308. cur_pos1 = ( org_pos + 32 ) & -64;
  309. delta1 = ( cur_pos1 + ( cur_len >> 1 ) - org_center );
  310. if ( delta1 < 0 )
  311. delta1 = -delta1;
  312. cur_pos2 = ( ( org_pos + org_len + 32 ) & -64 ) - cur_len;
  313. delta2 = ( cur_pos2 + ( cur_len >> 1 ) - org_center );
  314. if ( delta2 < 0 )
  315. delta2 = -delta2;
  316. edge->pos = ( delta1 <= delta2 ) ? cur_pos1 : cur_pos2;
  317. edge2->pos = edge->pos + cur_len;
  318. edge->flags |= AH_EDGE_DONE;
  319. edge2->flags |= AH_EDGE_DONE;
  320. if ( edge > edges && edge->pos < edge[-1].pos )
  321. edge->pos = edge[-1].pos;
  322. }
  323. }
  324. if ( !has_serifs )
  325. goto Next_Dimension;
  326. /* now, hint the remaining edges (serifs and single) in order */
  327. /* to complete our processing */
  328. for ( edge = edges; edge < edge_limit; edge++ )
  329. {
  330. if ( edge->flags & AH_EDGE_DONE )
  331. continue;
  332. if ( edge->serif )
  333. ah_align_serif_edge( hinter, edge->serif, edge, dimension );
  334. else if ( !anchor )
  335. {
  336. edge->pos = ( edge->opos + 32 ) & -64;
  337. anchor = edge;
  338. }
  339. else
  340. edge->pos = anchor->pos +
  341. ( ( edge->opos-anchor->opos + 32 ) & -64 );
  342. edge->flags |= AH_EDGE_DONE;
  343. if ( edge > edges && edge->pos < edge[-1].pos )
  344. edge->pos = edge[-1].pos;
  345. if ( edge + 1 < edge_limit &&
  346. edge[1].flags & AH_EDGE_DONE &&
  347. edge->pos > edge[1].pos )
  348. edge->pos = edge[1].pos;
  349. }
  350. Next_Dimension:
  351. edges = outline->vert_edges;
  352. edge_limit = edges + outline->num_vedges;
  353. }
  354. }
  355. FT_LOCAL_DEF( void )
  356. ah_hinter_hint_edges( AH_Hinter hinter )
  357. {
  358. /* AH_Interpolate_Blue_Edges( hinter ); -- doesn't seem to help */
  359. /* reduce the problem of the disappearing eye in the `e' of Times... */
  360. /* also, creates some artifacts near the blue zones? */
  361. {
  362. ah_hint_edges_3( hinter );
  363. }
  364. }
  365. /*************************************************************************/
  366. /*************************************************************************/
  367. /*************************************************************************/
  368. /**** ****/
  369. /**** P O I N T H I N T I N G ****/
  370. /**** ****/
  371. /*************************************************************************/
  372. /*************************************************************************/
  373. /*************************************************************************/
  374. static void
  375. ah_hinter_align_edge_points( AH_Hinter hinter )
  376. {
  377. AH_Outline outline = hinter->glyph;
  378. AH_Edge edges;
  379. AH_Edge edge_limit;
  380. FT_Int dimension;
  381. edges = outline->horz_edges;
  382. edge_limit = edges + outline->num_hedges;
  383. for ( dimension = 1; dimension >= 0; dimension-- )
  384. {
  385. AH_Edge edge;
  386. edge = edges;
  387. for ( ; edge < edge_limit; edge++ )
  388. {
  389. /* move the points of each segment */
  390. /* in each edge to the edge's position */
  391. AH_Segment seg = edge->first;
  392. do
  393. {
  394. AH_Point point = seg->first;
  395. for (;;)
  396. {
  397. if ( dimension )
  398. {
  399. point->y = edge->pos;
  400. point->flags |= AH_FLAG_TOUCH_Y;
  401. }
  402. else
  403. {
  404. point->x = edge->pos;
  405. point->flags |= AH_FLAG_TOUCH_X;
  406. }
  407. if ( point == seg->last )
  408. break;
  409. point = point->next;
  410. }
  411. seg = seg->edge_next;
  412. } while ( seg != edge->first );
  413. }
  414. edges = outline->vert_edges;
  415. edge_limit = edges + outline->num_vedges;
  416. }
  417. }
  418. /* hint the strong points -- this is equivalent to the TrueType `IP' */
  419. static void
  420. ah_hinter_align_strong_points( AH_Hinter hinter )
  421. {
  422. AH_Outline outline = hinter->glyph;
  423. FT_Int dimension;
  424. AH_Edge edges;
  425. AH_Edge edge_limit;
  426. AH_Point points;
  427. AH_Point point_limit;
  428. AH_Flags touch_flag;
  429. points = outline->points;
  430. point_limit = points + outline->num_points;
  431. edges = outline->horz_edges;
  432. edge_limit = edges + outline->num_hedges;
  433. touch_flag = AH_FLAG_TOUCH_Y;
  434. for ( dimension = 1; dimension >= 0; dimension-- )
  435. {
  436. AH_Point point;
  437. AH_Edge edge;
  438. if ( edges < edge_limit )
  439. for ( point = points; point < point_limit; point++ )
  440. {
  441. FT_Pos u, ou, fu; /* point position */
  442. FT_Pos delta;
  443. if ( point->flags & touch_flag )
  444. continue;
  445. #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
  446. /* if this point is candidate to weak interpolation, we will */
  447. /* interpolate it after all strong points have been processed */
  448. if ( ( point->flags & AH_FLAG_WEAK_INTERPOLATION ) &&
  449. !( point->flags & AH_FLAG_INFLECTION ) )
  450. continue;
  451. #endif
  452. if ( dimension )
  453. {
  454. u = point->fy;
  455. ou = point->oy;
  456. }
  457. else
  458. {
  459. u = point->fx;
  460. ou = point->ox;
  461. }
  462. fu = u;
  463. /* is the point before the first edge? */
  464. edge = edges;
  465. delta = edge->fpos - u;
  466. if ( delta >= 0 )
  467. {
  468. u = edge->pos - ( edge->opos - ou );
  469. goto Store_Point;
  470. }
  471. /* is the point after the last edge ? */
  472. edge = edge_limit - 1;
  473. delta = u - edge->fpos;
  474. if ( delta >= 0 )
  475. {
  476. u = edge->pos + ( ou - edge->opos );
  477. goto Store_Point;
  478. }
  479. /* otherwise, interpolate the point in between */
  480. {
  481. AH_Edge before = 0;
  482. AH_Edge after = 0;
  483. for ( edge = edges; edge < edge_limit; edge++ )
  484. {
  485. if ( u == edge->fpos )
  486. {
  487. u = edge->pos;
  488. goto Store_Point;
  489. }
  490. if ( u < edge->fpos )
  491. break;
  492. before = edge;
  493. }
  494. for ( edge = edge_limit - 1; edge >= edges; edge-- )
  495. {
  496. if ( u == edge->fpos )
  497. {
  498. u = edge->pos;
  499. goto Store_Point;
  500. }
  501. if ( u > edge->fpos )
  502. break;
  503. after = edge;
  504. }
  505. /* assert( before && after && before != after ) */
  506. u = before->pos + FT_MulDiv( fu - before->fpos,
  507. after->pos - before->pos,
  508. after->fpos - before->fpos );
  509. }
  510. Store_Point:
  511. /* save the point position */
  512. if ( dimension )
  513. point->y = u;
  514. else
  515. point->x = u;
  516. point->flags |= touch_flag;
  517. }
  518. edges = outline->vert_edges;
  519. edge_limit = edges + outline->num_vedges;
  520. touch_flag = AH_FLAG_TOUCH_X;
  521. }
  522. }
  523. #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
  524. static void
  525. ah_iup_shift( AH_Point p1,
  526. AH_Point p2,
  527. AH_Point ref )
  528. {
  529. AH_Point p;
  530. FT_Pos delta = ref->u - ref->v;
  531. for ( p = p1; p < ref; p++ )
  532. p->u = p->v + delta;
  533. for ( p = ref + 1; p <= p2; p++ )
  534. p->u = p->v + delta;
  535. }
  536. static void
  537. ah_iup_interp( AH_Point p1,
  538. AH_Point p2,
  539. AH_Point ref1,
  540. AH_Point ref2 )
  541. {
  542. AH_Point p;
  543. FT_Pos u;
  544. FT_Pos v1 = ref1->v;
  545. FT_Pos v2 = ref2->v;
  546. FT_Pos d1 = ref1->u - v1;
  547. FT_Pos d2 = ref2->u - v2;
  548. if ( p1 > p2 )
  549. return;
  550. if ( v1 == v2 )
  551. {
  552. for ( p = p1; p <= p2; p++ )
  553. {
  554. u = p->v;
  555. if ( u <= v1 )
  556. u += d1;
  557. else
  558. u += d2;
  559. p->u = u;
  560. }
  561. return;
  562. }
  563. if ( v1 < v2 )
  564. {
  565. for ( p = p1; p <= p2; p++ )
  566. {
  567. u = p->v;
  568. if ( u <= v1 )
  569. u += d1;
  570. else if ( u >= v2 )
  571. u += d2;
  572. else
  573. u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
  574. p->u = u;
  575. }
  576. }
  577. else
  578. {
  579. for ( p = p1; p <= p2; p++ )
  580. {
  581. u = p->v;
  582. if ( u <= v2 )
  583. u += d2;
  584. else if ( u >= v1 )
  585. u += d1;
  586. else
  587. u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
  588. p->u = u;
  589. }
  590. }
  591. }
  592. /* interpolate weak points -- this is equivalent to the TrueType `IUP' */
  593. static void
  594. ah_hinter_align_weak_points( AH_Hinter hinter )
  595. {
  596. AH_Outline outline = hinter->glyph;
  597. FT_Int dimension;
  598. AH_Point points;
  599. AH_Point point_limit;
  600. AH_Point* contour_limit;
  601. AH_Flags touch_flag;
  602. points = outline->points;
  603. point_limit = points + outline->num_points;
  604. /* PASS 1: Move segment points to edge positions */
  605. touch_flag = AH_FLAG_TOUCH_Y;
  606. contour_limit = outline->contours + outline->num_contours;
  607. ah_setup_uv( outline, AH_UV_OY );
  608. for ( dimension = 1; dimension >= 0; dimension-- )
  609. {
  610. AH_Point point;
  611. AH_Point end_point;
  612. AH_Point first_point;
  613. AH_Point* contour;
  614. point = points;
  615. contour = outline->contours;
  616. for ( ; contour < contour_limit; contour++ )
  617. {
  618. point = *contour;
  619. end_point = point->prev;
  620. first_point = point;
  621. while ( point <= end_point && !( point->flags & touch_flag ) )
  622. point++;
  623. if ( point <= end_point )
  624. {
  625. AH_Point first_touched = point;
  626. AH_Point cur_touched = point;
  627. point++;
  628. while ( point <= end_point )
  629. {
  630. if ( point->flags & touch_flag )
  631. {
  632. /* we found two successive touched points; we interpolate */
  633. /* all contour points between them */
  634. ah_iup_interp( cur_touched + 1, point - 1,
  635. cur_touched, point );
  636. cur_touched = point;
  637. }
  638. point++;
  639. }
  640. if ( cur_touched == first_touched )
  641. {
  642. /* this is a special case: only one point was touched in the */
  643. /* contour; we thus simply shift the whole contour */
  644. ah_iup_shift( first_point, end_point, cur_touched );
  645. }
  646. else
  647. {
  648. /* now interpolate after the last touched point to the end */
  649. /* of the contour */
  650. ah_iup_interp( cur_touched + 1, end_point,
  651. cur_touched, first_touched );
  652. /* if the first contour point isn't touched, interpolate */
  653. /* from the contour start to the first touched point */
  654. if ( first_touched > points )
  655. ah_iup_interp( first_point, first_touched - 1,
  656. cur_touched, first_touched );
  657. }
  658. }
  659. }
  660. /* now save the interpolated values back to x/y */
  661. if ( dimension )
  662. {
  663. for ( point = points; point < point_limit; point++ )
  664. point->y = point->u;
  665. touch_flag = AH_FLAG_TOUCH_X;
  666. ah_setup_uv( outline, AH_UV_OX );
  667. }
  668. else
  669. {
  670. for ( point = points; point < point_limit; point++ )
  671. point->x = point->u;
  672. break; /* exit loop */
  673. }
  674. }
  675. }
  676. #endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */
  677. FT_LOCAL_DEF( void )
  678. ah_hinter_align_points( AH_Hinter hinter )
  679. {
  680. ah_hinter_align_edge_points( hinter );
  681. #ifndef AH_OPTION_NO_STRONG_INTERPOLATION
  682. ah_hinter_align_strong_points( hinter );
  683. #endif
  684. #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
  685. ah_hinter_align_weak_points( hinter );
  686. #endif
  687. }
  688. /*************************************************************************/
  689. /*************************************************************************/
  690. /*************************************************************************/
  691. /**** ****/
  692. /**** H I N T E R O B J E C T M E T H O D S ****/
  693. /**** ****/
  694. /*************************************************************************/
  695. /*************************************************************************/
  696. /*************************************************************************/
  697. /* scale and fit the global metrics */
  698. static void
  699. ah_hinter_scale_globals( AH_Hinter hinter,
  700. FT_Fixed x_scale,
  701. FT_Fixed y_scale )
  702. {
  703. FT_Int n;
  704. AH_Face_Globals globals = hinter->globals;
  705. AH_Globals design = &globals->design;
  706. AH_Globals scaled = &globals->scaled;
  707. /* copy content */
  708. *scaled = *design;
  709. /* scale the standard widths & heights */
  710. for ( n = 0; n < design->num_widths; n++ )
  711. scaled->widths[n] = FT_MulFix( design->widths[n], x_scale );
  712. for ( n = 0; n < design->num_heights; n++ )
  713. scaled->heights[n] = FT_MulFix( design->heights[n], y_scale );
  714. scaled->stds[0] = ( design->num_widths > 0 ) ? scaled->widths[0] : 32000;
  715. scaled->stds[1] = ( design->num_heights > 0 ) ? scaled->heights[0] : 32000;
  716. /* scale the blue zones */
  717. for ( n = 0; n < AH_BLUE_MAX; n++ )
  718. {
  719. FT_Pos delta, delta2;
  720. delta = design->blue_shoots[n] - design->blue_refs[n];
  721. delta2 = delta;
  722. if ( delta < 0 )
  723. delta2 = -delta2;
  724. delta2 = FT_MulFix( delta2, y_scale );
  725. if ( delta2 < 32 )
  726. delta2 = 0;
  727. else if ( delta2 < 64 )
  728. delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & -32 );
  729. else
  730. delta2 = ( delta2 + 32 ) & -64;
  731. if ( delta < 0 )
  732. delta2 = -delta2;
  733. scaled->blue_refs[n] =
  734. ( FT_MulFix( design->blue_refs[n], y_scale ) + 32 ) & -64;
  735. scaled->blue_shoots[n] = scaled->blue_refs[n] + delta2;
  736. }
  737. globals->x_scale = x_scale;
  738. globals->y_scale = y_scale;
  739. }
  740. static void
  741. ah_hinter_align( AH_Hinter hinter )
  742. {
  743. ah_hinter_align_edge_points( hinter );
  744. ah_hinter_align_points( hinter );
  745. }
  746. /* finalize a hinter object */
  747. FT_LOCAL_DEF( void )
  748. ah_hinter_done( AH_Hinter hinter )
  749. {
  750. if ( hinter )
  751. {
  752. FT_Memory memory = hinter->memory;
  753. ah_loader_done( hinter->loader );
  754. ah_outline_done( hinter->glyph );
  755. /* note: the `globals' pointer is _not_ owned by the hinter */
  756. /* but by the current face object, we don't need to */
  757. /* release it */
  758. hinter->globals = 0;
  759. hinter->face = 0;
  760. FT_FREE( hinter );
  761. }
  762. }
  763. /* create a new empty hinter object */
  764. FT_LOCAL_DEF( FT_Error )
  765. ah_hinter_new( FT_Library library,
  766. AH_Hinter *ahinter )
  767. {
  768. AH_Hinter hinter = 0;
  769. FT_Memory memory = library->memory;
  770. FT_Error error;
  771. *ahinter = 0;
  772. /* allocate object */
  773. if ( FT_NEW( hinter ) )
  774. goto Exit;
  775. hinter->memory = memory;
  776. hinter->flags = 0;
  777. /* allocate outline and loader */
  778. error = ah_outline_new( memory, &hinter->glyph ) ||
  779. ah_loader_new ( memory, &hinter->loader ) ||
  780. ah_loader_create_extra( hinter->loader );
  781. if ( error )
  782. goto Exit;
  783. *ahinter = hinter;
  784. Exit:
  785. if ( error )
  786. ah_hinter_done( hinter );
  787. return error;
  788. }
  789. /* create a face's autohint globals */
  790. FT_LOCAL_DEF( FT_Error )
  791. ah_hinter_new_face_globals( AH_Hinter hinter,
  792. FT_Face face,
  793. AH_Globals globals )
  794. {
  795. FT_Error error;
  796. FT_Memory memory = hinter->memory;
  797. AH_Face_Globals face_globals;
  798. if ( FT_NEW( face_globals ) )
  799. goto Exit;
  800. hinter->face = face;
  801. hinter->globals = face_globals;
  802. if ( globals )
  803. face_globals->design = *globals;
  804. else
  805. ah_hinter_compute_globals( hinter );
  806. face->autohint.data = face_globals;
  807. face->autohint.finalizer = (FT_Generic_Finalizer)
  808. ah_hinter_done_face_globals;
  809. face_globals->face = face;
  810. Exit:
  811. return error;
  812. }
  813. /* discard a face's autohint globals */
  814. FT_LOCAL_DEF( void )
  815. ah_hinter_done_face_globals( AH_Face_Globals globals )
  816. {
  817. FT_Face face = globals->face;
  818. FT_Memory memory = face->memory;
  819. FT_FREE( globals );
  820. }
  821. static FT_Error
  822. ah_hinter_load( AH_Hinter hinter,
  823. FT_UInt glyph_index,
  824. FT_Int32 load_flags,
  825. FT_UInt depth )
  826. {
  827. FT_Face face = hinter->face;
  828. FT_GlyphSlot slot = face->glyph;
  829. FT_Slot_Internal internal = slot->internal;
  830. FT_Fixed x_scale = face->size->metrics.x_scale;
  831. FT_Fixed y_scale = face->size->metrics.y_scale;
  832. FT_Error error;
  833. AH_Outline outline = hinter->glyph;
  834. AH_Loader gloader = hinter->loader;
  835. /* load the glyph */
  836. error = FT_Load_Glyph( face, glyph_index, load_flags );
  837. if ( error )
  838. goto Exit;
  839. /* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */
  840. hinter->transformed = internal->glyph_transformed;
  841. if ( hinter->transformed )
  842. {
  843. FT_Matrix imatrix;
  844. imatrix = internal->glyph_matrix;
  845. hinter->trans_delta = internal->glyph_delta;
  846. hinter->trans_matrix = imatrix;
  847. FT_Matrix_Invert( &imatrix );
  848. FT_Vector_Transform( &hinter->trans_delta, &imatrix );
  849. }
  850. /* set linear horizontal metrics */
  851. slot->linearHoriAdvance = slot->metrics.horiAdvance;
  852. slot->linearVertAdvance = slot->metrics.vertAdvance;
  853. switch ( slot->format )
  854. {
  855. case FT_GLYPH_FORMAT_OUTLINE:
  856. /* translate glyph outline if we need to */
  857. if ( hinter->transformed )
  858. {
  859. FT_UInt n = slot->outline.n_points;
  860. FT_Vector* point = slot->outline.points;
  861. for ( ; n > 0; point++, n-- )
  862. {
  863. point->x += hinter->trans_delta.x;
  864. point->y += hinter->trans_delta.y;
  865. }
  866. }
  867. /* copy the outline points in the loader's current */
  868. /* extra points, which is used to keep original glyph coordinates */
  869. error = ah_loader_check_points( gloader, slot->outline.n_points + 2,
  870. slot->outline.n_contours );
  871. if ( error )
  872. goto Exit;
  873. FT_MEM_COPY( gloader->current.extra_points, slot->outline.points,
  874. slot->outline.n_points * sizeof ( FT_Vector ) );
  875. FT_MEM_COPY( gloader->current.outline.contours, slot->outline.contours,
  876. slot->outline.n_contours * sizeof ( short ) );
  877. FT_MEM_COPY( gloader->current.outline.tags, slot->outline.tags,
  878. slot->outline.n_points * sizeof ( char ) );
  879. gloader->current.outline.n_points = slot->outline.n_points;
  880. gloader->current.outline.n_contours = slot->outline.n_contours;
  881. /* compute original phantom points */
  882. hinter->pp1.x = 0;
  883. hinter->pp1.y = 0;
  884. hinter->pp2.x = FT_MulFix( slot->metrics.horiAdvance, x_scale );
  885. hinter->pp2.y = 0;
  886. /* be sure to check for spacing glyphs */
  887. if ( slot->outline.n_points == 0 )
  888. goto Hint_Metrics;
  889. /* now, load the slot image into the auto-outline, and run the */
  890. /* automatic hinting process */
  891. error = ah_outline_load( outline, face ); /* XXX: change to slot */
  892. if ( error )
  893. goto Exit;
  894. /* perform feature detection */
  895. ah_outline_detect_features( outline );
  896. if ( hinter->do_vert_hints )
  897. {
  898. ah_outline_compute_blue_edges( outline, hinter->globals );
  899. ah_outline_scale_blue_edges( outline, hinter->globals );
  900. }
  901. /* perform alignment control */
  902. ah_hinter_hint_edges( hinter );
  903. ah_hinter_align( hinter );
  904. /* now save the current outline into the loader's current table */
  905. ah_outline_save( outline, gloader );
  906. /* we now need to hint the metrics according to the change in */
  907. /* width/positioning that occured during the hinting process */
  908. {
  909. FT_Pos old_advance, old_rsb, old_lsb, new_lsb;
  910. AH_Edge edge1 = outline->vert_edges; /* leftmost edge */
  911. AH_Edge edge2 = edge1 +
  912. outline->num_vedges - 1; /* rightmost edge */
  913. old_advance = hinter->pp2.x;
  914. old_rsb = old_advance - edge2->opos;
  915. old_lsb = edge1->opos;
  916. new_lsb = edge1->pos;
  917. hinter->pp1.x = ( ( new_lsb - old_lsb ) + 32 ) & -64;
  918. hinter->pp2.x = ( ( edge2->pos + old_rsb ) + 32 ) & -64;
  919. /* try to fix certain bad advance computations */
  920. if ( hinter->pp2.x + hinter->pp1.x == edge2->pos && old_rsb > 4 )
  921. hinter->pp2.x += 64;
  922. }
  923. /* good, we simply add the glyph to our loader's base */
  924. ah_loader_add( gloader );
  925. break;
  926. case FT_GLYPH_FORMAT_COMPOSITE:
  927. {
  928. FT_UInt nn, num_subglyphs = slot->num_subglyphs;
  929. FT_UInt num_base_subgs, start_point;
  930. FT_SubGlyph subglyph;
  931. start_point = gloader->base.outline.n_points;
  932. /* first of all, copy the subglyph descriptors in the glyph loader */
  933. error = ah_loader_check_subglyphs( gloader, num_subglyphs );
  934. if ( error )
  935. goto Exit;
  936. FT_MEM_COPY( gloader->current.subglyphs, slot->subglyphs,
  937. num_subglyphs * sizeof ( FT_SubGlyph ) );
  938. gloader->current.num_subglyphs = num_subglyphs;
  939. num_base_subgs = gloader->base.num_subglyphs;
  940. /* now, read each subglyph independently */
  941. for ( nn = 0; nn < num_subglyphs; nn++ )
  942. {
  943. FT_Vector pp1, pp2;
  944. FT_Pos x, y;
  945. FT_UInt num_points, num_new_points, num_base_points;
  946. /* gloader.current.subglyphs can change during glyph loading due */
  947. /* to re-allocation -- we must recompute the current subglyph on */
  948. /* each iteration */
  949. subglyph = gloader->base.subglyphs + num_base_subgs + nn;
  950. pp1 = hinter->pp1;
  951. pp2 = hinter->pp2;
  952. num_base_points = gloader->base.outline.n_points;
  953. error = ah_hinter_load( hinter, subglyph->index,
  954. load_flags, depth + 1 );
  955. if ( error )
  956. goto Exit;
  957. /* recompute subglyph pointer */
  958. subglyph = gloader->base.subglyphs + num_base_subgs + nn;
  959. if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
  960. {
  961. pp1 = hinter->pp1;
  962. pp2 = hinter->pp2;
  963. }
  964. else
  965. {
  966. hinter->pp1 = pp1;
  967. hinter->pp2 = pp2;
  968. }
  969. num_points = gloader->base.outline.n_points;
  970. num_new_points = num_points - num_base_points;
  971. /* now perform the transform required for this subglyph */
  972. if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE |
  973. FT_SUBGLYPH_FLAG_XY_SCALE |
  974. FT_SUBGLYPH_FLAG_2X2 ) )
  975. {
  976. FT_Vector* cur = gloader->base.outline.points +
  977. num_base_points;
  978. FT_Vector* org = gloader->base.extra_points +
  979. num_base_points;
  980. FT_Vector* limit = cur + num_new_points;
  981. for ( ; cur < limit; cur++, org++ )
  982. {
  983. FT_Vector_Transform( cur, &subglyph->transform );
  984. FT_Vector_Transform( org, &subglyph->transform );
  985. }
  986. }
  987. /* apply offset */
  988. if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
  989. {
  990. FT_Int k = subglyph->arg1;
  991. FT_UInt l = subglyph->arg2;
  992. FT_Vector* p1;
  993. FT_Vector* p2;
  994. if ( start_point + k >= num_base_points ||
  995. l >= (FT_UInt)num_new_points )
  996. {
  997. error = AH_Err_Invalid_Composite;
  998. goto Exit;
  999. }
  1000. l += num_base_points;
  1001. /* for now, only use the current point coordinates */
  1002. /* we may consider another approach in the near future */
  1003. p1 = gloader->base.outline.points + start_point + k;
  1004. p2 = gloader->base.outline.points + start_point + l;
  1005. x = p1->x - p2->x;
  1006. y = p1->y - p2->y;
  1007. }
  1008. else
  1009. {
  1010. x = FT_MulFix( subglyph->arg1, x_scale );
  1011. y = FT_MulFix( subglyph->arg2, y_scale );
  1012. x = ( x + 32 ) & -64;
  1013. y = ( y + 32 ) & -64;
  1014. }
  1015. {
  1016. FT_Outline dummy = gloader->base.outline;
  1017. dummy.points += num_base_points;
  1018. dummy.n_points = (short)num_new_points;
  1019. FT_Outline_Translate( &dummy, x, y );
  1020. }
  1021. }
  1022. }
  1023. break;
  1024. default:
  1025. /* we don't support other formats (yet?) */
  1026. error = AH_Err_Unimplemented_Feature;
  1027. }
  1028. Hint_Metrics:
  1029. if ( depth == 0 )
  1030. {
  1031. FT_BBox bbox;
  1032. /* transform the hinted outline if needed */
  1033. if ( hinter->transformed )
  1034. FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix );
  1035. /* we must translate our final outline by -pp1.x, and compute */
  1036. /* the new metrics */
  1037. if ( hinter->pp1.x )
  1038. FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 );
  1039. FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
  1040. bbox.xMin &= -64;
  1041. bbox.yMin &= -64;
  1042. bbox.xMax = ( bbox.xMax + 63 ) & -64;
  1043. bbox.yMax = ( bbox.yMax + 63 ) & -64;
  1044. slot->metrics.width = bbox.xMax - bbox.xMin;
  1045. slot->metrics.height = bbox.yMax - bbox.yMin;
  1046. slot->metrics.horiBearingX = bbox.xMin;
  1047. slot->metrics.horiBearingY = bbox.yMax;
  1048. /* for mono-width fonts (like Andale, Courier, etc.), we need */
  1049. /* to keep the original rounded advance width */
  1050. if ( !FT_IS_FIXED_WIDTH( slot->face ) )
  1051. slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x;
  1052. else
  1053. slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
  1054. x_scale );
  1055. slot->metrics.horiAdvance = ( slot->metrics.horiAdvance + 32 ) & -64;
  1056. /* now copy outline into glyph slot */
  1057. ah_loader_rewind( slot->internal->loader );
  1058. error = ah_loader_copy_points( slot->internal->loader, gloader );
  1059. if ( error )
  1060. goto Exit;
  1061. slot->outline = slot->internal->loader->base.outline;
  1062. slot->format = FT_GLYPH_FORMAT_OUTLINE;
  1063. }
  1064. #ifdef DEBUG_HINTER
  1065. ah_debug_hinter = hinter;
  1066. #endif
  1067. Exit:
  1068. return error;
  1069. }
  1070. /* load and hint a given glyph */
  1071. FT_LOCAL_DEF( FT_Error )
  1072. ah_hinter_load_glyph( AH_Hinter hinter,
  1073. FT_GlyphSlot slot,
  1074. FT_Size size,
  1075. FT_UInt glyph_index,
  1076. FT_Int32 load_flags )
  1077. {
  1078. FT_Face face = slot->face;
  1079. FT_Error error;
  1080. FT_Fixed x_scale = size->metrics.x_scale;
  1081. FT_Fixed y_scale = size->metrics.y_scale;
  1082. AH_Face_Globals face_globals = FACE_GLOBALS( face );
  1083. FT_Render_Mode hint_mode = FT_LOAD_TARGET_MODE(load_flags);
  1084. /* first of all, we need to check that we're using the correct face and */
  1085. /* global hints to load the glyph */
  1086. if ( hinter->face != face || hinter->globals != face_globals )
  1087. {
  1088. hinter->face = face;
  1089. if ( !face_globals )
  1090. {
  1091. error = ah_hinter_new_face_globals( hinter, face, 0 );
  1092. if ( error )
  1093. goto Exit;
  1094. }
  1095. hinter->globals = FACE_GLOBALS( face );
  1096. face_globals = FACE_GLOBALS( face );
  1097. }
  1098. /* now, we must check the current character pixel size to see if we */
  1099. /* need to rescale the global metrics */
  1100. if ( face_globals->x_scale != x_scale ||
  1101. face_globals->y_scale != y_scale )
  1102. ah_hinter_scale_globals( hinter, x_scale, y_scale );
  1103. ah_loader_rewind( hinter->loader );
  1104. /* reset hinting flags according to load flags and current render target */
  1105. hinter->do_horz_hints = !FT_BOOL( load_flags & FT_LOAD_NO_AUTOHINT );
  1106. hinter->do_vert_hints = !FT_BOOL( load_flags & FT_LOAD_NO_AUTOHINT );
  1107. #ifdef DEBUG_HINTER
  1108. hinter->do_horz_hints = !ah_debug_disable_vert; /* not a bug, the meaning */
  1109. hinter->do_vert_hints = !ah_debug_disable_horz; /* of h/v is inverted! */
  1110. #endif
  1111. /* we snap the width of vertical stems for the monochrome and */
  1112. /* horizontal LCD rendering targets only. Corresponds to X snapping. */
  1113. hinter->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
  1114. hint_mode == FT_RENDER_MODE_LCD );
  1115. /* we snap the width of horizontal stems for the monochrome and */
  1116. /* vertical LCD rendering targets only. Corresponds to Y snapping. */
  1117. hinter->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
  1118. hint_mode == FT_RENDER_MODE_LCD_V );
  1119. #if 1
  1120. load_flags = FT_LOAD_NO_SCALE
  1121. | FT_LOAD_IGNORE_TRANSFORM ;
  1122. #else
  1123. load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_RECURSE;
  1124. #endif
  1125. error = ah_hinter_load( hinter, glyph_index, load_flags, 0 );
  1126. Exit:
  1127. return error;
  1128. }
  1129. /* retrieve a face's autohint globals for client applications */
  1130. FT_LOCAL_DEF( void )
  1131. ah_hinter_get_global_hints( AH_Hinter hinter,
  1132. FT_Face face,
  1133. void** global_hints,
  1134. long* global_len )
  1135. {
  1136. AH_Globals globals = 0;
  1137. FT_Memory memory = hinter->memory;
  1138. FT_Error error;
  1139. /* allocate new master globals */
  1140. if ( FT_NEW( globals ) )
  1141. goto Fail;
  1142. /* compute face globals if needed */
  1143. if ( !FACE_GLOBALS( face ) )
  1144. {
  1145. error = ah_hinter_new_face_globals( hinter, face, 0 );
  1146. if ( error )
  1147. goto Fail;
  1148. }
  1149. *globals = FACE_GLOBALS( face )->design;
  1150. *global_hints = globals;
  1151. *global_len = sizeof( *globals );
  1152. return;
  1153. Fail:
  1154. FT_FREE( globals );
  1155. *global_hints = 0;
  1156. *global_len = 0;
  1157. }
  1158. FT_LOCAL_DEF( void )
  1159. ah_hinter_done_global_hints( AH_Hinter hinter,
  1160. void* global_hints )
  1161. {
  1162. FT_Memory memory = hinter->memory;
  1163. FT_FREE( global_hints );
  1164. }
  1165. /* END */