1 /**************************************************************************** 2 * 3 * ftbitmap.c 4 * 5 * FreeType utility functions for bitmaps (body). 6 * 7 * Copyright (C) 2004-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 #include <freetype/internal/ftdebug.h> 20 21 #include <freetype/ftbitmap.h> 22 #include <freetype/ftimage.h> 23 #include <freetype/internal/ftobjs.h> 24 25 26 /************************************************************************** 27 * 28 * The macro FT_COMPONENT is used in trace mode. It is an implicit 29 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 30 * messages during execution. 31 */ 32 #undef FT_COMPONENT 33 #define FT_COMPONENT bitmap 34 35 36 static 37 const FT_Bitmap null_bitmap = { 0, 0, 0, NULL, 0, 0, 0, NULL }; 38 39 40 /* documentation is in ftbitmap.h */ 41 42 FT_EXPORT_DEF( void ) FT_Bitmap_Init(FT_Bitmap * abitmap)43 FT_Bitmap_Init( FT_Bitmap *abitmap ) 44 { 45 if ( abitmap ) 46 *abitmap = null_bitmap; 47 } 48 49 50 /* deprecated function name; retained for ABI compatibility */ 51 52 FT_EXPORT_DEF( void ) FT_Bitmap_New(FT_Bitmap * abitmap)53 FT_Bitmap_New( FT_Bitmap *abitmap ) 54 { 55 if ( abitmap ) 56 *abitmap = null_bitmap; 57 } 58 59 60 /* documentation is in ftbitmap.h */ 61 62 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Copy(FT_Library library,const FT_Bitmap * source,FT_Bitmap * target)63 FT_Bitmap_Copy( FT_Library library, 64 const FT_Bitmap *source, 65 FT_Bitmap *target) 66 { 67 FT_Memory memory; 68 FT_Error error = FT_Err_Ok; 69 70 FT_Int pitch; 71 FT_ULong size; 72 73 FT_Int source_pitch_sign, target_pitch_sign; 74 75 76 if ( !library ) 77 return FT_THROW( Invalid_Library_Handle ); 78 79 if ( !source || !target ) 80 return FT_THROW( Invalid_Argument ); 81 82 if ( source == target ) 83 return FT_Err_Ok; 84 85 source_pitch_sign = source->pitch < 0 ? -1 : 1; 86 target_pitch_sign = target->pitch < 0 ? -1 : 1; 87 88 if ( !source->buffer ) 89 { 90 *target = *source; 91 if ( source_pitch_sign != target_pitch_sign ) 92 target->pitch = -target->pitch; 93 94 return FT_Err_Ok; 95 } 96 97 memory = library->memory; 98 pitch = source->pitch; 99 100 if ( pitch < 0 ) 101 pitch = -pitch; 102 size = (FT_ULong)pitch * source->rows; 103 104 if ( target->buffer ) 105 { 106 FT_Int target_pitch = target->pitch; 107 FT_ULong target_size; 108 109 110 if ( target_pitch < 0 ) 111 target_pitch = -target_pitch; 112 target_size = (FT_ULong)target_pitch * target->rows; 113 114 if ( target_size != size ) 115 (void)FT_QREALLOC( target->buffer, target_size, size ); 116 } 117 else 118 (void)FT_QALLOC( target->buffer, size ); 119 120 if ( !error ) 121 { 122 unsigned char *p; 123 124 125 p = target->buffer; 126 *target = *source; 127 target->buffer = p; 128 129 if ( source_pitch_sign == target_pitch_sign ) 130 FT_MEM_COPY( target->buffer, source->buffer, size ); 131 else 132 { 133 /* take care of bitmap flow */ 134 FT_UInt i; 135 FT_Byte* s = source->buffer; 136 FT_Byte* t = target->buffer; 137 138 139 t += (FT_ULong)pitch * ( target->rows - 1 ); 140 141 for ( i = target->rows; i > 0; i-- ) 142 { 143 FT_ARRAY_COPY( t, s, pitch ); 144 145 s += pitch; 146 t -= pitch; 147 } 148 } 149 } 150 151 return error; 152 } 153 154 155 /* Enlarge `bitmap' horizontally and vertically by `xpixels' */ 156 /* and `ypixels', respectively. */ 157 158 static FT_Error ft_bitmap_assure_buffer(FT_Memory memory,FT_Bitmap * bitmap,FT_UInt xpixels,FT_UInt ypixels)159 ft_bitmap_assure_buffer( FT_Memory memory, 160 FT_Bitmap* bitmap, 161 FT_UInt xpixels, 162 FT_UInt ypixels ) 163 { 164 FT_Error error; 165 unsigned int pitch; 166 unsigned int new_pitch; 167 FT_UInt bpp; 168 FT_UInt width, height; 169 unsigned char* buffer = NULL; 170 171 172 width = bitmap->width; 173 height = bitmap->rows; 174 pitch = (unsigned int)FT_ABS( bitmap->pitch ); 175 176 switch ( bitmap->pixel_mode ) 177 { 178 case FT_PIXEL_MODE_MONO: 179 bpp = 1; 180 new_pitch = ( width + xpixels + 7 ) >> 3; 181 break; 182 case FT_PIXEL_MODE_GRAY2: 183 bpp = 2; 184 new_pitch = ( width + xpixels + 3 ) >> 2; 185 break; 186 case FT_PIXEL_MODE_GRAY4: 187 bpp = 4; 188 new_pitch = ( width + xpixels + 1 ) >> 1; 189 break; 190 case FT_PIXEL_MODE_GRAY: 191 case FT_PIXEL_MODE_LCD: 192 case FT_PIXEL_MODE_LCD_V: 193 bpp = 8; 194 new_pitch = width + xpixels; 195 break; 196 default: 197 return FT_THROW( Invalid_Glyph_Format ); 198 } 199 200 /* if no need to allocate memory */ 201 if ( ypixels == 0 && new_pitch <= pitch ) 202 { 203 /* zero the padding */ 204 FT_UInt bit_width = pitch * 8; 205 FT_UInt bit_last = ( width + xpixels ) * bpp; 206 207 208 if ( bit_last < bit_width ) 209 { 210 FT_Byte* line = bitmap->buffer + ( bit_last >> 3 ); 211 FT_Byte* end = bitmap->buffer + pitch; 212 FT_UInt shift = bit_last & 7; 213 FT_UInt mask = 0xFF00U >> shift; 214 FT_UInt count = height; 215 216 217 for ( ; count > 0; count--, line += pitch, end += pitch ) 218 { 219 FT_Byte* write = line; 220 221 222 if ( shift > 0 ) 223 { 224 write[0] = (FT_Byte)( write[0] & mask ); 225 write++; 226 } 227 if ( write < end ) 228 FT_MEM_ZERO( write, end - write ); 229 } 230 } 231 232 return FT_Err_Ok; 233 } 234 235 /* otherwise allocate new buffer */ 236 if ( FT_QALLOC_MULT( buffer, bitmap->rows + ypixels, new_pitch ) ) 237 return error; 238 239 /* new rows get added at the top of the bitmap, */ 240 /* thus take care of the flow direction */ 241 if ( bitmap->pitch > 0 ) 242 { 243 FT_UInt len = ( width * bpp + 7 ) >> 3; 244 245 unsigned char* in = bitmap->buffer; 246 unsigned char* out = buffer; 247 248 unsigned char* limit = bitmap->buffer + pitch * bitmap->rows; 249 unsigned int delta = new_pitch - len; 250 251 252 FT_MEM_ZERO( out, new_pitch * ypixels ); 253 out += new_pitch * ypixels; 254 255 while ( in < limit ) 256 { 257 FT_MEM_COPY( out, in, len ); 258 in += pitch; 259 out += len; 260 261 /* we use FT_QALLOC_MULT, which doesn't zero out the buffer; */ 262 /* consequently, we have to manually zero out the remaining bytes */ 263 FT_MEM_ZERO( out, delta ); 264 out += delta; 265 } 266 } 267 else 268 { 269 FT_UInt len = ( width * bpp + 7 ) >> 3; 270 271 unsigned char* in = bitmap->buffer; 272 unsigned char* out = buffer; 273 274 unsigned char* limit = bitmap->buffer + pitch * bitmap->rows; 275 unsigned int delta = new_pitch - len; 276 277 278 while ( in < limit ) 279 { 280 FT_MEM_COPY( out, in, len ); 281 in += pitch; 282 out += len; 283 284 FT_MEM_ZERO( out, delta ); 285 out += delta; 286 } 287 288 FT_MEM_ZERO( out, new_pitch * ypixels ); 289 } 290 291 FT_FREE( bitmap->buffer ); 292 bitmap->buffer = buffer; 293 294 /* set pitch only, width and height are left untouched */ 295 if ( bitmap->pitch < 0 ) 296 bitmap->pitch = -(int)new_pitch; 297 else 298 bitmap->pitch = (int)new_pitch; 299 300 return FT_Err_Ok; 301 } 302 303 304 /* documentation is in ftbitmap.h */ 305 306 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Embolden(FT_Library library,FT_Bitmap * bitmap,FT_Pos xStrength,FT_Pos yStrength)307 FT_Bitmap_Embolden( FT_Library library, 308 FT_Bitmap* bitmap, 309 FT_Pos xStrength, 310 FT_Pos yStrength ) 311 { 312 FT_Error error; 313 unsigned char* p; 314 FT_Int i, x, pitch; 315 FT_UInt y; 316 FT_Int xstr, ystr; 317 318 319 if ( !library ) 320 return FT_THROW( Invalid_Library_Handle ); 321 322 if ( !bitmap || !bitmap->buffer ) 323 return FT_THROW( Invalid_Argument ); 324 325 if ( ( ( FT_PIX_ROUND( xStrength ) >> 6 ) > FT_INT_MAX ) || 326 ( ( FT_PIX_ROUND( yStrength ) >> 6 ) > FT_INT_MAX ) ) 327 return FT_THROW( Invalid_Argument ); 328 329 xstr = (FT_Int)FT_PIX_ROUND( xStrength ) >> 6; 330 ystr = (FT_Int)FT_PIX_ROUND( yStrength ) >> 6; 331 332 if ( xstr == 0 && ystr == 0 ) 333 return FT_Err_Ok; 334 else if ( xstr < 0 || ystr < 0 ) 335 return FT_THROW( Invalid_Argument ); 336 337 switch ( bitmap->pixel_mode ) 338 { 339 case FT_PIXEL_MODE_GRAY2: 340 case FT_PIXEL_MODE_GRAY4: 341 { 342 FT_Bitmap tmp; 343 344 345 /* convert to 8bpp */ 346 FT_Bitmap_Init( &tmp ); 347 error = FT_Bitmap_Convert( library, bitmap, &tmp, 1 ); 348 if ( error ) 349 return error; 350 351 FT_Bitmap_Done( library, bitmap ); 352 *bitmap = tmp; 353 } 354 break; 355 356 case FT_PIXEL_MODE_MONO: 357 if ( xstr > 8 ) 358 xstr = 8; 359 break; 360 361 case FT_PIXEL_MODE_LCD: 362 xstr *= 3; 363 break; 364 365 case FT_PIXEL_MODE_LCD_V: 366 ystr *= 3; 367 break; 368 369 case FT_PIXEL_MODE_BGRA: 370 /* We don't embolden color glyphs. */ 371 return FT_Err_Ok; 372 } 373 374 error = ft_bitmap_assure_buffer( library->memory, bitmap, 375 (FT_UInt)xstr, (FT_UInt)ystr ); 376 if ( error ) 377 return error; 378 379 /* take care of bitmap flow */ 380 pitch = bitmap->pitch; 381 if ( pitch > 0 ) 382 p = bitmap->buffer + pitch * ystr; 383 else 384 { 385 pitch = -pitch; 386 p = bitmap->buffer + (FT_UInt)pitch * ( bitmap->rows - 1 ); 387 } 388 389 /* for each row */ 390 for ( y = 0; y < bitmap->rows; y++ ) 391 { 392 /* 393 * Horizontally: 394 * 395 * From the last pixel on, make each pixel or'ed with the 396 * `xstr' pixels before it. 397 */ 398 for ( x = pitch - 1; x >= 0; x-- ) 399 { 400 unsigned char tmp; 401 402 403 tmp = p[x]; 404 for ( i = 1; i <= xstr; i++ ) 405 { 406 if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO ) 407 { 408 p[x] |= tmp >> i; 409 410 /* the maximum value of 8 for `xstr' comes from here */ 411 if ( x > 0 ) 412 p[x] |= p[x - 1] << ( 8 - i ); 413 414 #if 0 415 if ( p[x] == 0xFF ) 416 break; 417 #endif 418 } 419 else 420 { 421 if ( x - i >= 0 ) 422 { 423 if ( p[x] + p[x - i] > bitmap->num_grays - 1 ) 424 { 425 p[x] = (unsigned char)( bitmap->num_grays - 1 ); 426 break; 427 } 428 else 429 { 430 p[x] = (unsigned char)( p[x] + p[x - i] ); 431 if ( p[x] == bitmap->num_grays - 1 ) 432 break; 433 } 434 } 435 else 436 break; 437 } 438 } 439 } 440 441 /* 442 * Vertically: 443 * 444 * Make the above `ystr' rows or'ed with it. 445 */ 446 for ( x = 1; x <= ystr; x++ ) 447 { 448 unsigned char* q; 449 450 451 q = p - bitmap->pitch * x; 452 for ( i = 0; i < pitch; i++ ) 453 q[i] |= p[i]; 454 } 455 456 p += bitmap->pitch; 457 } 458 459 bitmap->width += (FT_UInt)xstr; 460 bitmap->rows += (FT_UInt)ystr; 461 462 return FT_Err_Ok; 463 } 464 465 466 static FT_Byte ft_gray_for_premultiplied_srgb_bgra(const FT_Byte * bgra)467 ft_gray_for_premultiplied_srgb_bgra( const FT_Byte* bgra ) 468 { 469 FT_UInt a = bgra[3]; 470 FT_UInt l; 471 472 473 /* Short-circuit transparent color to avoid division by zero. */ 474 if ( !a ) 475 return 0; 476 477 /* 478 * Luminosity for sRGB is defined using ~0.2126,0.7152,0.0722 479 * coefficients for RGB channels *on the linear colors*. 480 * A gamma of 2.2 is fair to assume. And then, we need to 481 * undo the premultiplication too. 482 * 483 * https://accessibility.kde.org/hsl-adjusted.php 484 * 485 * We do the computation with integers only, applying a gamma of 2.0. 486 * We guarantee 32-bit arithmetic to avoid overflow but the resulting 487 * luminosity fits into 16 bits. 488 * 489 */ 490 491 l = ( 4732UL /* 0.0722 * 65536 */ * bgra[0] * bgra[0] + 492 46871UL /* 0.7152 * 65536 */ * bgra[1] * bgra[1] + 493 13933UL /* 0.2126 * 65536 */ * bgra[2] * bgra[2] ) >> 16; 494 495 /* 496 * Final transparency can be determined as follows. 497 * 498 * - If alpha is zero, we want 0. 499 * - If alpha is zero and luminosity is zero, we want 255. 500 * - If alpha is zero and luminosity is one, we want 0. 501 * 502 * So the formula is a * (1 - l) = a - l * a. 503 * 504 * We still need to undo premultiplication by dividing l by a*a. 505 * 506 */ 507 508 return (FT_Byte)( a - l / a ); 509 } 510 511 512 /* documentation is in ftbitmap.h */ 513 514 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Convert(FT_Library library,const FT_Bitmap * source,FT_Bitmap * target,FT_Int alignment)515 FT_Bitmap_Convert( FT_Library library, 516 const FT_Bitmap *source, 517 FT_Bitmap *target, 518 FT_Int alignment ) 519 { 520 FT_Error error = FT_Err_Ok; 521 FT_Memory memory; 522 523 FT_Byte* s; 524 FT_Byte* t; 525 526 527 if ( !library ) 528 return FT_THROW( Invalid_Library_Handle ); 529 530 if ( !source || !target ) 531 return FT_THROW( Invalid_Argument ); 532 533 memory = library->memory; 534 535 switch ( source->pixel_mode ) 536 { 537 case FT_PIXEL_MODE_MONO: 538 case FT_PIXEL_MODE_GRAY: 539 case FT_PIXEL_MODE_GRAY2: 540 case FT_PIXEL_MODE_GRAY4: 541 case FT_PIXEL_MODE_LCD: 542 case FT_PIXEL_MODE_LCD_V: 543 case FT_PIXEL_MODE_BGRA: 544 { 545 FT_Int pad, old_target_pitch, target_pitch; 546 FT_ULong old_size; 547 548 549 old_target_pitch = target->pitch; 550 if ( old_target_pitch < 0 ) 551 old_target_pitch = -old_target_pitch; 552 553 old_size = target->rows * (FT_UInt)old_target_pitch; 554 555 target->pixel_mode = FT_PIXEL_MODE_GRAY; 556 target->rows = source->rows; 557 target->width = source->width; 558 559 pad = 0; 560 if ( alignment > 0 ) 561 { 562 pad = (FT_Int)source->width % alignment; 563 if ( pad != 0 ) 564 pad = alignment - pad; 565 } 566 567 target_pitch = (FT_Int)source->width + pad; 568 569 if ( target_pitch > 0 && 570 (FT_ULong)target->rows > FT_ULONG_MAX / (FT_ULong)target_pitch ) 571 return FT_THROW( Invalid_Argument ); 572 573 if ( FT_QREALLOC( target->buffer, 574 old_size, target->rows * (FT_UInt)target_pitch ) ) 575 return error; 576 577 target->pitch = target->pitch < 0 ? -target_pitch : target_pitch; 578 } 579 break; 580 581 default: 582 error = FT_THROW( Invalid_Argument ); 583 } 584 585 s = source->buffer; 586 t = target->buffer; 587 588 /* take care of bitmap flow */ 589 if ( source->pitch < 0 ) 590 s -= source->pitch * (FT_Int)( source->rows - 1 ); 591 if ( target->pitch < 0 ) 592 t -= target->pitch * (FT_Int)( target->rows - 1 ); 593 594 switch ( source->pixel_mode ) 595 { 596 case FT_PIXEL_MODE_MONO: 597 { 598 FT_UInt i; 599 600 601 target->num_grays = 2; 602 603 for ( i = source->rows; i > 0; i-- ) 604 { 605 FT_Byte* ss = s; 606 FT_Byte* tt = t; 607 FT_UInt j; 608 609 610 /* get the full bytes */ 611 for ( j = source->width >> 3; j > 0; j-- ) 612 { 613 FT_Int val = ss[0]; /* avoid a byte->int cast on each line */ 614 615 616 tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 ); 617 tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 ); 618 tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 ); 619 tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 ); 620 tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 ); 621 tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 ); 622 tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 ); 623 tt[7] = (FT_Byte)( val & 0x01 ); 624 625 tt += 8; 626 ss += 1; 627 } 628 629 /* get remaining pixels (if any) */ 630 j = source->width & 7; 631 if ( j > 0 ) 632 { 633 FT_Int val = *ss; 634 635 636 for ( ; j > 0; j-- ) 637 { 638 tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7); 639 val <<= 1; 640 tt += 1; 641 } 642 } 643 644 s += source->pitch; 645 t += target->pitch; 646 } 647 } 648 break; 649 650 651 case FT_PIXEL_MODE_GRAY: 652 case FT_PIXEL_MODE_LCD: 653 case FT_PIXEL_MODE_LCD_V: 654 { 655 FT_UInt width = source->width; 656 FT_UInt i; 657 658 659 target->num_grays = 256; 660 661 for ( i = source->rows; i > 0; i-- ) 662 { 663 FT_ARRAY_COPY( t, s, width ); 664 665 s += source->pitch; 666 t += target->pitch; 667 } 668 } 669 break; 670 671 672 case FT_PIXEL_MODE_GRAY2: 673 { 674 FT_UInt i; 675 676 677 target->num_grays = 4; 678 679 for ( i = source->rows; i > 0; i-- ) 680 { 681 FT_Byte* ss = s; 682 FT_Byte* tt = t; 683 FT_UInt j; 684 685 686 /* get the full bytes */ 687 for ( j = source->width >> 2; j > 0; j-- ) 688 { 689 FT_Int val = ss[0]; 690 691 692 tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); 693 tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 ); 694 tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 ); 695 tt[3] = (FT_Byte)( ( val & 0x03 ) ); 696 697 ss += 1; 698 tt += 4; 699 } 700 701 j = source->width & 3; 702 if ( j > 0 ) 703 { 704 FT_Int val = ss[0]; 705 706 707 for ( ; j > 0; j-- ) 708 { 709 tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); 710 val <<= 2; 711 tt += 1; 712 } 713 } 714 715 s += source->pitch; 716 t += target->pitch; 717 } 718 } 719 break; 720 721 722 case FT_PIXEL_MODE_GRAY4: 723 { 724 FT_UInt i; 725 726 727 target->num_grays = 16; 728 729 for ( i = source->rows; i > 0; i-- ) 730 { 731 FT_Byte* ss = s; 732 FT_Byte* tt = t; 733 FT_UInt j; 734 735 736 /* get the full bytes */ 737 for ( j = source->width >> 1; j > 0; j-- ) 738 { 739 FT_Int val = ss[0]; 740 741 742 tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 ); 743 tt[1] = (FT_Byte)( ( val & 0x0F ) ); 744 745 ss += 1; 746 tt += 2; 747 } 748 749 if ( source->width & 1 ) 750 tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 ); 751 752 s += source->pitch; 753 t += target->pitch; 754 } 755 } 756 break; 757 758 759 case FT_PIXEL_MODE_BGRA: 760 { 761 FT_UInt i; 762 763 764 target->num_grays = 256; 765 766 for ( i = source->rows; i > 0; i-- ) 767 { 768 FT_Byte* ss = s; 769 FT_Byte* tt = t; 770 FT_UInt j; 771 772 773 for ( j = source->width; j > 0; j-- ) 774 { 775 tt[0] = ft_gray_for_premultiplied_srgb_bgra( ss ); 776 777 ss += 4; 778 tt += 1; 779 } 780 781 s += source->pitch; 782 t += target->pitch; 783 } 784 } 785 break; 786 787 default: 788 ; 789 } 790 791 return error; 792 } 793 794 795 /* documentation is in ftbitmap.h */ 796 797 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Blend(FT_Library library,const FT_Bitmap * source_,const FT_Vector source_offset_,FT_Bitmap * target,FT_Vector * atarget_offset,FT_Color color)798 FT_Bitmap_Blend( FT_Library library, 799 const FT_Bitmap* source_, 800 const FT_Vector source_offset_, 801 FT_Bitmap* target, 802 FT_Vector *atarget_offset, 803 FT_Color color ) 804 { 805 FT_Error error = FT_Err_Ok; 806 FT_Memory memory; 807 808 FT_Bitmap source_bitmap; 809 const FT_Bitmap* source; 810 811 FT_Vector source_offset; 812 FT_Vector target_offset; 813 814 FT_Bool free_source_bitmap = 0; 815 FT_Bool free_target_bitmap_on_error = 0; 816 817 FT_Pos source_llx, source_lly, source_urx, source_ury; 818 FT_Pos target_llx, target_lly, target_urx, target_ury; 819 FT_Pos final_llx, final_lly, final_urx, final_ury; 820 821 unsigned int final_rows, final_width; 822 long x, y; 823 824 825 if ( !library || !target || !source_ || !atarget_offset ) 826 return FT_THROW( Invalid_Argument ); 827 828 memory = library->memory; 829 830 if ( !( target->pixel_mode == FT_PIXEL_MODE_NONE || 831 ( target->pixel_mode == FT_PIXEL_MODE_BGRA && 832 target->buffer ) ) ) 833 return FT_THROW( Invalid_Argument ); 834 835 if ( source_->pixel_mode == FT_PIXEL_MODE_NONE ) 836 return FT_Err_Ok; /* nothing to do */ 837 838 /* pitches must have the same sign */ 839 if ( target->pixel_mode == FT_PIXEL_MODE_BGRA && 840 ( source_->pitch ^ target->pitch ) < 0 ) 841 return FT_THROW( Invalid_Argument ); 842 843 if ( !( source_->width && source_->rows ) ) 844 return FT_Err_Ok; /* nothing to do */ 845 846 /* assure integer pixel offsets */ 847 source_offset.x = FT_PIX_FLOOR( source_offset_.x ); 848 source_offset.y = FT_PIX_FLOOR( source_offset_.y ); 849 target_offset.x = FT_PIX_FLOOR( atarget_offset->x ); 850 target_offset.y = FT_PIX_FLOOR( atarget_offset->y ); 851 852 /* get source bitmap dimensions */ 853 source_llx = source_offset.x; 854 if ( FT_LONG_MIN + (FT_Pos)( source_->rows << 6 ) + 64 > source_offset.y ) 855 { 856 FT_TRACE5(( 857 "FT_Bitmap_Blend: y coordinate overflow in source bitmap\n" )); 858 return FT_THROW( Invalid_Argument ); 859 } 860 source_lly = source_offset.y - ( source_->rows << 6 ); 861 862 if ( FT_LONG_MAX - (FT_Pos)( source_->width << 6 ) - 64 < source_llx ) 863 { 864 FT_TRACE5(( 865 "FT_Bitmap_Blend: x coordinate overflow in source bitmap\n" )); 866 return FT_THROW( Invalid_Argument ); 867 } 868 source_urx = source_llx + ( source_->width << 6 ); 869 source_ury = source_offset.y; 870 871 /* get target bitmap dimensions */ 872 if ( target->width && target->rows ) 873 { 874 target_llx = target_offset.x; 875 if ( FT_LONG_MIN + (FT_Pos)( target->rows << 6 ) > target_offset.y ) 876 { 877 FT_TRACE5(( 878 "FT_Bitmap_Blend: y coordinate overflow in target bitmap\n" )); 879 return FT_THROW( Invalid_Argument ); 880 } 881 target_lly = target_offset.y - ( target->rows << 6 ); 882 883 if ( FT_LONG_MAX - (FT_Pos)( target->width << 6 ) < target_llx ) 884 { 885 FT_TRACE5(( 886 "FT_Bitmap_Blend: x coordinate overflow in target bitmap\n" )); 887 return FT_THROW( Invalid_Argument ); 888 } 889 target_urx = target_llx + ( target->width << 6 ); 890 target_ury = target_offset.y; 891 } 892 else 893 { 894 target_llx = FT_LONG_MAX; 895 target_lly = FT_LONG_MAX; 896 target_urx = FT_LONG_MIN; 897 target_ury = FT_LONG_MIN; 898 } 899 900 /* compute final bitmap dimensions */ 901 final_llx = FT_MIN( source_llx, target_llx ); 902 final_lly = FT_MIN( source_lly, target_lly ); 903 final_urx = FT_MAX( source_urx, target_urx ); 904 final_ury = FT_MAX( source_ury, target_ury ); 905 906 final_width = ( final_urx - final_llx ) >> 6; 907 final_rows = ( final_ury - final_lly ) >> 6; 908 909 #ifdef FT_DEBUG_LEVEL_TRACE 910 FT_TRACE5(( "FT_Bitmap_Blend:\n" 911 " source bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", 912 source_llx / 64, source_lly / 64, 913 source_urx / 64, source_ury / 64, 914 source_->width, source_->rows )); 915 916 if ( target->width && target->rows ) 917 FT_TRACE5(( " target bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", 918 target_llx / 64, target_lly / 64, 919 target_urx / 64, target_ury / 64, 920 target->width, target->rows )); 921 else 922 FT_TRACE5(( " target bitmap: empty\n" )); 923 924 if ( final_width && final_rows ) 925 FT_TRACE5(( " final bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", 926 final_llx / 64, final_lly / 64, 927 final_urx / 64, final_ury / 64, 928 final_width, final_rows )); 929 else 930 FT_TRACE5(( " final bitmap: empty\n" )); 931 #endif /* FT_DEBUG_LEVEL_TRACE */ 932 933 if ( !( final_width && final_rows ) ) 934 return FT_Err_Ok; /* nothing to do */ 935 936 /* for blending, set offset vector of final bitmap */ 937 /* temporarily to (0,0) */ 938 source_llx -= final_llx; 939 source_lly -= final_lly; 940 941 if ( target->width && target->rows ) 942 { 943 target_llx -= final_llx; 944 target_lly -= final_lly; 945 } 946 947 /* set up target bitmap */ 948 if ( target->pixel_mode == FT_PIXEL_MODE_NONE ) 949 { 950 /* create new empty bitmap */ 951 target->width = final_width; 952 target->rows = final_rows; 953 target->pixel_mode = FT_PIXEL_MODE_BGRA; 954 target->pitch = (int)final_width * 4; 955 target->num_grays = 256; 956 957 if ( FT_LONG_MAX / target->pitch < (int)target->rows ) 958 { 959 FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", 960 final_width, final_rows )); 961 return FT_THROW( Invalid_Argument ); 962 } 963 964 if ( FT_ALLOC( target->buffer, target->pitch * (int)target->rows ) ) 965 return error; 966 967 free_target_bitmap_on_error = 1; 968 } 969 else if ( target->width != final_width || 970 target->rows != final_rows ) 971 { 972 /* adjust old bitmap to enlarged size */ 973 int pitch, new_pitch; 974 975 unsigned char* buffer = NULL; 976 977 978 pitch = target->pitch; 979 980 if ( pitch < 0 ) 981 pitch = -pitch; 982 983 new_pitch = (int)final_width * 4; 984 985 if ( FT_LONG_MAX / new_pitch < (int)final_rows ) 986 { 987 FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", 988 final_width, final_rows )); 989 return FT_THROW( Invalid_Argument ); 990 } 991 992 /* TODO: provide an in-buffer solution for large bitmaps */ 993 /* to avoid allocation of a new buffer */ 994 if ( FT_ALLOC( buffer, new_pitch * (int)final_rows ) ) 995 goto Error; 996 997 /* copy data to new buffer */ 998 x = target_llx >> 6; 999 y = target_lly >> 6; 1000 1001 /* the bitmap flow is from top to bottom, */ 1002 /* but y is measured from bottom to top */ 1003 if ( target->pitch < 0 ) 1004 { 1005 /* XXX */ 1006 } 1007 else 1008 { 1009 unsigned char* p = 1010 target->buffer; 1011 unsigned char* q = 1012 buffer + 1013 ( final_rows - y - target->rows ) * new_pitch + 1014 x * 4; 1015 unsigned char* limit_p = 1016 p + pitch * (int)target->rows; 1017 1018 1019 while ( p < limit_p ) 1020 { 1021 FT_MEM_COPY( q, p, pitch ); 1022 1023 p += pitch; 1024 q += new_pitch; 1025 } 1026 } 1027 1028 FT_FREE( target->buffer ); 1029 1030 target->width = final_width; 1031 target->rows = final_rows; 1032 1033 if ( target->pitch < 0 ) 1034 target->pitch = -new_pitch; 1035 else 1036 target->pitch = new_pitch; 1037 1038 target->buffer = buffer; 1039 } 1040 1041 /* adjust source bitmap if necessary */ 1042 if ( source_->pixel_mode != FT_PIXEL_MODE_GRAY ) 1043 { 1044 FT_Bitmap_Init( &source_bitmap ); 1045 error = FT_Bitmap_Convert( library, source_, &source_bitmap, 1 ); 1046 if ( error ) 1047 goto Error; 1048 1049 source = &source_bitmap; 1050 free_source_bitmap = 1; 1051 } 1052 else 1053 source = source_; 1054 1055 /* do blending; the code below returns pre-multiplied channels, */ 1056 /* similar to what FreeType gets from `CBDT' tables */ 1057 x = source_llx >> 6; 1058 y = source_lly >> 6; 1059 1060 /* the bitmap flow is from top to bottom, */ 1061 /* but y is measured from bottom to top */ 1062 if ( target->pitch < 0 ) 1063 { 1064 /* XXX */ 1065 } 1066 else 1067 { 1068 unsigned char* p = 1069 source->buffer; 1070 unsigned char* q = 1071 target->buffer + 1072 ( target->rows - y - source->rows ) * target->pitch + 1073 x * 4; 1074 unsigned char* limit_p = 1075 p + source->pitch * (int)source->rows; 1076 1077 1078 while ( p < limit_p ) 1079 { 1080 unsigned char* r = p; 1081 unsigned char* s = q; 1082 unsigned char* limit_r = r + source->width; 1083 1084 1085 while ( r < limit_r ) 1086 { 1087 int aa = *r++; 1088 int fa = color.alpha * aa / 255; 1089 1090 int fb = color.blue * fa / 255; 1091 int fg = color.green * fa / 255; 1092 int fr = color.red * fa / 255; 1093 1094 int ba2 = 255 - fa; 1095 1096 int bb = s[0]; 1097 int bg = s[1]; 1098 int br = s[2]; 1099 int ba = s[3]; 1100 1101 1102 *s++ = (unsigned char)( bb * ba2 / 255 + fb ); 1103 *s++ = (unsigned char)( bg * ba2 / 255 + fg ); 1104 *s++ = (unsigned char)( br * ba2 / 255 + fr ); 1105 *s++ = (unsigned char)( ba * ba2 / 255 + fa ); 1106 } 1107 1108 p += source->pitch; 1109 q += target->pitch; 1110 } 1111 } 1112 1113 atarget_offset->x = final_llx; 1114 atarget_offset->y = final_lly + ( final_rows << 6 ); 1115 1116 Error: 1117 if ( error && free_target_bitmap_on_error ) 1118 FT_Bitmap_Done( library, target ); 1119 1120 if ( free_source_bitmap ) 1121 FT_Bitmap_Done( library, &source_bitmap ); 1122 1123 return error; 1124 } 1125 1126 1127 /* documentation is in ftbitmap.h */ 1128 1129 FT_EXPORT_DEF( FT_Error ) FT_GlyphSlot_Own_Bitmap(FT_GlyphSlot slot)1130 FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ) 1131 { 1132 if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP && 1133 !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) 1134 { 1135 FT_Bitmap bitmap; 1136 FT_Error error; 1137 1138 1139 FT_Bitmap_Init( &bitmap ); 1140 error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap ); 1141 if ( error ) 1142 return error; 1143 1144 slot->bitmap = bitmap; 1145 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 1146 } 1147 1148 return FT_Err_Ok; 1149 } 1150 1151 1152 /* documentation is in ftbitmap.h */ 1153 1154 FT_EXPORT_DEF( FT_Error ) FT_Bitmap_Done(FT_Library library,FT_Bitmap * bitmap)1155 FT_Bitmap_Done( FT_Library library, 1156 FT_Bitmap *bitmap ) 1157 { 1158 FT_Memory memory; 1159 1160 1161 if ( !library ) 1162 return FT_THROW( Invalid_Library_Handle ); 1163 1164 if ( !bitmap ) 1165 return FT_THROW( Invalid_Argument ); 1166 1167 memory = library->memory; 1168 1169 FT_FREE( bitmap->buffer ); 1170 *bitmap = null_bitmap; 1171 1172 return FT_Err_Ok; 1173 } 1174 1175 1176 /* END */ 1177