/src/freetype/src/autofit/afloader.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 554 lines · 369 code · 122 blank · 63 comment · 45 complexity · 56a7d131b2d6d7aad8f5a22deff16285 MD5 · raw file

  1. /***************************************************************************/
  2. /* */
  3. /* afloader.c */
  4. /* */
  5. /* Auto-fitter glyph loading routines (body). */
  6. /* */
  7. /* Copyright 2003-2009, 2011-2012 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 "afloader.h"
  18. #include "afhints.h"
  19. #include "afglobal.h"
  20. #include "aferrors.h"
  21. /* Initialize glyph loader. */
  22. FT_LOCAL_DEF( FT_Error )
  23. af_loader_init( AF_Loader loader,
  24. FT_Memory memory )
  25. {
  26. FT_ZERO( loader );
  27. af_glyph_hints_init( &loader->hints, memory );
  28. #ifdef FT_DEBUG_AUTOFIT
  29. _af_debug_hints = &loader->hints;
  30. #endif
  31. return FT_GlyphLoader_New( memory, &loader->gloader );
  32. }
  33. /* Reset glyph loader and compute globals if necessary. */
  34. FT_LOCAL_DEF( FT_Error )
  35. af_loader_reset( AF_Loader loader,
  36. FT_Face face )
  37. {
  38. FT_Error error = AF_Err_Ok;
  39. loader->face = face;
  40. loader->globals = (AF_FaceGlobals)face->autohint.data;
  41. FT_GlyphLoader_Rewind( loader->gloader );
  42. if ( loader->globals == NULL )
  43. {
  44. error = af_face_globals_new( face, &loader->globals );
  45. if ( !error )
  46. {
  47. face->autohint.data =
  48. (FT_Pointer)loader->globals;
  49. face->autohint.finalizer =
  50. (FT_Generic_Finalizer)af_face_globals_free;
  51. }
  52. }
  53. return error;
  54. }
  55. /* Finalize glyph loader. */
  56. FT_LOCAL_DEF( void )
  57. af_loader_done( AF_Loader loader )
  58. {
  59. af_glyph_hints_done( &loader->hints );
  60. loader->face = NULL;
  61. loader->globals = NULL;
  62. #ifdef FT_DEBUG_AUTOFIT
  63. _af_debug_hints = NULL;
  64. #endif
  65. FT_GlyphLoader_Done( loader->gloader );
  66. loader->gloader = NULL;
  67. }
  68. /* Load a single glyph component. This routine calls itself */
  69. /* recursively, if necessary, and does the main work of */
  70. /* `af_loader_load_glyph.' */
  71. static FT_Error
  72. af_loader_load_g( AF_Loader loader,
  73. AF_Scaler scaler,
  74. FT_UInt glyph_index,
  75. FT_Int32 load_flags,
  76. FT_UInt depth )
  77. {
  78. FT_Error error;
  79. FT_Face face = loader->face;
  80. FT_GlyphLoader gloader = loader->gloader;
  81. AF_ScriptMetrics metrics = loader->metrics;
  82. AF_GlyphHints hints = &loader->hints;
  83. FT_GlyphSlot slot = face->glyph;
  84. FT_Slot_Internal internal = slot->internal;
  85. error = FT_Load_Glyph( face, glyph_index, load_flags );
  86. if ( error )
  87. goto Exit;
  88. loader->transformed = internal->glyph_transformed;
  89. if ( loader->transformed )
  90. {
  91. FT_Matrix inverse;
  92. loader->trans_matrix = internal->glyph_matrix;
  93. loader->trans_delta = internal->glyph_delta;
  94. inverse = loader->trans_matrix;
  95. FT_Matrix_Invert( &inverse );
  96. FT_Vector_Transform( &loader->trans_delta, &inverse );
  97. }
  98. /* set linear metrics */
  99. slot->linearHoriAdvance = slot->metrics.horiAdvance;
  100. slot->linearVertAdvance = slot->metrics.vertAdvance;
  101. switch ( slot->format )
  102. {
  103. case FT_GLYPH_FORMAT_OUTLINE:
  104. /* translate the loaded glyph when an internal transform is needed */
  105. if ( loader->transformed )
  106. FT_Outline_Translate( &slot->outline,
  107. loader->trans_delta.x,
  108. loader->trans_delta.y );
  109. /* copy the outline points in the loader's current */
  110. /* extra points which is used to keep original glyph coordinates */
  111. error = FT_GLYPHLOADER_CHECK_POINTS( gloader,
  112. slot->outline.n_points + 4,
  113. slot->outline.n_contours );
  114. if ( error )
  115. goto Exit;
  116. FT_ARRAY_COPY( gloader->current.outline.points,
  117. slot->outline.points,
  118. slot->outline.n_points );
  119. FT_ARRAY_COPY( gloader->current.outline.contours,
  120. slot->outline.contours,
  121. slot->outline.n_contours );
  122. FT_ARRAY_COPY( gloader->current.outline.tags,
  123. slot->outline.tags,
  124. slot->outline.n_points );
  125. gloader->current.outline.n_points = slot->outline.n_points;
  126. gloader->current.outline.n_contours = slot->outline.n_contours;
  127. /* compute original horizontal phantom points (and ignore */
  128. /* vertical ones) */
  129. loader->pp1.x = hints->x_delta;
  130. loader->pp1.y = hints->y_delta;
  131. loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
  132. hints->x_scale ) + hints->x_delta;
  133. loader->pp2.y = hints->y_delta;
  134. /* be sure to check for spacing glyphs */
  135. if ( slot->outline.n_points == 0 )
  136. goto Hint_Metrics;
  137. /* now load the slot image into the auto-outline and run the */
  138. /* automatic hinting process */
  139. if ( metrics->clazz->script_hints_apply )
  140. metrics->clazz->script_hints_apply( hints,
  141. &gloader->current.outline,
  142. metrics );
  143. /* we now need to adjust the metrics according to the change in */
  144. /* width/positioning that occurred during the hinting process */
  145. if ( scaler->render_mode != FT_RENDER_MODE_LIGHT )
  146. {
  147. FT_Pos old_rsb, old_lsb, new_lsb;
  148. FT_Pos pp1x_uh, pp2x_uh;
  149. AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ];
  150. AF_Edge edge1 = axis->edges; /* leftmost edge */
  151. AF_Edge edge2 = edge1 +
  152. axis->num_edges - 1; /* rightmost edge */
  153. if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
  154. {
  155. old_rsb = loader->pp2.x - edge2->opos;
  156. old_lsb = edge1->opos;
  157. new_lsb = edge1->pos;
  158. /* remember unhinted values to later account */
  159. /* for rounding errors */
  160. pp1x_uh = new_lsb - old_lsb;
  161. pp2x_uh = edge2->pos + old_rsb;
  162. /* prefer too much space over too little space */
  163. /* for very small sizes */
  164. if ( old_lsb < 24 )
  165. pp1x_uh -= 8;
  166. if ( old_rsb < 24 )
  167. pp2x_uh += 8;
  168. loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
  169. loader->pp2.x = FT_PIX_ROUND( pp2x_uh );
  170. if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
  171. loader->pp1.x -= 64;
  172. if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
  173. loader->pp2.x += 64;
  174. slot->lsb_delta = loader->pp1.x - pp1x_uh;
  175. slot->rsb_delta = loader->pp2.x - pp2x_uh;
  176. }
  177. else
  178. {
  179. FT_Pos pp1x = loader->pp1.x;
  180. FT_Pos pp2x = loader->pp2.x;
  181. loader->pp1.x = FT_PIX_ROUND( pp1x );
  182. loader->pp2.x = FT_PIX_ROUND( pp2x );
  183. slot->lsb_delta = loader->pp1.x - pp1x;
  184. slot->rsb_delta = loader->pp2.x - pp2x;
  185. }
  186. }
  187. else
  188. {
  189. FT_Pos pp1x = loader->pp1.x;
  190. FT_Pos pp2x = loader->pp2.x;
  191. loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
  192. loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );
  193. slot->lsb_delta = loader->pp1.x - pp1x;
  194. slot->rsb_delta = loader->pp2.x - pp2x;
  195. }
  196. /* good, we simply add the glyph to our loader's base */
  197. FT_GlyphLoader_Add( gloader );
  198. break;
  199. case FT_GLYPH_FORMAT_COMPOSITE:
  200. {
  201. FT_UInt nn, num_subglyphs = slot->num_subglyphs;
  202. FT_UInt num_base_subgs, start_point;
  203. FT_SubGlyph subglyph;
  204. start_point = gloader->base.outline.n_points;
  205. /* first of all, copy the subglyph descriptors in the glyph loader */
  206. error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs );
  207. if ( error )
  208. goto Exit;
  209. FT_ARRAY_COPY( gloader->current.subglyphs,
  210. slot->subglyphs,
  211. num_subglyphs );
  212. gloader->current.num_subglyphs = num_subglyphs;
  213. num_base_subgs = gloader->base.num_subglyphs;
  214. /* now read each subglyph independently */
  215. for ( nn = 0; nn < num_subglyphs; nn++ )
  216. {
  217. FT_Vector pp1, pp2;
  218. FT_Pos x, y;
  219. FT_UInt num_points, num_new_points, num_base_points;
  220. /* gloader.current.subglyphs can change during glyph loading due */
  221. /* to re-allocation -- we must recompute the current subglyph on */
  222. /* each iteration */
  223. subglyph = gloader->base.subglyphs + num_base_subgs + nn;
  224. pp1 = loader->pp1;
  225. pp2 = loader->pp2;
  226. num_base_points = gloader->base.outline.n_points;
  227. error = af_loader_load_g( loader, scaler, subglyph->index,
  228. load_flags, depth + 1 );
  229. if ( error )
  230. goto Exit;
  231. /* recompute subglyph pointer */
  232. subglyph = gloader->base.subglyphs + num_base_subgs + nn;
  233. if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
  234. {
  235. pp1 = loader->pp1;
  236. pp2 = loader->pp2;
  237. }
  238. else
  239. {
  240. loader->pp1 = pp1;
  241. loader->pp2 = pp2;
  242. }
  243. num_points = gloader->base.outline.n_points;
  244. num_new_points = num_points - num_base_points;
  245. /* now perform the transformation required for this subglyph */
  246. if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE |
  247. FT_SUBGLYPH_FLAG_XY_SCALE |
  248. FT_SUBGLYPH_FLAG_2X2 ) )
  249. {
  250. FT_Vector* cur = gloader->base.outline.points +
  251. num_base_points;
  252. FT_Vector* limit = cur + num_new_points;
  253. for ( ; cur < limit; cur++ )
  254. FT_Vector_Transform( cur, &subglyph->transform );
  255. }
  256. /* apply offset */
  257. if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
  258. {
  259. FT_Int k = subglyph->arg1;
  260. FT_UInt l = subglyph->arg2;
  261. FT_Vector* p1;
  262. FT_Vector* p2;
  263. if ( start_point + k >= num_base_points ||
  264. l >= (FT_UInt)num_new_points )
  265. {
  266. error = AF_Err_Invalid_Composite;
  267. goto Exit;
  268. }
  269. l += num_base_points;
  270. /* for now, only use the current point coordinates; */
  271. /* we may consider another approach in the near future */
  272. p1 = gloader->base.outline.points + start_point + k;
  273. p2 = gloader->base.outline.points + start_point + l;
  274. x = p1->x - p2->x;
  275. y = p1->y - p2->y;
  276. }
  277. else
  278. {
  279. x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta;
  280. y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta;
  281. x = FT_PIX_ROUND( x );
  282. y = FT_PIX_ROUND( y );
  283. }
  284. {
  285. FT_Outline dummy = gloader->base.outline;
  286. dummy.points += num_base_points;
  287. dummy.n_points = (short)num_new_points;
  288. FT_Outline_Translate( &dummy, x, y );
  289. }
  290. }
  291. }
  292. break;
  293. default:
  294. /* we don't support other formats (yet?) */
  295. error = AF_Err_Unimplemented_Feature;
  296. }
  297. Hint_Metrics:
  298. if ( depth == 0 )
  299. {
  300. FT_BBox bbox;
  301. FT_Vector vvector;
  302. vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
  303. vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
  304. vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale );
  305. vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale );
  306. /* transform the hinted outline if needed */
  307. if ( loader->transformed )
  308. {
  309. FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
  310. FT_Vector_Transform( &vvector, &loader->trans_matrix );
  311. }
  312. #if 1
  313. /* we must translate our final outline by -pp1.x and compute */
  314. /* the new metrics */
  315. if ( loader->pp1.x )
  316. FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
  317. #endif
  318. FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
  319. bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
  320. bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
  321. bbox.xMax = FT_PIX_CEIL( bbox.xMax );
  322. bbox.yMax = FT_PIX_CEIL( bbox.yMax );
  323. slot->metrics.width = bbox.xMax - bbox.xMin;
  324. slot->metrics.height = bbox.yMax - bbox.yMin;
  325. slot->metrics.horiBearingX = bbox.xMin;
  326. slot->metrics.horiBearingY = bbox.yMax;
  327. slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
  328. slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );
  329. /* for mono-width fonts (like Andale, Courier, etc.) we need */
  330. /* to keep the original rounded advance width; ditto for */
  331. /* digits if all have the same advance width */
  332. #if 0
  333. if ( !FT_IS_FIXED_WIDTH( slot->face ) )
  334. slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
  335. else
  336. slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
  337. x_scale );
  338. #else
  339. if ( scaler->render_mode != FT_RENDER_MODE_LIGHT &&
  340. ( FT_IS_FIXED_WIDTH( slot->face ) ||
  341. ( af_face_globals_is_digit( loader->globals, glyph_index ) &&
  342. metrics->digits_have_same_width ) ) )
  343. {
  344. slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
  345. metrics->scaler.x_scale );
  346. /* Set delta values to 0. Otherwise code that uses them is */
  347. /* going to ruin the fixed advance width. */
  348. slot->lsb_delta = 0;
  349. slot->rsb_delta = 0;
  350. }
  351. else
  352. {
  353. /* non-spacing glyphs must stay as-is */
  354. if ( slot->metrics.horiAdvance )
  355. slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
  356. }
  357. #endif
  358. slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
  359. metrics->scaler.y_scale );
  360. slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
  361. slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );
  362. /* now copy outline into glyph slot */
  363. FT_GlyphLoader_Rewind( internal->loader );
  364. error = FT_GlyphLoader_CopyPoints( internal->loader, gloader );
  365. if ( error )
  366. goto Exit;
  367. /* reassign all outline fields except flags to protect them */
  368. slot->outline.n_contours = internal->loader->base.outline.n_contours;
  369. slot->outline.n_points = internal->loader->base.outline.n_points;
  370. slot->outline.points = internal->loader->base.outline.points;
  371. slot->outline.tags = internal->loader->base.outline.tags;
  372. slot->outline.contours = internal->loader->base.outline.contours;
  373. slot->format = FT_GLYPH_FORMAT_OUTLINE;
  374. }
  375. Exit:
  376. return error;
  377. }
  378. /* Load a glyph. */
  379. FT_LOCAL_DEF( FT_Error )
  380. af_loader_load_glyph( AF_Loader loader,
  381. FT_Face face,
  382. FT_UInt gindex,
  383. FT_Int32 load_flags )
  384. {
  385. FT_Error error;
  386. FT_Size size = face->size;
  387. AF_ScalerRec scaler;
  388. if ( !size )
  389. return AF_Err_Invalid_Argument;
  390. FT_ZERO( &scaler );
  391. scaler.face = face;
  392. scaler.x_scale = size->metrics.x_scale;
  393. scaler.x_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */
  394. scaler.y_scale = size->metrics.y_scale;
  395. scaler.y_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */
  396. scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags );
  397. scaler.flags = 0; /* XXX: fix this */
  398. error = af_loader_reset( loader, face );
  399. if ( !error )
  400. {
  401. AF_ScriptMetrics metrics;
  402. FT_UInt options = 0;
  403. #ifdef FT_OPTION_AUTOFIT2
  404. /* XXX: undocumented hook to activate the latin2 hinter */
  405. if ( load_flags & ( 1UL << 20 ) )
  406. options = 2;
  407. #endif
  408. error = af_face_globals_get_metrics( loader->globals, gindex,
  409. options, &metrics );
  410. if ( !error )
  411. {
  412. loader->metrics = metrics;
  413. if ( metrics->clazz->script_metrics_scale )
  414. metrics->clazz->script_metrics_scale( metrics, &scaler );
  415. else
  416. metrics->scaler = scaler;
  417. load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
  418. load_flags &= ~FT_LOAD_RENDER;
  419. if ( metrics->clazz->script_hints_init )
  420. {
  421. error = metrics->clazz->script_hints_init( &loader->hints,
  422. metrics );
  423. if ( error )
  424. goto Exit;
  425. }
  426. error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 );
  427. }
  428. }
  429. Exit:
  430. return error;
  431. }
  432. /* END */