[CMAKE]
[reactos.git] / lib / 3rdparty / freetype / src / base / ftobjs.c
1 /***************************************************************************/
2 /* */
3 /* ftobjs.c */
4 /* */
5 /* The FreeType private base classes (body). */
6 /* */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */
8 /* 2010 by */
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* */
11 /* This file is part of the FreeType project, and may only be used, */
12 /* modified, and distributed under the terms of the FreeType project */
13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14 /* this file you indicate that you have read the license and */
15 /* understand and accept it fully. */
16 /* */
17 /***************************************************************************/
18
19
20 #include <ft2build.h>
21 #include FT_LIST_H
22 #include FT_OUTLINE_H
23 #include FT_INTERNAL_VALIDATE_H
24 #include FT_INTERNAL_OBJECTS_H
25 #include FT_INTERNAL_DEBUG_H
26 #include FT_INTERNAL_RFORK_H
27 #include FT_INTERNAL_STREAM_H
28 #include FT_INTERNAL_SFNT_H /* for SFNT_Load_Table_Func */
29 #include FT_TRUETYPE_TABLES_H
30 #include FT_TRUETYPE_TAGS_H
31 #include FT_TRUETYPE_IDS_H
32
33 #include FT_SERVICE_SFNT_H
34 #include FT_SERVICE_POSTSCRIPT_NAME_H
35 #include FT_SERVICE_GLYPH_DICT_H
36 #include FT_SERVICE_TT_CMAP_H
37 #include FT_SERVICE_KERNING_H
38 #include FT_SERVICE_TRUETYPE_ENGINE_H
39
40 #ifdef FT_CONFIG_OPTION_MAC_FONTS
41 #include "ftbase.h"
42 #endif
43
44 #define GRID_FIT_METRICS
45
46
47 FT_BASE_DEF( FT_Pointer )
48 ft_service_list_lookup( FT_ServiceDesc service_descriptors,
49 const char* service_id )
50 {
51 FT_Pointer result = NULL;
52 FT_ServiceDesc desc = service_descriptors;
53
54
55 if ( desc && service_id )
56 {
57 for ( ; desc->serv_id != NULL; desc++ )
58 {
59 if ( ft_strcmp( desc->serv_id, service_id ) == 0 )
60 {
61 result = (FT_Pointer)desc->serv_data;
62 break;
63 }
64 }
65 }
66
67 return result;
68 }
69
70
71 FT_BASE_DEF( void )
72 ft_validator_init( FT_Validator valid,
73 const FT_Byte* base,
74 const FT_Byte* limit,
75 FT_ValidationLevel level )
76 {
77 valid->base = base;
78 valid->limit = limit;
79 valid->level = level;
80 valid->error = FT_Err_Ok;
81 }
82
83
84 FT_BASE_DEF( FT_Int )
85 ft_validator_run( FT_Validator valid )
86 {
87 /* This function doesn't work! None should call it. */
88 FT_UNUSED( valid );
89
90 return -1;
91 }
92
93
94 FT_BASE_DEF( void )
95 ft_validator_error( FT_Validator valid,
96 FT_Error error )
97 {
98 /* since the cast below also disables the compiler's */
99 /* type check, we introduce a dummy variable, which */
100 /* will be optimized away */
101 volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer;
102
103
104 valid->error = error;
105
106 /* throw away volatileness; use `jump_buffer' or the */
107 /* compiler may warn about an unused local variable */
108 ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 );
109 }
110
111
112 /*************************************************************************/
113 /*************************************************************************/
114 /*************************************************************************/
115 /**** ****/
116 /**** ****/
117 /**** S T R E A M ****/
118 /**** ****/
119 /**** ****/
120 /*************************************************************************/
121 /*************************************************************************/
122 /*************************************************************************/
123
124
125 /* create a new input stream from an FT_Open_Args structure */
126 /* */
127 FT_BASE_DEF( FT_Error )
128 FT_Stream_New( FT_Library library,
129 const FT_Open_Args* args,
130 FT_Stream *astream )
131 {
132 FT_Error error;
133 FT_Memory memory;
134 FT_Stream stream;
135
136
137 *astream = 0;
138
139 if ( !library )
140 return FT_Err_Invalid_Library_Handle;
141
142 if ( !args )
143 return FT_Err_Invalid_Argument;
144
145 memory = library->memory;
146
147 if ( FT_NEW( stream ) )
148 goto Exit;
149
150 stream->memory = memory;
151
152 if ( args->flags & FT_OPEN_MEMORY )
153 {
154 /* create a memory-based stream */
155 FT_Stream_OpenMemory( stream,
156 (const FT_Byte*)args->memory_base,
157 args->memory_size );
158 }
159 else if ( args->flags & FT_OPEN_PATHNAME )
160 {
161 /* create a normal system stream */
162 error = FT_Stream_Open( stream, args->pathname );
163 stream->pathname.pointer = args->pathname;
164 }
165 else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream )
166 {
167 /* use an existing, user-provided stream */
168
169 /* in this case, we do not need to allocate a new stream object */
170 /* since the caller is responsible for closing it himself */
171 FT_FREE( stream );
172 stream = args->stream;
173 }
174 else
175 error = FT_Err_Invalid_Argument;
176
177 if ( error )
178 FT_FREE( stream );
179 else
180 stream->memory = memory; /* just to be certain */
181
182 *astream = stream;
183
184 Exit:
185 return error;
186 }
187
188
189 FT_BASE_DEF( void )
190 FT_Stream_Free( FT_Stream stream,
191 FT_Int external )
192 {
193 if ( stream )
194 {
195 FT_Memory memory = stream->memory;
196
197
198 FT_Stream_Close( stream );
199
200 if ( !external )
201 FT_FREE( stream );
202 }
203 }
204
205
206 /*************************************************************************/
207 /* */
208 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
209 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
210 /* messages during execution. */
211 /* */
212 #undef FT_COMPONENT
213 #define FT_COMPONENT trace_objs
214
215
216 /*************************************************************************/
217 /*************************************************************************/
218 /*************************************************************************/
219 /**** ****/
220 /**** ****/
221 /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/
222 /**** ****/
223 /**** ****/
224 /*************************************************************************/
225 /*************************************************************************/
226 /*************************************************************************/
227
228
229 static FT_Error
230 ft_glyphslot_init( FT_GlyphSlot slot )
231 {
232 FT_Driver driver = slot->face->driver;
233 FT_Driver_Class clazz = driver->clazz;
234 FT_Memory memory = driver->root.memory;
235 FT_Error error = FT_Err_Ok;
236 FT_Slot_Internal internal = NULL;
237
238
239 slot->library = driver->root.library;
240
241 if ( FT_NEW( internal ) )
242 goto Exit;
243
244 slot->internal = internal;
245
246 if ( FT_DRIVER_USES_OUTLINES( driver ) )
247 error = FT_GlyphLoader_New( memory, &internal->loader );
248
249 if ( !error && clazz->init_slot )
250 error = clazz->init_slot( slot );
251
252 Exit:
253 return error;
254 }
255
256
257 FT_BASE_DEF( void )
258 ft_glyphslot_free_bitmap( FT_GlyphSlot slot )
259 {
260 if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
261 {
262 FT_Memory memory = FT_FACE_MEMORY( slot->face );
263
264
265 FT_FREE( slot->bitmap.buffer );
266 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
267 }
268 else
269 {
270 /* assume that the bitmap buffer was stolen or not */
271 /* allocated from the heap */
272 slot->bitmap.buffer = NULL;
273 }
274 }
275
276
277 FT_BASE_DEF( void )
278 ft_glyphslot_set_bitmap( FT_GlyphSlot slot,
279 FT_Byte* buffer )
280 {
281 ft_glyphslot_free_bitmap( slot );
282
283 slot->bitmap.buffer = buffer;
284
285 FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 );
286 }
287
288
289 FT_BASE_DEF( FT_Error )
290 ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot,
291 FT_ULong size )
292 {
293 FT_Memory memory = FT_FACE_MEMORY( slot->face );
294 FT_Error error;
295
296
297 if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
298 FT_FREE( slot->bitmap.buffer );
299 else
300 slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
301
302 (void)FT_ALLOC( slot->bitmap.buffer, size );
303 return error;
304 }
305
306
307 static void
308 ft_glyphslot_clear( FT_GlyphSlot slot )
309 {
310 /* free bitmap if needed */
311 ft_glyphslot_free_bitmap( slot );
312
313 /* clear all public fields in the glyph slot */
314 FT_ZERO( &slot->metrics );
315 FT_ZERO( &slot->outline );
316
317 slot->bitmap.width = 0;
318 slot->bitmap.rows = 0;
319 slot->bitmap.pitch = 0;
320 slot->bitmap.pixel_mode = 0;
321 /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */
322
323 slot->bitmap_left = 0;
324 slot->bitmap_top = 0;
325 slot->num_subglyphs = 0;
326 slot->subglyphs = 0;
327 slot->control_data = 0;
328 slot->control_len = 0;
329 slot->other = 0;
330 slot->format = FT_GLYPH_FORMAT_NONE;
331
332 slot->linearHoriAdvance = 0;
333 slot->linearVertAdvance = 0;
334 slot->lsb_delta = 0;
335 slot->rsb_delta = 0;
336 }
337
338
339 static void
340 ft_glyphslot_done( FT_GlyphSlot slot )
341 {
342 FT_Driver driver = slot->face->driver;
343 FT_Driver_Class clazz = driver->clazz;
344 FT_Memory memory = driver->root.memory;
345
346
347 if ( clazz->done_slot )
348 clazz->done_slot( slot );
349
350 /* free bitmap buffer if needed */
351 ft_glyphslot_free_bitmap( slot );
352
353 /* slot->internal might be NULL in out-of-memory situations */
354 if ( slot->internal )
355 {
356 /* free glyph loader */
357 if ( FT_DRIVER_USES_OUTLINES( driver ) )
358 {
359 FT_GlyphLoader_Done( slot->internal->loader );
360 slot->internal->loader = 0;
361 }
362
363 FT_FREE( slot->internal );
364 }
365 }
366
367
368 /* documentation is in ftobjs.h */
369
370 FT_BASE_DEF( FT_Error )
371 FT_New_GlyphSlot( FT_Face face,
372 FT_GlyphSlot *aslot )
373 {
374 FT_Error error;
375 FT_Driver driver;
376 FT_Driver_Class clazz;
377 FT_Memory memory;
378 FT_GlyphSlot slot;
379
380
381 if ( !face || !face->driver )
382 return FT_Err_Invalid_Argument;
383
384 driver = face->driver;
385 clazz = driver->clazz;
386 memory = driver->root.memory;
387
388 FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
389 if ( !FT_ALLOC( slot, clazz->slot_object_size ) )
390 {
391 slot->face = face;
392
393 error = ft_glyphslot_init( slot );
394 if ( error )
395 {
396 ft_glyphslot_done( slot );
397 FT_FREE( slot );
398 goto Exit;
399 }
400
401 slot->next = face->glyph;
402 face->glyph = slot;
403
404 if ( aslot )
405 *aslot = slot;
406 }
407 else if ( aslot )
408 *aslot = 0;
409
410
411 Exit:
412 FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error ));
413 return error;
414 }
415
416
417 /* documentation is in ftobjs.h */
418
419 FT_BASE_DEF( void )
420 FT_Done_GlyphSlot( FT_GlyphSlot slot )
421 {
422 if ( slot )
423 {
424 FT_Driver driver = slot->face->driver;
425 FT_Memory memory = driver->root.memory;
426 FT_GlyphSlot prev;
427 FT_GlyphSlot cur;
428
429
430 /* Remove slot from its parent face's list */
431 prev = NULL;
432 cur = slot->face->glyph;
433
434 while ( cur )
435 {
436 if ( cur == slot )
437 {
438 if ( !prev )
439 slot->face->glyph = cur->next;
440 else
441 prev->next = cur->next;
442
443 ft_glyphslot_done( slot );
444 FT_FREE( slot );
445 break;
446 }
447 prev = cur;
448 cur = cur->next;
449 }
450 }
451 }
452
453
454 /* documentation is in freetype.h */
455
456 FT_EXPORT_DEF( void )
457 FT_Set_Transform( FT_Face face,
458 FT_Matrix* matrix,
459 FT_Vector* delta )
460 {
461 FT_Face_Internal internal;
462
463
464 if ( !face )
465 return;
466
467 internal = face->internal;
468
469 internal->transform_flags = 0;
470
471 if ( !matrix )
472 {
473 internal->transform_matrix.xx = 0x10000L;
474 internal->transform_matrix.xy = 0;
475 internal->transform_matrix.yx = 0;
476 internal->transform_matrix.yy = 0x10000L;
477 matrix = &internal->transform_matrix;
478 }
479 else
480 internal->transform_matrix = *matrix;
481
482 /* set transform_flags bit flag 0 if `matrix' isn't the identity */
483 if ( ( matrix->xy | matrix->yx ) ||
484 matrix->xx != 0x10000L ||
485 matrix->yy != 0x10000L )
486 internal->transform_flags |= 1;
487
488 if ( !delta )
489 {
490 internal->transform_delta.x = 0;
491 internal->transform_delta.y = 0;
492 delta = &internal->transform_delta;
493 }
494 else
495 internal->transform_delta = *delta;
496
497 /* set transform_flags bit flag 1 if `delta' isn't the null vector */
498 if ( delta->x | delta->y )
499 internal->transform_flags |= 2;
500 }
501
502
503 static FT_Renderer
504 ft_lookup_glyph_renderer( FT_GlyphSlot slot );
505
506
507 #ifdef GRID_FIT_METRICS
508 static void
509 ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot,
510 FT_Bool vertical )
511 {
512 FT_Glyph_Metrics* metrics = &slot->metrics;
513 FT_Pos right, bottom;
514
515
516 if ( vertical )
517 {
518 metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
519 metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY );
520
521 right = FT_PIX_CEIL( metrics->vertBearingX + metrics->width );
522 bottom = FT_PIX_CEIL( metrics->vertBearingY + metrics->height );
523
524 metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
525 metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
526
527 metrics->width = right - metrics->vertBearingX;
528 metrics->height = bottom - metrics->vertBearingY;
529 }
530 else
531 {
532 metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
533 metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
534
535 right = FT_PIX_CEIL ( metrics->horiBearingX + metrics->width );
536 bottom = FT_PIX_FLOOR( metrics->horiBearingY - metrics->height );
537
538 metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
539 metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY );
540
541 metrics->width = right - metrics->horiBearingX;
542 metrics->height = metrics->horiBearingY - bottom;
543 }
544
545 metrics->horiAdvance = FT_PIX_ROUND( metrics->horiAdvance );
546 metrics->vertAdvance = FT_PIX_ROUND( metrics->vertAdvance );
547 }
548 #endif /* GRID_FIT_METRICS */
549
550
551 /* documentation is in freetype.h */
552
553 FT_EXPORT_DEF( FT_Error )
554 FT_Load_Glyph( FT_Face face,
555 FT_UInt glyph_index,
556 FT_Int32 load_flags )
557 {
558 FT_Error error;
559 FT_Driver driver;
560 FT_GlyphSlot slot;
561 FT_Library library;
562 FT_Bool autohint = FALSE;
563 FT_Module hinter;
564
565
566 if ( !face || !face->size || !face->glyph )
567 return FT_Err_Invalid_Face_Handle;
568
569 /* The validity test for `glyph_index' is performed by the */
570 /* font drivers. */
571
572 slot = face->glyph;
573 ft_glyphslot_clear( slot );
574
575 driver = face->driver;
576 library = driver->root.library;
577 hinter = library->auto_hinter;
578
579 /* resolve load flags dependencies */
580
581 if ( load_flags & FT_LOAD_NO_RECURSE )
582 load_flags |= FT_LOAD_NO_SCALE |
583 FT_LOAD_IGNORE_TRANSFORM;
584
585 if ( load_flags & FT_LOAD_NO_SCALE )
586 {
587 load_flags |= FT_LOAD_NO_HINTING |
588 FT_LOAD_NO_BITMAP;
589
590 load_flags &= ~FT_LOAD_RENDER;
591 }
592
593 /*
594 * Determine whether we need to auto-hint or not.
595 * The general rules are:
596 *
597 * - Do only auto-hinting if we have a hinter module, a scalable font
598 * format dealing with outlines, and no transforms except simple
599 * slants and/or rotations by integer multiples of 90 degrees.
600 *
601 * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
602 * have a native font hinter.
603 *
604 * - Otherwise, auto-hint for LIGHT hinting mode.
605 *
606 * - Exception: The font is `tricky' and requires the native hinter to
607 * load properly.
608 */
609
610 if ( hinter &&
611 !( load_flags & FT_LOAD_NO_HINTING ) &&
612 !( load_flags & FT_LOAD_NO_AUTOHINT ) &&
613 FT_DRIVER_IS_SCALABLE( driver ) &&
614 FT_DRIVER_USES_OUTLINES( driver ) &&
615 !FT_IS_TRICKY( face ) &&
616 ( ( face->internal->transform_matrix.yx == 0 &&
617 face->internal->transform_matrix.xx != 0 ) ||
618 ( face->internal->transform_matrix.xx == 0 &&
619 face->internal->transform_matrix.yx != 0 ) ) )
620 {
621 if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) ||
622 !FT_DRIVER_HAS_HINTER( driver ) )
623 autohint = TRUE;
624 else
625 {
626 FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
627
628
629 if ( mode == FT_RENDER_MODE_LIGHT ||
630 face->internal->ignore_unpatented_hinter )
631 autohint = TRUE;
632 }
633 }
634
635 if ( autohint )
636 {
637 FT_AutoHinter_Service hinting;
638
639
640 /* try to load embedded bitmaps first if available */
641 /* */
642 /* XXX: This is really a temporary hack that should disappear */
643 /* promptly with FreeType 2.1! */
644 /* */
645 if ( FT_HAS_FIXED_SIZES( face ) &&
646 ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
647 {
648 error = driver->clazz->load_glyph( slot, face->size,
649 glyph_index,
650 load_flags | FT_LOAD_SBITS_ONLY );
651
652 if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP )
653 goto Load_Ok;
654 }
655
656 {
657 FT_Face_Internal internal = face->internal;
658 FT_Int transform_flags = internal->transform_flags;
659
660
661 /* since the auto-hinter calls FT_Load_Glyph by itself, */
662 /* make sure that glyphs aren't transformed */
663 internal->transform_flags = 0;
664
665 /* load auto-hinted outline */
666 hinting = (FT_AutoHinter_Service)hinter->clazz->module_interface;
667
668 error = hinting->load_glyph( (FT_AutoHinter)hinter,
669 slot, face->size,
670 glyph_index, load_flags );
671
672 internal->transform_flags = transform_flags;
673 }
674 }
675 else
676 {
677 error = driver->clazz->load_glyph( slot,
678 face->size,
679 glyph_index,
680 load_flags );
681 if ( error )
682 goto Exit;
683
684 if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
685 {
686 /* check that the loaded outline is correct */
687 error = FT_Outline_Check( &slot->outline );
688 if ( error )
689 goto Exit;
690
691 #ifdef GRID_FIT_METRICS
692 if ( !( load_flags & FT_LOAD_NO_HINTING ) )
693 ft_glyphslot_grid_fit_metrics( slot,
694 FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) );
695 #endif
696 }
697 }
698
699 Load_Ok:
700 /* compute the advance */
701 if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
702 {
703 slot->advance.x = 0;
704 slot->advance.y = slot->metrics.vertAdvance;
705 }
706 else
707 {
708 slot->advance.x = slot->metrics.horiAdvance;
709 slot->advance.y = 0;
710 }
711
712 /* compute the linear advance in 16.16 pixels */
713 if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 &&
714 ( FT_IS_SCALABLE( face ) ) )
715 {
716 FT_Size_Metrics* metrics = &face->size->metrics;
717
718
719 /* it's tricky! */
720 slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance,
721 metrics->x_scale, 64 );
722
723 slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance,
724 metrics->y_scale, 64 );
725 }
726
727 if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 )
728 {
729 FT_Face_Internal internal = face->internal;
730
731
732 /* now, transform the glyph image if needed */
733 if ( internal->transform_flags )
734 {
735 /* get renderer */
736 FT_Renderer renderer = ft_lookup_glyph_renderer( slot );
737
738
739 if ( renderer )
740 error = renderer->clazz->transform_glyph(
741 renderer, slot,
742 &internal->transform_matrix,
743 &internal->transform_delta );
744 else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
745 {
746 /* apply `standard' transformation if no renderer is available */
747 if ( &internal->transform_matrix )
748 FT_Outline_Transform( &slot->outline,
749 &internal->transform_matrix );
750
751 if ( &internal->transform_delta )
752 FT_Outline_Translate( &slot->outline,
753 internal->transform_delta.x,
754 internal->transform_delta.y );
755 }
756
757 /* transform advance */
758 FT_Vector_Transform( &slot->advance, &internal->transform_matrix );
759 }
760 }
761
762 FT_TRACE5(( " x advance: %d\n" , slot->advance.x ));
763 FT_TRACE5(( " y advance: %d\n" , slot->advance.y ));
764
765 FT_TRACE5(( " linear x advance: %d\n" , slot->linearHoriAdvance ));
766 FT_TRACE5(( " linear y advance: %d\n" , slot->linearVertAdvance ));
767
768 /* do we need to render the image now? */
769 if ( !error &&
770 slot->format != FT_GLYPH_FORMAT_BITMAP &&
771 slot->format != FT_GLYPH_FORMAT_COMPOSITE &&
772 load_flags & FT_LOAD_RENDER )
773 {
774 FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
775
776
777 if ( mode == FT_RENDER_MODE_NORMAL &&
778 (load_flags & FT_LOAD_MONOCHROME ) )
779 mode = FT_RENDER_MODE_MONO;
780
781 error = FT_Render_Glyph( slot, mode );
782 }
783
784 Exit:
785 return error;
786 }
787
788
789 /* documentation is in freetype.h */
790
791 FT_EXPORT_DEF( FT_Error )
792 FT_Load_Char( FT_Face face,
793 FT_ULong char_code,
794 FT_Int32 load_flags )
795 {
796 FT_UInt glyph_index;
797
798
799 if ( !face )
800 return FT_Err_Invalid_Face_Handle;
801
802 glyph_index = (FT_UInt)char_code;
803 if ( face->charmap )
804 glyph_index = FT_Get_Char_Index( face, char_code );
805
806 return FT_Load_Glyph( face, glyph_index, load_flags );
807 }
808
809
810 /* destructor for sizes list */
811 static void
812 destroy_size( FT_Memory memory,
813 FT_Size size,
814 FT_Driver driver )
815 {
816 /* finalize client-specific data */
817 if ( size->generic.finalizer )
818 size->generic.finalizer( size );
819
820 /* finalize format-specific stuff */
821 if ( driver->clazz->done_size )
822 driver->clazz->done_size( size );
823
824 FT_FREE( size->internal );
825 FT_FREE( size );
826 }
827
828
829 static void
830 ft_cmap_done_internal( FT_CMap cmap );
831
832
833 static void
834 destroy_charmaps( FT_Face face,
835 FT_Memory memory )
836 {
837 FT_Int n;
838
839
840 if ( !face )
841 return;
842
843 for ( n = 0; n < face->num_charmaps; n++ )
844 {
845 FT_CMap cmap = FT_CMAP( face->charmaps[n] );
846
847
848 ft_cmap_done_internal( cmap );
849
850 face->charmaps[n] = NULL;
851 }
852
853 FT_FREE( face->charmaps );
854 face->num_charmaps = 0;
855 }
856
857
858 /* destructor for faces list */
859 static void
860 destroy_face( FT_Memory memory,
861 FT_Face face,
862 FT_Driver driver )
863 {
864 FT_Driver_Class clazz = driver->clazz;
865
866
867 /* discard auto-hinting data */
868 if ( face->autohint.finalizer )
869 face->autohint.finalizer( face->autohint.data );
870
871 /* Discard glyph slots for this face. */
872 /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */
873 while ( face->glyph )
874 FT_Done_GlyphSlot( face->glyph );
875
876 /* discard all sizes for this face */
877 FT_List_Finalize( &face->sizes_list,
878 (FT_List_Destructor)destroy_size,
879 memory,
880 driver );
881 face->size = 0;
882
883 /* now discard client data */
884 if ( face->generic.finalizer )
885 face->generic.finalizer( face );
886
887 /* discard charmaps */
888 destroy_charmaps( face, memory );
889
890 /* finalize format-specific stuff */
891 if ( clazz->done_face )
892 clazz->done_face( face );
893
894 /* close the stream for this face if needed */
895 FT_Stream_Free(
896 face->stream,
897 ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
898
899 face->stream = 0;
900
901 /* get rid of it */
902 if ( face->internal )
903 {
904 FT_FREE( face->internal );
905 }
906 FT_FREE( face );
907 }
908
909
910 static void
911 Destroy_Driver( FT_Driver driver )
912 {
913 FT_List_Finalize( &driver->faces_list,
914 (FT_List_Destructor)destroy_face,
915 driver->root.memory,
916 driver );
917
918 /* check whether we need to drop the driver's glyph loader */
919 if ( FT_DRIVER_USES_OUTLINES( driver ) )
920 FT_GlyphLoader_Done( driver->glyph_loader );
921 }
922
923
924 /*************************************************************************/
925 /* */
926 /* <Function> */
927 /* find_unicode_charmap */
928 /* */
929 /* <Description> */
930 /* This function finds a Unicode charmap, if there is one. */
931 /* And if there is more than one, it tries to favour the more */
932 /* extensive one, i.e., one that supports UCS-4 against those which */
933 /* are limited to the BMP (said UCS-2 encoding.) */
934 /* */
935 /* This function is called from open_face() (just below), and also */
936 /* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). */
937 /* */
938 static FT_Error
939 find_unicode_charmap( FT_Face face )
940 {
941 FT_CharMap* first;
942 FT_CharMap* cur;
943
944
945 /* caller should have already checked that `face' is valid */
946 FT_ASSERT( face );
947
948 first = face->charmaps;
949
950 if ( !first )
951 return FT_Err_Invalid_CharMap_Handle;
952
953 /*
954 * The original TrueType specification(s) only specified charmap
955 * formats that are capable of mapping 8 or 16 bit character codes to
956 * glyph indices.
957 *
958 * However, recent updates to the Apple and OpenType specifications
959 * introduced new formats that are capable of mapping 32-bit character
960 * codes as well. And these are already used on some fonts, mainly to
961 * map non-BMP Asian ideographs as defined in Unicode.
962 *
963 * For compatibility purposes, these fonts generally come with
964 * *several* Unicode charmaps:
965 *
966 * - One of them in the "old" 16-bit format, that cannot access
967 * all glyphs in the font.
968 *
969 * - Another one in the "new" 32-bit format, that can access all
970 * the glyphs.
971 *
972 * This function has been written to always favor a 32-bit charmap
973 * when found. Otherwise, a 16-bit one is returned when found.
974 */
975
976 /* Since the `interesting' table, with IDs (3,10), is normally the */
977 /* last one, we loop backwards. This loses with type1 fonts with */
978 /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */
979 /* chars (.01% ?), and this is the same about 99.99% of the time! */
980
981 cur = first + face->num_charmaps; /* points after the last one */
982
983 for ( ; --cur >= first; )
984 {
985 if ( cur[0]->encoding == FT_ENCODING_UNICODE )
986 {
987 /* XXX If some new encodings to represent UCS-4 are added, */
988 /* they should be added here. */
989 if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT &&
990 cur[0]->encoding_id == TT_MS_ID_UCS_4 ) ||
991 ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
992 cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) )
993 {
994 #ifdef FT_MAX_CHARMAP_CACHEABLE
995 if ( cur - first > FT_MAX_CHARMAP_CACHEABLE )
996 {
997 FT_ERROR(( "find_unicode_charmap: UCS-4 cmap is found "
998 "at too late position (%d)\n", cur - first ));
999 continue;
1000 }
1001 #endif
1002 face->charmap = cur[0];
1003 return FT_Err_Ok;
1004 }
1005 }
1006 }
1007
1008 /* We do not have any UCS-4 charmap. */
1009 /* Do the loop again and search for UCS-2 charmaps. */
1010 cur = first + face->num_charmaps;
1011
1012 for ( ; --cur >= first; )
1013 {
1014 if ( cur[0]->encoding == FT_ENCODING_UNICODE )
1015 {
1016 #ifdef FT_MAX_CHARMAP_CACHEABLE
1017 if ( cur - first > FT_MAX_CHARMAP_CACHEABLE )
1018 {
1019 FT_ERROR(( "find_unicode_charmap: UCS-2 cmap is found "
1020 "at too late position (%d)\n", cur - first ));
1021 continue;
1022 }
1023 #endif
1024 face->charmap = cur[0];
1025 return FT_Err_Ok;
1026 }
1027 }
1028
1029 return FT_Err_Invalid_CharMap_Handle;
1030 }
1031
1032
1033 /*************************************************************************/
1034 /* */
1035 /* <Function> */
1036 /* find_variant_selector_charmap */
1037 /* */
1038 /* <Description> */
1039 /* This function finds the variant selector charmap, if there is one. */
1040 /* There can only be one (platform=0, specific=5, format=14). */
1041 /* */
1042 static FT_CharMap
1043 find_variant_selector_charmap( FT_Face face )
1044 {
1045 FT_CharMap* first;
1046 FT_CharMap* end;
1047 FT_CharMap* cur;
1048
1049
1050 /* caller should have already checked that `face' is valid */
1051 FT_ASSERT( face );
1052
1053 first = face->charmaps;
1054
1055 if ( !first )
1056 return NULL;
1057
1058 end = first + face->num_charmaps; /* points after the last one */
1059
1060 for ( cur = first; cur < end; ++cur )
1061 {
1062 if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
1063 cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR &&
1064 FT_Get_CMap_Format( cur[0] ) == 14 )
1065 {
1066 #ifdef FT_MAX_CHARMAP_CACHEABLE
1067 if ( cur - first > FT_MAX_CHARMAP_CACHEABLE )
1068 {
1069 FT_ERROR(( "find_unicode_charmap: UVS cmap is found "
1070 "at too late position (%d)\n", cur - first ));
1071 continue;
1072 }
1073 #endif
1074 return cur[0];
1075 }
1076 }
1077
1078 return NULL;
1079 }
1080
1081
1082 /*************************************************************************/
1083 /* */
1084 /* <Function> */
1085 /* open_face */
1086 /* */
1087 /* <Description> */
1088 /* This function does some work for FT_Open_Face(). */
1089 /* */
1090 static FT_Error
1091 open_face( FT_Driver driver,
1092 FT_Stream stream,
1093 FT_Long face_index,
1094 FT_Int num_params,
1095 FT_Parameter* params,
1096 FT_Face *aface )
1097 {
1098 FT_Memory memory;
1099 FT_Driver_Class clazz;
1100 FT_Face face = 0;
1101 FT_Error error, error2;
1102 FT_Face_Internal internal = NULL;
1103
1104
1105 clazz = driver->clazz;
1106 memory = driver->root.memory;
1107
1108 /* allocate the face object and perform basic initialization */
1109 if ( FT_ALLOC( face, clazz->face_object_size ) )
1110 goto Fail;
1111
1112 if ( FT_NEW( internal ) )
1113 goto Fail;
1114
1115 face->internal = internal;
1116
1117 face->driver = driver;
1118 face->memory = memory;
1119 face->stream = stream;
1120
1121 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1122 {
1123 int i;
1124
1125
1126 face->internal->incremental_interface = 0;
1127 for ( i = 0; i < num_params && !face->internal->incremental_interface;
1128 i++ )
1129 if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL )
1130 face->internal->incremental_interface =
1131 (FT_Incremental_Interface)params[i].data;
1132 }
1133 #endif
1134
1135 if ( clazz->init_face )
1136 error = clazz->init_face( stream,
1137 face,
1138 (FT_Int)face_index,
1139 num_params,
1140 params );
1141 if ( error )
1142 goto Fail;
1143
1144 /* select Unicode charmap by default */
1145 error2 = find_unicode_charmap( face );
1146
1147 /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */
1148 /* is returned. */
1149
1150 /* no error should happen, but we want to play safe */
1151 if ( error2 && error2 != FT_Err_Invalid_CharMap_Handle )
1152 {
1153 error = error2;
1154 goto Fail;
1155 }
1156
1157 *aface = face;
1158
1159 Fail:
1160 if ( error )
1161 {
1162 destroy_charmaps( face, memory );
1163 if ( clazz->done_face )
1164 clazz->done_face( face );
1165 FT_FREE( internal );
1166 FT_FREE( face );
1167 *aface = 0;
1168 }
1169
1170 return error;
1171 }
1172
1173
1174 /* there's a Mac-specific extended implementation of FT_New_Face() */
1175 /* in src/base/ftmac.c */
1176
1177 #if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON )
1178
1179 /* documentation is in freetype.h */
1180
1181 FT_EXPORT_DEF( FT_Error )
1182 FT_New_Face( FT_Library library,
1183 const char* pathname,
1184 FT_Long face_index,
1185 FT_Face *aface )
1186 {
1187 FT_Open_Args args;
1188
1189
1190 /* test for valid `library' and `aface' delayed to FT_Open_Face() */
1191 if ( !pathname )
1192 return FT_Err_Invalid_Argument;
1193
1194 args.flags = FT_OPEN_PATHNAME;
1195 args.pathname = (char*)pathname;
1196 args.stream = NULL;
1197
1198 return FT_Open_Face( library, &args, face_index, aface );
1199 }
1200
1201 #endif /* defined( FT_MACINTOSH ) && !defined( DARWIN_NO_CARBON ) */
1202
1203
1204 /* documentation is in freetype.h */
1205
1206 FT_EXPORT_DEF( FT_Error )
1207 FT_New_Memory_Face( FT_Library library,
1208 const FT_Byte* file_base,
1209 FT_Long file_size,
1210 FT_Long face_index,
1211 FT_Face *aface )
1212 {
1213 FT_Open_Args args;
1214
1215
1216 /* test for valid `library' and `face' delayed to FT_Open_Face() */
1217 if ( !file_base )
1218 return FT_Err_Invalid_Argument;
1219
1220 args.flags = FT_OPEN_MEMORY;
1221 args.memory_base = file_base;
1222 args.memory_size = file_size;
1223 args.stream = NULL;
1224
1225 return FT_Open_Face( library, &args, face_index, aface );
1226 }
1227
1228
1229 #ifdef FT_CONFIG_OPTION_MAC_FONTS
1230
1231 /* The behavior here is very similar to that in base/ftmac.c, but it */
1232 /* is designed to work on non-mac systems, so no mac specific calls. */
1233 /* */
1234 /* We look at the file and determine if it is a mac dfont file or a mac */
1235 /* resource file, or a macbinary file containing a mac resource file. */
1236 /* */
1237 /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */
1238 /* the point, especially since there may be multiple `FOND' resources. */
1239 /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */
1240 /* they occur in the file. */
1241 /* */
1242 /* Note that multiple `POST' resources do not mean multiple postscript */
1243 /* fonts; they all get jammed together to make what is essentially a */
1244 /* pfb file. */
1245 /* */
1246 /* We aren't interested in `NFNT' or `FONT' bitmap resources. */
1247 /* */
1248 /* As soon as we get an `sfnt' load it into memory and pass it off to */
1249 /* FT_Open_Face. */
1250 /* */
1251 /* If we have a (set of) `POST' resources, massage them into a (memory) */
1252 /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */
1253 /* going to try to save the kerning info. After all that lives in the */
1254 /* `FOND' which isn't in the file containing the `POST' resources so */
1255 /* we don't really have access to it. */
1256
1257
1258 /* Finalizer for a memory stream; gets called by FT_Done_Face(). */
1259 /* It frees the memory it uses. */
1260 /* From ftmac.c. */
1261 static void
1262 memory_stream_close( FT_Stream stream )
1263 {
1264 FT_Memory memory = stream->memory;
1265
1266
1267 FT_FREE( stream->base );
1268
1269 stream->size = 0;
1270 stream->base = 0;
1271 stream->close = 0;
1272 }
1273
1274
1275 /* Create a new memory stream from a buffer and a size. */
1276 /* From ftmac.c. */
1277 static FT_Error
1278 new_memory_stream( FT_Library library,
1279 FT_Byte* base,
1280 FT_ULong size,
1281 FT_Stream_CloseFunc close,
1282 FT_Stream *astream )
1283 {
1284 FT_Error error;
1285 FT_Memory memory;
1286 FT_Stream stream;
1287
1288
1289 if ( !library )
1290 return FT_Err_Invalid_Library_Handle;
1291
1292 if ( !base )
1293 return FT_Err_Invalid_Argument;
1294
1295 *astream = 0;
1296 memory = library->memory;
1297 if ( FT_NEW( stream ) )
1298 goto Exit;
1299
1300 FT_Stream_OpenMemory( stream, base, size );
1301
1302 stream->close = close;
1303
1304 *astream = stream;
1305
1306 Exit:
1307 return error;
1308 }
1309
1310
1311 /* Create a new FT_Face given a buffer and a driver name. */
1312 /* from ftmac.c */
1313 FT_LOCAL_DEF( FT_Error )
1314 open_face_from_buffer( FT_Library library,
1315 FT_Byte* base,
1316 FT_ULong size,
1317 FT_Long face_index,
1318 const char* driver_name,
1319 FT_Face *aface )
1320 {
1321 FT_Open_Args args;
1322 FT_Error error;
1323 FT_Stream stream = NULL;
1324 FT_Memory memory = library->memory;
1325
1326
1327 error = new_memory_stream( library,
1328 base,
1329 size,
1330 memory_stream_close,
1331 &stream );
1332 if ( error )
1333 {
1334 FT_FREE( base );
1335 return error;
1336 }
1337
1338 args.flags = FT_OPEN_STREAM;
1339 args.stream = stream;
1340 if ( driver_name )
1341 {
1342 args.flags = args.flags | FT_OPEN_DRIVER;
1343 args.driver = FT_Get_Module( library, driver_name );
1344 }
1345
1346 #ifdef FT_MACINTOSH
1347 /* At this point, face_index has served its purpose; */
1348 /* whoever calls this function has already used it to */
1349 /* locate the correct font data. We should not propagate */
1350 /* this index to FT_Open_Face() (unless it is negative). */
1351
1352 if ( face_index > 0 )
1353 face_index = 0;
1354 #endif
1355
1356 error = FT_Open_Face( library, &args, face_index, aface );
1357
1358 if ( error == FT_Err_Ok )
1359 (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
1360 else
1361 #ifdef FT_MACINTOSH
1362 FT_Stream_Free( stream, 0 );
1363 #else
1364 {
1365 FT_Stream_Close( stream );
1366 FT_FREE( stream );
1367 }
1368 #endif
1369
1370 return error;
1371 }
1372
1373
1374 /* Look up `TYP1' or `CID ' table from sfnt table directory. */
1375 /* `offset' and `length' must exclude the binary header in tables. */
1376
1377 /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */
1378 /* format too. Here, since we can't expect that the TrueType font */
1379 /* driver is loaded unconditially, we must parse the font by */
1380 /* ourselves. We are only interested in the name of the table and */
1381 /* the offset. */
1382
1383 static FT_Error
1384 ft_lookup_PS_in_sfnt_stream( FT_Stream stream,
1385 FT_Long face_index,
1386 FT_ULong* offset,
1387 FT_ULong* length,
1388 FT_Bool* is_sfnt_cid )
1389 {
1390 FT_Error error;
1391 FT_UShort numTables;
1392 FT_Long pstable_index;
1393 FT_ULong tag;
1394 int i;
1395
1396
1397 *offset = 0;
1398 *length = 0;
1399 *is_sfnt_cid = FALSE;
1400
1401 /* TODO: support for sfnt-wrapped PS/CID in TTC format */
1402
1403 /* version check for 'typ1' (should be ignored?) */
1404 if ( FT_READ_ULONG( tag ) )
1405 return error;
1406 if ( tag != TTAG_typ1 )
1407 return FT_Err_Unknown_File_Format;
1408
1409 if ( FT_READ_USHORT( numTables ) )
1410 return error;
1411 if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */
1412 return error;
1413
1414 pstable_index = -1;
1415 *is_sfnt_cid = FALSE;
1416
1417 for ( i = 0; i < numTables; i++ )
1418 {
1419 if ( FT_READ_ULONG( tag ) || FT_STREAM_SKIP( 4 ) ||
1420 FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) )
1421 return error;
1422
1423 if ( tag == TTAG_CID )
1424 {
1425 pstable_index++;
1426 *offset += 22;
1427 *length -= 22;
1428 *is_sfnt_cid = TRUE;
1429 if ( face_index < 0 )
1430 return FT_Err_Ok;
1431 }
1432 else if ( tag == TTAG_TYP1 )
1433 {
1434 pstable_index++;
1435 *offset += 24;
1436 *length -= 24;
1437 *is_sfnt_cid = FALSE;
1438 if ( face_index < 0 )
1439 return FT_Err_Ok;
1440 }
1441 if ( face_index >= 0 && pstable_index == face_index )
1442 return FT_Err_Ok;
1443 }
1444 return FT_Err_Table_Missing;
1445 }
1446
1447
1448 FT_LOCAL_DEF( FT_Error )
1449 open_face_PS_from_sfnt_stream( FT_Library library,
1450 FT_Stream stream,
1451 FT_Long face_index,
1452 FT_Int num_params,
1453 FT_Parameter *params,
1454 FT_Face *aface )
1455 {
1456 FT_Error error;
1457 FT_Memory memory = library->memory;
1458 FT_ULong offset, length;
1459 FT_Long pos;
1460 FT_Bool is_sfnt_cid;
1461 FT_Byte* sfnt_ps;
1462
1463 FT_UNUSED( num_params );
1464 FT_UNUSED( params );
1465
1466
1467 pos = FT_Stream_Pos( stream );
1468
1469 error = ft_lookup_PS_in_sfnt_stream( stream,
1470 face_index,
1471 &offset,
1472 &length,
1473 &is_sfnt_cid );
1474 if ( error )
1475 goto Exit;
1476
1477 if ( FT_Stream_Seek( stream, pos + offset ) )
1478 goto Exit;
1479
1480 if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) )
1481 goto Exit;
1482
1483 error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length );
1484 if ( error )
1485 goto Exit;
1486
1487 error = open_face_from_buffer( library,
1488 sfnt_ps,
1489 length,
1490 face_index < 0 ? face_index : 0,
1491 is_sfnt_cid ? "cid" : "type1",
1492 aface );
1493 Exit:
1494 {
1495 FT_Error error1;
1496
1497
1498 if ( error == FT_Err_Unknown_File_Format )
1499 {
1500 error1 = FT_Stream_Seek( stream, pos );
1501 if ( error1 )
1502 return error1;
1503 }
1504
1505 return error;
1506 }
1507 }
1508
1509
1510 #if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON )
1511
1512 /* The resource header says we've got resource_cnt `POST' (type1) */
1513 /* resources in this file. They all need to be coalesced into */
1514 /* one lump which gets passed on to the type1 driver. */
1515 /* Here can be only one PostScript font in a file so face_index */
1516 /* must be 0 (or -1). */
1517 /* */
1518 static FT_Error
1519 Mac_Read_POST_Resource( FT_Library library,
1520 FT_Stream stream,
1521 FT_Long *offsets,
1522 FT_Long resource_cnt,
1523 FT_Long face_index,
1524 FT_Face *aface )
1525 {
1526 FT_Error error = FT_Err_Cannot_Open_Resource;
1527 FT_Memory memory = library->memory;
1528 FT_Byte* pfb_data;
1529 int i, type, flags;
1530 FT_Long len;
1531 FT_Long pfb_len, pfb_pos, pfb_lenpos;
1532 FT_Long rlen, temp;
1533
1534
1535 if ( face_index == -1 )
1536 face_index = 0;
1537 if ( face_index != 0 )
1538 return error;
1539
1540 /* Find the length of all the POST resources, concatenated. Assume */
1541 /* worst case (each resource in its own section). */
1542 pfb_len = 0;
1543 for ( i = 0; i < resource_cnt; ++i )
1544 {
1545 error = FT_Stream_Seek( stream, offsets[i] );
1546 if ( error )
1547 goto Exit;
1548 if ( FT_READ_LONG( temp ) )
1549 goto Exit;
1550 pfb_len += temp + 6;
1551 }
1552
1553 if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) )
1554 goto Exit;
1555
1556 pfb_data[0] = 0x80;
1557 pfb_data[1] = 1; /* Ascii section */
1558 pfb_data[2] = 0; /* 4-byte length, fill in later */
1559 pfb_data[3] = 0;
1560 pfb_data[4] = 0;
1561 pfb_data[5] = 0;
1562 pfb_pos = 6;
1563 pfb_lenpos = 2;
1564
1565 len = 0;
1566 type = 1;
1567 for ( i = 0; i < resource_cnt; ++i )
1568 {
1569 error = FT_Stream_Seek( stream, offsets[i] );
1570 if ( error )
1571 goto Exit2;
1572 if ( FT_READ_LONG( rlen ) )
1573 goto Exit;
1574 if ( FT_READ_USHORT( flags ) )
1575 goto Exit;
1576 FT_TRACE3(( "POST fragment[%d]: offsets=0x%08x, rlen=0x%08x, flags=0x%04x\n",
1577 i, offsets[i], rlen, flags ));
1578
1579 /* postpone the check of rlen longer than buffer until FT_Stream_Read() */
1580 if ( ( flags >> 8 ) == 0 ) /* Comment, should not be loaded */
1581 continue;
1582
1583 /* the flags are part of the resource, so rlen >= 2. */
1584 /* but some fonts declare rlen = 0 for empty fragment */
1585 if ( rlen > 2 )
1586 rlen -= 2;
1587 else
1588 rlen = 0;
1589
1590 if ( ( flags >> 8 ) == type )
1591 len += rlen;
1592 else
1593 {
1594 if ( pfb_lenpos + 3 > pfb_len + 2 )
1595 goto Exit2;
1596 pfb_data[pfb_lenpos ] = (FT_Byte)( len );
1597 pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
1598 pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
1599 pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
1600
1601 if ( ( flags >> 8 ) == 5 ) /* End of font mark */
1602 break;
1603
1604 if ( pfb_pos + 6 > pfb_len + 2 )
1605 goto Exit2;
1606 pfb_data[pfb_pos++] = 0x80;
1607
1608 type = flags >> 8;
1609 len = rlen;
1610
1611 pfb_data[pfb_pos++] = (FT_Byte)type;
1612 pfb_lenpos = pfb_pos;
1613 pfb_data[pfb_pos++] = 0; /* 4-byte length, fill in later */
1614 pfb_data[pfb_pos++] = 0;
1615 pfb_data[pfb_pos++] = 0;
1616 pfb_data[pfb_pos++] = 0;
1617 }
1618
1619 error = FT_Err_Cannot_Open_Resource;
1620 if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len )
1621 goto Exit2;
1622
1623 error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen );
1624 if ( error )
1625 goto Exit2;
1626 pfb_pos += rlen;
1627 }
1628
1629 if ( pfb_pos + 2 > pfb_len + 2 )
1630 goto Exit2;
1631 pfb_data[pfb_pos++] = 0x80;
1632 pfb_data[pfb_pos++] = 3;
1633
1634 if ( pfb_lenpos + 3 > pfb_len + 2 )
1635 goto Exit2;
1636 pfb_data[pfb_lenpos ] = (FT_Byte)( len );
1637 pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
1638 pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
1639 pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
1640
1641 return open_face_from_buffer( library,
1642 pfb_data,
1643 pfb_pos,
1644 face_index,
1645 "type1",
1646 aface );
1647
1648 Exit2:
1649 FT_FREE( pfb_data );
1650
1651 Exit:
1652 return error;
1653 }
1654
1655
1656 /* The resource header says we've got resource_cnt `sfnt' */
1657 /* (TrueType/OpenType) resources in this file. Look through */
1658 /* them for the one indicated by face_index, load it into mem, */
1659 /* pass it on the the truetype driver and return it. */
1660 /* */
1661 static FT_Error
1662 Mac_Read_sfnt_Resource( FT_Library library,
1663 FT_Stream stream,
1664 FT_Long *offsets,
1665 FT_Long resource_cnt,
1666 FT_Long face_index,
1667 FT_Face *aface )
1668 {
1669 FT_Memory memory = library->memory;
1670 FT_Byte* sfnt_data;
1671 FT_Error error;
1672 FT_Long flag_offset;
1673 FT_Long rlen;
1674 int is_cff;
1675 FT_Long face_index_in_resource = 0;
1676
1677
1678 if ( face_index == -1 )
1679 face_index = 0;
1680 if ( face_index >= resource_cnt )
1681 return FT_Err_Cannot_Open_Resource;
1682
1683 flag_offset = offsets[face_index];
1684 error = FT_Stream_Seek( stream, flag_offset );
1685 if ( error )
1686 goto Exit;
1687
1688 if ( FT_READ_LONG( rlen ) )
1689 goto Exit;
1690 if ( rlen == -1 )
1691 return FT_Err_Cannot_Open_Resource;
1692
1693 error = open_face_PS_from_sfnt_stream( library,
1694 stream,
1695 face_index,
1696 0, NULL,
1697 aface );
1698 if ( !error )
1699 goto Exit;
1700
1701 /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */
1702 if ( FT_Stream_Seek( stream, flag_offset + 4 ) )
1703 goto Exit;
1704
1705 if ( FT_ALLOC( sfnt_data, (FT_Long)rlen ) )
1706 return error;
1707 error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen );
1708 if ( error )
1709 goto Exit;
1710
1711 is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
1712 error = open_face_from_buffer( library,
1713 sfnt_data,
1714 rlen,
1715 face_index_in_resource,
1716 is_cff ? "cff" : "truetype",
1717 aface );
1718
1719 Exit:
1720 return error;
1721 }
1722
1723
1724 /* Check for a valid resource fork header, or a valid dfont */
1725 /* header. In a resource fork the first 16 bytes are repeated */
1726 /* at the location specified by bytes 4-7. In a dfont bytes */
1727 /* 4-7 point to 16 bytes of zeroes instead. */
1728 /* */
1729 static FT_Error
1730 IsMacResource( FT_Library library,
1731 FT_Stream stream,
1732 FT_Long resource_offset,
1733 FT_Long face_index,
1734 FT_Face *aface )
1735 {
1736 FT_Memory memory = library->memory;
1737 FT_Error error;
1738 FT_Long map_offset, rdara_pos;
1739 FT_Long *data_offsets;
1740 FT_Long count;
1741
1742
1743 error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset,
1744 &map_offset, &rdara_pos );
1745 if ( error )
1746 return error;
1747
1748 error = FT_Raccess_Get_DataOffsets( library, stream,
1749 map_offset, rdara_pos,
1750 TTAG_POST,
1751 &data_offsets, &count );
1752 if ( !error )
1753 {
1754 error = Mac_Read_POST_Resource( library, stream, data_offsets, count,
1755 face_index, aface );
1756 FT_FREE( data_offsets );
1757 /* POST exists in an LWFN providing a single face */
1758 if ( !error )
1759 (*aface)->num_faces = 1;
1760 return error;
1761 }
1762
1763 error = FT_Raccess_Get_DataOffsets( library, stream,
1764 map_offset, rdara_pos,
1765 TTAG_sfnt,
1766 &data_offsets, &count );
1767 if ( !error )
1768 {
1769 FT_Long face_index_internal = face_index % count;
1770
1771
1772 error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count,
1773 face_index_internal, aface );
1774 FT_FREE( data_offsets );
1775 if ( !error )
1776 (*aface)->num_faces = count;
1777 }
1778
1779 return error;
1780 }
1781
1782
1783 /* Check for a valid macbinary header, and if we find one */
1784 /* check that the (flattened) resource fork in it is valid. */
1785 /* */
1786 static FT_Error
1787 IsMacBinary( FT_Library library,
1788 FT_Stream stream,
1789 FT_Long face_index,
1790 FT_Face *aface )
1791 {
1792 unsigned char header[128];
1793 FT_Error error;
1794 FT_Long dlen, offset;
1795
1796
1797 if ( NULL == stream )
1798 return FT_Err_Invalid_Stream_Operation;
1799
1800 error = FT_Stream_Seek( stream, 0 );
1801 if ( error )
1802 goto Exit;
1803
1804 error = FT_Stream_Read( stream, (FT_Byte*)header, 128 );
1805 if ( error )
1806 goto Exit;
1807
1808 if ( header[ 0] != 0 ||
1809 header[74] != 0 ||
1810 header[82] != 0 ||
1811 header[ 1] == 0 ||
1812 header[ 1] > 33 ||
1813 header[63] != 0 ||
1814 header[2 + header[1]] != 0 )
1815 return FT_Err_Unknown_File_Format;
1816
1817 dlen = ( header[0x53] << 24 ) |
1818 ( header[0x54] << 16 ) |
1819 ( header[0x55] << 8 ) |
1820 header[0x56];
1821 #if 0
1822 rlen = ( header[0x57] << 24 ) |
1823 ( header[0x58] << 16 ) |
1824 ( header[0x59] << 8 ) |
1825 header[0x5a];
1826 #endif /* 0 */
1827 offset = 128 + ( ( dlen + 127 ) & ~127 );
1828
1829 return IsMacResource( library, stream, offset, face_index, aface );
1830
1831 Exit:
1832 return error;
1833 }
1834
1835
1836 static FT_Error
1837 load_face_in_embedded_rfork( FT_Library library,
1838 FT_Stream stream,
1839 FT_Long face_index,
1840 FT_Face *aface,
1841 const FT_Open_Args *args )
1842 {
1843
1844 #undef FT_COMPONENT
1845 #define FT_COMPONENT trace_raccess
1846
1847 FT_Memory memory = library->memory;
1848 FT_Error error = FT_Err_Unknown_File_Format;
1849 int i;
1850
1851 char * file_names[FT_RACCESS_N_RULES];
1852 FT_Long offsets[FT_RACCESS_N_RULES];
1853 FT_Error errors[FT_RACCESS_N_RULES];
1854 FT_Bool is_darwin_vfs, vfs_rfork_has_no_font = FALSE; /* not tested */
1855
1856 FT_Open_Args args2;
1857 FT_Stream stream2 = 0;
1858
1859
1860 FT_Raccess_Guess( library, stream,
1861 args->pathname, file_names, offsets, errors );
1862
1863 for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
1864 {
1865 is_darwin_vfs = raccess_rule_by_darwin_vfs( i );
1866 if ( is_darwin_vfs && vfs_rfork_has_no_font )
1867 {
1868 FT_TRACE3(( "Skip rule %d: darwin vfs resource fork"
1869 " is already checked and"
1870 " no font is found\n", i ));
1871 continue;
1872 }
1873
1874 if ( errors[i] )
1875 {
1876 FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors[i], i ));
1877 continue;
1878 }
1879
1880 args2.flags = FT_OPEN_PATHNAME;
1881 args2.pathname = file_names[i] ? file_names[i] : args->pathname;
1882
1883 FT_TRACE3(( "Try rule %d: %s (offset=%d) ...",
1884 i, args2.pathname, offsets[i] ));
1885
1886 error = FT_Stream_New( library, &args2, &stream2 );
1887 if ( is_darwin_vfs && error == FT_Err_Cannot_Open_Stream )
1888 vfs_rfork_has_no_font = TRUE;
1889
1890 if ( error )
1891 {
1892 FT_TRACE3(( "failed\n" ));
1893 continue;
1894 }
1895
1896 error = IsMacResource( library, stream2, offsets[i],
1897 face_index, aface );
1898 FT_Stream_Free( stream2, 0 );
1899
1900 FT_TRACE3(( "%s\n", error ? "failed": "successful" ));
1901
1902 if ( !error )
1903 break;
1904 else if ( is_darwin_vfs )
1905 vfs_rfork_has_no_font = TRUE;
1906 }
1907
1908 for (i = 0; i < FT_RACCESS_N_RULES; i++)
1909 {
1910 if ( file_names[i] )
1911 FT_FREE( file_names[i] );
1912 }
1913
1914 /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */
1915 if ( error )
1916 error = FT_Err_Unknown_File_Format;
1917
1918 return error;
1919
1920 #undef FT_COMPONENT
1921 #define FT_COMPONENT trace_objs
1922
1923 }
1924
1925
1926 /* Check for some macintosh formats without Carbon framework. */
1927 /* Is this a macbinary file? If so look at the resource fork. */
1928 /* Is this a mac dfont file? */
1929 /* Is this an old style resource fork? (in data) */
1930 /* Else call load_face_in_embedded_rfork to try extra rules */
1931 /* (defined in `ftrfork.c'). */
1932 /* */
1933 static FT_Error
1934 load_mac_face( FT_Library library,
1935 FT_Stream stream,
1936 FT_Long face_index,
1937 FT_Face *aface,
1938 const FT_Open_Args *args )
1939 {
1940 FT_Error error;
1941 FT_UNUSED( args );
1942
1943
1944 error = IsMacBinary( library, stream, face_index, aface );
1945 if ( FT_ERROR_BASE( error ) == FT_Err_Unknown_File_Format )
1946 {
1947
1948 #undef FT_COMPONENT
1949 #define FT_COMPONENT trace_raccess
1950
1951 FT_TRACE3(( "Try as dfont: %s ...", args->pathname ));
1952
1953 error = IsMacResource( library, stream, 0, face_index, aface );
1954
1955 FT_TRACE3(( "%s\n", error ? "failed" : "successful" ));
1956
1957 #undef FT_COMPONENT
1958 #define FT_COMPONENT trace_objs
1959
1960 }
1961
1962 if ( ( FT_ERROR_BASE( error ) == FT_Err_Unknown_File_Format ||
1963 FT_ERROR_BASE( error ) == FT_Err_Invalid_Stream_Operation ) &&
1964 ( args->flags & FT_OPEN_PATHNAME ) )
1965 error = load_face_in_embedded_rfork( library, stream,
1966 face_index, aface, args );
1967 return error;
1968 }
1969 #endif
1970
1971 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
1972
1973
1974 /* documentation is in freetype.h */
1975
1976 FT_EXPORT_DEF( FT_Error )
1977 FT_Open_Face( FT_Library library,
1978 const FT_Open_Args* args,
1979 FT_Long face_index,
1980 FT_Face *aface )
1981 {
1982 FT_Error error;
1983 FT_Driver driver;
1984 FT_Memory memory;
1985 FT_Stream stream = NULL;
1986 FT_Face face = NULL;
1987 FT_ListNode node = NULL;
1988 FT_Bool external_stream;
1989 FT_Module* cur;
1990 FT_Module* limit;
1991
1992
1993 /* test for valid `library' delayed to */
1994 /* FT_Stream_New() */
1995
1996 if ( ( !aface && face_index >= 0 ) || !args )
1997 return FT_Err_Invalid_Argument;
1998
1999 external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) &&
2000 args->stream );
2001
2002 /* create input stream */
2003 error = FT_Stream_New( library, args, &stream );
2004 if ( error )
2005 goto Fail3;
2006
2007 memory = library->memory;
2008
2009 /* If the font driver is specified in the `args' structure, use */
2010 /* it. Otherwise, we scan the list of registered drivers. */
2011 if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver )
2012 {
2013 driver = FT_DRIVER( args->driver );
2014
2015 /* not all modules are drivers, so check... */
2016 if ( FT_MODULE_IS_DRIVER( driver ) )
2017 {
2018 FT_Int num_params = 0;
2019 FT_Parameter* params = 0;
2020
2021
2022 if ( args->flags & FT_OPEN_PARAMS )
2023 {
2024 num_params = args->num_params;
2025 params = args->params;
2026 }
2027
2028 error = open_face( driver, stream, face_index,
2029 num_params, params, &face );
2030 if ( !error )
2031 goto Success;
2032 }
2033 else
2034 error = FT_Err_Invalid_Handle;
2035
2036 FT_Stream_Free( stream, external_stream );
2037 goto Fail;
2038 }
2039 else
2040 {
2041 /* check each font driver for an appropriate format */
2042 cur = library->modules;
2043 limit = cur + library->num_modules;
2044
2045
2046 for ( ; cur < limit; cur++ )
2047 {
2048 /* not all modules are font drivers, so check... */
2049 if ( FT_MODULE_IS_DRIVER( cur[0] ) )
2050 {
2051 FT_Int num_params = 0;
2052 FT_Parameter* params = 0;
2053
2054
2055 driver = FT_DRIVER( cur[0] );
2056
2057 if ( args->flags & FT_OPEN_PARAMS )
2058 {
2059 num_params = args->num_params;
2060 params = args->params;
2061 }
2062
2063 error = open_face( driver, stream, face_index,
2064 num_params, params, &face );
2065 if ( !error )
2066 goto Success;
2067
2068 #ifdef FT_CONFIG_OPTION_MAC_FONTS
2069 if ( ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 &&
2070 FT_ERROR_BASE( error ) == FT_Err_Table_Missing )
2071 {
2072 /* TrueType but essential tables are missing */
2073 if ( FT_Stream_Seek( stream, 0 ) )
2074 break;
2075
2076 error = open_face_PS_from_sfnt_stream( library,
2077 stream,
2078 face_index,
2079 num_params,
2080 params,
2081 aface );
2082 if ( !error )
2083 {
2084 FT_Stream_Free( stream, external_stream );
2085 return error;
2086 }
2087 }
2088 #endif
2089
2090 if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format )
2091 goto Fail3;
2092 }
2093 }
2094
2095 Fail3:
2096 /* If we are on the mac, and we get an FT_Err_Invalid_Stream_Operation */
2097 /* it may be because we have an empty data fork, so we need to check */
2098 /* the resource fork. */
2099 if ( FT_ERROR_BASE( error ) != FT_Err_Cannot_Open_Stream &&
2100 FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format &&
2101 FT_ERROR_BASE( error ) != FT_Err_Invalid_Stream_Operation )
2102 goto Fail2;
2103
2104 #if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
2105 error = load_mac_face( library, stream, face_index, aface, args );
2106 if ( !error )
2107 {
2108 /* We don't want to go to Success here. We've already done that. */
2109 /* On the other hand, if we succeeded we still need to close this */
2110 /* stream (we opened a different stream which extracted the */
2111 /* interesting information out of this stream here. That stream */
2112 /* will still be open and the face will point to it). */
2113 FT_Stream_Free( stream, external_stream );
2114 return error;
2115 }
2116
2117 if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format )
2118 goto Fail2;
2119 #endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
2120
2121 /* no driver is able to handle this format */
2122 error = FT_Err_Unknown_File_Format;
2123
2124 Fail2:
2125 FT_Stream_Free( stream, external_stream );
2126 goto Fail;
2127 }
2128
2129 Success:
2130 FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
2131
2132 /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
2133 if ( external_stream )
2134 face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
2135
2136 /* add the face object to its driver's list */
2137 if ( FT_NEW( node ) )
2138 goto Fail;
2139
2140 node->data = face;
2141 /* don't assume driver is the same as face->driver, so use */
2142 /* face->driver instead. */
2143 FT_List_Add( &face->driver->faces_list, node );
2144
2145 /* now allocate a glyph slot object for the face */
2146 FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
2147
2148 if ( face_index >= 0 )
2149 {
2150 error = FT_New_GlyphSlot( face, NULL );
2151 if ( error )
2152 goto Fail;
2153
2154 /* finally, allocate a size object for the face */
2155 {
2156 FT_Size size;
2157
2158
2159 FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
2160
2161 error = FT_New_Size( face, &size );
2162 if ( error )
2163 goto Fail;
2164
2165 face->size = size;
2166 }
2167 }
2168
2169 /* some checks */
2170
2171 if ( FT_IS_SCALABLE( face ) )
2172 {
2173 if ( face->height < 0 )
2174 face->height = (FT_Short)-face->height;
2175
2176 if ( !FT_HAS_VERTICAL( face ) )
2177 face->max_advance_height = (FT_Short)face->height;
2178 }
2179
2180 if ( FT_HAS_FIXED_SIZES( face ) )
2181 {
2182 FT_Int i;
2183
2184
2185 for ( i = 0; i < face->num_fixed_sizes; i++ )
2186 {
2187 FT_Bitmap_Size* bsize = face->available_sizes + i;
2188
2189
2190 if ( bsize->height < 0 )
2191 bsize->height = (FT_Short)-bsize->height;
2192 if ( bsize->x_ppem < 0 )
2193 bsize->x_ppem = (FT_Short)-bsize->x_ppem;
2194 if ( bsize->y_ppem < 0 )
2195 bsize->y_ppem = -bsize->y_ppem;
2196 }
2197 }
2198
2199 /* initialize internal face data */
2200 {
2201 FT_Face_Internal internal = face->internal;
2202
2203
2204 internal->transform_matrix.xx = 0x10000L;
2205 internal->transform_matrix.xy = 0;
2206 internal->transform_matrix.yx = 0;
2207 internal->transform_matrix.yy = 0x10000L;
2208
2209 internal->transform_delta.x = 0;
2210 internal->transform_delta.y = 0;
2211
2212 internal->refcount = 1;
2213 }
2214
2215 if ( aface )
2216 *aface = face;
2217 else
2218 FT_Done_Face( face );
2219
2220 goto Exit;
2221
2222 Fail:
2223 FT_Done_Face( face );
2224
2225 Exit:
2226 FT_TRACE4(( "FT_Open_Face: Return %d\n", error ));
2227
2228 return error;
2229 }
2230
2231
2232 /* documentation is in freetype.h */
2233
2234 FT_EXPORT_DEF( FT_Error )
2235 FT_Attach_File( FT_Face face,
2236 const char* filepathname )
2237 {
2238 FT_Open_Args open;
2239
2240
2241 /* test for valid `face' delayed to FT_Attach_Stream() */
2242
2243 if ( !filepathname )
2244 return FT_Err_Invalid_Argument;
2245
2246 open.stream = NULL;
2247 open.flags = FT_OPEN_PATHNAME;
2248 open.pathname = (char*)filepathname;
2249
2250 return FT_Attach_Stream( face, &open );
2251 }
2252
2253
2254 /* documentation is in freetype.h */
2255
2256 FT_EXPORT_DEF( FT_Error )
2257 FT_Attach_Stream( FT_Face face,
2258 FT_Open_Args* parameters )
2259 {
2260 FT_Stream stream;
2261 FT_Error error;
2262 FT_Driver driver;
2263
2264 FT_Driver_Class clazz;
2265
2266
2267 /* test for valid `parameters' delayed to FT_Stream_New() */
2268
2269 if ( !face )
2270 return FT_Err_Invalid_Face_Handle;
2271
2272 driver = face->driver;
2273 if ( !driver )
2274 return FT_Err_Invalid_Driver_Handle;
2275
2276 error = FT_Stream_New( driver->root.library, parameters, &stream );
2277 if ( error )
2278 goto Exit;
2279
2280 /* we implement FT_Attach_Stream in each driver through the */
2281 /* `attach_file' interface */
2282
2283 error = FT_Err_Unimplemented_Feature;
2284 clazz = driver->clazz;
2285 if ( clazz->attach_file )
2286 error = clazz->attach_file( face, stream );
2287
2288 /* close the attached stream */
2289 FT_Stream_Free( stream,
2290 (FT_Bool)( parameters->stream &&
2291 ( parameters->flags & FT_OPEN_STREAM ) ) );
2292
2293 Exit:
2294 return error;
2295 }
2296
2297
2298 /* documentation is in freetype.h */
2299
2300 FT_EXPORT_DEF( FT_Error )
2301 FT_Reference_Face( FT_Face face )
2302 {
2303 face->internal->refcount++;
2304
2305 return FT_Err_Ok;
2306 }
2307
2308
2309 /* documentation is in freetype.h */
2310
2311 FT_EXPORT_DEF( FT_Error )
2312 FT_Done_Face( FT_Face face )
2313 {
2314 FT_Error error;
2315 FT_Driver driver;
2316 FT_Memory memory;
2317 FT_ListNode node;
2318
2319
2320 error = FT_Err_Invalid_Face_Handle;
2321 if ( face && face->driver )
2322 {
2323 face->internal->refcount--;
2324 if ( face->internal->refcount > 0 )
2325 error = FT_Err_Ok;
2326 else
2327 {
2328 driver = face->driver;
2329 memory = driver->root.memory;
2330
2331 /* find face in driver's list */
2332 node = FT_List_Find( &driver->faces_list, face );
2333 if ( node )
2334 {
2335 /* remove face object from the driver's list */
2336 FT_List_Remove( &driver->faces_list, node );
2337 FT_FREE( node );
2338
2339 /* now destroy the object proper */
2340 destroy_face( memory, face, driver );
2341 error = FT_Err_Ok;
2342 }
2343 }
2344 }
2345
2346 return error;
2347 }
2348
2349
2350 /* documentation is in ftobjs.h */
2351
2352 FT_EXPORT_DEF( FT_Error )
2353 FT_New_Size( FT_Face face,
2354 FT_Size *asize )
2355 {
2356 FT_Error error;
2357 FT_Memory memory;
2358 FT_Driver driver;
2359 FT_Driver_Class clazz;
2360
2361 FT_Size size = 0;
2362 FT_ListNode node = 0;
2363
2364
2365 if ( !face )
2366 return FT_Err_Invalid_Face_Handle;
2367
2368 if ( !asize )
2369 return FT_Err_Invalid_Size_Handle;
2370
2371 if ( !face->driver )
2372 return FT_Err_Invalid_Driver_Handle;
2373
2374 *asize = 0;
2375
2376 driver = face->driver;
2377 clazz = driver->clazz;
2378 memory = face->memory;
2379
2380 /* Allocate new size object and perform basic initialisation */
2381 if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) )
2382 goto Exit;
2383
2384 size->face = face;
2385
2386 /* for now, do not use any internal fields in size objects */
2387 size->internal = 0;
2388
2389 if ( clazz->init_size )
2390 error = clazz->init_size( size );
2391
2392 /* in case of success, add to the face's list */
2393 if ( !error )
2394 {
2395 *asize = size;
2396 node->data = size;
2397 FT_List_Add( &face->sizes_list, node );
2398 }
2399
2400 Exit:
2401 if ( error )
2402 {
2403 FT_FREE( node );
2404 FT_FREE( size );
2405 }
2406
2407 return error;
2408 }
2409
2410
2411 /* documentation is in ftobjs.h */
2412
2413 FT_EXPORT_DEF( FT_Error )
2414 FT_Done_Size( FT_Size size )
2415 {
2416 FT_Error error;
2417 FT_Driver driver;
2418 FT_Memory memory;
2419 FT_Face face;
2420 FT_ListNode node;
2421
2422
2423 if ( !size )
2424 return FT_Err_Invalid_Size_Handle;
2425
2426 face = size->face;
2427 if ( !face )
2428 return FT_Err_Invalid_Face_Handle;
2429
2430 driver = face->driver;
2431 if ( !driver )
2432 return FT_Err_Invalid_Driver_Handle;
2433
2434 memory = driver->root.memory;
2435
2436 error = FT_Err_Ok;
2437 node = FT_List_Find( &face->sizes_list, size );
2438 if ( node )
2439 {
2440 FT_List_Remove( &face->sizes_list, node );
2441 FT_FREE( node );
2442
2443 if ( face->size == size )
2444 {
2445 face->size = 0;
2446 if ( face->sizes_list.head )
2447 face->size = (FT_Size)(face->sizes_list.head->data);
2448 }
2449
2450 destroy_size( memory, size, driver );
2451 }
2452 else
2453 error = FT_Err_Invalid_Size_Handle;
2454
2455 return error;
2456 }
2457
2458
2459 /* documentation is in ftobjs.h */
2460
2461 FT_BASE_DEF( FT_Error )
2462 FT_Match_Size( FT_Face face,
2463 FT_Size_Request req,
2464 FT_Bool ignore_width,
2465 FT_ULong* size_index )
2466 {
2467 FT_Int i;
2468 FT_Long w, h;
2469
2470
2471 if ( !FT_HAS_FIXED_SIZES( face ) )
2472 return FT_Err_Invalid_Face_Handle;
2473
2474 /* FT_Bitmap_Size doesn't provide enough info... */
2475 if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
2476 return FT_Err_Unimplemented_Feature;
2477
2478 w = FT_REQUEST_WIDTH ( req );
2479 h = FT_REQUEST_HEIGHT( req );
2480
2481 if ( req->width && !req->height )
2482 h = w;
2483 else if ( !req->width && req->height )
2484 w = h;
2485
2486 w = FT_PIX_ROUND( w );
2487 h = FT_PIX_ROUND( h );
2488
2489 for ( i = 0; i < face->num_fixed_sizes; i++ )
2490 {
2491 FT_Bitmap_Size* bsize = face->available_sizes + i;
2492
2493
2494 if ( h != FT_PIX_ROUND( bsize->y_ppem ) )
2495 continue;
2496
2497 if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width )
2498 {
2499 if ( size_index )
2500 *size_index = (FT_ULong)i;
2501
2502 return FT_Err_Ok;
2503 }
2504 }
2505
2506 return FT_Err_Invalid_Pixel_Size;
2507 }
2508
2509
2510 /* documentation is in ftobjs.h */
2511
2512 FT_BASE_DEF( void )
2513 ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics,
2514 FT_Pos advance )
2515 {
2516 FT_Pos height = metrics->height;
2517
2518
2519 /* compensate for glyph with bbox above/below the baseline */
2520 if ( metrics->horiBearingY < 0 )
2521 {
2522 if ( height < metrics->horiBearingY )
2523 height = metrics->horiBearingY;
2524 }
2525 else if ( metrics->horiBearingY > 0 )
2526 height -= metrics->horiBearingY;
2527
2528 /* the factor 1.2 is a heuristical value */
2529 if ( !advance )
2530 advance = height * 12 / 10;
2531
2532 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
2533 metrics->vertBearingY = ( advance - height ) / 2;
2534 metrics->vertAdvance = advance;
2535 }
2536
2537
2538 static void
2539 ft_recompute_scaled_metrics( FT_Face face,
2540 FT_Size_Metrics* metrics )
2541 {
2542 /* Compute root ascender, descender, test height, and max_advance */
2543
2544 #ifdef GRID_FIT_METRICS
2545 metrics->ascender = FT_PIX_CEIL( FT_MulFix( face->ascender,
2546 metrics->y_scale ) );
2547
2548 metrics->descender = FT_PIX_FLOOR( FT_MulFix( face->descender,
2549 metrics->y_scale ) );
2550
2551 metrics->height = FT_PIX_ROUND( FT_MulFix( face->height,
2552 metrics->y_scale ) );
2553
2554 metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width,
2555 metrics->x_scale ) );
2556 #else /* !GRID_FIT_METRICS */
2557 metrics->ascender = FT_MulFix( face->ascender,
2558 metrics->y_scale );
2559
2560 metrics->descender = FT_MulFix( face->descender,
2561 metrics->y_scale );
2562
2563 metrics->height = FT_MulFix( face->height,
2564 metrics->y_scale );
2565
2566 metrics->max_advance = FT_MulFix( face->max_advance_width,
2567 metrics->x_scale );
2568 #endif /* !GRID_FIT_METRICS */
2569 }
2570
2571
2572 FT_BASE_DEF( void )
2573 FT_Select_Metrics( FT_Face face,
2574 FT_ULong strike_index )
2575 {
2576 FT_Size_Metrics* metrics;
2577 FT_Bitmap_Size* bsize;
2578
2579
2580 metrics = &face->size->metrics;
2581 bsize = face->available_sizes + strike_index;
2582
2583 metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 );
2584 metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 );
2585
2586 if ( FT_IS_SCALABLE( face ) )
2587 {
2588 metrics->x_scale = FT_DivFix( bsize->x_ppem,
2589 face->units_per_EM );
2590 metrics->y_scale = FT_DivFix( bsize->y_ppem,
2591 face->units_per_EM );
2592
2593 ft_recompute_scaled_metrics( face, metrics );
2594 }
2595 else
2596 {
2597 metrics->x_scale = 1L << 16;
2598 metrics->y_scale = 1L << 16;
2599 metrics->ascender = bsize->y_ppem;
2600 metrics->descender = 0;
2601 metrics->height = bsize->height << 6;
2602 metrics->max_advance = bsize->x_ppem;
2603 }
2604 }
2605
2606
2607 FT_BASE_DEF( void )
2608 FT_Request_Metrics( FT_Face face,
2609 FT_Size_Request req )
2610 {
2611 FT_Size_Metrics* metrics;
2612
2613
2614 metrics = &face->size->metrics;
2615
2616 if ( FT_IS_SCALABLE( face ) )
2617 {
2618 FT_Long w = 0, h = 0, scaled_w = 0, scaled_h = 0;
2619
2620
2621 switch ( req->type )
2622 {
2623 case FT_SIZE_REQUEST_TYPE_NOMINAL:
2624 w = h = face->units_per_EM;
2625 break;
2626
2627 case FT_SIZE_REQUEST_TYPE_REAL_DIM:
2628 w = h = face->ascender - face->descender;
2629 break;
2630
2631 case FT_SIZE_REQUEST_TYPE_BBOX:
2632 w = face->bbox.xMax - face->bbox.xMin;
2633 h = face->bbox.yMax - face->bbox.yMin;
2634 break;
2635
2636 case FT_SIZE_REQUEST_TYPE_CELL:
2637 w = face->max_advance_width;
2638 h = face->ascender - face->descender;
2639 break;
2640
2641 case FT_SIZE_REQUEST_TYPE_SCALES:
2642 metrics->x_scale = (FT_Fixed)req->width;
2643 metrics->y_scale = (FT_Fixed)req->height;
2644 if ( !metrics->x_scale )
2645 metrics->x_scale = metrics->y_scale;
2646 else if ( !metrics->y_scale )
2647 metrics->y_scale = metrics->x_scale;
2648 goto Calculate_Ppem;
2649
2650 case FT_SIZE_REQUEST_TYPE_MAX:
2651 break;
2652 }
2653
2654 /* to be on the safe side */
2655 if ( w < 0 )
2656 w = -w;
2657
2658 if ( h < 0 )
2659 h = -h;
2660
2661 scaled_w = FT_REQUEST_WIDTH ( req );
2662 scaled_h = FT_REQUEST_HEIGHT( req );
2663
2664 /* determine scales */
2665 if ( req->width )
2666 {
2667 metrics->x_scale = FT_DivFix( scaled_w, w );
2668
2669 if ( req->height )
2670 {
2671 metrics->y_scale = FT_DivFix( scaled_h, h );
2672
2673 if ( req->type == FT_SIZE_REQUEST_TYPE_CELL )
2674 {
2675 if ( metrics->y_scale > metrics->x_scale )
2676 metrics->y_scale = metrics->x_scale;
2677 else
2678 metrics->x_scale = metrics->y_scale;
2679 }
2680 }
2681 else
2682 {
2683 metrics->y_scale = metrics->x_scale;
2684 scaled_h = FT_MulDiv( scaled_w, h, w );
2685 }
2686 }
2687 else
2688 {
2689 metrics->x_scale = metrics->y_scale = FT_DivFix( scaled_h, h );
2690 scaled_w = FT_MulDiv( scaled_h, w, h );
2691 }
2692
2693 Calculate_Ppem:
2694 /* calculate the ppems */
2695 if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
2696 {
2697 scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale );
2698 scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale );
2699 }
2700
2701 metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 );
2702 metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 );
2703
2704 ft_recompute_scaled_metrics( face, metrics );
2705 }
2706 else
2707 {
2708 FT_ZERO( metrics );
2709 metrics->x_scale = 1L << 16;
2710 metrics->y_scale = 1L << 16;
2711 }
2712 }
2713
2714
2715 /* documentation is in freetype.h */
2716
2717 FT_EXPORT_DEF( FT_Error )
2718 FT_Select_Size( FT_Face face,
2719 FT_Int strike_index )
2720 {
2721 FT_Driver_Class clazz;
2722
2723
2724 if ( !face || !FT_HAS_FIXED_SIZES( face ) )
2725 return FT_Err_Invalid_Face_Handle;
2726
2727 if ( strike_index < 0 || strike_index >= face->num_fixed_sizes )
2728 return FT_Err_Invalid_Argument;
2729
2730 clazz = face->driver->clazz;
2731
2732 if ( clazz->select_size )
2733 return clazz->select_size( face->size, (FT_ULong)strike_index );
2734
2735 FT_Select_Metrics( face, (FT_ULong)strike_index );
2736
2737 return FT_Err_Ok;
2738 }
2739
2740
2741 /* documentation is in freetype.h */
2742
2743 FT_EXPORT_DEF( FT_Error )
2744 FT_Request_Size( FT_Face face,
2745 FT_Size_Request req )
2746 {
2747 FT_Driver_Class clazz;
2748 FT_ULong strike_index;
2749
2750
2751 if ( !face )
2752 return FT_Err_Invalid_Face_Handle;
2753
2754 if ( !req || req->width < 0 || req->height < 0 ||
2755 req->type >= FT_SIZE_REQUEST_TYPE_MAX )
2756 return FT_Err_Invalid_Argument;
2757
2758 clazz = face->driver->clazz;
2759
2760 if ( clazz->request_size )
2761 return clazz->request_size( face->size, req );
2762
2763 /*
2764 * The reason that a driver doesn't have `request_size' defined is
2765 * either that the scaling here suffices or that the supported formats
2766 * are bitmap-only and size matching is not implemented.
2767 *
2768 * In the latter case, a simple size matching is done.
2769 */
2770 if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) )
2771 {
2772 FT_Error error;
2773
2774
2775 error = FT_Match_Size( face, req, 0, &strike_index );
2776 if ( error )
2777 return error;
2778
2779 FT_TRACE3(( "FT_Request_Size: bitmap strike %lu matched\n",
2780 strike_index ));
2781
2782 return FT_Select_Size( face, (FT_Int)strike_index );
2783 }
2784
2785 FT_Request_Metrics( face, req );
2786
2787 return FT_Err_Ok;
2788 }
2789
2790
2791 /* documentation is in freetype.h */
2792
2793 FT_EXPORT_DEF( FT_Error )
2794 FT_Set_Char_Size( FT_Face face,
2795 FT_F26Dot6 char_width,
2796 FT_F26Dot6 char_height,
2797 FT_UInt horz_resolution,
2798 FT_UInt vert_resolution )
2799 {
2800 FT_Size_RequestRec req;
2801
2802
2803 if ( !char_width )
2804 char_width = char_height;
2805 else if ( !char_height )
2806 char_height = char_width;
2807
2808 if ( !horz_resolution )
2809 horz_resolution = vert_resolution;
2810 else if ( !vert_resolution )
2811 vert_resolution = horz_resolution;
2812
2813 if ( char_width < 1 * 64 )
2814 char_width = 1 * 64;
2815 if ( char_height < 1 * 64 )
2816 char_height = 1 * 64;
2817
2818 if ( !horz_resolution )
2819 horz_resolution = vert_resolution = 72;
2820
2821 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
2822 req.width = char_width;
2823 req.height = char_height;
2824 req.horiResolution = horz_resolution;
2825 req.vertResolution = vert_resolution;
2826
2827 return FT_Request_Size( face, &req );
2828 }
2829
2830
2831 /* documentation is in freetype.h */
2832
2833 FT_EXPORT_DEF( FT_Error )
2834 FT_Set_Pixel_Sizes( FT_Face face,
2835 FT_UInt pixel_width,
2836 FT_UInt pixel_height )
2837 {
2838 FT_Size_RequestRec req;
2839
2840
2841 if ( pixel_width == 0 )
2842 pixel_width = pixel_height;
2843 else if ( pixel_height == 0 )
2844 pixel_height = pixel_width;
2845
2846 if ( pixel_width < 1 )
2847 pixel_width = 1;
2848 if ( pixel_height < 1 )
2849 pixel_height = 1;
2850
2851 /* use `>=' to avoid potential compiler warning on 16bit platforms */
2852 if ( pixel_width >= 0xFFFFU )
2853 pixel_width = 0xFFFFU;
2854 if ( pixel_height >= 0xFFFFU )
2855 pixel_height = 0xFFFFU;
2856
2857 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
2858 req.width = pixel_width << 6;
2859 req.height = pixel_height << 6;
2860 req.horiResolution = 0;
2861 req.vertResolution = 0;
2862
2863 return FT_Request_Size( face, &req );
2864 }
2865
2866
2867 /* documentation is in freetype.h */
2868
2869 FT_EXPORT_DEF( FT_Error )
2870 FT_Get_Kerning( FT_Face face,
2871 FT_UInt left_glyph,
2872 FT_UInt right_glyph,
2873 FT_UInt kern_mode,
2874 FT_Vector *akerning )
2875 {
2876 FT_Error error = FT_Err_Ok;
2877 FT_Driver driver;
2878
2879
2880 if ( !face )
2881 return FT_Err_Invalid_Face_Handle;
2882
2883 if ( !akerning )
2884 return FT_Err_Invalid_Argument;
2885
2886 driver = face->driver;
2887
2888 akerning->x = 0;
2889 akerning->y = 0;
2890
2891 if ( driver->clazz->get_kerning )
2892 {
2893 error = driver->clazz->get_kerning( face,
2894 left_glyph,
2895 right_glyph,
2896 akerning );
2897 if ( !error )
2898 {
2899 if ( kern_mode != FT_KERNING_UNSCALED )
2900 {
2901 akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale );
2902 akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale );
2903
2904 if ( kern_mode != FT_KERNING_UNFITTED )
2905 {
2906 /* we scale down kerning values for small ppem values */
2907 /* to avoid that rounding makes them too big. */
2908 /* `25' has been determined heuristically. */
2909 if ( face->size->metrics.x_ppem < 25 )
2910 akerning->x = FT_MulDiv( akerning->x,
2911 face->size->metrics.x_ppem, 25 );
2912 if ( face->size->metrics.y_ppem < 25 )
2913 akerning->y = FT_MulDiv( akerning->y,
2914 face->size->metrics.y_ppem, 25 );
2915
2916 akerning->x = FT_PIX_ROUND( akerning->x );
2917 akerning->y = FT_PIX_ROUND( akerning->y );
2918 }
2919 }
2920 }
2921 }
2922
2923 return error;
2924 }
2925
2926
2927 /* documentation is in freetype.h */
2928
2929 FT_EXPORT_DEF( FT_Error )
2930 FT_Get_Track_Kerning( FT_Face face,
2931 FT_Fixed point_size,
2932 FT_Int degree,
2933 FT_Fixed* akerning )
2934 {
2935 FT_Service_Kerning service;
2936 FT_Error error = FT_Err_Ok;
2937
2938
2939 if ( !face )
2940 return FT_Err_Invalid_Face_Handle;
2941
2942 if ( !akerning )
2943 return FT_Err_Invalid_Argument;
2944
2945 FT_FACE_FIND_SERVICE( face, service, KERNING );
2946 if ( !service )
2947 return FT_Err_Unimplemented_Feature;
2948
2949 error = service->get_track( face,
2950 point_size,
2951 degree,
2952 akerning );
2953
2954 return error;
2955 }
2956
2957
2958 /* documentation is in freetype.h */
2959
2960 FT_EXPORT_DEF( FT_Error )
2961 FT_Select_Charmap( FT_Face face,
2962 FT_Encoding encoding )
2963 {
2964 FT_CharMap* cur;
2965 FT_CharMap* limit;
2966
2967
2968 if ( !face )
2969 return FT_Err_Invalid_Face_Handle;
2970
2971 if ( encoding == FT_ENCODING_NONE )
2972 return FT_Err_Invalid_Argument;
2973
2974 /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */
2975 /* charmap available, i.e., one with UCS-4 characters, if possible. */
2976 /* */
2977 /* This is done by find_unicode_charmap() above, to share code. */
2978 if ( encoding == FT_ENCODING_UNICODE )
2979 return find_unicode_charmap( face );
2980
2981 cur = face->charmaps;
2982 if ( !cur )
2983 return FT_Err_Invalid_CharMap_Handle;
2984
2985 limit = cur + face->num_charmaps;
2986
2987 for ( ; cur < limit; cur++ )
2988 {
2989 if ( cur[0]->encoding == encoding )
2990 {
2991 #ifdef FT_MAX_CHARMAP_CACHEABLE
2992 if ( cur - face->charmaps > FT_MAX_CHARMAP_CACHEABLE )
2993 {
2994 FT_ERROR(( "FT_Select_Charmap: requested charmap is found (%d), "
2995 "but in too late position to cache\n",
2996 cur - face->charmaps ));
2997 continue;
2998 }
2999 #endif
3000 face->charmap = cur[0];
3001 return 0;
3002 }
3003 }
3004
3005 return FT_Err_Invalid_Argument;
3006 }
3007
3008
3009 /* documentation is in freetype.h */
3010
3011 FT_EXPORT_DEF( FT_Error )
3012 FT_Set_Charmap( FT_Face face,
3013 FT_CharMap charmap )
3014 {
3015 FT_CharMap* cur;
3016 FT_CharMap* limit;
3017
3018
3019 if ( !face )
3020 return FT_Err_Invalid_Face_Handle;
3021
3022 cur = face->charmaps;
3023 if ( !cur )
3024 return FT_Err_Invalid_CharMap_Handle;
3025 if ( FT_Get_CMap_Format( charmap ) == 14 )
3026 return FT_Err_Invalid_Argument;
3027
3028 limit = cur + face->num_charmaps;
3029
3030 for ( ; cur < limit; cur++ )
3031 {
3032 if ( cur[0] == charmap )
3033 {
3034 #ifdef FT_MAX_CHARMAP_CACHEABLE
3035 if ( cur - face->charmaps > FT_MAX_CHARMAP_CACHEABLE )
3036 {
3037 FT_ERROR(( "FT_Set_Charmap: requested charmap is found (%d), "
3038 "but in too late position to cache\n",
3039 cur - face->charmaps ));
3040 continue;
3041 }
3042 #endif
3043 face->charmap = cur[0];
3044 return 0;
3045 }
3046 }
3047 return FT_Err_Invalid_Argument;
3048 }
3049
3050
3051 /* documentation is in freetype.h */
3052
3053 FT_EXPORT_DEF( FT_Int )
3054 FT_Get_Charmap_Index( FT_CharMap charmap )
3055 {
3056 FT_Int i;
3057
3058
3059 if ( !charmap || !charmap->face )
3060 return -1;
3061
3062 for ( i = 0; i < charmap->face->num_charmaps; i++ )
3063 if ( charmap->face->charmaps[i] == charmap )
3064 break;
3065
3066 FT_ASSERT( i < charmap->face->num_charmaps );
3067
3068 #ifdef FT_MAX_CHARMAP_CACHEABLE
3069 if ( i > FT_MAX_CHARMAP_CACHEABLE )
3070 {
3071 FT_ERROR(( "FT_Get_Charmap_Index: requested charmap is found (%d), "
3072 "but in too late position to cache\n",
3073 i ));
3074 return -i;
3075 }
3076 #endif
3077 return i;
3078 }
3079
3080
3081 static void
3082 ft_cmap_done_internal( FT_CMap cmap )
3083 {
3084 FT_CMap_Class clazz = cmap->clazz;
3085 FT_Face face = cmap->charmap.face;
3086 FT_Memory memory = FT_FACE_MEMORY(face);
3087
3088
3089 if ( clazz->done )
3090 clazz->done( cmap );
3091
3092 FT_FREE( cmap );
3093 }
3094
3095
3096 FT_BASE_DEF( void )
3097 FT_CMap_Done( FT_CMap cmap )
3098 {
3099 if ( cmap )
3100 {
3101 FT_Face face = cmap->charmap.face;
3102 FT_Memory memory = FT_FACE_MEMORY( face );
3103 FT_Error error;
3104 FT_Int i, j;
3105
3106
3107 for ( i = 0; i < face->num_charmaps; i++ )
3108 {
3109 if ( (FT_CMap)face->charmaps[i] == cmap )
3110 {
3111 FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1];
3112
3113
3114 if ( FT_RENEW_ARRAY( face->charmaps,
3115 face->num_charmaps,
3116 face->num_charmaps - 1 ) )
3117 return;
3118
3119 /* remove it from our list of charmaps */
3120 for ( j = i + 1; j < face->num_charmaps; j++ )
3121 {
3122 if ( j == face->num_charmaps - 1 )
3123 face->charmaps[j - 1] = last_charmap;
3124 else
3125 face->charmaps[j - 1] = face->charmaps[j];
3126 }
3127
3128 face->num_charmaps--;
3129
3130 if ( (FT_CMap)face->charmap == cmap )
3131 face->charmap = NULL;
3132
3133 ft_cmap_done_internal( cmap );
3134
3135 break;
3136 }
3137 }
3138 }
3139 }
3140
3141
3142 FT_BASE_DEF( FT_Error )
3143 FT_CMap_New( FT_CMap_Class clazz,
3144 FT_Pointer init_data,
3145 FT_CharMap charmap,
3146 FT_CMap *acmap )
3147 {
3148 FT_Error error = FT_Err_Ok;
3149 FT_Face face;
3150 FT_Memory memory;
3151 FT_CMap cmap;
3152
3153
3154 if ( clazz == NULL || charmap == NULL || charmap->face == NULL )
3155 return FT_Err_Invalid_Argument;
3156
3157 face = charmap->face;
3158 memory = FT_FACE_MEMORY( face );
3159
3160 if ( !FT_ALLOC( cmap, clazz->size ) )
3161 {
3162 cmap->charmap = *charmap;
3163 cmap->clazz = clazz;
3164
3165 if ( clazz->init )
3166 {
3167 error = clazz->init( cmap, init_data );
3168 if ( error )
3169 goto Fail;
3170 }
3171
3172 /* add it to our list of charmaps */
3173 if ( FT_RENEW_ARRAY( face->charmaps,
3174 face->num_charmaps,
3175 face->num_charmaps + 1 ) )
3176 goto Fail;
3177
3178 face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap;
3179 }
3180
3181 Exit:
3182 if ( acmap )
3183 *acmap = cmap;
3184
3185 return error;
3186
3187 Fail:
3188 ft_cmap_done_internal( cmap );
3189 cmap = NULL;
3190 goto Exit;
3191 }
3192
3193
3194 /* documentation is in freetype.h */
3195
3196 FT_EXPORT_DEF( FT_UInt )
3197 FT_Get_Char_Index( FT_Face face,
3198 FT_ULong charcode )
3199 {
3200 FT_UInt result = 0;
3201
3202
3203 if ( face && face->charmap )
3204 {
3205 FT_CMap cmap = FT_CMAP( face->charmap );
3206
3207
3208 if ( charcode > 0xFFFFFFFFUL )
3209 {
3210 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3211 FT_TRACE1(( " 0x%x is truncated\n", charcode ));
3212 }
3213 result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode );
3214 }
3215 return result;
3216 }
3217
3218
3219 /* documentation is in freetype.h */
3220
3221 FT_EXPORT_DEF( FT_ULong )
3222 FT_Get_First_Char( FT_Face face,
3223 FT_UInt *agindex )
3224 {
3225 FT_ULong result = 0;
3226 FT_UInt gindex = 0;
3227
3228
3229 if ( face && face->charmap && face->num_glyphs )
3230 {
3231 gindex = FT_Get_Char_Index( face, 0 );
3232 if ( gindex == 0 || gindex >= (FT_UInt)face->num_glyphs )
3233 result = FT_Get_Next_Char( face, 0, &gindex );
3234 }
3235
3236 if ( agindex )
3237 *agindex = gindex;
3238
3239 return result;
3240 }
3241
3242
3243 /* documentation is in freetype.h */
3244
3245 FT_EXPORT_DEF( FT_ULong )
3246 FT_Get_Next_Char( FT_Face face,
3247 FT_ULong charcode,
3248 FT_UInt *agindex )
3249 {
3250 FT_ULong result = 0;
3251 FT_UInt gindex = 0;
3252
3253
3254 if ( face && face->charmap && face->num_glyphs )
3255 {
3256 FT_UInt32 code = (FT_UInt32)charcode;
3257 FT_CMap cmap = FT_CMAP( face->charmap );
3258
3259
3260 do {
3261 gindex = cmap->clazz->char_next( cmap, &code );
3262 } while ( gindex >= (FT_UInt)face->num_glyphs );
3263
3264 result = ( gindex == 0 ) ? 0 : code;
3265 }
3266
3267 if ( agindex )
3268 *agindex = gindex;
3269
3270 return result;
3271 }
3272
3273
3274 /* documentation is in freetype.h */
3275
3276 FT_EXPORT_DEF( FT_UInt )
3277 FT_Face_GetCharVariantIndex( FT_Face face,
3278 FT_ULong charcode,
3279 FT_ULong variantSelector )
3280 {
3281 FT_UInt result = 0;
3282
3283
3284 if ( face && face->charmap &&
3285 face->charmap->encoding == FT_ENCODING_UNICODE )
3286 {
3287 FT_CharMap charmap = find_variant_selector_charmap( face );
3288 FT_CMap ucmap = FT_CMAP( face->charmap );
3289
3290
3291 if ( charmap != NULL )
3292 {
3293 FT_CMap vcmap = FT_CMAP( charmap );
3294
3295
3296 if ( charcode > 0xFFFFFFFFUL )
3297 {
3298 FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
3299 FT_TRACE1(( " 0x%x is truncated\n", charcode ));
3300 }
3301 if ( variantSelector > 0xFFFFFFFFUL )
3302 {
3303 FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
3304 FT_TRACE1(( " 0x%x is truncated\n", variantSelector ));
3305 }
3306
3307 result = vcmap->clazz->char_var_index( vcmap, ucmap,
3308 (FT_UInt32)charcode,
3309 (FT_UInt32)variantSelector );
3310 }
3311 }
3312
3313 return result;
3314 }
3315
3316
3317 /* documentation is in freetype.h */
3318
3319 FT_EXPORT_DEF( FT_Int )
3320 FT_Face_GetCharVariantIsDefault( FT_Face face,
3321 FT_ULong charcode,
3322 FT_ULong variantSelector )
3323 {
3324 FT_Int result = -1;
3325
3326
3327 if ( face )
3328 {
3329 FT_CharMap charmap = find_variant_selector_charmap( face );
3330
3331
3332 if ( charmap != NULL )
3333 {
3334 FT_CMap vcmap = FT_CMAP( charmap );
3335
3336