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