Home | History | Annotate | Download | only in base
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  ftlcdfil.c                                                             */
      4 /*                                                                         */
      5 /*    FreeType API for color filtering of subpixel bitmap glyphs (body).   */
      6 /*                                                                         */
      7 /*  Copyright 2006-2016 by                                                 */
      8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
      9 /*                                                                         */
     10 /*  This file is part of the FreeType project, and may only be used,       */
     11 /*  modified, and distributed under the terms of the FreeType project      */
     12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
     13 /*  this file you indicate that you have read the license and              */
     14 /*  understand and accept it fully.                                        */
     15 /*                                                                         */
     16 /***************************************************************************/
     17 
     18 
     19 #include <ft2build.h>
     20 #include FT_INTERNAL_DEBUG_H
     21 
     22 #include FT_LCD_FILTER_H
     23 #include FT_IMAGE_H
     24 #include FT_INTERNAL_OBJECTS_H
     25 
     26 
     27 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
     28 
     29 /* define USE_LEGACY to implement the legacy filter */
     30 #define  USE_LEGACY
     31 
     32   /* FIR filter used by the default and light filters */
     33   static void
     34   _ft_lcd_filter_fir( FT_Bitmap*      bitmap,
     35                       FT_Render_Mode  mode,
     36                       FT_Library      library )
     37   {
     38     FT_Byte*  weights = library->lcd_weights;
     39     FT_UInt   width   = (FT_UInt)bitmap->width;
     40     FT_UInt   height  = (FT_UInt)bitmap->rows;
     41 
     42 
     43     /* horizontal in-place FIR filter */
     44     if ( mode == FT_RENDER_MODE_LCD && width >= 4 )
     45     {
     46       FT_Byte*  line = bitmap->buffer;
     47 
     48 
     49       /* take care of bitmap flow */
     50       if ( bitmap->pitch < 0 )
     51         line -= bitmap->pitch * (FT_Int)( bitmap->rows - 1 );
     52 
     53       /* `fir' and `pix' must be at least 32 bit wide, since the sum of */
     54       /* the values in `weights' can exceed 0xFF                        */
     55 
     56       for ( ; height > 0; height--, line += bitmap->pitch )
     57       {
     58         FT_UInt  fir[4];        /* below, `pix' is used as the 5th element */
     59         FT_UInt  val1, xx;
     60 
     61 
     62         val1   = line[0];
     63         fir[0] = weights[2] * val1;
     64         fir[1] = weights[3] * val1;
     65         fir[2] = weights[4] * val1;
     66         fir[3] = 0;
     67 
     68         val1    = line[1];
     69         fir[0] += weights[1] * val1;
     70         fir[1] += weights[2] * val1;
     71         fir[2] += weights[3] * val1;
     72         fir[3] += weights[4] * val1;
     73 
     74         for ( xx = 2; xx < width; xx++ )
     75         {
     76           FT_UInt  val, pix;
     77 
     78 
     79           val    = line[xx];
     80           pix    = fir[0] + weights[0] * val;
     81           fir[0] = fir[1] + weights[1] * val;
     82           fir[1] = fir[2] + weights[2] * val;
     83           fir[2] = fir[3] + weights[3] * val;
     84           fir[3] =          weights[4] * val;
     85 
     86           pix        >>= 8;
     87           pix         |= (FT_UInt)-(FT_Int)( pix >> 8 );
     88           line[xx - 2] = (FT_Byte)pix;
     89         }
     90 
     91         {
     92           FT_UInt  pix;
     93 
     94 
     95           pix          = fir[0] >> 8;
     96           pix         |= (FT_UInt)-(FT_Int)( pix >> 8 );
     97           line[xx - 2] = (FT_Byte)pix;
     98 
     99           pix          = fir[1] >> 8;
    100           pix         |= (FT_UInt)-(FT_Int)( pix >> 8 );
    101           line[xx - 1] = (FT_Byte)pix;
    102         }
    103       }
    104     }
    105 
    106     /* vertical in-place FIR filter */
    107     else if ( mode == FT_RENDER_MODE_LCD_V && height >= 4 )
    108     {
    109       FT_Byte*  column = bitmap->buffer;
    110       FT_Int    pitch  = bitmap->pitch;
    111 
    112 
    113       /* take care of bitmap flow */
    114       if ( bitmap->pitch < 0 )
    115         column -= bitmap->pitch * (FT_Int)( bitmap->rows - 1 );
    116 
    117       for ( ; width > 0; width--, column++ )
    118       {
    119         FT_Byte*  col = column;
    120         FT_UInt   fir[4];       /* below, `pix' is used as the 5th element */
    121         FT_UInt   val1, yy;
    122 
    123 
    124         val1   = col[0];
    125         fir[0] = weights[2] * val1;
    126         fir[1] = weights[3] * val1;
    127         fir[2] = weights[4] * val1;
    128         fir[3] = 0;
    129         col   += pitch;
    130 
    131         val1    = col[0];
    132         fir[0] += weights[1] * val1;
    133         fir[1] += weights[2] * val1;
    134         fir[2] += weights[3] * val1;
    135         fir[3] += weights[4] * val1;
    136         col    += pitch;
    137 
    138         for ( yy = 2; yy < height; yy++ )
    139         {
    140           FT_UInt  val, pix;
    141 
    142 
    143           val    = col[0];
    144           pix    = fir[0] + weights[0] * val;
    145           fir[0] = fir[1] + weights[1] * val;
    146           fir[1] = fir[2] + weights[2] * val;
    147           fir[2] = fir[3] + weights[3] * val;
    148           fir[3] =          weights[4] * val;
    149 
    150           pix           >>= 8;
    151           pix            |= (FT_UInt)-(FT_Int)( pix >> 8 );
    152           col[-2 * pitch] = (FT_Byte)pix;
    153           col            += pitch;
    154         }
    155 
    156         {
    157           FT_UInt  pix;
    158 
    159 
    160           pix             = fir[0] >> 8;
    161           pix            |= (FT_UInt)-(FT_Int)( pix >> 8 );
    162           col[-2 * pitch] = (FT_Byte)pix;
    163 
    164           pix         = fir[1] >> 8;
    165           pix        |= (FT_UInt)-(FT_Int)( pix >> 8 );
    166           col[-pitch] = (FT_Byte)pix;
    167         }
    168       }
    169     }
    170   }
    171 
    172 
    173 #ifdef USE_LEGACY
    174 
    175   /* intra-pixel filter used by the legacy filter */
    176   static void
    177   _ft_lcd_filter_legacy( FT_Bitmap*      bitmap,
    178                          FT_Render_Mode  mode,
    179                          FT_Library      library )
    180   {
    181     FT_UInt  width  = (FT_UInt)bitmap->width;
    182     FT_UInt  height = (FT_UInt)bitmap->rows;
    183     FT_Int   pitch  = bitmap->pitch;
    184 
    185     static const unsigned int  filters[3][3] =
    186     {
    187       { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 },
    188       { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 },
    189       { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
    190     };
    191 
    192     FT_UNUSED( library );
    193 
    194 
    195     /* horizontal in-place intra-pixel filter */
    196     if ( mode == FT_RENDER_MODE_LCD && width >= 3 )
    197     {
    198       FT_Byte*  line = bitmap->buffer;
    199 
    200 
    201       /* take care of bitmap flow */
    202       if ( bitmap->pitch < 0 )
    203         line -= bitmap->pitch * (FT_Int)( bitmap->rows - 1 );
    204 
    205       for ( ; height > 0; height--, line += pitch )
    206       {
    207         FT_UInt  xx;
    208 
    209 
    210         for ( xx = 0; xx < width; xx += 3 )
    211         {
    212           FT_UInt  r = 0;
    213           FT_UInt  g = 0;
    214           FT_UInt  b = 0;
    215           FT_UInt  p;
    216 
    217 
    218           p  = line[xx];
    219           r += filters[0][0] * p;
    220           g += filters[0][1] * p;
    221           b += filters[0][2] * p;
    222 
    223           p  = line[xx + 1];
    224           r += filters[1][0] * p;
    225           g += filters[1][1] * p;
    226           b += filters[1][2] * p;
    227 
    228           p  = line[xx + 2];
    229           r += filters[2][0] * p;
    230           g += filters[2][1] * p;
    231           b += filters[2][2] * p;
    232 
    233           line[xx]     = (FT_Byte)( r / 65536 );
    234           line[xx + 1] = (FT_Byte)( g / 65536 );
    235           line[xx + 2] = (FT_Byte)( b / 65536 );
    236         }
    237       }
    238     }
    239     else if ( mode == FT_RENDER_MODE_LCD_V && height >= 3 )
    240     {
    241       FT_Byte*  column = bitmap->buffer;
    242 
    243 
    244       /* take care of bitmap flow */
    245       if ( bitmap->pitch < 0 )
    246         column -= bitmap->pitch * (FT_Int)( bitmap->rows - 1 );
    247 
    248       for ( ; width > 0; width--, column++ )
    249       {
    250         FT_Byte*  col     = column;
    251         FT_Byte*  col_end = col + (FT_Int)height * pitch;
    252 
    253 
    254         for ( ; col < col_end; col += 3 * pitch )
    255         {
    256           FT_UInt  r = 0;
    257           FT_UInt  g = 0;
    258           FT_UInt  b = 0;
    259           FT_UInt  p;
    260 
    261 
    262           p  = col[0];
    263           r += filters[0][0] * p;
    264           g += filters[0][1] * p;
    265           b += filters[0][2] * p;
    266 
    267           p  = col[pitch];
    268           r += filters[1][0] * p;
    269           g += filters[1][1] * p;
    270           b += filters[1][2] * p;
    271 
    272           p  = col[pitch * 2];
    273           r += filters[2][0] * p;
    274           g += filters[2][1] * p;
    275           b += filters[2][2] * p;
    276 
    277           col[0]         = (FT_Byte)( r / 65536 );
    278           col[pitch]     = (FT_Byte)( g / 65536 );
    279           col[2 * pitch] = (FT_Byte)( b / 65536 );
    280         }
    281       }
    282     }
    283   }
    284 
    285 #endif /* USE_LEGACY */
    286 
    287 
    288   FT_EXPORT_DEF( FT_Error )
    289   FT_Library_SetLcdFilterWeights( FT_Library      library,
    290                                   unsigned char  *weights )
    291   {
    292     if ( !library )
    293       return FT_THROW( Invalid_Library_Handle );
    294 
    295     if ( !weights )
    296       return FT_THROW( Invalid_Argument );
    297 
    298     ft_memcpy( library->lcd_weights, weights, 5 );
    299     library->lcd_filter_func = _ft_lcd_filter_fir;
    300     library->lcd_extra       = 2;
    301 
    302     return FT_Err_Ok;
    303   }
    304 
    305 
    306   FT_EXPORT_DEF( FT_Error )
    307   FT_Library_SetLcdFilter( FT_Library    library,
    308                            FT_LcdFilter  filter )
    309   {
    310     static const FT_Byte  default_filter[5] =
    311                             { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
    312     static const FT_Byte  light_filter[5] =
    313                             { 0x00, 0x55, 0x56, 0x55, 0x00 };
    314 
    315 
    316     if ( !library )
    317       return FT_THROW( Invalid_Library_Handle );
    318 
    319     switch ( filter )
    320     {
    321     case FT_LCD_FILTER_NONE:
    322       library->lcd_filter_func = NULL;
    323       library->lcd_extra       = 0;
    324       break;
    325 
    326     case FT_LCD_FILTER_DEFAULT:
    327       ft_memcpy( library->lcd_weights, default_filter, 5 );
    328       library->lcd_filter_func = _ft_lcd_filter_fir;
    329       library->lcd_extra       = 2;
    330       break;
    331 
    332     case FT_LCD_FILTER_LIGHT:
    333       ft_memcpy( library->lcd_weights, light_filter, 5 );
    334       library->lcd_filter_func = _ft_lcd_filter_fir;
    335       library->lcd_extra       = 2;
    336       break;
    337 
    338 #ifdef USE_LEGACY
    339 
    340     case FT_LCD_FILTER_LEGACY:
    341     case FT_LCD_FILTER_LEGACY1:
    342       library->lcd_filter_func = _ft_lcd_filter_legacy;
    343       library->lcd_extra       = 0;
    344       break;
    345 
    346 #endif
    347 
    348     default:
    349       return FT_THROW( Invalid_Argument );
    350     }
    351 
    352     library->lcd_filter = filter;
    353 
    354     return FT_Err_Ok;
    355   }
    356 
    357 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    358 
    359   FT_EXPORT_DEF( FT_Error )
    360   FT_Library_SetLcdFilterWeights( FT_Library      library,
    361                                   unsigned char  *weights )
    362   {
    363     FT_UNUSED( library );
    364     FT_UNUSED( weights );
    365 
    366     return FT_THROW( Unimplemented_Feature );
    367   }
    368 
    369 
    370   FT_EXPORT_DEF( FT_Error )
    371   FT_Library_SetLcdFilter( FT_Library    library,
    372                            FT_LcdFilter  filter )
    373   {
    374     FT_UNUSED( library );
    375     FT_UNUSED( filter );
    376 
    377     return FT_THROW( Unimplemented_Feature );
    378   }
    379 
    380 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    381 
    382 
    383 /* END */
    384