tor-browser

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

ftsdfrend.c (16209B)


      1 /****************************************************************************
      2 *
      3 * ftsdfrend.c
      4 *
      5 *   Signed Distance Field renderer interface (body).
      6 *
      7 * Copyright (C) 2020-2025 by
      8 * David Turner, Robert Wilhelm, and Werner Lemberg.
      9 *
     10 * Written by Anuj Verma.
     11 *
     12 * This file is part of the FreeType project, and may only be used,
     13 * modified, and distributed under the terms of the FreeType project
     14 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
     15 * this file you indicate that you have read the license and
     16 * understand and accept it fully.
     17 *
     18 */
     19 
     20 
     21 #include <freetype/internal/ftdebug.h>
     22 #include <freetype/internal/ftobjs.h>
     23 #include <freetype/internal/services/svprop.h>
     24 #include <freetype/ftoutln.h>
     25 #include <freetype/ftbitmap.h>
     26 #include "ftsdfrend.h"
     27 #include "ftsdf.h"
     28 
     29 #include "ftsdferrs.h"
     30 
     31 
     32  /**************************************************************************
     33   *
     34   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     35   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     36   * messages during execution.
     37   */
     38 #undef  FT_COMPONENT
     39 #define FT_COMPONENT  sdf
     40 
     41 
     42  /**************************************************************************
     43   *
     44   * macros and default property values
     45   *
     46   */
     47 #define SDF_RENDERER( rend )  ( (SDF_Renderer)rend )
     48 
     49 
     50  /**************************************************************************
     51   *
     52   * for setting properties
     53   *
     54   */
     55 
     56  /* property setter function */
     57  static FT_Error
     58  sdf_property_set( FT_Module    module,
     59                    const char*  property_name,
     60                    const void*  value,
     61                    FT_Bool      value_is_string )
     62  {
     63    FT_Error      error  = FT_Err_Ok;
     64    SDF_Renderer  render = SDF_RENDERER( FT_RENDERER( module ) );
     65 
     66    FT_UNUSED( value_is_string );
     67 
     68 
     69    if ( ft_strcmp( property_name, "spread" ) == 0 )
     70    {
     71      FT_Int  val = *(const FT_Int*)value;
     72 
     73 
     74      if ( val > MAX_SPREAD || val < MIN_SPREAD )
     75      {
     76        FT_TRACE0(( "[sdf] sdf_property_set:"
     77                    " the `spread' property can have a value\n" ));
     78        FT_TRACE0(( "                       "
     79                    " within range [%d, %d] (value provided: %d)\n",
     80                    MIN_SPREAD, MAX_SPREAD, val ));
     81 
     82        error = FT_THROW( Invalid_Argument );
     83        goto Exit;
     84      }
     85 
     86      render->spread = (FT_UInt)val;
     87      FT_TRACE7(( "[sdf] sdf_property_set:"
     88                  " updated property `spread' to %d\n", val ));
     89    }
     90 
     91    else if ( ft_strcmp( property_name, "flip_sign" ) == 0 )
     92    {
     93      FT_Int  val = *(const FT_Int*)value;
     94 
     95 
     96      render->flip_sign = val ? 1 : 0;
     97      FT_TRACE7(( "[sdf] sdf_property_set:"
     98                  " updated property `flip_sign' to %d\n", val ));
     99    }
    100 
    101    else if ( ft_strcmp( property_name, "flip_y" ) == 0 )
    102    {
    103      FT_Int  val = *(const FT_Int*)value;
    104 
    105 
    106      render->flip_y = val ? 1 : 0;
    107      FT_TRACE7(( "[sdf] sdf_property_set:"
    108                  " updated property `flip_y' to %d\n", val ));
    109    }
    110 
    111    else if ( ft_strcmp( property_name, "overlaps" ) == 0 )
    112    {
    113      FT_Bool  val = *(const FT_Bool*)value;
    114 
    115 
    116      render->overlaps = val;
    117      FT_TRACE7(( "[sdf] sdf_property_set:"
    118                  " updated property `overlaps' to %d\n", val ));
    119    }
    120 
    121    else
    122    {
    123      FT_TRACE0(( "[sdf] sdf_property_set:"
    124                  " missing property `%s'\n", property_name ));
    125      error = FT_THROW( Missing_Property );
    126    }
    127 
    128  Exit:
    129    return error;
    130  }
    131 
    132 
    133  /* property getter function */
    134  static FT_Error
    135  sdf_property_get( FT_Module    module,
    136                    const char*  property_name,
    137                    void*        value )
    138  {
    139    FT_Error      error  = FT_Err_Ok;
    140    SDF_Renderer  render = SDF_RENDERER( FT_RENDERER( module ) );
    141 
    142 
    143    if ( ft_strcmp( property_name, "spread" ) == 0 )
    144    {
    145      FT_UInt*  val = (FT_UInt*)value;
    146 
    147 
    148      *val = render->spread;
    149    }
    150 
    151    else if ( ft_strcmp( property_name, "flip_sign" ) == 0 )
    152    {
    153      FT_Int*  val = (FT_Int*)value;
    154 
    155 
    156      *val = render->flip_sign;
    157    }
    158 
    159    else if ( ft_strcmp( property_name, "flip_y" ) == 0 )
    160    {
    161      FT_Int*  val = (FT_Int*)value;
    162 
    163 
    164      *val = render->flip_y;
    165    }
    166 
    167    else if ( ft_strcmp( property_name, "overlaps" ) == 0 )
    168    {
    169      FT_Int*  val = (FT_Int*)value;
    170 
    171 
    172      *val = render->overlaps;
    173    }
    174 
    175    else
    176    {
    177      FT_TRACE0(( "[sdf] sdf_property_get:"
    178                  " missing property `%s'\n", property_name ));
    179      error = FT_THROW( Missing_Property );
    180    }
    181 
    182    return error;
    183  }
    184 
    185 
    186  FT_DEFINE_SERVICE_PROPERTIESREC(
    187    sdf_service_properties,
    188 
    189    (FT_Properties_SetFunc)sdf_property_set,        /* set_property */
    190    (FT_Properties_GetFunc)sdf_property_get )       /* get_property */
    191 
    192 
    193  FT_DEFINE_SERVICEDESCREC1(
    194    sdf_services,
    195 
    196    FT_SERVICE_ID_PROPERTIES, &sdf_service_properties )
    197 
    198 
    199  static FT_Module_Interface
    200  ft_sdf_requester( FT_Module    module,
    201                    const char*  module_interface )
    202  {
    203    FT_UNUSED( module );
    204 
    205    return ft_service_list_lookup( sdf_services, module_interface );
    206  }
    207 
    208 
    209  /*************************************************************************/
    210  /*************************************************************************/
    211  /**                                                                     **/
    212  /**  OUTLINE TO SDF CONVERTER                                           **/
    213  /**                                                                     **/
    214  /*************************************************************************/
    215  /*************************************************************************/
    216 
    217  /**************************************************************************
    218   *
    219   * interface functions
    220   *
    221   */
    222 
    223  static FT_Error
    224  ft_sdf_init( FT_Module  module )   /* SDF_Renderer */
    225  {
    226    SDF_Renderer  sdf_render = SDF_RENDERER( module );
    227 
    228 
    229    sdf_render->spread    = DEFAULT_SPREAD;
    230    sdf_render->flip_sign = 0;
    231    sdf_render->flip_y    = 0;
    232    sdf_render->overlaps  = 0;
    233 
    234    return FT_Err_Ok;
    235  }
    236 
    237 
    238  static void
    239  ft_sdf_done( FT_Module  module )
    240  {
    241    FT_UNUSED( module );
    242  }
    243 
    244 
    245  /* generate signed distance field from a glyph's slot image */
    246  static FT_Error
    247  ft_sdf_render( FT_Renderer       module,
    248                 FT_GlyphSlot      slot,
    249                 FT_Render_Mode    mode,
    250                 const FT_Vector*  origin )
    251  {
    252    FT_Error     error   = FT_Err_Ok;
    253    FT_Outline*  outline = &slot->outline;
    254    FT_Bitmap*   bitmap  = &slot->bitmap;
    255    FT_Memory    memory  = NULL;
    256    FT_Renderer  render  = NULL;
    257 
    258    FT_Pos  x_shift = 0;
    259    FT_Pos  y_shift = 0;
    260 
    261    FT_Pos  x_pad = 0;
    262    FT_Pos  y_pad = 0;
    263 
    264    SDF_Raster_Params  params;
    265    SDF_Renderer       sdf_module = SDF_RENDERER( module );
    266 
    267 
    268    render = &sdf_module->root;
    269    memory = render->root.memory;
    270 
    271    /* check whether slot format is correct before rendering */
    272    if ( slot->format != render->glyph_format )
    273    {
    274      error = FT_THROW( Invalid_Glyph_Format );
    275      goto Exit;
    276    }
    277 
    278    /* check whether render mode is correct */
    279    if ( mode != FT_RENDER_MODE_SDF )
    280    {
    281      error = FT_THROW( Cannot_Render_Glyph );
    282      goto Exit;
    283    }
    284 
    285    /* deallocate the previously allocated bitmap */
    286    if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    287    {
    288      FT_FREE( bitmap->buffer );
    289      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    290    }
    291 
    292    /* preset the bitmap using the glyph's outline;         */
    293    /* the sdf bitmap is similar to an anti-aliased bitmap  */
    294    /* with a slightly bigger size and different pixel mode */
    295    if ( ft_glyphslot_preset_bitmap( slot, FT_RENDER_MODE_NORMAL, origin ) )
    296    {
    297      error = FT_THROW( Raster_Overflow );
    298      goto Exit;
    299    }
    300 
    301    /* nothing to render */
    302    if ( !bitmap->rows || !bitmap->pitch )
    303      goto Exit;
    304 
    305    /* the padding will simply be equal to the `spread' */
    306    x_pad = sdf_module->spread;
    307    y_pad = sdf_module->spread;
    308 
    309    /* apply the padding; will be in all the directions */
    310    bitmap->rows  += y_pad * 2;
    311    bitmap->width += x_pad * 2;
    312 
    313    /* ignore the pitch, pixel mode and set custom */
    314    bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
    315    bitmap->pitch      = (int)( bitmap->width );
    316    bitmap->num_grays  = 255;
    317 
    318    /* allocate new buffer */
    319    if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
    320      goto Exit;
    321 
    322    slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
    323 
    324    slot->bitmap_top  += y_pad;
    325    slot->bitmap_left -= x_pad;
    326 
    327    x_shift  = 64 * -slot->bitmap_left;
    328    y_shift  = 64 * -slot->bitmap_top;
    329    y_shift += 64 * (FT_Int)bitmap->rows;
    330 
    331    if ( origin )
    332    {
    333      x_shift += origin->x;
    334      y_shift += origin->y;
    335    }
    336 
    337    /* translate outline to render it into the bitmap */
    338    if ( x_shift || y_shift )
    339      FT_Outline_Translate( outline, x_shift, y_shift );
    340 
    341    /* set up parameters */
    342    params.root.target = bitmap;
    343    params.root.source = outline;
    344    params.root.flags  = FT_RASTER_FLAG_SDF;
    345    params.spread      = sdf_module->spread;
    346    params.flip_sign   = sdf_module->flip_sign;
    347    params.flip_y      = sdf_module->flip_y;
    348    params.overlaps    = sdf_module->overlaps;
    349 
    350    /* render the outline */
    351    error = render->raster_render( render->raster,
    352                                   (const FT_Raster_Params*)&params );
    353 
    354    /* transform the outline back to the original state */
    355    if ( x_shift || y_shift )
    356      FT_Outline_Translate( outline, -x_shift, -y_shift );
    357 
    358  Exit:
    359    if ( !error )
    360    {
    361      /* the glyph is successfully rendered to a bitmap */
    362      slot->format = FT_GLYPH_FORMAT_BITMAP;
    363    }
    364    else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    365    {
    366      FT_FREE( bitmap->buffer );
    367      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    368    }
    369 
    370    return error;
    371  }
    372 
    373 
    374  /* transform the glyph using matrix and/or delta */
    375  static FT_Error
    376  ft_sdf_transform( FT_Renderer       render,
    377                    FT_GlyphSlot      slot,
    378                    const FT_Matrix*  matrix,
    379                    const FT_Vector*  delta )
    380  {
    381    FT_Error  error = FT_Err_Ok;
    382 
    383 
    384    if ( slot->format != render->glyph_format )
    385    {
    386      error = FT_THROW( Invalid_Argument );
    387      goto Exit;
    388    }
    389 
    390    if ( matrix )
    391      FT_Outline_Transform( &slot->outline, matrix );
    392 
    393    if ( delta )
    394      FT_Outline_Translate( &slot->outline, delta->x, delta->y );
    395 
    396  Exit:
    397    return error;
    398  }
    399 
    400 
    401  /* return the control box of a glyph's outline */
    402  static void
    403  ft_sdf_get_cbox( FT_Renderer   render,
    404                   FT_GlyphSlot  slot,
    405                   FT_BBox*      cbox )
    406  {
    407    FT_ZERO( cbox );
    408 
    409    if ( slot->format == render->glyph_format )
    410      FT_Outline_Get_CBox( &slot->outline, cbox );
    411  }
    412 
    413 
    414  /* set render specific modes or attributes */
    415  static FT_Error
    416  ft_sdf_set_mode( FT_Renderer  render,
    417                   FT_ULong     mode_tag,
    418                   FT_Pointer   data )
    419  {
    420    /* pass it to the rasterizer */
    421    return render->clazz->raster_class->raster_set_mode( render->raster,
    422                                                         mode_tag,
    423                                                         data );
    424  }
    425 
    426 
    427  FT_DEFINE_RENDERER(
    428    ft_sdf_renderer_class,
    429 
    430    FT_MODULE_RENDERER,
    431    sizeof ( SDF_Renderer_Module ),
    432 
    433    "sdf",
    434    0x10000L,
    435    0x20000L,
    436 
    437    NULL,
    438 
    439    (FT_Module_Constructor)ft_sdf_init,
    440    (FT_Module_Destructor) ft_sdf_done,
    441    (FT_Module_Requester)  ft_sdf_requester,
    442 
    443    FT_GLYPH_FORMAT_OUTLINE,
    444 
    445    (FT_Renderer_RenderFunc)   ft_sdf_render,     /* render_glyph    */
    446    (FT_Renderer_TransformFunc)ft_sdf_transform,  /* transform_glyph */
    447    (FT_Renderer_GetCBoxFunc)  ft_sdf_get_cbox,   /* get_glyph_cbox  */
    448    (FT_Renderer_SetModeFunc)  ft_sdf_set_mode,   /* set_mode        */
    449 
    450    (FT_Raster_Funcs*)&ft_sdf_raster              /* raster_class    */
    451  )
    452 
    453 
    454  /*************************************************************************/
    455  /*************************************************************************/
    456  /**                                                                     **/
    457  /**  BITMAP TO SDF CONVERTER                                            **/
    458  /**                                                                     **/
    459  /*************************************************************************/
    460  /*************************************************************************/
    461 
    462  /* generate signed distance field from glyph's bitmap */
    463  static FT_Error
    464  ft_bsdf_render( FT_Renderer       module,
    465                  FT_GlyphSlot      slot,
    466                  FT_Render_Mode    mode,
    467                  const FT_Vector*  origin )
    468  {
    469    FT_Error   error  = FT_Err_Ok;
    470    FT_Memory  memory = NULL;
    471 
    472    FT_Bitmap*   bitmap  = &slot->bitmap;
    473    FT_Renderer  render  = NULL;
    474    FT_Bitmap    target;
    475 
    476    FT_Pos  x_pad = 0;
    477    FT_Pos  y_pad = 0;
    478 
    479    SDF_Raster_Params  params;
    480    SDF_Renderer       sdf_module = SDF_RENDERER( module );
    481 
    482 
    483    /* initialize the bitmap in case any error occurs */
    484    FT_Bitmap_Init( &target );
    485 
    486    render = &sdf_module->root;
    487    memory = render->root.memory;
    488 
    489    /* check whether slot format is correct before rendering */
    490    if ( slot->format != render->glyph_format )
    491    {
    492      error = FT_THROW( Invalid_Glyph_Format );
    493      goto Exit;
    494    }
    495 
    496    /* check whether render mode is correct */
    497    if ( mode != FT_RENDER_MODE_SDF )
    498    {
    499      error = FT_THROW( Cannot_Render_Glyph );
    500      goto Exit;
    501    }
    502 
    503    if ( origin )
    504    {
    505      FT_ERROR(( "ft_bsdf_render: can't translate the bitmap\n" ));
    506 
    507      error = FT_THROW( Unimplemented_Feature );
    508      goto Exit;
    509    }
    510 
    511    /* nothing to render */
    512    if ( !bitmap->rows || !bitmap->pitch )
    513      goto Exit;
    514 
    515    /* Do not generate SDF if the bitmap is not owned by the       */
    516    /* glyph: it might be that the source buffer is already freed. */
    517    if ( !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
    518    {
    519      FT_ERROR(( "ft_bsdf_render: can't generate SDF from"
    520                 " unowned source bitmap\n" ));
    521 
    522      error = FT_THROW( Invalid_Argument );
    523      goto Exit;
    524    }
    525 
    526    FT_Bitmap_New( &target );
    527 
    528    /* padding will simply be equal to `spread` */
    529    x_pad = sdf_module->spread;
    530    y_pad = sdf_module->spread;
    531 
    532    /* apply padding, which extends to all directions */
    533    target.rows  = bitmap->rows  + y_pad * 2;
    534    target.width = bitmap->width + x_pad * 2;
    535 
    536    /* set up the target bitmap */
    537    target.pixel_mode = FT_PIXEL_MODE_GRAY;
    538    target.pitch      = (int)( target.width );
    539    target.num_grays  = 255;
    540 
    541    if ( FT_ALLOC_MULT( target.buffer, target.rows, target.pitch ) )
    542      goto Exit;
    543 
    544    /* set up parameters */
    545    params.root.target = &target;
    546    params.root.source = bitmap;
    547    params.root.flags  = FT_RASTER_FLAG_SDF;
    548    params.spread      = sdf_module->spread;
    549    params.flip_sign   = sdf_module->flip_sign;
    550    params.flip_y      = sdf_module->flip_y;
    551 
    552    error = render->raster_render( render->raster,
    553                                   (const FT_Raster_Params*)&params );
    554 
    555  Exit:
    556    if ( !error )
    557    {
    558      /* the glyph is successfully converted to a SDF */
    559      if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    560        FT_FREE( bitmap->buffer );
    561 
    562      slot->bitmap       = target;
    563      slot->bitmap_top  += y_pad;
    564      slot->bitmap_left -= x_pad;
    565 
    566      if ( target.buffer )
    567        slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
    568    }
    569    else if ( target.buffer )
    570      FT_FREE( target.buffer );
    571 
    572    return error;
    573  }
    574 
    575 
    576  FT_DEFINE_RENDERER(
    577    ft_bitmap_sdf_renderer_class,
    578 
    579    FT_MODULE_RENDERER,
    580    sizeof ( SDF_Renderer_Module ),
    581 
    582    "bsdf",
    583    0x10000L,
    584    0x20000L,
    585 
    586    NULL,
    587 
    588    (FT_Module_Constructor)ft_sdf_init,
    589    (FT_Module_Destructor) ft_sdf_done,
    590    (FT_Module_Requester)  ft_sdf_requester,
    591 
    592    FT_GLYPH_FORMAT_BITMAP,
    593 
    594    (FT_Renderer_RenderFunc)   ft_bsdf_render,    /* render_glyph    */
    595    (FT_Renderer_TransformFunc)ft_sdf_transform,  /* transform_glyph */
    596    (FT_Renderer_GetCBoxFunc)  ft_sdf_get_cbox,   /* get_glyph_cbox  */
    597    (FT_Renderer_SetModeFunc)  ft_sdf_set_mode,   /* set_mode        */
    598 
    599    (FT_Raster_Funcs*)&ft_bitmap_sdf_raster       /* raster_class    */
    600  )
    601 
    602 
    603 /* END */