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