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