tor-browser

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

ftsvg.c (8942B)


      1 /****************************************************************************
      2 *
      3 * ftsvg.c
      4 *
      5 *   The FreeType SVG renderer interface (body).
      6 *
      7 * Copyright (C) 2022-2025 by
      8 * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
      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 #include <freetype/internal/ftdebug.h>
     19 #include <freetype/internal/ftserv.h>
     20 #include <freetype/internal/services/svprop.h>
     21 #include <freetype/otsvg.h>
     22 #include <freetype/internal/svginterface.h>
     23 #include <freetype/ftbbox.h>
     24 
     25 #include "ftsvg.h"
     26 #include "svgtypes.h"
     27 
     28 
     29  /**************************************************************************
     30   *
     31   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     32   * parameter of the FT_TRACE() and FT_ERROR() macros, usued to print/log
     33   * messages during execution.
     34   */
     35 #undef  FT_COMPONENT
     36 #define FT_COMPONENT  otsvg
     37 
     38 
     39 #ifdef FT_CONFIG_OPTION_SVG
     40 
     41  /* ft_svg_init */
     42  static FT_Error
     43  ft_svg_init( FT_Module  module )
     44  {
     45    SVG_Renderer  render = (SVG_Renderer)module;
     46 
     47    FT_Error  error = FT_Err_Ok;
     48 
     49 
     50    render->loaded    = FALSE;
     51    render->hooks_set = FALSE;
     52 
     53    return error;
     54  }
     55 
     56 
     57  static void
     58  ft_svg_done( FT_Module  module )
     59  {
     60    SVG_Renderer  render = (SVG_Renderer)module;
     61 
     62 
     63    if ( render->loaded    == TRUE &&
     64         render->hooks_set == TRUE )
     65      render->hooks.free_svg( &render->state );
     66 
     67    render->loaded = FALSE;
     68  }
     69 
     70 
     71  static FT_Error
     72  ft_svg_preset_slot( FT_Module     module,
     73                      FT_GlyphSlot  slot,
     74                      FT_Bool       cache )
     75  {
     76    SVG_Renderer       svg_renderer = (SVG_Renderer)module;
     77    SVG_RendererHooks  hooks        = svg_renderer->hooks;
     78 
     79 
     80    if ( svg_renderer->hooks_set == FALSE )
     81    {
     82      FT_TRACE1(( "Hooks are NOT set.  Can't render OT-SVG glyphs\n" ));
     83      return FT_THROW( Missing_SVG_Hooks );
     84    }
     85 
     86    if ( svg_renderer->loaded == FALSE )
     87    {
     88      FT_TRACE3(( "ft_svg_preset_slot: first presetting call,"
     89                  " calling init hook\n" ));
     90      hooks.init_svg( &svg_renderer->state );
     91 
     92      svg_renderer->loaded = TRUE;
     93    }
     94 
     95    return hooks.preset_slot( slot, cache, &svg_renderer->state );
     96  }
     97 
     98 
     99  static FT_Error
    100  ft_svg_render( FT_Renderer       renderer,
    101                 FT_GlyphSlot      slot,
    102                 FT_Render_Mode    mode,
    103                 const FT_Vector*  origin )
    104  {
    105    SVG_Renderer  svg_renderer = (SVG_Renderer)renderer;
    106 
    107    FT_Library  library = renderer->root.library;
    108    FT_Memory   memory  = library->memory;
    109    FT_Error    error;
    110 
    111    FT_ULong  size_image_buffer;
    112 
    113    SVG_RendererHooks  hooks = svg_renderer->hooks;
    114 
    115 
    116    FT_UNUSED( mode );
    117    FT_UNUSED( origin );
    118 
    119    if ( mode != FT_RENDER_MODE_NORMAL )
    120      return FT_THROW( Bad_Argument );
    121 
    122    if ( svg_renderer->hooks_set == FALSE )
    123    {
    124      FT_TRACE1(( "Hooks are NOT set.  Can't render OT-SVG glyphs\n" ));
    125      return FT_THROW( Missing_SVG_Hooks );
    126    }
    127 
    128    if ( svg_renderer->loaded == FALSE )
    129    {
    130      FT_TRACE3(( "ft_svg_render: first rendering, calling init hook\n" ));
    131      error = hooks.init_svg( &svg_renderer->state );
    132 
    133      svg_renderer->loaded = TRUE;
    134    }
    135 
    136    ft_svg_preset_slot( (FT_Module)renderer, slot, TRUE );
    137 
    138    size_image_buffer = (FT_ULong)slot->bitmap.pitch * slot->bitmap.rows;
    139    /* No `FT_QALLOC` here since we need a clean, empty canvas */
    140    /* to start with.                                          */
    141    if ( FT_ALLOC( slot->bitmap.buffer, size_image_buffer ) )
    142      return error;
    143 
    144    error = hooks.render_svg( slot, &svg_renderer->state );
    145    if ( error )
    146      FT_FREE( slot->bitmap.buffer );
    147    else
    148      slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
    149 
    150    return error;
    151  }
    152 
    153 
    154  static const SVG_Interface  svg_interface =
    155  {
    156    ft_svg_preset_slot  /* Preset_Bitmap_Func preset_slot */
    157  };
    158 
    159 
    160  static FT_Error
    161  ft_svg_property_set( FT_Module    module,
    162                       const char*  property_name,
    163                       const void*  value,
    164                       FT_Bool      value_is_string )
    165  {
    166    FT_Error      error    = FT_Err_Ok;
    167    SVG_Renderer  renderer = (SVG_Renderer)module;
    168 
    169 
    170    if ( !ft_strcmp( property_name, "svg-hooks" ) )
    171    {
    172      SVG_RendererHooks*  hooks;
    173 
    174 
    175      if ( value_is_string == TRUE )
    176      {
    177        error = FT_THROW( Invalid_Argument );
    178        goto Exit;
    179      }
    180 
    181      hooks = (SVG_RendererHooks*)value;
    182 
    183      if ( !hooks->init_svg    ||
    184           !hooks->free_svg    ||
    185           !hooks->render_svg  ||
    186           !hooks->preset_slot )
    187      {
    188        FT_TRACE0(( "ft_svg_property_set:"
    189                    " SVG rendering hooks not set because\n" ));
    190        FT_TRACE0(( "                    "
    191                    " at least one function pointer is NULL\n" ));
    192 
    193        error = FT_THROW( Invalid_Argument );
    194        goto Exit;
    195      }
    196 
    197      renderer->hooks     = *hooks;
    198      renderer->hooks_set = TRUE;
    199    }
    200    else
    201      error = FT_THROW( Missing_Property );
    202 
    203  Exit:
    204    return error;
    205  }
    206 
    207 
    208  static FT_Error
    209  ft_svg_property_get( FT_Module    module,
    210                       const char*  property_name,
    211                       void*        value )
    212  {
    213    FT_Error      error    = FT_Err_Ok;
    214    SVG_Renderer  renderer = (SVG_Renderer)module;
    215 
    216 
    217    if ( !ft_strcmp( property_name, "svg-hooks" ) )
    218    {
    219      SVG_RendererHooks*  hooks = (SVG_RendererHooks*)value;
    220 
    221 
    222      *hooks = renderer->hooks;
    223    }
    224    else
    225      error = FT_THROW( Missing_Property );
    226 
    227    return error;
    228  }
    229 
    230 
    231  FT_DEFINE_SERVICE_PROPERTIESREC(
    232    ft_svg_service_properties,
    233 
    234    ft_svg_property_set,  /* FT_Properties_SetFunc set_property */
    235    ft_svg_property_get   /* FT_Properties_GetFunc get_property */
    236  )
    237 
    238 
    239  FT_DEFINE_SERVICEDESCREC1(
    240    ft_svg_services,
    241    FT_SERVICE_ID_PROPERTIES, &ft_svg_service_properties )
    242 
    243 
    244  FT_CALLBACK_DEF( FT_Module_Interface )
    245  ft_svg_get_interface( FT_Module    module,
    246                        const char*  ft_svg_interface )
    247  {
    248    FT_Module_Interface  result;
    249 
    250 
    251    FT_UNUSED( module );
    252 
    253    result = ft_service_list_lookup( ft_svg_services, ft_svg_interface );
    254    if ( result )
    255      return result;
    256 
    257    return 0;
    258  }
    259 
    260 
    261  static FT_Error
    262  ft_svg_transform( FT_Renderer       renderer,
    263                    FT_GlyphSlot      slot,
    264                    const FT_Matrix*  _matrix,
    265                    const FT_Vector*  _delta )
    266  {
    267    FT_SVG_Document  doc    = (FT_SVG_Document)slot->other;
    268    FT_Matrix*       matrix = (FT_Matrix*)_matrix;
    269    FT_Vector*       delta  = (FT_Vector*)_delta;
    270 
    271    FT_Matrix  tmp_matrix;
    272    FT_Vector  tmp_delta;
    273 
    274    FT_Matrix  a, b;
    275    FT_Pos     x, y;
    276 
    277 
    278    FT_UNUSED( renderer );
    279 
    280    if ( !matrix )
    281    {
    282      tmp_matrix.xx = 0x10000;
    283      tmp_matrix.xy = 0;
    284      tmp_matrix.yx = 0;
    285      tmp_matrix.yy = 0x10000;
    286 
    287      matrix = &tmp_matrix;
    288    }
    289 
    290    if ( !delta )
    291    {
    292      tmp_delta.x = 0;
    293      tmp_delta.y = 0;
    294 
    295      delta = &tmp_delta;
    296    }
    297 
    298    a = doc->transform;
    299    b = *matrix;
    300    FT_Matrix_Multiply( &b, &a );
    301 
    302 
    303    x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, doc->delta.x ),
    304                            FT_MulFix( matrix->xy, doc->delta.y ) ),
    305                  delta->x );
    306    y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, doc->delta.x ),
    307                            FT_MulFix( matrix->yy, doc->delta.y ) ),
    308                  delta->y );
    309 
    310    doc->delta.x   = x;
    311    doc->delta.y   = y;
    312    doc->transform = a;
    313 
    314    return FT_Err_Ok;
    315  }
    316 
    317 #endif /* FT_CONFIG_OPTION_SVG */
    318 
    319 
    320 #ifdef FT_CONFIG_OPTION_SVG
    321 #define PUT_SVG_MODULE( a )  a
    322 #define SVG_GLYPH_FORMAT     FT_GLYPH_FORMAT_SVG
    323 #else
    324 #define PUT_SVG_MODULE( a )  NULL
    325 #define SVG_GLYPH_FORMAT     FT_GLYPH_FORMAT_NONE
    326 #endif
    327 
    328 
    329  FT_DEFINE_RENDERER(
    330    ft_svg_renderer_class,
    331 
    332      FT_MODULE_RENDERER,
    333      sizeof ( SVG_RendererRec ),
    334 
    335      "ot-svg",
    336      0x10000L,
    337      0x20000L,
    338 
    339      (const void*)PUT_SVG_MODULE( &svg_interface ), /* module specific interface */
    340 
    341      PUT_SVG_MODULE( ft_svg_init ),           /* FT_Module_Constructor module_init   */
    342      PUT_SVG_MODULE( ft_svg_done ),           /* FT_Module_Destructor  module_done   */
    343      PUT_SVG_MODULE( ft_svg_get_interface ),  /* FT_Module_Requester   get_interface */
    344 
    345      SVG_GLYPH_FORMAT,
    346 
    347      PUT_SVG_MODULE( ft_svg_render ),     /* FT_Renderer_RenderFunc    render_glyph    */
    348      PUT_SVG_MODULE( ft_svg_transform ),  /* FT_Renderer_TransformFunc transform_glyph */
    349      NULL,                                /* FT_Renderer_GetCBoxFunc   get_glyph_cbox  */
    350      NULL,                                /* FT_Renderer_SetModeFunc   set_mode        */
    351      NULL                                 /* FT_Raster_Funcs*          raster_class    */
    352  )
    353 
    354 
    355 /* END */