Imported Upstream version 2.13.2
[platform/upstream/freetype2.git] / src / pfr / pfrobjs.c
1 /****************************************************************************
2  *
3  * pfrobjs.c
4  *
5  *   FreeType PFR object methods (body).
6  *
7  * Copyright (C) 2002-2023 by
8  * David Turner, Robert Wilhelm, and Werner Lemberg.
9  *
10  * This file is part of the FreeType project, and may only be used,
11  * modified, and distributed under the terms of the FreeType project
12  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
13  * this file you indicate that you have read the license and
14  * understand and accept it fully.
15  *
16  */
17
18
19 #include "pfrobjs.h"
20 #include "pfrload.h"
21 #include "pfrgload.h"
22 #include "pfrcmap.h"
23 #include "pfrsbit.h"
24 #include <freetype/ftoutln.h>
25 #include <freetype/internal/ftdebug.h>
26 #include <freetype/internal/ftcalc.h>
27 #include <freetype/ttnameid.h>
28
29 #include "pfrerror.h"
30
31 #undef  FT_COMPONENT
32 #define FT_COMPONENT  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->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, memory );
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     {
87       FT_TRACE2(( "  not a PFR font\n" ));
88       error = FT_THROW( Unknown_File_Format );
89       goto Exit;
90     }
91
92     if ( !pfr_header_check( &face->header ) )
93     {
94       FT_TRACE2(( "  not a PFR font\n" ));
95       error = FT_THROW( Unknown_File_Format );
96       goto Exit;
97     }
98
99     /* check face index */
100     {
101       FT_Long  num_faces;
102
103
104       error = pfr_log_font_count( stream,
105                                   face->header.log_dir_offset,
106                                   &num_faces );
107       if ( error )
108         goto Exit;
109
110       pfrface->num_faces = num_faces;
111     }
112
113     if ( face_index < 0 )
114       goto Exit;
115
116     if ( ( face_index & 0xFFFF ) >= pfrface->num_faces )
117     {
118       FT_ERROR(( "pfr_face_init: invalid face index\n" ));
119       error = FT_THROW( Invalid_Argument );
120       goto Exit;
121     }
122
123     /* load the face */
124     error = pfr_log_font_load(
125               &face->log_font,
126               stream,
127               (FT_UInt)( face_index & 0xFFFF ),
128               face->header.log_dir_offset,
129               FT_BOOL( face->header.phy_font_max_size_high ) );
130     if ( error )
131       goto Exit;
132
133     /* load the physical font descriptor */
134     error = pfr_phy_font_load( &face->phy_font, stream,
135                                face->log_font.phys_offset,
136                                face->log_font.phys_size );
137     if ( error )
138       goto Exit;
139
140     /* set up all root face fields */
141     {
142       PFR_PhyFont  phy_font = &face->phy_font;
143
144
145       pfrface->face_index = face_index & 0xFFFF;
146       pfrface->num_glyphs = (FT_Long)phy_font->num_chars + 1;
147
148       pfrface->face_flags |= FT_FACE_FLAG_SCALABLE;
149
150       /* if gps_offset == 0 for all characters, we  */
151       /* assume that the font only contains bitmaps */
152       {
153         FT_UInt  nn;
154
155
156         for ( nn = 0; nn < phy_font->num_chars; nn++ )
157           if ( phy_font->chars[nn].gps_offset != 0 )
158             break;
159
160         if ( nn == phy_font->num_chars )
161         {
162           if ( phy_font->num_strikes > 0 )
163             pfrface->face_flags &= ~FT_FACE_FLAG_SCALABLE;
164           else
165           {
166             FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" ));
167             error = FT_THROW( Invalid_File_Format );
168             goto Exit;
169           }
170         }
171       }
172
173       if ( !( phy_font->flags & PFR_PHY_PROPORTIONAL ) )
174         pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
175
176       if ( phy_font->flags & PFR_PHY_VERTICAL )
177         pfrface->face_flags |= FT_FACE_FLAG_VERTICAL;
178       else
179         pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL;
180
181       if ( phy_font->num_strikes > 0 )
182         pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
183
184       if ( phy_font->num_kern_pairs > 0 )
185         pfrface->face_flags |= FT_FACE_FLAG_KERNING;
186
187       /* If no family name was found in the `undocumented' auxiliary
188        * data, use the font ID instead.  This sucks but is better than
189        * nothing.
190        */
191       pfrface->family_name = phy_font->family_name;
192       if ( !pfrface->family_name )
193         pfrface->family_name = phy_font->font_id;
194
195       /* note that the style name can be NULL in certain PFR fonts,
196        * probably meaning `Regular'
197        */
198       pfrface->style_name = phy_font->style_name;
199
200       pfrface->num_fixed_sizes = 0;
201       pfrface->available_sizes = NULL;
202
203       pfrface->bbox         = phy_font->bbox;
204       pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution;
205       pfrface->ascender     = (FT_Short) phy_font->bbox.yMax;
206       pfrface->descender    = (FT_Short) phy_font->bbox.yMin;
207
208       pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 );
209       if ( pfrface->height < pfrface->ascender - pfrface->descender )
210         pfrface->height = (FT_Short)( pfrface->ascender - pfrface->descender );
211
212       if ( phy_font->num_strikes > 0 )
213       {
214         FT_UInt          n, count = phy_font->num_strikes;
215         FT_Bitmap_Size*  size;
216         PFR_Strike       strike;
217         FT_Memory        memory = pfrface->memory;
218
219
220         if ( FT_QNEW_ARRAY( pfrface->available_sizes, count ) )
221           goto Exit;
222
223         size   = pfrface->available_sizes;
224         strike = phy_font->strikes;
225         for ( n = 0; n < count; n++, size++, strike++ )
226         {
227           size->height = (FT_Short)strike->y_ppm;
228           size->width  = (FT_Short)strike->x_ppm;
229           size->size   = (FT_Pos)( strike->y_ppm << 6 );
230           size->x_ppem = (FT_Pos)( strike->x_ppm << 6 );
231           size->y_ppem = (FT_Pos)( strike->y_ppm << 6 );
232         }
233         pfrface->num_fixed_sizes = (FT_Int)count;
234       }
235
236       /* now compute maximum advance width */
237       if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 )
238         pfrface->max_advance_width = (FT_Short)phy_font->standard_advance;
239       else
240       {
241         FT_Int    max = 0;
242         FT_UInt   count = phy_font->num_chars;
243         PFR_Char  gchar = phy_font->chars;
244
245
246         for ( ; count > 0; count--, gchar++ )
247         {
248           if ( max < gchar->advance )
249             max = gchar->advance;
250         }
251
252         pfrface->max_advance_width = (FT_Short)max;
253       }
254
255       pfrface->max_advance_height = pfrface->height;
256
257       pfrface->underline_position  = (FT_Short)( -pfrface->units_per_EM / 10 );
258       pfrface->underline_thickness = (FT_Short)(  pfrface->units_per_EM / 30 );
259
260       /* create charmap */
261       {
262         FT_CharMapRec  charmap;
263
264
265         charmap.face        = pfrface;
266         charmap.platform_id = TT_PLATFORM_MICROSOFT;
267         charmap.encoding_id = TT_MS_ID_UNICODE_CS;
268         charmap.encoding    = FT_ENCODING_UNICODE;
269
270         error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL );
271       }
272
273       /* check whether we have 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 ) ) )
342     {
343       error = pfr_slot_load_bitmap(
344                 slot,
345                 size,
346                 gindex,
347                 ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 );
348       if ( !error )
349         goto Exit;
350     }
351
352     if ( load_flags & FT_LOAD_SBITS_ONLY )
353     {
354       error = FT_THROW( Invalid_Argument );
355       goto Exit;
356     }
357
358     gchar               = face->phy_font.chars + gindex;
359     pfrslot->format     = FT_GLYPH_FORMAT_OUTLINE;
360     outline->n_points   = 0;
361     outline->n_contours = 0;
362     gps_offset          = face->header.gps_section_offset;
363
364     /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
365     error = pfr_glyph_load( &slot->glyph, face->root.stream,
366                             gps_offset, gchar->gps_offset, gchar->gps_size );
367
368     if ( !error )
369     {
370       FT_BBox            cbox;
371       FT_Glyph_Metrics*  metrics = &pfrslot->metrics;
372       FT_Pos             advance;
373       FT_UInt            em_metrics, em_outline;
374       FT_Bool            scaling;
375
376
377       scaling = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) );
378
379       /* copy outline data */
380       *outline = slot->glyph.loader->base.outline;
381
382       outline->flags &= ~FT_OUTLINE_OWNER;
383       outline->flags |= FT_OUTLINE_REVERSE_FILL;
384
385       if ( pfrsize->metrics.y_ppem < 24 )
386         outline->flags |= FT_OUTLINE_HIGH_PRECISION;
387
388       /* compute the advance vector */
389       metrics->horiAdvance = 0;
390       metrics->vertAdvance = 0;
391
392       advance    = gchar->advance;
393       em_metrics = face->phy_font.metrics_resolution;
394       em_outline = face->phy_font.outline_resolution;
395
396       if ( em_metrics != em_outline )
397         advance = FT_MulDiv( advance,
398                              (FT_Long)em_outline,
399                              (FT_Long)em_metrics );
400
401       if ( face->phy_font.flags & PFR_PHY_VERTICAL )
402         metrics->vertAdvance = advance;
403       else
404         metrics->horiAdvance = advance;
405
406       pfrslot->linearHoriAdvance = metrics->horiAdvance;
407       pfrslot->linearVertAdvance = metrics->vertAdvance;
408
409       /* make up vertical metrics(?) */
410       metrics->vertBearingX = 0;
411       metrics->vertBearingY = 0;
412
413 #if 0 /* some fonts seem to be broken here! */
414
415       /* Apply the font matrix, if any.                 */
416       /* TODO: Test existing fonts with unusual matrix  */
417       /* whether we have to adjust Units per EM.        */
418       {
419         FT_Matrix font_matrix;
420
421
422         font_matrix.xx = face->log_font.matrix[0] << 8;
423         font_matrix.yx = face->log_font.matrix[1] << 8;
424         font_matrix.xy = face->log_font.matrix[2] << 8;
425         font_matrix.yy = face->log_font.matrix[3] << 8;
426
427         FT_Outline_Transform( outline, &font_matrix );
428       }
429 #endif
430
431       /* scale when needed */
432       if ( scaling )
433       {
434         FT_Int      n;
435         FT_Fixed    x_scale = pfrsize->metrics.x_scale;
436         FT_Fixed    y_scale = pfrsize->metrics.y_scale;
437         FT_Vector*  vec     = outline->points;
438
439
440         /* scale outline points */
441         for ( n = 0; n < outline->n_points; n++, vec++ )
442         {
443           vec->x = FT_MulFix( vec->x, x_scale );
444           vec->y = FT_MulFix( vec->y, y_scale );
445         }
446
447         /* scale the advance */
448         metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
449         metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
450       }
451
452       /* compute the rest of the metrics */
453       FT_Outline_Get_CBox( outline, &cbox );
454
455       metrics->width        = cbox.xMax - cbox.xMin;
456       metrics->height       = cbox.yMax - cbox.yMin;
457       metrics->horiBearingX = cbox.xMin;
458       metrics->horiBearingY = cbox.yMax - metrics->height;
459     }
460
461   Exit:
462     return error;
463   }
464
465
466   /*************************************************************************/
467   /*************************************************************************/
468   /*****                                                               *****/
469   /*****                      KERNING METHOD                           *****/
470   /*****                                                               *****/
471   /*************************************************************************/
472   /*************************************************************************/
473
474   FT_LOCAL_DEF( FT_Error )
475   pfr_face_get_kerning( FT_Face     pfrface,        /* PFR_Face */
476                         FT_UInt     glyph1,
477                         FT_UInt     glyph2,
478                         FT_Vector*  kerning )
479   {
480     PFR_Face     face     = (PFR_Face)pfrface;
481     FT_Error     error    = FT_Err_Ok;
482     PFR_PhyFont  phy_font = &face->phy_font;
483     FT_UInt32    code1, code2, pair;
484
485
486     kerning->x = 0;
487     kerning->y = 0;
488
489     /* PFR indexing skips .notdef, which becomes UINT_MAX */
490     glyph1--;
491     glyph2--;
492
493     /* check the array bounds, .notdef is automatically out */
494     if ( glyph1 >= phy_font->num_chars ||
495          glyph2 >= phy_font->num_chars )
496       goto Exit;
497
498     /* convert glyph indices to character codes */
499     code1 = phy_font->chars[glyph1].char_code;
500     code2 = phy_font->chars[glyph2].char_code;
501     pair  = PFR_KERN_INDEX( code1, code2 );
502
503     /* now search the list of kerning items */
504     {
505       PFR_KernItem  item   = phy_font->kern_items;
506       FT_Stream     stream = pfrface->stream;
507
508
509       for ( ; item; item = item->next )
510       {
511         if ( pair >= item->pair1 && pair <= item->pair2 )
512           goto FoundPair;
513       }
514       goto Exit;
515
516     FoundPair: /* we found an item, now parse it and find the value if any */
517       if ( FT_STREAM_SEEK( item->offset )                       ||
518            FT_FRAME_ENTER( item->pair_count * item->pair_size ) )
519         goto Exit;
520
521       {
522         FT_UInt    count       = item->pair_count;
523         FT_UInt    size        = item->pair_size;
524         FT_UInt    power       = 1 << FT_MSB( count );
525         FT_UInt    probe       = power * size;
526         FT_UInt    extra       = count - power;
527         FT_Byte*   base        = stream->cursor;
528         FT_Bool    twobytes    = FT_BOOL( item->flags & PFR_KERN_2BYTE_CHAR );
529         FT_Bool    twobyte_adj = FT_BOOL( item->flags & PFR_KERN_2BYTE_ADJ  );
530         FT_Byte*   p;
531         FT_UInt32  cpair;
532
533
534         if ( extra > 0 )
535         {
536           p = base + extra * size;
537
538           if ( twobytes )
539             cpair = FT_NEXT_ULONG( p );
540           else
541             cpair = PFR_NEXT_KPAIR( p );
542
543           if ( cpair == pair )
544             goto Found;
545
546           if ( cpair < pair )
547           {
548             if ( twobyte_adj )
549               p += 2;
550             else
551               p++;
552             base = p;
553           }
554         }
555
556         while ( probe > size )
557         {
558           probe >>= 1;
559           p       = base + probe;
560
561           if ( twobytes )
562             cpair = FT_NEXT_ULONG( p );
563           else
564             cpair = PFR_NEXT_KPAIR( p );
565
566           if ( cpair == pair )
567             goto Found;
568
569           if ( cpair < pair )
570             base += probe;
571         }
572
573         p = base;
574
575         if ( twobytes )
576           cpair = FT_NEXT_ULONG( p );
577         else
578           cpair = PFR_NEXT_KPAIR( p );
579
580         if ( cpair == pair )
581         {
582           FT_Int  value;
583
584
585         Found:
586           if ( twobyte_adj )
587             value = FT_PEEK_SHORT( p );
588           else
589             value = p[0];
590
591           kerning->x = item->base_adj + value;
592         }
593       }
594
595       FT_FRAME_EXIT();
596     }
597
598   Exit:
599     return error;
600   }
601
602
603 /* END */