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