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