xref: /inferno-os/libfreetype/ftglyph.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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 )
FT_Matrix_Multiply(FT_Matrix * a,FT_Matrix * b)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 )
FT_Matrix_Invert(FT_Matrix * matrix)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
ft_bitmap_copy(FT_Memory memory,FT_Bitmap * source,FT_Bitmap * target)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
ft_bitmap_glyph_init(FT_BitmapGlyph glyph,FT_GlyphSlot slot)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
ft_bitmap_glyph_copy(FT_BitmapGlyph source,FT_BitmapGlyph target)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
ft_bitmap_glyph_done(FT_BitmapGlyph glyph)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
ft_bitmap_glyph_bbox(FT_BitmapGlyph glyph,FT_BBox * cbox)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
ft_outline_glyph_init(FT_OutlineGlyph glyph,FT_GlyphSlot slot)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
ft_outline_glyph_done(FT_OutlineGlyph glyph)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
ft_outline_glyph_copy(FT_OutlineGlyph source,FT_OutlineGlyph target)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
ft_outline_glyph_transform(FT_OutlineGlyph glyph,FT_Matrix * matrix,FT_Vector * delta)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
ft_outline_glyph_bbox(FT_OutlineGlyph glyph,FT_BBox * bbox)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
ft_outline_glyph_prepare(FT_OutlineGlyph glyph,FT_GlyphSlot slot)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
ft_new_glyph(FT_Library library,const FT_Glyph_Class * clazz,FT_Glyph * aglyph)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 )
FT_Glyph_Copy(FT_Glyph source,FT_Glyph * target)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 )
FT_Get_Glyph(FT_GlyphSlot slot,FT_Glyph * aglyph)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 )
FT_Glyph_Transform(FT_Glyph glyph,FT_Matrix * matrix,FT_Vector * delta)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 )
FT_Glyph_Get_CBox(FT_Glyph glyph,FT_UInt bbox_mode,FT_BBox * acbox)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 )
FT_Glyph_To_Bitmap(FT_Glyph * the_glyph,FT_Render_Mode render_mode,FT_Vector * origin,FT_Bool destroy)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 )
FT_Done_Glyph(FT_Glyph glyph)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