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