1 /****************************************************************************
   2  *
   3  * ftglyph.c
   4  *
   5  *   FreeType convenience functions to handle glyphs (body).
   6  *
   7  * Copyright (C) 1996-2019 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  glyph
  48 
  49 
  50   /*************************************************************************/
  51   /*************************************************************************/
  52   /****                                                                 ****/
  53   /****   FT_BitmapGlyph support                                        ****/
  54   /****                                                                 ****/
  55   /*************************************************************************/
  56   /*************************************************************************/
  57 
  58   FT_CALLBACK_DEF( FT_Error )
  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 )
  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 )
 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 )
 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 
 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 )
 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 )
 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 )
 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 )
 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 )
 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 
 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 )
 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 )
 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 )
 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 )
 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 )
 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_LONG( acbox->xMax );
 517       acbox->yMax = FT_PIX_CEIL_LONG( 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 )
 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 )
 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 */