]>
Commit | Line | Data |
---|---|---|
1 | /***************************************************************************/ | |
2 | /* */ | |
3 | /* ttgload.c */ | |
4 | /* */ | |
5 | /* TrueType Glyph Loader (body). */ | |
6 | /* */ | |
7 | /* Copyright 1996-2000 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 <freetype/internal/ftdebug.h> | |
20 | #include <freetype/internal/ftcalc.h> | |
21 | #include <freetype/internal/ftstream.h> | |
22 | #include <freetype/internal/sfnt.h> | |
23 | #include <freetype/tttags.h> | |
24 | #include <freetype/ftoutln.h> | |
25 | ||
26 | ||
27 | #ifdef FT_FLAT_COMPILE | |
28 | ||
29 | #include "ttgload.h" | |
30 | ||
31 | #else | |
32 | ||
33 | #include <truetype/ttgload.h> | |
34 | ||
35 | #endif | |
36 | ||
37 | ||
38 | /*************************************************************************/ | |
39 | /* */ | |
40 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
41 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
42 | /* messages during execution. */ | |
43 | /* */ | |
44 | #undef FT_COMPONENT | |
45 | #define FT_COMPONENT trace_ttgload | |
46 | ||
47 | ||
48 | /*************************************************************************/ | |
49 | /* */ | |
50 | /* Composite font flags. */ | |
51 | /* */ | |
52 | #define ARGS_ARE_WORDS 0x001 | |
53 | #define ARGS_ARE_XY_VALUES 0x002 | |
54 | #define ROUND_XY_TO_GRID 0x004 | |
55 | #define WE_HAVE_A_SCALE 0x008 | |
56 | /* reserved 0x010 */ | |
57 | #define MORE_COMPONENTS 0x020 | |
58 | #define WE_HAVE_AN_XY_SCALE 0x040 | |
59 | #define WE_HAVE_A_2X2 0x080 | |
60 | #define WE_HAVE_INSTR 0x100 | |
61 | #define USE_MY_METRICS 0x200 | |
62 | ||
63 | ||
64 | ||
65 | /*************************************************************************/ | |
66 | /* */ | |
67 | /* <Function> */ | |
68 | /* TT_Get_Metrics */ | |
69 | /* */ | |
70 | /* <Description> */ | |
71 | /* Returns the horizontal or vertical metrics in font units for a */ | |
72 | /* given glyph. The metrics are the left side bearing (resp. top */ | |
73 | /* side bearing) and advance width (resp. advance height). */ | |
74 | /* */ | |
75 | /* <Input> */ | |
76 | /* header :: A pointer to either the horizontal or vertical metrics */ | |
77 | /* structure. */ | |
78 | /* */ | |
79 | /* index :: The glyph index. */ | |
80 | /* */ | |
81 | /* <Output> */ | |
82 | /* bearing :: The bearing, either left side or top side. */ | |
83 | /* */ | |
84 | /* advance :: The advance width resp. advance height. */ | |
85 | /* */ | |
86 | /* <Note> */ | |
87 | /* This function will much probably move to another component in the */ | |
88 | /* near future, but I haven't decided which yet. */ | |
89 | /* */ | |
90 | LOCAL_FUNC | |
91 | void TT_Get_Metrics( TT_HoriHeader* header, | |
92 | FT_UInt index, | |
93 | FT_Short* bearing, | |
94 | FT_UShort* advance ) | |
95 | { | |
96 | TT_LongMetrics* longs_m; | |
97 | FT_UShort k = header->number_Of_HMetrics; | |
98 | ||
99 | ||
100 | if ( index < k ) | |
101 | { | |
102 | longs_m = (TT_LongMetrics*)header->long_metrics + index; | |
103 | *bearing = longs_m->bearing; | |
104 | *advance = longs_m->advance; | |
105 | } | |
106 | else | |
107 | { | |
108 | *bearing = ((TT_ShortMetrics*)header->short_metrics)[index - k]; | |
109 | *advance = ((TT_LongMetrics*)header->long_metrics)[k - 1].advance; | |
110 | } | |
111 | } | |
112 | ||
113 | ||
114 | /*************************************************************************/ | |
115 | /* */ | |
116 | /* Returns the horizontal metrics in font units for a given glyph. If */ | |
117 | /* `check' is true, take care of monospaced fonts by returning the */ | |
118 | /* advance width maximum. */ | |
119 | /* */ | |
120 | static | |
121 | void Get_HMetrics( TT_Face face, | |
122 | FT_UInt index, | |
123 | FT_Bool check, | |
124 | FT_Short* lsb, | |
125 | FT_UShort* aw ) | |
126 | { | |
127 | TT_Get_Metrics( &face->horizontal, index, lsb, aw ); | |
128 | ||
129 | if ( check && face->postscript.isFixedPitch ) | |
130 | *aw = face->horizontal.advance_Width_Max; | |
131 | } | |
132 | ||
133 | ||
134 | /*************************************************************************/ | |
135 | /* */ | |
136 | /* Returns the advance width table for a given pixel size if it is */ | |
137 | /* found in the font's `hdmx' table (if any). */ | |
138 | /* */ | |
139 | static | |
140 | FT_Byte* Get_Advance_Widths( TT_Face face, | |
141 | FT_UShort ppem ) | |
142 | { | |
143 | FT_UShort n; | |
144 | ||
145 | for ( n = 0; n < face->hdmx.num_records; n++ ) | |
146 | if ( face->hdmx.records[n].ppem == ppem ) | |
147 | return face->hdmx.records[n].widths; | |
148 | ||
149 | return NULL; | |
150 | } | |
151 | ||
152 | ||
153 | #define cur_to_org( n, zone ) \ | |
154 | MEM_Copy( (zone)->org, (zone)->cur, n * sizeof ( FT_Vector ) ) | |
155 | ||
156 | #define org_to_cur( n, zone ) \ | |
157 | MEM_Copy( (zone)->cur, (zone)->org, n * sizeof ( FT_Vector ) ) | |
158 | ||
159 | ||
160 | /*************************************************************************/ | |
161 | /* */ | |
162 | /* Translates an array of coordinates. */ | |
163 | /* */ | |
164 | static | |
165 | void translate_array( FT_UInt n, | |
166 | FT_Vector* coords, | |
167 | FT_Pos delta_x, | |
168 | FT_Pos delta_y ) | |
169 | { | |
170 | FT_UInt k; | |
171 | ||
172 | ||
173 | if ( delta_x ) | |
174 | for ( k = 0; k < n; k++ ) | |
175 | coords[k].x += delta_x; | |
176 | ||
177 | if ( delta_y ) | |
178 | for ( k = 0; k < n; k++ ) | |
179 | coords[k].y += delta_y; | |
180 | } | |
181 | ||
182 | ||
183 | static | |
184 | void tt_prepare_zone( TT_GlyphZone* zone, | |
185 | FT_GlyphLoad* load, | |
186 | FT_UInt start_point, | |
187 | FT_UInt start_contour ) | |
188 | { | |
189 | zone->n_points = load->outline.n_points - start_point; | |
190 | zone->n_contours = load->outline.n_contours - start_contour; | |
191 | zone->org = load->extra_points + start_point; | |
192 | zone->cur = load->outline.points + start_point; | |
193 | zone->tags = (FT_Byte*)load->outline.tags + start_point; | |
194 | zone->contours = (FT_UShort*)load->outline.contours + start_contour; | |
195 | } | |
196 | ||
197 | ||
198 | #undef IS_HINTED | |
199 | #define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 ) | |
200 | ||
201 | ||
202 | /*************************************************************************/ | |
203 | /* */ | |
204 | /* The following functions are used by default with TrueType fonts. */ | |
205 | /* However, they can be replaced by alternatives if we need to support */ | |
206 | /* TrueType-compressed formats (like MicroType) in the future. */ | |
207 | /* */ | |
208 | /*************************************************************************/ | |
209 | ||
210 | static | |
211 | FT_Error TT_Access_Glyph_Frame( TT_Loader* loader, | |
212 | FT_UInt glyph_index, | |
213 | FT_ULong offset, | |
214 | FT_UInt byte_count ) | |
215 | { | |
216 | FT_Error error; | |
217 | FT_Stream stream = loader->stream; | |
218 | ||
219 | ||
220 | /* the following line sets the `error' variable through macros! */ | |
221 | (void)( FILE_Seek( offset ) || ACCESS_Frame( byte_count ) ); | |
222 | ||
223 | FT_TRACE5(( "Glyph %ld\n", glyph_index )); | |
224 | return error; | |
225 | } | |
226 | ||
227 | ||
228 | static | |
229 | void TT_Forget_Glyph_Frame( TT_Loader* loader ) | |
230 | { | |
231 | FT_Stream stream = loader->stream; | |
232 | ||
233 | ||
234 | FORGET_Frame(); | |
235 | } | |
236 | ||
237 | ||
238 | static | |
239 | FT_Error TT_Load_Glyph_Header( TT_Loader* loader ) | |
240 | { | |
241 | FT_Stream stream = loader->stream; | |
242 | ||
243 | ||
244 | loader->n_contours = GET_Short(); | |
245 | ||
246 | loader->bbox.xMin = GET_Short(); | |
247 | loader->bbox.yMin = GET_Short(); | |
248 | loader->bbox.xMax = GET_Short(); | |
249 | loader->bbox.yMax = GET_Short(); | |
250 | ||
251 | FT_TRACE5(( " # of contours: %d\n", loader->n_contours )); | |
252 | FT_TRACE5(( " xMin: %4d xMax: %4d\n", loader->bbox.xMin, | |
253 | loader->bbox.xMax )); | |
254 | FT_TRACE5(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin, | |
255 | loader->bbox.yMax )); | |
256 | ||
257 | return FT_Err_Ok; | |
258 | } | |
259 | ||
260 | ||
261 | static | |
262 | FT_Error TT_Load_Simple_Glyph( TT_Loader* load ) | |
263 | { | |
264 | FT_Error error; | |
265 | FT_Stream stream = load->stream; | |
266 | FT_GlyphLoader* gloader = load->gloader; | |
267 | FT_Int n_contours = load->n_contours; | |
268 | FT_Outline* outline; | |
269 | TT_Face face = (TT_Face)load->face; | |
270 | TT_GlyphSlot slot = (TT_GlyphSlot)load->glyph; | |
271 | FT_UShort n_ins; | |
272 | FT_Int n, n_points; | |
273 | ||
274 | ||
275 | /* reading the contours endpoints & number of points */ | |
276 | { | |
277 | short* cur = gloader->current.outline.contours; | |
278 | short* limit = cur + n_contours; | |
279 | ||
280 | ||
281 | for ( ; cur < limit; cur++ ) | |
282 | cur[0] = GET_UShort(); | |
283 | ||
284 | n_points = 0; | |
285 | if ( n_contours > 0 ) | |
286 | n_points = cur[-1] + 1; | |
287 | ||
288 | error = FT_GlyphLoader_Check_Points( gloader, n_points + 2, 0 ); | |
289 | if ( error ) | |
290 | goto Fail; | |
291 | ||
292 | outline = &gloader->current.outline; | |
293 | } | |
294 | ||
295 | /* reading the bytecode instructions */ | |
296 | slot->control_len = 0; | |
297 | slot->control_data = 0; | |
298 | ||
299 | n_ins = GET_UShort(); | |
300 | ||
301 | FT_TRACE5(( " Instructions size: %d\n", n_ins )); | |
302 | ||
303 | if ( n_ins > face->max_profile.maxSizeOfInstructions ) | |
304 | { | |
305 | FT_TRACE0(( "ERROR: Too many instructions!\n" )); | |
306 | error = TT_Err_Too_Many_Ins; | |
307 | goto Fail; | |
308 | } | |
309 | ||
310 | if ( stream->cursor + n_ins > stream->limit ) | |
311 | { | |
312 | FT_TRACE0(( "ERROR: Instruction count mismatch!\n" )); | |
313 | error = TT_Err_Too_Many_Ins; | |
314 | goto Fail; | |
315 | } | |
316 | ||
317 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
318 | ||
319 | if ( ( load->load_flags & | |
320 | ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ) == 0 && | |
321 | load->instructions ) | |
322 | { | |
323 | slot->control_len = n_ins; | |
324 | slot->control_data = load->instructions; | |
325 | ||
326 | MEM_Copy( load->instructions, stream->cursor, n_ins ); | |
327 | } | |
328 | ||
329 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ | |
330 | ||
331 | stream->cursor += n_ins; | |
332 | ||
333 | /* reading the point tags */ | |
334 | ||
335 | { | |
336 | FT_Byte* flag = (FT_Byte*)outline->tags; | |
337 | FT_Byte* limit = flag + n_points; | |
338 | FT_Byte c, count; | |
339 | ||
340 | ||
341 | for ( ; flag < limit; flag++ ) | |
342 | { | |
343 | *flag = c = GET_Byte(); | |
344 | if ( c & 8 ) | |
345 | { | |
346 | for ( count = GET_Byte(); count > 0; count-- ) | |
347 | *++flag = c; | |
348 | } | |
349 | } | |
350 | } | |
351 | ||
352 | /* reading the X coordinates */ | |
353 | ||
354 | { | |
355 | FT_Vector* vec = outline->points; | |
356 | FT_Vector* limit = vec + n_points; | |
357 | FT_Byte* flag = (FT_Byte*)outline->tags; | |
358 | FT_Pos x = 0; | |
359 | ||
360 | ||
361 | for ( ; vec < limit; vec++, flag++ ) | |
362 | { | |
363 | FT_Pos y = 0; | |
364 | ||
365 | ||
366 | if ( *flag & 2 ) | |
367 | { | |
368 | y = GET_Byte(); | |
369 | if ( ( *flag & 16 ) == 0 ) | |
370 | y = -y; | |
371 | } | |
372 | else if ( ( *flag & 16 ) == 0 ) | |
373 | y = GET_Short(); | |
374 | ||
375 | x += y; | |
376 | vec->x = x; | |
377 | } | |
378 | } | |
379 | ||
380 | /* reading the Y coordinates */ | |
381 | ||
382 | { | |
383 | FT_Vector* vec = gloader->current.outline.points; | |
384 | FT_Vector* limit = vec + n_points; | |
385 | FT_Byte* flag = (FT_Byte*)outline->tags; | |
386 | FT_Pos x = 0; | |
387 | ||
388 | ||
389 | for ( ; vec < limit; vec++, flag++ ) | |
390 | { | |
391 | FT_Pos y = 0; | |
392 | ||
393 | ||
394 | if ( *flag & 4 ) | |
395 | { | |
396 | y = GET_Byte(); | |
397 | if ( ( *flag & 32 ) == 0 ) | |
398 | y = -y; | |
399 | } | |
400 | else if ( ( *flag & 32 ) == 0 ) | |
401 | y = GET_Short(); | |
402 | ||
403 | x += y; | |
404 | vec->y = x; | |
405 | } | |
406 | } | |
407 | ||
408 | /* clear the touch tags */ | |
409 | for ( n = 0; n < n_points; n++ ) | |
410 | outline->tags[n] &= FT_Curve_Tag_On; | |
411 | ||
412 | outline->n_points = n_points; | |
413 | outline->n_contours = n_contours; | |
414 | ||
415 | Fail: | |
416 | return error; | |
417 | } | |
418 | ||
419 | ||
420 | static | |
421 | FT_Error TT_Load_Composite_Glyph( TT_Loader* loader ) | |
422 | { | |
423 | FT_Error error; | |
424 | FT_Stream stream = loader->stream; | |
425 | FT_GlyphLoader* gloader = loader->gloader; | |
426 | FT_SubGlyph* subglyph; | |
427 | FT_UInt num_subglyphs; | |
428 | ||
429 | ||
430 | num_subglyphs = 0; | |
431 | ||
432 | do | |
433 | { | |
434 | FT_Fixed xx, xy, yy, yx; | |
435 | ||
436 | ||
437 | /* check that we can load a new subglyph */ | |
438 | error = FT_GlyphLoader_Check_Subglyphs( gloader, num_subglyphs + 1 ); | |
439 | if ( error ) | |
440 | goto Fail; | |
441 | ||
442 | subglyph = gloader->current.subglyphs + num_subglyphs; | |
443 | ||
444 | subglyph->arg1 = subglyph->arg2 = 0; | |
445 | ||
446 | subglyph->flags = GET_UShort(); | |
447 | subglyph->index = GET_UShort(); | |
448 | ||
449 | /* read arguments */ | |
450 | if ( subglyph->flags & ARGS_ARE_WORDS ) | |
451 | { | |
452 | subglyph->arg1 = GET_Short(); | |
453 | subglyph->arg2 = GET_Short(); | |
454 | } | |
455 | else | |
456 | { | |
457 | subglyph->arg1 = GET_Char(); | |
458 | subglyph->arg2 = GET_Char(); | |
459 | } | |
460 | ||
461 | /* read transform */ | |
462 | xx = yy = 0x10000L; | |
463 | xy = yx = 0; | |
464 | ||
465 | if ( subglyph->flags & WE_HAVE_A_SCALE ) | |
466 | { | |
467 | xx = (FT_Fixed)GET_Short() << 2; | |
468 | yy = xx; | |
469 | } | |
470 | else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) | |
471 | { | |
472 | xx = (FT_Fixed)GET_Short() << 2; | |
473 | yy = (FT_Fixed)GET_Short() << 2; | |
474 | } | |
475 | else if ( subglyph->flags & WE_HAVE_A_2X2 ) | |
476 | { | |
477 | xx = (FT_Fixed)GET_Short() << 2; | |
478 | xy = (FT_Fixed)GET_Short() << 2; | |
479 | yx = (FT_Fixed)GET_Short() << 2; | |
480 | yy = (FT_Fixed)GET_Short() << 2; | |
481 | } | |
482 | ||
483 | subglyph->transform.xx = xx; | |
484 | subglyph->transform.xy = xy; | |
485 | subglyph->transform.yx = yx; | |
486 | subglyph->transform.yy = yy; | |
487 | ||
488 | num_subglyphs++; | |
489 | ||
490 | } while ( subglyph->flags & MORE_COMPONENTS ); | |
491 | ||
492 | gloader->current.num_subglyphs = num_subglyphs; | |
493 | ||
494 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
495 | { | |
496 | /* we must undo the ACCESS_Frame in order to point to the */ | |
497 | /* composite instructions, if we find some. */ | |
498 | /* we will process them later... */ | |
499 | /* */ | |
500 | loader->ins_pos = FILE_Pos() + stream->cursor - stream->limit; | |
501 | } | |
502 | #endif | |
503 | ||
504 | Fail: | |
505 | return error; | |
506 | } | |
507 | ||
508 | ||
509 | LOCAL_FUNC | |
510 | void TT_Init_Glyph_Loading( TT_Face face ) | |
511 | { | |
512 | face->access_glyph_frame = TT_Access_Glyph_Frame; | |
513 | face->read_glyph_header = TT_Load_Glyph_Header; | |
514 | face->read_simple_glyph = TT_Load_Simple_Glyph; | |
515 | face->read_composite_glyph = TT_Load_Composite_Glyph; | |
516 | face->forget_glyph_frame = TT_Forget_Glyph_Frame; | |
517 | } | |
518 | ||
519 | ||
520 | /*************************************************************************/ | |
521 | /* */ | |
522 | /* <Function> */ | |
523 | /* TT_Process_Simple_Glyph */ | |
524 | /* */ | |
525 | /* <Description> */ | |
526 | /* Once a simple glyph has been loaded, it needs to be processed. */ | |
527 | /* Usually, this means scaling and hinting through bytecode */ | |
528 | /* interpretation. */ | |
529 | /* */ | |
530 | static | |
531 | FT_Error TT_Process_Simple_Glyph( TT_Loader* load, | |
532 | FT_Bool debug ) | |
533 | { | |
534 | FT_GlyphLoader* gloader = load->gloader; | |
535 | FT_Outline* outline = &gloader->current.outline; | |
536 | FT_UInt n_points = outline->n_points; | |
537 | FT_UInt n_ins; | |
538 | TT_GlyphZone* zone = &load->zone; | |
539 | FT_Error error = FT_Err_Ok; | |
540 | ||
541 | ||
542 | n_ins = load->glyph->control_len; | |
543 | ||
544 | /* add shadow points */ | |
545 | ||
546 | /* Now add the two shadow points at n and n + 1. */ | |
547 | /* We need the left side bearing and advance width. */ | |
548 | ||
549 | { | |
550 | FT_Vector* pp1; | |
551 | FT_Vector* pp2; | |
552 | ||
553 | ||
554 | /* pp1 = xMin - lsb */ | |
555 | pp1 = outline->points + n_points; | |
556 | pp1->x = load->bbox.xMin - load->left_bearing; | |
557 | pp1->y = 0; | |
558 | ||
559 | /* pp2 = pp1 + aw */ | |
560 | pp2 = pp1 + 1; | |
561 | pp2->x = pp1->x + load->advance; | |
562 | pp2->y = 0; | |
563 | ||
564 | outline->tags[n_points ] = 0; | |
565 | outline->tags[n_points + 1] = 0; | |
566 | } | |
567 | ||
568 | /* Note that we return two more points that are not */ | |
569 | /* part of the glyph outline. */ | |
570 | ||
571 | n_points += 2; | |
572 | ||
573 | /* set up zone for hinting */ | |
574 | tt_prepare_zone( zone, &gloader->current, 0, 0 ); | |
575 | ||
576 | /* eventually scale the glyph */ | |
577 | if ( !( load->load_flags & FT_LOAD_NO_SCALE ) ) | |
578 | { | |
579 | FT_Vector* vec = zone->cur; | |
580 | FT_Vector* limit = vec + n_points; | |
581 | FT_Fixed x_scale = load->size->metrics.x_scale; | |
582 | FT_Fixed y_scale = load->size->metrics.y_scale; | |
583 | ||
584 | ||
585 | /* first scale the glyph points */ | |
586 | for ( ; vec < limit; vec++ ) | |
587 | { | |
588 | vec->x = FT_MulFix( vec->x, x_scale ); | |
589 | vec->y = FT_MulFix( vec->y, y_scale ); | |
590 | } | |
591 | } | |
592 | ||
593 | cur_to_org( n_points, zone ); | |
594 | ||
595 | /* eventually hint the glyph */ | |
596 | if ( IS_HINTED( load->load_flags ) ) | |
597 | { | |
598 | FT_Pos x = zone->org[n_points-2].x; | |
599 | ||
600 | ||
601 | x = ( ( x + 32 ) & -64 ) - x; | |
602 | translate_array( n_points, zone->org, x, 0 ); | |
603 | ||
604 | org_to_cur( n_points, zone ); | |
605 | ||
606 | zone->cur[n_points - 1].x = ( zone->cur[n_points - 1].x + 32 ) & -64; | |
607 | ||
608 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
609 | ||
610 | /* now consider hinting */ | |
611 | if ( n_ins > 0 ) | |
612 | { | |
613 | error = TT_Set_CodeRange( load->exec, tt_coderange_glyph, | |
614 | load->exec->glyphIns, n_ins ); | |
615 | if ( error ) | |
616 | goto Exit; | |
617 | ||
618 | load->exec->is_composite = FALSE; | |
619 | load->exec->pedantic_hinting = (FT_Bool)( load->load_flags & | |
620 | FT_LOAD_PEDANTIC ); | |
621 | load->exec->pts = *zone; | |
622 | load->exec->pts.n_points += 2; | |
623 | ||
624 | error = TT_Run_Context( load->exec, debug ); | |
625 | if ( error && load->exec->pedantic_hinting ) | |
626 | goto Exit; | |
627 | ||
628 | error = FT_Err_Ok; /* ignore bytecode errors in non-pedantic mode */ | |
629 | } | |
630 | ||
631 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ | |
632 | ||
633 | } | |
634 | ||
635 | /* save glyph phantom points */ | |
636 | if ( !load->preserve_pps ) | |
637 | { | |
638 | load->pp1 = zone->cur[n_points - 2]; | |
639 | load->pp2 = zone->cur[n_points - 1]; | |
640 | } | |
641 | ||
642 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
643 | Exit: | |
644 | #endif | |
645 | return error; | |
646 | } | |
647 | ||
648 | ||
649 | /*************************************************************************/ | |
650 | /* */ | |
651 | /* <Function> */ | |
652 | /* load_truetype_glyph */ | |
653 | /* */ | |
654 | /* <Description> */ | |
655 | /* Loads a given truetype glyph. Handles composites and uses a */ | |
656 | /* TT_Loader object. */ | |
657 | /* */ | |
658 | static | |
659 | FT_Error load_truetype_glyph( TT_Loader* loader, | |
660 | FT_UInt glyph_index ) | |
661 | { | |
662 | FT_Stream stream = loader->stream; | |
663 | FT_Error error; | |
664 | TT_Face face = (TT_Face)loader->face; | |
665 | FT_ULong offset; | |
666 | FT_Int contours_count; | |
667 | FT_UInt index, num_points, num_contours, count; | |
668 | FT_Fixed x_scale, y_scale; | |
669 | FT_ULong ins_offset; | |
670 | FT_GlyphLoader* gloader = loader->gloader; | |
671 | FT_Bool opened_frame = 0; | |
672 | ||
673 | ||
674 | /* check glyph index */ | |
675 | index = glyph_index; | |
676 | if ( index >= (FT_UInt)face->root.num_glyphs ) | |
677 | { | |
678 | error = TT_Err_Invalid_Glyph_Index; | |
679 | goto Exit; | |
680 | } | |
681 | ||
682 | loader->glyph_index = glyph_index; | |
683 | num_contours = 0; | |
684 | num_points = 0; | |
685 | ins_offset = 0; | |
686 | ||
687 | x_scale = 0x10000L; | |
688 | y_scale = 0x10000L; | |
689 | if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) | |
690 | { | |
691 | x_scale = loader->size->metrics.x_scale; | |
692 | y_scale = loader->size->metrics.y_scale; | |
693 | } | |
694 | ||
695 | /* get horizontal metrics */ | |
696 | { | |
697 | FT_Short left_bearing; | |
698 | FT_UShort advance_width; | |
699 | ||
700 | ||
701 | Get_HMetrics( face, index, | |
702 | (FT_Bool)!(loader->load_flags & | |
703 | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH), | |
704 | &left_bearing, | |
705 | &advance_width ); | |
706 | ||
707 | loader->left_bearing = left_bearing; | |
708 | loader->advance = advance_width; | |
709 | } | |
710 | ||
711 | offset = face->glyph_locations[index]; | |
712 | count = 0; | |
713 | ||
714 | if ( index < (FT_UInt)face->num_locations - 1 ) | |
715 | count = face->glyph_locations[index + 1] - offset; | |
716 | ||
717 | if ( count == 0 ) | |
718 | { | |
719 | /* as described by Frederic Loyer, these are spaces, and */ | |
720 | /* not the unknown glyph. */ | |
721 | loader->bbox.xMin = 0; | |
722 | loader->bbox.xMax = 0; | |
723 | loader->bbox.yMin = 0; | |
724 | loader->bbox.yMax = 0; | |
725 | ||
726 | loader->pp1.x = 0; | |
727 | loader->pp2.x = loader->advance; | |
728 | ||
729 | if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) | |
730 | loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); | |
731 | ||
732 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
733 | ||
734 | if ( loader->exec ) | |
735 | loader->exec->glyphSize = 0; | |
736 | ||
737 | #endif | |
738 | ||
739 | error = FT_Err_Ok; | |
740 | goto Exit; | |
741 | } | |
742 | ||
743 | offset = loader->glyf_offset + offset; | |
744 | ||
745 | /* access glyph frame */ | |
746 | error = face->access_glyph_frame( loader, glyph_index, offset, count ); | |
747 | if ( error ) | |
748 | goto Exit; | |
749 | ||
750 | opened_frame = 1; | |
751 | ||
752 | /* read first glyph header */ | |
753 | error = face->read_glyph_header( loader ); | |
754 | if ( error ) | |
755 | goto Fail; | |
756 | ||
757 | contours_count = loader->n_contours; | |
758 | ||
759 | count -= 10; | |
760 | ||
761 | loader->pp1.x = loader->bbox.xMin - loader->left_bearing; | |
762 | loader->pp1.y = 0; | |
763 | loader->pp2.x = loader->pp1.x + loader->advance; | |
764 | loader->pp2.y = 0; | |
765 | ||
766 | if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) | |
767 | { | |
768 | loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); | |
769 | loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); | |
770 | } | |
771 | ||
772 | /***********************************************************************/ | |
773 | /***********************************************************************/ | |
774 | /***********************************************************************/ | |
775 | ||
776 | /* if it is a simple glyph, load it */ | |
777 | ||
778 | if ( contours_count >= 0 ) | |
779 | { | |
780 | /* check that we can add the contours to the glyph */ | |
781 | error = FT_GlyphLoader_Check_Points( gloader, 0, contours_count ); | |
782 | if ( error ) | |
783 | goto Fail; | |
784 | ||
785 | error = face->read_simple_glyph( loader ); | |
786 | if ( error ) | |
787 | goto Fail; | |
788 | ||
789 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
790 | ||
791 | { | |
792 | TT_Size size = (TT_Size)loader->size; | |
793 | ||
794 | ||
795 | error = TT_Process_Simple_Glyph( loader, | |
796 | (FT_Bool)( size && size->debug ) ); | |
797 | } | |
798 | ||
799 | #else | |
800 | ||
801 | error = TT_Process_Simple_Glyph( loader, 0 ); | |
802 | ||
803 | #endif | |
804 | ||
805 | if ( error ) | |
806 | goto Fail; | |
807 | ||
808 | FT_GlyphLoader_Add( gloader ); | |
809 | ||
810 | /* Note: We could have put the simple loader source there */ | |
811 | /* but the code is fat enough already :-) */ | |
812 | } | |
813 | ||
814 | /***********************************************************************/ | |
815 | /***********************************************************************/ | |
816 | /***********************************************************************/ | |
817 | ||
818 | /* otherwise, load a composite! */ | |
819 | else | |
820 | { | |
821 | TT_GlyphSlot glyph = (TT_GlyphSlot)loader->glyph; | |
822 | FT_UInt start_point, start_contour; | |
823 | FT_ULong ins_pos; /* position of composite instructions, if any */ | |
824 | ||
825 | ||
826 | /* for each subglyph, read composite header */ | |
827 | start_point = gloader->base.outline.n_points; | |
828 | start_contour = gloader->base.outline.n_contours; | |
829 | ||
830 | error = face->read_composite_glyph( loader ); | |
831 | if ( error ) | |
832 | goto Fail; | |
833 | ||
834 | ins_pos = loader->ins_pos; | |
835 | face->forget_glyph_frame( loader ); | |
836 | opened_frame = 0; | |
837 | ||
838 | /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */ | |
839 | /* `as is' in the glyph slot (the client application will be */ | |
840 | /* responsible for interpreting this data)... */ | |
841 | /* */ | |
842 | if ( loader->load_flags & FT_LOAD_NO_RECURSE ) | |
843 | { | |
844 | /* set up remaining glyph fields */ | |
845 | FT_GlyphLoader_Add( gloader ); | |
846 | ||
847 | glyph->num_subglyphs = gloader->base.num_subglyphs; | |
848 | glyph->format = ft_glyph_format_composite; | |
849 | glyph->subglyphs = gloader->base.subglyphs; | |
850 | ||
851 | goto Exit; | |
852 | } | |
853 | ||
854 | /*********************************************************************/ | |
855 | /*********************************************************************/ | |
856 | /*********************************************************************/ | |
857 | ||
858 | /* Now, read each subglyph independently. */ | |
859 | { | |
860 | FT_Int n, num_base_points, num_new_points; | |
861 | FT_SubGlyph* subglyph = 0; | |
862 | ||
863 | FT_UInt num_subglyphs = gloader->current.num_subglyphs; | |
864 | FT_UInt num_base_subgs = gloader->base.num_subglyphs; | |
865 | ||
866 | ||
867 | FT_GlyphLoader_Add( gloader ); | |
868 | ||
869 | for ( n = 0; n < (FT_Int)num_subglyphs; n++ ) | |
870 | { | |
871 | FT_Vector pp1, pp2; | |
872 | FT_Pos x, y; | |
873 | ||
874 | ||
875 | /* Each time we call load_truetype_glyph in this loop, the */ | |
876 | /* value of `gloader.base.subglyphs' can change due to table */ | |
877 | /* reallocations. We thus need to recompute the subglyph */ | |
878 | /* pointer on each iteration. */ | |
879 | subglyph = gloader->base.subglyphs + num_base_subgs + n; | |
880 | ||
881 | pp1 = loader->pp1; | |
882 | pp2 = loader->pp2; | |
883 | ||
884 | num_base_points = gloader->base.outline.n_points; | |
885 | ||
886 | error = load_truetype_glyph( loader, subglyph->index ); | |
887 | if ( error ) | |
888 | goto Fail; | |
889 | ||
890 | subglyph = gloader->base.subglyphs + num_base_subgs + n; | |
891 | ||
892 | if ( subglyph->flags & USE_MY_METRICS ) | |
893 | { | |
894 | pp1 = loader->pp1; | |
895 | pp2 = loader->pp2; | |
896 | } | |
897 | else | |
898 | { | |
899 | loader->pp1 = pp1; | |
900 | loader->pp2 = pp2; | |
901 | } | |
902 | ||
903 | num_points = gloader->base.outline.n_points; | |
904 | ||
905 | num_new_points = num_points - num_base_points; | |
906 | ||
907 | /* now perform the transform required for this subglyph */ | |
908 | ||
909 | if ( subglyph->flags & ( WE_HAVE_A_SCALE | | |
910 | WE_HAVE_AN_XY_SCALE | | |
911 | WE_HAVE_A_2X2 ) ) | |
912 | { | |
913 | FT_Vector* cur = gloader->base.outline.points + | |
914 | num_base_points; | |
915 | FT_Vector* org = gloader->base.extra_points + | |
916 | num_base_points; | |
917 | FT_Vector* limit = cur + num_new_points; | |
918 | ||
919 | ||
920 | for ( ; cur < limit; cur++, org++ ) | |
921 | { | |
922 | FT_Vector_Transform( cur, &subglyph->transform ); | |
923 | FT_Vector_Transform( org, &subglyph->transform ); | |
924 | } | |
925 | } | |
926 | ||
927 | /* apply offset */ | |
928 | ||
929 | if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) ) | |
930 | { | |
931 | FT_UInt k = subglyph->arg1; | |
932 | FT_UInt l = subglyph->arg2; | |
933 | FT_Vector* p1; | |
934 | FT_Vector* p2; | |
935 | ||
936 | ||
937 | if ( start_point + k >= (FT_UInt)num_base_points || | |
938 | l >= (FT_UInt)num_new_points ) | |
939 | { | |
940 | error = TT_Err_Invalid_Composite; | |
941 | goto Fail; | |
942 | } | |
943 | ||
944 | l += num_base_points; | |
945 | ||
946 | p1 = gloader->base.outline.points + start_point + k; | |
947 | p2 = gloader->base.outline.points + start_point + l; | |
948 | ||
949 | x = p1->x - p2->x; | |
950 | y = p1->y - p2->y; | |
951 | } | |
952 | else | |
953 | { | |
954 | x = subglyph->arg1; | |
955 | y = subglyph->arg2; | |
956 | ||
957 | if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) | |
958 | { | |
959 | x = FT_MulFix( x, x_scale ); | |
960 | y = FT_MulFix( y, y_scale ); | |
961 | ||
962 | if ( subglyph->flags & ROUND_XY_TO_GRID ) | |
963 | { | |
964 | x = ( x + 32 ) & -64; | |
965 | y = ( y + 32 ) & -64; | |
966 | } | |
967 | } | |
968 | } | |
969 | ||
970 | translate_array( num_new_points, loader->zone.cur, x, y ); | |
971 | cur_to_org( num_new_points, &loader->zone ); | |
972 | } | |
973 | ||
974 | /*******************************************************************/ | |
975 | /*******************************************************************/ | |
976 | /*******************************************************************/ | |
977 | ||
978 | /* we have finished loading all sub-glyphs; now, look for */ | |
979 | /* instructions for this composite! */ | |
980 | ||
981 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
982 | ||
983 | if ( num_subglyphs > 0 && | |
984 | loader->exec && | |
985 | ins_pos > 0 && | |
986 | subglyph->flags & WE_HAVE_INSTR ) | |
987 | { | |
988 | FT_UShort n_ins; | |
989 | TT_ExecContext exec = loader->exec; | |
990 | TT_GlyphZone* pts; | |
991 | FT_Vector* pp1; | |
992 | ||
993 | ||
994 | /* read size of instructions */ | |
995 | if ( FILE_Seek( ins_pos ) || | |
996 | READ_UShort( n_ins ) ) | |
997 | goto Fail; | |
998 | FT_TRACE5(( " Instructions size = %d\n", n_ins )); | |
999 | ||
1000 | /* in some fonts? */ | |
1001 | if ( n_ins == 0xFFFF ) | |
1002 | n_ins = 0; | |
1003 | ||
1004 | /* check it */ | |
1005 | if ( n_ins > face->max_profile.maxSizeOfInstructions ) | |
1006 | { | |
1007 | FT_TRACE0(( "Too many instructions (%d) in composite glyph %ld\n", | |
1008 | n_ins, subglyph->index )); | |
1009 | return TT_Err_Too_Many_Ins; | |
1010 | } | |
1011 | ||
1012 | /* read the instructions */ | |
1013 | if ( FILE_Read( exec->glyphIns, n_ins ) ) | |
1014 | goto Fail; | |
1015 | ||
1016 | glyph->control_data = exec->glyphIns; | |
1017 | glyph->control_len = n_ins; | |
1018 | ||
1019 | error = TT_Set_CodeRange( exec, | |
1020 | tt_coderange_glyph, | |
1021 | exec->glyphIns, | |
1022 | n_ins ); | |
1023 | if ( error ) | |
1024 | goto Fail; | |
1025 | ||
1026 | /* prepare the execution context */ | |
1027 | tt_prepare_zone( &exec->pts, &gloader->base, | |
1028 | start_point, start_contour ); | |
1029 | pts = &exec->pts; | |
1030 | ||
1031 | pts->n_points = num_points + 2; | |
1032 | pts->n_contours = gloader->base.outline.n_contours; | |
1033 | ||
1034 | /* add phantom points */ | |
1035 | pp1 = pts->cur + num_points; | |
1036 | pp1[0] = loader->pp1; | |
1037 | pp1[1] = loader->pp2; | |
1038 | ||
1039 | pts->tags[num_points ] = 0; | |
1040 | pts->tags[num_points + 1] = 0; | |
1041 | ||
1042 | /* if hinting, round the phantom points */ | |
1043 | if ( IS_HINTED( loader->load_flags ) ) | |
1044 | { | |
1045 | pp1[0].x = ( ( loader->pp1.x + 32 ) & -64 ); | |
1046 | pp1[1].x = ( ( loader->pp2.x + 32 ) & -64 ); | |
1047 | } | |
1048 | ||
1049 | { | |
1050 | FT_UInt k; | |
1051 | ||
1052 | ||
1053 | for ( k = 0; k < num_points; k++ ) | |
1054 | pts->tags[k] &= FT_Curve_Tag_On; | |
1055 | } | |
1056 | ||
1057 | cur_to_org( num_points + 2, pts ); | |
1058 | ||
1059 | /* now consider hinting */ | |
1060 | if ( IS_HINTED( loader->load_flags ) && n_ins > 0 ) | |
1061 | { | |
1062 | exec->is_composite = TRUE; | |
1063 | exec->pedantic_hinting = | |
1064 | (FT_Bool)( loader->load_flags & FT_LOAD_PEDANTIC ); | |
1065 | ||
1066 | error = TT_Run_Context( exec, ((TT_Size)loader->size)->debug ); | |
1067 | if ( error && exec->pedantic_hinting ) | |
1068 | goto Fail; | |
1069 | } | |
1070 | ||
1071 | /* save glyph origin and advance points */ | |
1072 | loader->pp1 = pp1[0]; | |
1073 | loader->pp2 = pp1[1]; | |
1074 | } | |
1075 | ||
1076 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ | |
1077 | ||
1078 | } | |
1079 | /* end of composite loading */ | |
1080 | } | |
1081 | ||
1082 | /***********************************************************************/ | |
1083 | /***********************************************************************/ | |
1084 | /***********************************************************************/ | |
1085 | ||
1086 | Fail: | |
1087 | if ( opened_frame ) | |
1088 | face->forget_glyph_frame( loader ); | |
1089 | ||
1090 | Exit: | |
1091 | return error; | |
1092 | } | |
1093 | ||
1094 | ||
1095 | static | |
1096 | void compute_glyph_metrics( TT_Loader* loader, | |
1097 | FT_UInt glyph_index ) | |
1098 | { | |
1099 | FT_BBox bbox; | |
1100 | TT_Face face = (TT_Face)loader->face; | |
1101 | FT_Fixed x_scale, y_scale; | |
1102 | TT_GlyphSlot glyph = loader->glyph; | |
1103 | TT_Size size = (TT_Size)loader->size; | |
1104 | ||
1105 | ||
1106 | x_scale = 0x10000L; | |
1107 | y_scale = 0x10000L; | |
1108 | if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) | |
1109 | { | |
1110 | x_scale = size->root.metrics.x_scale; | |
1111 | y_scale = size->root.metrics.y_scale; | |
1112 | } | |
1113 | ||
1114 | if ( glyph->format != ft_glyph_format_composite ) | |
1115 | { | |
1116 | glyph->outline.flags &= ~ft_outline_single_pass; | |
1117 | ||
1118 | /* copy outline to our glyph slot */ | |
1119 | FT_GlyphLoader_Copy_Points( glyph->loader, loader->gloader ); | |
1120 | glyph->outline = glyph->loader->base.outline; | |
1121 | ||
1122 | /* translate array so that (0,0) is the glyph's origin */ | |
1123 | FT_Outline_Translate( &glyph->outline, -loader->pp1.x, 0 ); | |
1124 | ||
1125 | FT_Outline_Get_CBox( &glyph->outline, &bbox ); | |
1126 | ||
1127 | if ( IS_HINTED( loader->load_flags ) ) | |
1128 | { | |
1129 | /* grid-fit the bounding box */ | |
1130 | bbox.xMin &= -64; | |
1131 | bbox.yMin &= -64; | |
1132 | bbox.xMax = ( bbox.xMax + 63 ) & -64; | |
1133 | bbox.yMax = ( bbox.yMax + 63 ) & -64; | |
1134 | } | |
1135 | } | |
1136 | else | |
1137 | bbox = loader->bbox; | |
1138 | ||
1139 | /* get the device-independent horizontal advance. It is scaled later */ | |
1140 | /* by the base layer. */ | |
1141 | { | |
1142 | FT_Pos advance = loader->advance; | |
1143 | ||
1144 | ||
1145 | /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */ | |
1146 | /* correctly support DynaLab fonts, which have an incorrect */ | |
1147 | /* `advance_Width_Max' field! It is used, to my knowledge, */ | |
1148 | /* exclusively in the X-TrueType font server. */ | |
1149 | /* */ | |
1150 | if ( face->postscript.isFixedPitch && | |
1151 | ( loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 ) | |
1152 | advance = face->horizontal.advance_Width_Max; | |
1153 | ||
1154 | /* we need to return the advance in font units in linearHoriAdvance, */ | |
1155 | /* it will be scaled later by the base layer. */ | |
1156 | glyph->linearHoriAdvance = advance; | |
1157 | } | |
1158 | ||
1159 | glyph->metrics.horiBearingX = bbox.xMin; | |
1160 | glyph->metrics.horiBearingY = bbox.yMax; | |
1161 | glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; | |
1162 | ||
1163 | /* Now take care of vertical metrics. In the case where there is */ | |
1164 | /* no vertical information within the font (relatively common), make */ | |
1165 | /* up some metrics by `hand'... */ | |
1166 | ||
1167 | { | |
1168 | FT_Short top_bearing; /* vertical top side bearing (EM units) */ | |
1169 | FT_UShort advance_height; /* vertical advance height (EM units) */ | |
1170 | ||
1171 | FT_Pos left; /* scaled vertical left side bearing */ | |
1172 | FT_Pos Top; /* scaled original vertical top side bearing */ | |
1173 | FT_Pos top; /* scaled vertical top side bearing */ | |
1174 | FT_Pos advance; /* scaled vertical advance height */ | |
1175 | ||
1176 | ||
1177 | /* Get the unscaled `tsb' and `ah' */ | |
1178 | if ( face->vertical_info && | |
1179 | face->vertical.number_Of_VMetrics > 0 ) | |
1180 | { | |
1181 | /* Don't assume that both the vertical header and vertical */ | |
1182 | /* metrics are present in the same font :-) */ | |
1183 | ||
1184 | TT_Get_Metrics( (TT_HoriHeader*)&face->vertical, | |
1185 | glyph_index, | |
1186 | &top_bearing, | |
1187 | &advance_height ); | |
1188 | } | |
1189 | else | |
1190 | { | |
1191 | /* Make up the distances from the horizontal header. */ | |
1192 | ||
1193 | /* NOTE: The OS/2 values are the only `portable' ones, */ | |
1194 | /* which is why we use them, if there is an OS/2 */ | |
1195 | /* table in the font. Otherwise, we use the */ | |
1196 | /* values defined in the horizontal header. */ | |
1197 | /* */ | |
1198 | /* NOTE2: The sTypoDescender is negative, which is why */ | |
1199 | /* we compute the baseline-to-baseline distance */ | |
1200 | /* here with: */ | |
1201 | /* ascender - descender + linegap */ | |
1202 | /* */ | |
1203 | if ( face->os2.version != 0xFFFF ) | |
1204 | { | |
1205 | top_bearing = face->os2.sTypoLineGap / 2; | |
1206 | advance_height = (FT_UShort)( face->os2.sTypoAscender - | |
1207 | face->os2.sTypoDescender + | |
1208 | face->os2.sTypoLineGap ); | |
1209 | } | |
1210 | else | |
1211 | { | |
1212 | top_bearing = face->horizontal.Line_Gap / 2; | |
1213 | advance_height = (FT_UShort)( face->horizontal.Ascender + | |
1214 | face->horizontal.Descender + | |
1215 | face->horizontal.Line_Gap ); | |
1216 | } | |
1217 | } | |
1218 | ||
1219 | /* We must adjust the top_bearing value from the bounding box given */ | |
1220 | /* in the glyph header to te bounding box calculated with */ | |
1221 | /* FT_Get_Outline_CBox(). */ | |
1222 | ||
1223 | /* scale the metrics */ | |
1224 | if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) | |
1225 | { | |
1226 | Top = FT_MulFix( top_bearing, y_scale ); | |
1227 | top = FT_MulFix( top_bearing + loader->bbox.yMax, y_scale ) | |
1228 | - bbox.yMax; | |
1229 | advance = FT_MulFix( advance_height, y_scale ); | |
1230 | } | |
1231 | else | |
1232 | { | |
1233 | Top = top_bearing; | |
1234 | top = top_bearing + loader->bbox.yMax - bbox.yMax; | |
1235 | advance = advance_height; | |
1236 | } | |
1237 | ||
1238 | /* set the advance height in design units. It is scaled later by */ | |
1239 | /* the base layer. */ | |
1240 | glyph->linearVertAdvance = advance_height; | |
1241 | ||
1242 | /* XXX: for now, we have no better algorithm for the lsb, but it */ | |
1243 | /* should work fine. */ | |
1244 | /* */ | |
1245 | left = ( bbox.xMin - bbox.xMax ) / 2; | |
1246 | ||
1247 | /* grid-fit them if necessary */ | |
1248 | if ( IS_HINTED( loader->load_flags ) ) | |
1249 | { | |
1250 | left &= -64; | |
1251 | top = ( top + 63 ) & -64; | |
1252 | advance = ( advance + 32 ) & -64; | |
1253 | } | |
1254 | ||
1255 | glyph->metrics.vertBearingX = left; | |
1256 | glyph->metrics.vertBearingY = top; | |
1257 | glyph->metrics.vertAdvance = advance; | |
1258 | } | |
1259 | ||
1260 | /* adjust advance width to the value contained in the hdmx table */ | |
1261 | if ( !face->postscript.isFixedPitch && size && | |
1262 | IS_HINTED( loader->load_flags ) ) | |
1263 | { | |
1264 | FT_Byte* widths = Get_Advance_Widths( face, | |
1265 | size->root.metrics.x_ppem ); | |
1266 | ||
1267 | ||
1268 | if ( widths ) | |
1269 | glyph->metrics.horiAdvance = widths[glyph_index] << 6; | |
1270 | } | |
1271 | ||
1272 | /* set glyph dimensions */ | |
1273 | glyph->metrics.width = bbox.xMax - bbox.xMin; | |
1274 | glyph->metrics.height = bbox.yMax - bbox.yMin; | |
1275 | } | |
1276 | ||
1277 | ||
1278 | /*************************************************************************/ | |
1279 | /* */ | |
1280 | /* <Function> */ | |
1281 | /* TT_Load_Glyph */ | |
1282 | /* */ | |
1283 | /* <Description> */ | |
1284 | /* A function used to load a single glyph within a given glyph slot, */ | |
1285 | /* for a given size. */ | |
1286 | /* */ | |
1287 | /* <Input> */ | |
1288 | /* glyph :: A handle to a target slot object where the glyph */ | |
1289 | /* will be loaded. */ | |
1290 | /* */ | |
1291 | /* size :: A handle to the source face size at which the glyph */ | |
1292 | /* must be scaled/loaded. */ | |
1293 | /* */ | |
1294 | /* glyph_index :: The index of the glyph in the font file. */ | |
1295 | /* */ | |
1296 | /* load_flags :: A flag indicating what to load for this glyph. The */ | |
1297 | /* FT_LOAD_XXX constants can be used to control the */ | |
1298 | /* glyph loading process (e.g., whether the outline */ | |
1299 | /* should be scaled, whether to load bitmaps or not, */ | |
1300 | /* whether to hint the outline, etc). */ | |
1301 | /* */ | |
1302 | /* <Return> */ | |
1303 | /* FreeType error code. 0 means success. */ | |
1304 | /* */ | |
1305 | LOCAL_FUNC | |
1306 | FT_Error TT_Load_Glyph( TT_Size size, | |
1307 | TT_GlyphSlot glyph, | |
1308 | FT_UShort glyph_index, | |
1309 | FT_UInt load_flags ) | |
1310 | { | |
1311 | SFNT_Interface* sfnt; | |
1312 | TT_Face face; | |
1313 | FT_Stream stream; | |
1314 | FT_Memory memory; | |
1315 | FT_Error error; | |
1316 | TT_Loader loader; | |
1317 | ||
1318 | ||
1319 | face = (TT_Face)glyph->face; | |
1320 | sfnt = (SFNT_Interface*)face->sfnt; | |
1321 | stream = face->root.stream; | |
1322 | memory = face->root.memory; | |
1323 | error = 0; | |
1324 | ||
1325 | if ( !size || ( load_flags & FT_LOAD_NO_SCALE ) || | |
1326 | ( load_flags & FT_LOAD_NO_RECURSE ) ) | |
1327 | { | |
1328 | size = NULL; | |
1329 | load_flags |= FT_LOAD_NO_SCALE | | |
1330 | FT_LOAD_NO_HINTING | | |
1331 | FT_LOAD_NO_BITMAP; | |
1332 | } | |
1333 | ||
1334 | glyph->num_subglyphs = 0; | |
1335 | ||
1336 | #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS | |
1337 | ||
1338 | /* try to load embedded bitmap if any */ | |
1339 | if ( size && | |
1340 | ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && | |
1341 | sfnt->load_sbits ) | |
1342 | { | |
1343 | TT_SBit_Metrics metrics; | |
1344 | ||
1345 | ||
1346 | error = sfnt->load_sbit_image( face, | |
1347 | size->root.metrics.x_ppem, | |
1348 | size->root.metrics.y_ppem, | |
1349 | glyph_index, | |
1350 | load_flags, | |
1351 | stream, | |
1352 | &glyph->bitmap, | |
1353 | &metrics ); | |
1354 | if ( !error ) | |
1355 | { | |
1356 | glyph->outline.n_points = 0; | |
1357 | glyph->outline.n_contours = 0; | |
1358 | ||
1359 | glyph->metrics.width = (FT_Pos)metrics.width << 6; | |
1360 | glyph->metrics.height = (FT_Pos)metrics.height << 6; | |
1361 | ||
1362 | glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6; | |
1363 | glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6; | |
1364 | glyph->metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6; | |
1365 | ||
1366 | glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6; | |
1367 | glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6; | |
1368 | glyph->metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6; | |
1369 | ||
1370 | glyph->format = ft_glyph_format_bitmap; | |
1371 | if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) | |
1372 | { | |
1373 | glyph->bitmap_left = metrics.vertBearingX; | |
1374 | glyph->bitmap_top = metrics.vertBearingY; | |
1375 | } | |
1376 | else | |
1377 | { | |
1378 | glyph->bitmap_left = metrics.horiBearingX; | |
1379 | glyph->bitmap_top = metrics.horiBearingY; | |
1380 | } | |
1381 | return error; | |
1382 | } | |
1383 | } | |
1384 | ||
1385 | #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ | |
1386 | ||
1387 | /* seek to the beginning of the glyph table. For Type 42 fonts */ | |
1388 | /* the table might be accessed from a Postscript stream or something */ | |
1389 | /* else... */ | |
1390 | ||
1391 | error = face->goto_table( face, TTAG_glyf, stream, 0 ); | |
1392 | if ( error ) | |
1393 | { | |
1394 | FT_ERROR(( "TT_Load_Glyph: could not access glyph table\n" )); | |
1395 | goto Exit; | |
1396 | } | |
1397 | ||
1398 | MEM_Set( &loader, 0, sizeof ( loader ) ); | |
1399 | ||
1400 | /* update the glyph zone bounds */ | |
1401 | { | |
1402 | FT_GlyphLoader* gloader = FT_FACE_DRIVER(face)->glyph_loader; | |
1403 | ||
1404 | ||
1405 | loader.gloader = gloader; | |
1406 | ||
1407 | FT_GlyphLoader_Rewind( gloader ); | |
1408 | ||
1409 | tt_prepare_zone( &loader.zone, &gloader->base, 0, 0 ); | |
1410 | tt_prepare_zone( &loader.base, &gloader->base, 0, 0 ); | |
1411 | } | |
1412 | ||
1413 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
1414 | ||
1415 | if ( size ) | |
1416 | { | |
1417 | /* query new execution context */ | |
1418 | loader.exec = size->debug ? size->context : TT_New_Context( face ); | |
1419 | if ( !loader.exec ) | |
1420 | return TT_Err_Could_Not_Find_Context; | |
1421 | ||
1422 | TT_Load_Context( loader.exec, face, size ); | |
1423 | loader.instructions = loader.exec->glyphIns; | |
1424 | ||
1425 | /* load default graphics state - if needed */ | |
1426 | if ( size->GS.instruct_control & 2 ) | |
1427 | loader.exec->GS = tt_default_graphics_state; | |
1428 | } | |
1429 | ||
1430 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ | |
1431 | ||
1432 | /* clear all outline flags, except the `owner' one */ | |
1433 | glyph->outline.flags = 0; | |
1434 | ||
1435 | if ( size && size->root.metrics.y_ppem < 24 ) | |
1436 | glyph->outline.flags |= ft_outline_high_precision; | |
1437 | ||
1438 | /* let's initialize the rest of our loader now */ | |
1439 | ||
1440 | loader.load_flags = load_flags; | |
1441 | ||
1442 | loader.face = (FT_Face)face; | |
1443 | loader.size = (FT_Size)size; | |
1444 | loader.glyph = (FT_GlyphSlot)glyph; | |
1445 | loader.stream = stream; | |
1446 | ||
1447 | loader.glyf_offset = FILE_Pos(); | |
1448 | ||
1449 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
1450 | ||
1451 | /* if the cvt program has disabled hinting, the argument */ | |
1452 | /* is ignored. */ | |
1453 | if ( size && ( size->GS.instruct_control & 1 ) ) | |
1454 | loader.load_flags |= FT_LOAD_NO_HINTING; | |
1455 | ||
1456 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ | |
1457 | ||
1458 | /* Main loading loop */ | |
1459 | glyph->format = ft_glyph_format_outline; | |
1460 | glyph->num_subglyphs = 0; | |
1461 | error = load_truetype_glyph( &loader, glyph_index ); | |
1462 | if ( !error ) | |
1463 | compute_glyph_metrics( &loader, glyph_index ); | |
1464 | ||
1465 | #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER | |
1466 | ||
1467 | if ( !size || !size->debug ) | |
1468 | TT_Done_Context( loader.exec ); | |
1469 | ||
1470 | #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ | |
1471 | ||
1472 | Exit: | |
1473 | return error; | |
1474 | } | |
1475 | ||
1476 | ||
1477 | /* END */ |