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