| 1 | /**************************************************************************** | 
| 2 |  * | 
| 3 |  * ftglyph.c | 
| 4 |  * | 
| 5 |  *   FreeType convenience functions to handle glyphs (body). | 
| 6 |  * | 
| 7 |  * Copyright (C) 1996-2023 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 <freetype/internal/ftdebug.h> | 
| 32 |  | 
| 33 | #include <freetype/ftglyph.h> | 
| 34 | #include <freetype/ftoutln.h> | 
| 35 | #include <freetype/ftbitmap.h> | 
| 36 | #include <freetype/internal/ftobjs.h> | 
| 37 | #include <freetype/otsvg.h> | 
| 38 |  | 
| 39 | #include "ftbase.h" | 
| 40 |  | 
| 41 |  | 
| 42 |   /************************************************************************** | 
| 43 |    * | 
| 44 |    * The macro FT_COMPONENT is used in trace mode.  It is an implicit | 
| 45 |    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log | 
| 46 |    * messages during execution. | 
| 47 |    */ | 
| 48 | #undef  FT_COMPONENT | 
| 49 | #define FT_COMPONENT  glyph | 
| 50 |  | 
| 51 |  | 
| 52 |   /*************************************************************************/ | 
| 53 |   /*************************************************************************/ | 
| 54 |   /****                                                                 ****/ | 
| 55 |   /****   FT_BitmapGlyph support                                        ****/ | 
| 56 |   /****                                                                 ****/ | 
| 57 |   /*************************************************************************/ | 
| 58 |   /*************************************************************************/ | 
| 59 |  | 
| 60 |   FT_CALLBACK_DEF( FT_Error ) | 
| 61 |   ft_bitmap_glyph_init( FT_Glyph      bitmap_glyph, | 
| 62 |                         FT_GlyphSlot  slot ) | 
| 63 |   { | 
| 64 |     FT_BitmapGlyph  glyph   = (FT_BitmapGlyph)bitmap_glyph; | 
| 65 |     FT_Error        error   = FT_Err_Ok; | 
| 66 |     FT_Library      library = FT_GLYPH( glyph )->library; | 
| 67 |  | 
| 68 |  | 
| 69 |     if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) | 
| 70 |     { | 
| 71 |       error = FT_THROW( Invalid_Glyph_Format ); | 
| 72 |       goto Exit; | 
| 73 |     } | 
| 74 |  | 
| 75 |     glyph->left = slot->bitmap_left; | 
| 76 |     glyph->top  = slot->bitmap_top; | 
| 77 |  | 
| 78 |     /* do lazy copying whenever possible */ | 
| 79 |     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) | 
| 80 |     { | 
| 81 |       glyph->bitmap          = slot->bitmap; | 
| 82 |       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; | 
| 83 |     } | 
| 84 |     else | 
| 85 |     { | 
| 86 |       FT_Bitmap_Init( &glyph->bitmap ); | 
| 87 |       error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap ); | 
| 88 |     } | 
| 89 |  | 
| 90 |   Exit: | 
| 91 |     return error; | 
| 92 |   } | 
| 93 |  | 
| 94 |  | 
| 95 |   FT_CALLBACK_DEF( FT_Error ) | 
| 96 |   ft_bitmap_glyph_copy( FT_Glyph  bitmap_source, | 
| 97 |                         FT_Glyph  bitmap_target ) | 
| 98 |   { | 
| 99 |     FT_Library      library = bitmap_source->library; | 
| 100 |     FT_BitmapGlyph  source  = (FT_BitmapGlyph)bitmap_source; | 
| 101 |     FT_BitmapGlyph  target  = (FT_BitmapGlyph)bitmap_target; | 
| 102 |  | 
| 103 |  | 
| 104 |     target->left = source->left; | 
| 105 |     target->top  = source->top; | 
| 106 |  | 
| 107 |     return FT_Bitmap_Copy( library, &source->bitmap, &target->bitmap ); | 
| 108 |   } | 
| 109 |  | 
| 110 |  | 
| 111 |   FT_CALLBACK_DEF( void ) | 
| 112 |   ft_bitmap_glyph_done( FT_Glyph  bitmap_glyph ) | 
| 113 |   { | 
| 114 |     FT_BitmapGlyph  glyph   = (FT_BitmapGlyph)bitmap_glyph; | 
| 115 |     FT_Library      library = FT_GLYPH( glyph )->library; | 
| 116 |  | 
| 117 |  | 
| 118 |     FT_Bitmap_Done( library, &glyph->bitmap ); | 
| 119 |   } | 
| 120 |  | 
| 121 |  | 
| 122 |   FT_CALLBACK_DEF( void ) | 
| 123 |   ft_bitmap_glyph_bbox( FT_Glyph  bitmap_glyph, | 
| 124 |                         FT_BBox*  cbox ) | 
| 125 |   { | 
| 126 |     FT_BitmapGlyph  glyph = (FT_BitmapGlyph)bitmap_glyph; | 
| 127 |  | 
| 128 |  | 
| 129 |     cbox->xMin = glyph->left * 64; | 
| 130 |     cbox->xMax = cbox->xMin + (FT_Pos)( glyph->bitmap.width * 64 ); | 
| 131 |     cbox->yMax = glyph->top * 64; | 
| 132 |     cbox->yMin = cbox->yMax - (FT_Pos)( glyph->bitmap.rows * 64 ); | 
| 133 |   } | 
| 134 |  | 
| 135 |  | 
| 136 |   FT_DEFINE_GLYPH( | 
| 137 |     ft_bitmap_glyph_class, | 
| 138 |  | 
| 139 |     sizeof ( FT_BitmapGlyphRec ), | 
| 140 |     FT_GLYPH_FORMAT_BITMAP, | 
| 141 |  | 
| 142 |     ft_bitmap_glyph_init,    /* FT_Glyph_InitFunc       glyph_init      */ | 
| 143 |     ft_bitmap_glyph_done,    /* FT_Glyph_DoneFunc       glyph_done      */ | 
| 144 |     ft_bitmap_glyph_copy,    /* FT_Glyph_CopyFunc       glyph_copy      */ | 
| 145 |     NULL,                    /* FT_Glyph_TransformFunc  glyph_transform */ | 
| 146 |     ft_bitmap_glyph_bbox,    /* FT_Glyph_GetBBoxFunc    glyph_bbox      */ | 
| 147 |     NULL                     /* FT_Glyph_PrepareFunc    glyph_prepare   */ | 
| 148 |   ) | 
| 149 |  | 
| 150 |  | 
| 151 |   /*************************************************************************/ | 
| 152 |   /*************************************************************************/ | 
| 153 |   /****                                                                 ****/ | 
| 154 |   /****   FT_OutlineGlyph support                                       ****/ | 
| 155 |   /****                                                                 ****/ | 
| 156 |   /*************************************************************************/ | 
| 157 |   /*************************************************************************/ | 
| 158 |  | 
| 159 |  | 
| 160 |   FT_CALLBACK_DEF( FT_Error ) | 
| 161 |   ft_outline_glyph_init( FT_Glyph      outline_glyph, | 
| 162 |                          FT_GlyphSlot  slot ) | 
| 163 |   { | 
| 164 |     FT_OutlineGlyph  glyph   = (FT_OutlineGlyph)outline_glyph; | 
| 165 |     FT_Error         error   = FT_Err_Ok; | 
| 166 |     FT_Library       library = FT_GLYPH( glyph )->library; | 
| 167 |     FT_Outline*      source  = &slot->outline; | 
| 168 |     FT_Outline*      target  = &glyph->outline; | 
| 169 |  | 
| 170 |  | 
| 171 |     /* check format in glyph slot */ | 
| 172 |     if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) | 
| 173 |     { | 
| 174 |       error = FT_THROW( Invalid_Glyph_Format ); | 
| 175 |       goto Exit; | 
| 176 |     } | 
| 177 |  | 
| 178 |     /* allocate new outline */ | 
| 179 |     error = FT_Outline_New( library, | 
| 180 |                             (FT_UInt)source->n_points, | 
| 181 |                             source->n_contours, | 
| 182 |                             &glyph->outline ); | 
| 183 |     if ( error ) | 
| 184 |       goto Exit; | 
| 185 |  | 
| 186 |     FT_Outline_Copy( source, target ); | 
| 187 |  | 
| 188 |   Exit: | 
| 189 |     return error; | 
| 190 |   } | 
| 191 |  | 
| 192 |  | 
| 193 |   FT_CALLBACK_DEF( void ) | 
| 194 |   ft_outline_glyph_done( FT_Glyph  outline_glyph ) | 
| 195 |   { | 
| 196 |     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph; | 
| 197 |  | 
| 198 |  | 
| 199 |     FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline ); | 
| 200 |   } | 
| 201 |  | 
| 202 |  | 
| 203 |   FT_CALLBACK_DEF( FT_Error ) | 
| 204 |   ft_outline_glyph_copy( FT_Glyph  outline_source, | 
| 205 |                          FT_Glyph  outline_target ) | 
| 206 |   { | 
| 207 |     FT_OutlineGlyph  source  = (FT_OutlineGlyph)outline_source; | 
| 208 |     FT_OutlineGlyph  target  = (FT_OutlineGlyph)outline_target; | 
| 209 |     FT_Error         error; | 
| 210 |     FT_Library       library = FT_GLYPH( source )->library; | 
| 211 |  | 
| 212 |  | 
| 213 |     error = FT_Outline_New( library, | 
| 214 |                             (FT_UInt)source->outline.n_points, | 
| 215 |                             source->outline.n_contours, | 
| 216 |                             &target->outline ); | 
| 217 |     if ( !error ) | 
| 218 |       FT_Outline_Copy( &source->outline, &target->outline ); | 
| 219 |  | 
| 220 |     return error; | 
| 221 |   } | 
| 222 |  | 
| 223 |  | 
| 224 |   FT_CALLBACK_DEF( void ) | 
| 225 |   ft_outline_glyph_transform( FT_Glyph          outline_glyph, | 
| 226 |                               const FT_Matrix*  matrix, | 
| 227 |                               const FT_Vector*  delta ) | 
| 228 |   { | 
| 229 |     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph; | 
| 230 |  | 
| 231 |  | 
| 232 |     if ( matrix ) | 
| 233 |       FT_Outline_Transform( &glyph->outline, matrix ); | 
| 234 |  | 
| 235 |     if ( delta ) | 
| 236 |       FT_Outline_Translate( &glyph->outline, delta->x, delta->y ); | 
| 237 |   } | 
| 238 |  | 
| 239 |  | 
| 240 |   FT_CALLBACK_DEF( void ) | 
| 241 |   ft_outline_glyph_bbox( FT_Glyph  outline_glyph, | 
| 242 |                          FT_BBox*  bbox ) | 
| 243 |   { | 
| 244 |     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph; | 
| 245 |  | 
| 246 |  | 
| 247 |     FT_Outline_Get_CBox( &glyph->outline, bbox ); | 
| 248 |   } | 
| 249 |  | 
| 250 |  | 
| 251 |   FT_CALLBACK_DEF( FT_Error ) | 
| 252 |   ft_outline_glyph_prepare( FT_Glyph      outline_glyph, | 
| 253 |                             FT_GlyphSlot  slot ) | 
| 254 |   { | 
| 255 |     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph; | 
| 256 |  | 
| 257 |  | 
| 258 |     slot->format         = FT_GLYPH_FORMAT_OUTLINE; | 
| 259 |     slot->outline        = glyph->outline; | 
| 260 |     slot->outline.flags &= ~FT_OUTLINE_OWNER; | 
| 261 |  | 
| 262 |     return FT_Err_Ok; | 
| 263 |   } | 
| 264 |  | 
| 265 |  | 
| 266 |   FT_DEFINE_GLYPH( | 
| 267 |     ft_outline_glyph_class, | 
| 268 |  | 
| 269 |     sizeof ( FT_OutlineGlyphRec ), | 
| 270 |     FT_GLYPH_FORMAT_OUTLINE, | 
| 271 |  | 
| 272 |     ft_outline_glyph_init,      /* FT_Glyph_InitFunc       glyph_init      */ | 
| 273 |     ft_outline_glyph_done,      /* FT_Glyph_DoneFunc       glyph_done      */ | 
| 274 |     ft_outline_glyph_copy,      /* FT_Glyph_CopyFunc       glyph_copy      */ | 
| 275 |     ft_outline_glyph_transform, /* FT_Glyph_TransformFunc  glyph_transform */ | 
| 276 |     ft_outline_glyph_bbox,      /* FT_Glyph_GetBBoxFunc    glyph_bbox      */ | 
| 277 |     ft_outline_glyph_prepare    /* FT_Glyph_PrepareFunc    glyph_prepare   */ | 
| 278 |   ) | 
| 279 |  | 
| 280 |  | 
| 281 | #ifdef FT_CONFIG_OPTION_SVG | 
| 282 |  | 
| 283 |   /*************************************************************************/ | 
| 284 |   /*************************************************************************/ | 
| 285 |   /****                                                                 ****/ | 
| 286 |   /****   FT_SvgGlyph support                                           ****/ | 
| 287 |   /****                                                                 ****/ | 
| 288 |   /*************************************************************************/ | 
| 289 |   /*************************************************************************/ | 
| 290 |  | 
| 291 |  | 
| 292 |   FT_CALLBACK_DEF( FT_Error ) | 
| 293 |   ft_svg_glyph_init( FT_Glyph      svg_glyph, | 
| 294 |                      FT_GlyphSlot  slot ) | 
| 295 |   { | 
| 296 |     FT_ULong         doc_length; | 
| 297 |     FT_SVG_Document  document; | 
| 298 |     FT_SvgGlyph      glyph = (FT_SvgGlyph)svg_glyph; | 
| 299 |  | 
| 300 |     FT_Error   error  = FT_Err_Ok; | 
| 301 |     FT_Memory  memory = FT_GLYPH( glyph )->library->memory; | 
| 302 |  | 
| 303 |  | 
| 304 |     if ( slot->format != FT_GLYPH_FORMAT_SVG ) | 
| 305 |     { | 
| 306 |       error = FT_THROW( Invalid_Glyph_Format ); | 
| 307 |       goto Exit; | 
| 308 |     } | 
| 309 |  | 
| 310 |     if ( slot->other == NULL ) | 
| 311 |     { | 
| 312 |       error = FT_THROW( Invalid_Slot_Handle ); | 
| 313 |       goto Exit; | 
| 314 |     } | 
| 315 |  | 
| 316 |     document = (FT_SVG_Document)slot->other; | 
| 317 |  | 
| 318 |     if ( document->svg_document_length == 0 ) | 
| 319 |     { | 
| 320 |       error = FT_THROW( Invalid_Slot_Handle ); | 
| 321 |       goto Exit; | 
| 322 |     } | 
| 323 |  | 
| 324 |     /* allocate a new document */ | 
| 325 |     doc_length = document->svg_document_length; | 
| 326 |     if ( FT_QALLOC( glyph->svg_document, doc_length ) ) | 
| 327 |       goto Exit; | 
| 328 |     glyph->svg_document_length = doc_length; | 
| 329 |  | 
| 330 |     glyph->glyph_index = slot->glyph_index; | 
| 331 |  | 
| 332 |     glyph->metrics      = document->metrics; | 
| 333 |     glyph->units_per_EM = document->units_per_EM; | 
| 334 |  | 
| 335 |     glyph->start_glyph_id = document->start_glyph_id; | 
| 336 |     glyph->end_glyph_id   = document->end_glyph_id; | 
| 337 |  | 
| 338 |     glyph->transform = document->transform; | 
| 339 |     glyph->delta     = document->delta; | 
| 340 |  | 
| 341 |     /* copy the document into glyph */ | 
| 342 |     FT_MEM_COPY( glyph->svg_document, document->svg_document, doc_length ); | 
| 343 |  | 
| 344 |   Exit: | 
| 345 |     return error; | 
| 346 |   } | 
| 347 |  | 
| 348 |  | 
| 349 |   FT_CALLBACK_DEF( void ) | 
| 350 |   ft_svg_glyph_done( FT_Glyph  svg_glyph ) | 
| 351 |   { | 
| 352 |     FT_SvgGlyph  glyph  = (FT_SvgGlyph)svg_glyph; | 
| 353 |     FT_Memory    memory = svg_glyph->library->memory; | 
| 354 |  | 
| 355 |  | 
| 356 |     /* just free the memory */ | 
| 357 |     FT_FREE( glyph->svg_document ); | 
| 358 |   } | 
| 359 |  | 
| 360 |  | 
| 361 |   FT_CALLBACK_DEF( FT_Error ) | 
| 362 |   ft_svg_glyph_copy( FT_Glyph  svg_source, | 
| 363 |                      FT_Glyph  svg_target ) | 
| 364 |   { | 
| 365 |     FT_SvgGlyph  source = (FT_SvgGlyph)svg_source; | 
| 366 |     FT_SvgGlyph  target = (FT_SvgGlyph)svg_target; | 
| 367 |  | 
| 368 |     FT_Error   error  = FT_Err_Ok; | 
| 369 |     FT_Memory  memory = FT_GLYPH( source )->library->memory; | 
| 370 |  | 
| 371 |  | 
| 372 |     if ( svg_source->format != FT_GLYPH_FORMAT_SVG ) | 
| 373 |     { | 
| 374 |       error = FT_THROW( Invalid_Glyph_Format ); | 
| 375 |       goto Exit; | 
| 376 |     } | 
| 377 |  | 
| 378 |     if ( source->svg_document_length == 0 ) | 
| 379 |     { | 
| 380 |       error = FT_THROW( Invalid_Slot_Handle ); | 
| 381 |       goto Exit; | 
| 382 |     } | 
| 383 |  | 
| 384 |     target->glyph_index = source->glyph_index; | 
| 385 |  | 
| 386 |     target->svg_document_length = source->svg_document_length; | 
| 387 |  | 
| 388 |     target->metrics      = source->metrics; | 
| 389 |     target->units_per_EM = source->units_per_EM; | 
| 390 |  | 
| 391 |     target->start_glyph_id = source->start_glyph_id; | 
| 392 |     target->end_glyph_id   = source->end_glyph_id; | 
| 393 |  | 
| 394 |     target->transform = source->transform; | 
| 395 |     target->delta     = source->delta; | 
| 396 |  | 
| 397 |     /* allocate space for the SVG document */ | 
| 398 |     if ( FT_QALLOC( target->svg_document, target->svg_document_length ) ) | 
| 399 |       goto Exit; | 
| 400 |  | 
| 401 |     /* copy the document */ | 
| 402 |     FT_MEM_COPY( target->svg_document, | 
| 403 |                  source->svg_document, | 
| 404 |                  target->svg_document_length ); | 
| 405 |  | 
| 406 |   Exit: | 
| 407 |     return error; | 
| 408 |   } | 
| 409 |  | 
| 410 |  | 
| 411 |   FT_CALLBACK_DEF( void ) | 
| 412 |   ft_svg_glyph_transform( FT_Glyph          svg_glyph, | 
| 413 |                           const FT_Matrix*  _matrix, | 
| 414 |                           const FT_Vector*  _delta ) | 
| 415 |   { | 
| 416 |     FT_SvgGlyph  glyph  = (FT_SvgGlyph)svg_glyph; | 
| 417 |     FT_Matrix*   matrix = (FT_Matrix*)_matrix; | 
| 418 |     FT_Vector*   delta  = (FT_Vector*)_delta; | 
| 419 |  | 
| 420 |     FT_Matrix  tmp_matrix; | 
| 421 |     FT_Vector  tmp_delta; | 
| 422 |  | 
| 423 |     FT_Matrix  a, b; | 
| 424 |     FT_Pos     x, y; | 
| 425 |  | 
| 426 |  | 
| 427 |     if ( !matrix ) | 
| 428 |     { | 
| 429 |       tmp_matrix.xx = 0x10000; | 
| 430 |       tmp_matrix.xy = 0; | 
| 431 |       tmp_matrix.yx = 0; | 
| 432 |       tmp_matrix.yy = 0x10000; | 
| 433 |  | 
| 434 |       matrix = &tmp_matrix; | 
| 435 |     } | 
| 436 |  | 
| 437 |     if ( !delta ) | 
| 438 |     { | 
| 439 |       tmp_delta.x = 0; | 
| 440 |       tmp_delta.y = 0; | 
| 441 |  | 
| 442 |       delta = &tmp_delta; | 
| 443 |     } | 
| 444 |  | 
| 445 |     a = glyph->transform; | 
| 446 |     b = *matrix; | 
| 447 |     FT_Matrix_Multiply( &b, &a ); | 
| 448 |  | 
| 449 |     x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, glyph->delta.x ), | 
| 450 |                             FT_MulFix( matrix->xy, glyph->delta.y ) ), | 
| 451 |                   delta->x ); | 
| 452 |     y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, glyph->delta.x ), | 
| 453 |                             FT_MulFix( matrix->yy, glyph->delta.y ) ), | 
| 454 |                   delta->y ); | 
| 455 |  | 
| 456 |     glyph->delta.x = x; | 
| 457 |     glyph->delta.y = y; | 
| 458 |  | 
| 459 |     glyph->transform = a; | 
| 460 |   } | 
| 461 |  | 
| 462 |  | 
| 463 |   FT_CALLBACK_DEF( FT_Error ) | 
| 464 |   ft_svg_glyph_prepare( FT_Glyph      svg_glyph, | 
| 465 |                         FT_GlyphSlot  slot ) | 
| 466 |   { | 
| 467 |     FT_SvgGlyph  glyph = (FT_SvgGlyph)svg_glyph; | 
| 468 |  | 
| 469 |     FT_Error   error  = FT_Err_Ok; | 
| 470 |     FT_Memory  memory = svg_glyph->library->memory; | 
| 471 |  | 
| 472 |     FT_SVG_Document  document = NULL; | 
| 473 |  | 
| 474 |  | 
| 475 |     if ( FT_NEW( document ) ) | 
| 476 |       return error; | 
| 477 |  | 
| 478 |     document->svg_document        = glyph->svg_document; | 
| 479 |     document->svg_document_length = glyph->svg_document_length; | 
| 480 |  | 
| 481 |     document->metrics      = glyph->metrics; | 
| 482 |     document->units_per_EM = glyph->units_per_EM; | 
| 483 |  | 
| 484 |     document->start_glyph_id = glyph->start_glyph_id; | 
| 485 |     document->end_glyph_id   = glyph->end_glyph_id; | 
| 486 |  | 
| 487 |     document->transform = glyph->transform; | 
| 488 |     document->delta     = glyph->delta; | 
| 489 |  | 
| 490 |     slot->format      = FT_GLYPH_FORMAT_SVG; | 
| 491 |     slot->glyph_index = glyph->glyph_index; | 
| 492 |     slot->other       = document; | 
| 493 |  | 
| 494 |     return error; | 
| 495 |   } | 
| 496 |  | 
| 497 |  | 
| 498 |   FT_DEFINE_GLYPH( | 
| 499 |     ft_svg_glyph_class, | 
| 500 |  | 
| 501 |     sizeof ( FT_SvgGlyphRec ), | 
| 502 |     FT_GLYPH_FORMAT_SVG, | 
| 503 |  | 
| 504 |     ft_svg_glyph_init,      /* FT_Glyph_InitFunc       glyph_init      */ | 
| 505 |     ft_svg_glyph_done,      /* FT_Glyph_DoneFunc       glyph_done      */ | 
| 506 |     ft_svg_glyph_copy,      /* FT_Glyph_CopyFunc       glyph_copy      */ | 
| 507 |     ft_svg_glyph_transform, /* FT_Glyph_TransformFunc  glyph_transform */ | 
| 508 |     NULL,                   /* FT_Glyph_GetBBoxFunc    glyph_bbox      */ | 
| 509 |     ft_svg_glyph_prepare    /* FT_Glyph_PrepareFunc    glyph_prepare   */ | 
| 510 |   ) | 
| 511 |  | 
| 512 | #endif /* FT_CONFIG_OPTION_SVG */ | 
| 513 |  | 
| 514 |  | 
| 515 |   /*************************************************************************/ | 
| 516 |   /*************************************************************************/ | 
| 517 |   /****                                                                 ****/ | 
| 518 |   /****   FT_Glyph class and API                                        ****/ | 
| 519 |   /****                                                                 ****/ | 
| 520 |   /*************************************************************************/ | 
| 521 |   /*************************************************************************/ | 
| 522 |  | 
| 523 |    static FT_Error | 
| 524 |    ft_new_glyph( FT_Library             library, | 
| 525 |                  const FT_Glyph_Class*  clazz, | 
| 526 |                  FT_Glyph*              aglyph ) | 
| 527 |    { | 
| 528 |      FT_Memory  memory = library->memory; | 
| 529 |      FT_Error   error; | 
| 530 |      FT_Glyph   glyph  = NULL; | 
| 531 |  | 
| 532 |  | 
| 533 |      *aglyph = NULL; | 
| 534 |  | 
| 535 |      if ( !FT_ALLOC( glyph, clazz->glyph_size ) ) | 
| 536 |      { | 
| 537 |        glyph->library = library; | 
| 538 |        glyph->clazz   = clazz; | 
| 539 |        glyph->format  = clazz->glyph_format; | 
| 540 |  | 
| 541 |        *aglyph = glyph; | 
| 542 |      } | 
| 543 |  | 
| 544 |      return error; | 
| 545 |    } | 
| 546 |  | 
| 547 |  | 
| 548 |   /* documentation is in ftglyph.h */ | 
| 549 |  | 
| 550 |   FT_EXPORT_DEF( FT_Error ) | 
| 551 |   FT_Glyph_Copy( FT_Glyph   source, | 
| 552 |                  FT_Glyph  *target ) | 
| 553 |   { | 
| 554 |     FT_Glyph               copy; | 
| 555 |     FT_Error               error; | 
| 556 |     const FT_Glyph_Class*  clazz; | 
| 557 |  | 
| 558 |  | 
| 559 |     /* check arguments */ | 
| 560 |     if ( !target || !source || !source->clazz ) | 
| 561 |     { | 
| 562 |       error = FT_THROW( Invalid_Argument ); | 
| 563 |       goto Exit; | 
| 564 |     } | 
| 565 |  | 
| 566 |     *target = NULL; | 
| 567 |  | 
| 568 |     if ( !source || !source->clazz ) | 
| 569 |     { | 
| 570 |       error = FT_THROW( Invalid_Argument ); | 
| 571 |       goto Exit; | 
| 572 |     } | 
| 573 |  | 
| 574 |     clazz = source->clazz; | 
| 575 |     error = ft_new_glyph( source->library, clazz, © ); | 
| 576 |     if ( error ) | 
| 577 |       goto Exit; | 
| 578 |  | 
| 579 |     copy->advance = source->advance; | 
| 580 |     copy->format  = source->format; | 
| 581 |  | 
| 582 |     if ( clazz->glyph_copy ) | 
| 583 |       error = clazz->glyph_copy( source, copy ); | 
| 584 |  | 
| 585 |     if ( error ) | 
| 586 |       FT_Done_Glyph( copy ); | 
| 587 |     else | 
| 588 |       *target = copy; | 
| 589 |  | 
| 590 |   Exit: | 
| 591 |     return error; | 
| 592 |   } | 
| 593 |  | 
| 594 |  | 
| 595 |   /* documentation is in ftglyph.h */ | 
| 596 |  | 
| 597 |   FT_EXPORT( FT_Error ) | 
| 598 |   FT_New_Glyph( FT_Library       library, | 
| 599 |                 FT_Glyph_Format  format, | 
| 600 |                 FT_Glyph        *aglyph ) | 
| 601 |   { | 
| 602 |     const FT_Glyph_Class*  clazz = NULL; | 
| 603 |  | 
| 604 |     if ( !library || !aglyph ) | 
| 605 |       return FT_THROW( Invalid_Argument ); | 
| 606 |  | 
| 607 |     /* if it is a bitmap, that's easy :-) */ | 
| 608 |     if ( format == FT_GLYPH_FORMAT_BITMAP ) | 
| 609 |       clazz = &ft_bitmap_glyph_class; | 
| 610 |  | 
| 611 |     /* if it is an outline */ | 
| 612 |     else if ( format == FT_GLYPH_FORMAT_OUTLINE ) | 
| 613 |       clazz = &ft_outline_glyph_class; | 
| 614 |  | 
| 615 | #ifdef FT_CONFIG_OPTION_SVG | 
| 616 |     /* if it is an SVG glyph */ | 
| 617 |     else if ( format == FT_GLYPH_FORMAT_SVG ) | 
| 618 |       clazz = &ft_svg_glyph_class; | 
| 619 | #endif | 
| 620 |  | 
| 621 |     else | 
| 622 |     { | 
| 623 |       /* try to find a renderer that supports the glyph image format */ | 
| 624 |       FT_Renderer  render = FT_Lookup_Renderer( library, format, 0 ); | 
| 625 |  | 
| 626 |  | 
| 627 |       if ( render ) | 
| 628 |         clazz = &render->glyph_class; | 
| 629 |     } | 
| 630 |  | 
| 631 |     if ( !clazz ) | 
| 632 |       return FT_THROW( Invalid_Glyph_Format ); | 
| 633 |  | 
| 634 |     /* create FT_Glyph object */ | 
| 635 |     return ft_new_glyph( library, clazz, aglyph ); | 
| 636 |   } | 
| 637 |  | 
| 638 |  | 
| 639 |   /* documentation is in ftglyph.h */ | 
| 640 |  | 
| 641 |   FT_EXPORT_DEF( FT_Error ) | 
| 642 |   FT_Get_Glyph( FT_GlyphSlot  slot, | 
| 643 |                 FT_Glyph     *aglyph ) | 
| 644 |   { | 
| 645 |     FT_Error  error; | 
| 646 |     FT_Glyph  glyph; | 
| 647 |  | 
| 648 |  | 
| 649 |     if ( !slot ) | 
| 650 |       return FT_THROW( Invalid_Slot_Handle ); | 
| 651 |  | 
| 652 |     if ( !aglyph ) | 
| 653 |       return FT_THROW( Invalid_Argument ); | 
| 654 |  | 
| 655 |     /* create FT_Glyph object */ | 
| 656 |     error = FT_New_Glyph( slot->library, slot->format, &glyph ); | 
| 657 |     if ( error ) | 
| 658 |       goto Exit; | 
| 659 |  | 
| 660 |     /* copy advance while converting 26.6 to 16.16 format */ | 
| 661 |     if ( slot->advance.x >=  0x8000L * 64 || | 
| 662 |          slot->advance.x <= -0x8000L * 64 ) | 
| 663 |     { | 
| 664 |       FT_ERROR(( "FT_Get_Glyph: advance width too large\n"  )); | 
| 665 |       error = FT_THROW( Invalid_Argument ); | 
| 666 |       goto Exit2; | 
| 667 |     } | 
| 668 |     if ( slot->advance.y >=  0x8000L * 64 || | 
| 669 |          slot->advance.y <= -0x8000L * 64 ) | 
| 670 |     { | 
| 671 |       FT_ERROR(( "FT_Get_Glyph: advance height too large\n"  )); | 
| 672 |       error = FT_THROW( Invalid_Argument ); | 
| 673 |       goto Exit2; | 
| 674 |     } | 
| 675 |  | 
| 676 |     glyph->advance.x = slot->advance.x * 1024; | 
| 677 |     glyph->advance.y = slot->advance.y * 1024; | 
| 678 |  | 
| 679 |     /* now import the image from the glyph slot */ | 
| 680 |     error = glyph->clazz->glyph_init( glyph, slot ); | 
| 681 |  | 
| 682 |   Exit2: | 
| 683 |     /* if an error occurred, destroy the glyph */ | 
| 684 |     if ( error ) | 
| 685 |     { | 
| 686 |       FT_Done_Glyph( glyph ); | 
| 687 |       *aglyph = NULL; | 
| 688 |     } | 
| 689 |     else | 
| 690 |       *aglyph = glyph; | 
| 691 |  | 
| 692 |   Exit: | 
| 693 |     return error; | 
| 694 |   } | 
| 695 |  | 
| 696 |  | 
| 697 |   /* documentation is in ftglyph.h */ | 
| 698 |  | 
| 699 |   FT_EXPORT_DEF( FT_Error ) | 
| 700 |   FT_Glyph_Transform( FT_Glyph          glyph, | 
| 701 |                       const FT_Matrix*  matrix, | 
| 702 |                       const FT_Vector*  delta ) | 
| 703 |   { | 
| 704 |     FT_Error  error = FT_Err_Ok; | 
| 705 |  | 
| 706 |  | 
| 707 |     if ( !glyph || !glyph->clazz ) | 
| 708 |       error = FT_THROW( Invalid_Argument ); | 
| 709 |     else | 
| 710 |     { | 
| 711 |       const FT_Glyph_Class*  clazz = glyph->clazz; | 
| 712 |  | 
| 713 |  | 
| 714 |       if ( clazz->glyph_transform ) | 
| 715 |       { | 
| 716 |         /* transform glyph image */ | 
| 717 |         clazz->glyph_transform( glyph, matrix, delta ); | 
| 718 |  | 
| 719 |         /* transform advance vector */ | 
| 720 |         if ( matrix ) | 
| 721 |           FT_Vector_Transform( &glyph->advance, matrix ); | 
| 722 |       } | 
| 723 |       else | 
| 724 |         error = FT_THROW( Invalid_Glyph_Format ); | 
| 725 |     } | 
| 726 |     return error; | 
| 727 |   } | 
| 728 |  | 
| 729 |  | 
| 730 |   /* documentation is in ftglyph.h */ | 
| 731 |  | 
| 732 |   FT_EXPORT_DEF( void ) | 
| 733 |   FT_Glyph_Get_CBox( FT_Glyph  glyph, | 
| 734 |                      FT_UInt   bbox_mode, | 
| 735 |                      FT_BBox  *acbox ) | 
| 736 |   { | 
| 737 |     const FT_Glyph_Class*  clazz; | 
| 738 |  | 
| 739 |  | 
| 740 |     if ( !acbox ) | 
| 741 |       return; | 
| 742 |  | 
| 743 |     acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0; | 
| 744 |  | 
| 745 |     if ( !glyph || !glyph->clazz ) | 
| 746 |       return; | 
| 747 |  | 
| 748 |     clazz = glyph->clazz; | 
| 749 |     if ( !clazz->glyph_bbox ) | 
| 750 |       return; | 
| 751 |  | 
| 752 |     /* retrieve bbox in 26.6 coordinates */ | 
| 753 |     clazz->glyph_bbox( glyph, acbox ); | 
| 754 |  | 
| 755 |     /* perform grid fitting if needed */ | 
| 756 |     if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT || | 
| 757 |          bbox_mode == FT_GLYPH_BBOX_PIXELS  ) | 
| 758 |     { | 
| 759 |       acbox->xMin = FT_PIX_FLOOR( acbox->xMin ); | 
| 760 |       acbox->yMin = FT_PIX_FLOOR( acbox->yMin ); | 
| 761 |       acbox->xMax = FT_PIX_CEIL_LONG( acbox->xMax ); | 
| 762 |       acbox->yMax = FT_PIX_CEIL_LONG( acbox->yMax ); | 
| 763 |     } | 
| 764 |  | 
| 765 |     /* convert to integer pixels if needed */ | 
| 766 |     if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE || | 
| 767 |          bbox_mode == FT_GLYPH_BBOX_PIXELS   ) | 
| 768 |     { | 
| 769 |       acbox->xMin >>= 6; | 
| 770 |       acbox->yMin >>= 6; | 
| 771 |       acbox->xMax >>= 6; | 
| 772 |       acbox->yMax >>= 6; | 
| 773 |     } | 
| 774 |   } | 
| 775 |  | 
| 776 |  | 
| 777 |   /* documentation is in ftglyph.h */ | 
| 778 |  | 
| 779 |   FT_EXPORT_DEF( FT_Error ) | 
| 780 |   FT_Glyph_To_Bitmap( FT_Glyph*         the_glyph, | 
| 781 |                       FT_Render_Mode    render_mode, | 
| 782 |                       const FT_Vector*  origin, | 
| 783 |                       FT_Bool           destroy ) | 
| 784 |   { | 
| 785 |     FT_GlyphSlotRec           dummy; | 
| 786 |     FT_GlyphSlot_InternalRec  dummy_internal; | 
| 787 |     FT_Error                  error = FT_Err_Ok; | 
| 788 |     FT_Glyph                  b, glyph; | 
| 789 |     FT_BitmapGlyph            bitmap = NULL; | 
| 790 |     const FT_Glyph_Class*     clazz; | 
| 791 |  | 
| 792 |     FT_Library                library; | 
| 793 |  | 
| 794 |  | 
| 795 |     /* check argument */ | 
| 796 |     if ( !the_glyph ) | 
| 797 |       goto Bad; | 
| 798 |     glyph = *the_glyph; | 
| 799 |     if ( !glyph ) | 
| 800 |       goto Bad; | 
| 801 |  | 
| 802 |     clazz   = glyph->clazz; | 
| 803 |     library = glyph->library; | 
| 804 |     if ( !library || !clazz ) | 
| 805 |       goto Bad; | 
| 806 |  | 
| 807 |     /* when called with a bitmap glyph, do nothing and return successfully */ | 
| 808 |     if ( clazz == &ft_bitmap_glyph_class ) | 
| 809 |       goto Exit; | 
| 810 |  | 
| 811 |     if ( !clazz->glyph_prepare ) | 
| 812 |       goto Bad; | 
| 813 |  | 
| 814 |     /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */ | 
| 815 |     /* then calling FT_Render_Glyph_Internal()                            */ | 
| 816 |  | 
| 817 |     FT_ZERO( &dummy ); | 
| 818 |     FT_ZERO( &dummy_internal ); | 
| 819 |     dummy.internal = &dummy_internal; | 
| 820 |     dummy.library  = library; | 
| 821 |     dummy.format   = clazz->glyph_format; | 
| 822 |  | 
| 823 |     /* create result bitmap glyph */ | 
| 824 |     error = ft_new_glyph( library, &ft_bitmap_glyph_class, &b ); | 
| 825 |     if ( error ) | 
| 826 |       goto Exit; | 
| 827 |     bitmap = (FT_BitmapGlyph)b; | 
| 828 |  | 
| 829 | #if 1 | 
| 830 |     /* if `origin' is set, translate the glyph image */ | 
| 831 |     if ( origin ) | 
| 832 |       FT_Glyph_Transform( glyph, NULL, origin ); | 
| 833 | #else | 
| 834 |     FT_UNUSED( origin ); | 
| 835 | #endif | 
| 836 |  | 
| 837 |     /* prepare dummy slot for rendering */ | 
| 838 |     error = clazz->glyph_prepare( glyph, &dummy ); | 
| 839 |     if ( !error ) | 
| 840 |       error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode ); | 
| 841 |  | 
| 842 | #ifdef FT_CONFIG_OPTION_SVG | 
| 843 |     if ( clazz == &ft_svg_glyph_class ) | 
| 844 |     { | 
| 845 |       FT_Memory  memory = library->memory; | 
| 846 |  | 
| 847 |  | 
| 848 |       FT_FREE( dummy.other ); | 
| 849 |     } | 
| 850 | #endif | 
| 851 |  | 
| 852 | #if 1 | 
| 853 |     if ( !destroy && origin ) | 
| 854 |     { | 
| 855 |       FT_Vector  v; | 
| 856 |  | 
| 857 |  | 
| 858 |       v.x = -origin->x; | 
| 859 |       v.y = -origin->y; | 
| 860 |       FT_Glyph_Transform( glyph, NULL, &v ); | 
| 861 |     } | 
| 862 | #endif | 
| 863 |  | 
| 864 |     if ( error ) | 
| 865 |       goto Exit; | 
| 866 |  | 
| 867 |     /* in case of success, copy the bitmap to the glyph bitmap */ | 
| 868 |     error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy ); | 
| 869 |     if ( error ) | 
| 870 |       goto Exit; | 
| 871 |  | 
| 872 |     /* copy advance */ | 
| 873 |     bitmap->root.advance = glyph->advance; | 
| 874 |  | 
| 875 |     if ( destroy ) | 
| 876 |       FT_Done_Glyph( glyph ); | 
| 877 |  | 
| 878 |     *the_glyph = FT_GLYPH( bitmap ); | 
| 879 |  | 
| 880 |   Exit: | 
| 881 |     if ( error && bitmap ) | 
| 882 |       FT_Done_Glyph( FT_GLYPH( bitmap ) ); | 
| 883 |  | 
| 884 |     return error; | 
| 885 |  | 
| 886 |   Bad: | 
| 887 |     error = FT_THROW( Invalid_Argument ); | 
| 888 |     goto Exit; | 
| 889 |   } | 
| 890 |  | 
| 891 |  | 
| 892 |   /* documentation is in ftglyph.h */ | 
| 893 |  | 
| 894 |   FT_EXPORT_DEF( void ) | 
| 895 |   FT_Done_Glyph( FT_Glyph  glyph ) | 
| 896 |   { | 
| 897 |     if ( glyph ) | 
| 898 |     { | 
| 899 |       FT_Memory              memory = glyph->library->memory; | 
| 900 |       const FT_Glyph_Class*  clazz  = glyph->clazz; | 
| 901 |  | 
| 902 |  | 
| 903 |       if ( clazz->glyph_done ) | 
| 904 |         clazz->glyph_done( glyph ); | 
| 905 |  | 
| 906 |       FT_FREE( glyph ); | 
| 907 |     } | 
| 908 |   } | 
| 909 |  | 
| 910 |  | 
| 911 | /* END */ | 
| 912 |  |