1 /***************************************************************************/
5 /* FreeType PFR object methods (body). */
7 /* Copyright 2002-2018 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 /***************************************************************************/
25 #include FT_INTERNAL_DEBUG_H
26 #include FT_INTERNAL_CALC_H
27 #include FT_TRUETYPE_IDS_H
32 #define FT_COMPONENT trace_pfr
35 /*************************************************************************/
36 /*************************************************************************/
38 /***** FACE OBJECT METHODS *****/
40 /*************************************************************************/
41 /*************************************************************************/
44 pfr_face_done( FT_Face pfrface
) /* PFR_Face */
46 PFR_Face face
= (PFR_Face
)pfrface
;
53 memory
= pfrface
->driver
->root
.memory
;
55 /* we don't want dangling pointers */
56 pfrface
->family_name
= NULL
;
57 pfrface
->style_name
= NULL
;
59 /* finalize the physical font record */
60 pfr_phy_font_done( &face
->phy_font
, FT_FACE_MEMORY( face
) );
62 /* no need to finalize the logical font or the header */
63 FT_FREE( pfrface
->available_sizes
);
67 FT_LOCAL_DEF( FT_Error
)
68 pfr_face_init( FT_Stream stream
,
72 FT_Parameter
* params
)
74 PFR_Face face
= (PFR_Face
)pfrface
;
77 FT_UNUSED( num_params
);
81 FT_TRACE2(( "PFR driver\n" ));
83 /* load the header and check it */
84 error
= pfr_header_load( &face
->header
, stream
);
88 if ( !pfr_header_check( &face
->header
) )
90 FT_TRACE2(( " not a PFR font\n" ));
91 error
= FT_THROW( Unknown_File_Format
);
95 /* check face index */
100 error
= pfr_log_font_count( stream
,
101 face
->header
.log_dir_offset
,
106 pfrface
->num_faces
= num_faces
;
109 if ( face_index
< 0 )
112 if ( ( face_index
& 0xFFFF ) >= pfrface
->num_faces
)
114 FT_ERROR(( "pfr_face_init: invalid face index\n" ));
115 error
= FT_THROW( Invalid_Argument
);
120 error
= pfr_log_font_load(
123 (FT_UInt
)( face_index
& 0xFFFF ),
124 face
->header
.log_dir_offset
,
125 FT_BOOL( face
->header
.phy_font_max_size_high
!= 0 ) );
129 /* now load the physical font descriptor */
130 error
= pfr_phy_font_load( &face
->phy_font
, stream
,
131 face
->log_font
.phys_offset
,
132 face
->log_font
.phys_size
);
136 /* now set up all root face fields */
138 PFR_PhyFont phy_font
= &face
->phy_font
;
141 pfrface
->face_index
= face_index
& 0xFFFF;
142 pfrface
->num_glyphs
= (FT_Long
)phy_font
->num_chars
+ 1;
144 pfrface
->face_flags
|= FT_FACE_FLAG_SCALABLE
;
146 /* if gps_offset == 0 for all characters, we */
147 /* assume that the font only contains bitmaps */
152 for ( nn
= 0; nn
< phy_font
->num_chars
; nn
++ )
153 if ( phy_font
->chars
[nn
].gps_offset
!= 0 )
156 if ( nn
== phy_font
->num_chars
)
158 if ( phy_font
->num_strikes
> 0 )
159 pfrface
->face_flags
= 0; /* not scalable */
162 FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" ));
163 error
= FT_THROW( Invalid_File_Format
);
169 if ( ( phy_font
->flags
& PFR_PHY_PROPORTIONAL
) == 0 )
170 pfrface
->face_flags
|= FT_FACE_FLAG_FIXED_WIDTH
;
172 if ( phy_font
->flags
& PFR_PHY_VERTICAL
)
173 pfrface
->face_flags
|= FT_FACE_FLAG_VERTICAL
;
175 pfrface
->face_flags
|= FT_FACE_FLAG_HORIZONTAL
;
177 if ( phy_font
->num_strikes
> 0 )
178 pfrface
->face_flags
|= FT_FACE_FLAG_FIXED_SIZES
;
180 if ( phy_font
->num_kern_pairs
> 0 )
181 pfrface
->face_flags
|= FT_FACE_FLAG_KERNING
;
183 /* If no family name was found in the `undocumented' auxiliary
184 * data, use the font ID instead. This sucks but is better than
187 pfrface
->family_name
= phy_font
->family_name
;
188 if ( !pfrface
->family_name
)
189 pfrface
->family_name
= phy_font
->font_id
;
191 /* note that the style name can be NULL in certain PFR fonts,
192 * probably meaning `Regular'
194 pfrface
->style_name
= phy_font
->style_name
;
196 pfrface
->num_fixed_sizes
= 0;
197 pfrface
->available_sizes
= NULL
;
199 pfrface
->bbox
= phy_font
->bbox
;
200 pfrface
->units_per_EM
= (FT_UShort
)phy_font
->outline_resolution
;
201 pfrface
->ascender
= (FT_Short
) phy_font
->bbox
.yMax
;
202 pfrface
->descender
= (FT_Short
) phy_font
->bbox
.yMin
;
204 pfrface
->height
= (FT_Short
)( ( pfrface
->units_per_EM
* 12 ) / 10 );
205 if ( pfrface
->height
< pfrface
->ascender
- pfrface
->descender
)
206 pfrface
->height
= (FT_Short
)(pfrface
->ascender
- pfrface
->descender
);
208 if ( phy_font
->num_strikes
> 0 )
210 FT_UInt n
, count
= phy_font
->num_strikes
;
211 FT_Bitmap_Size
* size
;
213 FT_Memory memory
= pfrface
->stream
->memory
;
216 if ( FT_NEW_ARRAY( pfrface
->available_sizes
, count
) )
219 size
= pfrface
->available_sizes
;
220 strike
= phy_font
->strikes
;
221 for ( n
= 0; n
< count
; n
++, size
++, strike
++ )
223 size
->height
= (FT_Short
)strike
->y_ppm
;
224 size
->width
= (FT_Short
)strike
->x_ppm
;
225 size
->size
= (FT_Pos
)( strike
->y_ppm
<< 6 );
226 size
->x_ppem
= (FT_Pos
)( strike
->x_ppm
<< 6 );
227 size
->y_ppem
= (FT_Pos
)( strike
->y_ppm
<< 6 );
229 pfrface
->num_fixed_sizes
= (FT_Int
)count
;
232 /* now compute maximum advance width */
233 if ( ( phy_font
->flags
& PFR_PHY_PROPORTIONAL
) == 0 )
234 pfrface
->max_advance_width
= (FT_Short
)phy_font
->standard_advance
;
238 FT_UInt count
= phy_font
->num_chars
;
239 PFR_Char gchar
= phy_font
->chars
;
242 for ( ; count
> 0; count
--, gchar
++ )
244 if ( max
< gchar
->advance
)
245 max
= gchar
->advance
;
248 pfrface
->max_advance_width
= (FT_Short
)max
;
251 pfrface
->max_advance_height
= pfrface
->height
;
253 pfrface
->underline_position
= (FT_Short
)( -pfrface
->units_per_EM
/ 10 );
254 pfrface
->underline_thickness
= (FT_Short
)( pfrface
->units_per_EM
/ 30 );
258 FT_CharMapRec charmap
;
261 charmap
.face
= pfrface
;
262 charmap
.platform_id
= TT_PLATFORM_MICROSOFT
;
263 charmap
.encoding_id
= TT_MS_ID_UNICODE_CS
;
264 charmap
.encoding
= FT_ENCODING_UNICODE
;
266 error
= FT_CMap_New( &pfr_cmap_class_rec
, NULL
, &charmap
, NULL
);
269 /* check whether we have loaded any kerning pairs */
270 if ( phy_font
->num_kern_pairs
)
271 pfrface
->face_flags
|= FT_FACE_FLAG_KERNING
;
279 /*************************************************************************/
280 /*************************************************************************/
282 /***** SLOT OBJECT METHOD *****/
284 /*************************************************************************/
285 /*************************************************************************/
287 FT_LOCAL_DEF( FT_Error
)
288 pfr_slot_init( FT_GlyphSlot pfrslot
) /* PFR_Slot */
290 PFR_Slot slot
= (PFR_Slot
)pfrslot
;
291 FT_GlyphLoader loader
= pfrslot
->internal
->loader
;
294 pfr_glyph_init( &slot
->glyph
, loader
);
301 pfr_slot_done( FT_GlyphSlot pfrslot
) /* PFR_Slot */
303 PFR_Slot slot
= (PFR_Slot
)pfrslot
;
306 pfr_glyph_done( &slot
->glyph
);
310 FT_LOCAL_DEF( FT_Error
)
311 pfr_slot_load( FT_GlyphSlot pfrslot
, /* PFR_Slot */
312 FT_Size pfrsize
, /* PFR_Size */
314 FT_Int32 load_flags
)
316 PFR_Slot slot
= (PFR_Slot
)pfrslot
;
317 PFR_Size size
= (PFR_Size
)pfrsize
;
319 PFR_Face face
= (PFR_Face
)pfrslot
->face
;
321 FT_Outline
* outline
= &pfrslot
->outline
;
325 FT_TRACE1(( "pfr_slot_load: glyph index %d\n", gindex
));
330 if ( !face
|| gindex
>= face
->phy_font
.num_chars
)
332 error
= FT_THROW( Invalid_Argument
);
336 /* try to load an embedded bitmap */
337 if ( ( load_flags
& ( FT_LOAD_NO_SCALE
| FT_LOAD_NO_BITMAP
) ) == 0 )
339 error
= pfr_slot_load_bitmap(
343 ( load_flags
& FT_LOAD_BITMAP_METRICS_ONLY
) != 0 );
348 if ( load_flags
& FT_LOAD_SBITS_ONLY
)
350 error
= FT_THROW( Invalid_Argument
);
354 gchar
= face
->phy_font
.chars
+ gindex
;
355 pfrslot
->format
= FT_GLYPH_FORMAT_OUTLINE
;
356 outline
->n_points
= 0;
357 outline
->n_contours
= 0;
358 gps_offset
= face
->header
.gps_section_offset
;
360 /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
361 error
= pfr_glyph_load( &slot
->glyph
, face
->root
.stream
,
362 gps_offset
, gchar
->gps_offset
, gchar
->gps_size
);
367 FT_Glyph_Metrics
* metrics
= &pfrslot
->metrics
;
369 FT_UInt em_metrics
, em_outline
;
373 scaling
= FT_BOOL( ( load_flags
& FT_LOAD_NO_SCALE
) == 0 );
375 /* copy outline data */
376 *outline
= slot
->glyph
.loader
->base
.outline
;
378 outline
->flags
&= ~FT_OUTLINE_OWNER
;
379 outline
->flags
|= FT_OUTLINE_REVERSE_FILL
;
381 if ( size
&& pfrsize
->metrics
.y_ppem
< 24 )
382 outline
->flags
|= FT_OUTLINE_HIGH_PRECISION
;
384 /* compute the advance vector */
385 metrics
->horiAdvance
= 0;
386 metrics
->vertAdvance
= 0;
388 advance
= gchar
->advance
;
389 em_metrics
= face
->phy_font
.metrics_resolution
;
390 em_outline
= face
->phy_font
.outline_resolution
;
392 if ( em_metrics
!= em_outline
)
393 advance
= FT_MulDiv( advance
,
395 (FT_Long
)em_metrics
);
397 if ( face
->phy_font
.flags
& PFR_PHY_VERTICAL
)
398 metrics
->vertAdvance
= advance
;
400 metrics
->horiAdvance
= advance
;
402 pfrslot
->linearHoriAdvance
= metrics
->horiAdvance
;
403 pfrslot
->linearVertAdvance
= metrics
->vertAdvance
;
405 /* make up vertical metrics(?) */
406 metrics
->vertBearingX
= 0;
407 metrics
->vertBearingY
= 0;
409 #if 0 /* some fonts seem to be broken here! */
411 /* Apply the font matrix, if any. */
412 /* TODO: Test existing fonts with unusual matrix */
413 /* whether we have to adjust Units per EM. */
415 FT_Matrix font_matrix
;
418 font_matrix
.xx
= face
->log_font
.matrix
[0] << 8;
419 font_matrix
.yx
= face
->log_font
.matrix
[1] << 8;
420 font_matrix
.xy
= face
->log_font
.matrix
[2] << 8;
421 font_matrix
.yy
= face
->log_font
.matrix
[3] << 8;
423 FT_Outline_Transform( outline
, &font_matrix
);
427 /* scale when needed */
431 FT_Fixed x_scale
= pfrsize
->metrics
.x_scale
;
432 FT_Fixed y_scale
= pfrsize
->metrics
.y_scale
;
433 FT_Vector
* vec
= outline
->points
;
436 /* scale outline points */
437 for ( n
= 0; n
< outline
->n_points
; n
++, vec
++ )
439 vec
->x
= FT_MulFix( vec
->x
, x_scale
);
440 vec
->y
= FT_MulFix( vec
->y
, y_scale
);
443 /* scale the advance */
444 metrics
->horiAdvance
= FT_MulFix( metrics
->horiAdvance
, x_scale
);
445 metrics
->vertAdvance
= FT_MulFix( metrics
->vertAdvance
, y_scale
);
448 /* compute the rest of the metrics */
449 FT_Outline_Get_CBox( outline
, &cbox
);
451 metrics
->width
= cbox
.xMax
- cbox
.xMin
;
452 metrics
->height
= cbox
.yMax
- cbox
.yMin
;
453 metrics
->horiBearingX
= cbox
.xMin
;
454 metrics
->horiBearingY
= cbox
.yMax
- metrics
->height
;
462 /*************************************************************************/
463 /*************************************************************************/
465 /***** KERNING METHOD *****/
467 /*************************************************************************/
468 /*************************************************************************/
470 FT_LOCAL_DEF( FT_Error
)
471 pfr_face_get_kerning( FT_Face pfrface
, /* PFR_Face */
476 PFR_Face face
= (PFR_Face
)pfrface
;
477 FT_Error error
= FT_Err_Ok
;
478 PFR_PhyFont phy_font
= &face
->phy_font
;
479 FT_UInt32 code1
, code2
, pair
;
491 /* convert glyph indices to character codes */
492 if ( glyph1
> phy_font
->num_chars
||
493 glyph2
> phy_font
->num_chars
)
496 code1
= phy_font
->chars
[glyph1
].char_code
;
497 code2
= phy_font
->chars
[glyph2
].char_code
;
498 pair
= PFR_KERN_INDEX( code1
, code2
);
500 /* now search the list of kerning items */
502 PFR_KernItem item
= phy_font
->kern_items
;
503 FT_Stream stream
= pfrface
->stream
;
506 for ( ; item
; item
= item
->next
)
508 if ( pair
>= item
->pair1
&& pair
<= item
->pair2
)
513 FoundPair
: /* we found an item, now parse it and find the value if any */
514 if ( FT_STREAM_SEEK( item
->offset
) ||
515 FT_FRAME_ENTER( item
->pair_count
* item
->pair_size
) )
519 FT_UInt count
= item
->pair_count
;
520 FT_UInt size
= item
->pair_size
;
521 FT_UInt power
= 1 << FT_MSB( count
);
522 FT_UInt probe
= power
* size
;
523 FT_UInt extra
= count
- power
;
524 FT_Byte
* base
= stream
->cursor
;
525 FT_Bool twobytes
= FT_BOOL( item
->flags
& PFR_KERN_2BYTE_CHAR
);
526 FT_Bool twobyte_adj
= FT_BOOL( item
->flags
& PFR_KERN_2BYTE_ADJ
);
533 p
= base
+ extra
* size
;
536 cpair
= FT_NEXT_ULONG( p
);
538 cpair
= PFR_NEXT_KPAIR( p
);
553 while ( probe
> size
)
559 cpair
= FT_NEXT_ULONG( p
);
561 cpair
= PFR_NEXT_KPAIR( p
);
573 cpair
= FT_NEXT_ULONG( p
);
575 cpair
= PFR_NEXT_KPAIR( p
);
584 value
= FT_PEEK_SHORT( p
);
588 kerning
->x
= item
->base_adj
+ value
;