pshalgo3.c 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757
  1. /***************************************************************************/
  2. /* */
  3. /* pshalgo3.c */
  4. /* */
  5. /* PostScript hinting algorithm 3 (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 "pshalgo3.h"
  21. #undef FT_COMPONENT
  22. #define FT_COMPONENT trace_pshalgo2
  23. #ifdef DEBUG_HINTER
  24. PSH3_Hint_Table ps3_debug_hint_table = 0;
  25. PSH3_HintFunc ps3_debug_hint_func = 0;
  26. PSH3_Glyph ps3_debug_glyph = 0;
  27. #endif
  28. #define COMPUTE_INFLEXS /* compute inflection points to optimize "S" and others */
  29. #define STRONGER /* slightly increase the contrast of smooth hinting */
  30. /*************************************************************************/
  31. /*************************************************************************/
  32. /***** *****/
  33. /***** BASIC HINTS RECORDINGS *****/
  34. /***** *****/
  35. /*************************************************************************/
  36. /*************************************************************************/
  37. /* return true iff two stem hints overlap */
  38. static FT_Int
  39. psh3_hint_overlap( PSH3_Hint hint1,
  40. PSH3_Hint hint2 )
  41. {
  42. return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
  43. hint2->org_pos + hint2->org_len >= hint1->org_pos );
  44. }
  45. /* destroy hints table */
  46. static void
  47. psh3_hint_table_done( PSH3_Hint_Table table,
  48. FT_Memory memory )
  49. {
  50. FT_FREE( table->zones );
  51. table->num_zones = 0;
  52. table->zone = 0;
  53. FT_FREE( table->sort );
  54. FT_FREE( table->hints );
  55. table->num_hints = 0;
  56. table->max_hints = 0;
  57. table->sort_global = 0;
  58. }
  59. /* deactivate all hints in a table */
  60. static void
  61. psh3_hint_table_deactivate( PSH3_Hint_Table table )
  62. {
  63. FT_UInt count = table->max_hints;
  64. PSH3_Hint hint = table->hints;
  65. for ( ; count > 0; count--, hint++ )
  66. {
  67. psh3_hint_deactivate( hint );
  68. hint->order = -1;
  69. }
  70. }
  71. /* internal function used to record a new hint */
  72. static void
  73. psh3_hint_table_record( PSH3_Hint_Table table,
  74. FT_UInt idx )
  75. {
  76. PSH3_Hint hint = table->hints + idx;
  77. if ( idx >= table->max_hints )
  78. {
  79. FT_ERROR(( "psh3_hint_table_record: invalid hint index %d\n", idx ));
  80. return;
  81. }
  82. /* ignore active hints */
  83. if ( psh3_hint_is_active( hint ) )
  84. return;
  85. psh3_hint_activate( hint );
  86. /* now scan the current active hint set in order to determine */
  87. /* if we are overlapping with another segment */
  88. {
  89. PSH3_Hint* sorted = table->sort_global;
  90. FT_UInt count = table->num_hints;
  91. PSH3_Hint hint2;
  92. hint->parent = 0;
  93. for ( ; count > 0; count--, sorted++ )
  94. {
  95. hint2 = sorted[0];
  96. if ( psh3_hint_overlap( hint, hint2 ) )
  97. {
  98. hint->parent = hint2;
  99. break;
  100. }
  101. }
  102. }
  103. if ( table->num_hints < table->max_hints )
  104. table->sort_global[table->num_hints++] = hint;
  105. else
  106. FT_ERROR(( "psh3_hint_table_record: too many sorted hints! BUG!\n" ));
  107. }
  108. static void
  109. psh3_hint_table_record_mask( PSH3_Hint_Table table,
  110. PS_Mask hint_mask )
  111. {
  112. FT_Int mask = 0, val = 0;
  113. FT_Byte* cursor = hint_mask->bytes;
  114. FT_UInt idx, limit;
  115. limit = hint_mask->num_bits;
  116. for ( idx = 0; idx < limit; idx++ )
  117. {
  118. if ( mask == 0 )
  119. {
  120. val = *cursor++;
  121. mask = 0x80;
  122. }
  123. if ( val & mask )
  124. psh3_hint_table_record( table, idx );
  125. mask >>= 1;
  126. }
  127. }
  128. /* create hints table */
  129. static FT_Error
  130. psh3_hint_table_init( PSH3_Hint_Table table,
  131. PS_Hint_Table hints,
  132. PS_Mask_Table hint_masks,
  133. PS_Mask_Table counter_masks,
  134. FT_Memory memory )
  135. {
  136. FT_UInt count = hints->num_hints;
  137. FT_Error error;
  138. FT_UNUSED( counter_masks );
  139. /* allocate our tables */
  140. if ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
  141. FT_NEW_ARRAY( table->hints, count ) ||
  142. FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
  143. goto Exit;
  144. table->max_hints = count;
  145. table->sort_global = table->sort + count;
  146. table->num_hints = 0;
  147. table->num_zones = 0;
  148. table->zone = 0;
  149. /* now, initialize the "hints" array */
  150. {
  151. PSH3_Hint write = table->hints;
  152. PS_Hint read = hints->hints;
  153. for ( ; count > 0; count--, write++, read++ )
  154. {
  155. write->org_pos = read->pos;
  156. write->org_len = read->len;
  157. write->flags = read->flags;
  158. }
  159. }
  160. /* we now need to determine the initial "parent" stems; first */
  161. /* activate the hints that are given by the initial hint masks */
  162. if ( hint_masks )
  163. {
  164. FT_UInt Count = hint_masks->num_masks;
  165. PS_Mask Mask = hint_masks->masks;
  166. table->hint_masks = hint_masks;
  167. for ( ; Count > 0; Count--, Mask++ )
  168. psh3_hint_table_record_mask( table, Mask );
  169. }
  170. /* now, do a linear parse in case some hints were left alone */
  171. if ( table->num_hints != table->max_hints )
  172. {
  173. FT_UInt Index, Count;
  174. FT_ERROR(( "psh3_hint_table_init: missing/incorrect hint masks!\n" ));
  175. Count = table->max_hints;
  176. for ( Index = 0; Index < Count; Index++ )
  177. psh3_hint_table_record( table, Index );
  178. }
  179. Exit:
  180. return error;
  181. }
  182. static void
  183. psh3_hint_table_activate_mask( PSH3_Hint_Table table,
  184. PS_Mask hint_mask )
  185. {
  186. FT_Int mask = 0, val = 0;
  187. FT_Byte* cursor = hint_mask->bytes;
  188. FT_UInt idx, limit, count;
  189. limit = hint_mask->num_bits;
  190. count = 0;
  191. psh3_hint_table_deactivate( table );
  192. for ( idx = 0; idx < limit; idx++ )
  193. {
  194. if ( mask == 0 )
  195. {
  196. val = *cursor++;
  197. mask = 0x80;
  198. }
  199. if ( val & mask )
  200. {
  201. PSH3_Hint hint = &table->hints[idx];
  202. if ( !psh3_hint_is_active( hint ) )
  203. {
  204. FT_UInt count2;
  205. #if 0
  206. PSH3_Hint* sort = table->sort;
  207. PSH3_Hint hint2;
  208. for ( count2 = count; count2 > 0; count2--, sort++ )
  209. {
  210. hint2 = sort[0];
  211. if ( psh3_hint_overlap( hint, hint2 ) )
  212. FT_ERROR(( "psh3_hint_table_activate_mask:"
  213. " found overlapping hints\n" ))
  214. }
  215. #else
  216. count2 = 0;
  217. #endif
  218. if ( count2 == 0 )
  219. {
  220. psh3_hint_activate( hint );
  221. if ( count < table->max_hints )
  222. table->sort[count++] = hint;
  223. else
  224. FT_ERROR(( "psh3_hint_tableactivate_mask:"
  225. " too many active hints\n" ));
  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. PSH3_Hint hint1, hint2;
  237. PSH3_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. static FT_Pos
  262. psh3_dimension_quantize_len( PSH_Dimension dim,
  263. FT_Pos len,
  264. FT_Bool do_snapping )
  265. {
  266. if ( len <= 64 )
  267. len = 64;
  268. else
  269. {
  270. FT_Pos delta = len - dim->stdw.widths[0].cur;
  271. if ( delta < 0 )
  272. delta = -delta;
  273. if ( delta < 40 )
  274. {
  275. len = dim->stdw.widths[0].cur;
  276. if ( len < 48 )
  277. len = 48;
  278. }
  279. if ( len < 3 * 64 )
  280. {
  281. delta = ( len & 63 );
  282. len &= -64;
  283. if ( delta < 10 )
  284. len += delta;
  285. else if ( delta < 32 )
  286. len += 10;
  287. else if ( delta < 54 )
  288. len += 54;
  289. else
  290. len += delta;
  291. }
  292. else
  293. len = ( len + 32 ) & -64;
  294. }
  295. if ( do_snapping )
  296. len = ( len + 32 ) & -64;
  297. return len;
  298. }
  299. #ifdef DEBUG_HINTER
  300. static void
  301. ps3_simple_scale( PSH3_Hint_Table table,
  302. FT_Fixed scale,
  303. FT_Fixed delta,
  304. FT_Int dimension )
  305. {
  306. PSH3_Hint hint;
  307. FT_UInt count;
  308. for ( count = 0; count < table->max_hints; count++ )
  309. {
  310. hint = table->hints + count;
  311. hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
  312. hint->cur_len = FT_MulFix( hint->org_len, scale );
  313. if ( ps3_debug_hint_func )
  314. ps3_debug_hint_func( hint, dimension );
  315. }
  316. }
  317. #endif /* DEBUG_HINTER */
  318. static FT_Fixed
  319. psh3_hint_snap_stem_side_delta( FT_Fixed pos,
  320. FT_Fixed len )
  321. {
  322. FT_Fixed delta1 = ( ( pos + 32 ) & -64 ) - pos;
  323. FT_Fixed delta2 = ( ( pos + len + 32 ) & -64 ) - pos - len;
  324. if ( ABS( delta1 ) <= ABS( delta2 ) )
  325. return delta1;
  326. else
  327. return delta2;
  328. }
  329. static void
  330. psh3_hint_align( PSH3_Hint hint,
  331. PSH_Globals globals,
  332. FT_Int dimension,
  333. PSH3_Glyph glyph )
  334. {
  335. PSH_Dimension dim = &globals->dimension[dimension];
  336. FT_Fixed scale = dim->scale_mult;
  337. FT_Fixed delta = dim->scale_delta;
  338. if ( !psh3_hint_is_fitted( hint ) )
  339. {
  340. FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
  341. FT_Pos len = FT_MulFix( hint->org_len, scale );
  342. FT_Int do_snapping;
  343. FT_Pos fit_len;
  344. PSH_AlignmentRec align;
  345. /* ignore stem alignments when requested through the hint flags */
  346. if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
  347. ( dimension == 1 && !glyph->do_vert_hints ) )
  348. {
  349. hint->cur_pos = pos;
  350. hint->cur_len = len;
  351. psh3_hint_set_fitted( hint );
  352. return;
  353. }
  354. /* perform stem snapping when requested */
  355. do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
  356. ( dimension == 1 && glyph->do_vert_snapping );
  357. hint->cur_len = fit_len = len;
  358. /* check blue zones for horizontal stems */
  359. align.align = PSH_BLUE_ALIGN_NONE;
  360. align.align_bot = align.align_top = 0;
  361. if ( dimension == 1 )
  362. psh_blues_snap_stem( &globals->blues,
  363. hint->org_pos + hint->org_len,
  364. hint->org_pos,
  365. &align );
  366. switch ( align.align )
  367. {
  368. case PSH_BLUE_ALIGN_TOP:
  369. /* the top of the stem is aligned against a blue zone */
  370. hint->cur_pos = align.align_top - fit_len;
  371. break;
  372. case PSH_BLUE_ALIGN_BOT:
  373. /* the bottom of the stem is aligned against a blue zone */
  374. hint->cur_pos = align.align_bot;
  375. break;
  376. case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
  377. /* both edges of the stem are aligned against blue zones */
  378. hint->cur_pos = align.align_bot;
  379. hint->cur_len = align.align_top - align.align_bot;
  380. break;
  381. default:
  382. {
  383. PSH3_Hint parent = hint->parent;
  384. if ( parent )
  385. {
  386. FT_Pos par_org_center, par_cur_center;
  387. FT_Pos cur_org_center, cur_delta;
  388. /* ensure that parent is already fitted */
  389. if ( !psh3_hint_is_fitted( parent ) )
  390. psh3_hint_align( parent, globals, dimension, glyph );
  391. par_org_center = parent->org_pos + ( parent->org_len >> 1 );
  392. par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 );
  393. cur_org_center = hint->org_pos + ( hint->org_len >> 1 );
  394. cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
  395. pos = par_cur_center + cur_delta - ( len >> 1 );
  396. }
  397. hint->cur_pos = pos;
  398. hint->cur_len = fit_len;
  399. if ( len <= 64 )
  400. {
  401. /* the stem is less than one pixel, we will center it */
  402. /* around the nearest pixel center */
  403. /* */
  404. pos = ( pos + ( (len >> 1) & -64 ) );
  405. len = 64;
  406. }
  407. else
  408. {
  409. len = psh3_dimension_quantize_len( dim, len, 0 );
  410. }
  411. /* now that we have a good hinted stem width, try to position */
  412. /* the stem along a pixel grid integer coordinate */
  413. hint->cur_pos = pos + psh3_hint_snap_stem_side_delta( pos, len );
  414. hint->cur_len = len;
  415. }
  416. }
  417. if ( do_snapping )
  418. {
  419. pos = hint->cur_pos;
  420. len = hint->cur_len;
  421. if ( len < 64 )
  422. len = 64;
  423. else
  424. len = ( len + 32 ) & -64;
  425. switch ( align.align )
  426. {
  427. case PSH_BLUE_ALIGN_TOP:
  428. hint->cur_pos = align.align_top - len;
  429. hint->cur_len = len;
  430. break;
  431. case PSH_BLUE_ALIGN_BOT:
  432. hint->cur_len = len;
  433. break;
  434. case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP:
  435. /* don't touch */
  436. break;
  437. default:
  438. hint->cur_len = len;
  439. if ( len & 64 )
  440. pos = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
  441. else
  442. pos = ( pos + ( len >> 1 ) + 32 ) & -64;
  443. hint->cur_pos = pos - ( len >> 1 );
  444. hint->cur_len = len;
  445. }
  446. }
  447. psh3_hint_set_fitted( hint );
  448. #ifdef DEBUG_HINTER
  449. if ( ps3_debug_hint_func )
  450. ps3_debug_hint_func( hint, dimension );
  451. #endif
  452. }
  453. }
  454. static void
  455. psh3_hint_table_align_hints( PSH3_Hint_Table table,
  456. PSH_Globals globals,
  457. FT_Int dimension,
  458. PSH3_Glyph glyph )
  459. {
  460. PSH3_Hint hint;
  461. FT_UInt count;
  462. #ifdef DEBUG_HINTER
  463. PSH_Dimension dim = &globals->dimension[dimension];
  464. FT_Fixed scale = dim->scale_mult;
  465. FT_Fixed delta = dim->scale_delta;
  466. if ( ps_debug_no_vert_hints && dimension == 0 )
  467. {
  468. ps3_simple_scale( table, scale, delta, dimension );
  469. return;
  470. }
  471. if ( ps_debug_no_horz_hints && dimension == 1 )
  472. {
  473. ps3_simple_scale( table, scale, delta, dimension );
  474. return;
  475. }
  476. #endif /* DEBUG_HINTER*/
  477. hint = table->hints;
  478. count = table->max_hints;
  479. for ( ; count > 0; count--, hint++ )
  480. psh3_hint_align( hint, globals, dimension, glyph );
  481. }
  482. /*************************************************************************/
  483. /*************************************************************************/
  484. /***** *****/
  485. /***** POINTS INTERPOLATION ROUTINES *****/
  486. /***** *****/
  487. /*************************************************************************/
  488. /*************************************************************************/
  489. #define PSH3_ZONE_MIN -3200000L
  490. #define PSH3_ZONE_MAX +3200000L
  491. #define xxDEBUG_ZONES
  492. #ifdef DEBUG_ZONES
  493. #include <stdio.h>
  494. static void
  495. psh3_print_zone( PSH3_Zone zone )
  496. {
  497. printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
  498. zone->scale / 65536.0,
  499. zone->delta / 64.0,
  500. zone->min,
  501. zone->max );
  502. }
  503. #else
  504. #define psh3_print_zone( x ) do { } while ( 0 )
  505. #endif /* DEBUG_ZONES */
  506. /*************************************************************************/
  507. /*************************************************************************/
  508. /***** *****/
  509. /***** HINTER GLYPH MANAGEMENT *****/
  510. /***** *****/
  511. /*************************************************************************/
  512. /*************************************************************************/
  513. #ifdef COMPUTE_INFLEXS
  514. /* compute all inflex points in a given glyph */
  515. static void
  516. psh3_glyph_compute_inflections( PSH3_Glyph glyph )
  517. {
  518. FT_UInt n;
  519. for ( n = 0; n < glyph->num_contours; n++ )
  520. {
  521. PSH3_Point first, start, end, before, after;
  522. FT_Angle angle_in, angle_seg, angle_out;
  523. FT_Angle diff_in, diff_out;
  524. FT_Int finished = 0;
  525. /* we need at least 4 points to create an inflection point */
  526. if ( glyph->contours[n].count < 4 )
  527. continue;
  528. /* compute first segment in contour */
  529. first = glyph->contours[n].start;
  530. start = end = first;
  531. do
  532. {
  533. end = end->next;
  534. if ( end == first )
  535. goto Skip;
  536. } while ( PSH3_POINT_EQUAL_ORG( end, first ) );
  537. angle_seg = PSH3_POINT_ANGLE( start, end );
  538. /* extend the segment start whenever possible */
  539. before = start;
  540. do
  541. {
  542. do
  543. {
  544. start = before;
  545. before = before->prev;
  546. if ( before == first )
  547. goto Skip;
  548. } while ( PSH3_POINT_EQUAL_ORG( before, start ) );
  549. angle_in = PSH3_POINT_ANGLE( before, start );
  550. } while ( angle_in == angle_seg );
  551. first = start;
  552. diff_in = FT_Angle_Diff( angle_in, angle_seg );
  553. /* now, process all segments in the contour */
  554. do
  555. {
  556. /* first, extend current segment's end whenever possible */
  557. after = end;
  558. do
  559. {
  560. do
  561. {
  562. end = after;
  563. after = after->next;
  564. if ( after == first )
  565. finished = 1;
  566. } while ( PSH3_POINT_EQUAL_ORG( end, after ) );
  567. angle_out = PSH3_POINT_ANGLE( end, after );
  568. } while ( angle_out == angle_seg );
  569. diff_out = FT_Angle_Diff( angle_seg, angle_out );
  570. if ( ( diff_in ^ diff_out ) < 0 )
  571. {
  572. /* diff_in and diff_out have different signs, we have */
  573. /* inflection points here... */
  574. do
  575. {
  576. psh3_point_set_inflex( start );
  577. start = start->next;
  578. }
  579. while ( start != end );
  580. psh3_point_set_inflex( start );
  581. }
  582. start = end;
  583. end = after;
  584. angle_seg = angle_out;
  585. diff_in = diff_out;
  586. } while ( !finished );
  587. Skip:
  588. ;
  589. }
  590. }
  591. #endif /* COMPUTE_INFLEXS */
  592. static void
  593. psh3_glyph_done( PSH3_Glyph glyph )
  594. {
  595. FT_Memory memory = glyph->memory;
  596. psh3_hint_table_done( &glyph->hint_tables[1], memory );
  597. psh3_hint_table_done( &glyph->hint_tables[0], memory );
  598. FT_FREE( glyph->points );
  599. FT_FREE( glyph->contours );
  600. glyph->num_points = 0;
  601. glyph->num_contours = 0;
  602. glyph->memory = 0;
  603. }
  604. static int
  605. psh3_compute_dir( FT_Pos dx,
  606. FT_Pos dy )
  607. {
  608. FT_Pos ax, ay;
  609. int result = PSH3_DIR_NONE;
  610. ax = ( dx >= 0 ) ? dx : -dx;
  611. ay = ( dy >= 0 ) ? dy : -dy;
  612. if ( ay * 12 < ax )
  613. {
  614. /* |dy| <<< |dx| means a near-horizontal segment */
  615. result = ( dx >= 0 ) ? PSH3_DIR_RIGHT : PSH3_DIR_LEFT;
  616. }
  617. else if ( ax * 12 < ay )
  618. {
  619. /* |dx| <<< |dy| means a near-vertical segment */
  620. result = ( dy >= 0 ) ? PSH3_DIR_UP : PSH3_DIR_DOWN;
  621. }
  622. return result;
  623. }
  624. /* load outline point coordinates into hinter glyph */
  625. static void
  626. psh3_glyph_load_points( PSH3_Glyph glyph,
  627. FT_Int dimension )
  628. {
  629. FT_Vector* vec = glyph->outline->points;
  630. PSH3_Point point = glyph->points;
  631. FT_UInt count = glyph->num_points;
  632. for ( ; count > 0; count--, point++, vec++ )
  633. {
  634. point->flags2 = 0;
  635. point->hint = NULL;
  636. if ( dimension == 0 )
  637. {
  638. point->org_u = vec->x;
  639. point->org_v = vec->y;
  640. }
  641. else
  642. {
  643. point->org_u = vec->y;
  644. point->org_v = vec->x;
  645. }
  646. #ifdef DEBUG_HINTER
  647. point->org_x = vec->x;
  648. point->org_y = vec->y;
  649. #endif
  650. }
  651. }
  652. /* save hinted point coordinates back to outline */
  653. static void
  654. psh3_glyph_save_points( PSH3_Glyph glyph,
  655. FT_Int dimension )
  656. {
  657. FT_UInt n;
  658. PSH3_Point point = glyph->points;
  659. FT_Vector* vec = glyph->outline->points;
  660. char* tags = glyph->outline->tags;
  661. for ( n = 0; n < glyph->num_points; n++ )
  662. {
  663. if ( dimension == 0 )
  664. vec[n].x = point->cur_u;
  665. else
  666. vec[n].y = point->cur_u;
  667. if ( psh3_point_is_strong( point ) )
  668. tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
  669. #ifdef DEBUG_HINTER
  670. if ( dimension == 0 )
  671. {
  672. point->cur_x = point->cur_u;
  673. point->flags_x = point->flags2 | point->flags;
  674. }
  675. else
  676. {
  677. point->cur_y = point->cur_u;
  678. point->flags_y = point->flags2 | point->flags;
  679. }
  680. #endif
  681. point++;
  682. }
  683. }
  684. static FT_Error
  685. psh3_glyph_init( PSH3_Glyph glyph,
  686. FT_Outline* outline,
  687. PS_Hints ps_hints,
  688. PSH_Globals globals )
  689. {
  690. FT_Error error;
  691. FT_Memory memory;
  692. /* clear all fields */
  693. FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
  694. memory = globals->memory;
  695. /* allocate and setup points + contours arrays */
  696. if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) ||
  697. FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
  698. goto Exit;
  699. glyph->num_points = outline->n_points;
  700. glyph->num_contours = outline->n_contours;
  701. {
  702. FT_UInt first = 0, next, n;
  703. PSH3_Point points = glyph->points;
  704. PSH3_Contour contour = glyph->contours;
  705. for ( n = 0; n < glyph->num_contours; n++ )
  706. {
  707. FT_Int count;
  708. PSH3_Point point;
  709. next = outline->contours[n] + 1;
  710. count = next - first;
  711. contour->start = points + first;
  712. contour->count = (FT_UInt)count;
  713. if ( count > 0 )
  714. {
  715. point = points + first;
  716. point->prev = points + next - 1;
  717. point->contour = contour;
  718. for ( ; count > 1; count-- )
  719. {
  720. point[0].next = point + 1;
  721. point[1].prev = point;
  722. point++;
  723. point->contour = contour;
  724. }
  725. point->next = points + first;
  726. }
  727. contour++;
  728. first = next;
  729. }
  730. }
  731. {
  732. PSH3_Point points = glyph->points;
  733. PSH3_Point point = points;
  734. FT_Vector* vec = outline->points;
  735. FT_UInt n;
  736. for ( n = 0; n < glyph->num_points; n++, point++ )
  737. {
  738. FT_Int n_prev = point->prev - points;
  739. FT_Int n_next = point->next - points;
  740. FT_Pos dxi, dyi, dxo, dyo;
  741. if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
  742. point->flags = PSH3_POINT_OFF;
  743. dxi = vec[n].x - vec[n_prev].x;
  744. dyi = vec[n].y - vec[n_prev].y;
  745. point->dir_in = (FT_Char)psh3_compute_dir( dxi, dyi );
  746. dxo = vec[n_next].x - vec[n].x;
  747. dyo = vec[n_next].y - vec[n].y;
  748. point->dir_out = (FT_Char)psh3_compute_dir( dxo, dyo );
  749. /* detect smooth points */
  750. if ( point->flags & PSH3_POINT_OFF )
  751. point->flags |= PSH3_POINT_SMOOTH;
  752. else if ( point->dir_in != PSH3_DIR_NONE ||
  753. point->dir_out != PSH3_DIR_NONE )
  754. {
  755. if ( point->dir_in == point->dir_out )
  756. point->flags |= PSH3_POINT_SMOOTH;
  757. }
  758. else
  759. {
  760. FT_Angle angle_in, angle_out, diff;
  761. angle_in = FT_Atan2( dxi, dyi );
  762. angle_out = FT_Atan2( dxo, dyo );
  763. diff = angle_in - angle_out;
  764. if ( diff < 0 )
  765. diff = -diff;
  766. if ( diff > FT_ANGLE_PI )
  767. diff = FT_ANGLE_2PI - diff;
  768. if ( diff < FT_ANGLE_PI / 16 )
  769. point->flags |= PSH3_POINT_SMOOTH;
  770. }
  771. }
  772. }
  773. glyph->memory = memory;
  774. glyph->outline = outline;
  775. glyph->globals = globals;
  776. #ifdef COMPUTE_INFLEXS
  777. psh3_glyph_load_points( glyph, 0 );
  778. psh3_glyph_compute_inflections( glyph );
  779. #endif /* COMPUTE_INFLEXS */
  780. /* now deal with hints tables */
  781. error = psh3_hint_table_init( &glyph->hint_tables [0],
  782. &ps_hints->dimension[0].hints,
  783. &ps_hints->dimension[0].masks,
  784. &ps_hints->dimension[0].counters,
  785. memory );
  786. if ( error )
  787. goto Exit;
  788. error = psh3_hint_table_init( &glyph->hint_tables [1],
  789. &ps_hints->dimension[1].hints,
  790. &ps_hints->dimension[1].masks,
  791. &ps_hints->dimension[1].counters,
  792. memory );
  793. if ( error )
  794. goto Exit;
  795. Exit:
  796. return error;
  797. }
  798. /* compute all extrema in a glyph for a given dimension */
  799. static void
  800. psh3_glyph_compute_extrema( PSH3_Glyph glyph )
  801. {
  802. FT_UInt n;
  803. /* first of all, compute all local extrema */
  804. for ( n = 0; n < glyph->num_contours; n++ )
  805. {
  806. PSH3_Point first = glyph->contours[n].start;
  807. PSH3_Point point, before, after;
  808. point = first;
  809. before = point;
  810. after = point;
  811. do
  812. {
  813. before = before->prev;
  814. if ( before == first )
  815. goto Skip;
  816. } while ( before->org_u == point->org_u );
  817. first = point = before->next;
  818. for (;;)
  819. {
  820. after = point;
  821. do
  822. {
  823. after = after->next;
  824. if ( after == first )
  825. goto Next;
  826. } while ( after->org_u == point->org_u );
  827. if ( before->org_u < point->org_u )
  828. {
  829. if ( after->org_u < point->org_u )
  830. {
  831. /* local maximum */
  832. goto Extremum;
  833. }
  834. }
  835. else /* before->org_u > point->org_u */
  836. {
  837. if ( after->org_u > point->org_u )
  838. {
  839. /* local minimum */
  840. Extremum:
  841. do
  842. {
  843. psh3_point_set_extremum( point );
  844. point = point->next;
  845. } while ( point != after );
  846. }
  847. }
  848. before = after->prev;
  849. point = after;
  850. } /* for */
  851. Next:
  852. ;
  853. }
  854. /* for each extrema, determine its direction along the */
  855. /* orthogonal axis */
  856. for ( n = 0; n < glyph->num_points; n++ )
  857. {
  858. PSH3_Point point, before, after;
  859. point = &glyph->points[n];
  860. before = point;
  861. after = point;
  862. if ( psh3_point_is_extremum( point ) )
  863. {
  864. do
  865. {
  866. before = before->prev;
  867. if ( before == point )
  868. goto Skip;
  869. } while ( before->org_v == point->org_v );
  870. do
  871. {
  872. after = after->next;
  873. if ( after == point )
  874. goto Skip;
  875. } while ( after->org_v == point->org_v );
  876. }
  877. if ( before->org_v < point->org_v &&
  878. after->org_v > point->org_v )
  879. {
  880. psh3_point_set_positive( point );
  881. }
  882. else if ( before->org_v > point->org_v &&
  883. after->org_v < point->org_v )
  884. {
  885. psh3_point_set_negative( point );
  886. }
  887. Skip:
  888. ;
  889. }
  890. }
  891. #define PSH3_STRONG_THRESHOLD 30
  892. /* major_dir is the direction for points on the bottom/left of the stem; */
  893. /* Points on the top/right of the stem will have a direction of */
  894. /* -major_dir. */
  895. static void
  896. psh3_hint_table_find_strong_point( PSH3_Hint_Table table,
  897. PSH3_Point point,
  898. FT_Int major_dir )
  899. {
  900. PSH3_Hint* sort = table->sort;
  901. FT_UInt num_hints = table->num_hints;
  902. FT_Int point_dir = 0;
  903. if ( PSH3_DIR_COMPARE( point->dir_in, major_dir ) )
  904. point_dir = point->dir_in;
  905. else if ( PSH3_DIR_COMPARE( point->dir_out, major_dir ) )
  906. point_dir = point->dir_out;
  907. if ( point_dir )
  908. {
  909. FT_UInt flag;
  910. for ( ; num_hints > 0; num_hints--, sort++ )
  911. {
  912. PSH3_Hint hint = sort[0];
  913. FT_Pos d;
  914. if ( point_dir == major_dir )
  915. {
  916. flag = PSH3_POINT_EDGE_MIN;
  917. d = point->org_u - hint->org_pos;
  918. if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
  919. {
  920. Is_Strong:
  921. psh3_point_set_strong( point );
  922. point->flags2 |= flag;
  923. point->hint = hint;
  924. break;
  925. }
  926. }
  927. else if ( point_dir == -major_dir )
  928. {
  929. flag = PSH3_POINT_EDGE_MAX;
  930. d = point->org_u - hint->org_pos - hint->org_len;
  931. if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
  932. goto Is_Strong;
  933. }
  934. }
  935. }
  936. #if 1
  937. else if ( psh3_point_is_extremum( point ) )
  938. {
  939. /* treat extrema as special cases for stem edge alignment */
  940. FT_UInt min_flag, max_flag;
  941. if ( major_dir == PSH3_DIR_HORIZONTAL )
  942. {
  943. min_flag = PSH3_POINT_POSITIVE;
  944. max_flag = PSH3_POINT_NEGATIVE;
  945. }
  946. else
  947. {
  948. min_flag = PSH3_POINT_NEGATIVE;
  949. max_flag = PSH3_POINT_POSITIVE;
  950. }
  951. for ( ; num_hints > 0; num_hints--, sort++ )
  952. {
  953. PSH3_Hint hint = sort[0];
  954. FT_Pos d, flag;
  955. if ( point->flags2 & min_flag )
  956. {
  957. flag = PSH3_POINT_EDGE_MIN;
  958. d = point->org_u - hint->org_pos;
  959. if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
  960. {
  961. Is_Strong2:
  962. point->flags2 |= flag;
  963. point->hint = hint;
  964. psh3_point_set_strong( point );
  965. break;
  966. }
  967. }
  968. else if ( point->flags2 & max_flag )
  969. {
  970. flag = PSH3_POINT_EDGE_MAX;
  971. d = point->org_u - hint->org_pos - hint->org_len;
  972. if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
  973. goto Is_Strong2;
  974. }
  975. if ( point->org_u >= hint->org_pos &&
  976. point->org_u <= hint->org_pos + hint->org_len )
  977. {
  978. point->hint = hint;
  979. }
  980. }
  981. }
  982. #endif /* 1 */
  983. }
  984. /* find strong points in a glyph */
  985. static void
  986. psh3_glyph_find_strong_points( PSH3_Glyph glyph,
  987. FT_Int dimension )
  988. {
  989. /* a point is strong if it is located on a stem */
  990. /* edge and has an "in" or "out" tangent to the hint's direction */
  991. {
  992. PSH3_Hint_Table table = &glyph->hint_tables[dimension];
  993. PS_Mask mask = table->hint_masks->masks;
  994. FT_UInt num_masks = table->hint_masks->num_masks;
  995. FT_UInt first = 0;
  996. FT_Int major_dir = dimension == 0 ? PSH3_DIR_VERTICAL
  997. : PSH3_DIR_HORIZONTAL;
  998. /* process secondary hints to "selected" points */
  999. if ( num_masks > 1 && glyph->num_points > 0 )
  1000. {
  1001. first = mask->end_point;
  1002. mask++;
  1003. for ( ; num_masks > 1; num_masks--, mask++ )
  1004. {
  1005. FT_UInt next;
  1006. FT_Int count;
  1007. next = mask->end_point;
  1008. count = next - first;
  1009. if ( count > 0 )
  1010. {
  1011. PSH3_Point point = glyph->points + first;
  1012. psh3_hint_table_activate_mask( table, mask );
  1013. for ( ; count > 0; count--, point++ )
  1014. psh3_hint_table_find_strong_point( table, point, major_dir );
  1015. }
  1016. first = next;
  1017. }
  1018. }
  1019. /* process primary hints for all points */
  1020. if ( num_masks == 1 )
  1021. {
  1022. FT_UInt count = glyph->num_points;
  1023. PSH3_Point point = glyph->points;
  1024. psh3_hint_table_activate_mask( table, table->hint_masks->masks );
  1025. for ( ; count > 0; count--, point++ )
  1026. {
  1027. if ( !psh3_point_is_strong( point ) )
  1028. psh3_hint_table_find_strong_point( table, point, major_dir );
  1029. }
  1030. }
  1031. /* now, certain points may have been attached to hint and */
  1032. /* not marked as strong; update their flags then */
  1033. {
  1034. FT_UInt count = glyph->num_points;
  1035. PSH3_Point point = glyph->points;
  1036. for ( ; count > 0; count--, point++ )
  1037. if ( point->hint && !psh3_point_is_strong( point ) )
  1038. psh3_point_set_strong( point );
  1039. }
  1040. }
  1041. }
  1042. /* interpolate strong points with the help of hinted coordinates */
  1043. static void
  1044. psh3_glyph_interpolate_strong_points( PSH3_Glyph glyph,
  1045. FT_Int dimension )
  1046. {
  1047. PSH_Dimension dim = &glyph->globals->dimension[dimension];
  1048. FT_Fixed scale = dim->scale_mult;
  1049. {
  1050. FT_UInt count = glyph->num_points;
  1051. PSH3_Point point = glyph->points;
  1052. for ( ; count > 0; count--, point++ )
  1053. {
  1054. PSH3_Hint hint = point->hint;
  1055. if ( hint )
  1056. {
  1057. FT_Pos delta;
  1058. if ( psh3_point_is_edge_min( point ) )
  1059. {
  1060. point->cur_u = hint->cur_pos;
  1061. }
  1062. else if ( psh3_point_is_edge_max( point ) )
  1063. {
  1064. point->cur_u = hint->cur_pos + hint->cur_len;
  1065. }
  1066. else
  1067. {
  1068. delta = point->org_u - hint->org_pos;
  1069. if ( delta <= 0 )
  1070. point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
  1071. else if ( delta >= hint->org_len )
  1072. point->cur_u = hint->cur_pos + hint->cur_len +
  1073. FT_MulFix( delta - hint->org_len, scale );
  1074. else if ( hint->org_len > 0 )
  1075. point->cur_u = hint->cur_pos +
  1076. FT_MulDiv( delta, hint->cur_len,
  1077. hint->org_len );
  1078. else
  1079. point->cur_u = hint->cur_pos;
  1080. }
  1081. psh3_point_set_fitted( point );
  1082. }
  1083. }
  1084. }
  1085. }
  1086. static void
  1087. psh3_glyph_interpolate_normal_points( PSH3_Glyph glyph,
  1088. FT_Int dimension )
  1089. {
  1090. #if 1
  1091. PSH_Dimension dim = &glyph->globals->dimension[dimension];
  1092. FT_Fixed scale = dim->scale_mult;
  1093. /* first technique: a point is strong if it is a local extrema */
  1094. {
  1095. FT_UInt count = glyph->num_points;
  1096. PSH3_Point point = glyph->points;
  1097. for ( ; count > 0; count--, point++ )
  1098. {
  1099. if ( psh3_point_is_strong( point ) )
  1100. continue;
  1101. /* sometimes, some local extremas are smooth points */
  1102. if ( psh3_point_is_smooth( point ) )
  1103. {
  1104. if ( point->dir_in == PSH3_DIR_NONE ||
  1105. point->dir_in != point->dir_out )
  1106. continue;
  1107. if ( !psh3_point_is_extremum( point ) &&
  1108. !psh3_point_is_inflex( point ) )
  1109. continue;
  1110. point->flags &= ~PSH3_POINT_SMOOTH;
  1111. }
  1112. /* find best enclosing point coordinates */
  1113. {
  1114. PSH3_Point before = 0;
  1115. PSH3_Point after = 0;
  1116. FT_Pos diff_before = -32000;
  1117. FT_Pos diff_after = 32000;
  1118. FT_Pos u = point->org_u;
  1119. FT_Int count2 = glyph->num_points;
  1120. PSH3_Point cur = glyph->points;
  1121. for ( ; count2 > 0; count2--, cur++ )
  1122. {
  1123. if ( psh3_point_is_strong( cur ) )
  1124. {
  1125. FT_Pos diff = cur->org_u - u;;
  1126. if ( diff <= 0 )
  1127. {
  1128. if ( diff > diff_before )
  1129. {
  1130. diff_before = diff;
  1131. before = cur;
  1132. }
  1133. }
  1134. else if ( diff >= 0 )
  1135. {
  1136. if ( diff < diff_after )
  1137. {
  1138. diff_after = diff;
  1139. after = cur;
  1140. }
  1141. }
  1142. }
  1143. }
  1144. if ( !before )
  1145. {
  1146. if ( !after )
  1147. continue;
  1148. /* we are before the first strong point coordinate; */
  1149. /* simply translate the point */
  1150. point->cur_u = after->cur_u +
  1151. FT_MulFix( point->org_u - after->org_u, scale );
  1152. }
  1153. else if ( !after )
  1154. {
  1155. /* we are after the last strong point coordinate; */
  1156. /* simply translate the point */
  1157. point->cur_u = before->cur_u +
  1158. FT_MulFix( point->org_u - before->org_u, scale );
  1159. }
  1160. else
  1161. {
  1162. if ( diff_before == 0 )
  1163. point->cur_u = before->cur_u;
  1164. else if ( diff_after == 0 )
  1165. point->cur_u = after->cur_u;
  1166. else
  1167. point->cur_u = before->cur_u +
  1168. FT_MulDiv( u - before->org_u,
  1169. after->cur_u - before->cur_u,
  1170. after->org_u - before->org_u );
  1171. }
  1172. psh3_point_set_fitted( point );
  1173. }
  1174. }
  1175. }
  1176. #endif /* 1 */
  1177. }
  1178. /* interpolate other points */
  1179. static void
  1180. psh3_glyph_interpolate_other_points( PSH3_Glyph glyph,
  1181. FT_Int dimension )
  1182. {
  1183. PSH_Dimension dim = &glyph->globals->dimension[dimension];
  1184. FT_Fixed scale = dim->scale_mult;
  1185. FT_Fixed delta = dim->scale_delta;
  1186. PSH3_Contour contour = glyph->contours;
  1187. FT_UInt num_contours = glyph->num_contours;
  1188. for ( ; num_contours > 0; num_contours--, contour++ )
  1189. {
  1190. PSH3_Point start = contour->start;
  1191. PSH3_Point first, next, point;
  1192. FT_UInt fit_count;
  1193. /* count the number of strong points in this contour */
  1194. next = start + contour->count;
  1195. fit_count = 0;
  1196. first = 0;
  1197. for ( point = start; point < next; point++ )
  1198. if ( psh3_point_is_fitted( point ) )
  1199. {
  1200. if ( !first )
  1201. first = point;
  1202. fit_count++;
  1203. }
  1204. /* if there are less than 2 fitted points in the contour, we */
  1205. /* simply scale and eventually translate the contour points */
  1206. if ( fit_count < 2 )
  1207. {
  1208. if ( fit_count == 1 )
  1209. delta = first->cur_u - FT_MulFix( first->org_u, scale );
  1210. for ( point = start; point < next; point++ )
  1211. if ( point != first )
  1212. point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
  1213. goto Next_Contour;
  1214. }
  1215. /* there are more than 2 strong points in this contour; we */
  1216. /* need to interpolate weak points between them */
  1217. start = first;
  1218. do
  1219. {
  1220. point = first;
  1221. /* skip consecutive fitted points */
  1222. for (;;)
  1223. {
  1224. next = first->next;
  1225. if ( next == start )
  1226. goto Next_Contour;
  1227. if ( !psh3_point_is_fitted( next ) )
  1228. break;
  1229. first = next;
  1230. }
  1231. /* find next fitted point after unfitted one */
  1232. for (;;)
  1233. {
  1234. next = next->next;
  1235. if ( psh3_point_is_fitted( next ) )
  1236. break;
  1237. }
  1238. /* now interpolate between them */
  1239. {
  1240. FT_Pos org_a, org_ab, cur_a, cur_ab;
  1241. FT_Pos org_c, org_ac, cur_c;
  1242. FT_Fixed scale_ab;
  1243. if ( first->org_u <= next->org_u )
  1244. {
  1245. org_a = first->org_u;
  1246. cur_a = first->cur_u;
  1247. org_ab = next->org_u - org_a;
  1248. cur_ab = next->cur_u - cur_a;
  1249. }
  1250. else
  1251. {
  1252. org_a = next->org_u;
  1253. cur_a = next->cur_u;
  1254. org_ab = first->org_u - org_a;
  1255. cur_ab = first->cur_u - cur_a;
  1256. }
  1257. scale_ab = 0x10000L;
  1258. if ( org_ab > 0 )
  1259. scale_ab = FT_DivFix( cur_ab, org_ab );
  1260. point = first->next;
  1261. do
  1262. {
  1263. org_c = point->org_u;
  1264. org_ac = org_c - org_a;
  1265. if ( org_ac <= 0 )
  1266. {
  1267. /* on the left of the interpolation zone */
  1268. cur_c = cur_a + FT_MulFix( org_ac, scale );
  1269. }
  1270. else if ( org_ac >= org_ab )
  1271. {
  1272. /* on the right on the interpolation zone */
  1273. cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
  1274. }
  1275. else
  1276. {
  1277. /* within the interpolation zone */
  1278. cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
  1279. }
  1280. point->cur_u = cur_c;
  1281. point = point->next;
  1282. } while ( point != next );
  1283. }
  1284. /* keep going until all points in the contours have been processed */
  1285. first = next;
  1286. } while ( first != start );
  1287. Next_Contour:
  1288. ;
  1289. }
  1290. }
  1291. /*************************************************************************/
  1292. /*************************************************************************/
  1293. /***** *****/
  1294. /***** HIGH-LEVEL INTERFACE *****/
  1295. /***** *****/
  1296. /*************************************************************************/
  1297. /*************************************************************************/
  1298. FT_Error
  1299. ps3_hints_apply( PS_Hints ps_hints,
  1300. FT_Outline* outline,
  1301. PSH_Globals globals,
  1302. FT_Render_Mode hint_mode )
  1303. {
  1304. PSH3_GlyphRec glyphrec;
  1305. PSH3_Glyph glyph = &glyphrec;
  1306. FT_Error error;
  1307. #ifdef DEBUG_HINTER
  1308. FT_Memory memory;
  1309. #endif
  1310. FT_Int dimension;
  1311. #ifdef DEBUG_HINTER
  1312. memory = globals->memory;
  1313. if ( ps3_debug_glyph )
  1314. {
  1315. psh3_glyph_done( ps3_debug_glyph );
  1316. FT_FREE( ps3_debug_glyph );
  1317. }
  1318. if ( FT_NEW( glyph ) )
  1319. return error;
  1320. ps3_debug_glyph = glyph;
  1321. #endif /* DEBUG_HINTER */
  1322. error = psh3_glyph_init( glyph, outline, ps_hints, globals );
  1323. if ( error )
  1324. goto Exit;
  1325. glyph->do_horz_hints = 1;
  1326. glyph->do_vert_hints = 1;
  1327. glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
  1328. hint_mode == FT_RENDER_MODE_LCD );
  1329. glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
  1330. hint_mode == FT_RENDER_MODE_LCD_V );
  1331. for ( dimension = 0; dimension < 2; dimension++ )
  1332. {
  1333. /* load outline coordinates into glyph */
  1334. psh3_glyph_load_points( glyph, dimension );
  1335. /* compute local extrema */
  1336. psh3_glyph_compute_extrema( glyph );
  1337. /* compute aligned stem/hints positions */
  1338. psh3_hint_table_align_hints( &glyph->hint_tables[dimension],
  1339. glyph->globals,
  1340. dimension,
  1341. glyph );
  1342. /* find strong points, align them, then interpolate others */
  1343. psh3_glyph_find_strong_points( glyph, dimension );
  1344. psh3_glyph_interpolate_strong_points( glyph, dimension );
  1345. psh3_glyph_interpolate_normal_points( glyph, dimension );
  1346. psh3_glyph_interpolate_other_points( glyph, dimension );
  1347. /* save hinted coordinates back to outline */
  1348. psh3_glyph_save_points( glyph, dimension );
  1349. }
  1350. Exit:
  1351. #ifndef DEBUG_HINTER
  1352. psh3_glyph_done( glyph );
  1353. #endif
  1354. return error;
  1355. }
  1356. /* END */