(root)/
freetype-2.13.2/
src/
base/
ftbitmap.c
       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 */