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