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