1
/***************************************************************************/
5
/* FreeType PFR glyph loader (body). */
7
/* Copyright 2002, 2003 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;
62
glyph->num_x_control = 0;
63
glyph->num_y_control = 0;
65
FT_FREE( glyph->subs );
71
glyph->path_begun = 0;
75
/* close current contour, if any */
77
pfr_glyph_close_contour( PFR_Glyph glyph )
79
FT_GlyphLoader loader = glyph->loader;
80
FT_Outline* outline = &loader->current.outline;
84
if ( !glyph->path_begun )
87
/* compute first and last point indices in current glyph outline */
88
last = outline->n_points - 1;
90
if ( outline->n_contours > 0 )
91
first = outline->contours[outline->n_contours - 1];
93
/* if the last point falls on the same location than the first one */
94
/* we need to delete it */
97
FT_Vector* p1 = outline->points + first;
98
FT_Vector* p2 = outline->points + last;
101
if ( p1->x == p2->x && p1->y == p2->y )
108
/* don't add empty contours */
110
outline->contours[outline->n_contours++] = (short)last;
112
glyph->path_begun = 0;
116
/* reset glyph to start the loading of a new glyph */
118
pfr_glyph_start( PFR_Glyph glyph )
120
glyph->path_begun = 0;
125
pfr_glyph_line_to( PFR_Glyph glyph,
128
FT_GlyphLoader loader = glyph->loader;
129
FT_Outline* outline = &loader->current.outline;
133
/* check that we have begun a new path */
134
FT_ASSERT( glyph->path_begun != 0 );
136
error = FT_GlyphLoader_CheckPoints( loader, 1, 0 );
139
FT_UInt n = outline->n_points;
142
outline->points[n] = *to;
143
outline->tags [n] = FT_CURVE_TAG_ON;
153
pfr_glyph_curve_to( PFR_Glyph glyph,
158
FT_GlyphLoader loader = glyph->loader;
159
FT_Outline* outline = &loader->current.outline;
163
/* check that we have begun a new path */
164
FT_ASSERT( glyph->path_begun != 0 );
166
error = FT_GlyphLoader_CheckPoints( loader, 3, 0 );
169
FT_Vector* vec = outline->points + outline->n_points;
170
FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points;
176
tag[0] = FT_CURVE_TAG_CUBIC;
177
tag[1] = FT_CURVE_TAG_CUBIC;
178
tag[2] = FT_CURVE_TAG_ON;
180
outline->n_points = (FT_Short)( outline->n_points + 3 );
188
pfr_glyph_move_to( PFR_Glyph glyph,
191
FT_GlyphLoader loader = glyph->loader;
195
/* close current contour if any */
196
pfr_glyph_close_contour( glyph );
198
/* indicate that a new contour has started */
199
glyph->path_begun = 1;
201
/* check that there is space for a new contour and a new point */
202
error = FT_GlyphLoader_CheckPoints( loader, 1, 1 );
204
/* add new start point */
205
error = pfr_glyph_line_to( glyph, to );
212
pfr_glyph_end( PFR_Glyph glyph )
214
/* close current contour if any */
215
pfr_glyph_close_contour( glyph );
217
/* merge the current glyph into the stack */
218
FT_GlyphLoader_Add( glyph->loader );
222
/*************************************************************************/
223
/*************************************************************************/
225
/***** PFR GLYPH LOADER *****/
227
/*************************************************************************/
228
/*************************************************************************/
231
/* load a simple glyph */
233
pfr_glyph_load_simple( PFR_Glyph glyph,
238
FT_Memory memory = glyph->loader->memory;
239
FT_UInt flags, x_count, y_count, i, count, mask;
244
flags = PFR_NEXT_BYTE( p );
246
/* test for composite glyphs */
247
FT_ASSERT( ( flags & PFR_GLYPH_IS_COMPOUND ) == 0 );
252
if ( flags & PFR_GLYPH_1BYTE_XYCOUNT )
255
count = PFR_NEXT_BYTE( p );
256
x_count = ( count & 15 );
257
y_count = ( count >> 4 );
261
if ( flags & PFR_GLYPH_XCOUNT )
264
x_count = PFR_NEXT_BYTE( p );
267
if ( flags & PFR_GLYPH_YCOUNT )
270
y_count = PFR_NEXT_BYTE( p );
274
count = x_count + y_count;
276
/* re-allocate array when necessary */
277
if ( count > glyph->max_xy_control )
279
FT_UInt new_max = FT_PAD_CEIL( count, 8 );
282
if ( FT_RENEW_ARRAY( glyph->x_control,
283
glyph->max_xy_control,
287
glyph->max_xy_control = new_max;
290
glyph->y_control = glyph->x_control + x_count;
295
for ( i = 0; i < count; i++ )
297
if ( ( i & 7 ) == 0 )
300
mask = PFR_NEXT_BYTE( p );
306
x = PFR_NEXT_SHORT( p );
311
x += PFR_NEXT_BYTE( p );
314
glyph->x_control[i] = x;
319
/* XXX: for now we ignore the secondary stroke and edge definitions */
320
/* since we don't want to support native PFR hinting */
322
if ( flags & PFR_GLYPH_EXTRA_ITEMS )
324
error = pfr_extra_items_skip( &p, limit );
329
pfr_glyph_start( glyph );
331
/* now load a simple glyph */
337
pos[0].x = pos[0].y = 0;
342
FT_Int format, args_format = 0, args_count, n;
345
/***************************************************************/
346
/* read instruction */
349
format = PFR_NEXT_BYTE( p );
351
switch ( format >> 4 )
353
case 0: /* end glyph */
354
FT_TRACE6(( "- end glyph" ));
358
case 1: /* general line operation */
359
FT_TRACE6(( "- general line" ));
362
case 4: /* move to inside contour */
363
FT_TRACE6(( "- move to inside" ));
366
case 5: /* move to outside contour */
367
FT_TRACE6(( "- move to outside" ));
369
args_format = format & 15;
373
case 2: /* horizontal line to */
374
FT_TRACE6(( "- horizontal line to cx.%d", format & 15 ));
376
pos[0].x = glyph->x_control[format & 15];
381
case 3: /* vertical line to */
382
FT_TRACE6(( "- vertical line to cy.%d", format & 15 ));
384
pos[0].y = glyph->y_control[format & 15];
389
case 6: /* horizontal to vertical curve */
390
FT_TRACE6(( "- hv curve " ));
395
case 7: /* vertical to horizontal curve */
396
FT_TRACE6(( "- vh curve" ));
401
default: /* general curve to */
402
FT_TRACE6(( "- general curve" ));
404
args_format = format & 15;
407
/***********************************************************/
408
/* now read arguments */
411
for ( n = 0; n < args_count; n++ )
416
/* read the X argument */
417
switch ( args_format & 3 )
419
case 0: /* 8-bit index */
421
idx = PFR_NEXT_BYTE( p );
422
cur->x = glyph->x_control[idx];
423
FT_TRACE7(( " cx#%d", idx ));
426
case 1: /* 16-bit value */
428
cur->x = PFR_NEXT_SHORT( p );
429
FT_TRACE7(( " x.%d", cur->x ));
432
case 2: /* 8-bit delta */
434
delta = PFR_NEXT_INT8( p );
435
cur->x = pos[3].x + delta;
436
FT_TRACE7(( " dx.%d", delta ));
444
/* read the Y argument */
445
switch ( ( args_format >> 2 ) & 3 )
447
case 0: /* 8-bit index */
449
idx = PFR_NEXT_BYTE( p );
450
cur->y = glyph->y_control[idx];
451
FT_TRACE7(( " cy#%d", idx ));
454
case 1: /* 16-bit absolute value */
456
cur->y = PFR_NEXT_SHORT( p );
457
FT_TRACE7(( " y.%d", cur->y ));
460
case 2: /* 8-bit delta */
462
delta = PFR_NEXT_INT8( p );
463
cur->y = pos[3].y + delta;
464
FT_TRACE7(( " dy.%d", delta ));
472
/* read the additional format flag for the general curve */
473
if ( n == 0 && args_count == 4 )
476
args_format = PFR_NEXT_BYTE( p );
482
/* save the previous point */
489
/***********************************************************/
490
/* finally, execute instruction */
492
switch ( format >> 4 )
494
case 0: /* end glyph => EXIT */
495
pfr_glyph_end( glyph );
498
case 1: /* line operations */
501
error = pfr_glyph_line_to( glyph, pos );
504
case 4: /* move to inside contour */
505
case 5: /* move to outside contour */
506
error = pfr_glyph_move_to( glyph, pos );
509
default: /* curve operations */
510
error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 );
512
Test_Error: /* test error condition */
523
error = PFR_Err_Invalid_Table;
524
FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" ));
529
/* load a composite/compound glyph */
531
pfr_glyph_load_compound( PFR_Glyph glyph,
536
FT_GlyphLoader loader = glyph->loader;
537
FT_Memory memory = loader->memory;
538
PFR_SubGlyph subglyph;
539
FT_UInt flags, i, count, org_count;
544
flags = PFR_NEXT_BYTE( p );
546
/* test for composite glyphs */
547
FT_ASSERT( ( flags & PFR_GLYPH_IS_COMPOUND ) != 0 );
549
count = flags & 0x3F;
551
/* ignore extra items when present */
553
if ( flags & PFR_GLYPH_EXTRA_ITEMS )
555
error = pfr_extra_items_skip( &p, limit );
556
if (error) goto Exit;
559
/* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */
560
/* the PFR format is dumb, using direct file offsets to point to the */
561
/* sub-glyphs (instead of glyph indices). Sigh. */
563
/* For now, we load the list of sub-glyphs into a different array */
564
/* but this will prevent us from using the auto-hinter at its best */
567
org_count = glyph->num_subs;
569
if ( org_count + count > glyph->max_subs )
571
FT_UInt new_max = ( org_count + count + 3 ) & -4;
574
if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) )
577
glyph->max_subs = new_max;
580
subglyph = glyph->subs + org_count;
582
for ( i = 0; i < count; i++, subglyph++ )
591
format = PFR_NEXT_BYTE( p );
593
/* read scale when available */
594
subglyph->x_scale = 0x10000L;
595
if ( format & PFR_SUBGLYPH_XSCALE )
598
subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4;
601
subglyph->y_scale = 0x10000L;
602
if ( format & PFR_SUBGLYPH_YSCALE )
605
subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4;
609
switch ( format & 3 )
613
x_pos = PFR_NEXT_SHORT( p );
618
x_pos += PFR_NEXT_INT8( p );
625
switch ( ( format >> 2 ) & 3 )
629
y_pos = PFR_NEXT_SHORT( p );
634
y_pos += PFR_NEXT_INT8( p );
641
subglyph->x_delta = x_pos;
642
subglyph->y_delta = y_pos;
644
/* read glyph position and size now */
645
if ( format & PFR_SUBGLYPH_2BYTE_SIZE )
648
subglyph->gps_size = PFR_NEXT_USHORT( p );
653
subglyph->gps_size = PFR_NEXT_BYTE( p );
656
if ( format & PFR_SUBGLYPH_3BYTE_OFFSET )
659
subglyph->gps_offset = PFR_NEXT_LONG( p );
664
subglyph->gps_offset = PFR_NEXT_USHORT( p );
674
error = PFR_Err_Invalid_Table;
675
FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" ));
684
pfr_glyph_load_rec( PFR_Glyph glyph,
695
if ( FT_STREAM_SEEK( gps_offset + offset ) ||
696
FT_FRAME_ENTER( size ) )
699
p = (FT_Byte*)stream->cursor;
702
if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND )
704
FT_Int n, old_count, count;
705
FT_GlyphLoader loader = glyph->loader;
706
FT_Outline* base = &loader->base.outline;
709
old_count = glyph->num_subs;
711
/* this is a compound glyph - load it */
712
error = pfr_glyph_load_compound( glyph, p, limit );
719
count = glyph->num_subs - old_count;
721
/* now, load each individual glyph */
722
for ( n = 0; n < count; n++ )
724
FT_Int i, old_points, num_points;
725
PFR_SubGlyph subglyph;
728
subglyph = glyph->subs + old_count + n;
729
old_points = base->n_points;
731
error = pfr_glyph_load_rec( glyph, stream, gps_offset,
732
subglyph->gps_offset,
733
subglyph->gps_size );
737
/* note that `glyph->subs' might have been re-allocated */
738
subglyph = glyph->subs + old_count + n;
739
num_points = base->n_points - old_points;
741
/* translate and eventually scale the new glyph points */
742
if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L )
744
FT_Vector* vec = base->points + old_points;
747
for ( i = 0; i < num_points; i++, vec++ )
749
vec->x = FT_MulFix( vec->x, subglyph->x_scale ) +
751
vec->y = FT_MulFix( vec->y, subglyph->y_scale ) +
757
FT_Vector* vec = loader->base.outline.points + old_points;
760
for ( i = 0; i < num_points; i++, vec++ )
762
vec->x += subglyph->x_delta;
763
vec->y += subglyph->y_delta;
767
/* proceed to next sub-glyph */
772
/* load a simple glyph */
773
error = pfr_glyph_load_simple( glyph, p, limit );
786
FT_LOCAL_DEF( FT_Error )
787
pfr_glyph_load( PFR_Glyph glyph,
793
/* initialize glyph loader */
794
FT_GlyphLoader_Rewind( glyph->loader );
796
/* load the glyph, recursively when needed */
797
return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size );