1 | /**************************************************************************** |
2 | * |
3 | * pfrgload.c |
4 | * |
5 | * FreeType PFR glyph loader (body). |
6 | * |
7 | * Copyright (C) 2002-2023 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 "pfrgload.h" |
20 | #include "pfrsbit.h" |
21 | #include "pfrload.h" /* for macro definitions */ |
22 | #include <freetype/internal/ftdebug.h> |
23 | |
24 | #include "pfrerror.h" |
25 | |
26 | #undef FT_COMPONENT |
27 | #define FT_COMPONENT pfr |
28 | |
29 | |
30 | /*************************************************************************/ |
31 | /*************************************************************************/ |
32 | /***** *****/ |
33 | /***** PFR GLYPH BUILDER *****/ |
34 | /***** *****/ |
35 | /*************************************************************************/ |
36 | /*************************************************************************/ |
37 | |
38 | |
39 | FT_LOCAL_DEF( void ) |
40 | pfr_glyph_init( PFR_Glyph glyph, |
41 | FT_GlyphLoader loader ) |
42 | { |
43 | FT_ZERO( glyph ); |
44 | |
45 | glyph->loader = loader; |
46 | |
47 | FT_GlyphLoader_Rewind( loader ); |
48 | } |
49 | |
50 | |
51 | FT_LOCAL_DEF( void ) |
52 | pfr_glyph_done( PFR_Glyph glyph ) |
53 | { |
54 | FT_Memory memory = glyph->loader->memory; |
55 | |
56 | |
57 | FT_FREE( glyph->x_control ); |
58 | glyph->y_control = NULL; |
59 | |
60 | glyph->max_xy_control = 0; |
61 | #if 0 |
62 | glyph->num_x_control = 0; |
63 | glyph->num_y_control = 0; |
64 | #endif |
65 | |
66 | FT_FREE( glyph->subs ); |
67 | |
68 | glyph->max_subs = 0; |
69 | glyph->num_subs = 0; |
70 | |
71 | glyph->loader = NULL; |
72 | glyph->path_begun = 0; |
73 | } |
74 | |
75 | |
76 | /* close current contour, if any */ |
77 | static void |
78 | pfr_glyph_close_contour( PFR_Glyph glyph ) |
79 | { |
80 | FT_GlyphLoader loader = glyph->loader; |
81 | FT_Outline* outline = &loader->current.outline; |
82 | FT_Int last, first; |
83 | |
84 | |
85 | if ( !glyph->path_begun ) |
86 | return; |
87 | |
88 | /* compute first and last point indices in current glyph outline */ |
89 | last = outline->n_points - 1; |
90 | first = 0; |
91 | if ( outline->n_contours > 0 ) |
92 | first = outline->contours[outline->n_contours - 1]; |
93 | |
94 | /* if the last point falls on the same location as the first one */ |
95 | /* we need to delete it */ |
96 | if ( last > first ) |
97 | { |
98 | FT_Vector* p1 = outline->points + first; |
99 | FT_Vector* p2 = outline->points + last; |
100 | |
101 | |
102 | if ( p1->x == p2->x && p1->y == p2->y ) |
103 | { |
104 | outline->n_points--; |
105 | last--; |
106 | } |
107 | } |
108 | |
109 | /* don't add empty contours */ |
110 | if ( last >= first ) |
111 | outline->contours[outline->n_contours++] = (short)last; |
112 | |
113 | glyph->path_begun = 0; |
114 | } |
115 | |
116 | |
117 | /* reset glyph to start the loading of a new glyph */ |
118 | static void |
119 | pfr_glyph_start( PFR_Glyph glyph ) |
120 | { |
121 | glyph->path_begun = 0; |
122 | } |
123 | |
124 | |
125 | static FT_Error |
126 | pfr_glyph_line_to( PFR_Glyph glyph, |
127 | FT_Vector* to ) |
128 | { |
129 | FT_GlyphLoader loader = glyph->loader; |
130 | FT_Outline* outline = &loader->current.outline; |
131 | FT_Error error; |
132 | |
133 | |
134 | /* check that we have begun a new path */ |
135 | if ( !glyph->path_begun ) |
136 | { |
137 | error = FT_THROW( Invalid_Table ); |
138 | FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); |
139 | goto Exit; |
140 | } |
141 | |
142 | error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 0 ); |
143 | if ( !error ) |
144 | { |
145 | FT_Int n = outline->n_points; |
146 | |
147 | |
148 | outline->points[n] = *to; |
149 | outline->tags [n] = FT_CURVE_TAG_ON; |
150 | |
151 | outline->n_points++; |
152 | } |
153 | |
154 | Exit: |
155 | return error; |
156 | } |
157 | |
158 | |
159 | static FT_Error |
160 | pfr_glyph_curve_to( PFR_Glyph glyph, |
161 | FT_Vector* control1, |
162 | FT_Vector* control2, |
163 | FT_Vector* to ) |
164 | { |
165 | FT_GlyphLoader loader = glyph->loader; |
166 | FT_Outline* outline = &loader->current.outline; |
167 | FT_Error error; |
168 | |
169 | |
170 | /* check that we have begun a new path */ |
171 | if ( !glyph->path_begun ) |
172 | { |
173 | error = FT_THROW( Invalid_Table ); |
174 | FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); |
175 | goto Exit; |
176 | } |
177 | |
178 | error = FT_GLYPHLOADER_CHECK_POINTS( loader, 3, 0 ); |
179 | if ( !error ) |
180 | { |
181 | FT_Vector* vec = outline->points + outline->n_points; |
182 | FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points; |
183 | |
184 | |
185 | vec[0] = *control1; |
186 | vec[1] = *control2; |
187 | vec[2] = *to; |
188 | tag[0] = FT_CURVE_TAG_CUBIC; |
189 | tag[1] = FT_CURVE_TAG_CUBIC; |
190 | tag[2] = FT_CURVE_TAG_ON; |
191 | |
192 | outline->n_points = (FT_Short)( outline->n_points + 3 ); |
193 | } |
194 | |
195 | Exit: |
196 | return error; |
197 | } |
198 | |
199 | |
200 | static FT_Error |
201 | pfr_glyph_move_to( PFR_Glyph glyph, |
202 | FT_Vector* to ) |
203 | { |
204 | FT_GlyphLoader loader = glyph->loader; |
205 | FT_Error error; |
206 | |
207 | |
208 | /* close current contour if any */ |
209 | pfr_glyph_close_contour( glyph ); |
210 | |
211 | /* indicate that a new contour has started */ |
212 | glyph->path_begun = 1; |
213 | |
214 | /* check that there is space for a new contour and a new point */ |
215 | error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 1 ); |
216 | if ( !error ) |
217 | { |
218 | /* add new start point */ |
219 | error = pfr_glyph_line_to( glyph, to ); |
220 | } |
221 | |
222 | return error; |
223 | } |
224 | |
225 | |
226 | static void |
227 | pfr_glyph_end( PFR_Glyph glyph ) |
228 | { |
229 | /* close current contour if any */ |
230 | pfr_glyph_close_contour( glyph ); |
231 | |
232 | /* merge the current glyph into the stack */ |
233 | FT_GlyphLoader_Add( glyph->loader ); |
234 | } |
235 | |
236 | |
237 | /*************************************************************************/ |
238 | /*************************************************************************/ |
239 | /***** *****/ |
240 | /***** PFR GLYPH LOADER *****/ |
241 | /***** *****/ |
242 | /*************************************************************************/ |
243 | /*************************************************************************/ |
244 | |
245 | |
246 | /* load a simple glyph */ |
247 | static FT_Error |
248 | pfr_glyph_load_simple( PFR_Glyph glyph, |
249 | FT_Byte* p, |
250 | FT_Byte* limit ) |
251 | { |
252 | FT_Error error = FT_Err_Ok; |
253 | FT_Memory memory = glyph->loader->memory; |
254 | FT_UInt flags, x_count, y_count, i, count, mask; |
255 | FT_Int x; |
256 | |
257 | |
258 | PFR_CHECK( 1 ); |
259 | flags = PFR_NEXT_BYTE( p ); |
260 | |
261 | /* test for composite glyphs */ |
262 | if ( flags & PFR_GLYPH_IS_COMPOUND ) |
263 | goto Failure; |
264 | |
265 | x_count = 0; |
266 | y_count = 0; |
267 | |
268 | if ( flags & PFR_GLYPH_1BYTE_XYCOUNT ) |
269 | { |
270 | PFR_CHECK( 1 ); |
271 | count = PFR_NEXT_BYTE( p ); |
272 | x_count = count & 15; |
273 | y_count = count >> 4; |
274 | } |
275 | else |
276 | { |
277 | if ( flags & PFR_GLYPH_XCOUNT ) |
278 | { |
279 | PFR_CHECK( 1 ); |
280 | x_count = PFR_NEXT_BYTE( p ); |
281 | } |
282 | |
283 | if ( flags & PFR_GLYPH_YCOUNT ) |
284 | { |
285 | PFR_CHECK( 1 ); |
286 | y_count = PFR_NEXT_BYTE( p ); |
287 | } |
288 | } |
289 | |
290 | count = x_count + y_count; |
291 | |
292 | /* re-allocate array when necessary */ |
293 | if ( count > glyph->max_xy_control ) |
294 | { |
295 | FT_UInt new_max = FT_PAD_CEIL( count, 8 ); |
296 | |
297 | |
298 | if ( FT_RENEW_ARRAY( glyph->x_control, |
299 | glyph->max_xy_control, |
300 | new_max ) ) |
301 | goto Exit; |
302 | |
303 | glyph->max_xy_control = new_max; |
304 | } |
305 | |
306 | glyph->y_control = glyph->x_control + x_count; |
307 | |
308 | mask = 0; |
309 | x = 0; |
310 | |
311 | for ( i = 0; i < count; i++ ) |
312 | { |
313 | if ( ( i & 7 ) == 0 ) |
314 | { |
315 | PFR_CHECK( 1 ); |
316 | mask = PFR_NEXT_BYTE( p ); |
317 | } |
318 | |
319 | if ( mask & 1 ) |
320 | { |
321 | PFR_CHECK( 2 ); |
322 | x = PFR_NEXT_SHORT( p ); |
323 | } |
324 | else |
325 | { |
326 | PFR_CHECK( 1 ); |
327 | x += PFR_NEXT_BYTE( p ); |
328 | } |
329 | |
330 | glyph->x_control[i] = x; |
331 | |
332 | mask >>= 1; |
333 | } |
334 | |
335 | /* XXX: we ignore the secondary stroke and edge definitions */ |
336 | /* since we don't support native PFR hinting */ |
337 | /* */ |
338 | if ( flags & PFR_GLYPH_SINGLE_EXTRA_ITEMS ) |
339 | { |
340 | error = pfr_extra_items_skip( &p, limit ); |
341 | if ( error ) |
342 | goto Exit; |
343 | } |
344 | |
345 | pfr_glyph_start( glyph ); |
346 | |
347 | /* now load a simple glyph */ |
348 | { |
349 | FT_Vector pos[4]; |
350 | FT_Vector* cur; |
351 | |
352 | |
353 | pos[0].x = pos[0].y = 0; |
354 | pos[3] = pos[0]; |
355 | |
356 | for (;;) |
357 | { |
358 | FT_UInt format, format_low, args_format = 0, args_count, n; |
359 | |
360 | |
361 | /**************************************************************** |
362 | * read instruction |
363 | */ |
364 | PFR_CHECK( 1 ); |
365 | format = PFR_NEXT_BYTE( p ); |
366 | format_low = format & 15; |
367 | |
368 | switch ( format >> 4 ) |
369 | { |
370 | case 0: /* end glyph */ |
371 | FT_TRACE6(( "- end glyph" )); |
372 | args_count = 0; |
373 | break; |
374 | |
375 | case 1: /* general line operation */ |
376 | FT_TRACE6(( "- general line" )); |
377 | goto Line1; |
378 | |
379 | case 4: /* move to inside contour */ |
380 | FT_TRACE6(( "- move to inside" )); |
381 | goto Line1; |
382 | |
383 | case 5: /* move to outside contour */ |
384 | FT_TRACE6(( "- move to outside" )); |
385 | Line1: |
386 | args_format = format_low; |
387 | args_count = 1; |
388 | break; |
389 | |
390 | case 2: /* horizontal line to */ |
391 | FT_TRACE6(( "- horizontal line to cx.%d" , format_low )); |
392 | if ( format_low >= x_count ) |
393 | goto Failure; |
394 | pos[0].x = glyph->x_control[format_low]; |
395 | pos[0].y = pos[3].y; |
396 | pos[3] = pos[0]; |
397 | args_count = 0; |
398 | break; |
399 | |
400 | case 3: /* vertical line to */ |
401 | FT_TRACE6(( "- vertical line to cy.%d" , format_low )); |
402 | if ( format_low >= y_count ) |
403 | goto Failure; |
404 | pos[0].x = pos[3].x; |
405 | pos[0].y = glyph->y_control[format_low]; |
406 | pos[3] = pos[0]; |
407 | args_count = 0; |
408 | break; |
409 | |
410 | case 6: /* horizontal to vertical curve */ |
411 | FT_TRACE6(( "- hv curve" )); |
412 | args_format = 0xB8E; |
413 | args_count = 3; |
414 | break; |
415 | |
416 | case 7: /* vertical to horizontal curve */ |
417 | FT_TRACE6(( "- vh curve" )); |
418 | args_format = 0xE2B; |
419 | args_count = 3; |
420 | break; |
421 | |
422 | default: /* general curve to */ |
423 | FT_TRACE6(( "- general curve" )); |
424 | args_count = 4; |
425 | args_format = format_low; |
426 | } |
427 | |
428 | /************************************************************ |
429 | * now read arguments |
430 | */ |
431 | cur = pos; |
432 | for ( n = 0; n < args_count; n++ ) |
433 | { |
434 | FT_UInt idx; |
435 | FT_Int delta; |
436 | |
437 | |
438 | /* read the X argument */ |
439 | switch ( args_format & 3 ) |
440 | { |
441 | case 0: /* 8-bit index */ |
442 | PFR_CHECK( 1 ); |
443 | idx = PFR_NEXT_BYTE( p ); |
444 | if ( idx >= x_count ) |
445 | goto Failure; |
446 | cur->x = glyph->x_control[idx]; |
447 | FT_TRACE7(( " cx#%d" , idx )); |
448 | break; |
449 | |
450 | case 1: /* 16-bit absolute value */ |
451 | PFR_CHECK( 2 ); |
452 | cur->x = PFR_NEXT_SHORT( p ); |
453 | FT_TRACE7(( " x.%ld" , cur->x )); |
454 | break; |
455 | |
456 | case 2: /* 8-bit delta */ |
457 | PFR_CHECK( 1 ); |
458 | delta = PFR_NEXT_INT8( p ); |
459 | cur->x = pos[3].x + delta; |
460 | FT_TRACE7(( " dx.%d" , delta )); |
461 | break; |
462 | |
463 | default: |
464 | FT_TRACE7(( " |" )); |
465 | cur->x = pos[3].x; |
466 | } |
467 | |
468 | /* read the Y argument */ |
469 | switch ( ( args_format >> 2 ) & 3 ) |
470 | { |
471 | case 0: /* 8-bit index */ |
472 | PFR_CHECK( 1 ); |
473 | idx = PFR_NEXT_BYTE( p ); |
474 | if ( idx >= y_count ) |
475 | goto Failure; |
476 | cur->y = glyph->y_control[idx]; |
477 | FT_TRACE7(( " cy#%d" , idx )); |
478 | break; |
479 | |
480 | case 1: /* 16-bit absolute value */ |
481 | PFR_CHECK( 2 ); |
482 | cur->y = PFR_NEXT_SHORT( p ); |
483 | FT_TRACE7(( " y.%ld" , cur->y )); |
484 | break; |
485 | |
486 | case 2: /* 8-bit delta */ |
487 | PFR_CHECK( 1 ); |
488 | delta = PFR_NEXT_INT8( p ); |
489 | cur->y = pos[3].y + delta; |
490 | FT_TRACE7(( " dy.%d" , delta )); |
491 | break; |
492 | |
493 | default: |
494 | FT_TRACE7(( " -" )); |
495 | cur->y = pos[3].y; |
496 | } |
497 | |
498 | /* read the additional format flag for the general curve */ |
499 | if ( n == 0 && args_count == 4 ) |
500 | { |
501 | PFR_CHECK( 1 ); |
502 | args_format = PFR_NEXT_BYTE( p ); |
503 | args_count--; |
504 | } |
505 | else |
506 | args_format >>= 4; |
507 | |
508 | /* save the previous point */ |
509 | pos[3] = cur[0]; |
510 | cur++; |
511 | } |
512 | |
513 | FT_TRACE7(( "\n" )); |
514 | |
515 | /************************************************************ |
516 | * finally, execute instruction |
517 | */ |
518 | switch ( format >> 4 ) |
519 | { |
520 | case 0: /* end glyph => EXIT */ |
521 | pfr_glyph_end( glyph ); |
522 | goto Exit; |
523 | |
524 | case 1: /* line operations */ |
525 | case 2: |
526 | case 3: |
527 | error = pfr_glyph_line_to( glyph, pos ); |
528 | goto Test_Error; |
529 | |
530 | case 4: /* move to inside contour */ |
531 | case 5: /* move to outside contour */ |
532 | error = pfr_glyph_move_to( glyph, pos ); |
533 | goto Test_Error; |
534 | |
535 | default: /* curve operations */ |
536 | error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 ); |
537 | |
538 | Test_Error: /* test error condition */ |
539 | if ( error ) |
540 | goto Exit; |
541 | } |
542 | } /* for (;;) */ |
543 | } |
544 | |
545 | Exit: |
546 | return error; |
547 | |
548 | Failure: |
549 | Too_Short: |
550 | error = FT_THROW( Invalid_Table ); |
551 | FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" )); |
552 | goto Exit; |
553 | } |
554 | |
555 | |
556 | /* load a composite/compound glyph */ |
557 | static FT_Error |
558 | pfr_glyph_load_compound( PFR_Glyph glyph, |
559 | FT_Byte* p, |
560 | FT_Byte* limit ) |
561 | { |
562 | FT_Error error = FT_Err_Ok; |
563 | FT_Memory memory = glyph->loader->memory; |
564 | PFR_SubGlyph subglyph; |
565 | FT_UInt flags, i, count, org_count; |
566 | FT_Int x_pos, y_pos; |
567 | |
568 | |
569 | PFR_CHECK( 1 ); |
570 | flags = PFR_NEXT_BYTE( p ); |
571 | |
572 | /* test for composite glyphs */ |
573 | if ( !( flags & PFR_GLYPH_IS_COMPOUND ) ) |
574 | goto Failure; |
575 | |
576 | count = flags & 0x3F; |
577 | |
578 | /* ignore extra items when present */ |
579 | /* */ |
580 | if ( flags & PFR_GLYPH_COMPOUND_EXTRA_ITEMS ) |
581 | { |
582 | error = pfr_extra_items_skip( &p, limit ); |
583 | if ( error ) |
584 | goto Exit; |
585 | } |
586 | |
587 | /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */ |
588 | /* the PFR format is dumb, using direct file offsets to point to the */ |
589 | /* sub-glyphs (instead of glyph indices). Sigh. */ |
590 | /* */ |
591 | /* For now, we load the list of sub-glyphs into a different array */ |
592 | /* but this will prevent us from using the auto-hinter at its best */ |
593 | /* quality. */ |
594 | /* */ |
595 | org_count = glyph->num_subs; |
596 | |
597 | if ( org_count + count > glyph->max_subs ) |
598 | { |
599 | FT_UInt new_max = ( org_count + count + 3 ) & (FT_UInt)-4; |
600 | |
601 | |
602 | /* we arbitrarily limit the number of subglyphs */ |
603 | /* to avoid endless recursion */ |
604 | if ( new_max > 64 ) |
605 | { |
606 | error = FT_THROW( Invalid_Table ); |
607 | FT_ERROR(( "pfr_glyph_load_compound:" |
608 | " too many compound glyphs components\n" )); |
609 | goto Exit; |
610 | } |
611 | |
612 | if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) ) |
613 | goto Exit; |
614 | |
615 | glyph->max_subs = new_max; |
616 | } |
617 | |
618 | subglyph = glyph->subs + org_count; |
619 | |
620 | for ( i = 0; i < count; i++, subglyph++ ) |
621 | { |
622 | FT_UInt format; |
623 | |
624 | |
625 | x_pos = 0; |
626 | y_pos = 0; |
627 | |
628 | PFR_CHECK( 1 ); |
629 | format = PFR_NEXT_BYTE( p ); |
630 | |
631 | /* read scale when available */ |
632 | subglyph->x_scale = 0x10000L; |
633 | if ( format & PFR_SUBGLYPH_XSCALE ) |
634 | { |
635 | PFR_CHECK( 2 ); |
636 | subglyph->x_scale = PFR_NEXT_SHORT( p ) * 16; |
637 | } |
638 | |
639 | subglyph->y_scale = 0x10000L; |
640 | if ( format & PFR_SUBGLYPH_YSCALE ) |
641 | { |
642 | PFR_CHECK( 2 ); |
643 | subglyph->y_scale = PFR_NEXT_SHORT( p ) * 16; |
644 | } |
645 | |
646 | /* read offset */ |
647 | switch ( format & 3 ) |
648 | { |
649 | case 1: |
650 | PFR_CHECK( 2 ); |
651 | x_pos = PFR_NEXT_SHORT( p ); |
652 | break; |
653 | |
654 | case 2: |
655 | PFR_CHECK( 1 ); |
656 | x_pos += PFR_NEXT_INT8( p ); |
657 | break; |
658 | |
659 | default: |
660 | ; |
661 | } |
662 | |
663 | switch ( ( format >> 2 ) & 3 ) |
664 | { |
665 | case 1: |
666 | PFR_CHECK( 2 ); |
667 | y_pos = PFR_NEXT_SHORT( p ); |
668 | break; |
669 | |
670 | case 2: |
671 | PFR_CHECK( 1 ); |
672 | y_pos += PFR_NEXT_INT8( p ); |
673 | break; |
674 | |
675 | default: |
676 | ; |
677 | } |
678 | |
679 | subglyph->x_delta = x_pos; |
680 | subglyph->y_delta = y_pos; |
681 | |
682 | /* read glyph position and size now */ |
683 | if ( format & PFR_SUBGLYPH_2BYTE_SIZE ) |
684 | { |
685 | PFR_CHECK( 2 ); |
686 | subglyph->gps_size = PFR_NEXT_USHORT( p ); |
687 | } |
688 | else |
689 | { |
690 | PFR_CHECK( 1 ); |
691 | subglyph->gps_size = PFR_NEXT_BYTE( p ); |
692 | } |
693 | |
694 | if ( format & PFR_SUBGLYPH_3BYTE_OFFSET ) |
695 | { |
696 | PFR_CHECK( 3 ); |
697 | subglyph->gps_offset = PFR_NEXT_ULONG( p ); |
698 | } |
699 | else |
700 | { |
701 | PFR_CHECK( 2 ); |
702 | subglyph->gps_offset = PFR_NEXT_USHORT( p ); |
703 | } |
704 | |
705 | glyph->num_subs++; |
706 | } |
707 | |
708 | Exit: |
709 | return error; |
710 | |
711 | Failure: |
712 | Too_Short: |
713 | error = FT_THROW( Invalid_Table ); |
714 | FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" )); |
715 | goto Exit; |
716 | } |
717 | |
718 | |
719 | static FT_Error |
720 | pfr_glyph_load_rec( PFR_Glyph glyph, |
721 | FT_Stream stream, |
722 | FT_ULong gps_offset, |
723 | FT_ULong offset, |
724 | FT_ULong size ) |
725 | { |
726 | FT_Error error; |
727 | FT_Byte* p; |
728 | FT_Byte* limit; |
729 | |
730 | |
731 | if ( FT_STREAM_SEEK( gps_offset + offset ) || |
732 | FT_FRAME_ENTER( size ) ) |
733 | goto Exit; |
734 | |
735 | p = (FT_Byte*)stream->cursor; |
736 | limit = p + size; |
737 | |
738 | if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND ) |
739 | { |
740 | FT_UInt n, old_count, count; |
741 | FT_GlyphLoader loader = glyph->loader; |
742 | FT_Outline* base = &loader->base.outline; |
743 | |
744 | |
745 | old_count = glyph->num_subs; |
746 | |
747 | /* this is a compound glyph - load it */ |
748 | error = pfr_glyph_load_compound( glyph, p, limit ); |
749 | |
750 | FT_FRAME_EXIT(); |
751 | |
752 | if ( error ) |
753 | goto Exit; |
754 | |
755 | count = glyph->num_subs - old_count; |
756 | |
757 | FT_TRACE4(( "compound glyph with %d element%s (offset %lu):\n" , |
758 | count, |
759 | count == 1 ? "" : "s" , |
760 | offset )); |
761 | |
762 | /* now, load each individual glyph */ |
763 | for ( n = 0; n < count; n++ ) |
764 | { |
765 | FT_Int i, old_points, num_points; |
766 | PFR_SubGlyph subglyph; |
767 | |
768 | |
769 | FT_TRACE4(( " subglyph %d:\n" , n )); |
770 | |
771 | subglyph = glyph->subs + old_count + n; |
772 | old_points = base->n_points; |
773 | |
774 | error = pfr_glyph_load_rec( glyph, stream, gps_offset, |
775 | subglyph->gps_offset, |
776 | subglyph->gps_size ); |
777 | if ( error ) |
778 | break; |
779 | |
780 | /* note that `glyph->subs' might have been re-allocated */ |
781 | subglyph = glyph->subs + old_count + n; |
782 | num_points = base->n_points - old_points; |
783 | |
784 | /* translate and eventually scale the new glyph points */ |
785 | if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L ) |
786 | { |
787 | FT_Vector* vec = base->points + old_points; |
788 | |
789 | |
790 | for ( i = 0; i < num_points; i++, vec++ ) |
791 | { |
792 | vec->x = FT_MulFix( vec->x, subglyph->x_scale ) + |
793 | subglyph->x_delta; |
794 | vec->y = FT_MulFix( vec->y, subglyph->y_scale ) + |
795 | subglyph->y_delta; |
796 | } |
797 | } |
798 | else |
799 | { |
800 | FT_Vector* vec = loader->base.outline.points + old_points; |
801 | |
802 | |
803 | for ( i = 0; i < num_points; i++, vec++ ) |
804 | { |
805 | vec->x += subglyph->x_delta; |
806 | vec->y += subglyph->y_delta; |
807 | } |
808 | } |
809 | |
810 | /* proceed to next sub-glyph */ |
811 | } |
812 | |
813 | FT_TRACE4(( "end compound glyph with %d element%s\n" , |
814 | count, |
815 | count == 1 ? "" : "s" )); |
816 | } |
817 | else |
818 | { |
819 | FT_TRACE4(( "simple glyph (offset %lu)\n" , offset )); |
820 | |
821 | /* load a simple glyph */ |
822 | error = pfr_glyph_load_simple( glyph, p, limit ); |
823 | |
824 | FT_FRAME_EXIT(); |
825 | } |
826 | |
827 | Exit: |
828 | return error; |
829 | } |
830 | |
831 | |
832 | FT_LOCAL_DEF( FT_Error ) |
833 | pfr_glyph_load( PFR_Glyph glyph, |
834 | FT_Stream stream, |
835 | FT_ULong gps_offset, |
836 | FT_ULong offset, |
837 | FT_ULong size ) |
838 | { |
839 | /* initialize glyph loader */ |
840 | FT_GlyphLoader_Rewind( glyph->loader ); |
841 | |
842 | glyph->num_subs = 0; |
843 | |
844 | /* load the glyph, recursively when needed */ |
845 | return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size ); |
846 | } |
847 | |
848 | |
849 | /* END */ |
850 | |