1/***************************************************************************/
2/*                                                                         */
3/*  ftglyph.c                                                              */
4/*                                                                         */
5/*    FreeType convenience functions to handle glyphs (body).              */
6/*                                                                         */
7/*  Copyright 1996-2017 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 )
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 )
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 )
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 )
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
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 )
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 )
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 )
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 )
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 )
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
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 )
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 )
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    glyph->advance.x = slot->advance.x * 1024;
412    glyph->advance.y = slot->advance.y * 1024;
413
414    /* now import the image from the glyph slot */
415    error = clazz->glyph_init( glyph, slot );
416
417    /* if an error occurred, destroy the glyph */
418    if ( error )
419      FT_Done_Glyph( glyph );
420    else
421      *aglyph = glyph;
422
423  Exit:
424    return error;
425  }
426
427
428  /* documentation is in ftglyph.h */
429
430  FT_EXPORT_DEF( FT_Error )
431  FT_Glyph_Transform( FT_Glyph    glyph,
432                      FT_Matrix*  matrix,
433                      FT_Vector*  delta )
434  {
435    FT_Error  error = FT_Err_Ok;
436
437
438    if ( !glyph || !glyph->clazz )
439      error = FT_THROW( Invalid_Argument );
440    else
441    {
442      const FT_Glyph_Class*  clazz = glyph->clazz;
443
444
445      if ( clazz->glyph_transform )
446      {
447        /* transform glyph image */
448        clazz->glyph_transform( glyph, matrix, delta );
449
450        /* transform advance vector */
451        if ( matrix )
452          FT_Vector_Transform( &glyph->advance, matrix );
453      }
454      else
455        error = FT_THROW( Invalid_Glyph_Format );
456    }
457    return error;
458  }
459
460
461  /* documentation is in ftglyph.h */
462
463  FT_EXPORT_DEF( void )
464  FT_Glyph_Get_CBox( FT_Glyph  glyph,
465                     FT_UInt   bbox_mode,
466                     FT_BBox  *acbox )
467  {
468    const FT_Glyph_Class*  clazz;
469
470
471    if ( !acbox )
472      return;
473
474    acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0;
475
476    if ( !glyph || !glyph->clazz )
477      return;
478
479    clazz = glyph->clazz;
480    if ( !clazz->glyph_bbox )
481      return;
482
483    /* retrieve bbox in 26.6 coordinates */
484    clazz->glyph_bbox( glyph, acbox );
485
486    /* perform grid fitting if needed */
487    if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT ||
488         bbox_mode == FT_GLYPH_BBOX_PIXELS  )
489    {
490      acbox->xMin = FT_PIX_FLOOR( acbox->xMin );
491      acbox->yMin = FT_PIX_FLOOR( acbox->yMin );
492      acbox->xMax = FT_PIX_CEIL( acbox->xMax );
493      acbox->yMax = FT_PIX_CEIL( acbox->yMax );
494    }
495
496    /* convert to integer pixels if needed */
497    if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE ||
498         bbox_mode == FT_GLYPH_BBOX_PIXELS   )
499    {
500      acbox->xMin >>= 6;
501      acbox->yMin >>= 6;
502      acbox->xMax >>= 6;
503      acbox->yMax >>= 6;
504    }
505  }
506
507
508  /* documentation is in ftglyph.h */
509
510  FT_EXPORT_DEF( FT_Error )
511  FT_Glyph_To_Bitmap( FT_Glyph*       the_glyph,
512                      FT_Render_Mode  render_mode,
513                      FT_Vector*      origin,
514                      FT_Bool         destroy )
515  {
516    FT_GlyphSlotRec           dummy;
517    FT_GlyphSlot_InternalRec  dummy_internal;
518    FT_Error                  error = FT_Err_Ok;
519    FT_Glyph                  b, glyph;
520    FT_BitmapGlyph            bitmap = NULL;
521    const FT_Glyph_Class*     clazz;
522
523    /* FT_BITMAP_GLYPH_CLASS_GET dereferences `library' in PIC mode */
524    FT_Library                library;
525
526
527    /* check argument */
528    if ( !the_glyph )
529      goto Bad;
530    glyph = *the_glyph;
531    if ( !glyph )
532      goto Bad;
533
534    clazz   = glyph->clazz;
535    library = glyph->library;
536    if ( !library || !clazz )
537      goto Bad;
538
539    /* when called with a bitmap glyph, do nothing and return successfully */
540    if ( clazz == FT_BITMAP_GLYPH_CLASS_GET )
541      goto Exit;
542
543    if ( !clazz->glyph_prepare )
544      goto Bad;
545
546    /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */
547    /* then calling FT_Render_Glyph_Internal()                            */
548
549    FT_ZERO( &dummy );
550    FT_ZERO( &dummy_internal );
551    dummy.internal = &dummy_internal;
552    dummy.library  = library;
553    dummy.format   = clazz->glyph_format;
554
555    /* create result bitmap glyph */
556    error = ft_new_glyph( library, FT_BITMAP_GLYPH_CLASS_GET, &b );
557    if ( error )
558      goto Exit;
559    bitmap = (FT_BitmapGlyph)b;
560
561#if 1
562    /* if `origin' is set, translate the glyph image */
563    if ( origin )
564      FT_Glyph_Transform( glyph, 0, origin );
565#else
566    FT_UNUSED( origin );
567#endif
568
569    /* prepare dummy slot for rendering */
570    error = clazz->glyph_prepare( glyph, &dummy );
571    if ( !error )
572      error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode );
573
574#if 1
575    if ( !destroy && origin )
576    {
577      FT_Vector  v;
578
579
580      v.x = -origin->x;
581      v.y = -origin->y;
582      FT_Glyph_Transform( glyph, 0, &v );
583    }
584#endif
585
586    if ( error )
587      goto Exit;
588
589    /* in case of success, copy the bitmap to the glyph bitmap */
590    error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy );
591    if ( error )
592      goto Exit;
593
594    /* copy advance */
595    bitmap->root.advance = glyph->advance;
596
597    if ( destroy )
598      FT_Done_Glyph( glyph );
599
600    *the_glyph = FT_GLYPH( bitmap );
601
602  Exit:
603    if ( error && bitmap )
604      FT_Done_Glyph( FT_GLYPH( bitmap ) );
605
606    return error;
607
608  Bad:
609    error = FT_THROW( Invalid_Argument );
610    goto Exit;
611  }
612
613
614  /* documentation is in ftglyph.h */
615
616  FT_EXPORT_DEF( void )
617  FT_Done_Glyph( FT_Glyph  glyph )
618  {
619    if ( glyph )
620    {
621      FT_Memory              memory = glyph->library->memory;
622      const FT_Glyph_Class*  clazz  = glyph->clazz;
623
624
625      if ( clazz->glyph_done )
626        clazz->glyph_done( glyph );
627
628      FT_FREE( glyph );
629    }
630  }
631
632
633/* END */
634