(root)/
freetype-2.13.2/
src/
svg/
ftsvg.c
       1  /****************************************************************************
       2   *
       3   * ftsvg.c
       4   *
       5   *   The FreeType SVG renderer interface (body).
       6   *
       7   * Copyright (C) 2022-2023 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 */