|
1 /***************************************************************************/ |
|
2 /* */ |
|
3 /* pfrobjs.c */ |
|
4 /* */ |
|
5 /* FreeType PFR object methods (body). */ |
|
6 /* */ |
|
7 /* Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 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 "pfrobjs.h" |
|
20 #include "pfrload.h" |
|
21 #include "pfrgload.h" |
|
22 #include "pfrcmap.h" |
|
23 #include "pfrsbit.h" |
|
24 #include FT_OUTLINE_H |
|
25 #include FT_INTERNAL_DEBUG_H |
|
26 #include FT_TRUETYPE_IDS_H |
|
27 |
|
28 #include "pfrerror.h" |
|
29 |
|
30 #undef FT_COMPONENT |
|
31 #define FT_COMPONENT trace_pfr |
|
32 |
|
33 |
|
34 /*************************************************************************/ |
|
35 /*************************************************************************/ |
|
36 /***** *****/ |
|
37 /***** FACE OBJECT METHODS *****/ |
|
38 /***** *****/ |
|
39 /*************************************************************************/ |
|
40 /*************************************************************************/ |
|
41 |
|
42 FT_LOCAL_DEF( void ) |
|
43 pfr_face_done( FT_Face pfrface ) /* PFR_Face */ |
|
44 { |
|
45 PFR_Face face = (PFR_Face)pfrface; |
|
46 FT_Memory memory; |
|
47 |
|
48 |
|
49 if ( !face ) |
|
50 return; |
|
51 |
|
52 memory = pfrface->driver->root.memory; |
|
53 |
|
54 /* we don't want dangling pointers */ |
|
55 pfrface->family_name = NULL; |
|
56 pfrface->style_name = NULL; |
|
57 |
|
58 /* finalize the physical font record */ |
|
59 pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) ); |
|
60 |
|
61 /* no need to finalize the logical font or the header */ |
|
62 FT_FREE( pfrface->available_sizes ); |
|
63 } |
|
64 |
|
65 |
|
66 FT_LOCAL_DEF( FT_Error ) |
|
67 pfr_face_init( FT_Stream stream, |
|
68 FT_Face pfrface, |
|
69 FT_Int face_index, |
|
70 FT_Int num_params, |
|
71 FT_Parameter* params ) |
|
72 { |
|
73 PFR_Face face = (PFR_Face)pfrface; |
|
74 FT_Error error; |
|
75 |
|
76 FT_UNUSED( num_params ); |
|
77 FT_UNUSED( params ); |
|
78 |
|
79 |
|
80 /* load the header and check it */ |
|
81 error = pfr_header_load( &face->header, stream ); |
|
82 if ( error ) |
|
83 goto Exit; |
|
84 |
|
85 if ( !pfr_header_check( &face->header ) ) |
|
86 { |
|
87 FT_TRACE4(( "pfr_face_init: not a valid PFR font\n" )); |
|
88 error = PFR_Err_Unknown_File_Format; |
|
89 goto Exit; |
|
90 } |
|
91 |
|
92 /* check face index */ |
|
93 { |
|
94 FT_UInt num_faces; |
|
95 |
|
96 |
|
97 error = pfr_log_font_count( stream, |
|
98 face->header.log_dir_offset, |
|
99 &num_faces ); |
|
100 if ( error ) |
|
101 goto Exit; |
|
102 |
|
103 pfrface->num_faces = num_faces; |
|
104 } |
|
105 |
|
106 if ( face_index < 0 ) |
|
107 goto Exit; |
|
108 |
|
109 if ( face_index >= pfrface->num_faces ) |
|
110 { |
|
111 FT_ERROR(( "pfr_face_init: invalid face index\n" )); |
|
112 error = PFR_Err_Invalid_Argument; |
|
113 goto Exit; |
|
114 } |
|
115 |
|
116 /* load the face */ |
|
117 error = pfr_log_font_load( |
|
118 &face->log_font, stream, face_index, |
|
119 face->header.log_dir_offset, |
|
120 FT_BOOL( face->header.phy_font_max_size_high != 0 ) ); |
|
121 if ( error ) |
|
122 goto Exit; |
|
123 |
|
124 /* now load the physical font descriptor */ |
|
125 error = pfr_phy_font_load( &face->phy_font, stream, |
|
126 face->log_font.phys_offset, |
|
127 face->log_font.phys_size ); |
|
128 if ( error ) |
|
129 goto Exit; |
|
130 |
|
131 /* now set up all root face fields */ |
|
132 { |
|
133 PFR_PhyFont phy_font = &face->phy_font; |
|
134 |
|
135 |
|
136 pfrface->face_index = face_index; |
|
137 pfrface->num_glyphs = phy_font->num_chars + 1; |
|
138 pfrface->face_flags = FT_FACE_FLAG_SCALABLE; |
|
139 |
|
140 /* if all characters point to the same gps_offset 0, we */ |
|
141 /* assume that the font only contains bitmaps */ |
|
142 { |
|
143 FT_UInt nn; |
|
144 |
|
145 |
|
146 for ( nn = 0; nn < phy_font->num_chars; nn++ ) |
|
147 if ( phy_font->chars[nn].gps_offset != 0 ) |
|
148 break; |
|
149 |
|
150 if ( nn == phy_font->num_chars ) |
|
151 { |
|
152 if ( phy_font->num_strikes > 0 ) |
|
153 pfrface->face_flags = 0; /* not scalable */ |
|
154 else |
|
155 { |
|
156 FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" )); |
|
157 error = PFR_Err_Invalid_File_Format; |
|
158 goto Exit; |
|
159 } |
|
160 } |
|
161 } |
|
162 |
|
163 if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 ) |
|
164 pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; |
|
165 |
|
166 if ( phy_font->flags & PFR_PHY_VERTICAL ) |
|
167 pfrface->face_flags |= FT_FACE_FLAG_VERTICAL; |
|
168 else |
|
169 pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL; |
|
170 |
|
171 if ( phy_font->num_strikes > 0 ) |
|
172 pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES; |
|
173 |
|
174 if ( phy_font->num_kern_pairs > 0 ) |
|
175 pfrface->face_flags |= FT_FACE_FLAG_KERNING; |
|
176 |
|
177 /* If no family name was found in the "undocumented" auxiliary |
|
178 * data, use the font ID instead. This sucks but is better than |
|
179 * nothing. |
|
180 */ |
|
181 pfrface->family_name = phy_font->family_name; |
|
182 if ( pfrface->family_name == NULL ) |
|
183 pfrface->family_name = phy_font->font_id; |
|
184 |
|
185 /* note that the style name can be NULL in certain PFR fonts, |
|
186 * probably meaning "Regular" |
|
187 */ |
|
188 pfrface->style_name = phy_font->style_name; |
|
189 |
|
190 pfrface->num_fixed_sizes = 0; |
|
191 pfrface->available_sizes = 0; |
|
192 |
|
193 pfrface->bbox = phy_font->bbox; |
|
194 pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution; |
|
195 pfrface->ascender = (FT_Short) phy_font->bbox.yMax; |
|
196 pfrface->descender = (FT_Short) phy_font->bbox.yMin; |
|
197 |
|
198 pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 ); |
|
199 if ( pfrface->height < pfrface->ascender - pfrface->descender ) |
|
200 pfrface->height = (FT_Short)(pfrface->ascender - pfrface->descender); |
|
201 |
|
202 if ( phy_font->num_strikes > 0 ) |
|
203 { |
|
204 FT_UInt n, count = phy_font->num_strikes; |
|
205 FT_Bitmap_Size* size; |
|
206 PFR_Strike strike; |
|
207 FT_Memory memory = pfrface->stream->memory; |
|
208 |
|
209 |
|
210 if ( FT_NEW_ARRAY( pfrface->available_sizes, count ) ) |
|
211 goto Exit; |
|
212 |
|
213 size = pfrface->available_sizes; |
|
214 strike = phy_font->strikes; |
|
215 for ( n = 0; n < count; n++, size++, strike++ ) |
|
216 { |
|
217 size->height = (FT_UShort)strike->y_ppm; |
|
218 size->width = (FT_UShort)strike->x_ppm; |
|
219 size->size = strike->y_ppm << 6; |
|
220 size->x_ppem = strike->x_ppm << 6; |
|
221 size->y_ppem = strike->y_ppm << 6; |
|
222 } |
|
223 pfrface->num_fixed_sizes = count; |
|
224 } |
|
225 |
|
226 /* now compute maximum advance width */ |
|
227 if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 ) |
|
228 pfrface->max_advance_width = (FT_Short)phy_font->standard_advance; |
|
229 else |
|
230 { |
|
231 FT_Int max = 0; |
|
232 FT_UInt count = phy_font->num_chars; |
|
233 PFR_Char gchar = phy_font->chars; |
|
234 |
|
235 |
|
236 for ( ; count > 0; count--, gchar++ ) |
|
237 { |
|
238 if ( max < gchar->advance ) |
|
239 max = gchar->advance; |
|
240 } |
|
241 |
|
242 pfrface->max_advance_width = (FT_Short)max; |
|
243 } |
|
244 |
|
245 pfrface->max_advance_height = pfrface->height; |
|
246 |
|
247 pfrface->underline_position = (FT_Short)( -pfrface->units_per_EM / 10 ); |
|
248 pfrface->underline_thickness = (FT_Short)( pfrface->units_per_EM / 30 ); |
|
249 |
|
250 /* create charmap */ |
|
251 { |
|
252 FT_CharMapRec charmap; |
|
253 |
|
254 |
|
255 charmap.face = pfrface; |
|
256 charmap.platform_id = TT_PLATFORM_MICROSOFT; |
|
257 charmap.encoding_id = TT_MS_ID_UNICODE_CS; |
|
258 charmap.encoding = FT_ENCODING_UNICODE; |
|
259 |
|
260 error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL ); |
|
261 |
|
262 #if 0 |
|
263 /* Select default charmap */ |
|
264 if ( pfrface->num_charmaps ) |
|
265 pfrface->charmap = pfrface->charmaps[0]; |
|
266 #endif |
|
267 } |
|
268 |
|
269 /* check whether we've loaded any kerning pairs */ |
|
270 if ( phy_font->num_kern_pairs ) |
|
271 pfrface->face_flags |= FT_FACE_FLAG_KERNING; |
|
272 } |
|
273 |
|
274 Exit: |
|
275 return error; |
|
276 } |
|
277 |
|
278 |
|
279 /*************************************************************************/ |
|
280 /*************************************************************************/ |
|
281 /***** *****/ |
|
282 /***** SLOT OBJECT METHOD *****/ |
|
283 /***** *****/ |
|
284 /*************************************************************************/ |
|
285 /*************************************************************************/ |
|
286 |
|
287 FT_LOCAL_DEF( FT_Error ) |
|
288 pfr_slot_init( FT_GlyphSlot pfrslot ) /* PFR_Slot */ |
|
289 { |
|
290 PFR_Slot slot = (PFR_Slot)pfrslot; |
|
291 FT_GlyphLoader loader = pfrslot->internal->loader; |
|
292 |
|
293 |
|
294 pfr_glyph_init( &slot->glyph, loader ); |
|
295 |
|
296 return 0; |
|
297 } |
|
298 |
|
299 |
|
300 FT_LOCAL_DEF( void ) |
|
301 pfr_slot_done( FT_GlyphSlot pfrslot ) /* PFR_Slot */ |
|
302 { |
|
303 PFR_Slot slot = (PFR_Slot)pfrslot; |
|
304 |
|
305 |
|
306 pfr_glyph_done( &slot->glyph ); |
|
307 } |
|
308 |
|
309 |
|
310 FT_LOCAL_DEF( FT_Error ) |
|
311 pfr_slot_load( FT_GlyphSlot pfrslot, /* PFR_Slot */ |
|
312 FT_Size pfrsize, /* PFR_Size */ |
|
313 FT_UInt gindex, |
|
314 FT_Int32 load_flags ) |
|
315 { |
|
316 PFR_Slot slot = (PFR_Slot)pfrslot; |
|
317 PFR_Size size = (PFR_Size)pfrsize; |
|
318 FT_Error error; |
|
319 PFR_Face face = (PFR_Face)pfrslot->face; |
|
320 PFR_Char gchar; |
|
321 FT_Outline* outline = &pfrslot->outline; |
|
322 FT_ULong gps_offset; |
|
323 |
|
324 |
|
325 if ( gindex > 0 ) |
|
326 gindex--; |
|
327 |
|
328 if ( !face || gindex >= face->phy_font.num_chars ) |
|
329 { |
|
330 error = PFR_Err_Invalid_Argument; |
|
331 goto Exit; |
|
332 } |
|
333 |
|
334 /* try to load an embedded bitmap */ |
|
335 if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 ) |
|
336 { |
|
337 error = pfr_slot_load_bitmap( slot, size, gindex ); |
|
338 if ( error == 0 ) |
|
339 goto Exit; |
|
340 } |
|
341 |
|
342 if ( load_flags & FT_LOAD_SBITS_ONLY ) |
|
343 { |
|
344 error = PFR_Err_Invalid_Argument; |
|
345 goto Exit; |
|
346 } |
|
347 |
|
348 gchar = face->phy_font.chars + gindex; |
|
349 pfrslot->format = FT_GLYPH_FORMAT_OUTLINE; |
|
350 outline->n_points = 0; |
|
351 outline->n_contours = 0; |
|
352 gps_offset = face->header.gps_section_offset; |
|
353 |
|
354 /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */ |
|
355 error = pfr_glyph_load( &slot->glyph, face->root.stream, |
|
356 gps_offset, gchar->gps_offset, gchar->gps_size ); |
|
357 |
|
358 if ( !error ) |
|
359 { |
|
360 FT_BBox cbox; |
|
361 FT_Glyph_Metrics* metrics = &pfrslot->metrics; |
|
362 FT_Pos advance; |
|
363 FT_Int em_metrics, em_outline; |
|
364 FT_Bool scaling; |
|
365 |
|
366 |
|
367 scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); |
|
368 |
|
369 /* copy outline data */ |
|
370 *outline = slot->glyph.loader->base.outline; |
|
371 |
|
372 outline->flags &= ~FT_OUTLINE_OWNER; |
|
373 outline->flags |= FT_OUTLINE_REVERSE_FILL; |
|
374 |
|
375 if ( size && pfrsize->metrics.y_ppem < 24 ) |
|
376 outline->flags |= FT_OUTLINE_HIGH_PRECISION; |
|
377 |
|
378 /* compute the advance vector */ |
|
379 metrics->horiAdvance = 0; |
|
380 metrics->vertAdvance = 0; |
|
381 |
|
382 advance = gchar->advance; |
|
383 em_metrics = face->phy_font.metrics_resolution; |
|
384 em_outline = face->phy_font.outline_resolution; |
|
385 |
|
386 if ( em_metrics != em_outline ) |
|
387 advance = FT_MulDiv( advance, em_outline, em_metrics ); |
|
388 |
|
389 if ( face->phy_font.flags & PFR_PHY_VERTICAL ) |
|
390 metrics->vertAdvance = advance; |
|
391 else |
|
392 metrics->horiAdvance = advance; |
|
393 |
|
394 pfrslot->linearHoriAdvance = metrics->horiAdvance; |
|
395 pfrslot->linearVertAdvance = metrics->vertAdvance; |
|
396 |
|
397 /* make-up vertical metrics(?) */ |
|
398 metrics->vertBearingX = 0; |
|
399 metrics->vertBearingY = 0; |
|
400 |
|
401 #if 0 /* some fonts seem to be broken here! */ |
|
402 |
|
403 /* Apply the font matrix, if any. */ |
|
404 /* TODO: Test existing fonts with unusual matrix */ |
|
405 /* whether we have to adjust Units per EM. */ |
|
406 { |
|
407 FT_Matrix font_matrix; |
|
408 |
|
409 |
|
410 font_matrix.xx = face->log_font.matrix[0] << 8; |
|
411 font_matrix.yx = face->log_font.matrix[1] << 8; |
|
412 font_matrix.xy = face->log_font.matrix[2] << 8; |
|
413 font_matrix.yy = face->log_font.matrix[3] << 8; |
|
414 |
|
415 FT_Outline_Transform( outline, &font_matrix ); |
|
416 } |
|
417 #endif |
|
418 |
|
419 /* scale when needed */ |
|
420 if ( scaling ) |
|
421 { |
|
422 FT_Int n; |
|
423 FT_Fixed x_scale = pfrsize->metrics.x_scale; |
|
424 FT_Fixed y_scale = pfrsize->metrics.y_scale; |
|
425 FT_Vector* vec = outline->points; |
|
426 |
|
427 |
|
428 /* scale outline points */ |
|
429 for ( n = 0; n < outline->n_points; n++, vec++ ) |
|
430 { |
|
431 vec->x = FT_MulFix( vec->x, x_scale ); |
|
432 vec->y = FT_MulFix( vec->y, y_scale ); |
|
433 } |
|
434 |
|
435 /* scale the advance */ |
|
436 metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); |
|
437 metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); |
|
438 } |
|
439 |
|
440 /* compute the rest of the metrics */ |
|
441 FT_Outline_Get_CBox( outline, &cbox ); |
|
442 |
|
443 metrics->width = cbox.xMax - cbox.xMin; |
|
444 metrics->height = cbox.yMax - cbox.yMin; |
|
445 metrics->horiBearingX = cbox.xMin; |
|
446 metrics->horiBearingY = cbox.yMax - metrics->height; |
|
447 } |
|
448 |
|
449 Exit: |
|
450 return error; |
|
451 } |
|
452 |
|
453 |
|
454 /*************************************************************************/ |
|
455 /*************************************************************************/ |
|
456 /***** *****/ |
|
457 /***** KERNING METHOD *****/ |
|
458 /***** *****/ |
|
459 /*************************************************************************/ |
|
460 /*************************************************************************/ |
|
461 |
|
462 FT_LOCAL_DEF( FT_Error ) |
|
463 pfr_face_get_kerning( FT_Face pfrface, /* PFR_Face */ |
|
464 FT_UInt glyph1, |
|
465 FT_UInt glyph2, |
|
466 FT_Vector* kerning ) |
|
467 { |
|
468 PFR_Face face = (PFR_Face)pfrface; |
|
469 FT_Error error = PFR_Err_Ok; |
|
470 PFR_PhyFont phy_font = &face->phy_font; |
|
471 FT_UInt32 code1, code2, pair; |
|
472 |
|
473 |
|
474 kerning->x = 0; |
|
475 kerning->y = 0; |
|
476 |
|
477 if ( glyph1 > 0 ) |
|
478 glyph1--; |
|
479 |
|
480 if ( glyph2 > 0 ) |
|
481 glyph2--; |
|
482 |
|
483 /* convert glyph indices to character codes */ |
|
484 if ( glyph1 > phy_font->num_chars || |
|
485 glyph2 > phy_font->num_chars ) |
|
486 goto Exit; |
|
487 |
|
488 code1 = phy_font->chars[glyph1].char_code; |
|
489 code2 = phy_font->chars[glyph2].char_code; |
|
490 pair = PFR_KERN_INDEX( code1, code2 ); |
|
491 |
|
492 /* now search the list of kerning items */ |
|
493 { |
|
494 PFR_KernItem item = phy_font->kern_items; |
|
495 FT_Stream stream = pfrface->stream; |
|
496 |
|
497 |
|
498 for ( ; item; item = item->next ) |
|
499 { |
|
500 if ( pair >= item->pair1 && pair <= item->pair2 ) |
|
501 goto FoundPair; |
|
502 } |
|
503 goto Exit; |
|
504 |
|
505 FoundPair: /* we found an item, now parse it and find the value if any */ |
|
506 if ( FT_STREAM_SEEK( item->offset ) || |
|
507 FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) |
|
508 goto Exit; |
|
509 |
|
510 { |
|
511 FT_UInt count = item->pair_count; |
|
512 FT_UInt size = item->pair_size; |
|
513 FT_UInt power = (FT_UInt)ft_highpow2( (FT_UInt32)count ); |
|
514 FT_UInt probe = power * size; |
|
515 FT_UInt extra = count - power; |
|
516 FT_Byte* base = stream->cursor; |
|
517 FT_Bool twobytes = FT_BOOL( item->flags & 1 ); |
|
518 FT_Bool twobyte_adj = FT_BOOL( item->flags & 2 ); |
|
519 FT_Byte* p; |
|
520 FT_UInt32 cpair; |
|
521 |
|
522 |
|
523 if ( extra > 0 ) |
|
524 { |
|
525 p = base + extra * size; |
|
526 |
|
527 if ( twobytes ) |
|
528 cpair = FT_NEXT_ULONG( p ); |
|
529 else |
|
530 cpair = PFR_NEXT_KPAIR( p ); |
|
531 |
|
532 if ( cpair == pair ) |
|
533 goto Found; |
|
534 |
|
535 if ( cpair < pair ) |
|
536 { |
|
537 if ( twobyte_adj ) |
|
538 p += 2; |
|
539 else |
|
540 p++; |
|
541 base = p; |
|
542 } |
|
543 } |
|
544 |
|
545 while ( probe > size ) |
|
546 { |
|
547 probe >>= 1; |
|
548 p = base + probe; |
|
549 |
|
550 if ( twobytes ) |
|
551 cpair = FT_NEXT_ULONG( p ); |
|
552 else |
|
553 cpair = PFR_NEXT_KPAIR( p ); |
|
554 |
|
555 if ( cpair == pair ) |
|
556 goto Found; |
|
557 |
|
558 if ( cpair < pair ) |
|
559 base += probe; |
|
560 } |
|
561 |
|
562 p = base; |
|
563 |
|
564 if ( twobytes ) |
|
565 cpair = FT_NEXT_ULONG( p ); |
|
566 else |
|
567 cpair = PFR_NEXT_KPAIR( p ); |
|
568 |
|
569 if ( cpair == pair ) |
|
570 { |
|
571 FT_Int value; |
|
572 |
|
573 |
|
574 Found: |
|
575 if ( twobyte_adj ) |
|
576 value = FT_PEEK_SHORT( p ); |
|
577 else |
|
578 value = p[0]; |
|
579 |
|
580 kerning->x = item->base_adj + value; |
|
581 } |
|
582 } |
|
583 |
|
584 FT_FRAME_EXIT(); |
|
585 } |
|
586 |
|
587 Exit: |
|
588 return error; |
|
589 } |
|
590 |
|
591 /* END */ |