tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ftbitmap.c (28296B)


      1 /****************************************************************************
      2 *
      3 * ftbitmap.c
      4 *
      5 *   FreeType utility functions for bitmaps (body).
      6 *
      7 * Copyright (C) 2004-2025 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); %u x %u\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); %u x %u\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); %u x %u\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 (%u x %u)\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 (%u x %u)\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 */