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