tor-browser

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

ftlcdfil.c (11455B)


      1 /****************************************************************************
      2 *
      3 * ftlcdfil.c
      4 *
      5 *   FreeType API for color filtering of subpixel bitmap glyphs (body).
      6 *
      7 * Copyright (C) 2006-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/ftlcdfil.h>
     22 #include <freetype/ftimage.h>
     23 #include <freetype/internal/ftobjs.h>
     24 
     25 
     26 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
     27 
     28 /* define USE_LEGACY to implement the legacy filter */
     29 #define  USE_LEGACY
     30 
     31 #define FT_SHIFTCLAMP( x )  ( x >>= 8, (FT_Byte)( x > 255 ? 255 : x ) )
     32 
     33 
     34  /* add padding according to filter weights */
     35  FT_BASE_DEF( void )
     36  ft_lcd_padding( FT_BBox*        cbox,
     37                  FT_GlyphSlot    slot,
     38                  FT_Render_Mode  mode )
     39  {
     40    FT_Byte*                 lcd_weights;
     41    FT_Bitmap_LcdFilterFunc  lcd_filter_func;
     42 
     43 
     44    /* Per-face LCD filtering takes priority if set up. */
     45    if ( slot->face && slot->face->internal->lcd_filter_func )
     46    {
     47      lcd_weights     = slot->face->internal->lcd_weights;
     48      lcd_filter_func = slot->face->internal->lcd_filter_func;
     49    }
     50    else
     51    {
     52      lcd_weights     = slot->library->lcd_weights;
     53      lcd_filter_func = slot->library->lcd_filter_func;
     54    }
     55 
     56    if ( lcd_filter_func == ft_lcd_filter_fir )
     57    {
     58      if ( mode == FT_RENDER_MODE_LCD )
     59      {
     60        cbox->xMin -= lcd_weights[0] ? 43 :
     61                      lcd_weights[1] ? 22 : 0;
     62        cbox->xMax += lcd_weights[4] ? 43 :
     63                      lcd_weights[3] ? 22 : 0;
     64      }
     65      else if ( mode == FT_RENDER_MODE_LCD_V )
     66      {
     67        cbox->yMin -= lcd_weights[0] ? 43 :
     68                      lcd_weights[1] ? 22 : 0;
     69        cbox->yMax += lcd_weights[4] ? 43 :
     70                      lcd_weights[3] ? 22 : 0;
     71      }
     72    }
     73  }
     74 
     75 
     76  /* FIR filter used by the default and light filters */
     77  FT_BASE_DEF( void )
     78  ft_lcd_filter_fir( FT_Bitmap*           bitmap,
     79                     FT_LcdFiveTapFilter  weights )
     80  {
     81    FT_UInt   width  = (FT_UInt)bitmap->width;
     82    FT_UInt   height = (FT_UInt)bitmap->rows;
     83    FT_Int    pitch  = bitmap->pitch;
     84    FT_Byte*  origin = bitmap->buffer;
     85    FT_Byte   mode   = bitmap->pixel_mode;
     86 
     87 
     88    /* take care of bitmap flow */
     89    if ( pitch > 0 && height > 0 )
     90      origin += pitch * (FT_Int)( height - 1 );
     91 
     92    /* horizontal in-place FIR filter */
     93    if ( mode == FT_PIXEL_MODE_LCD && width >= 2 )
     94    {
     95      FT_Byte*  line = origin;
     96 
     97 
     98      /* `fir' must be at least 32 bit wide, since the sum of */
     99      /* the values in `weights' can exceed 0xFF              */
    100 
    101      for ( ; height > 0; height--, line -= pitch )
    102      {
    103        FT_UInt  fir[5];
    104        FT_UInt  val, xx;
    105 
    106 
    107        val    = line[0];
    108        fir[2] = weights[2] * val;
    109        fir[3] = weights[3] * val;
    110        fir[4] = weights[4] * val;
    111 
    112        val    = line[1];
    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        for ( xx = 2; xx < width; xx++ )
    119        {
    120          val    = line[xx];
    121          fir[0] = fir[1] + weights[0] * val;
    122          fir[1] = fir[2] + weights[1] * val;
    123          fir[2] = fir[3] + weights[2] * val;
    124          fir[3] = fir[4] + weights[3] * val;
    125          fir[4] =          weights[4] * val;
    126 
    127          line[xx - 2] = FT_SHIFTCLAMP( fir[0] );
    128        }
    129 
    130        line[xx - 2] = FT_SHIFTCLAMP( fir[1] );
    131        line[xx - 1] = FT_SHIFTCLAMP( fir[2] );
    132      }
    133    }
    134 
    135    /* vertical in-place FIR filter */
    136    else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 2 )
    137    {
    138      FT_Byte*  column = origin;
    139 
    140 
    141      for ( ; width > 0; width--, column++ )
    142      {
    143        FT_Byte*  col = column;
    144        FT_UInt   fir[5];
    145        FT_UInt   val, yy;
    146 
    147 
    148        val    = col[0];
    149        fir[2] = weights[2] * val;
    150        fir[3] = weights[3] * val;
    151        fir[4] = weights[4] * val;
    152        col   -= pitch;
    153 
    154        val    = col[0];
    155        fir[1] = fir[2] + weights[1] * val;
    156        fir[2] = fir[3] + weights[2] * val;
    157        fir[3] = fir[4] + weights[3] * val;
    158        fir[4] =          weights[4] * val;
    159        col   -= pitch;
    160 
    161        for ( yy = 2; yy < height; yy++, col -= pitch )
    162        {
    163          val    = col[0];
    164          fir[0] = fir[1] + weights[0] * val;
    165          fir[1] = fir[2] + weights[1] * val;
    166          fir[2] = fir[3] + weights[2] * val;
    167          fir[3] = fir[4] + weights[3] * val;
    168          fir[4] =          weights[4] * val;
    169 
    170          col[pitch * 2]  = FT_SHIFTCLAMP( fir[0] );
    171        }
    172 
    173        col[pitch * 2]  = FT_SHIFTCLAMP( fir[1] );
    174        col[pitch]      = FT_SHIFTCLAMP( fir[2] );
    175      }
    176    }
    177  }
    178 
    179 
    180 #ifdef USE_LEGACY
    181 
    182  /* intra-pixel filter used by the legacy filter */
    183  static void
    184  _ft_lcd_filter_legacy( FT_Bitmap*      bitmap,
    185                         FT_Byte*        weights )
    186  {
    187    FT_UInt   width  = (FT_UInt)bitmap->width;
    188    FT_UInt   height = (FT_UInt)bitmap->rows;
    189    FT_Int    pitch  = bitmap->pitch;
    190    FT_Byte*  origin = bitmap->buffer;
    191    FT_Byte   mode   = bitmap->pixel_mode;
    192 
    193    static const unsigned int  filters[3][3] =
    194    {
    195      { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 },
    196      { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 },
    197      { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
    198    };
    199 
    200    FT_UNUSED( weights );
    201 
    202 
    203    /* take care of bitmap flow */
    204    if ( pitch > 0 && height > 0 )
    205      origin += pitch * (FT_Int)( height - 1 );
    206 
    207    /* horizontal in-place intra-pixel filter */
    208    if ( mode == FT_PIXEL_MODE_LCD && width >= 3 )
    209    {
    210      FT_Byte*  line = origin;
    211 
    212 
    213      for ( ; height > 0; height--, line -= pitch )
    214      {
    215        FT_UInt  xx;
    216 
    217 
    218        for ( xx = 0; xx < width; xx += 3 )
    219        {
    220          FT_UInt  r, g, b;
    221          FT_UInt  p;
    222 
    223 
    224          p  = line[xx];
    225          r  = filters[0][0] * p;
    226          g  = filters[0][1] * p;
    227          b  = filters[0][2] * p;
    228 
    229          p  = line[xx + 1];
    230          r += filters[1][0] * p;
    231          g += filters[1][1] * p;
    232          b += filters[1][2] * p;
    233 
    234          p  = line[xx + 2];
    235          r += filters[2][0] * p;
    236          g += filters[2][1] * p;
    237          b += filters[2][2] * p;
    238 
    239          line[xx]     = (FT_Byte)( r / 65536 );
    240          line[xx + 1] = (FT_Byte)( g / 65536 );
    241          line[xx + 2] = (FT_Byte)( b / 65536 );
    242        }
    243      }
    244    }
    245    else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 3 )
    246    {
    247      FT_Byte*  column = origin;
    248 
    249 
    250      for ( ; width > 0; width--, column++ )
    251      {
    252        FT_Byte*  col = column - 2 * pitch;
    253 
    254 
    255        for ( ; height > 0; height -= 3, col -= 3 * pitch )
    256        {
    257          FT_UInt  r, g, b;
    258          FT_UInt  p;
    259 
    260 
    261          p  = col[0];
    262          r  = filters[0][0] * p;
    263          g  = filters[0][1] * p;
    264          b  = filters[0][2] * p;
    265 
    266          p  = col[pitch];
    267          r += filters[1][0] * p;
    268          g += filters[1][1] * p;
    269          b += filters[1][2] * p;
    270 
    271          p  = col[pitch * 2];
    272          r += filters[2][0] * p;
    273          g += filters[2][1] * p;
    274          b += filters[2][2] * p;
    275 
    276          col[0]         = (FT_Byte)( r / 65536 );
    277          col[pitch]     = (FT_Byte)( g / 65536 );
    278          col[pitch * 2] = (FT_Byte)( b / 65536 );
    279        }
    280      }
    281    }
    282  }
    283 
    284 #endif /* USE_LEGACY */
    285 
    286 
    287  /* documentation in ftlcdfil.h */
    288 
    289  FT_EXPORT_DEF( FT_Error )
    290  FT_Library_SetLcdFilterWeights( FT_Library      library,
    291                                  unsigned char  *weights )
    292  {
    293    if ( !library )
    294      return FT_THROW( Invalid_Library_Handle );
    295 
    296    if ( !weights )
    297      return FT_THROW( Invalid_Argument );
    298 
    299    ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS );
    300    library->lcd_filter_func = ft_lcd_filter_fir;
    301 
    302    return FT_Err_Ok;
    303  }
    304 
    305 
    306  /* documentation in ftlcdfil.h */
    307 
    308  FT_EXPORT_DEF( FT_Error )
    309  FT_Library_SetLcdFilter( FT_Library    library,
    310                           FT_LcdFilter  filter )
    311  {
    312    static const FT_LcdFiveTapFilter  default_weights =
    313                   { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
    314    static const FT_LcdFiveTapFilter  light_weights =
    315                   { 0x00, 0x55, 0x56, 0x55, 0x00 };
    316 
    317 
    318    if ( !library )
    319      return FT_THROW( Invalid_Library_Handle );
    320 
    321    switch ( filter )
    322    {
    323    case FT_LCD_FILTER_NONE:
    324      library->lcd_filter_func = NULL;
    325      break;
    326 
    327    case FT_LCD_FILTER_DEFAULT:
    328      ft_memcpy( library->lcd_weights,
    329                 default_weights,
    330                 FT_LCD_FILTER_FIVE_TAPS );
    331      library->lcd_filter_func = ft_lcd_filter_fir;
    332      break;
    333 
    334    case FT_LCD_FILTER_LIGHT:
    335      ft_memcpy( library->lcd_weights,
    336                 light_weights,
    337                 FT_LCD_FILTER_FIVE_TAPS );
    338      library->lcd_filter_func = ft_lcd_filter_fir;
    339      break;
    340 
    341 #ifdef USE_LEGACY
    342 
    343    case FT_LCD_FILTER_LEGACY:
    344    case FT_LCD_FILTER_LEGACY1:
    345      library->lcd_filter_func = _ft_lcd_filter_legacy;
    346      break;
    347 
    348 #endif
    349 
    350    default:
    351      return FT_THROW( Invalid_Argument );
    352    }
    353 
    354    return FT_Err_Ok;
    355  }
    356 
    357 
    358  FT_EXPORT_DEF( FT_Error )
    359  FT_Library_SetLcdGeometry( FT_Library  library,
    360                             FT_Vector   sub[3] )
    361  {
    362    FT_UNUSED( library );
    363    FT_UNUSED( sub );
    364 
    365    return FT_THROW( Unimplemented_Feature );
    366  }
    367 
    368 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    369 
    370  /* add padding to accommodate outline shifts */
    371  FT_BASE_DEF( void )
    372  ft_lcd_padding( FT_BBox*        cbox,
    373                  FT_GlyphSlot    slot,
    374                  FT_Render_Mode  mode )
    375  {
    376    FT_Vector*  sub = slot->library->lcd_geometry;
    377 
    378    if ( mode == FT_RENDER_MODE_LCD )
    379    {
    380      cbox->xMin -= FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x );
    381      cbox->xMax -= FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x );
    382      cbox->yMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y );
    383      cbox->yMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y );
    384    }
    385    else if ( mode == FT_RENDER_MODE_LCD_V )
    386    {
    387      cbox->xMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y );
    388      cbox->xMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y );
    389      cbox->yMin += FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x );
    390      cbox->yMax += FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x );
    391    }
    392  }
    393 
    394 
    395  FT_EXPORT_DEF( FT_Error )
    396  FT_Library_SetLcdFilterWeights( FT_Library      library,
    397                                  unsigned char  *weights )
    398  {
    399    FT_UNUSED( library );
    400    FT_UNUSED( weights );
    401 
    402    return FT_THROW( Unimplemented_Feature );
    403  }
    404 
    405 
    406  FT_EXPORT_DEF( FT_Error )
    407  FT_Library_SetLcdFilter( FT_Library    library,
    408                           FT_LcdFilter  filter )
    409  {
    410    FT_UNUSED( library );
    411    FT_UNUSED( filter );
    412 
    413    return FT_THROW( Unimplemented_Feature );
    414  }
    415 
    416 
    417  /* documentation in ftlcdfil.h */
    418 
    419  FT_EXPORT_DEF( FT_Error )
    420  FT_Library_SetLcdGeometry( FT_Library  library,
    421                             FT_Vector   sub[3] )
    422  {
    423    if ( !library )
    424      return FT_THROW( Invalid_Library_Handle );
    425 
    426    if ( !sub )
    427      return FT_THROW( Invalid_Argument );
    428 
    429    ft_memcpy( library->lcd_geometry, sub, 3 * sizeof( FT_Vector ) );
    430 
    431    return FT_Err_Ok;
    432  }
    433 
    434 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    435 
    436 
    437 /* END */