tor-browser

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

ftsmooth.c (16549B)


      1 /****************************************************************************
      2 *
      3 * ftsmooth.c
      4 *
      5 *   Anti-aliasing renderer interface (body).
      6 *
      7 * Copyright (C) 2000-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 #include <freetype/internal/ftobjs.h>
     21 #include <freetype/ftoutln.h>
     22 #include "ftsmooth.h"
     23 #include "ftgrays.h"
     24 
     25 #include "ftsmerrs.h"
     26 
     27 
     28  /* sets render-specific mode */
     29  static FT_Error
     30  ft_smooth_set_mode( FT_Renderer  render,
     31                      FT_ULong     mode_tag,
     32                      FT_Pointer   data )
     33  {
     34    /* we simply pass it to the raster */
     35    return render->clazz->raster_class->raster_set_mode( render->raster,
     36                                                         mode_tag,
     37                                                         data );
     38  }
     39 
     40  /* transform a given glyph image */
     41  static FT_Error
     42  ft_smooth_transform( FT_Renderer       render,
     43                       FT_GlyphSlot      slot,
     44                       const FT_Matrix*  matrix,
     45                       const FT_Vector*  delta )
     46  {
     47    FT_Error  error = FT_Err_Ok;
     48 
     49 
     50    if ( slot->format != render->glyph_format )
     51    {
     52      error = FT_THROW( Invalid_Argument );
     53      goto Exit;
     54    }
     55 
     56    if ( matrix )
     57      FT_Outline_Transform( &slot->outline, matrix );
     58 
     59    if ( delta )
     60      FT_Outline_Translate( &slot->outline, delta->x, delta->y );
     61 
     62  Exit:
     63    return error;
     64  }
     65 
     66 
     67  /* return the glyph's control box */
     68  static void
     69  ft_smooth_get_cbox( FT_Renderer   render,
     70                      FT_GlyphSlot  slot,
     71                      FT_BBox*      cbox )
     72  {
     73    FT_ZERO( cbox );
     74 
     75    if ( slot->format == render->glyph_format )
     76      FT_Outline_Get_CBox( &slot->outline, cbox );
     77  }
     78 
     79  typedef struct TOrigin_
     80  {
     81    unsigned char*  origin;  /* pixmap origin at the bottom-left */
     82    int             pitch;   /* pitch to go down one row */
     83 
     84  } TOrigin;
     85 
     86 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
     87 
     88  /* initialize renderer -- init its raster */
     89  static FT_Error
     90  ft_smooth_init( FT_Module  module )   /* FT_Renderer */
     91  {
     92    FT_Renderer  render = (FT_Renderer)module;
     93 
     94    FT_Vector*  sub = render->root.library->lcd_geometry;
     95 
     96 
     97    /* set up default subpixel geometry for striped RGB panels. */
     98    sub[0].x = -21;
     99    sub[0].y = 0;
    100    sub[1].x = 0;
    101    sub[1].y = 0;
    102    sub[2].x = 21;
    103    sub[2].y = 0;
    104 
    105    render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
    106 
    107    return 0;
    108  }
    109 
    110 
    111  /* This function writes every third byte in direct rendering mode */
    112  static void
    113  ft_smooth_lcd_spans( int             y,
    114                       int             count,
    115                       const FT_Span*  spans,
    116                       void*           target_ )   /* TOrigin* */
    117  {
    118    TOrigin*  target = (TOrigin*)target_;
    119 
    120    unsigned char*  dst_line = target->origin - y * target->pitch;
    121    unsigned char*  dst;
    122    unsigned short  w;
    123 
    124 
    125    for ( ; count--; spans++ )
    126      for ( dst = dst_line + spans->x * 3, w = spans->len; w--; dst += 3 )
    127        *dst = spans->coverage;
    128  }
    129 
    130 
    131  static FT_Error
    132  ft_smooth_raster_lcd( FT_Renderer  render,
    133                        FT_Outline*  outline,
    134                        FT_Bitmap*   bitmap )
    135  {
    136    FT_Error      error = FT_Err_Ok;
    137    FT_Vector*    sub   = render->root.library->lcd_geometry;
    138    FT_Pos        x, y;
    139 
    140    FT_Raster_Params   params;
    141    TOrigin            target;
    142 
    143 
    144    /* Render 3 separate coverage bitmaps, shifting the outline.  */
    145    /* Set up direct rendering to record them on each third byte. */
    146    params.source     = outline;
    147    params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
    148    params.gray_spans = ft_smooth_lcd_spans;
    149    params.user       = &target;
    150 
    151    params.clip_box.xMin = 0;
    152    params.clip_box.yMin = 0;
    153    params.clip_box.xMax = bitmap->width;
    154    params.clip_box.yMax = bitmap->rows;
    155 
    156    if ( bitmap->pitch < 0 )
    157      target.origin = bitmap->buffer;
    158    else
    159      target.origin = bitmap->buffer
    160                      + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
    161 
    162    target.pitch = bitmap->pitch;
    163 
    164    FT_Outline_Translate( outline,
    165                          -sub[0].x,
    166                          -sub[0].y );
    167    error = render->raster_render( render->raster, &params );
    168    x = sub[0].x;
    169    y = sub[0].y;
    170    if ( error )
    171      goto Exit;
    172 
    173    target.origin++;
    174    FT_Outline_Translate( outline,
    175                          sub[0].x - sub[1].x,
    176                          sub[0].y - sub[1].y );
    177    error = render->raster_render( render->raster, &params );
    178    x = sub[1].x;
    179    y = sub[1].y;
    180    if ( error )
    181      goto Exit;
    182 
    183    target.origin++;
    184    FT_Outline_Translate( outline,
    185                          sub[1].x - sub[2].x,
    186                          sub[1].y - sub[2].y );
    187    error = render->raster_render( render->raster, &params );
    188    x = sub[2].x;
    189    y = sub[2].y;
    190 
    191  Exit:
    192    FT_Outline_Translate( outline, x, y );
    193 
    194    return error;
    195  }
    196 
    197 
    198  static FT_Error
    199  ft_smooth_raster_lcdv( FT_Renderer  render,
    200                         FT_Outline*  outline,
    201                         FT_Bitmap*   bitmap )
    202  {
    203    FT_Error     error = FT_Err_Ok;
    204    int          pitch = bitmap->pitch;
    205    FT_Vector*   sub   = render->root.library->lcd_geometry;
    206    FT_Pos       x, y;
    207 
    208    FT_Raster_Params  params;
    209 
    210 
    211    params.target = bitmap;
    212    params.source = outline;
    213    params.flags  = FT_RASTER_FLAG_AA;
    214 
    215    /* Render 3 separate coverage bitmaps, shifting the outline. */
    216    /* Notice that the subpixel geometry vectors are rotated.    */
    217    /* Triple the pitch to render on each third row.            */
    218    bitmap->pitch *= 3;
    219    bitmap->rows  /= 3;
    220 
    221    FT_Outline_Translate( outline,
    222                          -sub[0].y,
    223                          sub[0].x );
    224    error = render->raster_render( render->raster, &params );
    225    x = sub[0].y;
    226    y = -sub[0].x;
    227    if ( error )
    228      goto Exit;
    229 
    230    bitmap->buffer += pitch;
    231    FT_Outline_Translate( outline,
    232                          sub[0].y - sub[1].y,
    233                          sub[1].x - sub[0].x );
    234    error = render->raster_render( render->raster, &params );
    235    x = sub[1].y;
    236    y = -sub[1].x;
    237    bitmap->buffer -= pitch;
    238    if ( error )
    239      goto Exit;
    240 
    241    bitmap->buffer += 2 * pitch;
    242    FT_Outline_Translate( outline,
    243                          sub[1].y - sub[2].y,
    244                          sub[2].x - sub[1].x );
    245    error = render->raster_render( render->raster, &params );
    246    x = sub[2].y;
    247    y = -sub[2].x;
    248    bitmap->buffer -= 2 * pitch;
    249 
    250  Exit:
    251    FT_Outline_Translate( outline, x, y );
    252 
    253    bitmap->pitch /= 3;
    254    bitmap->rows  *= 3;
    255 
    256    return error;
    257  }
    258 
    259 #else   /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    260 
    261  /* initialize renderer -- init its raster */
    262  static FT_Error
    263  ft_smooth_init( FT_Module  module )   /* FT_Renderer */
    264  {
    265    FT_Renderer  render = (FT_Renderer)module;
    266 
    267 
    268    /* set up default LCD filtering */
    269    FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT );
    270 
    271    render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
    272 
    273    return 0;
    274  }
    275 
    276 
    277  static FT_Error
    278  ft_smooth_raster_lcd( FT_Renderer  render,
    279                        FT_Outline*  outline,
    280                        FT_Bitmap*   bitmap )
    281  {
    282    FT_Error    error      = FT_Err_Ok;
    283    FT_Vector*  points     = outline->points;
    284    FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
    285    FT_Vector*  vec;
    286 
    287    FT_Raster_Params  params;
    288 
    289 
    290    params.target = bitmap;
    291    params.source = outline;
    292    params.flags  = FT_RASTER_FLAG_AA;
    293 
    294    /* implode outline */
    295    for ( vec = points; vec < points_end; vec++ )
    296      vec->x *= 3;
    297 
    298    /* render outline into the bitmap */
    299    error = render->raster_render( render->raster, &params );
    300 
    301    /* deflate outline */
    302    for ( vec = points; vec < points_end; vec++ )
    303      vec->x /= 3;
    304 
    305    return error;
    306  }
    307 
    308 
    309  static FT_Error
    310  ft_smooth_raster_lcdv( FT_Renderer  render,
    311                         FT_Outline*  outline,
    312                         FT_Bitmap*   bitmap )
    313  {
    314    FT_Error    error      = FT_Err_Ok;
    315    FT_Vector*  points     = outline->points;
    316    FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
    317    FT_Vector*  vec;
    318 
    319    FT_Raster_Params  params;
    320 
    321 
    322    params.target = bitmap;
    323    params.source = outline;
    324    params.flags  = FT_RASTER_FLAG_AA;
    325 
    326    /* implode outline */
    327    for ( vec = points; vec < points_end; vec++ )
    328      vec->y *= 3;
    329 
    330    /* render outline into the bitmap */
    331    error = render->raster_render( render->raster, &params );
    332 
    333    /* deflate outline */
    334    for ( vec = points; vec < points_end; vec++ )
    335      vec->y /= 3;
    336 
    337    return error;
    338  }
    339 
    340 #endif  /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    341 
    342 /* Oversampling scale to be used in rendering overlaps */
    343 #define SCALE  ( 1 << 2 )
    344 
    345  /* This function averages inflated spans in direct rendering mode */
    346  static void
    347  ft_smooth_overlap_spans( int             y,
    348                           int             count,
    349                           const FT_Span*  spans,
    350                           void*           target_ )
    351  {
    352    TOrigin*  target = (TOrigin*)target_;
    353 
    354 
    355    unsigned char*  dst = target->origin - ( y / SCALE ) * target->pitch;
    356    unsigned short  x;
    357    unsigned int    cover, sum;
    358 
    359 
    360    /* When accumulating the oversampled spans we need to assure that  */
    361    /* fully covered pixels are equal to 255 and do not overflow.      */
    362    /* It is important that the SCALE is a power of 2, each subpixel   */
    363    /* cover can also reach a power of 2 after rounding, and the total */
    364    /* is clamped to 255 when it adds up to 256.                       */
    365    for ( ; count--; spans++ )
    366    {
    367      cover = ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE );
    368      for ( x = 0; x < spans->len; x++ )
    369      {
    370        sum                           = dst[( spans->x + x ) / SCALE] + cover;
    371        dst[( spans->x + x ) / SCALE] = (unsigned char)( sum - ( sum >> 8 ) );
    372      }
    373    }
    374  }
    375 
    376 
    377  static FT_Error
    378  ft_smooth_raster_overlap( FT_Renderer  render,
    379                            FT_Outline*  outline,
    380                            FT_Bitmap*   bitmap )
    381  {
    382    FT_Error    error      = FT_Err_Ok;
    383    FT_Vector*  points     = outline->points;
    384    FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
    385    FT_Vector*  vec;
    386 
    387    FT_Raster_Params   params;
    388    TOrigin            target;
    389 
    390 
    391    /* Reject outlines that are too wide for 16-bit FT_Span.       */
    392    /* Other limits are applied upstream with the same error code. */
    393    if ( bitmap->width * SCALE > 0x7FFF )
    394      return FT_THROW( Raster_Overflow );
    395 
    396    /* Set up direct rendering to average oversampled spans. */
    397    params.source     = outline;
    398    params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
    399    params.gray_spans = ft_smooth_overlap_spans;
    400    params.user       = &target;
    401 
    402    params.clip_box.xMin = 0;
    403    params.clip_box.yMin = 0;
    404    params.clip_box.xMax = bitmap->width * SCALE;
    405    params.clip_box.yMax = bitmap->rows  * SCALE;
    406 
    407    if ( bitmap->pitch < 0 )
    408      target.origin = bitmap->buffer;
    409    else
    410      target.origin = bitmap->buffer
    411                      + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
    412 
    413    target.pitch = bitmap->pitch;
    414 
    415    /* inflate outline */
    416    for ( vec = points; vec < points_end; vec++ )
    417    {
    418      vec->x *= SCALE;
    419      vec->y *= SCALE;
    420    }
    421 
    422    /* render outline into the bitmap */
    423    error = render->raster_render( render->raster, &params );
    424 
    425    /* deflate outline */
    426    for ( vec = points; vec < points_end; vec++ )
    427    {
    428      vec->x /= SCALE;
    429      vec->y /= SCALE;
    430    }
    431 
    432    return error;
    433  }
    434 
    435 #undef SCALE
    436 
    437  static FT_Error
    438  ft_smooth_render( FT_Renderer       render,
    439                    FT_GlyphSlot      slot,
    440                    FT_Render_Mode    mode,
    441                    const FT_Vector*  origin )
    442  {
    443    FT_Error     error   = FT_Err_Ok;
    444    FT_Outline*  outline = &slot->outline;
    445    FT_Bitmap*   bitmap  = &slot->bitmap;
    446    FT_Memory    memory  = render->root.memory;
    447    FT_Pos       x_shift = 0;
    448    FT_Pos       y_shift = 0;
    449 
    450 
    451    /* check glyph image format */
    452    if ( slot->format != render->glyph_format )
    453    {
    454      error = FT_THROW( Invalid_Argument );
    455      goto Exit;
    456    }
    457 
    458    /* check mode */
    459    if ( mode != FT_RENDER_MODE_NORMAL &&
    460         mode != FT_RENDER_MODE_LIGHT  &&
    461         mode != FT_RENDER_MODE_LCD    &&
    462         mode != FT_RENDER_MODE_LCD_V  )
    463    {
    464      error = FT_THROW( Cannot_Render_Glyph );
    465      goto Exit;
    466    }
    467 
    468    /* release old bitmap buffer */
    469    if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    470    {
    471      FT_FREE( bitmap->buffer );
    472      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    473    }
    474 
    475    if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) )
    476    {
    477      error = FT_THROW( Raster_Overflow );
    478      goto Exit;
    479    }
    480 
    481    if ( !bitmap->rows || !bitmap->pitch )
    482      goto Exit;
    483 
    484    /* allocate new one */
    485    if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
    486      goto Exit;
    487 
    488    slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
    489 
    490    x_shift = 64 * -slot->bitmap_left;
    491    y_shift = 64 * -slot->bitmap_top;
    492    if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
    493      y_shift += 64 * (FT_Int)bitmap->rows / 3;
    494    else
    495      y_shift += 64 * (FT_Int)bitmap->rows;
    496 
    497    if ( origin )
    498    {
    499      x_shift += origin->x;
    500      y_shift += origin->y;
    501    }
    502 
    503    /* translate outline to render it into the bitmap */
    504    if ( x_shift || y_shift )
    505      FT_Outline_Translate( outline, x_shift, y_shift );
    506 
    507    if ( mode == FT_RENDER_MODE_NORMAL ||
    508         mode == FT_RENDER_MODE_LIGHT  )
    509    {
    510      if ( outline->flags & FT_OUTLINE_OVERLAP )
    511        error = ft_smooth_raster_overlap( render, outline, bitmap );
    512      else
    513      {
    514        FT_Raster_Params  params;
    515 
    516 
    517        params.target = bitmap;
    518        params.source = outline;
    519        params.flags  = FT_RASTER_FLAG_AA;
    520 
    521        error = render->raster_render( render->raster, &params );
    522      }
    523    }
    524    else
    525    {
    526      if ( mode == FT_RENDER_MODE_LCD )
    527        error = ft_smooth_raster_lcd ( render, outline, bitmap );
    528      else if ( mode == FT_RENDER_MODE_LCD_V )
    529        error = ft_smooth_raster_lcdv( render, outline, bitmap );
    530 
    531 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    532 
    533      /* finally apply filtering */
    534      {
    535        FT_Byte*                 lcd_weights;
    536        FT_Bitmap_LcdFilterFunc  lcd_filter_func;
    537 
    538 
    539        /* Per-face LCD filtering takes priority if set up. */
    540        if ( slot->face && slot->face->internal->lcd_filter_func )
    541        {
    542          lcd_weights     = slot->face->internal->lcd_weights;
    543          lcd_filter_func = slot->face->internal->lcd_filter_func;
    544        }
    545        else
    546        {
    547          lcd_weights     = slot->library->lcd_weights;
    548          lcd_filter_func = slot->library->lcd_filter_func;
    549        }
    550 
    551        if ( lcd_filter_func )
    552          lcd_filter_func( bitmap, lcd_weights );
    553      }
    554 
    555 #endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    556 
    557    }
    558 
    559  Exit:
    560    if ( !error )
    561    {
    562      /* everything is fine; the glyph is now officially a bitmap */
    563      slot->format = FT_GLYPH_FORMAT_BITMAP;
    564    }
    565    else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    566    {
    567      FT_FREE( bitmap->buffer );
    568      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    569    }
    570 
    571    if ( x_shift || y_shift )
    572      FT_Outline_Translate( outline, -x_shift, -y_shift );
    573 
    574    return error;
    575  }
    576 
    577 
    578  FT_DEFINE_RENDERER(
    579    ft_smooth_renderer_class,
    580 
    581      FT_MODULE_RENDERER,
    582      sizeof ( FT_RendererRec ),
    583 
    584      "smooth",
    585      0x10000L,
    586      0x20000L,
    587 
    588      NULL,    /* module specific interface */
    589 
    590      (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
    591      (FT_Module_Destructor) NULL,            /* module_done   */
    592      (FT_Module_Requester)  NULL,            /* get_interface */
    593 
    594    FT_GLYPH_FORMAT_OUTLINE,
    595 
    596    (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */
    597    (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */
    598    (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */
    599    (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */
    600 
    601    (FT_Raster_Funcs*)&ft_grays_raster               /* raster_class    */
    602  )
    603 
    604 
    605 /* END */