1
/***************************************************************************/
5
/* FreeType PFR glyph loader (body). */
7
/* Copyright 2002, 2003, 2005, 2007, 2010 by */
8
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16
/***************************************************************************/
21
#include "pfrload.h" /* for macro definitions */
22
#include FT_INTERNAL_DEBUG_H
27
#define FT_COMPONENT trace_pfr
30
/*************************************************************************/
31
/*************************************************************************/
33
/***** PFR GLYPH BUILDER *****/
35
/*************************************************************************/
36
/*************************************************************************/
40
pfr_glyph_init( PFR_Glyph glyph,
41
FT_GlyphLoader loader )
45
glyph->loader = loader;
46
glyph->path_begun = 0;
48
FT_GlyphLoader_Rewind( loader );
53
pfr_glyph_done( PFR_Glyph glyph )
55
FT_Memory memory = glyph->loader->memory;
58
FT_FREE( glyph->x_control );
59
glyph->y_control = NULL;
61
glyph->max_xy_control = 0;
63
glyph->num_x_control = 0;
64
glyph->num_y_control = 0;
67
FT_FREE( glyph->subs );
73
glyph->path_begun = 0;
77
/* close current contour, if any */
79
pfr_glyph_close_contour( PFR_Glyph glyph )
81
FT_GlyphLoader loader = glyph->loader;
82
FT_Outline* outline = &loader->current.outline;
86
if ( !glyph->path_begun )
89
/* compute first and last point indices in current glyph outline */
90
last = outline->n_points - 1;
92
if ( outline->n_contours > 0 )
93
first = outline->contours[outline->n_contours - 1];
95
/* if the last point falls on the same location than the first one */
96
/* we need to delete it */
99
FT_Vector* p1 = outline->points + first;
100
FT_Vector* p2 = outline->points + last;
103
if ( p1->x == p2->x && p1->y == p2->y )
110
/* don't add empty contours */
112
outline->contours[outline->n_contours++] = (short)last;
114
glyph->path_begun = 0;
118
/* reset glyph to start the loading of a new glyph */
120
pfr_glyph_start( PFR_Glyph glyph )
122
glyph->path_begun = 0;
127
pfr_glyph_line_to( PFR_Glyph glyph,
130
FT_GlyphLoader loader = glyph->loader;
131
FT_Outline* outline = &loader->current.outline;
135
/* check that we have begun a new path */
136
if ( !glyph->path_begun )
138
error = PFR_Err_Invalid_Table;
139
FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" ));
143
error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 0 );
146
FT_UInt n = outline->n_points;
149
outline->points[n] = *to;
150
outline->tags [n] = FT_CURVE_TAG_ON;
161
pfr_glyph_curve_to( PFR_Glyph glyph,
166
FT_GlyphLoader loader = glyph->loader;
167
FT_Outline* outline = &loader->current.outline;
171
/* check that we have begun a new path */
172
if ( !glyph->path_begun )
174
error = PFR_Err_Invalid_Table;
175
FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" ));
179
error = FT_GLYPHLOADER_CHECK_POINTS( loader, 3, 0 );
182
FT_Vector* vec = outline->points + outline->n_points;
183
FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points;
189
tag[0] = FT_CURVE_TAG_CUBIC;
190
tag[1] = FT_CURVE_TAG_CUBIC;
191
tag[2] = FT_CURVE_TAG_ON;
193
outline->n_points = (FT_Short)( outline->n_points + 3 );
202
pfr_glyph_move_to( PFR_Glyph glyph,
205
FT_GlyphLoader loader = glyph->loader;
209
/* close current contour if any */
210
pfr_glyph_close_contour( glyph );
212
/* indicate that a new contour has started */
213
glyph->path_begun = 1;
215
/* check that there is space for a new contour and a new point */
216
error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 1 );
218
/* add new start point */
219
error = pfr_glyph_line_to( glyph, to );
226
pfr_glyph_end( PFR_Glyph glyph )
228
/* close current contour if any */
229
pfr_glyph_close_contour( glyph );
231
/* merge the current glyph into the stack */
232
FT_GlyphLoader_Add( glyph->loader );
236
/*************************************************************************/
237
/*************************************************************************/
239
/***** PFR GLYPH LOADER *****/
241
/*************************************************************************/
242
/*************************************************************************/
245
/* load a simple glyph */
247
pfr_glyph_load_simple( PFR_Glyph glyph,
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;
258
flags = PFR_NEXT_BYTE( p );
260
/* test for composite glyphs */
261
if ( flags & PFR_GLYPH_IS_COMPOUND )
267
if ( flags & PFR_GLYPH_1BYTE_XYCOUNT )
270
count = PFR_NEXT_BYTE( p );
271
x_count = count & 15;
272
y_count = count >> 4;
276
if ( flags & PFR_GLYPH_XCOUNT )
279
x_count = PFR_NEXT_BYTE( p );
282
if ( flags & PFR_GLYPH_YCOUNT )
285
y_count = PFR_NEXT_BYTE( p );
289
count = x_count + y_count;
291
/* re-allocate array when necessary */
292
if ( count > glyph->max_xy_control )
294
FT_UInt new_max = FT_PAD_CEIL( count, 8 );
297
if ( FT_RENEW_ARRAY( glyph->x_control,
298
glyph->max_xy_control,
302
glyph->max_xy_control = new_max;
305
glyph->y_control = glyph->x_control + x_count;
310
for ( i = 0; i < count; i++ )
312
if ( ( i & 7 ) == 0 )
315
mask = PFR_NEXT_BYTE( p );
321
x = PFR_NEXT_SHORT( p );
326
x += PFR_NEXT_BYTE( p );
329
glyph->x_control[i] = x;
334
/* XXX: for now we ignore the secondary stroke and edge definitions */
335
/* since we don't want to support native PFR hinting */
337
if ( flags & PFR_GLYPH_EXTRA_ITEMS )
339
error = pfr_extra_items_skip( &p, limit );
344
pfr_glyph_start( glyph );
346
/* now load a simple glyph */
352
pos[0].x = pos[0].y = 0;
357
FT_UInt format, format_low, args_format = 0, args_count, n;
360
/***************************************************************/
361
/* read instruction */
364
format = PFR_NEXT_BYTE( p );
365
format_low = format & 15;
367
switch ( format >> 4 )
369
case 0: /* end glyph */
370
FT_TRACE6(( "- end glyph" ));
374
case 1: /* general line operation */
375
FT_TRACE6(( "- general line" ));
378
case 4: /* move to inside contour */
379
FT_TRACE6(( "- move to inside" ));
382
case 5: /* move to outside contour */
383
FT_TRACE6(( "- move to outside" ));
385
args_format = format_low;
389
case 2: /* horizontal line to */
390
FT_TRACE6(( "- horizontal line to cx.%d", format_low ));
391
if ( format_low >= x_count )
393
pos[0].x = glyph->x_control[format_low];
399
case 3: /* vertical line to */
400
FT_TRACE6(( "- vertical line to cy.%d", format_low ));
401
if ( format_low >= y_count )
404
pos[0].y = glyph->y_control[format_low];
409
case 6: /* horizontal to vertical curve */
410
FT_TRACE6(( "- hv curve " ));
415
case 7: /* vertical to horizontal curve */
416
FT_TRACE6(( "- vh curve" ));
421
default: /* general curve to */
422
FT_TRACE6(( "- general curve" ));
424
args_format = format_low;
427
/***********************************************************/
428
/* now read arguments */
431
for ( n = 0; n < args_count; n++ )
437
/* read the X argument */
438
switch ( args_format & 3 )
440
case 0: /* 8-bit index */
442
idx = PFR_NEXT_BYTE( p );
443
if ( idx >= x_count )
445
cur->x = glyph->x_control[idx];
446
FT_TRACE7(( " cx#%d", idx ));
449
case 1: /* 16-bit value */
451
cur->x = PFR_NEXT_SHORT( p );
452
FT_TRACE7(( " x.%d", cur->x ));
455
case 2: /* 8-bit delta */
457
delta = PFR_NEXT_INT8( p );
458
cur->x = pos[3].x + delta;
459
FT_TRACE7(( " dx.%d", delta ));
467
/* read the Y argument */
468
switch ( ( args_format >> 2 ) & 3 )
470
case 0: /* 8-bit index */
472
idx = PFR_NEXT_BYTE( p );
473
if ( idx >= y_count )
475
cur->y = glyph->y_control[idx];
476
FT_TRACE7(( " cy#%d", idx ));
479
case 1: /* 16-bit absolute value */
481
cur->y = PFR_NEXT_SHORT( p );
482
FT_TRACE7(( " y.%d", cur->y ));
485
case 2: /* 8-bit delta */
487
delta = PFR_NEXT_INT8( p );
488
cur->y = pos[3].y + delta;
489
FT_TRACE7(( " dy.%d", delta ));
497
/* read the additional format flag for the general curve */
498
if ( n == 0 && args_count == 4 )
501
args_format = PFR_NEXT_BYTE( p );
507
/* save the previous point */
514
/***********************************************************/
515
/* finally, execute instruction */
517
switch ( format >> 4 )
519
case 0: /* end glyph => EXIT */
520
pfr_glyph_end( glyph );
523
case 1: /* line operations */
526
error = pfr_glyph_line_to( glyph, pos );
529
case 4: /* move to inside contour */
530
case 5: /* move to outside contour */
531
error = pfr_glyph_move_to( glyph, pos );
534
default: /* curve operations */
535
error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 );
537
Test_Error: /* test error condition */
549
error = PFR_Err_Invalid_Table;
550
FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" ));
555
/* load a composite/compound glyph */
557
pfr_glyph_load_compound( PFR_Glyph glyph,
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;
570
flags = PFR_NEXT_BYTE( p );
572
/* test for composite glyphs */
573
if ( !( flags & PFR_GLYPH_IS_COMPOUND ) )
576
count = flags & 0x3F;
578
/* ignore extra items when present */
580
if ( flags & PFR_GLYPH_EXTRA_ITEMS )
582
error = pfr_extra_items_skip( &p, limit );
583
if (error) goto Exit;
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. */
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 */
594
org_count = glyph->num_subs;
596
if ( org_count + count > glyph->max_subs )
598
FT_UInt new_max = ( org_count + count + 3 ) & (FT_UInt)-4;
601
/* we arbitrarily limit the number of subglyphs */
602
/* to avoid endless recursion */
605
error = PFR_Err_Invalid_Table;
606
FT_ERROR(( "pfr_glyph_load_compound:"
607
" too many compound glyphs components\n" ));
611
if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) )
614
glyph->max_subs = new_max;
617
subglyph = glyph->subs + org_count;
619
for ( i = 0; i < count; i++, subglyph++ )
628
format = PFR_NEXT_BYTE( p );
630
/* read scale when available */
631
subglyph->x_scale = 0x10000L;
632
if ( format & PFR_SUBGLYPH_XSCALE )
635
subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4;
638
subglyph->y_scale = 0x10000L;
639
if ( format & PFR_SUBGLYPH_YSCALE )
642
subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4;
646
switch ( format & 3 )
650
x_pos = PFR_NEXT_SHORT( p );
655
x_pos += PFR_NEXT_INT8( p );
662
switch ( ( format >> 2 ) & 3 )
666
y_pos = PFR_NEXT_SHORT( p );
671
y_pos += PFR_NEXT_INT8( p );
678
subglyph->x_delta = x_pos;
679
subglyph->y_delta = y_pos;
681
/* read glyph position and size now */
682
if ( format & PFR_SUBGLYPH_2BYTE_SIZE )
685
subglyph->gps_size = PFR_NEXT_USHORT( p );
690
subglyph->gps_size = PFR_NEXT_BYTE( p );
693
if ( format & PFR_SUBGLYPH_3BYTE_OFFSET )
696
subglyph->gps_offset = PFR_NEXT_LONG( p );
701
subglyph->gps_offset = PFR_NEXT_USHORT( p );
712
error = PFR_Err_Invalid_Table;
713
FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" ));
719
pfr_glyph_load_rec( PFR_Glyph glyph,
730
if ( FT_STREAM_SEEK( gps_offset + offset ) ||
731
FT_FRAME_ENTER( size ) )
734
p = (FT_Byte*)stream->cursor;
737
if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND )
739
FT_Int n, old_count, count;
740
FT_GlyphLoader loader = glyph->loader;
741
FT_Outline* base = &loader->base.outline;
744
old_count = glyph->num_subs;
746
/* this is a compound glyph - load it */
747
error = pfr_glyph_load_compound( glyph, p, limit );
754
count = glyph->num_subs - old_count;
756
FT_TRACE4(( "compound glyph with %d elements (offset %lu):\n",
759
/* now, load each individual glyph */
760
for ( n = 0; n < count; n++ )
762
FT_Int i, old_points, num_points;
763
PFR_SubGlyph subglyph;
766
FT_TRACE4(( "subglyph %d:\n", n ));
768
subglyph = glyph->subs + old_count + n;
769
old_points = base->n_points;
771
error = pfr_glyph_load_rec( glyph, stream, gps_offset,
772
subglyph->gps_offset,
773
subglyph->gps_size );
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;
781
/* translate and eventually scale the new glyph points */
782
if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L )
784
FT_Vector* vec = base->points + old_points;
787
for ( i = 0; i < num_points; i++, vec++ )
789
vec->x = FT_MulFix( vec->x, subglyph->x_scale ) +
791
vec->y = FT_MulFix( vec->y, subglyph->y_scale ) +
797
FT_Vector* vec = loader->base.outline.points + old_points;
800
for ( i = 0; i < num_points; i++, vec++ )
802
vec->x += subglyph->x_delta;
803
vec->y += subglyph->y_delta;
807
/* proceed to next sub-glyph */
810
FT_TRACE4(( "end compound glyph with %d elements\n", count ));
814
FT_TRACE4(( "simple glyph (offset %lu)\n", offset ));
816
/* load a simple glyph */
817
error = pfr_glyph_load_simple( glyph, p, limit );
827
FT_LOCAL_DEF( FT_Error )
828
pfr_glyph_load( PFR_Glyph glyph,
834
/* initialize glyph loader */
835
FT_GlyphLoader_Rewind( glyph->loader );
839
/* load the glyph, recursively when needed */
840
return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size );