1 /****************************************************************************
2  *
3  * ftglyph.c
4  *
5  *   FreeType convenience functions to handle glyphs (body).
6  *
7  * Copyright 1996-2018 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    *
20    * This file contains the definition of several convenience functions
21    * that can be used by client applications to easily retrieve glyph
22    * bitmaps and outlines from a given face.
23    *
24    * These functions should be optional if you are writing a font server
25    * or text layout engine on top of FreeType.  However, they are pretty
26    * handy for many other simple uses of the library.
27    *
28    */
29 
30 
31 #include <ft2build.h>
32 #include FT_INTERNAL_DEBUG_H
33 
34 #include FT_GLYPH_H
35 #include FT_OUTLINE_H
36 #include FT_BITMAP_H
37 #include FT_INTERNAL_OBJECTS_H
38 
39 
40   /**************************************************************************
41    *
42    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
43    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
44    * messages during execution.
45    */
46 #undef  FT_COMPONENT
47 #define FT_COMPONENT  trace_glyph
48 
49 
50   /*************************************************************************/
51   /*************************************************************************/
52   /****                                                                 ****/
53   /****   FT_BitmapGlyph support                                        ****/
54   /****                                                                 ****/
55   /*************************************************************************/
56   /*************************************************************************/
57 
58   FT_CALLBACK_DEF( FT_Error )
ft_bitmap_glyph_init(FT_Glyph bitmap_glyph,FT_GlyphSlot slot)59   ft_bitmap_glyph_init( FT_Glyph      bitmap_glyph,
60                         FT_GlyphSlot  slot )
61   {
62     FT_BitmapGlyph  glyph   = (FT_BitmapGlyph)bitmap_glyph;
63     FT_Error        error   = FT_Err_Ok;
64     FT_Library      library = FT_GLYPH( glyph )->library;
65 
66 
67     if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
68     {
69       error = FT_THROW( Invalid_Glyph_Format );
70       goto Exit;
71     }
72 
73     glyph->left = slot->bitmap_left;
74     glyph->top  = slot->bitmap_top;
75 
76     /* do lazy copying whenever possible */
77     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
78     {
79       glyph->bitmap = slot->bitmap;
80       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
81     }
82     else
83     {
84       FT_Bitmap_Init( &glyph->bitmap );
85       error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap );
86     }
87 
88   Exit:
89     return error;
90   }
91 
92 
93   FT_CALLBACK_DEF( FT_Error )
ft_bitmap_glyph_copy(FT_Glyph bitmap_source,FT_Glyph bitmap_target)94   ft_bitmap_glyph_copy( FT_Glyph  bitmap_source,
95                         FT_Glyph  bitmap_target )
96   {
97     FT_Library      library = bitmap_source->library;
98     FT_BitmapGlyph  source  = (FT_BitmapGlyph)bitmap_source;
99     FT_BitmapGlyph  target  = (FT_BitmapGlyph)bitmap_target;
100 
101 
102     target->left = source->left;
103     target->top  = source->top;
104 
105     return FT_Bitmap_Copy( library, &source->bitmap, &target->bitmap );
106   }
107 
108 
109   FT_CALLBACK_DEF( void )
ft_bitmap_glyph_done(FT_Glyph bitmap_glyph)110   ft_bitmap_glyph_done( FT_Glyph  bitmap_glyph )
111   {
112     FT_BitmapGlyph  glyph   = (FT_BitmapGlyph)bitmap_glyph;
113     FT_Library      library = FT_GLYPH( glyph )->library;
114 
115 
116     FT_Bitmap_Done( library, &glyph->bitmap );
117   }
118 
119 
120   FT_CALLBACK_DEF( void )
ft_bitmap_glyph_bbox(FT_Glyph bitmap_glyph,FT_BBox * cbox)121   ft_bitmap_glyph_bbox( FT_Glyph  bitmap_glyph,
122                         FT_BBox*  cbox )
123   {
124     FT_BitmapGlyph  glyph = (FT_BitmapGlyph)bitmap_glyph;
125 
126 
127     cbox->xMin = glyph->left * 64;
128     cbox->xMax = cbox->xMin + (FT_Pos)( glyph->bitmap.width * 64 );
129     cbox->yMax = glyph->top * 64;
130     cbox->yMin = cbox->yMax - (FT_Pos)( glyph->bitmap.rows * 64 );
131   }
132 
133 
FT_DEFINE_GLYPH(ft_bitmap_glyph_class,sizeof (FT_BitmapGlyphRec),FT_GLYPH_FORMAT_BITMAP,ft_bitmap_glyph_init,ft_bitmap_glyph_done,ft_bitmap_glyph_copy,NULL,ft_bitmap_glyph_bbox,NULL)134   FT_DEFINE_GLYPH(
135     ft_bitmap_glyph_class,
136 
137     sizeof ( FT_BitmapGlyphRec ),
138     FT_GLYPH_FORMAT_BITMAP,
139 
140     ft_bitmap_glyph_init,    /* FT_Glyph_InitFunc       glyph_init      */
141     ft_bitmap_glyph_done,    /* FT_Glyph_DoneFunc       glyph_done      */
142     ft_bitmap_glyph_copy,    /* FT_Glyph_CopyFunc       glyph_copy      */
143     NULL,                    /* FT_Glyph_TransformFunc  glyph_transform */
144     ft_bitmap_glyph_bbox,    /* FT_Glyph_GetBBoxFunc    glyph_bbox      */
145     NULL                     /* FT_Glyph_PrepareFunc    glyph_prepare   */
146   )
147 
148 
149   /*************************************************************************/
150   /*************************************************************************/
151   /****                                                                 ****/
152   /****   FT_OutlineGlyph support                                       ****/
153   /****                                                                 ****/
154   /*************************************************************************/
155   /*************************************************************************/
156 
157 
158   FT_CALLBACK_DEF( FT_Error )
159   ft_outline_glyph_init( FT_Glyph      outline_glyph,
160                          FT_GlyphSlot  slot )
161   {
162     FT_OutlineGlyph  glyph   = (FT_OutlineGlyph)outline_glyph;
163     FT_Error         error   = FT_Err_Ok;
164     FT_Library       library = FT_GLYPH( glyph )->library;
165     FT_Outline*      source  = &slot->outline;
166     FT_Outline*      target  = &glyph->outline;
167 
168 
169     /* check format in glyph slot */
170     if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
171     {
172       error = FT_THROW( Invalid_Glyph_Format );
173       goto Exit;
174     }
175 
176     /* allocate new outline */
177     error = FT_Outline_New( library,
178                             (FT_UInt)source->n_points,
179                             source->n_contours,
180                             &glyph->outline );
181     if ( error )
182       goto Exit;
183 
184     FT_Outline_Copy( source, target );
185 
186   Exit:
187     return error;
188   }
189 
190 
191   FT_CALLBACK_DEF( void )
ft_outline_glyph_done(FT_Glyph outline_glyph)192   ft_outline_glyph_done( FT_Glyph  outline_glyph )
193   {
194     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;
195 
196 
197     FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline );
198   }
199 
200 
201   FT_CALLBACK_DEF( FT_Error )
ft_outline_glyph_copy(FT_Glyph outline_source,FT_Glyph outline_target)202   ft_outline_glyph_copy( FT_Glyph  outline_source,
203                          FT_Glyph  outline_target )
204   {
205     FT_OutlineGlyph  source  = (FT_OutlineGlyph)outline_source;
206     FT_OutlineGlyph  target  = (FT_OutlineGlyph)outline_target;
207     FT_Error         error;
208     FT_Library       library = FT_GLYPH( source )->library;
209 
210 
211     error = FT_Outline_New( library,
212                             (FT_UInt)source->outline.n_points,
213                             source->outline.n_contours,
214                             &target->outline );
215     if ( !error )
216       FT_Outline_Copy( &source->outline, &target->outline );
217 
218     return error;
219   }
220 
221 
222   FT_CALLBACK_DEF( void )
ft_outline_glyph_transform(FT_Glyph outline_glyph,const FT_Matrix * matrix,const FT_Vector * delta)223   ft_outline_glyph_transform( FT_Glyph          outline_glyph,
224                               const FT_Matrix*  matrix,
225                               const FT_Vector*  delta )
226   {
227     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;
228 
229 
230     if ( matrix )
231       FT_Outline_Transform( &glyph->outline, matrix );
232 
233     if ( delta )
234       FT_Outline_Translate( &glyph->outline, delta->x, delta->y );
235   }
236 
237 
238   FT_CALLBACK_DEF( void )
ft_outline_glyph_bbox(FT_Glyph outline_glyph,FT_BBox * bbox)239   ft_outline_glyph_bbox( FT_Glyph  outline_glyph,
240                          FT_BBox*  bbox )
241   {
242     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;
243 
244 
245     FT_Outline_Get_CBox( &glyph->outline, bbox );
246   }
247 
248 
249   FT_CALLBACK_DEF( FT_Error )
ft_outline_glyph_prepare(FT_Glyph outline_glyph,FT_GlyphSlot slot)250   ft_outline_glyph_prepare( FT_Glyph      outline_glyph,
251                             FT_GlyphSlot  slot )
252   {
253     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;
254 
255 
256     slot->format         = FT_GLYPH_FORMAT_OUTLINE;
257     slot->outline        = glyph->outline;
258     slot->outline.flags &= ~FT_OUTLINE_OWNER;
259 
260     return FT_Err_Ok;
261   }
262 
263 
FT_DEFINE_GLYPH(ft_outline_glyph_class,sizeof (FT_OutlineGlyphRec),FT_GLYPH_FORMAT_OUTLINE,ft_outline_glyph_init,ft_outline_glyph_done,ft_outline_glyph_copy,ft_outline_glyph_transform,ft_outline_glyph_bbox,ft_outline_glyph_prepare)264   FT_DEFINE_GLYPH(
265     ft_outline_glyph_class,
266 
267     sizeof ( FT_OutlineGlyphRec ),
268     FT_GLYPH_FORMAT_OUTLINE,
269 
270     ft_outline_glyph_init,      /* FT_Glyph_InitFunc       glyph_init      */
271     ft_outline_glyph_done,      /* FT_Glyph_DoneFunc       glyph_done      */
272     ft_outline_glyph_copy,      /* FT_Glyph_CopyFunc       glyph_copy      */
273     ft_outline_glyph_transform, /* FT_Glyph_TransformFunc  glyph_transform */
274     ft_outline_glyph_bbox,      /* FT_Glyph_GetBBoxFunc    glyph_bbox      */
275     ft_outline_glyph_prepare    /* FT_Glyph_PrepareFunc    glyph_prepare   */
276   )
277 
278 
279   /*************************************************************************/
280   /*************************************************************************/
281   /****                                                                 ****/
282   /****   FT_Glyph class and API                                        ****/
283   /****                                                                 ****/
284   /*************************************************************************/
285   /*************************************************************************/
286 
287    static FT_Error
288    ft_new_glyph( FT_Library             library,
289                  const FT_Glyph_Class*  clazz,
290                  FT_Glyph*              aglyph )
291    {
292      FT_Memory  memory = library->memory;
293      FT_Error   error;
294      FT_Glyph   glyph  = NULL;
295 
296 
297      *aglyph = NULL;
298 
299      if ( !FT_ALLOC( glyph, clazz->glyph_size ) )
300      {
301        glyph->library = library;
302        glyph->clazz   = clazz;
303        glyph->format  = clazz->glyph_format;
304 
305        *aglyph = glyph;
306      }
307 
308      return error;
309    }
310 
311 
312   /* documentation is in ftglyph.h */
313 
314   FT_EXPORT_DEF( FT_Error )
FT_Glyph_Copy(FT_Glyph source,FT_Glyph * target)315   FT_Glyph_Copy( FT_Glyph   source,
316                  FT_Glyph  *target )
317   {
318     FT_Glyph               copy;
319     FT_Error               error;
320     const FT_Glyph_Class*  clazz;
321 
322 
323     /* check arguments */
324     if ( !target || !source || !source->clazz )
325     {
326       error = FT_THROW( Invalid_Argument );
327       goto Exit;
328     }
329 
330     *target = NULL;
331 
332     if ( !source || !source->clazz )
333     {
334       error = FT_THROW( Invalid_Argument );
335       goto Exit;
336     }
337 
338     clazz = source->clazz;
339     error = ft_new_glyph( source->library, clazz, &copy );
340     if ( error )
341       goto Exit;
342 
343     copy->advance = source->advance;
344     copy->format  = source->format;
345 
346     if ( clazz->glyph_copy )
347       error = clazz->glyph_copy( source, copy );
348 
349     if ( error )
350       FT_Done_Glyph( copy );
351     else
352       *target = copy;
353 
354   Exit:
355     return error;
356   }
357 
358 
359   /* documentation is in ftglyph.h */
360 
361   FT_EXPORT( FT_Error )
FT_New_Glyph(FT_Library library,FT_Glyph_Format format,FT_Glyph * aglyph)362   FT_New_Glyph( FT_Library       library,
363                 FT_Glyph_Format  format,
364                 FT_Glyph        *aglyph )
365   {
366     const FT_Glyph_Class*  clazz = NULL;
367 
368     if ( !library || !aglyph )
369       return FT_THROW( Invalid_Argument );
370 
371     /* if it is a bitmap, that's easy :-) */
372     if ( format == FT_GLYPH_FORMAT_BITMAP )
373       clazz = &ft_bitmap_glyph_class;
374 
375     /* if it is an outline */
376     else if ( format == FT_GLYPH_FORMAT_OUTLINE )
377       clazz = &ft_outline_glyph_class;
378 
379     else
380     {
381       /* try to find a renderer that supports the glyph image format */
382       FT_Renderer  render = FT_Lookup_Renderer( library, format, 0 );
383 
384 
385       if ( render )
386         clazz = &render->glyph_class;
387     }
388 
389     if ( !clazz )
390       return FT_THROW( Invalid_Glyph_Format );
391 
392     /* create FT_Glyph object */
393     return ft_new_glyph( library, clazz, aglyph );
394   }
395 
396 
397   /* documentation is in ftglyph.h */
398 
399   FT_EXPORT_DEF( FT_Error )
FT_Get_Glyph(FT_GlyphSlot slot,FT_Glyph * aglyph)400   FT_Get_Glyph( FT_GlyphSlot  slot,
401                 FT_Glyph     *aglyph )
402   {
403     FT_Error    error;
404     FT_Glyph    glyph;
405 
406 
407     if ( !slot )
408       return FT_THROW( Invalid_Slot_Handle );
409 
410     if ( !aglyph )
411       return FT_THROW( Invalid_Argument );
412 
413     /* create FT_Glyph object */
414     error = FT_New_Glyph( slot->library, slot->format, &glyph );
415     if ( error )
416       goto Exit;
417 
418     /* copy advance while converting 26.6 to 16.16 format */
419     if ( slot->advance.x >=  0x8000L * 64 ||
420          slot->advance.x <= -0x8000L * 64 )
421     {
422       FT_ERROR(( "FT_Get_Glyph: advance width too large\n" ));
423       error = FT_THROW( Invalid_Argument );
424       goto Exit2;
425     }
426     if ( slot->advance.y >=  0x8000L * 64 ||
427          slot->advance.y <= -0x8000L * 64 )
428     {
429       FT_ERROR(( "FT_Get_Glyph: advance height too large\n" ));
430       error = FT_THROW( Invalid_Argument );
431       goto Exit2;
432     }
433 
434     glyph->advance.x = slot->advance.x * 1024;
435     glyph->advance.y = slot->advance.y * 1024;
436 
437     /* now import the image from the glyph slot */
438     error = glyph->clazz->glyph_init( glyph, slot );
439 
440   Exit2:
441     /* if an error occurred, destroy the glyph */
442     if ( error )
443       FT_Done_Glyph( glyph );
444     else
445       *aglyph = glyph;
446 
447   Exit:
448     return error;
449   }
450 
451 
452   /* documentation is in ftglyph.h */
453 
454   FT_EXPORT_DEF( FT_Error )
FT_Glyph_Transform(FT_Glyph glyph,FT_Matrix * matrix,FT_Vector * delta)455   FT_Glyph_Transform( FT_Glyph    glyph,
456                       FT_Matrix*  matrix,
457                       FT_Vector*  delta )
458   {
459     FT_Error  error = FT_Err_Ok;
460 
461 
462     if ( !glyph || !glyph->clazz )
463       error = FT_THROW( Invalid_Argument );
464     else
465     {
466       const FT_Glyph_Class*  clazz = glyph->clazz;
467 
468 
469       if ( clazz->glyph_transform )
470       {
471         /* transform glyph image */
472         clazz->glyph_transform( glyph, matrix, delta );
473 
474         /* transform advance vector */
475         if ( matrix )
476           FT_Vector_Transform( &glyph->advance, matrix );
477       }
478       else
479         error = FT_THROW( Invalid_Glyph_Format );
480     }
481     return error;
482   }
483 
484 
485   /* documentation is in ftglyph.h */
486 
487   FT_EXPORT_DEF( void )
FT_Glyph_Get_CBox(FT_Glyph glyph,FT_UInt bbox_mode,FT_BBox * acbox)488   FT_Glyph_Get_CBox( FT_Glyph  glyph,
489                      FT_UInt   bbox_mode,
490                      FT_BBox  *acbox )
491   {
492     const FT_Glyph_Class*  clazz;
493 
494 
495     if ( !acbox )
496       return;
497 
498     acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0;
499 
500     if ( !glyph || !glyph->clazz )
501       return;
502 
503     clazz = glyph->clazz;
504     if ( !clazz->glyph_bbox )
505       return;
506 
507     /* retrieve bbox in 26.6 coordinates */
508     clazz->glyph_bbox( glyph, acbox );
509 
510     /* perform grid fitting if needed */
511     if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT ||
512          bbox_mode == FT_GLYPH_BBOX_PIXELS  )
513     {
514       acbox->xMin = FT_PIX_FLOOR( acbox->xMin );
515       acbox->yMin = FT_PIX_FLOOR( acbox->yMin );
516       acbox->xMax = FT_PIX_CEIL( acbox->xMax );
517       acbox->yMax = FT_PIX_CEIL( acbox->yMax );
518     }
519 
520     /* convert to integer pixels if needed */
521     if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE ||
522          bbox_mode == FT_GLYPH_BBOX_PIXELS   )
523     {
524       acbox->xMin >>= 6;
525       acbox->yMin >>= 6;
526       acbox->xMax >>= 6;
527       acbox->yMax >>= 6;
528     }
529   }
530 
531 
532   /* documentation is in ftglyph.h */
533 
534   FT_EXPORT_DEF( FT_Error )
FT_Glyph_To_Bitmap(FT_Glyph * the_glyph,FT_Render_Mode render_mode,FT_Vector * origin,FT_Bool destroy)535   FT_Glyph_To_Bitmap( FT_Glyph*       the_glyph,
536                       FT_Render_Mode  render_mode,
537                       FT_Vector*      origin,
538                       FT_Bool         destroy )
539   {
540     FT_GlyphSlotRec           dummy;
541     FT_GlyphSlot_InternalRec  dummy_internal;
542     FT_Error                  error = FT_Err_Ok;
543     FT_Glyph                  b, glyph;
544     FT_BitmapGlyph            bitmap = NULL;
545     const FT_Glyph_Class*     clazz;
546 
547     FT_Library                library;
548 
549 
550     /* check argument */
551     if ( !the_glyph )
552       goto Bad;
553     glyph = *the_glyph;
554     if ( !glyph )
555       goto Bad;
556 
557     clazz   = glyph->clazz;
558     library = glyph->library;
559     if ( !library || !clazz )
560       goto Bad;
561 
562     /* when called with a bitmap glyph, do nothing and return successfully */
563     if ( clazz == &ft_bitmap_glyph_class )
564       goto Exit;
565 
566     if ( !clazz->glyph_prepare )
567       goto Bad;
568 
569     /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */
570     /* then calling FT_Render_Glyph_Internal()                            */
571 
572     FT_ZERO( &dummy );
573     FT_ZERO( &dummy_internal );
574     dummy.internal = &dummy_internal;
575     dummy.library  = library;
576     dummy.format   = clazz->glyph_format;
577 
578     /* create result bitmap glyph */
579     error = ft_new_glyph( library, &ft_bitmap_glyph_class, &b );
580     if ( error )
581       goto Exit;
582     bitmap = (FT_BitmapGlyph)b;
583 
584 #if 1
585     /* if `origin' is set, translate the glyph image */
586     if ( origin )
587       FT_Glyph_Transform( glyph, 0, origin );
588 #else
589     FT_UNUSED( origin );
590 #endif
591 
592     /* prepare dummy slot for rendering */
593     error = clazz->glyph_prepare( glyph, &dummy );
594     if ( !error )
595       error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode );
596 
597 #if 1
598     if ( !destroy && origin )
599     {
600       FT_Vector  v;
601 
602 
603       v.x = -origin->x;
604       v.y = -origin->y;
605       FT_Glyph_Transform( glyph, 0, &v );
606     }
607 #endif
608 
609     if ( error )
610       goto Exit;
611 
612     /* in case of success, copy the bitmap to the glyph bitmap */
613     error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy );
614     if ( error )
615       goto Exit;
616 
617     /* copy advance */
618     bitmap->root.advance = glyph->advance;
619 
620     if ( destroy )
621       FT_Done_Glyph( glyph );
622 
623     *the_glyph = FT_GLYPH( bitmap );
624 
625   Exit:
626     if ( error && bitmap )
627       FT_Done_Glyph( FT_GLYPH( bitmap ) );
628 
629     return error;
630 
631   Bad:
632     error = FT_THROW( Invalid_Argument );
633     goto Exit;
634   }
635 
636 
637   /* documentation is in ftglyph.h */
638 
639   FT_EXPORT_DEF( void )
FT_Done_Glyph(FT_Glyph glyph)640   FT_Done_Glyph( FT_Glyph  glyph )
641   {
642     if ( glyph )
643     {
644       FT_Memory              memory = glyph->library->memory;
645       const FT_Glyph_Class*  clazz  = glyph->clazz;
646 
647 
648       if ( clazz->glyph_done )
649         clazz->glyph_done( glyph );
650 
651       FT_FREE( glyph );
652     }
653   }
654 
655 
656 /* END */
657