tizen 2.3.1 release
[framework/graphics/freetype.git] / src / pfr / pfrobjs.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  pfrobjs.c                                                              */
4 /*                                                                         */
5 /*    FreeType PFR object methods (body).                                  */
6 /*                                                                         */
7 /*  Copyright 2002-2008, 2010-2011, 2013, 2014 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 "pfrobjs.h"
20 #include "pfrload.h"
21 #include "pfrgload.h"
22 #include "pfrcmap.h"
23 #include "pfrsbit.h"
24 #include FT_OUTLINE_H
25 #include FT_INTERNAL_DEBUG_H
26 #include FT_INTERNAL_CALC_H
27 #include FT_TRUETYPE_IDS_H
28
29 #include "pfrerror.h"
30
31 #undef  FT_COMPONENT
32 #define FT_COMPONENT  trace_pfr
33
34
35   /*************************************************************************/
36   /*************************************************************************/
37   /*****                                                               *****/
38   /*****                     FACE OBJECT METHODS                       *****/
39   /*****                                                               *****/
40   /*************************************************************************/
41   /*************************************************************************/
42
43   FT_LOCAL_DEF( void )
44   pfr_face_done( FT_Face  pfrface )     /* PFR_Face */
45   {
46     PFR_Face   face = (PFR_Face)pfrface;
47     FT_Memory  memory;
48
49
50     if ( !face )
51       return;
52
53     memory = pfrface->driver->root.memory;
54
55     /* we don't want dangling pointers */
56     pfrface->family_name = NULL;
57     pfrface->style_name  = NULL;
58
59     /* finalize the physical font record */
60     pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) );
61
62     /* no need to finalize the logical font or the header */
63     FT_FREE( pfrface->available_sizes );
64   }
65
66
67   FT_LOCAL_DEF( FT_Error )
68   pfr_face_init( FT_Stream      stream,
69                  FT_Face        pfrface,
70                  FT_Int         face_index,
71                  FT_Int         num_params,
72                  FT_Parameter*  params )
73   {
74     PFR_Face  face = (PFR_Face)pfrface;
75     FT_Error  error;
76
77     FT_UNUSED( num_params );
78     FT_UNUSED( params );
79
80
81     FT_TRACE2(( "PFR driver\n" ));
82
83     /* load the header and check it */
84     error = pfr_header_load( &face->header, stream );
85     if ( error )
86       goto Exit;
87
88     if ( !pfr_header_check( &face->header ) )
89     {
90       FT_TRACE2(( "  not a PFR font\n" ));
91       error = FT_THROW( Unknown_File_Format );
92       goto Exit;
93     }
94
95     /* check face index */
96     {
97       FT_UInt  num_faces;
98
99
100       error = pfr_log_font_count( stream,
101                                   face->header.log_dir_offset,
102                                   &num_faces );
103       if ( error )
104         goto Exit;
105
106       pfrface->num_faces = num_faces;
107     }
108
109     if ( face_index < 0 )
110       goto Exit;
111
112     if ( face_index >= pfrface->num_faces )
113     {
114       FT_ERROR(( "pfr_face_init: invalid face index\n" ));
115       error = FT_THROW( Invalid_Argument );
116       goto Exit;
117     }
118
119     /* load the face */
120     error = pfr_log_font_load(
121                &face->log_font, stream, face_index,
122                face->header.log_dir_offset,
123                FT_BOOL( face->header.phy_font_max_size_high != 0 ) );
124     if ( error )
125       goto Exit;
126
127     /* now load the physical font descriptor */
128     error = pfr_phy_font_load( &face->phy_font, stream,
129                                face->log_font.phys_offset,
130                                face->log_font.phys_size );
131     if ( error )
132       goto Exit;
133
134     /* now set up all root face fields */
135     {
136       PFR_PhyFont  phy_font = &face->phy_font;
137
138
139       pfrface->face_index = face_index;
140       pfrface->num_glyphs = phy_font->num_chars + 1;
141
142       pfrface->face_flags |= FT_FACE_FLAG_SCALABLE;
143
144       /* if all characters point to the same gps_offset 0, we */
145       /* assume that the font only contains bitmaps           */
146       {
147         FT_UInt  nn;
148
149
150         for ( nn = 0; nn < phy_font->num_chars; nn++ )
151           if ( phy_font->chars[nn].gps_offset != 0 )
152             break;
153
154         if ( nn == phy_font->num_chars )
155         {
156           if ( phy_font->num_strikes > 0 )
157             pfrface->face_flags = 0;        /* not scalable */
158           else
159           {
160             FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" ));
161             error = FT_THROW( Invalid_File_Format );
162             goto Exit;
163           }
164         }
165       }
166
167       if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 )
168         pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
169
170       if ( phy_font->flags & PFR_PHY_VERTICAL )
171         pfrface->face_flags |= FT_FACE_FLAG_VERTICAL;
172       else
173         pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL;
174
175       if ( phy_font->num_strikes > 0 )
176         pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
177
178       if ( phy_font->num_kern_pairs > 0 )
179         pfrface->face_flags |= FT_FACE_FLAG_KERNING;
180
181       /* If no family name was found in the "undocumented" auxiliary
182        * data, use the font ID instead.  This sucks but is better than
183        * nothing.
184        */
185       pfrface->family_name = phy_font->family_name;
186       if ( pfrface->family_name == NULL )
187         pfrface->family_name = phy_font->font_id;
188
189       /* note that the style name can be NULL in certain PFR fonts,
190        * probably meaning "Regular"
191        */
192       pfrface->style_name = phy_font->style_name;
193
194       pfrface->num_fixed_sizes = 0;
195       pfrface->available_sizes = 0;
196
197       pfrface->bbox         = phy_font->bbox;
198       pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution;
199       pfrface->ascender     = (FT_Short) phy_font->bbox.yMax;
200       pfrface->descender    = (FT_Short) phy_font->bbox.yMin;
201
202       pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 );
203       if ( pfrface->height < pfrface->ascender - pfrface->descender )
204         pfrface->height = (FT_Short)(pfrface->ascender - pfrface->descender);
205
206       if ( phy_font->num_strikes > 0 )
207       {
208         FT_UInt          n, count = phy_font->num_strikes;
209         FT_Bitmap_Size*  size;
210         PFR_Strike       strike;
211         FT_Memory        memory = pfrface->stream->memory;
212
213
214         if ( FT_NEW_ARRAY( pfrface->available_sizes, count ) )
215           goto Exit;
216
217         size   = pfrface->available_sizes;
218         strike = phy_font->strikes;
219         for ( n = 0; n < count; n++, size++, strike++ )
220         {
221           size->height = (FT_UShort)strike->y_ppm;
222           size->width  = (FT_UShort)strike->x_ppm;
223           size->size   = strike->y_ppm << 6;
224           size->x_ppem = strike->x_ppm << 6;
225           size->y_ppem = strike->y_ppm << 6;
226         }
227         pfrface->num_fixed_sizes = count;
228       }
229
230       /* now compute maximum advance width */
231       if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 )
232         pfrface->max_advance_width = (FT_Short)phy_font->standard_advance;
233       else
234       {
235         FT_Int    max = 0;
236         FT_UInt   count = phy_font->num_chars;
237         PFR_Char  gchar = phy_font->chars;
238
239
240         for ( ; count > 0; count--, gchar++ )
241         {
242           if ( max < gchar->advance )
243             max = gchar->advance;
244         }
245
246         pfrface->max_advance_width = (FT_Short)max;
247       }
248
249       pfrface->max_advance_height = pfrface->height;
250
251       pfrface->underline_position  = (FT_Short)( -pfrface->units_per_EM / 10 );
252       pfrface->underline_thickness = (FT_Short)(  pfrface->units_per_EM / 30 );
253
254       /* create charmap */
255       {
256         FT_CharMapRec  charmap;
257
258
259         charmap.face        = pfrface;
260         charmap.platform_id = TT_PLATFORM_MICROSOFT;
261         charmap.encoding_id = TT_MS_ID_UNICODE_CS;
262         charmap.encoding    = FT_ENCODING_UNICODE;
263
264         error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL );
265
266 #if 0
267         /* Select default charmap */
268         if ( pfrface->num_charmaps )
269           pfrface->charmap = pfrface->charmaps[0];
270 #endif
271       }
272
273       /* check whether we've loaded any kerning pairs */
274       if ( phy_font->num_kern_pairs )
275         pfrface->face_flags |= FT_FACE_FLAG_KERNING;
276     }
277
278   Exit:
279     return error;
280   }
281
282
283   /*************************************************************************/
284   /*************************************************************************/
285   /*****                                                               *****/
286   /*****                    SLOT OBJECT METHOD                         *****/
287   /*****                                                               *****/
288   /*************************************************************************/
289   /*************************************************************************/
290
291   FT_LOCAL_DEF( FT_Error )
292   pfr_slot_init( FT_GlyphSlot  pfrslot )        /* PFR_Slot */
293   {
294     PFR_Slot        slot   = (PFR_Slot)pfrslot;
295     FT_GlyphLoader  loader = pfrslot->internal->loader;
296
297
298     pfr_glyph_init( &slot->glyph, loader );
299
300     return 0;
301   }
302
303
304   FT_LOCAL_DEF( void )
305   pfr_slot_done( FT_GlyphSlot  pfrslot )        /* PFR_Slot */
306   {
307     PFR_Slot  slot = (PFR_Slot)pfrslot;
308
309
310     pfr_glyph_done( &slot->glyph );
311   }
312
313
314   FT_LOCAL_DEF( FT_Error )
315   pfr_slot_load( FT_GlyphSlot  pfrslot,         /* PFR_Slot */
316                  FT_Size       pfrsize,         /* PFR_Size */
317                  FT_UInt       gindex,
318                  FT_Int32      load_flags )
319   {
320     PFR_Slot     slot    = (PFR_Slot)pfrslot;
321     PFR_Size     size    = (PFR_Size)pfrsize;
322     FT_Error     error;
323     PFR_Face     face    = (PFR_Face)pfrslot->face;
324     PFR_Char     gchar;
325     FT_Outline*  outline = &pfrslot->outline;
326     FT_ULong     gps_offset;
327
328
329     FT_TRACE1(( "pfr_slot_load: glyph index %d\n", gindex ));
330
331     if ( gindex > 0 )
332       gindex--;
333
334     if ( !face || gindex >= face->phy_font.num_chars )
335     {
336       error = FT_THROW( Invalid_Argument );
337       goto Exit;
338     }
339
340     /* try to load an embedded bitmap */
341     if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
342     {
343       error = pfr_slot_load_bitmap( slot, size, gindex );
344       if ( error == 0 )
345         goto Exit;
346     }
347
348     if ( load_flags & FT_LOAD_SBITS_ONLY )
349     {
350       error = FT_THROW( Invalid_Argument );
351       goto Exit;
352     }
353
354     gchar               = face->phy_font.chars + gindex;
355     pfrslot->format     = FT_GLYPH_FORMAT_OUTLINE;
356     outline->n_points   = 0;
357     outline->n_contours = 0;
358     gps_offset          = face->header.gps_section_offset;
359
360     /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
361     error = pfr_glyph_load( &slot->glyph, face->root.stream,
362                             gps_offset, gchar->gps_offset, gchar->gps_size );
363
364     if ( !error )
365     {
366       FT_BBox            cbox;
367       FT_Glyph_Metrics*  metrics = &pfrslot->metrics;
368       FT_Pos             advance;
369       FT_Int             em_metrics, em_outline;
370       FT_Bool            scaling;
371
372
373       scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );
374
375       /* copy outline data */
376       *outline = slot->glyph.loader->base.outline;
377
378       outline->flags &= ~FT_OUTLINE_OWNER;
379       outline->flags |= FT_OUTLINE_REVERSE_FILL;
380
381       if ( size && pfrsize->metrics.y_ppem < 24 )
382         outline->flags |= FT_OUTLINE_HIGH_PRECISION;
383
384       /* compute the advance vector */
385       metrics->horiAdvance = 0;
386       metrics->vertAdvance = 0;
387
388       advance    = gchar->advance;
389       em_metrics = face->phy_font.metrics_resolution;
390       em_outline = face->phy_font.outline_resolution;
391
392       if ( em_metrics != em_outline )
393         advance = FT_MulDiv( advance, em_outline, em_metrics );
394
395       if ( face->phy_font.flags & PFR_PHY_VERTICAL )
396         metrics->vertAdvance = advance;
397       else
398         metrics->horiAdvance = advance;
399
400       pfrslot->linearHoriAdvance = metrics->horiAdvance;
401       pfrslot->linearVertAdvance = metrics->vertAdvance;
402
403       /* make-up vertical metrics(?) */
404       metrics->vertBearingX = 0;
405       metrics->vertBearingY = 0;
406
407 #if 0 /* some fonts seem to be broken here! */
408
409       /* Apply the font matrix, if any.                 */
410       /* TODO: Test existing fonts with unusual matrix  */
411       /* whether we have to adjust Units per EM.        */
412       {
413         FT_Matrix font_matrix;
414
415
416         font_matrix.xx = face->log_font.matrix[0] << 8;
417         font_matrix.yx = face->log_font.matrix[1] << 8;
418         font_matrix.xy = face->log_font.matrix[2] << 8;
419         font_matrix.yy = face->log_font.matrix[3] << 8;
420
421         FT_Outline_Transform( outline, &font_matrix );
422       }
423 #endif
424
425       /* scale when needed */
426       if ( scaling )
427       {
428         FT_Int      n;
429         FT_Fixed    x_scale = pfrsize->metrics.x_scale;
430         FT_Fixed    y_scale = pfrsize->metrics.y_scale;
431         FT_Vector*  vec     = outline->points;
432
433
434         /* scale outline points */
435         for ( n = 0; n < outline->n_points; n++, vec++ )
436         {
437           vec->x = FT_MulFix( vec->x, x_scale );
438           vec->y = FT_MulFix( vec->y, y_scale );
439         }
440
441         /* scale the advance */
442         metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
443         metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
444       }
445
446       /* compute the rest of the metrics */
447       FT_Outline_Get_CBox( outline, &cbox );
448
449       metrics->width        = cbox.xMax - cbox.xMin;
450       metrics->height       = cbox.yMax - cbox.yMin;
451       metrics->horiBearingX = cbox.xMin;
452       metrics->horiBearingY = cbox.yMax - metrics->height;
453     }
454
455   Exit:
456     return error;
457   }
458
459
460   /*************************************************************************/
461   /*************************************************************************/
462   /*****                                                               *****/
463   /*****                      KERNING METHOD                           *****/
464   /*****                                                               *****/
465   /*************************************************************************/
466   /*************************************************************************/
467
468   FT_LOCAL_DEF( FT_Error )
469   pfr_face_get_kerning( FT_Face     pfrface,        /* PFR_Face */
470                         FT_UInt     glyph1,
471                         FT_UInt     glyph2,
472                         FT_Vector*  kerning )
473   {
474     PFR_Face     face     = (PFR_Face)pfrface;
475     FT_Error     error    = FT_Err_Ok;
476     PFR_PhyFont  phy_font = &face->phy_font;
477     FT_UInt32    code1, code2, pair;
478
479
480     kerning->x = 0;
481     kerning->y = 0;
482
483     if ( glyph1 > 0 )
484       glyph1--;
485
486     if ( glyph2 > 0 )
487       glyph2--;
488
489     /* convert glyph indices to character codes */
490     if ( glyph1 > phy_font->num_chars ||
491          glyph2 > phy_font->num_chars )
492       goto Exit;
493
494     code1 = phy_font->chars[glyph1].char_code;
495     code2 = phy_font->chars[glyph2].char_code;
496     pair  = PFR_KERN_INDEX( code1, code2 );
497
498     /* now search the list of kerning items */
499     {
500       PFR_KernItem  item   = phy_font->kern_items;
501       FT_Stream     stream = pfrface->stream;
502
503
504       for ( ; item; item = item->next )
505       {
506         if ( pair >= item->pair1 && pair <= item->pair2 )
507           goto FoundPair;
508       }
509       goto Exit;
510
511     FoundPair: /* we found an item, now parse it and find the value if any */
512       if ( FT_STREAM_SEEK( item->offset )                       ||
513            FT_FRAME_ENTER( item->pair_count * item->pair_size ) )
514         goto Exit;
515
516       {
517         FT_UInt    count       = item->pair_count;
518         FT_UInt    size        = item->pair_size;
519         FT_UInt    power       = 1 << FT_MSB( count );
520         FT_UInt    probe       = power * size;
521         FT_UInt    extra       = count - power;
522         FT_Byte*   base        = stream->cursor;
523         FT_Bool    twobytes    = FT_BOOL( item->flags & 1 );
524         FT_Bool    twobyte_adj = FT_BOOL( item->flags & 2 );
525         FT_Byte*   p;
526         FT_UInt32  cpair;
527
528
529         if ( extra > 0 )
530         {
531           p = base + extra * size;
532
533           if ( twobytes )
534             cpair = FT_NEXT_ULONG( p );
535           else
536             cpair = PFR_NEXT_KPAIR( p );
537
538           if ( cpair == pair )
539             goto Found;
540
541           if ( cpair < pair )
542           {
543             if ( twobyte_adj )
544               p += 2;
545             else
546               p++;
547             base = p;
548           }
549         }
550
551         while ( probe > size )
552         {
553           probe >>= 1;
554           p       = base + probe;
555
556           if ( twobytes )
557             cpair = FT_NEXT_ULONG( p );
558           else
559             cpair = PFR_NEXT_KPAIR( p );
560
561           if ( cpair == pair )
562             goto Found;
563
564           if ( cpair < pair )
565             base += probe;
566         }
567
568         p = base;
569
570         if ( twobytes )
571           cpair = FT_NEXT_ULONG( p );
572         else
573           cpair = PFR_NEXT_KPAIR( p );
574
575         if ( cpair == pair )
576         {
577           FT_Int  value;
578
579
580         Found:
581           if ( twobyte_adj )
582             value = FT_PEEK_SHORT( p );
583           else
584             value = p[0];
585
586           kerning->x = item->base_adj + value;
587         }
588       }
589
590       FT_FRAME_EXIT();
591     }
592
593   Exit:
594     return error;
595   }
596
597 /* END */