1 /**************************************************************************** 2 * 3 * ftglyph.c 4 * 5 * FreeType convenience functions to handle glyphs (body). 6 * 7 * Copyright 1996-2018 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 trace_glyph 48 49 50 /*************************************************************************/ 51 /*************************************************************************/ 52 /**** ****/ 53 /**** FT_BitmapGlyph support ****/ 54 /**** ****/ 55 /*************************************************************************/ 56 /*************************************************************************/ 57 58 FT_CALLBACK_DEF( FT_Error ) ft_bitmap_glyph_init(FT_Glyph bitmap_glyph,FT_GlyphSlot slot)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 ) ft_bitmap_glyph_copy(FT_Glyph bitmap_source,FT_Glyph bitmap_target)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 ) ft_bitmap_glyph_done(FT_Glyph bitmap_glyph)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 ) ft_bitmap_glyph_bbox(FT_Glyph bitmap_glyph,FT_BBox * cbox)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 FT_DEFINE_GLYPH(ft_bitmap_glyph_class,sizeof (FT_BitmapGlyphRec),FT_GLYPH_FORMAT_BITMAP,ft_bitmap_glyph_init,ft_bitmap_glyph_done,ft_bitmap_glyph_copy,NULL,ft_bitmap_glyph_bbox,NULL)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 ) ft_outline_glyph_done(FT_Glyph outline_glyph)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 ) ft_outline_glyph_copy(FT_Glyph outline_source,FT_Glyph outline_target)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 ) ft_outline_glyph_transform(FT_Glyph outline_glyph,const FT_Matrix * matrix,const FT_Vector * delta)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 ) ft_outline_glyph_bbox(FT_Glyph outline_glyph,FT_BBox * bbox)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 ) ft_outline_glyph_prepare(FT_Glyph outline_glyph,FT_GlyphSlot slot)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 FT_DEFINE_GLYPH(ft_outline_glyph_class,sizeof (FT_OutlineGlyphRec),FT_GLYPH_FORMAT_OUTLINE,ft_outline_glyph_init,ft_outline_glyph_done,ft_outline_glyph_copy,ft_outline_glyph_transform,ft_outline_glyph_bbox,ft_outline_glyph_prepare)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 ) FT_Glyph_Copy(FT_Glyph source,FT_Glyph * target)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, © ); 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 ) FT_New_Glyph(FT_Library library,FT_Glyph_Format format,FT_Glyph * aglyph)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 ) FT_Get_Glyph(FT_GlyphSlot slot,FT_Glyph * aglyph)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 ) FT_Glyph_Transform(FT_Glyph glyph,FT_Matrix * matrix,FT_Vector * delta)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 ) FT_Glyph_Get_CBox(FT_Glyph glyph,FT_UInt bbox_mode,FT_BBox * acbox)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( acbox->xMax ); 517 acbox->yMax = FT_PIX_CEIL( 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 ) FT_Glyph_To_Bitmap(FT_Glyph * the_glyph,FT_Render_Mode render_mode,FT_Vector * origin,FT_Bool destroy)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 ) FT_Done_Glyph(FT_Glyph glyph)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 */ 657