OLD | NEW |
| (Empty) |
1 /***************************************************************************/ | |
2 /* */ | |
3 /* ftobjs.c */ | |
4 /* */ | |
5 /* The FreeType private base classes (body). */ | |
6 /* */ | |
7 /* Copyright 1996-2013 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 "../../include/ft2build.h" | |
20 #include "../../include/freetype/ftlist.h" | |
21 #include "../../include/freetype/ftoutln.h" | |
22 #include "../../include/freetype/internal/ftvalid.h" | |
23 #include "../../include/freetype/internal/ftobjs.h" | |
24 #include "../../include/freetype/internal/ftdebug.h" | |
25 #include "../../include/freetype/internal/ftrfork.h" | |
26 #include "../../include/freetype/internal/ftstream.h" | |
27 #include "../../include/freetype/internal/sfnt.h" /* for SFNT_Load_Table_Func
*/ | |
28 #include "../../include/freetype/tttables.h" | |
29 #include "../../include/freetype/tttags.h" | |
30 #include "../../include/freetype/ttnameid.h" | |
31 | |
32 #include "../../include/freetype/internal/services/svprop.h" | |
33 #include "../../include/freetype/internal/services/svsfnt.h" | |
34 #include "../../include/freetype/internal/services/svpostnm.h" | |
35 #include "../../include/freetype/internal/services/svgldict.h" | |
36 #include "../../include/freetype/internal/services/svttcmap.h" | |
37 #include "../../include/freetype/internal/services/svkern.h" | |
38 #include "../../include/freetype/internal/services/svtteng.h" | |
39 | |
40 #ifdef FT_CONFIG_OPTION_MAC_FONTS | |
41 #include "ftbase.h" | |
42 #endif | |
43 | |
44 | |
45 #ifdef FT_DEBUG_LEVEL_TRACE | |
46 | |
47 #include "../../include/freetype/ftbitmap.h" | |
48 | |
49 #if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ | |
50 /* We disable the warning `conversion from XXX to YYY, */ | |
51 /* possible loss of data' in order to compile cleanly with */ | |
52 /* the maximum level of warnings: `md5.c' is non-FreeType */ | |
53 /* code, and it gets used during development builds only. */ | |
54 #pragma warning( push ) | |
55 #pragma warning( disable : 4244 ) | |
56 #endif /* _MSC_VER */ | |
57 | |
58 /* it's easiest to include `md5.c' directly */ | |
59 #define free md5_free /* suppress a shadow warning */ | |
60 #include "md5.c" | |
61 #undef free | |
62 | |
63 #if defined( _MSC_VER ) | |
64 #pragma warning( pop ) | |
65 #endif | |
66 | |
67 #endif /* FT_DEBUG_LEVEL_TRACE */ | |
68 | |
69 | |
70 #define GRID_FIT_METRICS | |
71 | |
72 | |
73 FT_BASE_DEF( FT_Pointer ) | |
74 ft_service_list_lookup( FT_ServiceDesc service_descriptors, | |
75 const char* service_id ) | |
76 { | |
77 FT_Pointer result = NULL; | |
78 FT_ServiceDesc desc = service_descriptors; | |
79 | |
80 | |
81 if ( desc && service_id ) | |
82 { | |
83 for ( ; desc->serv_id != NULL; desc++ ) | |
84 { | |
85 if ( ft_strcmp( desc->serv_id, service_id ) == 0 ) | |
86 { | |
87 result = (FT_Pointer)desc->serv_data; | |
88 break; | |
89 } | |
90 } | |
91 } | |
92 | |
93 return result; | |
94 } | |
95 | |
96 | |
97 FT_BASE_DEF( void ) | |
98 ft_validator_init( FT_Validator valid, | |
99 const FT_Byte* base, | |
100 const FT_Byte* limit, | |
101 FT_ValidationLevel level ) | |
102 { | |
103 valid->base = base; | |
104 valid->limit = limit; | |
105 valid->level = level; | |
106 valid->error = FT_Err_Ok; | |
107 } | |
108 | |
109 | |
110 FT_BASE_DEF( FT_Int ) | |
111 ft_validator_run( FT_Validator valid ) | |
112 { | |
113 /* This function doesn't work! None should call it. */ | |
114 FT_UNUSED( valid ); | |
115 | |
116 return -1; | |
117 } | |
118 | |
119 | |
120 FT_BASE_DEF( void ) | |
121 ft_validator_error( FT_Validator valid, | |
122 FT_Error error ) | |
123 { | |
124 /* since the cast below also disables the compiler's */ | |
125 /* type check, we introduce a dummy variable, which */ | |
126 /* will be optimized away */ | |
127 volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer; | |
128 | |
129 | |
130 valid->error = error; | |
131 | |
132 /* throw away volatileness; use `jump_buffer' or the */ | |
133 /* compiler may warn about an unused local variable */ | |
134 ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 ); | |
135 } | |
136 | |
137 | |
138 /*************************************************************************/ | |
139 /*************************************************************************/ | |
140 /*************************************************************************/ | |
141 /**** ****/ | |
142 /**** ****/ | |
143 /**** S T R E A M ****/ | |
144 /**** ****/ | |
145 /**** ****/ | |
146 /*************************************************************************/ | |
147 /*************************************************************************/ | |
148 /*************************************************************************/ | |
149 | |
150 | |
151 /* create a new input stream from an FT_Open_Args structure */ | |
152 /* */ | |
153 FT_BASE_DEF( FT_Error ) | |
154 FT_Stream_New( FT_Library library, | |
155 const FT_Open_Args* args, | |
156 FT_Stream *astream ) | |
157 { | |
158 FT_Error error; | |
159 FT_Memory memory; | |
160 FT_Stream stream = NULL; | |
161 | |
162 | |
163 *astream = 0; | |
164 | |
165 if ( !library ) | |
166 return FT_THROW( Invalid_Library_Handle ); | |
167 | |
168 if ( !args ) | |
169 return FT_THROW( Invalid_Argument ); | |
170 | |
171 memory = library->memory; | |
172 | |
173 if ( FT_NEW( stream ) ) | |
174 goto Exit; | |
175 | |
176 stream->memory = memory; | |
177 | |
178 if ( args->flags & FT_OPEN_MEMORY ) | |
179 { | |
180 /* create a memory-based stream */ | |
181 FT_Stream_OpenMemory( stream, | |
182 (const FT_Byte*)args->memory_base, | |
183 args->memory_size ); | |
184 } | |
185 | |
186 #ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT | |
187 | |
188 else if ( args->flags & FT_OPEN_PATHNAME ) | |
189 { | |
190 /* create a normal system stream */ | |
191 error = FT_Stream_Open( stream, args->pathname ); | |
192 stream->pathname.pointer = args->pathname; | |
193 } | |
194 else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream ) | |
195 { | |
196 /* use an existing, user-provided stream */ | |
197 | |
198 /* in this case, we do not need to allocate a new stream object */ | |
199 /* since the caller is responsible for closing it himself */ | |
200 FT_FREE( stream ); | |
201 stream = args->stream; | |
202 } | |
203 | |
204 #endif | |
205 | |
206 else | |
207 error = FT_THROW( Invalid_Argument ); | |
208 | |
209 if ( error ) | |
210 FT_FREE( stream ); | |
211 else | |
212 stream->memory = memory; /* just to be certain */ | |
213 | |
214 *astream = stream; | |
215 | |
216 Exit: | |
217 return error; | |
218 } | |
219 | |
220 | |
221 FT_BASE_DEF( void ) | |
222 FT_Stream_Free( FT_Stream stream, | |
223 FT_Int external ) | |
224 { | |
225 if ( stream ) | |
226 { | |
227 FT_Memory memory = stream->memory; | |
228 | |
229 | |
230 FT_Stream_Close( stream ); | |
231 | |
232 if ( !external ) | |
233 FT_FREE( stream ); | |
234 } | |
235 } | |
236 | |
237 | |
238 /*************************************************************************/ | |
239 /* */ | |
240 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
241 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
242 /* messages during execution. */ | |
243 /* */ | |
244 #undef FT_COMPONENT | |
245 #define FT_COMPONENT trace_objs | |
246 | |
247 | |
248 /*************************************************************************/ | |
249 /*************************************************************************/ | |
250 /*************************************************************************/ | |
251 /**** ****/ | |
252 /**** ****/ | |
253 /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/ | |
254 /**** ****/ | |
255 /**** ****/ | |
256 /*************************************************************************/ | |
257 /*************************************************************************/ | |
258 /*************************************************************************/ | |
259 | |
260 | |
261 static FT_Error | |
262 ft_glyphslot_init( FT_GlyphSlot slot ) | |
263 { | |
264 FT_Driver driver = slot->face->driver; | |
265 FT_Driver_Class clazz = driver->clazz; | |
266 FT_Memory memory = driver->root.memory; | |
267 FT_Error error = FT_Err_Ok; | |
268 FT_Slot_Internal internal = NULL; | |
269 | |
270 | |
271 slot->library = driver->root.library; | |
272 | |
273 if ( FT_NEW( internal ) ) | |
274 goto Exit; | |
275 | |
276 slot->internal = internal; | |
277 | |
278 if ( FT_DRIVER_USES_OUTLINES( driver ) ) | |
279 error = FT_GlyphLoader_New( memory, &internal->loader ); | |
280 | |
281 if ( !error && clazz->init_slot ) | |
282 error = clazz->init_slot( slot ); | |
283 | |
284 Exit: | |
285 return error; | |
286 } | |
287 | |
288 | |
289 FT_BASE_DEF( void ) | |
290 ft_glyphslot_free_bitmap( FT_GlyphSlot slot ) | |
291 { | |
292 if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) | |
293 { | |
294 FT_Memory memory = FT_FACE_MEMORY( slot->face ); | |
295 | |
296 | |
297 FT_FREE( slot->bitmap.buffer ); | |
298 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; | |
299 } | |
300 else | |
301 { | |
302 /* assume that the bitmap buffer was stolen or not */ | |
303 /* allocated from the heap */ | |
304 slot->bitmap.buffer = NULL; | |
305 } | |
306 } | |
307 | |
308 | |
309 FT_BASE_DEF( void ) | |
310 ft_glyphslot_set_bitmap( FT_GlyphSlot slot, | |
311 FT_Byte* buffer ) | |
312 { | |
313 ft_glyphslot_free_bitmap( slot ); | |
314 | |
315 slot->bitmap.buffer = buffer; | |
316 | |
317 FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 ); | |
318 } | |
319 | |
320 | |
321 FT_BASE_DEF( FT_Error ) | |
322 ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, | |
323 FT_ULong size ) | |
324 { | |
325 FT_Memory memory = FT_FACE_MEMORY( slot->face ); | |
326 FT_Error error; | |
327 | |
328 | |
329 if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) | |
330 FT_FREE( slot->bitmap.buffer ); | |
331 else | |
332 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; | |
333 | |
334 (void)FT_ALLOC( slot->bitmap.buffer, size ); | |
335 return error; | |
336 } | |
337 | |
338 | |
339 static void | |
340 ft_glyphslot_clear( FT_GlyphSlot slot ) | |
341 { | |
342 /* free bitmap if needed */ | |
343 ft_glyphslot_free_bitmap( slot ); | |
344 | |
345 /* clear all public fields in the glyph slot */ | |
346 FT_ZERO( &slot->metrics ); | |
347 FT_ZERO( &slot->outline ); | |
348 | |
349 slot->bitmap.width = 0; | |
350 slot->bitmap.rows = 0; | |
351 slot->bitmap.pitch = 0; | |
352 slot->bitmap.pixel_mode = 0; | |
353 /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */ | |
354 | |
355 slot->bitmap_left = 0; | |
356 slot->bitmap_top = 0; | |
357 slot->num_subglyphs = 0; | |
358 slot->subglyphs = 0; | |
359 slot->control_data = 0; | |
360 slot->control_len = 0; | |
361 slot->other = 0; | |
362 slot->format = FT_GLYPH_FORMAT_NONE; | |
363 | |
364 slot->linearHoriAdvance = 0; | |
365 slot->linearVertAdvance = 0; | |
366 slot->lsb_delta = 0; | |
367 slot->rsb_delta = 0; | |
368 } | |
369 | |
370 | |
371 static void | |
372 ft_glyphslot_done( FT_GlyphSlot slot ) | |
373 { | |
374 FT_Driver driver = slot->face->driver; | |
375 FT_Driver_Class clazz = driver->clazz; | |
376 FT_Memory memory = driver->root.memory; | |
377 | |
378 | |
379 if ( clazz->done_slot ) | |
380 clazz->done_slot( slot ); | |
381 | |
382 /* free bitmap buffer if needed */ | |
383 ft_glyphslot_free_bitmap( slot ); | |
384 | |
385 /* slot->internal might be NULL in out-of-memory situations */ | |
386 if ( slot->internal ) | |
387 { | |
388 /* free glyph loader */ | |
389 if ( FT_DRIVER_USES_OUTLINES( driver ) ) | |
390 { | |
391 FT_GlyphLoader_Done( slot->internal->loader ); | |
392 slot->internal->loader = 0; | |
393 } | |
394 | |
395 FT_FREE( slot->internal ); | |
396 } | |
397 } | |
398 | |
399 | |
400 /* documentation is in ftobjs.h */ | |
401 | |
402 FT_BASE_DEF( FT_Error ) | |
403 FT_New_GlyphSlot( FT_Face face, | |
404 FT_GlyphSlot *aslot ) | |
405 { | |
406 FT_Error error; | |
407 FT_Driver driver; | |
408 FT_Driver_Class clazz; | |
409 FT_Memory memory; | |
410 FT_GlyphSlot slot = NULL; | |
411 | |
412 | |
413 if ( !face || !face->driver ) | |
414 return FT_THROW( Invalid_Argument ); | |
415 | |
416 driver = face->driver; | |
417 clazz = driver->clazz; | |
418 memory = driver->root.memory; | |
419 | |
420 FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" )); | |
421 if ( !FT_ALLOC( slot, clazz->slot_object_size ) ) | |
422 { | |
423 slot->face = face; | |
424 | |
425 error = ft_glyphslot_init( slot ); | |
426 if ( error ) | |
427 { | |
428 ft_glyphslot_done( slot ); | |
429 FT_FREE( slot ); | |
430 goto Exit; | |
431 } | |
432 | |
433 slot->next = face->glyph; | |
434 face->glyph = slot; | |
435 | |
436 if ( aslot ) | |
437 *aslot = slot; | |
438 } | |
439 else if ( aslot ) | |
440 *aslot = 0; | |
441 | |
442 | |
443 Exit: | |
444 FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error )); | |
445 return error; | |
446 } | |
447 | |
448 | |
449 /* documentation is in ftobjs.h */ | |
450 | |
451 FT_BASE_DEF( void ) | |
452 FT_Done_GlyphSlot( FT_GlyphSlot slot ) | |
453 { | |
454 if ( slot ) | |
455 { | |
456 FT_Driver driver = slot->face->driver; | |
457 FT_Memory memory = driver->root.memory; | |
458 FT_GlyphSlot prev; | |
459 FT_GlyphSlot cur; | |
460 | |
461 | |
462 /* Remove slot from its parent face's list */ | |
463 prev = NULL; | |
464 cur = slot->face->glyph; | |
465 | |
466 while ( cur ) | |
467 { | |
468 if ( cur == slot ) | |
469 { | |
470 if ( !prev ) | |
471 slot->face->glyph = cur->next; | |
472 else | |
473 prev->next = cur->next; | |
474 | |
475 /* finalize client-specific data */ | |
476 if ( slot->generic.finalizer ) | |
477 slot->generic.finalizer( slot ); | |
478 | |
479 ft_glyphslot_done( slot ); | |
480 FT_FREE( slot ); | |
481 break; | |
482 } | |
483 prev = cur; | |
484 cur = cur->next; | |
485 } | |
486 } | |
487 } | |
488 | |
489 | |
490 /* documentation is in freetype.h */ | |
491 | |
492 FT_EXPORT_DEF( void ) | |
493 FT_Set_Transform( FT_Face face, | |
494 FT_Matrix* matrix, | |
495 FT_Vector* delta ) | |
496 { | |
497 FT_Face_Internal internal; | |
498 | |
499 | |
500 if ( !face ) | |
501 return; | |
502 | |
503 internal = face->internal; | |
504 | |
505 internal->transform_flags = 0; | |
506 | |
507 if ( !matrix ) | |
508 { | |
509 internal->transform_matrix.xx = 0x10000L; | |
510 internal->transform_matrix.xy = 0; | |
511 internal->transform_matrix.yx = 0; | |
512 internal->transform_matrix.yy = 0x10000L; | |
513 matrix = &internal->transform_matrix; | |
514 } | |
515 else | |
516 internal->transform_matrix = *matrix; | |
517 | |
518 /* set transform_flags bit flag 0 if `matrix' isn't the identity */ | |
519 if ( ( matrix->xy | matrix->yx ) || | |
520 matrix->xx != 0x10000L || | |
521 matrix->yy != 0x10000L ) | |
522 internal->transform_flags |= 1; | |
523 | |
524 if ( !delta ) | |
525 { | |
526 internal->transform_delta.x = 0; | |
527 internal->transform_delta.y = 0; | |
528 delta = &internal->transform_delta; | |
529 } | |
530 else | |
531 internal->transform_delta = *delta; | |
532 | |
533 /* set transform_flags bit flag 1 if `delta' isn't the null vector */ | |
534 if ( delta->x | delta->y ) | |
535 internal->transform_flags |= 2; | |
536 } | |
537 | |
538 | |
539 static FT_Renderer | |
540 ft_lookup_glyph_renderer( FT_GlyphSlot slot ); | |
541 | |
542 | |
543 #ifdef GRID_FIT_METRICS | |
544 static void | |
545 ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot, | |
546 FT_Bool vertical ) | |
547 { | |
548 FT_Glyph_Metrics* metrics = &slot->metrics; | |
549 FT_Pos right, bottom; | |
550 | |
551 | |
552 if ( vertical ) | |
553 { | |
554 metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); | |
555 metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY ); | |
556 | |
557 right = FT_PIX_CEIL( metrics->vertBearingX + metrics->width ); | |
558 bottom = FT_PIX_CEIL( metrics->vertBearingY + metrics->height ); | |
559 | |
560 metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); | |
561 metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); | |
562 | |
563 metrics->width = right - metrics->vertBearingX; | |
564 metrics->height = bottom - metrics->vertBearingY; | |
565 } | |
566 else | |
567 { | |
568 metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); | |
569 metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); | |
570 | |
571 right = FT_PIX_CEIL ( metrics->horiBearingX + metrics->width ); | |
572 bottom = FT_PIX_FLOOR( metrics->horiBearingY - metrics->height ); | |
573 | |
574 metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); | |
575 metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY ); | |
576 | |
577 metrics->width = right - metrics->horiBearingX; | |
578 metrics->height = metrics->horiBearingY - bottom; | |
579 } | |
580 | |
581 metrics->horiAdvance = FT_PIX_ROUND( metrics->horiAdvance ); | |
582 metrics->vertAdvance = FT_PIX_ROUND( metrics->vertAdvance ); | |
583 } | |
584 #endif /* GRID_FIT_METRICS */ | |
585 | |
586 | |
587 /* documentation is in freetype.h */ | |
588 | |
589 FT_EXPORT_DEF( FT_Error ) | |
590 FT_Load_Glyph( FT_Face face, | |
591 FT_UInt glyph_index, | |
592 FT_Int32 load_flags ) | |
593 { | |
594 FT_Error error; | |
595 FT_Driver driver; | |
596 FT_GlyphSlot slot; | |
597 FT_Library library; | |
598 FT_Bool autohint = FALSE; | |
599 FT_Module hinter; | |
600 TT_Face ttface = (TT_Face)face; | |
601 | |
602 | |
603 if ( !face || !face->size || !face->glyph ) | |
604 return FT_THROW( Invalid_Face_Handle ); | |
605 | |
606 /* The validity test for `glyph_index' is performed by the */ | |
607 /* font drivers. */ | |
608 | |
609 slot = face->glyph; | |
610 ft_glyphslot_clear( slot ); | |
611 | |
612 driver = face->driver; | |
613 library = driver->root.library; | |
614 hinter = library->auto_hinter; | |
615 | |
616 /* resolve load flags dependencies */ | |
617 | |
618 if ( load_flags & FT_LOAD_NO_RECURSE ) | |
619 load_flags |= FT_LOAD_NO_SCALE | | |
620 FT_LOAD_IGNORE_TRANSFORM; | |
621 | |
622 if ( load_flags & FT_LOAD_NO_SCALE ) | |
623 { | |
624 load_flags |= FT_LOAD_NO_HINTING | | |
625 FT_LOAD_NO_BITMAP; | |
626 | |
627 load_flags &= ~FT_LOAD_RENDER; | |
628 } | |
629 | |
630 /* | |
631 * Determine whether we need to auto-hint or not. | |
632 * The general rules are: | |
633 * | |
634 * - Do only auto-hinting if we have a hinter module, a scalable font | |
635 * format dealing with outlines, and no transforms except simple | |
636 * slants and/or rotations by integer multiples of 90 degrees. | |
637 * | |
638 * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't | |
639 * have a native font hinter. | |
640 * | |
641 * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't | |
642 * any hinting bytecode in the TrueType/OpenType font. | |
643 * | |
644 * - Exception: The font is `tricky' and requires the native hinter to | |
645 * load properly. | |
646 */ | |
647 | |
648 if ( hinter && | |
649 !( load_flags & FT_LOAD_NO_HINTING ) && | |
650 !( load_flags & FT_LOAD_NO_AUTOHINT ) && | |
651 FT_DRIVER_IS_SCALABLE( driver ) && | |
652 FT_DRIVER_USES_OUTLINES( driver ) && | |
653 !FT_IS_TRICKY( face ) && | |
654 ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) || | |
655 ( face->internal->transform_matrix.yx == 0 && | |
656 face->internal->transform_matrix.xx != 0 ) || | |
657 ( face->internal->transform_matrix.xx == 0 && | |
658 face->internal->transform_matrix.yx != 0 ) ) ) | |
659 { | |
660 if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) || | |
661 !FT_DRIVER_HAS_HINTER( driver ) ) | |
662 autohint = TRUE; | |
663 else | |
664 { | |
665 FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); | |
666 | |
667 | |
668 /* the check for `num_locations' assures that we actually */ | |
669 /* test for instructions in a TTF and not in a CFF-based OTF */ | |
670 if ( mode == FT_RENDER_MODE_LIGHT || | |
671 face->internal->ignore_unpatented_hinter || | |
672 ( FT_IS_SFNT( face ) && | |
673 ttface->num_locations && | |
674 ttface->max_profile.maxSizeOfInstructions == 0 ) ) | |
675 autohint = TRUE; | |
676 } | |
677 } | |
678 | |
679 if ( autohint ) | |
680 { | |
681 FT_AutoHinter_Interface hinting; | |
682 | |
683 | |
684 /* try to load embedded bitmaps first if available */ | |
685 /* */ | |
686 /* XXX: This is really a temporary hack that should disappear */ | |
687 /* promptly with FreeType 2.1! */ | |
688 /* */ | |
689 if ( FT_HAS_FIXED_SIZES( face ) && | |
690 ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) | |
691 { | |
692 error = driver->clazz->load_glyph( slot, face->size, | |
693 glyph_index, | |
694 load_flags | FT_LOAD_SBITS_ONLY ); | |
695 | |
696 if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP ) | |
697 goto Load_Ok; | |
698 } | |
699 | |
700 { | |
701 FT_Face_Internal internal = face->internal; | |
702 FT_Int transform_flags = internal->transform_flags; | |
703 | |
704 | |
705 /* since the auto-hinter calls FT_Load_Glyph by itself, */ | |
706 /* make sure that glyphs aren't transformed */ | |
707 internal->transform_flags = 0; | |
708 | |
709 /* load auto-hinted outline */ | |
710 hinting = (FT_AutoHinter_Interface)hinter->clazz->module_interface; | |
711 | |
712 error = hinting->load_glyph( (FT_AutoHinter)hinter, | |
713 slot, face->size, | |
714 glyph_index, load_flags ); | |
715 | |
716 internal->transform_flags = transform_flags; | |
717 } | |
718 } | |
719 else | |
720 { | |
721 error = driver->clazz->load_glyph( slot, | |
722 face->size, | |
723 glyph_index, | |
724 load_flags ); | |
725 if ( error ) | |
726 goto Exit; | |
727 | |
728 if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) | |
729 { | |
730 /* check that the loaded outline is correct */ | |
731 error = FT_Outline_Check( &slot->outline ); | |
732 if ( error ) | |
733 goto Exit; | |
734 | |
735 #ifdef GRID_FIT_METRICS | |
736 if ( !( load_flags & FT_LOAD_NO_HINTING ) ) | |
737 ft_glyphslot_grid_fit_metrics( slot, | |
738 FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) ); | |
739 #endif | |
740 } | |
741 } | |
742 | |
743 Load_Ok: | |
744 /* compute the advance */ | |
745 if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) | |
746 { | |
747 slot->advance.x = 0; | |
748 slot->advance.y = slot->metrics.vertAdvance; | |
749 } | |
750 else | |
751 { | |
752 slot->advance.x = slot->metrics.horiAdvance; | |
753 slot->advance.y = 0; | |
754 } | |
755 | |
756 /* compute the linear advance in 16.16 pixels */ | |
757 if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 && | |
758 ( FT_IS_SCALABLE( face ) ) ) | |
759 { | |
760 FT_Size_Metrics* metrics = &face->size->metrics; | |
761 | |
762 | |
763 /* it's tricky! */ | |
764 slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance, | |
765 metrics->x_scale, 64 ); | |
766 | |
767 slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance, | |
768 metrics->y_scale, 64 ); | |
769 } | |
770 | |
771 if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 ) | |
772 { | |
773 FT_Face_Internal internal = face->internal; | |
774 | |
775 | |
776 /* now, transform the glyph image if needed */ | |
777 if ( internal->transform_flags ) | |
778 { | |
779 /* get renderer */ | |
780 FT_Renderer renderer = ft_lookup_glyph_renderer( slot ); | |
781 | |
782 | |
783 if ( renderer ) | |
784 error = renderer->clazz->transform_glyph( | |
785 renderer, slot, | |
786 &internal->transform_matrix, | |
787 &internal->transform_delta ); | |
788 else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) | |
789 { | |
790 /* apply `standard' transformation if no renderer is available */ | |
791 if ( internal->transform_flags & 1 ) | |
792 FT_Outline_Transform( &slot->outline, | |
793 &internal->transform_matrix ); | |
794 | |
795 if ( internal->transform_flags & 2 ) | |
796 FT_Outline_Translate( &slot->outline, | |
797 internal->transform_delta.x, | |
798 internal->transform_delta.y ); | |
799 } | |
800 | |
801 /* transform advance */ | |
802 FT_Vector_Transform( &slot->advance, &internal->transform_matrix ); | |
803 } | |
804 } | |
805 | |
806 FT_TRACE5(( " x advance: %d\n" , slot->advance.x )); | |
807 FT_TRACE5(( " y advance: %d\n" , slot->advance.y )); | |
808 | |
809 FT_TRACE5(( " linear x advance: %d\n" , slot->linearHoriAdvance )); | |
810 FT_TRACE5(( " linear y advance: %d\n" , slot->linearVertAdvance )); | |
811 | |
812 /* do we need to render the image now? */ | |
813 if ( !error && | |
814 slot->format != FT_GLYPH_FORMAT_BITMAP && | |
815 slot->format != FT_GLYPH_FORMAT_COMPOSITE && | |
816 load_flags & FT_LOAD_RENDER ) | |
817 { | |
818 FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); | |
819 | |
820 | |
821 if ( mode == FT_RENDER_MODE_NORMAL && | |
822 (load_flags & FT_LOAD_MONOCHROME ) ) | |
823 mode = FT_RENDER_MODE_MONO; | |
824 | |
825 error = FT_Render_Glyph( slot, mode ); | |
826 } | |
827 | |
828 Exit: | |
829 return error; | |
830 } | |
831 | |
832 | |
833 /* documentation is in freetype.h */ | |
834 | |
835 FT_EXPORT_DEF( FT_Error ) | |
836 FT_Load_Char( FT_Face face, | |
837 FT_ULong char_code, | |
838 FT_Int32 load_flags ) | |
839 { | |
840 FT_UInt glyph_index; | |
841 | |
842 | |
843 if ( !face ) | |
844 return FT_THROW( Invalid_Face_Handle ); | |
845 | |
846 glyph_index = (FT_UInt)char_code; | |
847 if ( face->charmap ) | |
848 glyph_index = FT_Get_Char_Index( face, char_code ); | |
849 | |
850 return FT_Load_Glyph( face, glyph_index, load_flags ); | |
851 } | |
852 | |
853 | |
854 /* destructor for sizes list */ | |
855 static void | |
856 destroy_size( FT_Memory memory, | |
857 FT_Size size, | |
858 FT_Driver driver ) | |
859 { | |
860 /* finalize client-specific data */ | |
861 if ( size->generic.finalizer ) | |
862 size->generic.finalizer( size ); | |
863 | |
864 /* finalize format-specific stuff */ | |
865 if ( driver->clazz->done_size ) | |
866 driver->clazz->done_size( size ); | |
867 | |
868 FT_FREE( size->internal ); | |
869 FT_FREE( size ); | |
870 } | |
871 | |
872 | |
873 static void | |
874 ft_cmap_done_internal( FT_CMap cmap ); | |
875 | |
876 | |
877 static void | |
878 destroy_charmaps( FT_Face face, | |
879 FT_Memory memory ) | |
880 { | |
881 FT_Int n; | |
882 | |
883 | |
884 if ( !face ) | |
885 return; | |
886 | |
887 for ( n = 0; n < face->num_charmaps; n++ ) | |
888 { | |
889 FT_CMap cmap = FT_CMAP( face->charmaps[n] ); | |
890 | |
891 | |
892 ft_cmap_done_internal( cmap ); | |
893 | |
894 face->charmaps[n] = NULL; | |
895 } | |
896 | |
897 FT_FREE( face->charmaps ); | |
898 face->num_charmaps = 0; | |
899 } | |
900 | |
901 | |
902 /* destructor for faces list */ | |
903 static void | |
904 destroy_face( FT_Memory memory, | |
905 FT_Face face, | |
906 FT_Driver driver ) | |
907 { | |
908 FT_Driver_Class clazz = driver->clazz; | |
909 | |
910 | |
911 /* discard auto-hinting data */ | |
912 if ( face->autohint.finalizer ) | |
913 face->autohint.finalizer( face->autohint.data ); | |
914 | |
915 /* Discard glyph slots for this face. */ | |
916 /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */ | |
917 while ( face->glyph ) | |
918 FT_Done_GlyphSlot( face->glyph ); | |
919 | |
920 /* discard all sizes for this face */ | |
921 FT_List_Finalize( &face->sizes_list, | |
922 (FT_List_Destructor)destroy_size, | |
923 memory, | |
924 driver ); | |
925 face->size = 0; | |
926 | |
927 /* now discard client data */ | |
928 if ( face->generic.finalizer ) | |
929 face->generic.finalizer( face ); | |
930 | |
931 /* discard charmaps */ | |
932 destroy_charmaps( face, memory ); | |
933 | |
934 /* finalize format-specific stuff */ | |
935 if ( clazz->done_face ) | |
936 clazz->done_face( face ); | |
937 | |
938 /* close the stream for this face if needed */ | |
939 FT_Stream_Free( | |
940 face->stream, | |
941 ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); | |
942 | |
943 face->stream = 0; | |
944 | |
945 /* get rid of it */ | |
946 if ( face->internal ) | |
947 { | |
948 FT_FREE( face->internal ); | |
949 } | |
950 FT_FREE( face ); | |
951 } | |
952 | |
953 | |
954 static void | |
955 Destroy_Driver( FT_Driver driver ) | |
956 { | |
957 FT_List_Finalize( &driver->faces_list, | |
958 (FT_List_Destructor)destroy_face, | |
959 driver->root.memory, | |
960 driver ); | |
961 | |
962 /* check whether we need to drop the driver's glyph loader */ | |
963 if ( FT_DRIVER_USES_OUTLINES( driver ) ) | |
964 FT_GlyphLoader_Done( driver->glyph_loader ); | |
965 } | |
966 | |
967 | |
968 /*************************************************************************/ | |
969 /* */ | |
970 /* <Function> */ | |
971 /* find_unicode_charmap */ | |
972 /* */ | |
973 /* <Description> */ | |
974 /* This function finds a Unicode charmap, if there is one. */ | |
975 /* And if there is more than one, it tries to favour the more */ | |
976 /* extensive one, i.e., one that supports UCS-4 against those which */ | |
977 /* are limited to the BMP (said UCS-2 encoding.) */ | |
978 /* */ | |
979 /* This function is called from open_face() (just below), and also */ | |
980 /* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). */ | |
981 /* */ | |
982 static FT_Error | |
983 find_unicode_charmap( FT_Face face ) | |
984 { | |
985 FT_CharMap* first; | |
986 FT_CharMap* cur; | |
987 | |
988 | |
989 /* caller should have already checked that `face' is valid */ | |
990 FT_ASSERT( face ); | |
991 | |
992 first = face->charmaps; | |
993 | |
994 if ( !first ) | |
995 return FT_THROW( Invalid_CharMap_Handle ); | |
996 | |
997 /* | |
998 * The original TrueType specification(s) only specified charmap | |
999 * formats that are capable of mapping 8 or 16 bit character codes to | |
1000 * glyph indices. | |
1001 * | |
1002 * However, recent updates to the Apple and OpenType specifications | |
1003 * introduced new formats that are capable of mapping 32-bit character | |
1004 * codes as well. And these are already used on some fonts, mainly to | |
1005 * map non-BMP Asian ideographs as defined in Unicode. | |
1006 * | |
1007 * For compatibility purposes, these fonts generally come with | |
1008 * *several* Unicode charmaps: | |
1009 * | |
1010 * - One of them in the "old" 16-bit format, that cannot access | |
1011 * all glyphs in the font. | |
1012 * | |
1013 * - Another one in the "new" 32-bit format, that can access all | |
1014 * the glyphs. | |
1015 * | |
1016 * This function has been written to always favor a 32-bit charmap | |
1017 * when found. Otherwise, a 16-bit one is returned when found. | |
1018 */ | |
1019 | |
1020 /* Since the `interesting' table, with IDs (3,10), is normally the */ | |
1021 /* last one, we loop backwards. This loses with type1 fonts with */ | |
1022 /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */ | |
1023 /* chars (.01% ?), and this is the same about 99.99% of the time! */ | |
1024 | |
1025 cur = first + face->num_charmaps; /* points after the last one */ | |
1026 | |
1027 for ( ; --cur >= first; ) | |
1028 { | |
1029 if ( cur[0]->encoding == FT_ENCODING_UNICODE ) | |
1030 { | |
1031 /* XXX If some new encodings to represent UCS-4 are added, */ | |
1032 /* they should be added here. */ | |
1033 if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT && | |
1034 cur[0]->encoding_id == TT_MS_ID_UCS_4 ) || | |
1035 ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && | |
1036 cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) ) | |
1037 { | |
1038 #ifdef FT_MAX_CHARMAP_CACHEABLE | |
1039 if ( cur - first > FT_MAX_CHARMAP_CACHEABLE ) | |
1040 { | |
1041 FT_ERROR(( "find_unicode_charmap: UCS-4 cmap is found " | |
1042 "at too late position (%d)\n", cur - first )); | |
1043 continue; | |
1044 } | |
1045 #endif | |
1046 face->charmap = cur[0]; | |
1047 return FT_Err_Ok; | |
1048 } | |
1049 } | |
1050 } | |
1051 | |
1052 /* We do not have any UCS-4 charmap. */ | |
1053 /* Do the loop again and search for UCS-2 charmaps. */ | |
1054 cur = first + face->num_charmaps; | |
1055 | |
1056 for ( ; --cur >= first; ) | |
1057 { | |
1058 if ( cur[0]->encoding == FT_ENCODING_UNICODE ) | |
1059 { | |
1060 #ifdef FT_MAX_CHARMAP_CACHEABLE | |
1061 if ( cur - first > FT_MAX_CHARMAP_CACHEABLE ) | |
1062 { | |
1063 FT_ERROR(( "find_unicode_charmap: UCS-2 cmap is found " | |
1064 "at too late position (%d)\n", cur - first )); | |
1065 continue; | |
1066 } | |
1067 #endif | |
1068 face->charmap = cur[0]; | |
1069 return FT_Err_Ok; | |
1070 } | |
1071 } | |
1072 | |
1073 return FT_THROW( Invalid_CharMap_Handle ); | |
1074 } | |
1075 | |
1076 | |
1077 /*************************************************************************/ | |
1078 /* */ | |
1079 /* <Function> */ | |
1080 /* find_variant_selector_charmap */ | |
1081 /* */ | |
1082 /* <Description> */ | |
1083 /* This function finds the variant selector charmap, if there is one. */ | |
1084 /* There can only be one (platform=0, specific=5, format=14). */ | |
1085 /* */ | |
1086 static FT_CharMap | |
1087 find_variant_selector_charmap( FT_Face face ) | |
1088 { | |
1089 FT_CharMap* first; | |
1090 FT_CharMap* end; | |
1091 FT_CharMap* cur; | |
1092 | |
1093 | |
1094 /* caller should have already checked that `face' is valid */ | |
1095 FT_ASSERT( face ); | |
1096 | |
1097 first = face->charmaps; | |
1098 | |
1099 if ( !first ) | |
1100 return NULL; | |
1101 | |
1102 end = first + face->num_charmaps; /* points after the last one */ | |
1103 | |
1104 for ( cur = first; cur < end; ++cur ) | |
1105 { | |
1106 if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && | |
1107 cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR && | |
1108 FT_Get_CMap_Format( cur[0] ) == 14 ) | |
1109 { | |
1110 #ifdef FT_MAX_CHARMAP_CACHEABLE | |
1111 if ( cur - first > FT_MAX_CHARMAP_CACHEABLE ) | |
1112 { | |
1113 FT_ERROR(( "find_unicode_charmap: UVS cmap is found " | |
1114 "at too late position (%d)\n", cur - first )); | |
1115 continue; | |
1116 } | |
1117 #endif | |
1118 return cur[0]; | |
1119 } | |
1120 } | |
1121 | |
1122 return NULL; | |
1123 } | |
1124 | |
1125 | |
1126 /*************************************************************************/ | |
1127 /* */ | |
1128 /* <Function> */ | |
1129 /* open_face */ | |
1130 /* */ | |
1131 /* <Description> */ | |
1132 /* This function does some work for FT_Open_Face(). */ | |
1133 /* */ | |
1134 static FT_Error | |
1135 open_face( FT_Driver driver, | |
1136 FT_Stream stream, | |
1137 FT_Long face_index, | |
1138 FT_Int num_params, | |
1139 FT_Parameter* params, | |
1140 FT_Face *aface ) | |
1141 { | |
1142 FT_Memory memory; | |
1143 FT_Driver_Class clazz; | |
1144 FT_Face face = 0; | |
1145 FT_Error error, error2; | |
1146 FT_Face_Internal internal = NULL; | |
1147 | |
1148 | |
1149 clazz = driver->clazz; | |
1150 memory = driver->root.memory; | |
1151 | |
1152 /* allocate the face object and perform basic initialization */ | |
1153 if ( FT_ALLOC( face, clazz->face_object_size ) ) | |
1154 goto Fail; | |
1155 | |
1156 face->driver = driver; | |
1157 face->memory = memory; | |
1158 face->stream = stream; | |
1159 | |
1160 if ( FT_NEW( internal ) ) | |
1161 goto Fail; | |
1162 | |
1163 face->internal = internal; | |
1164 | |
1165 #ifdef FT_CONFIG_OPTION_INCREMENTAL | |
1166 { | |
1167 int i; | |
1168 | |
1169 | |
1170 face->internal->incremental_interface = 0; | |
1171 for ( i = 0; i < num_params && !face->internal->incremental_interface; | |
1172 i++ ) | |
1173 if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL ) | |
1174 face->internal->incremental_interface = | |
1175 (FT_Incremental_Interface)params[i].data; | |
1176 } | |
1177 #endif | |
1178 | |
1179 if ( clazz->init_face ) | |
1180 error = clazz->init_face( stream, | |
1181 face, | |
1182 (FT_Int)face_index, | |
1183 num_params, | |
1184 params ); | |
1185 if ( error ) | |
1186 goto Fail; | |
1187 | |
1188 /* select Unicode charmap by default */ | |
1189 error2 = find_unicode_charmap( face ); | |
1190 | |
1191 /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */ | |
1192 /* is returned. */ | |
1193 | |
1194 /* no error should happen, but we want to play safe */ | |
1195 if ( error2 && FT_ERR_NEQ( error2, Invalid_CharMap_Handle ) ) | |
1196 { | |
1197 error = error2; | |
1198 goto Fail; | |
1199 } | |
1200 | |
1201 *aface = face; | |
1202 | |
1203 Fail: | |
1204 if ( error ) | |
1205 { | |
1206 destroy_charmaps( face, memory ); | |
1207 if ( clazz->done_face ) | |
1208 clazz->done_face( face ); | |
1209 FT_FREE( internal ); | |
1210 FT_FREE( face ); | |
1211 *aface = 0; | |
1212 } | |
1213 | |
1214 return error; | |
1215 } | |
1216 | |
1217 | |
1218 /* there's a Mac-specific extended implementation of FT_New_Face() */ | |
1219 /* in src/base/ftmac.c */ | |
1220 | |
1221 //#ifndef FT_MACINTOSH | |
1222 | |
1223 /* documentation is in freetype.h */ | |
1224 | |
1225 FT_EXPORT_DEF( FT_Error ) | |
1226 FT_New_Face( FT_Library library, | |
1227 const char* pathname, | |
1228 FT_Long face_index, | |
1229 FT_Face *aface ) | |
1230 { | |
1231 FT_Open_Args args; | |
1232 | |
1233 | |
1234 /* test for valid `library' and `aface' delayed to FT_Open_Face() */ | |
1235 if ( !pathname ) | |
1236 return FT_THROW( Invalid_Argument ); | |
1237 | |
1238 args.flags = FT_OPEN_PATHNAME; | |
1239 args.pathname = (char*)pathname; | |
1240 args.stream = NULL; | |
1241 | |
1242 return FT_Open_Face( library, &args, face_index, aface ); | |
1243 } | |
1244 | |
1245 //#endif | |
1246 | |
1247 | |
1248 /* documentation is in freetype.h */ | |
1249 | |
1250 FT_EXPORT_DEF( FT_Error ) | |
1251 FT_New_Memory_Face( FT_Library library, | |
1252 const FT_Byte* file_base, | |
1253 FT_Long file_size, | |
1254 FT_Long face_index, | |
1255 FT_Face *aface ) | |
1256 { | |
1257 FT_Open_Args args; | |
1258 | |
1259 | |
1260 /* test for valid `library' and `face' delayed to FT_Open_Face() */ | |
1261 if ( !file_base ) | |
1262 return FT_THROW( Invalid_Argument ); | |
1263 | |
1264 args.flags = FT_OPEN_MEMORY; | |
1265 args.memory_base = file_base; | |
1266 args.memory_size = file_size; | |
1267 args.stream = NULL; | |
1268 | |
1269 return FT_Open_Face( library, &args, face_index, aface ); | |
1270 } | |
1271 | |
1272 | |
1273 #ifdef FT_CONFIG_OPTION_MAC_FONTS | |
1274 | |
1275 /* The behavior here is very similar to that in base/ftmac.c, but it */ | |
1276 /* is designed to work on non-mac systems, so no mac specific calls. */ | |
1277 /* */ | |
1278 /* We look at the file and determine if it is a mac dfont file or a mac */ | |
1279 /* resource file, or a macbinary file containing a mac resource file. */ | |
1280 /* */ | |
1281 /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */ | |
1282 /* the point, especially since there may be multiple `FOND' resources. */ | |
1283 /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */ | |
1284 /* they occur in the file. */ | |
1285 /* */ | |
1286 /* Note that multiple `POST' resources do not mean multiple postscript */ | |
1287 /* fonts; they all get jammed together to make what is essentially a */ | |
1288 /* pfb file. */ | |
1289 /* */ | |
1290 /* We aren't interested in `NFNT' or `FONT' bitmap resources. */ | |
1291 /* */ | |
1292 /* As soon as we get an `sfnt' load it into memory and pass it off to */ | |
1293 /* FT_Open_Face. */ | |
1294 /* */ | |
1295 /* If we have a (set of) `POST' resources, massage them into a (memory) */ | |
1296 /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */ | |
1297 /* going to try to save the kerning info. After all that lives in the */ | |
1298 /* `FOND' which isn't in the file containing the `POST' resources so */ | |
1299 /* we don't really have access to it. */ | |
1300 | |
1301 | |
1302 /* Finalizer for a memory stream; gets called by FT_Done_Face(). */ | |
1303 /* It frees the memory it uses. */ | |
1304 /* From ftmac.c. */ | |
1305 static void | |
1306 memory_stream_close( FT_Stream stream ) | |
1307 { | |
1308 FT_Memory memory = stream->memory; | |
1309 | |
1310 | |
1311 FT_FREE( stream->base ); | |
1312 | |
1313 stream->size = 0; | |
1314 stream->base = 0; | |
1315 stream->close = 0; | |
1316 } | |
1317 | |
1318 | |
1319 /* Create a new memory stream from a buffer and a size. */ | |
1320 /* From ftmac.c. */ | |
1321 static FT_Error | |
1322 new_memory_stream( FT_Library library, | |
1323 FT_Byte* base, | |
1324 FT_ULong size, | |
1325 FT_Stream_CloseFunc close, | |
1326 FT_Stream *astream ) | |
1327 { | |
1328 FT_Error error; | |
1329 FT_Memory memory; | |
1330 FT_Stream stream = NULL; | |
1331 | |
1332 | |
1333 if ( !library ) | |
1334 return FT_THROW( Invalid_Library_Handle ); | |
1335 | |
1336 if ( !base ) | |
1337 return FT_THROW( Invalid_Argument ); | |
1338 | |
1339 *astream = 0; | |
1340 memory = library->memory; | |
1341 if ( FT_NEW( stream ) ) | |
1342 goto Exit; | |
1343 | |
1344 FT_Stream_OpenMemory( stream, base, size ); | |
1345 | |
1346 stream->close = close; | |
1347 | |
1348 *astream = stream; | |
1349 | |
1350 Exit: | |
1351 return error; | |
1352 } | |
1353 | |
1354 | |
1355 /* Create a new FT_Face given a buffer and a driver name. */ | |
1356 /* from ftmac.c */ | |
1357 FT_LOCAL_DEF( FT_Error ) | |
1358 open_face_from_buffer( FT_Library library, | |
1359 FT_Byte* base, | |
1360 FT_ULong size, | |
1361 FT_Long face_index, | |
1362 const char* driver_name, | |
1363 FT_Face *aface ) | |
1364 { | |
1365 FT_Open_Args args; | |
1366 FT_Error error; | |
1367 FT_Stream stream = NULL; | |
1368 FT_Memory memory = library->memory; | |
1369 | |
1370 | |
1371 error = new_memory_stream( library, | |
1372 base, | |
1373 size, | |
1374 memory_stream_close, | |
1375 &stream ); | |
1376 if ( error ) | |
1377 { | |
1378 FT_FREE( base ); | |
1379 return error; | |
1380 } | |
1381 | |
1382 args.flags = FT_OPEN_STREAM; | |
1383 args.stream = stream; | |
1384 if ( driver_name ) | |
1385 { | |
1386 args.flags = args.flags | FT_OPEN_DRIVER; | |
1387 args.driver = FT_Get_Module( library, driver_name ); | |
1388 } | |
1389 | |
1390 #ifdef FT_MACINTOSH | |
1391 /* At this point, face_index has served its purpose; */ | |
1392 /* whoever calls this function has already used it to */ | |
1393 /* locate the correct font data. We should not propagate */ | |
1394 /* this index to FT_Open_Face() (unless it is negative). */ | |
1395 | |
1396 if ( face_index > 0 ) | |
1397 face_index = 0; | |
1398 #endif | |
1399 | |
1400 error = FT_Open_Face( library, &args, face_index, aface ); | |
1401 | |
1402 if ( error == FT_Err_Ok ) | |
1403 (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; | |
1404 else | |
1405 #ifdef FT_MACINTOSH | |
1406 FT_Stream_Free( stream, 0 ); | |
1407 #else | |
1408 { | |
1409 FT_Stream_Close( stream ); | |
1410 FT_FREE( stream ); | |
1411 } | |
1412 #endif | |
1413 | |
1414 return error; | |
1415 } | |
1416 | |
1417 | |
1418 /* Look up `TYP1' or `CID ' table from sfnt table directory. */ | |
1419 /* `offset' and `length' must exclude the binary header in tables. */ | |
1420 | |
1421 /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */ | |
1422 /* format too. Here, since we can't expect that the TrueType font */ | |
1423 /* driver is loaded unconditially, we must parse the font by */ | |
1424 /* ourselves. We are only interested in the name of the table and */ | |
1425 /* the offset. */ | |
1426 | |
1427 static FT_Error | |
1428 ft_lookup_PS_in_sfnt_stream( FT_Stream stream, | |
1429 FT_Long face_index, | |
1430 FT_ULong* offset, | |
1431 FT_ULong* length, | |
1432 FT_Bool* is_sfnt_cid ) | |
1433 { | |
1434 FT_Error error; | |
1435 FT_UShort numTables; | |
1436 FT_Long pstable_index; | |
1437 FT_ULong tag; | |
1438 int i; | |
1439 | |
1440 | |
1441 *offset = 0; | |
1442 *length = 0; | |
1443 *is_sfnt_cid = FALSE; | |
1444 | |
1445 /* TODO: support for sfnt-wrapped PS/CID in TTC format */ | |
1446 | |
1447 /* version check for 'typ1' (should be ignored?) */ | |
1448 if ( FT_READ_ULONG( tag ) ) | |
1449 return error; | |
1450 if ( tag != TTAG_typ1 ) | |
1451 return FT_THROW( Unknown_File_Format ); | |
1452 | |
1453 if ( FT_READ_USHORT( numTables ) ) | |
1454 return error; | |
1455 if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */ | |
1456 return error; | |
1457 | |
1458 pstable_index = -1; | |
1459 *is_sfnt_cid = FALSE; | |
1460 | |
1461 for ( i = 0; i < numTables; i++ ) | |
1462 { | |
1463 if ( FT_READ_ULONG( tag ) || FT_STREAM_SKIP( 4 ) || | |
1464 FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) ) | |
1465 return error; | |
1466 | |
1467 if ( tag == TTAG_CID ) | |
1468 { | |
1469 pstable_index++; | |
1470 *offset += 22; | |
1471 *length -= 22; | |
1472 *is_sfnt_cid = TRUE; | |
1473 if ( face_index < 0 ) | |
1474 return FT_Err_Ok; | |
1475 } | |
1476 else if ( tag == TTAG_TYP1 ) | |
1477 { | |
1478 pstable_index++; | |
1479 *offset += 24; | |
1480 *length -= 24; | |
1481 *is_sfnt_cid = FALSE; | |
1482 if ( face_index < 0 ) | |
1483 return FT_Err_Ok; | |
1484 } | |
1485 if ( face_index >= 0 && pstable_index == face_index ) | |
1486 return FT_Err_Ok; | |
1487 } | |
1488 return FT_THROW( Table_Missing ); | |
1489 } | |
1490 | |
1491 | |
1492 FT_LOCAL_DEF( FT_Error ) | |
1493 open_face_PS_from_sfnt_stream( FT_Library library, | |
1494 FT_Stream stream, | |
1495 FT_Long face_index, | |
1496 FT_Int num_params, | |
1497 FT_Parameter *params, | |
1498 FT_Face *aface ) | |
1499 { | |
1500 FT_Error error; | |
1501 FT_Memory memory = library->memory; | |
1502 FT_ULong offset, length; | |
1503 FT_Long pos; | |
1504 FT_Bool is_sfnt_cid; | |
1505 FT_Byte* sfnt_ps = NULL; | |
1506 | |
1507 FT_UNUSED( num_params ); | |
1508 FT_UNUSED( params ); | |
1509 | |
1510 | |
1511 pos = FT_Stream_Pos( stream ); | |
1512 | |
1513 error = ft_lookup_PS_in_sfnt_stream( stream, | |
1514 face_index, | |
1515 &offset, | |
1516 &length, | |
1517 &is_sfnt_cid ); | |
1518 if ( error ) | |
1519 goto Exit; | |
1520 | |
1521 if ( FT_Stream_Seek( stream, pos + offset ) ) | |
1522 goto Exit; | |
1523 | |
1524 if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) ) | |
1525 goto Exit; | |
1526 | |
1527 error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length ); | |
1528 if ( error ) | |
1529 goto Exit; | |
1530 | |
1531 error = open_face_from_buffer( library, | |
1532 sfnt_ps, | |
1533 length, | |
1534 FT_MIN( face_index, 0 ), | |
1535 is_sfnt_cid ? "cid" : "type1", | |
1536 aface ); | |
1537 Exit: | |
1538 { | |
1539 FT_Error error1; | |
1540 | |
1541 | |
1542 if ( FT_ERR_EQ( error, Unknown_File_Format ) ) | |
1543 { | |
1544 error1 = FT_Stream_Seek( stream, pos ); | |
1545 if ( error1 ) | |
1546 return error1; | |
1547 } | |
1548 | |
1549 return error; | |
1550 } | |
1551 } | |
1552 | |
1553 | |
1554 #ifndef FT_MACINTOSH | |
1555 | |
1556 /* The resource header says we've got resource_cnt `POST' (type1) */ | |
1557 /* resources in this file. They all need to be coalesced into */ | |
1558 /* one lump which gets passed on to the type1 driver. */ | |
1559 /* Here can be only one PostScript font in a file so face_index */ | |
1560 /* must be 0 (or -1). */ | |
1561 /* */ | |
1562 static FT_Error | |
1563 Mac_Read_POST_Resource( FT_Library library, | |
1564 FT_Stream stream, | |
1565 FT_Long *offsets, | |
1566 FT_Long resource_cnt, | |
1567 FT_Long face_index, | |
1568 FT_Face *aface ) | |
1569 { | |
1570 FT_Error error = FT_ERR( Cannot_Open_Resource ); | |
1571 FT_Memory memory = library->memory; | |
1572 FT_Byte* pfb_data = NULL; | |
1573 int i, type, flags; | |
1574 FT_Long len; | |
1575 FT_Long pfb_len, pfb_pos, pfb_lenpos; | |
1576 FT_Long rlen, temp; | |
1577 | |
1578 | |
1579 if ( face_index == -1 ) | |
1580 face_index = 0; | |
1581 if ( face_index != 0 ) | |
1582 return error; | |
1583 | |
1584 /* Find the length of all the POST resources, concatenated. Assume */ | |
1585 /* worst case (each resource in its own section). */ | |
1586 pfb_len = 0; | |
1587 for ( i = 0; i < resource_cnt; ++i ) | |
1588 { | |
1589 error = FT_Stream_Seek( stream, offsets[i] ); | |
1590 if ( error ) | |
1591 goto Exit; | |
1592 if ( FT_READ_LONG( temp ) ) | |
1593 goto Exit; | |
1594 pfb_len += temp + 6; | |
1595 } | |
1596 | |
1597 if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) ) | |
1598 goto Exit; | |
1599 | |
1600 pfb_data[0] = 0x80; | |
1601 pfb_data[1] = 1; /* Ascii section */ | |
1602 pfb_data[2] = 0; /* 4-byte length, fill in later */ | |
1603 pfb_data[3] = 0; | |
1604 pfb_data[4] = 0; | |
1605 pfb_data[5] = 0; | |
1606 pfb_pos = 6; | |
1607 pfb_lenpos = 2; | |
1608 | |
1609 len = 0; | |
1610 type = 1; | |
1611 for ( i = 0; i < resource_cnt; ++i ) | |
1612 { | |
1613 error = FT_Stream_Seek( stream, offsets[i] ); | |
1614 if ( error ) | |
1615 goto Exit2; | |
1616 if ( FT_READ_LONG( rlen ) ) | |
1617 goto Exit; | |
1618 if ( FT_READ_USHORT( flags ) ) | |
1619 goto Exit; | |
1620 FT_TRACE3(( "POST fragment[%d]: offsets=0x%08x, rlen=0x%08x, flags=0x%04x\
n", | |
1621 i, offsets[i], rlen, flags )); | |
1622 | |
1623 /* postpone the check of rlen longer than buffer until FT_Stream_Read() */ | |
1624 if ( ( flags >> 8 ) == 0 ) /* Comment, should not be loaded */ | |
1625 continue; | |
1626 | |
1627 /* the flags are part of the resource, so rlen >= 2. */ | |
1628 /* but some fonts declare rlen = 0 for empty fragment */ | |
1629 if ( rlen > 2 ) | |
1630 rlen -= 2; | |
1631 else | |
1632 rlen = 0; | |
1633 | |
1634 if ( ( flags >> 8 ) == type ) | |
1635 len += rlen; | |
1636 else | |
1637 { | |
1638 if ( pfb_lenpos + 3 > pfb_len + 2 ) | |
1639 goto Exit2; | |
1640 pfb_data[pfb_lenpos ] = (FT_Byte)( len ); | |
1641 pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); | |
1642 pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); | |
1643 pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); | |
1644 | |
1645 if ( ( flags >> 8 ) == 5 ) /* End of font mark */ | |
1646 break; | |
1647 | |
1648 if ( pfb_pos + 6 > pfb_len + 2 ) | |
1649 goto Exit2; | |
1650 pfb_data[pfb_pos++] = 0x80; | |
1651 | |
1652 type = flags >> 8; | |
1653 len = rlen; | |
1654 | |
1655 pfb_data[pfb_pos++] = (FT_Byte)type; | |
1656 pfb_lenpos = pfb_pos; | |
1657 pfb_data[pfb_pos++] = 0; /* 4-byte length, fill in later */ | |
1658 pfb_data[pfb_pos++] = 0; | |
1659 pfb_data[pfb_pos++] = 0; | |
1660 pfb_data[pfb_pos++] = 0; | |
1661 } | |
1662 | |
1663 error = FT_ERR( Cannot_Open_Resource ); | |
1664 if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len ) | |
1665 goto Exit2; | |
1666 | |
1667 error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen ); | |
1668 if ( error ) | |
1669 goto Exit2; | |
1670 pfb_pos += rlen; | |
1671 } | |
1672 | |
1673 if ( pfb_pos + 2 > pfb_len + 2 ) | |
1674 goto Exit2; | |
1675 pfb_data[pfb_pos++] = 0x80; | |
1676 pfb_data[pfb_pos++] = 3; | |
1677 | |
1678 if ( pfb_lenpos + 3 > pfb_len + 2 ) | |
1679 goto Exit2; | |
1680 pfb_data[pfb_lenpos ] = (FT_Byte)( len ); | |
1681 pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); | |
1682 pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); | |
1683 pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); | |
1684 | |
1685 return open_face_from_buffer( library, | |
1686 pfb_data, | |
1687 pfb_pos, | |
1688 face_index, | |
1689 "type1", | |
1690 aface ); | |
1691 | |
1692 Exit2: | |
1693 FT_FREE( pfb_data ); | |
1694 | |
1695 Exit: | |
1696 return error; | |
1697 } | |
1698 | |
1699 | |
1700 /* The resource header says we've got resource_cnt `sfnt' */ | |
1701 /* (TrueType/OpenType) resources in this file. Look through */ | |
1702 /* them for the one indicated by face_index, load it into mem, */ | |
1703 /* pass it on the the truetype driver and return it. */ | |
1704 /* */ | |
1705 static FT_Error | |
1706 Mac_Read_sfnt_Resource( FT_Library library, | |
1707 FT_Stream stream, | |
1708 FT_Long *offsets, | |
1709 FT_Long resource_cnt, | |
1710 FT_Long face_index, | |
1711 FT_Face *aface ) | |
1712 { | |
1713 FT_Memory memory = library->memory; | |
1714 FT_Byte* sfnt_data = NULL; | |
1715 FT_Error error; | |
1716 FT_Long flag_offset; | |
1717 FT_Long rlen; | |
1718 int is_cff; | |
1719 FT_Long face_index_in_resource = 0; | |
1720 | |
1721 | |
1722 if ( face_index == -1 ) | |
1723 face_index = 0; | |
1724 if ( face_index >= resource_cnt ) | |
1725 return FT_THROW( Cannot_Open_Resource ); | |
1726 | |
1727 flag_offset = offsets[face_index]; | |
1728 error = FT_Stream_Seek( stream, flag_offset ); | |
1729 if ( error ) | |
1730 goto Exit; | |
1731 | |
1732 if ( FT_READ_LONG( rlen ) ) | |
1733 goto Exit; | |
1734 if ( rlen == -1 ) | |
1735 return FT_THROW( Cannot_Open_Resource ); | |
1736 | |
1737 error = open_face_PS_from_sfnt_stream( library, | |
1738 stream, | |
1739 face_index, | |
1740 0, NULL, | |
1741 aface ); | |
1742 if ( !error ) | |
1743 goto Exit; | |
1744 | |
1745 /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */ | |
1746 if ( FT_Stream_Seek( stream, flag_offset + 4 ) ) | |
1747 goto Exit; | |
1748 | |
1749 if ( FT_ALLOC( sfnt_data, (FT_Long)rlen ) ) | |
1750 return error; | |
1751 error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen ); | |
1752 if ( error ) | |
1753 goto Exit; | |
1754 | |
1755 is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); | |
1756 error = open_face_from_buffer( library, | |
1757 sfnt_data, | |
1758 rlen, | |
1759 face_index_in_resource, | |
1760 is_cff ? "cff" : "truetype", | |
1761 aface ); | |
1762 | |
1763 Exit: | |
1764 return error; | |
1765 } | |
1766 | |
1767 | |
1768 /* Check for a valid resource fork header, or a valid dfont */ | |
1769 /* header. In a resource fork the first 16 bytes are repeated */ | |
1770 /* at the location specified by bytes 4-7. In a dfont bytes */ | |
1771 /* 4-7 point to 16 bytes of zeroes instead. */ | |
1772 /* */ | |
1773 static FT_Error | |
1774 IsMacResource( FT_Library library, | |
1775 FT_Stream stream, | |
1776 FT_Long resource_offset, | |
1777 FT_Long face_index, | |
1778 FT_Face *aface ) | |
1779 { | |
1780 FT_Memory memory = library->memory; | |
1781 FT_Error error; | |
1782 FT_Long map_offset, rdara_pos; | |
1783 FT_Long *data_offsets; | |
1784 FT_Long count; | |
1785 | |
1786 | |
1787 error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset, | |
1788 &map_offset, &rdara_pos ); | |
1789 if ( error ) | |
1790 return error; | |
1791 | |
1792 error = FT_Raccess_Get_DataOffsets( library, stream, | |
1793 map_offset, rdara_pos, | |
1794 TTAG_POST, | |
1795 &data_offsets, &count ); | |
1796 if ( !error ) | |
1797 { | |
1798 error = Mac_Read_POST_Resource( library, stream, data_offsets, count, | |
1799 face_index, aface ); | |
1800 FT_FREE( data_offsets ); | |
1801 /* POST exists in an LWFN providing a single face */ | |
1802 if ( !error ) | |
1803 (*aface)->num_faces = 1; | |
1804 return error; | |
1805 } | |
1806 | |
1807 error = FT_Raccess_Get_DataOffsets( library, stream, | |
1808 map_offset, rdara_pos, | |
1809 TTAG_sfnt, | |
1810 &data_offsets, &count ); | |
1811 if ( !error ) | |
1812 { | |
1813 FT_Long face_index_internal = face_index % count; | |
1814 | |
1815 | |
1816 error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count, | |
1817 face_index_internal, aface ); | |
1818 FT_FREE( data_offsets ); | |
1819 if ( !error ) | |
1820 (*aface)->num_faces = count; | |
1821 } | |
1822 | |
1823 return error; | |
1824 } | |
1825 | |
1826 | |
1827 /* Check for a valid macbinary header, and if we find one */ | |
1828 /* check that the (flattened) resource fork in it is valid. */ | |
1829 /* */ | |
1830 static FT_Error | |
1831 IsMacBinary( FT_Library library, | |
1832 FT_Stream stream, | |
1833 FT_Long face_index, | |
1834 FT_Face *aface ) | |
1835 { | |
1836 unsigned char header[128]; | |
1837 FT_Error error; | |
1838 FT_Long dlen, offset; | |
1839 | |
1840 | |
1841 if ( NULL == stream ) | |
1842 return FT_THROW( Invalid_Stream_Operation ); | |
1843 | |
1844 error = FT_Stream_Seek( stream, 0 ); | |
1845 if ( error ) | |
1846 goto Exit; | |
1847 | |
1848 error = FT_Stream_Read( stream, (FT_Byte*)header, 128 ); | |
1849 if ( error ) | |
1850 goto Exit; | |
1851 | |
1852 if ( header[ 0] != 0 || | |
1853 header[74] != 0 || | |
1854 header[82] != 0 || | |
1855 header[ 1] == 0 || | |
1856 header[ 1] > 33 || | |
1857 header[63] != 0 || | |
1858 header[2 + header[1]] != 0 ) | |
1859 return FT_THROW( Unknown_File_Format ); | |
1860 | |
1861 dlen = ( header[0x53] << 24 ) | | |
1862 ( header[0x54] << 16 ) | | |
1863 ( header[0x55] << 8 ) | | |
1864 header[0x56]; | |
1865 #if 0 | |
1866 rlen = ( header[0x57] << 24 ) | | |
1867 ( header[0x58] << 16 ) | | |
1868 ( header[0x59] << 8 ) | | |
1869 header[0x5a]; | |
1870 #endif /* 0 */ | |
1871 offset = 128 + ( ( dlen + 127 ) & ~127 ); | |
1872 | |
1873 return IsMacResource( library, stream, offset, face_index, aface ); | |
1874 | |
1875 Exit: | |
1876 return error; | |
1877 } | |
1878 | |
1879 | |
1880 static FT_Error | |
1881 load_face_in_embedded_rfork( FT_Library library, | |
1882 FT_Stream stream, | |
1883 FT_Long face_index, | |
1884 FT_Face *aface, | |
1885 const FT_Open_Args *args ) | |
1886 { | |
1887 | |
1888 #undef FT_COMPONENT | |
1889 #define FT_COMPONENT trace_raccess | |
1890 | |
1891 FT_Memory memory = library->memory; | |
1892 FT_Error error = FT_ERR( Unknown_File_Format ); | |
1893 int i; | |
1894 | |
1895 char * file_names[FT_RACCESS_N_RULES]; | |
1896 FT_Long offsets[FT_RACCESS_N_RULES]; | |
1897 FT_Error errors[FT_RACCESS_N_RULES]; | |
1898 FT_Bool is_darwin_vfs, vfs_rfork_has_no_font = FALSE; /* not tested */ | |
1899 | |
1900 FT_Open_Args args2; | |
1901 FT_Stream stream2 = 0; | |
1902 | |
1903 | |
1904 FT_Raccess_Guess( library, stream, | |
1905 args->pathname, file_names, offsets, errors ); | |
1906 | |
1907 for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) | |
1908 { | |
1909 is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, i ); | |
1910 if ( is_darwin_vfs && vfs_rfork_has_no_font ) | |
1911 { | |
1912 FT_TRACE3(( "Skip rule %d: darwin vfs resource fork" | |
1913 " is already checked and" | |
1914 " no font is found\n", i )); | |
1915 continue; | |
1916 } | |
1917 | |
1918 if ( errors[i] ) | |
1919 { | |
1920 FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors[i], i )); | |
1921 continue; | |
1922 } | |
1923 | |
1924 args2.flags = FT_OPEN_PATHNAME; | |
1925 args2.pathname = file_names[i] ? file_names[i] : args->pathname; | |
1926 | |
1927 FT_TRACE3(( "Try rule %d: %s (offset=%d) ...", | |
1928 i, args2.pathname, offsets[i] )); | |
1929 | |
1930 error = FT_Stream_New( library, &args2, &stream2 ); | |
1931 if ( is_darwin_vfs && FT_ERR_EQ( error, Cannot_Open_Stream ) ) | |
1932 vfs_rfork_has_no_font = TRUE; | |
1933 | |
1934 if ( error ) | |
1935 { | |
1936 FT_TRACE3(( "failed\n" )); | |
1937 continue; | |
1938 } | |
1939 | |
1940 error = IsMacResource( library, stream2, offsets[i], | |
1941 face_index, aface ); | |
1942 FT_Stream_Free( stream2, 0 ); | |
1943 | |
1944 FT_TRACE3(( "%s\n", error ? "failed": "successful" )); | |
1945 | |
1946 if ( !error ) | |
1947 break; | |
1948 else if ( is_darwin_vfs ) | |
1949 vfs_rfork_has_no_font = TRUE; | |
1950 } | |
1951 | |
1952 for (i = 0; i < FT_RACCESS_N_RULES; i++) | |
1953 { | |
1954 if ( file_names[i] ) | |
1955 FT_FREE( file_names[i] ); | |
1956 } | |
1957 | |
1958 /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */ | |
1959 if ( error ) | |
1960 error = FT_ERR( Unknown_File_Format ); | |
1961 | |
1962 return error; | |
1963 | |
1964 #undef FT_COMPONENT | |
1965 #define FT_COMPONENT trace_objs | |
1966 | |
1967 } | |
1968 | |
1969 | |
1970 /* Check for some macintosh formats without Carbon framework. */ | |
1971 /* Is this a macbinary file? If so look at the resource fork. */ | |
1972 /* Is this a mac dfont file? */ | |
1973 /* Is this an old style resource fork? (in data) */ | |
1974 /* Else call load_face_in_embedded_rfork to try extra rules */ | |
1975 /* (defined in `ftrfork.c'). */ | |
1976 /* */ | |
1977 static FT_Error | |
1978 load_mac_face( FT_Library library, | |
1979 FT_Stream stream, | |
1980 FT_Long face_index, | |
1981 FT_Face *aface, | |
1982 const FT_Open_Args *args ) | |
1983 { | |
1984 FT_Error error; | |
1985 FT_UNUSED( args ); | |
1986 | |
1987 | |
1988 error = IsMacBinary( library, stream, face_index, aface ); | |
1989 if ( FT_ERR_EQ( error, Unknown_File_Format ) ) | |
1990 { | |
1991 | |
1992 #undef FT_COMPONENT | |
1993 #define FT_COMPONENT trace_raccess | |
1994 | |
1995 FT_TRACE3(( "Try as dfont: %s ...", args->pathname )); | |
1996 | |
1997 error = IsMacResource( library, stream, 0, face_index, aface ); | |
1998 | |
1999 FT_TRACE3(( "%s\n", error ? "failed" : "successful" )); | |
2000 | |
2001 #undef FT_COMPONENT | |
2002 #define FT_COMPONENT trace_objs | |
2003 | |
2004 } | |
2005 | |
2006 if ( ( FT_ERR_EQ( error, Unknown_File_Format ) || | |
2007 FT_ERR_EQ( error, Invalid_Stream_Operation ) ) && | |
2008 ( args->flags & FT_OPEN_PATHNAME ) ) | |
2009 error = load_face_in_embedded_rfork( library, stream, | |
2010 face_index, aface, args ); | |
2011 return error; | |
2012 } | |
2013 #endif | |
2014 | |
2015 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ | |
2016 | |
2017 | |
2018 /* documentation is in freetype.h */ | |
2019 | |
2020 FT_EXPORT_DEF( FT_Error ) | |
2021 FT_Open_Face( FT_Library library, | |
2022 const FT_Open_Args* args, | |
2023 FT_Long face_index, | |
2024 FT_Face *aface ) | |
2025 { | |
2026 FT_Error error; | |
2027 FT_Driver driver = NULL; | |
2028 FT_Memory memory = NULL; | |
2029 FT_Stream stream = NULL; | |
2030 FT_Face face = NULL; | |
2031 FT_ListNode node = NULL; | |
2032 FT_Bool external_stream; | |
2033 FT_Module* cur; | |
2034 FT_Module* limit; | |
2035 | |
2036 | |
2037 /* test for valid `library' delayed to */ | |
2038 /* FT_Stream_New() */ | |
2039 | |
2040 if ( ( !aface && face_index >= 0 ) || !args ) | |
2041 return FT_THROW( Invalid_Argument ); | |
2042 | |
2043 external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) && | |
2044 args->stream ); | |
2045 | |
2046 /* create input stream */ | |
2047 error = FT_Stream_New( library, args, &stream ); | |
2048 if ( error ) | |
2049 goto Fail3; | |
2050 | |
2051 memory = library->memory; | |
2052 | |
2053 /* If the font driver is specified in the `args' structure, use */ | |
2054 /* it. Otherwise, we scan the list of registered drivers. */ | |
2055 if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver ) | |
2056 { | |
2057 driver = FT_DRIVER( args->driver ); | |
2058 | |
2059 /* not all modules are drivers, so check... */ | |
2060 if ( FT_MODULE_IS_DRIVER( driver ) ) | |
2061 { | |
2062 FT_Int num_params = 0; | |
2063 FT_Parameter* params = 0; | |
2064 | |
2065 | |
2066 if ( args->flags & FT_OPEN_PARAMS ) | |
2067 { | |
2068 num_params = args->num_params; | |
2069 params = args->params; | |
2070 } | |
2071 | |
2072 error = open_face( driver, stream, face_index, | |
2073 num_params, params, &face ); | |
2074 if ( !error ) | |
2075 goto Success; | |
2076 } | |
2077 else | |
2078 error = FT_THROW( Invalid_Handle ); | |
2079 | |
2080 FT_Stream_Free( stream, external_stream ); | |
2081 goto Fail; | |
2082 } | |
2083 else | |
2084 { | |
2085 error = FT_ERR( Missing_Module ); | |
2086 | |
2087 /* check each font driver for an appropriate format */ | |
2088 cur = library->modules; | |
2089 limit = cur + library->num_modules; | |
2090 | |
2091 for ( ; cur < limit; cur++ ) | |
2092 { | |
2093 /* not all modules are font drivers, so check... */ | |
2094 if ( FT_MODULE_IS_DRIVER( cur[0] ) ) | |
2095 { | |
2096 FT_Int num_params = 0; | |
2097 FT_Parameter* params = 0; | |
2098 | |
2099 | |
2100 driver = FT_DRIVER( cur[0] ); | |
2101 | |
2102 if ( args->flags & FT_OPEN_PARAMS ) | |
2103 { | |
2104 num_params = args->num_params; | |
2105 params = args->params; | |
2106 } | |
2107 | |
2108 error = open_face( driver, stream, face_index, | |
2109 num_params, params, &face ); | |
2110 if ( !error ) | |
2111 goto Success; | |
2112 | |
2113 #ifdef FT_CONFIG_OPTION_MAC_FONTS | |
2114 if ( ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 && | |
2115 FT_ERR_EQ( error, Table_Missing ) ) | |
2116 { | |
2117 /* TrueType but essential tables are missing */ | |
2118 if ( FT_Stream_Seek( stream, 0 ) ) | |
2119 break; | |
2120 | |
2121 error = open_face_PS_from_sfnt_stream( library, | |
2122 stream, | |
2123 face_index, | |
2124 num_params, | |
2125 params, | |
2126 aface ); | |
2127 if ( !error ) | |
2128 { | |
2129 FT_Stream_Free( stream, external_stream ); | |
2130 return error; | |
2131 } | |
2132 } | |
2133 #endif | |
2134 | |
2135 if ( FT_ERR_NEQ( error, Unknown_File_Format ) ) | |
2136 goto Fail3; | |
2137 } | |
2138 } | |
2139 | |
2140 Fail3: | |
2141 /* If we are on the mac, and we get an */ | |
2142 /* FT_Err_Invalid_Stream_Operation it may be because we have an */ | |
2143 /* empty data fork, so we need to check the resource fork. */ | |
2144 if ( FT_ERR_NEQ( error, Cannot_Open_Stream ) && | |
2145 FT_ERR_NEQ( error, Unknown_File_Format ) && | |
2146 FT_ERR_NEQ( error, Invalid_Stream_Operation ) ) | |
2147 goto Fail2; | |
2148 | |
2149 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS ) | |
2150 error = load_mac_face( library, stream, face_index, aface, args ); | |
2151 if ( !error ) | |
2152 { | |
2153 /* We don't want to go to Success here. We've already done that. */ | |
2154 /* On the other hand, if we succeeded we still need to close this */ | |
2155 /* stream (we opened a different stream which extracted the */ | |
2156 /* interesting information out of this stream here. That stream */ | |
2157 /* will still be open and the face will point to it). */ | |
2158 FT_Stream_Free( stream, external_stream ); | |
2159 return error; | |
2160 } | |
2161 | |
2162 if ( FT_ERR_NEQ( error, Unknown_File_Format ) ) | |
2163 goto Fail2; | |
2164 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ | |
2165 | |
2166 /* no driver is able to handle this format */ | |
2167 error = FT_THROW( Unknown_File_Format ); | |
2168 | |
2169 Fail2: | |
2170 FT_Stream_Free( stream, external_stream ); | |
2171 goto Fail; | |
2172 } | |
2173 | |
2174 Success: | |
2175 FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" )); | |
2176 | |
2177 /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */ | |
2178 if ( external_stream ) | |
2179 face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM; | |
2180 | |
2181 /* add the face object to its driver's list */ | |
2182 if ( FT_NEW( node ) ) | |
2183 goto Fail; | |
2184 | |
2185 node->data = face; | |
2186 /* don't assume driver is the same as face->driver, so use */ | |
2187 /* face->driver instead. */ | |
2188 FT_List_Add( &face->driver->faces_list, node ); | |
2189 | |
2190 /* now allocate a glyph slot object for the face */ | |
2191 FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" )); | |
2192 | |
2193 if ( face_index >= 0 ) | |
2194 { | |
2195 error = FT_New_GlyphSlot( face, NULL ); | |
2196 if ( error ) | |
2197 goto Fail; | |
2198 | |
2199 /* finally, allocate a size object for the face */ | |
2200 { | |
2201 FT_Size size; | |
2202 | |
2203 | |
2204 FT_TRACE4(( "FT_Open_Face: Creating size object\n" )); | |
2205 | |
2206 error = FT_New_Size( face, &size ); | |
2207 if ( error ) | |
2208 goto Fail; | |
2209 | |
2210 face->size = size; | |
2211 } | |
2212 } | |
2213 | |
2214 /* some checks */ | |
2215 | |
2216 if ( FT_IS_SCALABLE( face ) ) | |
2217 { | |
2218 if ( face->height < 0 ) | |
2219 face->height = (FT_Short)-face->height; | |
2220 | |
2221 if ( !FT_HAS_VERTICAL( face ) ) | |
2222 face->max_advance_height = (FT_Short)face->height; | |
2223 } | |
2224 | |
2225 if ( FT_HAS_FIXED_SIZES( face ) ) | |
2226 { | |
2227 FT_Int i; | |
2228 | |
2229 | |
2230 for ( i = 0; i < face->num_fixed_sizes; i++ ) | |
2231 { | |
2232 FT_Bitmap_Size* bsize = face->available_sizes + i; | |
2233 | |
2234 | |
2235 if ( bsize->height < 0 ) | |
2236 bsize->height = (FT_Short)-bsize->height; | |
2237 if ( bsize->x_ppem < 0 ) | |
2238 bsize->x_ppem = (FT_Short)-bsize->x_ppem; | |
2239 if ( bsize->y_ppem < 0 ) | |
2240 bsize->y_ppem = -bsize->y_ppem; | |
2241 } | |
2242 } | |
2243 | |
2244 /* initialize internal face data */ | |
2245 { | |
2246 FT_Face_Internal internal = face->internal; | |
2247 | |
2248 | |
2249 internal->transform_matrix.xx = 0x10000L; | |
2250 internal->transform_matrix.xy = 0; | |
2251 internal->transform_matrix.yx = 0; | |
2252 internal->transform_matrix.yy = 0x10000L; | |
2253 | |
2254 internal->transform_delta.x = 0; | |
2255 internal->transform_delta.y = 0; | |
2256 | |
2257 internal->refcount = 1; | |
2258 } | |
2259 | |
2260 if ( aface ) | |
2261 *aface = face; | |
2262 else | |
2263 FT_Done_Face( face ); | |
2264 | |
2265 goto Exit; | |
2266 | |
2267 Fail: | |
2268 if ( node ) | |
2269 FT_Done_Face( face ); /* face must be in the driver's list */ | |
2270 else if ( face ) | |
2271 destroy_face( memory, face, driver ); | |
2272 | |
2273 Exit: | |
2274 FT_TRACE4(( "FT_Open_Face: Return %d\n", error )); | |
2275 | |
2276 return error; | |
2277 } | |
2278 | |
2279 | |
2280 /* documentation is in freetype.h */ | |
2281 | |
2282 FT_EXPORT_DEF( FT_Error ) | |
2283 FT_Attach_File( FT_Face face, | |
2284 const char* filepathname ) | |
2285 { | |
2286 FT_Open_Args open; | |
2287 | |
2288 | |
2289 /* test for valid `face' delayed to FT_Attach_Stream() */ | |
2290 | |
2291 if ( !filepathname ) | |
2292 return FT_THROW( Invalid_Argument ); | |
2293 | |
2294 open.stream = NULL; | |
2295 open.flags = FT_OPEN_PATHNAME; | |
2296 open.pathname = (char*)filepathname; | |
2297 | |
2298 return FT_Attach_Stream( face, &open ); | |
2299 } | |
2300 | |
2301 | |
2302 /* documentation is in freetype.h */ | |
2303 | |
2304 FT_EXPORT_DEF( FT_Error ) | |
2305 FT_Attach_Stream( FT_Face face, | |
2306 FT_Open_Args* parameters ) | |
2307 { | |
2308 FT_Stream stream; | |
2309 FT_Error error; | |
2310 FT_Driver driver; | |
2311 | |
2312 FT_Driver_Class clazz; | |
2313 | |
2314 | |
2315 /* test for valid `parameters' delayed to FT_Stream_New() */ | |
2316 | |
2317 if ( !face ) | |
2318 return FT_THROW( Invalid_Face_Handle ); | |
2319 | |
2320 driver = face->driver; | |
2321 if ( !driver ) | |
2322 return FT_THROW( Invalid_Driver_Handle ); | |
2323 | |
2324 error = FT_Stream_New( driver->root.library, parameters, &stream ); | |
2325 if ( error ) | |
2326 goto Exit; | |
2327 | |
2328 /* we implement FT_Attach_Stream in each driver through the */ | |
2329 /* `attach_file' interface */ | |
2330 | |
2331 error = FT_ERR( Unimplemented_Feature ); | |
2332 clazz = driver->clazz; | |
2333 if ( clazz->attach_file ) | |
2334 error = clazz->attach_file( face, stream ); | |
2335 | |
2336 /* close the attached stream */ | |
2337 FT_Stream_Free( stream, | |
2338 (FT_Bool)( parameters->stream && | |
2339 ( parameters->flags & FT_OPEN_STREAM ) ) ); | |
2340 | |
2341 Exit: | |
2342 return error; | |
2343 } | |
2344 | |
2345 | |
2346 /* documentation is in freetype.h */ | |
2347 | |
2348 FT_EXPORT_DEF( FT_Error ) | |
2349 FT_Reference_Face( FT_Face face ) | |
2350 { | |
2351 face->internal->refcount++; | |
2352 | |
2353 return FT_Err_Ok; | |
2354 } | |
2355 | |
2356 | |
2357 /* documentation is in freetype.h */ | |
2358 | |
2359 FT_EXPORT_DEF( FT_Error ) | |
2360 FT_Done_Face( FT_Face face ) | |
2361 { | |
2362 FT_Error error; | |
2363 FT_Driver driver; | |
2364 FT_Memory memory; | |
2365 FT_ListNode node; | |
2366 | |
2367 | |
2368 error = FT_ERR( Invalid_Face_Handle ); | |
2369 if ( face && face->driver ) | |
2370 { | |
2371 face->internal->refcount--; | |
2372 if ( face->internal->refcount > 0 ) | |
2373 error = FT_Err_Ok; | |
2374 else | |
2375 { | |
2376 driver = face->driver; | |
2377 memory = driver->root.memory; | |
2378 | |
2379 /* find face in driver's list */ | |
2380 node = FT_List_Find( &driver->faces_list, face ); | |
2381 if ( node ) | |
2382 { | |
2383 /* remove face object from the driver's list */ | |
2384 FT_List_Remove( &driver->faces_list, node ); | |
2385 FT_FREE( node ); | |
2386 | |
2387 /* now destroy the object proper */ | |
2388 destroy_face( memory, face, driver ); | |
2389 error = FT_Err_Ok; | |
2390 } | |
2391 } | |
2392 } | |
2393 | |
2394 return error; | |
2395 } | |
2396 | |
2397 | |
2398 /* documentation is in ftobjs.h */ | |
2399 | |
2400 FT_EXPORT_DEF( FT_Error ) | |
2401 FT_New_Size( FT_Face face, | |
2402 FT_Size *asize ) | |
2403 { | |
2404 FT_Error error; | |
2405 FT_Memory memory; | |
2406 FT_Driver driver; | |
2407 FT_Driver_Class clazz; | |
2408 | |
2409 FT_Size size = 0; | |
2410 FT_ListNode node = 0; | |
2411 | |
2412 | |
2413 if ( !face ) | |
2414 return FT_THROW( Invalid_Face_Handle ); | |
2415 | |
2416 if ( !asize ) | |
2417 return FT_THROW( Invalid_Size_Handle ); | |
2418 | |
2419 if ( !face->driver ) | |
2420 return FT_THROW( Invalid_Driver_Handle ); | |
2421 | |
2422 *asize = 0; | |
2423 | |
2424 driver = face->driver; | |
2425 clazz = driver->clazz; | |
2426 memory = face->memory; | |
2427 | |
2428 /* Allocate new size object and perform basic initialisation */ | |
2429 if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) ) | |
2430 goto Exit; | |
2431 | |
2432 size->face = face; | |
2433 | |
2434 /* for now, do not use any internal fields in size objects */ | |
2435 size->internal = 0; | |
2436 | |
2437 if ( clazz->init_size ) | |
2438 error = clazz->init_size( size ); | |
2439 | |
2440 /* in case of success, add to the face's list */ | |
2441 if ( !error ) | |
2442 { | |
2443 *asize = size; | |
2444 node->data = size; | |
2445 FT_List_Add( &face->sizes_list, node ); | |
2446 } | |
2447 | |
2448 Exit: | |
2449 if ( error ) | |
2450 { | |
2451 FT_FREE( node ); | |
2452 FT_FREE( size ); | |
2453 } | |
2454 | |
2455 return error; | |
2456 } | |
2457 | |
2458 | |
2459 /* documentation is in ftobjs.h */ | |
2460 | |
2461 FT_EXPORT_DEF( FT_Error ) | |
2462 FT_Done_Size( FT_Size size ) | |
2463 { | |
2464 FT_Error error; | |
2465 FT_Driver driver; | |
2466 FT_Memory memory; | |
2467 FT_Face face; | |
2468 FT_ListNode node; | |
2469 | |
2470 | |
2471 if ( !size ) | |
2472 return FT_THROW( Invalid_Size_Handle ); | |
2473 | |
2474 face = size->face; | |
2475 if ( !face ) | |
2476 return FT_THROW( Invalid_Face_Handle ); | |
2477 | |
2478 driver = face->driver; | |
2479 if ( !driver ) | |
2480 return FT_THROW( Invalid_Driver_Handle ); | |
2481 | |
2482 memory = driver->root.memory; | |
2483 | |
2484 error = FT_Err_Ok; | |
2485 node = FT_List_Find( &face->sizes_list, size ); | |
2486 if ( node ) | |
2487 { | |
2488 FT_List_Remove( &face->sizes_list, node ); | |
2489 FT_FREE( node ); | |
2490 | |
2491 if ( face->size == size ) | |
2492 { | |
2493 face->size = 0; | |
2494 if ( face->sizes_list.head ) | |
2495 face->size = (FT_Size)(face->sizes_list.head->data); | |
2496 } | |
2497 | |
2498 destroy_size( memory, size, driver ); | |
2499 } | |
2500 else | |
2501 error = FT_THROW( Invalid_Size_Handle ); | |
2502 | |
2503 return error; | |
2504 } | |
2505 | |
2506 | |
2507 /* documentation is in ftobjs.h */ | |
2508 | |
2509 FT_BASE_DEF( FT_Error ) | |
2510 FT_Match_Size( FT_Face face, | |
2511 FT_Size_Request req, | |
2512 FT_Bool ignore_width, | |
2513 FT_ULong* size_index ) | |
2514 { | |
2515 FT_Int i; | |
2516 FT_Long w, h; | |
2517 | |
2518 | |
2519 if ( !FT_HAS_FIXED_SIZES( face ) ) | |
2520 return FT_THROW( Invalid_Face_Handle ); | |
2521 | |
2522 /* FT_Bitmap_Size doesn't provide enough info... */ | |
2523 if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) | |
2524 return FT_THROW( Unimplemented_Feature ); | |
2525 | |
2526 w = FT_REQUEST_WIDTH ( req ); | |
2527 h = FT_REQUEST_HEIGHT( req ); | |
2528 | |
2529 if ( req->width && !req->height ) | |
2530 h = w; | |
2531 else if ( !req->width && req->height ) | |
2532 w = h; | |
2533 | |
2534 w = FT_PIX_ROUND( w ); | |
2535 h = FT_PIX_ROUND( h ); | |
2536 | |
2537 for ( i = 0; i < face->num_fixed_sizes; i++ ) | |
2538 { | |
2539 FT_Bitmap_Size* bsize = face->available_sizes + i; | |
2540 | |
2541 | |
2542 if ( h != FT_PIX_ROUND( bsize->y_ppem ) ) | |
2543 continue; | |
2544 | |
2545 if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width ) | |
2546 { | |
2547 FT_TRACE3(( "FT_Match_Size: bitmap strike %d matches\n", i )); | |
2548 | |
2549 if ( size_index ) | |
2550 *size_index = (FT_ULong)i; | |
2551 | |
2552 return FT_Err_Ok; | |
2553 } | |
2554 } | |
2555 | |
2556 return FT_THROW( Invalid_Pixel_Size ); | |
2557 } | |
2558 | |
2559 | |
2560 /* documentation is in ftobjs.h */ | |
2561 | |
2562 FT_BASE_DEF( void ) | |
2563 ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics, | |
2564 FT_Pos advance ) | |
2565 { | |
2566 FT_Pos height = metrics->height; | |
2567 | |
2568 | |
2569 /* compensate for glyph with bbox above/below the baseline */ | |
2570 if ( metrics->horiBearingY < 0 ) | |
2571 { | |
2572 if ( height < metrics->horiBearingY ) | |
2573 height = metrics->horiBearingY; | |
2574 } | |
2575 else if ( metrics->horiBearingY > 0 ) | |
2576 height -= metrics->horiBearingY; | |
2577 | |
2578 /* the factor 1.2 is a heuristical value */ | |
2579 if ( !advance ) | |
2580 advance = height * 12 / 10; | |
2581 | |
2582 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2; | |
2583 metrics->vertBearingY = ( advance - height ) / 2; | |
2584 metrics->vertAdvance = advance; | |
2585 } | |
2586 | |
2587 | |
2588 static void | |
2589 ft_recompute_scaled_metrics( FT_Face face, | |
2590 FT_Size_Metrics* metrics ) | |
2591 { | |
2592 /* Compute root ascender, descender, test height, and max_advance */ | |
2593 | |
2594 #ifdef GRID_FIT_METRICS | |
2595 metrics->ascender = FT_PIX_CEIL( FT_MulFix( face->ascender, | |
2596 metrics->y_scale ) ); | |
2597 | |
2598 metrics->descender = FT_PIX_FLOOR( FT_MulFix( face->descender, | |
2599 metrics->y_scale ) ); | |
2600 | |
2601 metrics->height = FT_PIX_ROUND( FT_MulFix( face->height, | |
2602 metrics->y_scale ) ); | |
2603 | |
2604 metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width, | |
2605 metrics->x_scale ) ); | |
2606 #else /* !GRID_FIT_METRICS */ | |
2607 metrics->ascender = FT_MulFix( face->ascender, | |
2608 metrics->y_scale ); | |
2609 | |
2610 metrics->descender = FT_MulFix( face->descender, | |
2611 metrics->y_scale ); | |
2612 | |
2613 metrics->height = FT_MulFix( face->height, | |
2614 metrics->y_scale ); | |
2615 | |
2616 metrics->max_advance = FT_MulFix( face->max_advance_width, | |
2617 metrics->x_scale ); | |
2618 #endif /* !GRID_FIT_METRICS */ | |
2619 } | |
2620 | |
2621 | |
2622 FT_BASE_DEF( void ) | |
2623 FT_Select_Metrics( FT_Face face, | |
2624 FT_ULong strike_index ) | |
2625 { | |
2626 FT_Size_Metrics* metrics; | |
2627 FT_Bitmap_Size* bsize; | |
2628 | |
2629 | |
2630 metrics = &face->size->metrics; | |
2631 bsize = face->available_sizes + strike_index; | |
2632 | |
2633 metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 ); | |
2634 metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 ); | |
2635 | |
2636 if ( FT_IS_SCALABLE( face ) ) | |
2637 { | |
2638 metrics->x_scale = FT_DivFix( bsize->x_ppem, | |
2639 face->units_per_EM ); | |
2640 metrics->y_scale = FT_DivFix( bsize->y_ppem, | |
2641 face->units_per_EM ); | |
2642 | |
2643 ft_recompute_scaled_metrics( face, metrics ); | |
2644 } | |
2645 else | |
2646 { | |
2647 metrics->x_scale = 1L << 16; | |
2648 metrics->y_scale = 1L << 16; | |
2649 metrics->ascender = bsize->y_ppem; | |
2650 metrics->descender = 0; | |
2651 metrics->height = bsize->height << 6; | |
2652 metrics->max_advance = bsize->x_ppem; | |
2653 } | |
2654 | |
2655 FT_TRACE5(( "FT_Select_Metrics:\n" )); | |
2656 FT_TRACE5(( " x scale: %d (%f)\n", | |
2657 metrics->x_scale, metrics->x_scale / 65536.0 )); | |
2658 FT_TRACE5(( " y scale: %d (%f)\n", | |
2659 metrics->y_scale, metrics->y_scale / 65536.0 )); | |
2660 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); | |
2661 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); | |
2662 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); | |
2663 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); | |
2664 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); | |
2665 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); | |
2666 } | |
2667 | |
2668 | |
2669 FT_BASE_DEF( void ) | |
2670 FT_Request_Metrics( FT_Face face, | |
2671 FT_Size_Request req ) | |
2672 { | |
2673 FT_Size_Metrics* metrics; | |
2674 | |
2675 | |
2676 metrics = &face->size->metrics; | |
2677 | |
2678 if ( FT_IS_SCALABLE( face ) ) | |
2679 { | |
2680 FT_Long w = 0, h = 0, scaled_w = 0, scaled_h = 0; | |
2681 | |
2682 | |
2683 switch ( req->type ) | |
2684 { | |
2685 case FT_SIZE_REQUEST_TYPE_NOMINAL: | |
2686 w = h = face->units_per_EM; | |
2687 break; | |
2688 | |
2689 case FT_SIZE_REQUEST_TYPE_REAL_DIM: | |
2690 w = h = face->ascender - face->descender; | |
2691 break; | |
2692 | |
2693 case FT_SIZE_REQUEST_TYPE_BBOX: | |
2694 w = face->bbox.xMax - face->bbox.xMin; | |
2695 h = face->bbox.yMax - face->bbox.yMin; | |
2696 break; | |
2697 | |
2698 case FT_SIZE_REQUEST_TYPE_CELL: | |
2699 w = face->max_advance_width; | |
2700 h = face->ascender - face->descender; | |
2701 break; | |
2702 | |
2703 case FT_SIZE_REQUEST_TYPE_SCALES: | |
2704 metrics->x_scale = (FT_Fixed)req->width; | |
2705 metrics->y_scale = (FT_Fixed)req->height; | |
2706 if ( !metrics->x_scale ) | |
2707 metrics->x_scale = metrics->y_scale; | |
2708 else if ( !metrics->y_scale ) | |
2709 metrics->y_scale = metrics->x_scale; | |
2710 goto Calculate_Ppem; | |
2711 | |
2712 case FT_SIZE_REQUEST_TYPE_MAX: | |
2713 break; | |
2714 } | |
2715 | |
2716 /* to be on the safe side */ | |
2717 if ( w < 0 ) | |
2718 w = -w; | |
2719 | |
2720 if ( h < 0 ) | |
2721 h = -h; | |
2722 | |
2723 scaled_w = FT_REQUEST_WIDTH ( req ); | |
2724 scaled_h = FT_REQUEST_HEIGHT( req ); | |
2725 | |
2726 /* determine scales */ | |
2727 if ( req->width ) | |
2728 { | |
2729 metrics->x_scale = FT_DivFix( scaled_w, w ); | |
2730 | |
2731 if ( req->height ) | |
2732 { | |
2733 metrics->y_scale = FT_DivFix( scaled_h, h ); | |
2734 | |
2735 if ( req->type == FT_SIZE_REQUEST_TYPE_CELL ) | |
2736 { | |
2737 if ( metrics->y_scale > metrics->x_scale ) | |
2738 metrics->y_scale = metrics->x_scale; | |
2739 else | |
2740 metrics->x_scale = metrics->y_scale; | |
2741 } | |
2742 } | |
2743 else | |
2744 { | |
2745 metrics->y_scale = metrics->x_scale; | |
2746 scaled_h = FT_MulDiv( scaled_w, h, w ); | |
2747 } | |
2748 } | |
2749 else | |
2750 { | |
2751 metrics->x_scale = metrics->y_scale = FT_DivFix( scaled_h, h ); | |
2752 scaled_w = FT_MulDiv( scaled_h, w, h ); | |
2753 } | |
2754 | |
2755 Calculate_Ppem: | |
2756 /* calculate the ppems */ | |
2757 if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) | |
2758 { | |
2759 scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale ); | |
2760 scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale ); | |
2761 } | |
2762 | |
2763 metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 ); | |
2764 metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 ); | |
2765 | |
2766 ft_recompute_scaled_metrics( face, metrics ); | |
2767 } | |
2768 else | |
2769 { | |
2770 FT_ZERO( metrics ); | |
2771 metrics->x_scale = 1L << 16; | |
2772 metrics->y_scale = 1L << 16; | |
2773 } | |
2774 | |
2775 FT_TRACE5(( "FT_Request_Metrics:\n" )); | |
2776 FT_TRACE5(( " x scale: %d (%f)\n", | |
2777 metrics->x_scale, metrics->x_scale / 65536.0 )); | |
2778 FT_TRACE5(( " y scale: %d (%f)\n", | |
2779 metrics->y_scale, metrics->y_scale / 65536.0 )); | |
2780 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); | |
2781 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); | |
2782 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); | |
2783 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); | |
2784 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); | |
2785 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); | |
2786 } | |
2787 | |
2788 | |
2789 /* documentation is in freetype.h */ | |
2790 | |
2791 FT_EXPORT_DEF( FT_Error ) | |
2792 FT_Select_Size( FT_Face face, | |
2793 FT_Int strike_index ) | |
2794 { | |
2795 FT_Driver_Class clazz; | |
2796 | |
2797 | |
2798 if ( !face || !FT_HAS_FIXED_SIZES( face ) ) | |
2799 return FT_THROW( Invalid_Face_Handle ); | |
2800 | |
2801 if ( strike_index < 0 || strike_index >= face->num_fixed_sizes ) | |
2802 return FT_THROW( Invalid_Argument ); | |
2803 | |
2804 clazz = face->driver->clazz; | |
2805 | |
2806 if ( clazz->select_size ) | |
2807 { | |
2808 FT_Error error; | |
2809 | |
2810 | |
2811 error = clazz->select_size( face->size, (FT_ULong)strike_index ); | |
2812 | |
2813 #ifdef FT_DEBUG_LEVEL_TRACE | |
2814 { | |
2815 FT_Size_Metrics* metrics = &face->size->metrics; | |
2816 | |
2817 | |
2818 FT_TRACE5(( "FT_Select_Size (font driver's `select_size'):\n" )); | |
2819 FT_TRACE5(( " x scale: %d (%f)\n", | |
2820 metrics->x_scale, metrics->x_scale / 65536.0 )); | |
2821 FT_TRACE5(( " y scale: %d (%f)\n", | |
2822 metrics->y_scale, metrics->y_scale / 65536.0 )); | |
2823 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); | |
2824 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); | |
2825 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); | |
2826 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); | |
2827 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); | |
2828 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); | |
2829 } | |
2830 #endif | |
2831 | |
2832 return error; | |
2833 } | |
2834 | |
2835 FT_Select_Metrics( face, (FT_ULong)strike_index ); | |
2836 | |
2837 return FT_Err_Ok; | |
2838 } | |
2839 | |
2840 | |
2841 /* documentation is in freetype.h */ | |
2842 | |
2843 FT_EXPORT_DEF( FT_Error ) | |
2844 FT_Request_Size( FT_Face face, | |
2845 FT_Size_Request req ) | |
2846 { | |
2847 FT_Driver_Class clazz; | |
2848 FT_ULong strike_index; | |
2849 | |
2850 | |
2851 if ( !face ) | |
2852 return FT_THROW( Invalid_Face_Handle ); | |
2853 | |
2854 if ( !req || req->width < 0 || req->height < 0 || | |
2855 req->type >= FT_SIZE_REQUEST_TYPE_MAX ) | |
2856 return FT_THROW( Invalid_Argument ); | |
2857 | |
2858 clazz = face->driver->clazz; | |
2859 | |
2860 if ( clazz->request_size ) | |
2861 { | |
2862 FT_Error error; | |
2863 | |
2864 | |
2865 error = clazz->request_size( face->size, req ); | |
2866 | |
2867 #ifdef FT_DEBUG_LEVEL_TRACE | |
2868 { | |
2869 FT_Size_Metrics* metrics = &face->size->metrics; | |
2870 | |
2871 | |
2872 FT_TRACE5(( "FT_Request_Size (font driver's `request_size'):\n" )); | |
2873 FT_TRACE5(( " x scale: %d (%f)\n", | |
2874 metrics->x_scale, metrics->x_scale / 65536.0 )); | |
2875 FT_TRACE5(( " y scale: %d (%f)\n", | |
2876 metrics->y_scale, metrics->y_scale / 65536.0 )); | |
2877 FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); | |
2878 FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); | |
2879 FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); | |
2880 FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); | |
2881 FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); | |
2882 FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); | |
2883 } | |
2884 #endif | |
2885 | |
2886 return error; | |
2887 } | |
2888 | |
2889 /* | |
2890 * The reason that a driver doesn't have `request_size' defined is | |
2891 * either that the scaling here suffices or that the supported formats | |
2892 * are bitmap-only and size matching is not implemented. | |
2893 * | |
2894 * In the latter case, a simple size matching is done. | |
2895 */ | |
2896 if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) ) | |
2897 { | |
2898 FT_Error error; | |
2899 | |
2900 | |
2901 error = FT_Match_Size( face, req, 0, &strike_index ); | |
2902 if ( error ) | |
2903 return error; | |
2904 | |
2905 return FT_Select_Size( face, (FT_Int)strike_index ); | |
2906 } | |
2907 | |
2908 FT_Request_Metrics( face, req ); | |
2909 | |
2910 return FT_Err_Ok; | |
2911 } | |
2912 | |
2913 | |
2914 /* documentation is in freetype.h */ | |
2915 | |
2916 FT_EXPORT_DEF( FT_Error ) | |
2917 FT_Set_Char_Size( FT_Face face, | |
2918 FT_F26Dot6 char_width, | |
2919 FT_F26Dot6 char_height, | |
2920 FT_UInt horz_resolution, | |
2921 FT_UInt vert_resolution ) | |
2922 { | |
2923 FT_Size_RequestRec req; | |
2924 | |
2925 | |
2926 if ( !char_width ) | |
2927 char_width = char_height; | |
2928 else if ( !char_height ) | |
2929 char_height = char_width; | |
2930 | |
2931 if ( !horz_resolution ) | |
2932 horz_resolution = vert_resolution; | |
2933 else if ( !vert_resolution ) | |
2934 vert_resolution = horz_resolution; | |
2935 | |
2936 if ( char_width < 1 * 64 ) | |
2937 char_width = 1 * 64; | |
2938 if ( char_height < 1 * 64 ) | |
2939 char_height = 1 * 64; | |
2940 | |
2941 if ( !horz_resolution ) | |
2942 horz_resolution = vert_resolution = 72; | |
2943 | |
2944 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; | |
2945 req.width = char_width; | |
2946 req.height = char_height; | |
2947 req.horiResolution = horz_resolution; | |
2948 req.vertResolution = vert_resolution; | |
2949 | |
2950 return FT_Request_Size( face, &req ); | |
2951 } | |
2952 | |
2953 | |
2954 /* documentation is in freetype.h */ | |
2955 | |
2956 FT_EXPORT_DEF( FT_Error ) | |
2957 FT_Set_Pixel_Sizes( FT_Face face, | |
2958 FT_UInt pixel_width, | |
2959 FT_UInt pixel_height ) | |
2960 { | |
2961 FT_Size_RequestRec req; | |
2962 | |
2963 | |
2964 if ( pixel_width == 0 ) | |
2965 pixel_width = pixel_height; | |
2966 else if ( pixel_height == 0 ) | |
2967 pixel_height = pixel_width; | |
2968 | |
2969 if ( pixel_width < 1 ) | |
2970 pixel_width = 1; | |
2971 if ( pixel_height < 1 ) | |
2972 pixel_height = 1; | |
2973 | |
2974 /* use `>=' to avoid potential compiler warning on 16bit platforms */ | |
2975 if ( pixel_width >= 0xFFFFU ) | |
2976 pixel_width = 0xFFFFU; | |
2977 if ( pixel_height >= 0xFFFFU ) | |
2978 pixel_height = 0xFFFFU; | |
2979 | |
2980 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; | |
2981 req.width = pixel_width << 6; | |
2982 req.height = pixel_height << 6; | |
2983 req.horiResolution = 0; | |
2984 req.vertResolution = 0; | |
2985 | |
2986 return FT_Request_Size( face, &req ); | |
2987 } | |
2988 | |
2989 | |
2990 /* documentation is in freetype.h */ | |
2991 | |
2992 FT_EXPORT_DEF( FT_Error ) | |
2993 FT_Get_Kerning( FT_Face face, | |
2994 FT_UInt left_glyph, | |
2995 FT_UInt right_glyph, | |
2996 FT_UInt kern_mode, | |
2997 FT_Vector *akerning ) | |
2998 { | |
2999 FT_Error error = FT_Err_Ok; | |
3000 FT_Driver driver; | |
3001 | |
3002 | |
3003 if ( !face ) | |
3004 return FT_THROW( Invalid_Face_Handle ); | |
3005 | |
3006 if ( !akerning ) | |
3007 return FT_THROW( Invalid_Argument ); | |
3008 | |
3009 driver = face->driver; | |
3010 | |
3011 akerning->x = 0; | |
3012 akerning->y = 0; | |
3013 | |
3014 if ( driver->clazz->get_kerning ) | |
3015 { | |
3016 error = driver->clazz->get_kerning( face, | |
3017 left_glyph, | |
3018 right_glyph, | |
3019 akerning ); | |
3020 if ( !error ) | |
3021 { | |
3022 if ( kern_mode != FT_KERNING_UNSCALED ) | |
3023 { | |
3024 akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale ); | |
3025 akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale ); | |
3026 | |
3027 if ( kern_mode != FT_KERNING_UNFITTED ) | |
3028 { | |
3029 /* we scale down kerning values for small ppem values */ | |
3030 /* to avoid that rounding makes them too big. */ | |
3031 /* `25' has been determined heuristically. */ | |
3032 if ( face->size->metrics.x_ppem < 25 ) | |
3033 akerning->x = FT_MulDiv( akerning->x, | |
3034 face->size->metrics.x_ppem, 25 ); | |
3035 if ( face->size->metrics.y_ppem < 25 ) | |
3036 akerning->y = FT_MulDiv( akerning->y, | |
3037 face->size->metrics.y_ppem, 25 ); | |
3038 | |
3039 akerning->x = FT_PIX_ROUND( akerning->x ); | |
3040 akerning->y = FT_PIX_ROUND( akerning->y ); | |
3041 } | |
3042 } | |
3043 } | |
3044 } | |
3045 | |
3046 return error; | |
3047 } | |
3048 | |
3049 | |
3050 /* documentation is in freetype.h */ | |
3051 | |
3052 FT_EXPORT_DEF( FT_Error ) | |
3053 FT_Get_Track_Kerning( FT_Face face, | |
3054 FT_Fixed point_size, | |
3055 FT_Int degree, | |
3056 FT_Fixed* akerning ) | |
3057 { | |
3058 FT_Service_Kerning service; | |
3059 FT_Error error = FT_Err_Ok; | |
3060 | |
3061 | |
3062 if ( !face ) | |
3063 return FT_THROW( Invalid_Face_Handle ); | |
3064 | |
3065 if ( !akerning ) | |
3066 return FT_THROW( Invalid_Argument ); | |
3067 | |
3068 FT_FACE_FIND_SERVICE( face, service, KERNING ); | |
3069 if ( !service ) | |
3070 return FT_THROW( Unimplemented_Feature ); | |
3071 | |
3072 error = service->get_track( face, | |
3073 point_size, | |
3074 degree, | |
3075 akerning ); | |
3076 | |
3077 return error; | |
3078 } | |
3079 | |
3080 | |
3081 /* documentation is in freetype.h */ | |
3082 | |
3083 FT_EXPORT_DEF( FT_Error ) | |
3084 FT_Select_Charmap( FT_Face face, | |
3085 FT_Encoding encoding ) | |
3086 { | |
3087 FT_CharMap* cur; | |
3088 FT_CharMap* limit; | |
3089 | |
3090 | |
3091 if ( !face ) | |
3092 return FT_THROW( Invalid_Face_Handle ); | |
3093 | |
3094 if ( encoding == FT_ENCODING_NONE ) | |
3095 return FT_THROW( Invalid_Argument ); | |
3096 | |
3097 /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */ | |
3098 /* charmap available, i.e., one with UCS-4 characters, if possible. */ | |
3099 /* */ | |
3100 /* This is done by find_unicode_charmap() above, to share code. */ | |
3101 if ( encoding == FT_ENCODING_UNICODE ) | |
3102 return find_unicode_charmap( face ); | |
3103 | |
3104 cur = face->charmaps; | |
3105 if ( !cur ) | |
3106 return FT_THROW( Invalid_CharMap_Handle ); | |
3107 | |
3108 limit = cur + face->num_charmaps; | |
3109 | |
3110 for ( ; cur < limit; cur++ ) | |
3111 { | |
3112 if ( cur[0]->encoding == encoding ) | |
3113 { | |
3114 #ifdef FT_MAX_CHARMAP_CACHEABLE | |
3115 if ( cur - face->charmaps > FT_MAX_CHARMAP_CACHEABLE ) | |
3116 { | |
3117 FT_ERROR(( "FT_Select_Charmap: requested charmap is found (%d), " | |
3118 "but in too late position to cache\n", | |
3119 cur - face->charmaps )); | |
3120 continue; | |
3121 } | |
3122 #endif | |
3123 face->charmap = cur[0]; | |
3124 return 0; | |
3125 } | |
3126 } | |
3127 | |
3128 return FT_THROW( Invalid_Argument ); | |
3129 } | |
3130 | |
3131 | |
3132 /* documentation is in freetype.h */ | |
3133 | |
3134 FT_EXPORT_DEF( FT_Error ) | |
3135 FT_Set_Charmap( FT_Face face, | |
3136 FT_CharMap charmap ) | |
3137 { | |
3138 FT_CharMap* cur; | |
3139 FT_CharMap* limit; | |
3140 | |
3141 | |
3142 if ( !face ) | |
3143 return FT_THROW( Invalid_Face_Handle ); | |
3144 | |
3145 cur = face->charmaps; | |
3146 if ( !cur ) | |
3147 return FT_THROW( Invalid_CharMap_Handle ); | |
3148 if ( FT_Get_CMap_Format( charmap ) == 14 ) | |
3149 return FT_THROW( Invalid_Argument ); | |
3150 | |
3151 limit = cur + face->num_charmaps; | |
3152 | |
3153 for ( ; cur < limit; cur++ ) | |
3154 { | |
3155 if ( cur[0] == charmap ) | |
3156 { | |
3157 #ifdef FT_MAX_CHARMAP_CACHEABLE | |
3158 if ( cur - face->charmaps > FT_MAX_CHARMAP_CACHEABLE ) | |
3159 { | |
3160 FT_ERROR(( "FT_Set_Charmap: requested charmap is found (%d), " | |
3161 "but in too late position to cache\n", | |
3162 cur - face->charmaps )); | |
3163 continue; | |
3164 } | |
3165 #endif | |
3166 face->charmap = cur[0]; | |
3167 return 0; | |
3168 } | |
3169 } | |
3170 return FT_THROW( Invalid_Argument ); | |
3171 } | |
3172 | |
3173 | |
3174 /* documentation is in freetype.h */ | |
3175 | |
3176 FT_EXPORT_DEF( FT_Int ) | |
3177 FT_Get_Charmap_Index( FT_CharMap charmap ) | |
3178 { | |
3179 FT_Int i; | |
3180 | |
3181 | |
3182 if ( !charmap || !charmap->face ) | |
3183 return -1; | |
3184 | |
3185 for ( i = 0; i < charmap->face->num_charmaps; i++ ) | |
3186 if ( charmap->face->charmaps[i] == charmap ) | |
3187 break; | |
3188 | |
3189 FT_ASSERT( i < charmap->face->num_charmaps ); | |
3190 | |
3191 #ifdef FT_MAX_CHARMAP_CACHEABLE | |
3192 if ( i > FT_MAX_CHARMAP_CACHEABLE ) | |
3193 { | |
3194 FT_ERROR(( "FT_Get_Charmap_Index: requested charmap is found (%d), " | |
3195 "but in too late position to cache\n", | |
3196 i )); | |
3197 return -i; | |
3198 } | |
3199 #endif | |
3200 return i; | |
3201 } | |
3202 | |
3203 | |
3204 static void | |
3205 ft_cmap_done_internal( FT_CMap cmap ) | |
3206 { | |
3207 FT_CMap_Class clazz = cmap->clazz; | |
3208 FT_Face face = cmap->charmap.face; | |
3209 FT_Memory memory = FT_FACE_MEMORY( face ); | |
3210 | |
3211 | |
3212 if ( clazz->done ) | |
3213 clazz->done( cmap ); | |
3214 | |
3215 FT_FREE( cmap ); | |
3216 } | |
3217 | |
3218 | |
3219 FT_BASE_DEF( void ) | |
3220 FT_CMap_Done( FT_CMap cmap ) | |
3221 { | |
3222 if ( cmap ) | |
3223 { | |
3224 FT_Face face = cmap->charmap.face; | |
3225 FT_Memory memory = FT_FACE_MEMORY( face ); | |
3226 FT_Error error; | |
3227 FT_Int i, j; | |
3228 | |
3229 | |
3230 for ( i = 0; i < face->num_charmaps; i++ ) | |
3231 { | |
3232 if ( (FT_CMap)face->charmaps[i] == cmap ) | |
3233 { | |
3234 FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1]; | |
3235 | |
3236 | |
3237 if ( FT_RENEW_ARRAY( face->charmaps, | |
3238 face->num_charmaps, | |
3239 face->num_charmaps - 1 ) ) | |
3240 return; | |
3241 | |
3242 /* remove it from our list of charmaps */ | |
3243 for ( j = i + 1; j < face->num_charmaps; j++ ) | |
3244 { | |
3245 if ( j == face->num_charmaps - 1 ) | |
3246 face->charmaps[j - 1] = last_charmap; | |
3247 else | |
3248 face->charmaps[j - 1] = face->charmaps[j]; | |
3249 } | |
3250 | |
3251 face->num_charmaps--; | |
3252 | |
3253 if ( (FT_CMap)face->charmap == cmap ) | |
3254 face->charmap = NULL; | |
3255 | |
3256 ft_cmap_done_internal( cmap ); | |
3257 | |
3258 break; | |
3259 } | |
3260 } | |
3261 } | |
3262 } | |
3263 | |
3264 | |
3265 FT_BASE_DEF( FT_Error ) | |
3266 FT_CMap_New( FT_CMap_Class clazz, | |
3267 FT_Pointer init_data, | |
3268 FT_CharMap charmap, | |
3269 FT_CMap *acmap ) | |
3270 { | |
3271 FT_Error error = FT_Err_Ok; | |
3272 FT_Face face; | |
3273 FT_Memory memory; | |
3274 FT_CMap cmap = NULL; | |
3275 | |
3276 | |
3277 if ( clazz == NULL || charmap == NULL || charmap->face == NULL ) | |
3278 return FT_THROW( Invalid_Argument ); | |
3279 | |
3280 face = charmap->face; | |
3281 memory = FT_FACE_MEMORY( face ); | |
3282 | |
3283 if ( !FT_ALLOC( cmap, clazz->size ) ) | |
3284 { | |
3285 cmap->charmap = *charmap; | |
3286 cmap->clazz = clazz; | |
3287 | |
3288 if ( clazz->init ) | |
3289 { | |
3290 error = clazz->init( cmap, init_data ); | |
3291 if ( error ) | |
3292 goto Fail; | |
3293 } | |
3294 | |
3295 /* add it to our list of charmaps */ | |
3296 if ( FT_RENEW_ARRAY( face->charmaps, | |
3297 face->num_charmaps, | |
3298 face->num_charmaps + 1 ) ) | |
3299 goto Fail; | |
3300 | |
3301 face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap; | |
3302 } | |
3303 | |
3304 Exit: | |
3305 if ( acmap ) | |
3306 *acmap = cmap; | |
3307 | |
3308 return error; | |
3309 | |
3310 Fail: | |
3311 ft_cmap_done_internal( cmap ); | |
3312 cmap = NULL; | |
3313 goto Exit; | |
3314 } | |
3315 | |
3316 | |
3317 /* documentation is in freetype.h */ | |
3318 | |
3319 FT_EXPORT_DEF( FT_UInt ) | |
3320 FT_Get_Char_Index( FT_Face face, | |
3321 FT_ULong charcode ) | |
3322 { | |
3323 FT_UInt result = 0; | |
3324 | |
3325 | |
3326 if ( face && face->charmap ) | |
3327 { | |
3328 FT_CMap cmap = FT_CMAP( face->charmap ); | |
3329 | |
3330 | |
3331 if ( charcode > 0xFFFFFFFFUL ) | |
3332 { | |
3333 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); | |
3334 FT_TRACE1(( " 0x%x is truncated\n", charcode )); | |
3335 } | |
3336 result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode ); | |
3337 } | |
3338 return result; | |
3339 } | |
3340 | |
3341 | |
3342 /* documentation is in freetype.h */ | |
3343 | |
3344 FT_EXPORT_DEF( FT_ULong ) | |
3345 FT_Get_First_Char( FT_Face face, | |
3346 FT_UInt *agindex ) | |
3347 { | |
3348 FT_ULong result = 0; | |
3349 FT_UInt gindex = 0; | |
3350 | |
3351 | |
3352 if ( face && face->charmap && face->num_glyphs ) | |
3353 { | |
3354 gindex = FT_Get_Char_Index( face, 0 ); | |
3355 if ( gindex == 0 || gindex >= (FT_UInt)face->num_glyphs ) | |
3356 result = FT_Get_Next_Char( face, 0, &gindex ); | |
3357 } | |
3358 | |
3359 if ( agindex ) | |
3360 *agindex = gindex; | |
3361 | |
3362 return result; | |
3363 } | |
3364 | |
3365 | |
3366 /* documentation is in freetype.h */ | |
3367 | |
3368 FT_EXPORT_DEF( FT_ULong ) | |
3369 FT_Get_Next_Char( FT_Face face, | |
3370 FT_ULong charcode, | |
3371 FT_UInt *agindex ) | |
3372 { | |
3373 FT_ULong result = 0; | |
3374 FT_UInt gindex = 0; | |
3375 | |
3376 | |
3377 if ( face && face->charmap && face->num_glyphs ) | |
3378 { | |
3379 FT_UInt32 code = (FT_UInt32)charcode; | |
3380 FT_CMap cmap = FT_CMAP( face->charmap ); | |
3381 | |
3382 | |
3383 do { | |
3384 gindex = cmap->clazz->char_next( cmap, &code ); | |
3385 } while ( gindex >= (FT_UInt)face->num_glyphs ); | |
3386 | |
3387 result = ( gindex == 0 ) ? 0 : code; | |
3388 } | |
3389 | |
3390 if ( agindex ) | |
3391 *agindex = gindex; | |
3392 | |
3393 return result; | |
3394 } | |
3395 | |
3396 | |
3397 /* documentation is in freetype.h */ | |
3398 | |
3399 FT_EXPORT_DEF( FT_UInt ) | |
3400 FT_Face_GetCharVariantIndex( FT_Face face, | |
3401 FT_ULong charcode, | |
3402 FT_ULong variantSelector ) | |
3403 { | |
3404 FT_UInt result = 0; | |
3405 | |
3406 | |
3407 if ( face && face->charmap && | |
3408 face->charmap->encoding == FT_ENCODING_UNICODE ) | |
3409 { | |
3410 FT_CharMap charmap = find_variant_selector_charmap( face ); | |
3411 FT_CMap ucmap = FT_CMAP( face->charmap ); | |
3412 | |
3413 | |
3414 if ( charmap != NULL ) | |
3415 { | |
3416 FT_CMap vcmap = FT_CMAP( charmap ); | |
3417 | |
3418 | |
3419 if ( charcode > 0xFFFFFFFFUL ) | |
3420 { | |
3421 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); | |
3422 FT_TRACE1(( " 0x%x is truncated\n", charcode )); | |
3423 } | |
3424 if ( variantSelector > 0xFFFFFFFFUL ) | |
3425 { | |
3426 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); | |
3427 FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); | |
3428 } | |
3429 | |
3430 result = vcmap->clazz->char_var_index( vcmap, ucmap, | |
3431 (FT_UInt32)charcode, | |
3432 (FT_UInt32)variantSelector ); | |
3433 } | |
3434 } | |
3435 | |
3436 return result; | |
3437 } | |
3438 | |
3439 | |
3440 /* documentation is in freetype.h */ | |
3441 | |
3442 FT_EXPORT_DEF( FT_Int ) | |
3443 FT_Face_GetCharVariantIsDefault( FT_Face face, | |
3444 FT_ULong charcode, | |
3445 FT_ULong variantSelector ) | |
3446 { | |
3447 FT_Int result = -1; | |
3448 | |
3449 | |
3450 if ( face ) | |
3451 { | |
3452 FT_CharMap charmap = find_variant_selector_charmap( face ); | |
3453 | |
3454 | |
3455 if ( charmap != NULL ) | |
3456 { | |
3457 FT_CMap vcmap = FT_CMAP( charmap ); | |
3458 | |
3459 | |
3460 if ( charcode > 0xFFFFFFFFUL ) | |
3461 { | |
3462 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); | |
3463 FT_TRACE1(( " 0x%x is truncated\n", charcode )); | |
3464 } | |
3465 if ( variantSelector > 0xFFFFFFFFUL ) | |
3466 { | |
3467 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); | |
3468 FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); | |
3469 } | |
3470 | |
3471 result = vcmap->clazz->char_var_default( vcmap, | |
3472 (FT_UInt32)charcode, | |
3473 (FT_UInt32)variantSelector ); | |
3474 } | |
3475 } | |
3476 | |
3477 return result; | |
3478 } | |
3479 | |
3480 | |
3481 /* documentation is in freetype.h */ | |
3482 | |
3483 FT_EXPORT_DEF( FT_UInt32* ) | |
3484 FT_Face_GetVariantSelectors( FT_Face face ) | |
3485 { | |
3486 FT_UInt32 *result = NULL; | |
3487 | |
3488 | |
3489 if ( face ) | |
3490 { | |
3491 FT_CharMap charmap = find_variant_selector_charmap( face ); | |
3492 | |
3493 | |
3494 if ( charmap != NULL ) | |
3495 { | |
3496 FT_CMap vcmap = FT_CMAP( charmap ); | |
3497 FT_Memory memory = FT_FACE_MEMORY( face ); | |
3498 | |
3499 | |
3500 result = vcmap->clazz->variant_list( vcmap, memory ); | |
3501 } | |
3502 } | |
3503 | |
3504 return result; | |
3505 } | |
3506 | |
3507 | |
3508 /* documentation is in freetype.h */ | |
3509 | |
3510 FT_EXPORT_DEF( FT_UInt32* ) | |
3511 FT_Face_GetVariantsOfChar( FT_Face face, | |
3512 FT_ULong charcode ) | |
3513 { | |
3514 FT_UInt32 *result = NULL; | |
3515 | |
3516 | |
3517 if ( face ) | |
3518 { | |
3519 FT_CharMap charmap = find_variant_selector_charmap( face ); | |
3520 | |
3521 | |
3522 if ( charmap != NULL ) | |
3523 { | |
3524 FT_CMap vcmap = FT_CMAP( charmap ); | |
3525 FT_Memory memory = FT_FACE_MEMORY( face ); | |
3526 | |
3527 | |
3528 if ( charcode > 0xFFFFFFFFUL ) | |
3529 { | |
3530 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); | |
3531 FT_TRACE1(( " 0x%x is truncated\n", charcode )); | |
3532 } | |
3533 | |
3534 result = vcmap->clazz->charvariant_list( vcmap, memory, | |
3535 (FT_UInt32)charcode ); | |
3536 } | |
3537 } | |
3538 return result; | |
3539 } | |
3540 | |
3541 | |
3542 /* documentation is in freetype.h */ | |
3543 | |
3544 FT_EXPORT_DEF( FT_UInt32* ) | |
3545 FT_Face_GetCharsOfVariant( FT_Face face, | |
3546 FT_ULong variantSelector ) | |
3547 { | |
3548 FT_UInt32 *result = NULL; | |
3549 | |
3550 | |
3551 if ( face ) | |
3552 { | |
3553 FT_CharMap charmap = find_variant_selector_charmap( face ); | |
3554 | |
3555 | |
3556 if ( charmap != NULL ) | |
3557 { | |
3558 FT_CMap vcmap = FT_CMAP( charmap ); | |
3559 FT_Memory memory = FT_FACE_MEMORY( face ); | |
3560 | |
3561 | |
3562 if ( variantSelector > 0xFFFFFFFFUL ) | |
3563 { | |
3564 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); | |
3565 FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); | |
3566 } | |
3567 | |
3568 result = vcmap->clazz->variantchar_list( vcmap, memory, | |
3569 (FT_UInt32)variantSelector ); | |
3570 } | |
3571 } | |
3572 | |
3573 return result; | |
3574 } | |
3575 | |
3576 | |
3577 /* documentation is in freetype.h */ | |
3578 | |
3579 FT_EXPORT_DEF( FT_UInt ) | |
3580 FT_Get_Name_Index( FT_Face face, | |
3581 FT_String* glyph_name ) | |
3582 { | |
3583 FT_UInt result = 0; | |
3584 | |
3585 | |
3586 if ( face && FT_HAS_GLYPH_NAMES( face ) ) | |
3587 { | |
3588 FT_Service_GlyphDict service; | |
3589 | |
3590 | |
3591 FT_FACE_LOOKUP_SERVICE( face, | |
3592 service, | |
3593 GLYPH_DICT ); | |
3594 | |
3595 if ( service && service->name_index ) | |
3596 result = service->name_index( face, glyph_name ); | |
3597 } | |
3598 | |
3599 return result; | |
3600 } | |
3601 | |
3602 | |
3603 /* documentation is in freetype.h */ | |
3604 | |
3605 FT_EXPORT_DEF( FT_Error ) | |
3606 FT_Get_Glyph_Name( FT_Face face, | |
3607 FT_UInt glyph_index, | |
3608 FT_Pointer buffer, | |
3609 FT_UInt buffer_max ) | |
3610 { | |
3611 FT_Error error = FT_ERR( Invalid_Argument ); | |
3612 | |
3613 | |
3614 /* clean up buffer */ | |
3615 if ( buffer && buffer_max > 0 ) | |
3616 ((FT_Byte*)buffer)[0] = 0; | |
3617 | |
3618 if ( face && | |
3619 (FT_Long)glyph_index < face->num_glyphs && | |
3620 FT_HAS_GLYPH_NAMES( face ) ) | |
3621 { | |
3622 FT_Service_GlyphDict service; | |
3623 | |
3624 | |
3625 FT_FACE_LOOKUP_SERVICE( face, | |
3626 service, | |
3627 GLYPH_DICT ); | |
3628 | |
3629 if ( service && service->get_name ) | |
3630 error = service->get_name( face, glyph_index, buffer, buffer_max ); | |
3631 } | |
3632 | |
3633 return error; | |
3634 } | |
3635 | |
3636 | |
3637 /* documentation is in freetype.h */ | |
3638 | |
3639 FT_EXPORT_DEF( const char* ) | |
3640 FT_Get_Postscript_Name( FT_Face face ) | |
3641 { | |
3642 const char* result = NULL; | |
3643 | |
3644 | |
3645 if ( !face ) | |
3646 goto Exit; | |
3647 | |
3648 if ( !result ) | |
3649 { | |
3650 FT_Service_PsFontName service; | |
3651 | |
3652 | |
3653 FT_FACE_LOOKUP_SERVICE( face, | |
3654 service, | |
3655 POSTSCRIPT_FONT_NAME ); | |
3656 | |
3657 if ( service && service->get_ps_font_name ) | |
3658 result = service->get_ps_font_name( face ); | |
3659 } | |
3660 | |
3661 Exit: | |
3662 return result; | |
3663 } | |
3664 | |
3665 | |
3666 /* documentation is in tttables.h */ | |
3667 | |
3668 FT_EXPORT_DEF( void* ) | |
3669 FT_Get_Sfnt_Table( FT_Face face, | |
3670 FT_Sfnt_Tag tag ) | |
3671 { | |
3672 void* table = 0; | |
3673 FT_Service_SFNT_Table service; | |
3674 | |
3675 | |
3676 if ( face && FT_IS_SFNT( face ) ) | |
3677 { | |
3678 FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); | |
3679 if ( service != NULL ) | |
3680 table = service->get_table( face, tag ); | |
3681 } | |
3682 | |
3683 return table; | |
3684 } | |
3685 | |
3686 | |
3687 /* documentation is in tttables.h */ | |
3688 | |
3689 FT_EXPORT_DEF( FT_Error ) | |
3690 FT_Load_Sfnt_Table( FT_Face face, | |
3691 FT_ULong tag, | |
3692 FT_Long offset, | |
3693 FT_Byte* buffer, | |
3694 FT_ULong* length ) | |
3695 { | |
3696 FT_Service_SFNT_Table service; | |
3697 | |
3698 | |
3699 if ( !face || !FT_IS_SFNT( face ) ) | |
3700 return FT_THROW( Invalid_Face_Handle ); | |
3701 | |
3702 FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); | |
3703 if ( service == NULL ) | |
3704 return FT_THROW( Unimplemented_Feature ); | |
3705 | |
3706 return service->load_table( face, tag, offset, buffer, length ); | |
3707 } | |
3708 | |
3709 | |
3710 /* documentation is in tttables.h */ | |
3711 | |
3712 FT_EXPORT_DEF( FT_Error ) | |
3713 FT_Sfnt_Table_Info( FT_Face face, | |
3714 FT_UInt table_index, | |
3715 FT_ULong *tag, | |
3716 FT_ULong *length ) | |
3717 { | |
3718 FT_Service_SFNT_Table service; | |
3719 FT_ULong offset; | |
3720 | |
3721 | |
3722 if ( !face || !FT_IS_SFNT( face ) ) | |
3723 return FT_THROW( Invalid_Face_Handle ); | |
3724 | |
3725 FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); | |
3726 if ( service == NULL ) | |
3727 return FT_THROW( Unimplemented_Feature ); | |
3728 | |
3729 return service->table_info( face, table_index, tag, &offset, length ); | |
3730 } | |
3731 | |
3732 | |
3733 /* documentation is in tttables.h */ | |
3734 | |
3735 FT_EXPORT_DEF( FT_ULong ) | |
3736 FT_Get_CMap_Language_ID( FT_CharMap charmap ) | |
3737 { | |
3738 FT_Service_TTCMaps service; | |
3739 FT_Face face; | |
3740 TT_CMapInfo cmap_info; | |
3741 | |
3742 | |
3743 if ( !charmap || !charmap->face ) | |
3744 return 0; | |
3745 | |
3746 face = charmap->face; | |
3747 FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); | |
3748 if ( service == NULL ) | |
3749 return 0; | |
3750 if ( service->get_cmap_info( charmap, &cmap_info )) | |
3751 return 0; | |
3752 | |
3753 return cmap_info.language; | |
3754 } | |
3755 | |
3756 | |
3757 /* documentation is in tttables.h */ | |
3758 | |
3759 FT_EXPORT_DEF( FT_Long ) | |
3760 FT_Get_CMap_Format( FT_CharMap charmap ) | |
3761 { | |
3762 FT_Service_TTCMaps service; | |
3763 FT_Face face; | |
3764 TT_CMapInfo cmap_info; | |
3765 | |
3766 | |
3767 if ( !charmap || !charmap->face ) | |
3768 return -1; | |
3769 | |
3770 face = charmap->face; | |
3771 FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); | |
3772 if ( service == NULL ) | |
3773 return -1; | |
3774 if ( service->get_cmap_info( charmap, &cmap_info )) | |
3775 return -1; | |
3776 | |
3777 return cmap_info.format; | |
3778 } | |
3779 | |
3780 | |
3781 /* documentation is in ftsizes.h */ | |
3782 | |
3783 FT_EXPORT_DEF( FT_Error ) | |
3784 FT_Activate_Size( FT_Size size ) | |
3785 { | |
3786 FT_Face face; | |
3787 | |
3788 | |
3789 if ( size == NULL ) | |
3790 return FT_THROW( Invalid_Argument ); | |
3791 | |
3792 face = size->face; | |
3793 if ( face == NULL || face->driver == NULL ) | |
3794 return FT_THROW( Invalid_Argument ); | |
3795 | |
3796 /* we don't need anything more complex than that; all size objects */ | |
3797 /* are already listed by the face */ | |
3798 face->size = size; | |
3799 | |
3800 return FT_Err_Ok; | |
3801 } | |
3802 | |
3803 | |
3804 /*************************************************************************/ | |
3805 /*************************************************************************/ | |
3806 /*************************************************************************/ | |
3807 /**** ****/ | |
3808 /**** ****/ | |
3809 /**** R E N D E R E R S ****/ | |
3810 /**** ****/ | |
3811 /**** ****/ | |
3812 /*************************************************************************/ | |
3813 /*************************************************************************/ | |
3814 /*************************************************************************/ | |
3815 | |
3816 /* lookup a renderer by glyph format in the library's list */ | |
3817 FT_BASE_DEF( FT_Renderer ) | |
3818 FT_Lookup_Renderer( FT_Library library, | |
3819 FT_Glyph_Format format, | |
3820 FT_ListNode* node ) | |
3821 { | |
3822 FT_ListNode cur; | |
3823 FT_Renderer result = 0; | |
3824 | |
3825 | |
3826 if ( !library ) | |
3827 goto Exit; | |
3828 | |
3829 cur = library->renderers.head; | |
3830 | |
3831 if ( node ) | |
3832 { | |
3833 if ( *node ) | |
3834 cur = (*node)->next; | |
3835 *node = 0; | |
3836 } | |
3837 | |
3838 while ( cur ) | |
3839 { | |
3840 FT_Renderer renderer = FT_RENDERER( cur->data ); | |
3841 | |
3842 | |
3843 if ( renderer->glyph_format == format ) | |
3844 { | |
3845 if ( node ) | |
3846 *node = cur; | |
3847 | |
3848 result = renderer; | |
3849 break; | |
3850 } | |
3851 cur = cur->next; | |
3852 } | |
3853 | |
3854 Exit: | |
3855 return result; | |
3856 } | |
3857 | |
3858 | |
3859 static FT_Renderer | |
3860 ft_lookup_glyph_renderer( FT_GlyphSlot slot ) | |
3861 { | |
3862 FT_Face face = slot->face; | |
3863 FT_Library library = FT_FACE_LIBRARY( face ); | |
3864 FT_Renderer result = library->cur_renderer; | |
3865 | |
3866 | |
3867 if ( !result || result->glyph_format != slot->format ) | |
3868 result = FT_Lookup_Renderer( library, slot->format, 0 ); | |
3869 | |
3870 return result; | |
3871 } | |
3872 | |
3873 | |
3874 static void | |
3875 ft_set_current_renderer( FT_Library library ) | |
3876 { | |
3877 FT_Renderer renderer; | |
3878 | |
3879 | |
3880 renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 ); | |
3881 library->cur_renderer = renderer; | |
3882 } | |
3883 | |
3884 | |
3885 static FT_Error | |
3886 ft_add_renderer( FT_Module module ) | |
3887 { | |
3888 FT_Library library = module->library; | |
3889 FT_Memory memory = library->memory; | |
3890 FT_Error error; | |
3891 FT_ListNode node = NULL; | |
3892 | |
3893 | |
3894 if ( FT_NEW( node ) ) | |
3895 goto Exit; | |
3896 | |
3897 { | |
3898 FT_Renderer render = FT_RENDERER( module ); | |
3899 FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz; | |
3900 | |
3901 | |
3902 render->clazz = clazz; | |
3903 render->glyph_format = clazz->glyph_format; | |
3904 | |
3905 /* allocate raster object if needed */ | |
3906 if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && | |
3907 clazz->raster_class->raster_new ) | |
3908 { | |
3909 error = clazz->raster_class->raster_new( memory, &render->raster ); | |
3910 if ( error ) | |
3911 goto Fail; | |
3912 | |
3913 render->raster_render = clazz->raster_class->raster_render; | |
3914 render->render = clazz->render_glyph; | |
3915 } | |
3916 | |
3917 /* add to list */ | |
3918 node->data = module; | |
3919 FT_List_Add( &library->renderers, node ); | |
3920 | |
3921 ft_set_current_renderer( library ); | |
3922 } | |
3923 | |
3924 Fail: | |
3925 if ( error ) | |
3926 FT_FREE( node ); | |
3927 | |
3928 Exit: | |
3929 return error; | |
3930 } | |
3931 | |
3932 | |
3933 static void | |
3934 ft_remove_renderer( FT_Module module ) | |
3935 { | |
3936 FT_Library library = module->library; | |
3937 FT_Memory memory = library->memory; | |
3938 FT_ListNode node; | |
3939 | |
3940 | |
3941 node = FT_List_Find( &library->renderers, module ); | |
3942 if ( node ) | |
3943 { | |
3944 FT_Renderer render = FT_RENDERER( module ); | |
3945 | |
3946 | |
3947 /* release raster object, if any */ | |
3948 if ( render->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && | |
3949 render->raster ) | |
3950 render->clazz->raster_class->raster_done( render->raster ); | |
3951 | |
3952 /* remove from list */ | |
3953 FT_List_Remove( &library->renderers, node ); | |
3954 FT_FREE( node ); | |
3955 | |
3956 ft_set_current_renderer( library ); | |
3957 } | |
3958 } | |
3959 | |
3960 | |
3961 /* documentation is in ftrender.h */ | |
3962 | |
3963 FT_EXPORT_DEF( FT_Renderer ) | |
3964 FT_Get_Renderer( FT_Library library, | |
3965 FT_Glyph_Format format ) | |
3966 { | |
3967 /* test for valid `library' delayed to FT_Lookup_Renderer() */ | |
3968 | |
3969 return FT_Lookup_Renderer( library, format, 0 ); | |
3970 } | |
3971 | |
3972 | |
3973 /* documentation is in ftrender.h */ | |
3974 | |
3975 FT_EXPORT_DEF( FT_Error ) | |
3976 FT_Set_Renderer( FT_Library library, | |
3977 FT_Renderer renderer, | |
3978 FT_UInt num_params, | |
3979 FT_Parameter* parameters ) | |
3980 { | |
3981 FT_ListNode node; | |
3982 FT_Error error = FT_Err_Ok; | |
3983 | |
3984 | |
3985 if ( !library ) | |
3986 return FT_THROW( Invalid_Library_Handle ); | |
3987 | |
3988 if ( !renderer ) | |
3989 return FT_THROW( Invalid_Argument ); | |
3990 | |
3991 node = FT_List_Find( &library->renderers, renderer ); | |
3992 if ( !node ) | |
3993 { | |
3994 error = FT_THROW( Invalid_Argument ); | |
3995 goto Exit; | |
3996 } | |
3997 | |
3998 FT_List_Up( &library->renderers, node ); | |
3999 | |
4000 if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE ) | |
4001 library->cur_renderer = renderer; | |
4002 | |
4003 if ( num_params > 0 ) | |
4004 { | |
4005 FT_Renderer_SetModeFunc set_mode = renderer->clazz->set_mode; | |
4006 | |
4007 | |
4008 for ( ; num_params > 0; num_params-- ) | |
4009 { | |
4010 error = set_mode( renderer, parameters->tag, parameters->data ); | |
4011 if ( error ) | |
4012 break; | |
4013 parameters++; | |
4014 } | |
4015 } | |
4016 | |
4017 Exit: | |
4018 return error; | |
4019 } | |
4020 | |
4021 | |
4022 FT_BASE_DEF( FT_Error ) | |
4023 FT_Render_Glyph_Internal( FT_Library library, | |
4024 FT_GlyphSlot slot, | |
4025 FT_Render_Mode render_mode ) | |
4026 { | |
4027 FT_Error error = FT_Err_Ok; | |
4028 FT_Renderer renderer; | |
4029 | |
4030 | |
4031 /* if it is already a bitmap, no need to do anything */ | |
4032 switch ( slot->format ) | |
4033 { | |
4034 case FT_GLYPH_FORMAT_BITMAP: /* already a bitmap, don't do anything */ | |
4035 break; | |
4036 | |
4037 default: | |
4038 { | |
4039 FT_ListNode node = 0; | |
4040 FT_Bool update = 0; | |
4041 | |
4042 | |
4043 /* small shortcut for the very common case */ | |
4044 if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) | |
4045 { | |
4046 renderer = library->cur_renderer; | |
4047 node = library->renderers.head; | |
4048 } | |
4049 else | |
4050 renderer = FT_Lookup_Renderer( library, slot->format, &node ); | |
4051 | |
4052 error = FT_ERR( Unimplemented_Feature ); | |
4053 while ( renderer ) | |
4054 { | |
4055 error = renderer->render( renderer, slot, render_mode, NULL ); | |
4056 if ( !error || | |
4057 FT_ERR_NEQ( error, Cannot_Render_Glyph ) ) | |
4058 break; | |
4059 | |
4060 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ | |
4061 /* is unsupported by the current renderer for this glyph image */ | |
4062 /* format. */ | |
4063 | |
4064 /* now, look for another renderer that supports the same */ | |
4065 /* format. */ | |
4066 renderer = FT_Lookup_Renderer( library, slot->format, &node ); | |
4067 update = 1; | |
4068 } | |
4069 | |
4070 /* if we changed the current renderer for the glyph image format */ | |
4071 /* we need to select it as the next current one */ | |
4072 if ( !error && update && renderer ) | |
4073 FT_Set_Renderer( library, renderer, 0, 0 ); | |
4074 } | |
4075 } | |
4076 | |
4077 #ifdef FT_DEBUG_LEVEL_TRACE | |
4078 | |
4079 #undef FT_COMPONENT | |
4080 #define FT_COMPONENT trace_bitmap | |
4081 | |
4082 /* we convert to a single bitmap format for computing the checksum */ | |
4083 { | |
4084 FT_Bitmap bitmap; | |
4085 FT_Error err; | |
4086 | |
4087 | |
4088 FT_Bitmap_New( &bitmap ); | |
4089 | |
4090 err = FT_Bitmap_Convert( library, &slot->bitmap, &bitmap, 1 ); | |
4091 if ( !err ) | |
4092 { | |
4093 MD5_CTX ctx; | |
4094 unsigned char md5[16]; | |
4095 int i; | |
4096 | |
4097 | |
4098 MD5_Init( &ctx); | |
4099 MD5_Update( &ctx, bitmap.buffer, bitmap.rows * bitmap.pitch ); | |
4100 MD5_Final( md5, &ctx ); | |
4101 | |
4102 FT_TRACE3(( "MD5 checksum for %dx%d bitmap:\n" | |
4103 " ", | |
4104 bitmap.rows, bitmap.pitch )); | |
4105 for ( i = 0; i < 16; i++ ) | |
4106 FT_TRACE3(( "%02X", md5[i] )); | |
4107 FT_TRACE3(( "\n" )); | |
4108 } | |
4109 | |
4110 FT_Bitmap_Done( library, &bitmap ); | |
4111 } | |
4112 | |
4113 #undef FT_COMPONENT | |
4114 #define FT_COMPONENT trace_objs | |
4115 | |
4116 #endif /* FT_DEBUG_LEVEL_TRACE */ | |
4117 | |
4118 return error; | |
4119 } | |
4120 | |
4121 /* documentation is in freetype.h */ | |
4122 | |
4123 FT_EXPORT_DEF( FT_Error ) | |
4124 FT_Render_Glyph( FT_GlyphSlot slot, | |
4125 FT_Render_Mode render_mode ) | |
4126 { | |
4127 FT_Library library; | |
4128 | |
4129 if ( !slot || !slot->face ) | |
4130 return FT_THROW( Invalid_Argument ); | |
4131 | |
4132 library = FT_FACE_LIBRARY( slot->face ); | |
4133 | |
4134 return FT_Render_Glyph_Internal( library, slot, render_mode ); | |
4135 } | |
4136 | |
4137 | |
4138 /*************************************************************************/ | |
4139 /*************************************************************************/ | |
4140 /*************************************************************************/ | |
4141 /**** ****/ | |
4142 /**** ****/ | |
4143 /**** M O D U L E S ****/ | |
4144 /**** ****/ | |
4145 /**** ****/ | |
4146 /*************************************************************************/ | |
4147 /*************************************************************************/ | |
4148 /*************************************************************************/ | |
4149 | |
4150 | |
4151 /*************************************************************************/ | |
4152 /* */ | |
4153 /* <Function> */ | |
4154 /* Destroy_Module */ | |
4155 /* */ | |
4156 /* <Description> */ | |
4157 /* Destroys a given module object. For drivers, this also destroys */ | |
4158 /* all child faces. */ | |
4159 /* */ | |
4160 /* <InOut> */ | |
4161 /* module :: A handle to the target driver object. */ | |
4162 /* */ | |
4163 /* <Note> */ | |
4164 /* The driver _must_ be LOCKED! */ | |
4165 /* */ | |
4166 static void | |
4167 Destroy_Module( FT_Module module ) | |
4168 { | |
4169 FT_Memory memory = module->memory; | |
4170 FT_Module_Class* clazz = module->clazz; | |
4171 FT_Library library = module->library; | |
4172 | |
4173 | |
4174 if ( library && library->auto_hinter == module ) | |
4175 library->auto_hinter = 0; | |
4176 | |
4177 /* if the module is a renderer */ | |
4178 if ( FT_MODULE_IS_RENDERER( module ) ) | |
4179 ft_remove_renderer( module ); | |
4180 | |
4181 /* if the module is a font driver, add some steps */ | |
4182 if ( FT_MODULE_IS_DRIVER( module ) ) | |
4183 Destroy_Driver( FT_DRIVER( module ) ); | |
4184 | |
4185 /* finalize the module object */ | |
4186 if ( clazz->module_done ) | |
4187 clazz->module_done( module ); | |
4188 | |
4189 /* discard it */ | |
4190 FT_FREE( module ); | |
4191 } | |
4192 | |
4193 | |
4194 /* documentation is in ftmodapi.h */ | |
4195 | |
4196 FT_EXPORT_DEF( FT_Error ) | |
4197 FT_Add_Module( FT_Library library, | |
4198 const FT_Module_Class* clazz ) | |
4199 { | |
4200 FT_Error error; | |
4201 FT_Memory memory; | |
4202 FT_Module module; | |
4203 FT_UInt nn; | |
4204 | |
4205 | |
4206 #define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \ | |
4207 FREETYPE_MINOR ) | |
4208 | |
4209 if ( !library ) | |
4210 return FT_THROW( Invalid_Library_Handle ); | |
4211 | |
4212 if ( !clazz ) | |
4213 return FT_THROW( Invalid_Argument ); | |
4214 | |
4215 /* check freetype version */ | |
4216 if ( clazz->module_requires > FREETYPE_VER_FIXED ) | |
4217 return FT_THROW( Invalid_Version ); | |
4218 | |
4219 /* look for a module with the same name in the library's table */ | |
4220 for ( nn = 0; nn < library->num_modules; nn++ ) | |
4221 { | |
4222 module = library->modules[nn]; | |
4223 if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 ) | |
4224 { | |
4225 /* this installed module has the same name, compare their versions */ | |
4226 if ( clazz->module_version <= module->clazz->module_version ) | |
4227 return FT_THROW( Lower_Module_Version ); | |
4228 | |
4229 /* remove the module from our list, then exit the loop to replace */ | |
4230 /* it by our new version.. */ | |
4231 FT_Remove_Module( library, module ); | |
4232 break; | |
4233 } | |
4234 } | |
4235 | |
4236 memory = library->memory; | |
4237 error = FT_Err_Ok; | |
4238 | |
4239 if ( library->num_modules >= FT_MAX_MODULES ) | |
4240 { | |
4241 error = FT_THROW( Too_Many_Drivers ); | |
4242 goto Exit; | |
4243 } | |
4244 | |
4245 /* allocate module object */ | |
4246 if ( FT_ALLOC( module, clazz->module_size ) ) | |
4247 goto Exit; | |
4248 | |
4249 /* base initialization */ | |
4250 module->library = library; | |
4251 module->memory = memory; | |
4252 module->clazz = (FT_Module_Class*)clazz; | |
4253 | |
4254 /* check whether the module is a renderer - this must be performed */ | |
4255 /* before the normal module initialization */ | |
4256 if ( FT_MODULE_IS_RENDERER( module ) ) | |
4257 { | |
4258 /* add to the renderers list */ | |
4259 error = ft_add_renderer( module ); | |
4260 if ( error ) | |
4261 goto Fail; | |
4262 } | |
4263 | |
4264 /* is the module a auto-hinter? */ | |
4265 if ( FT_MODULE_IS_HINTER( module ) ) | |
4266 library->auto_hinter = module; | |
4267 | |
4268 /* if the module is a font driver */ | |
4269 if ( FT_MODULE_IS_DRIVER( module ) ) | |
4270 { | |
4271 /* allocate glyph loader if needed */ | |
4272 FT_Driver driver = FT_DRIVER( module ); | |
4273 | |
4274 | |
4275 driver->clazz = (FT_Driver_Class)module->clazz; | |
4276 if ( FT_DRIVER_USES_OUTLINES( driver ) ) | |
4277 { | |
4278 error = FT_GlyphLoader_New( memory, &driver->glyph_loader ); | |
4279 if ( error ) | |
4280 goto Fail; | |
4281 } | |
4282 } | |
4283 | |
4284 if ( clazz->module_init ) | |
4285 { | |
4286 error = clazz->module_init( module ); | |
4287 if ( error ) | |
4288 goto Fail; | |
4289 } | |
4290 | |
4291 /* add module to the library's table */ | |
4292 library->modules[library->num_modules++] = module; | |
4293 | |
4294 Exit: | |
4295 return error; | |
4296 | |
4297 Fail: | |
4298 if ( FT_MODULE_IS_DRIVER( module ) ) | |
4299 { | |
4300 FT_Driver driver = FT_DRIVER( module ); | |
4301 | |
4302 | |
4303 if ( FT_DRIVER_USES_OUTLINES( driver ) ) | |
4304 FT_GlyphLoader_Done( driver->glyph_loader ); | |
4305 } | |
4306 | |
4307 if ( FT_MODULE_IS_RENDERER( module ) ) | |
4308 { | |
4309 FT_Renderer renderer = FT_RENDERER( module ); | |
4310 | |
4311 | |
4312 if ( renderer->clazz && | |
4313 renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && | |
4314 renderer->raster ) | |
4315 renderer->clazz->raster_class->raster_done( renderer->raster ); | |
4316 } | |
4317 | |
4318 FT_FREE( module ); | |
4319 goto Exit; | |
4320 } | |
4321 | |
4322 | |
4323 /* documentation is in ftmodapi.h */ | |
4324 | |
4325 FT_EXPORT_DEF( FT_Module ) | |
4326 FT_Get_Module( FT_Library library, | |
4327 const char* module_name ) | |
4328 { | |
4329 FT_Module result = 0; | |
4330 FT_Module* cur; | |
4331 FT_Module* limit; | |
4332 | |
4333 | |
4334 if ( !library || !module_name ) | |
4335 return result; | |
4336 | |
4337 cur = library->modules; | |
4338 limit = cur + library->num_modules; | |
4339 | |
4340 for ( ; cur < limit; cur++ ) | |
4341 if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 ) | |
4342 { | |
4343 result = cur[0]; | |
4344 break; | |
4345 } | |
4346 | |
4347 return result; | |
4348 } | |
4349 | |
4350 | |
4351 /* documentation is in ftobjs.h */ | |
4352 | |
4353 FT_BASE_DEF( const void* ) | |
4354 FT_Get_Module_Interface( FT_Library library, | |
4355 const char* mod_name ) | |
4356 { | |
4357 FT_Module module; | |
4358 | |
4359 | |
4360 /* test for valid `library' delayed to FT_Get_Module() */ | |
4361 | |
4362 module = FT_Get_Module( library, mod_name ); | |
4363 | |
4364 return module ? module->clazz->module_interface : 0; | |
4365 } | |
4366 | |
4367 | |
4368 FT_BASE_DEF( FT_Pointer ) | |
4369 ft_module_get_service( FT_Module module, | |
4370 const char* service_id ) | |
4371 { | |
4372 FT_Pointer result = NULL; | |
4373 | |
4374 | |
4375 if ( module ) | |
4376 { | |
4377 FT_ASSERT( module->clazz && module->clazz->get_interface ); | |
4378 | |
4379 /* first, look for the service in the module */ | |
4380 if ( module->clazz->get_interface ) | |
4381 result = module->clazz->get_interface( module, service_id ); | |
4382 | |
4383 if ( result == NULL ) | |
4384 { | |
4385 /* we didn't find it, look in all other modules then */ | |
4386 FT_Library library = module->library; | |
4387 FT_Module* cur = library->modules; | |
4388 FT_Module* limit = cur + library->num_modules; | |
4389 | |
4390 | |
4391 for ( ; cur < limit; cur++ ) | |
4392 { | |
4393 if ( cur[0] != module ) | |
4394 { | |
4395 FT_ASSERT( cur[0]->clazz ); | |
4396 | |
4397 if ( cur[0]->clazz->get_interface ) | |
4398 { | |
4399 result = cur[0]->clazz->get_interface( cur[0], service_id ); | |
4400 if ( result != NULL ) | |
4401 break; | |
4402 } | |
4403 } | |
4404 } | |
4405 } | |
4406 } | |
4407 | |
4408 return result; | |
4409 } | |
4410 | |
4411 | |
4412 /* documentation is in ftmodapi.h */ | |
4413 | |
4414 FT_EXPORT_DEF( FT_Error ) | |
4415 FT_Remove_Module( FT_Library library, | |
4416 FT_Module module ) | |
4417 { | |
4418 /* try to find the module from the table, then remove it from there */ | |
4419 | |
4420 if ( !library ) | |
4421 return FT_THROW( Invalid_Library_Handle ); | |
4422 | |
4423 if ( module ) | |
4424 { | |
4425 FT_Module* cur = library->modules; | |
4426 FT_Module* limit = cur + library->num_modules; | |
4427 | |
4428 | |
4429 for ( ; cur < limit; cur++ ) | |
4430 { | |
4431 if ( cur[0] == module ) | |
4432 { | |
4433 /* remove it from the table */ | |
4434 library->num_modules--; | |
4435 limit--; | |
4436 while ( cur < limit ) | |
4437 { | |
4438 cur[0] = cur[1]; | |
4439 cur++; | |
4440 } | |
4441 limit[0] = 0; | |
4442 | |
4443 /* destroy the module */ | |
4444 Destroy_Module( module ); | |
4445 | |
4446 return FT_Err_Ok; | |
4447 } | |
4448 } | |
4449 } | |
4450 return FT_THROW( Invalid_Driver_Handle ); | |
4451 } | |
4452 | |
4453 | |
4454 FT_Error | |
4455 ft_property_do( FT_Library library, | |
4456 const FT_String* module_name, | |
4457 const FT_String* property_name, | |
4458 void* value, | |
4459 FT_Bool set ) | |
4460 { | |
4461 FT_Module* cur; | |
4462 FT_Module* limit; | |
4463 FT_Module_Interface interface1; | |
4464 FT_Service_Properties service; | |
4465 | |
4466 #ifdef FT_DEBUG_LEVEL_ERROR | |
4467 const FT_String* set_name = "FT_Property_Set"; | |
4468 const FT_String* get_name = "FT_Property_Get"; | |
4469 const FT_String* func_name = set ? set_name : get_name; | |
4470 #endif | |
4471 | |
4472 FT_Bool missing_func; | |
4473 | |
4474 | |
4475 if ( !library ) | |
4476 return FT_THROW( Invalid_Library_Handle ); | |
4477 | |
4478 if ( !module_name || !property_name || !value ) | |
4479 return FT_THROW( Invalid_Argument ); | |
4480 | |
4481 cur = library->modules; | |
4482 limit = cur + library->num_modules; | |
4483 | |
4484 /* search module */ | |
4485 for ( ; cur < limit; cur++ ) | |
4486 if ( !ft_strcmp( cur[0]->clazz->module_name, module_name ) ) | |
4487 break; | |
4488 | |
4489 if ( cur == limit ) | |
4490 { | |
4491 FT_ERROR(( "%s: can't find module `%s'\n", | |
4492 func_name, module_name )); | |
4493 return FT_THROW( Missing_Module ); | |
4494 } | |
4495 | |
4496 /* check whether we have a service interface */ | |
4497 if ( !cur[0]->clazz->get_interface ) | |
4498 { | |
4499 FT_ERROR(( "%s: module `%s' doesn't support properties\n", | |
4500 func_name, module_name )); | |
4501 return FT_THROW( Unimplemented_Feature ); | |
4502 } | |
4503 | |
4504 /* search property service */ | |
4505 interface1 = cur[0]->clazz->get_interface( cur[0], | |
4506 FT_SERVICE_ID_PROPERTIES ); | |
4507 if ( !interface1 ) | |
4508 { | |
4509 FT_ERROR(( "%s: module `%s' doesn't support properties\n", | |
4510 func_name, module_name )); | |
4511 return FT_THROW( Unimplemented_Feature ); | |
4512 } | |
4513 | |
4514 service = (FT_Service_Properties)interface1; | |
4515 | |
4516 if ( set ) | |
4517 missing_func = (FT_Bool)( !service->set_property ); | |
4518 else | |
4519 missing_func = (FT_Bool)( !service->get_property ); | |
4520 | |
4521 if ( missing_func ) | |
4522 { | |
4523 FT_ERROR(( "%s: property service of module `%s' is broken\n", | |
4524 func_name, module_name )); | |
4525 return FT_THROW( Unimplemented_Feature ); | |
4526 } | |
4527 | |
4528 return set ? service->set_property( cur[0], property_name, value ) | |
4529 : service->get_property( cur[0], property_name, value ); | |
4530 } | |
4531 | |
4532 | |
4533 /* documentation is in ftmodapi.h */ | |
4534 | |
4535 FT_EXPORT_DEF( FT_Error ) | |
4536 FT_Property_Set( FT_Library library, | |
4537 const FT_String* module_name, | |
4538 const FT_String* property_name, | |
4539 const void* value ) | |
4540 { | |
4541 return ft_property_do( library, | |
4542 module_name, | |
4543 property_name, | |
4544 (void*)value, | |
4545 TRUE ); | |
4546 } | |
4547 | |
4548 | |
4549 /* documentation is in ftmodapi.h */ | |
4550 | |
4551 FT_EXPORT_DEF( FT_Error ) | |
4552 FT_Property_Get( FT_Library library, | |
4553 const FT_String* module_name, | |
4554 const FT_String* property_name, | |
4555 void* value ) | |
4556 { | |
4557 return ft_property_do( library, | |
4558 module_name, | |
4559 property_name, | |
4560 value, | |
4561 FALSE ); | |
4562 } | |
4563 | |
4564 | |
4565 /*************************************************************************/ | |
4566 /*************************************************************************/ | |
4567 /*************************************************************************/ | |
4568 /**** ****/ | |
4569 /**** ****/ | |
4570 /**** L I B R A R Y ****/ | |
4571 /**** ****/ | |
4572 /**** ****/ | |
4573 /*************************************************************************/ | |
4574 /*************************************************************************/ | |
4575 /*************************************************************************/ | |
4576 | |
4577 | |
4578 /* documentation is in ftmodapi.h */ | |
4579 | |
4580 FT_EXPORT_DEF( FT_Error ) | |
4581 FT_Reference_Library( FT_Library library ) | |
4582 { | |
4583 library->refcount++; | |
4584 | |
4585 return FT_Err_Ok; | |
4586 } | |
4587 | |
4588 | |
4589 /* documentation is in ftmodapi.h */ | |
4590 | |
4591 FT_EXPORT_DEF( FT_Error ) | |
4592 FT_New_Library( FT_Memory memory, | |
4593 FT_Library *alibrary ) | |
4594 { | |
4595 FT_Library library = NULL; | |
4596 FT_Error error; | |
4597 | |
4598 | |
4599 if ( !memory ) | |
4600 return FT_THROW( Invalid_Argument ); | |
4601 | |
4602 #ifdef FT_DEBUG_LEVEL_ERROR | |
4603 /* init debugging support */ | |
4604 ft_debug_init(); | |
4605 #endif | |
4606 | |
4607 /* first of all, allocate the library object */ | |
4608 if ( FT_NEW( library ) ) | |
4609 return error; | |
4610 | |
4611 library->memory = memory; | |
4612 | |
4613 #ifdef FT_CONFIG_OPTION_PIC | |
4614 /* initialize position independent code containers */ | |
4615 error = ft_pic_container_init( library ); | |
4616 if ( error ) | |
4617 goto Fail; | |
4618 #endif | |
4619 | |
4620 /* allocate the render pool */ | |
4621 library->raster_pool_size = FT_RENDER_POOL_SIZE; | |
4622 #if FT_RENDER_POOL_SIZE > 0 | |
4623 if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) ) | |
4624 goto Fail; | |
4625 #endif | |
4626 | |
4627 library->version_major = FREETYPE_MAJOR; | |
4628 library->version_minor = FREETYPE_MINOR; | |
4629 library->version_patch = FREETYPE_PATCH; | |
4630 | |
4631 library->refcount = 1; | |
4632 | |
4633 /* That's ok now */ | |
4634 *alibrary = library; | |
4635 | |
4636 return FT_Err_Ok; | |
4637 | |
4638 Fail: | |
4639 #ifdef FT_CONFIG_OPTION_PIC | |
4640 ft_pic_container_destroy( library ); | |
4641 #endif | |
4642 FT_FREE( library ); | |
4643 return error; | |
4644 } | |
4645 | |
4646 | |
4647 /* documentation is in freetype.h */ | |
4648 | |
4649 FT_EXPORT_DEF( void ) | |
4650 FT_Library_Version( FT_Library library, | |
4651 FT_Int *amajor, | |
4652 FT_Int *aminor, | |
4653 FT_Int *apatch ) | |
4654 { | |
4655 FT_Int major = 0; | |
4656 FT_Int minor = 0; | |
4657 FT_Int patch = 0; | |
4658 | |
4659 | |
4660 if ( library ) | |
4661 { | |
4662 major = library->version_major; | |
4663 minor = library->version_minor; | |
4664 patch = library->version_patch; | |
4665 } | |
4666 | |
4667 if ( amajor ) | |
4668 *amajor = major; | |
4669 | |
4670 if ( aminor ) | |
4671 *aminor = minor; | |
4672 | |
4673 if ( apatch ) | |
4674 *apatch = patch; | |
4675 } | |
4676 | |
4677 | |
4678 /* documentation is in ftmodapi.h */ | |
4679 | |
4680 FT_EXPORT_DEF( FT_Error ) | |
4681 FT_Done_Library( FT_Library library ) | |
4682 { | |
4683 FT_Memory memory; | |
4684 | |
4685 | |
4686 if ( !library ) | |
4687 return FT_THROW( Invalid_Library_Handle ); | |
4688 | |
4689 library->refcount--; | |
4690 if ( library->refcount > 0 ) | |
4691 goto Exit; | |
4692 | |
4693 memory = library->memory; | |
4694 | |
4695 /* | |
4696 * Close all faces in the library. If we don't do this, we can have | |
4697 * some subtle memory leaks. | |
4698 * | |
4699 * Example: | |
4700 * | |
4701 * - the cff font driver uses the pshinter module in cff_size_done | |
4702 * - if the pshinter module is destroyed before the cff font driver, | |
4703 * opened FT_Face objects managed by the driver are not properly | |
4704 * destroyed, resulting in a memory leak | |
4705 * | |
4706 * Some faces are dependent on other faces, like Type42 faces that | |
4707 * depend on TrueType faces synthesized internally. | |
4708 * | |
4709 * The order of drivers should be specified in driver_name[]. | |
4710 */ | |
4711 { | |
4712 FT_UInt m, n; | |
4713 const char* driver_name[] = { "type42", NULL }; | |
4714 | |
4715 | |
4716 for ( m = 0; | |
4717 m < sizeof ( driver_name ) / sizeof ( driver_name[0] ); | |
4718 m++ ) | |
4719 { | |
4720 for ( n = 0; n < library->num_modules; n++ ) | |
4721 { | |
4722 FT_Module module = library->modules[n]; | |
4723 const char* module_name = module->clazz->module_name; | |
4724 FT_List faces; | |
4725 | |
4726 | |
4727 if ( driver_name[m] && | |
4728 ft_strcmp( module_name, driver_name[m] ) != 0 ) | |
4729 continue; | |
4730 | |
4731 if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 ) | |
4732 continue; | |
4733 | |
4734 FT_TRACE7(( "FT_Done_Library: close faces for %s\n", module_name )); | |
4735 | |
4736 faces = &FT_DRIVER( module )->faces_list; | |
4737 while ( faces->head ) | |
4738 { | |
4739 FT_Done_Face( FT_FACE( faces->head->data ) ); | |
4740 if ( faces->head ) | |
4741 FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" )); | |
4742 } | |
4743 } | |
4744 } | |
4745 } | |
4746 | |
4747 /* Close all other modules in the library */ | |
4748 #if 1 | |
4749 /* XXX Modules are removed in the reversed order so that */ | |
4750 /* type42 module is removed before truetype module. This */ | |
4751 /* avoids double free in some occasions. It is a hack. */ | |
4752 while ( library->num_modules > 0 ) | |
4753 FT_Remove_Module( library, | |
4754 library->modules[library->num_modules - 1] ); | |
4755 #else | |
4756 { | |
4757 FT_UInt n; | |
4758 | |
4759 | |
4760 for ( n = 0; n < library->num_modules; n++ ) | |
4761 { | |
4762 FT_Module module = library->modules[n]; | |
4763 | |
4764 | |
4765 if ( module ) | |
4766 { | |
4767 Destroy_Module( module ); | |
4768 library->modules[n] = 0; | |
4769 } | |
4770 } | |
4771 } | |
4772 #endif | |
4773 | |
4774 /* Destroy raster objects */ | |
4775 FT_FREE( library->raster_pool ); | |
4776 library->raster_pool_size = 0; | |
4777 | |
4778 #ifdef FT_CONFIG_OPTION_PIC | |
4779 /* Destroy pic container contents */ | |
4780 ft_pic_container_destroy( library ); | |
4781 #endif | |
4782 | |
4783 FT_FREE( library ); | |
4784 | |
4785 Exit: | |
4786 return FT_Err_Ok; | |
4787 } | |
4788 | |
4789 | |
4790 /* documentation is in ftmodapi.h */ | |
4791 | |
4792 FT_EXPORT_DEF( void ) | |
4793 FT_Set_Debug_Hook( FT_Library library, | |
4794 FT_UInt hook_index, | |
4795 FT_DebugHook_Func debug_hook ) | |
4796 { | |
4797 if ( library && debug_hook && | |
4798 hook_index < | |
4799 ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) ) | |
4800 library->debug_hooks[hook_index] = debug_hook; | |
4801 } | |
4802 | |
4803 | |
4804 /* documentation is in ftmodapi.h */ | |
4805 | |
4806 FT_EXPORT_DEF( FT_TrueTypeEngineType ) | |
4807 FT_Get_TrueType_Engine_Type( FT_Library library ) | |
4808 { | |
4809 FT_TrueTypeEngineType result = FT_TRUETYPE_ENGINE_TYPE_NONE; | |
4810 | |
4811 | |
4812 if ( library ) | |
4813 { | |
4814 FT_Module module = FT_Get_Module( library, "truetype" ); | |
4815 | |
4816 | |
4817 if ( module ) | |
4818 { | |
4819 FT_Service_TrueTypeEngine service; | |
4820 | |
4821 | |
4822 service = (FT_Service_TrueTypeEngine) | |
4823 ft_module_get_service( module, | |
4824 FT_SERVICE_ID_TRUETYPE_ENGINE ); | |
4825 if ( service ) | |
4826 result = service->engine_type; | |
4827 } | |
4828 } | |
4829 | |
4830 return result; | |
4831 } | |
4832 | |
4833 | |
4834 /* documentation is in freetype.h */ | |
4835 | |
4836 FT_EXPORT_DEF( FT_Error ) | |
4837 FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, | |
4838 FT_UInt sub_index, | |
4839 FT_Int *p_index, | |
4840 FT_UInt *p_flags, | |
4841 FT_Int *p_arg1, | |
4842 FT_Int *p_arg2, | |
4843 FT_Matrix *p_transform ) | |
4844 { | |
4845 FT_Error error = FT_ERR( Invalid_Argument ); | |
4846 | |
4847 | |
4848 if ( glyph && | |
4849 glyph->subglyphs && | |
4850 glyph->format == FT_GLYPH_FORMAT_COMPOSITE && | |
4851 sub_index < glyph->num_subglyphs ) | |
4852 { | |
4853 FT_SubGlyph subg = glyph->subglyphs + sub_index; | |
4854 | |
4855 | |
4856 *p_index = subg->index; | |
4857 *p_flags = subg->flags; | |
4858 *p_arg1 = subg->arg1; | |
4859 *p_arg2 = subg->arg2; | |
4860 *p_transform = subg->transform; | |
4861 } | |
4862 | |
4863 return error; | |
4864 } | |
4865 | |
4866 | |
4867 /* END */ | |
OLD | NEW |