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