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