shithub: freetype+ttf2subf

Download patch

ref: 0bf49bd229427b56ab61e8e2c08f3fe448286890
parent: 97c09a803eb6cd44456e0251529db2ae96a019f8
author: Moazin Khatti <moazinkhatri@gmail.com>
date: Sat Dec 25 15:14:11 EST 2021

Add 'svg' module for OT-SVG rendering.

* CMakeLists.txt (BASE_SRCS): Add svg module file.
* meson.build (ft2_public_headers): Add `otsvg.h`.

* modules.cfg (RASTER_MODULES): Add `svg` module.

* builds/meson/parse_modules_cfg.py: Add svg module.

* include/freetype/config/ftmodule.h: Add `ft_svg_renderer_class`.
* include/freetype/fterrdef.h: Add `Invalid_SVG_Document` and
`Missing_SVG_Hooks` error codes.
* include/freetype/internal/fttrace.h: Add tracing for `otsvg`.
* include/freetype/internal/svginterface.h: New file.  It adds an interface
to enable the presetting hook from the `base` module.
* include/freetype/otsvg.h (SVG_Lib_Init_Func, SVG_Lib_Free_Func,
SVG_Lib_Render_Func, SVG_Lib_Preset_Slot_Func): New hooks for SVG rendering.
(SVG_RendererHooks): New structure to access them.

* src/base/ftobjs.c: Include `svginterface.h`.
(ft_glyphslot_preset_bitmap): Add code for presetting the slot for SVG
glyphs.
(ft_add_renderer): Updated.

* src/svg/*: New files.

git/fs: mount .git/fs: mount/attach disallowed
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -400,6 +400,7 @@
   src/sdf/sdf.c
   src/sfnt/sfnt.c
   src/smooth/smooth.c
+  src/svg/svg.c
   src/truetype/truetype.c
   src/type1/type1.c
   src/type42/type42.c
--- a/builds/meson/parse_modules_cfg.py
+++ b/builds/meson/parse_modules_cfg.py
@@ -87,6 +87,7 @@
         name = {
             "raster": "ft_raster1",
             "smooth": "ft_smooth",
+            "svg": "ft_svg",
         }.get(module)
         result += (
             "FT_USE_MODULE( FT_Renderer_Class, %s_renderer_class )\n" % name
--- a/include/freetype/config/ftmodule.h
+++ b/include/freetype/config/ftmodule.h
@@ -28,5 +28,6 @@
 FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class )
 FT_USE_MODULE( FT_Renderer_Class, ft_sdf_renderer_class )
 FT_USE_MODULE( FT_Renderer_Class, ft_bitmap_sdf_renderer_class )
+FT_USE_MODULE( FT_Renderer_Class, ft_svg_renderer_class )
 
 /* EOF */
--- a/include/freetype/fterrdef.h
+++ b/include/freetype/fterrdef.h
@@ -101,6 +101,8 @@
                 "too many hints" )
   FT_ERRORDEF_( Invalid_Pixel_Size,                          0x17,
                 "invalid pixel size" )
+  FT_ERRORDEF_( Invalid_SVG_Document,                        0x18,
+                "invalid SVG document" )
 
   /* handle errors */
 
@@ -234,6 +236,8 @@
                 "found FDEF or IDEF opcode in glyf bytecode" )
   FT_ERRORDEF_( Missing_Bitmap,                              0x9D,
                 "missing bitmap in strike" )
+  FT_ERRORDEF_( Missing_SVG_Hooks,                           0x9E,
+                "SVG hooks have not been set" )
 
   /* CFF, CID, and Type 1 errors */
 
--- a/include/freetype/internal/fttrace.h
+++ b/include/freetype/internal/fttrace.h
@@ -49,6 +49,9 @@
 FT_TRACE_DEF( raster )    /* monochrome rasterizer   (ftraster.c) */
 FT_TRACE_DEF( smooth )    /* anti-aliasing raster    (ftgrays.c)  */
 
+  /* ot-svg module */
+FT_TRACE_DEF( otsvg )     /* OT-SVG renderer         (ftsvg.c)    */
+
   /* cache sub-system */
 FT_TRACE_DEF( cache )     /* cache sub-system   (ftcache.c, etc.) */
 
--- /dev/null
+++ b/include/freetype/internal/svginterface.h
@@ -1,0 +1,46 @@
+/****************************************************************************
+ *
+ * svginterface.h
+ *
+ *   Interface of ot-svg module (specification only).
+ *
+ * Copyright (C) 2022 by
+ * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#ifndef SVGINTERFACE_H_
+#define SVGINTERFACE_H_
+
+#include <ft2build.h>
+#include <freetype/otsvg.h>
+
+
+FT_BEGIN_HEADER
+
+  typedef FT_Error
+  (*Preset_Bitmap_Func)( FT_Module     module,
+                         FT_GlyphSlot  slot,
+                         FT_Bool       cache );
+
+  typedef struct  SVG_Interface_
+  {
+    Preset_Bitmap_Func  preset_slot;
+
+  } SVG_Interface;
+
+  typedef SVG_Interface*  SVG_Service;
+
+FT_END_HEADER
+
+#endif /* SVGINTERFACE_H_ */
+
+
+/* END */
--- a/include/freetype/otsvg.h
+++ b/include/freetype/otsvg.h
@@ -30,6 +30,217 @@
 
 FT_BEGIN_HEADER
 
+
+  /**************************************************************************
+   *
+   * @functype:
+   *   SVG_Lib_Init_Func
+   *
+   * @description:
+   *   A callback that is called when the first OT-SVG glyph is rendered in
+   *   the lifetime of an @FT_Library object.  In a typical implementation,
+   *   one would want to allocate a structure and point the `data_pointer`
+   *   to it and perform any library initializations that might be needed.
+   *
+   *   For more information on the implementation, see our standard hooks
+   *   based on Librsvg in the 'FreeType Demo Programs' repository.
+   *
+   * @inout:
+   *   data_pointer ::
+   *     The SVG rendering module stores a pointer variable that can be used
+   *     by clients to store any data that needs to be shared across
+   *     different hooks.  `data_pointer` is essentially a pointer to that
+   *     pointer such that it can be written to as well as read from.
+   *
+   * @return:
+   *   FreeType error code.  0 means success.
+   *
+   * @since:
+   *   2.12
+   */
+  typedef FT_Error
+  (*SVG_Lib_Init_Func)( FT_Pointer  *data_pointer );
+
+
+  /**************************************************************************
+   *
+   * @functype:
+   *   SVG_Lib_Free_Func
+   *
+   * @description:
+   *   A callback that is called when the `ot-svg` module is being freed.
+   *   It is only called if the init hook was called earlier.  This means
+   *   that neither the init nor the free hook is called if no OT-SVG glyph
+   *   is rendered.
+   *
+   *   In a typical implementation, one would want to free any state
+   *   structure that was allocated in the init hook and perform any
+   *   library-related closure that might be needed.
+   *
+   *   For more information on the implementation, see our standard hooks
+   *   based on Librsvg in the 'FreeType Demo Programs' repository.
+   *
+   * @inout:
+   *   data_pointer ::
+   *     The SVG rendering module stores a pointer variable that can be used
+   *     by clients to store any data that needs to be shared across
+   *     different hooks.  `data_pointer` is essentially a pointer to that
+   *     pointer such that it can be written to as well as read from.
+   *
+   * @since:
+   *   2.12
+   */
+  typedef void
+  (*SVG_Lib_Free_Func)( FT_Pointer  *data_pointer );
+
+
+  /**************************************************************************
+   *
+   * @functype:
+   *   SVG_Lib_Render_Func
+   *
+   * @description:
+   *   A callback that is called to render an OT-SVG glyph.  This callback
+   *   hook is called right after the preset hook @SVG_Lib_Preset_SlotFunc
+   *   has been called with `cache` set to `TRUE`.  The data necessary to
+   *   render is available through the handle @FT_SVG_Document, which is set
+   *   in the `other` field of @FT_GlyphSlotRec.
+   *
+   *   The render hook is expected to render the SVG glyph to the bitmap
+   *   buffer that is allocated already at `slot->bitmap.buffer`.  It also
+   *   sets the `num_grays` value as well as `slot->format`.
+   *
+   *   For more information on the implementation, see our standard hooks
+   *   based on Librsvg in the 'FreeType Demo Programs' repository.
+   *
+   * @input:
+   *   slot ::
+   *     The slot to render.
+   *
+   * @inout:
+   *   data_pointer ::
+   *     The SVG rendering module stores a pointer variable that can be used
+   *     by clients to store any data that needs to be shared across
+   *     different hooks.  `data_pointer` is essentially a pointer to that
+   *     pointer such that it can be written to as well as read from.
+   *
+   * @return:
+   *   FreeType error code.  0 means success.
+   *
+   * @since:
+   *   2.12
+   */
+  typedef FT_Error
+  (*SVG_Lib_Render_Func)( FT_GlyphSlot  slot,
+                          FT_Pointer   *data_pointer );
+
+
+  /**************************************************************************
+   *
+   * @functype:
+   *   SVG_Lib_Preset_Slot_Func
+   *
+   * @description:
+   *   A callback that is called to preset the glyph slot.  It is called from
+   *   two places.
+   *
+   *   1. When `FT_Load_Glyph` needs to preset the glyph slot.
+   *   2. Right before the `svg` module calls the render callback hook.
+   *
+   *   When it is the former, the argument `cache` is set to `FALSE`.  When
+   *   it is the latter, the argument `cache` is set to `TRUE`.  This
+   *   distinction has been made because many calculations that are necessary
+   *   for presetting a glyph slot are the same needed later for the render
+   *   callback hook.  Thus, if `cache` is `TRUE`, the hook can _cache_ those
+   *   calculations in a memory block referenced by the state pointer.
+   *
+   *   This hook is expected to preset the slot by setting parameters such as
+   *   `bitmap_left`, `bitmap_top`, `width`, `rows`, `pitch`, and
+   *   `pixel_mode`.  It is also expected to set all the metrics for the slot
+   *   including the vertical advance if it is not already set.  Typically,
+   *   fonts have horizontal advances but not vertical ones.  If those are
+   *   available, they had already been set, otherwise they have to be
+   *   estimated and set manually.  The hook must take into account the
+   *   transformations that have been set, and translate the transformation
+   *   matrices into the SVG coordinate system, as the original matrix is
+   *   intended for the TTF/CFF coordinate system.
+   *
+   *   For more information on the implementation, see our standard hooks
+   *   based on Librsvg in the 'FreeType Demo Programs' repository.
+   *
+   * @input:
+   *   slot ::
+   *     The glyph slot that has the SVG document loaded.
+   *
+   *   cache ::
+   *     See description.
+   *
+   * @inout:
+   *   data_pointer ::
+   *     The SVG rendering module stores a pointer variable that can be used
+   *     by clients to store any data that needs to be shared across
+   *     different hooks.  `data_pointer` is essentially a pointer to that
+   *     pointer such that it can be written to as well as read from.
+   *
+   * @return:
+   *   FreeType error code.  0 means success.
+   *
+   * @since:
+   *   2.12
+   */
+  typedef FT_Error
+  (*SVG_Lib_Preset_Slot_Func)( FT_GlyphSlot  slot,
+                               FT_Bool       cache,
+                               FT_Pointer   *state );
+
+
+  /**************************************************************************
+   *
+   * @struct:
+   *   SVG_RendererHooks
+   *
+   * @description:
+   *   A structure that stores the four hooks needed to render OT-SVG glyphs
+   *   properly.  The structure is publicly used to set the hooks via driver
+   *   properties.
+   *
+   *   The behavior of each hook is described in its documentation.  One
+   *   thing to note is that the preset hook and the render hook often need
+   *   to do the same operations; therefore, it's better to cache the
+   *   intermediate data in a state structure to avoid calculating it twice.
+   *   For example, in the preset hook one can draw the glyph on a recorder
+   *   surface and later create a bitmap surface from it in the render hook.
+   *
+   *   For more information on the implementation, see our standard hooks
+   *   based on Librsvg in the 'FreeType Demo Programs' repository.
+   *
+   * @fields:
+   *   init_svg ::
+   *     The initialization hook.
+   *
+   *   free_svg ::
+   *     The cleanup hook.
+   *
+   *   render_hook ::
+   *     The render hook.
+   *
+   *   preset_slot ::
+   *     The preset hook.
+   *
+   * @since:
+   *   2.12
+   */
+  typedef struct SVG_RendererHooks_
+  {
+    SVG_Lib_Init_Func    init_svg;
+    SVG_Lib_Free_Func    free_svg;
+    SVG_Lib_Render_Func  render_svg;
+
+    SVG_Lib_Preset_Slot_Func  preset_slot;
+
+  } SVG_RendererHooks;
+
+
   /**************************************************************************
    *
    * @struct:
--- a/meson.build
+++ b/meson.build
@@ -172,6 +172,7 @@
   'include/freetype/fttrigon.h',
   'include/freetype/fttypes.h',
   'include/freetype/ftwinfnt.h',
+  'include/freetype/otsvg.h',
   'include/freetype/t1tables.h',
   'include/freetype/ttnameid.h',
   'include/freetype/tttables.h',
--- a/modules.cfg
+++ b/modules.cfg
@@ -99,6 +99,9 @@
 # Monochrome rasterizer.
 RASTER_MODULES += raster
 
+# OT-SVG.
+RASTER_MODULES += svg
+
 # Signed distance field rasterizer.
 RASTER_MODULES += sdf
 
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -28,6 +28,7 @@
 #include <freetype/internal/ftstream.h>
 #include <freetype/internal/sfnt.h>          /* for SFNT_Load_Table_Func */
 #include <freetype/internal/psaux.h>         /* for PS_Driver            */
+#include <freetype/internal/svginterface.h>
 
 #include <freetype/tttables.h>
 #include <freetype/tttags.h>
@@ -386,7 +387,18 @@
     FT_Pos   width, height, pitch;
 
 
-    if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
+    if ( slot->format == FT_GLYPH_FORMAT_SVG )
+    {
+      FT_Module    module;
+      SVG_Service  svg_service;
+
+
+      module      = FT_Get_Module( slot->library, "ot-svg" );
+      svg_service = (SVG_Service)module->clazz->module_interface;
+
+      return (FT_Bool)svg_service->preset_slot( module, slot, FALSE );
+    }
+    else if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
       return 1;
 
     if ( origin )
@@ -4539,7 +4551,7 @@
       render->glyph_format = clazz->glyph_format;
 
       /* allocate raster object if needed */
-      if ( clazz->raster_class->raster_new )
+      if ( clazz->raster_class && clazz->raster_class->raster_new )
       {
         error = clazz->raster_class->raster_new( memory, &render->raster );
         if ( error )
@@ -4548,6 +4560,11 @@
         render->raster_render = clazz->raster_class->raster_render;
         render->render        = clazz->render_glyph;
       }
+
+#ifdef FT_CONFIG_OPTION_SVG
+      if ( clazz->glyph_format == FT_GLYPH_FORMAT_SVG )
+        render->render = clazz->render_glyph;
+#endif
 
       /* add to list */
       node->data = module;
--- a/src/sfnt/ttsvg.c
+++ b/src/sfnt/ttsvg.c
@@ -299,7 +299,7 @@
     if ( ( doc_list[0] == 0x1F ) && ( doc_list[1] == 0x8B )
                                  && ( doc_list[2] == 0x08 ) )
     {
-#ifdef FT_CONFIG_OPTION_SYSTEM_ZLIB
+#ifdef FT_CONFIG_OPTION_USE_ZLIB
 
       FT_ULong  uncomp_size;
       FT_Byte*  uncomp_buffer;
@@ -339,12 +339,12 @@
       doc_list   = uncomp_buffer;
       doc_length = uncomp_size;
 
-#else /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */
+#else /* !FT_CONFIG_OPTION_USE_ZLIB */
 
       error = FT_THROW( Unimplemented_Feature );
       goto Exit;
 
-#endif /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */
+#endif /* !FT_CONFIG_OPTION_USE_ZLIB */
     }
 
     svg_document->svg_document        = doc_list;
--- /dev/null
+++ b/src/svg/ftsvg.c
@@ -1,0 +1,332 @@
+/****************************************************************************
+ *
+ * ftsvg.c
+ *
+ *   The FreeType SVG renderer interface (body).
+ *
+ * Copyright (C) 2022 by
+ * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftserv.h>
+#include <freetype/internal/services/svprop.h>
+#include <freetype/otsvg.h>
+#include <freetype/internal/svginterface.h>
+#include <freetype/ftbbox.h>
+
+#include "ftsvg.h"
+#include "svgtypes.h"
+
+
+  /**************************************************************************
+   *
+   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
+   * parameter of the FT_TRACE() and FT_ERROR() macros, usued to print/log
+   * messages during execution.
+   */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  otsvg
+
+
+#ifdef FT_CONFIG_OPTION_SVG
+
+  /* ft_svg_init */
+  static FT_Error
+  ft_svg_init( SVG_Renderer  svg_module )
+  {
+    FT_Error  error = FT_Err_Ok;
+
+
+    svg_module->loaded    = FALSE;
+    svg_module->hooks_set = FALSE;
+
+    return error;
+  }
+
+
+  static void
+  ft_svg_done( SVG_Renderer  svg_module )
+  {
+    if ( svg_module->loaded    == TRUE &&
+         svg_module->hooks_set == TRUE )
+      svg_module->hooks.free_svg( &svg_module->state );
+
+    svg_module->loaded = FALSE;
+  }
+
+
+  static FT_Error
+  ft_svg_preset_slot( FT_Module     module,
+                      FT_GlyphSlot  slot,
+                      FT_Bool       cache )
+  {
+    SVG_Renderer       svg_renderer = (SVG_Renderer)module;
+    SVG_RendererHooks  hooks        = svg_renderer->hooks;
+
+
+    if ( svg_renderer->hooks_set == FALSE )
+    {
+      FT_TRACE1(( "Hooks are NOT set.  Can't render OT-SVG glyphs\n" ));
+      return FT_THROW( Missing_SVG_Hooks );
+    }
+
+    if ( svg_renderer->loaded == FALSE )
+    {
+      FT_TRACE3(( "ft_svg_preset_slot: first presetting call,"
+                  " calling init hook\n" ));
+      hooks.init_svg( &svg_renderer->state );
+
+      svg_renderer->loaded = TRUE;
+    }
+
+    return hooks.preset_slot( slot, cache, &svg_renderer->state );
+  }
+
+
+  static FT_Error
+  ft_svg_render( FT_Renderer       renderer,
+                 FT_GlyphSlot      slot,
+                 FT_Render_Mode    mode,
+                 const FT_Vector*  origin )
+  {
+    SVG_Renderer  svg_renderer = (SVG_Renderer)renderer;
+
+    FT_Library  library = renderer->root.library;
+    FT_Memory   memory  = library->memory;
+    FT_Error    error;
+
+    FT_ULong  size_image_buffer;
+
+    SVG_RendererHooks  hooks = svg_renderer->hooks;
+
+
+    FT_UNUSED( mode );
+    FT_UNUSED( origin );
+
+    if ( mode != FT_RENDER_MODE_NORMAL )
+      return FT_THROW( Bad_Argument );
+
+    if ( svg_renderer->hooks_set == FALSE )
+    {
+      FT_TRACE1(( "Hooks are NOT set.  Can't render OT-SVG glyphs\n" ));
+      return FT_THROW( Missing_SVG_Hooks );
+    }
+
+    if ( svg_renderer->loaded == FALSE )
+    {
+      FT_TRACE3(( "ft_svg_render: first rendering, calling init hook\n" ));
+      error = hooks.init_svg( &svg_renderer->state );
+
+      svg_renderer->loaded = TRUE;
+    }
+
+    ft_svg_preset_slot( (FT_Module)renderer, slot, TRUE );
+
+    size_image_buffer = (FT_ULong)slot->bitmap.pitch * slot->bitmap.rows;
+    /* No `FT_QALLOC` here since we need a clean, empty canvas */
+    /* to start with.                                          */
+    if ( FT_ALLOC( slot->bitmap.buffer, size_image_buffer ) )
+      return error;
+
+    error = hooks.render_svg( slot, &svg_renderer->state );
+    if ( error )
+      FT_FREE( slot->bitmap.buffer );
+    else
+      slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
+
+    return error;
+  }
+
+
+  static const SVG_Interface  svg_interface =
+  {
+    (Preset_Bitmap_Func)ft_svg_preset_slot
+  };
+
+
+  static FT_Error
+  ft_svg_property_set( FT_Module    module,
+                       const char*  property_name,
+                       const void*  value,
+                       FT_Bool      value_is_string )
+  {
+    FT_Error      error    = FT_Err_Ok;
+    SVG_Renderer  renderer = (SVG_Renderer)module;
+
+
+    if ( !ft_strcmp( property_name, "svg_hooks" ) )
+    {
+      SVG_RendererHooks*  hooks;
+
+
+      if ( value_is_string == TRUE )
+        return FT_THROW( Invalid_Argument );
+
+      hooks = (SVG_RendererHooks*)value;
+
+      renderer->hooks     = *hooks;
+      renderer->hooks_set = TRUE;
+    }
+    else
+      error = FT_THROW( Missing_Property );
+
+    return error;
+  }
+
+
+  static FT_Error
+  ft_svg_property_get( FT_Module    module,
+                       const char*  property_name,
+                       const void*  value )
+  {
+    FT_Error      error    = FT_Err_Ok;
+    SVG_Renderer  renderer = (SVG_Renderer)module;
+
+
+    if ( !ft_strcmp( property_name, "svg_hooks" ) )
+    {
+      SVG_RendererHooks*  hooks = (SVG_RendererHooks*)value;
+
+
+      *hooks = renderer->hooks;
+    }
+    else
+      error = FT_THROW( Missing_Property );
+
+    return error;
+  }
+
+
+  FT_DEFINE_SERVICE_PROPERTIESREC(
+    ft_svg_service_properties,
+
+    (FT_Properties_SetFunc)ft_svg_property_set, /* set_property */
+    (FT_Properties_GetFunc)ft_svg_property_get  /* get_property */
+  )
+
+
+  FT_DEFINE_SERVICEDESCREC1(
+    ft_svg_services,
+    FT_SERVICE_ID_PROPERTIES, &ft_svg_service_properties )
+
+
+  FT_CALLBACK_DEF( FT_Module_Interface )
+  ft_svg_get_interface( FT_Module    module,
+                        const char*  ft_svg_interface )
+  {
+    FT_Module_Interface  result;
+
+
+    FT_UNUSED( module );
+
+    result = ft_service_list_lookup( ft_svg_services, ft_svg_interface );
+    if ( result )
+      return result;
+
+    return 0;
+  }
+
+
+  static FT_Error
+  ft_svg_transform( FT_Renderer       renderer,
+                    FT_GlyphSlot      slot,
+                    const FT_Matrix*  _matrix,
+                    const FT_Vector*  _delta )
+  {
+    FT_SVG_Document  doc    = (FT_SVG_Document)slot->other;
+    FT_Matrix*       matrix = (FT_Matrix*)_matrix;
+    FT_Vector*       delta  = (FT_Vector*)_delta;
+
+    FT_Matrix  tmp_matrix;
+    FT_Vector  tmp_delta;
+
+    FT_Matrix  a, b;
+    FT_Pos     x, y;
+
+
+    FT_UNUSED( renderer );
+
+    if ( !matrix )
+    {
+      tmp_matrix.xx = 0x10000;
+      tmp_matrix.xy = 0;
+      tmp_matrix.yx = 0;
+      tmp_matrix.yy = 0x10000;
+
+      matrix = &tmp_matrix;
+    }
+
+    if ( !delta )
+    {
+      tmp_delta.x = 0;
+      tmp_delta.y = 0;
+
+      delta = &tmp_delta;
+    }
+
+    a = doc->transform;
+    b = *matrix;
+    FT_Matrix_Multiply( &b, &a );
+
+
+    x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, doc->delta.x ),
+                            FT_MulFix( matrix->xy, doc->delta.y ) ),
+                  delta->x );
+    y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, doc->delta.x ),
+                            FT_MulFix( matrix->yy, doc->delta.y ) ),
+                  delta->y );
+
+    doc->delta.x   = x;
+    doc->delta.y   = y;
+    doc->transform = a;
+
+    return FT_Err_Ok;
+  }
+
+#endif /* FT_CONFIG_OPTION_SVG */
+
+
+#ifdef FT_CONFIG_OPTION_SVG
+#define PUT_SVG_MODULE( a )  a
+#define SVG_GLYPH_FORMAT     FT_GLYPH_FORMAT_SVG
+#else
+#define PUT_SVG_MODULE( a )  NULL
+#define SVG_GLYPH_FORMAT     FT_GLYPH_FORMAT_NONE
+#endif
+
+
+  FT_DEFINE_RENDERER(
+    ft_svg_renderer_class,
+
+      FT_MODULE_RENDERER,
+      sizeof ( SVG_RendererRec ),
+
+      "ot-svg",
+      0x10000L,
+      0x20000L,
+
+      (const void*)PUT_SVG_MODULE( &svg_interface ), /* module specific interface */
+
+      (FT_Module_Constructor)PUT_SVG_MODULE( ft_svg_init ), /* module_init   */
+      (FT_Module_Destructor)PUT_SVG_MODULE( ft_svg_done ),  /* module_done   */
+      PUT_SVG_MODULE( ft_svg_get_interface ),               /* get_interface */
+
+      SVG_GLYPH_FORMAT,
+
+      (FT_Renderer_RenderFunc)   PUT_SVG_MODULE( ft_svg_render ),    /* render_glyph    */
+      (FT_Renderer_TransformFunc)PUT_SVG_MODULE( ft_svg_transform ), /* transform_glyph */
+      NULL,                                                          /* get_glyph_cbox  */
+      NULL,                                                          /* set_mode        */
+      NULL                                                           /* raster_class    */
+  )
+
+
+/* END */
--- /dev/null
+++ b/src/svg/ftsvg.h
@@ -1,0 +1,35 @@
+/****************************************************************************
+ *
+ * ftsvg.h
+ *
+ *   The FreeType SVG renderer interface (specification).
+ *
+ * Copyright (C) 2022 by
+ * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+#ifndef FTSVG_H_
+#define FTSVG_H_
+
+#include <ft2build.h>
+#include <freetype/ftrender.h>
+#include <freetype/internal/ftobjs.h>
+
+
+FT_BEGIN_HEADER
+
+  FT_DECLARE_RENDERER( ft_svg_renderer_class )
+
+FT_END_HEADER
+
+#endif /* FTSVG_H_ */
+
+
+/* END */
--- /dev/null
+++ b/src/svg/module.mk
@@ -1,0 +1,23 @@
+#
+# FreeType 2 SVG renderer module definition
+#
+
+
+# Copyright (C) 2022 by
+# David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+
+FTMODULE_H_COMMANDS += SVG_MODULE
+
+define SVG_MODULE
+$(OPEN_DRIVER) FT_Renderer_Class, ft_svg_renderer_class $(CLOSE_DRIVER)
+$(ECHO_DRIVER)ot-svg    $(ECHO_DRIVER_DESC)OT-SVG glyph renderer module$(ECHO_DRIVER_DONE)
+endef
+
+# EOF
--- /dev/null
+++ b/src/svg/rules.mk
@@ -1,0 +1,70 @@
+#
+# FreeType 2 SVG renderer module build rules
+#
+
+
+# Copyright (C) 2022 by
+# David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+
+# SVG renderer driver directory
+#
+SVG_DIR := $(SRC_DIR)/svg
+
+# compilation flags for the driver
+#
+SVG_COMPILE := $(CC) $(ANSIFLAGS)                            \
+                     $I$(subst /,$(COMPILER_SEP),$(SVG_DIR)) \
+                     $(INCLUDE_FLAGS)                        \
+                     $(FT_CFLAGS)
+
+# SVG renderer sources (i.e., C files)
+#
+SVG_DRV_SRC := $(SVG_DIR)/ftsvg.c
+
+
+# SVG renderer headers
+#
+SVG_DRV_H := $(SVG_DIR)/ftsvg.h    \
+             $(SVG_DIR)/svgtypes.h
+
+
+# SVG renderer object(s)
+#
+#   SVG_DRV_OBJ_M is used during `multi' builds.
+#   SVG_DRV_OBJ_S is used during `single' builds.
+#
+SVG_DRV_OBJ_M := $(SVG_DRV_SRC:$(SVG_DIR)/%.c=$(OBJ_DIR)/%.$O)
+SVG_DRV_OBJ_S := $(OBJ_DIR)/svg.$O
+
+# SVG renderer source file for single build
+#
+SVG_DRV_SRC_S := $(SVG_DIR)/svg.c
+
+
+# SVG renderer - single object
+#
+$(SVG_DRV_OBJ_S): $(SVG_DRV_SRC_S) $(SVG_DRV_SRC) \
+                  $(FREETYPE_H) $(SVG_DRV_H)
+	$(SVG_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(SVG_DRV_SRC_S))
+
+
+# SVG renderer - multiple objects
+#
+$(OBJ_DIR)/%.$O: $(SVG_DIR)/%.c $(FREETYPE_H) $(SVG_DRV_H)
+	$(SVG_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(SVG_DRV_OBJ_S)
+DRV_OBJS_M += $(SVG_DRV_OBJ_M)
+
+
+# EOF
--- /dev/null
+++ b/src/svg/svg.c
@@ -1,0 +1,24 @@
+/****************************************************************************
+ *
+ * svg.c
+ *
+ *   FreeType SVG renderer module component (body only).
+ *
+ * Copyright (C) 2022 by
+ * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include "svgtypes.h"
+#include "ftsvg.c"
+
+
+/* END */
--- /dev/null
+++ b/src/svg/svgtypes.h
@@ -1,0 +1,42 @@
+/****************************************************************************
+ *
+ * svgtypes.h
+ *
+ *   The FreeType SVG renderer internal types (specification).
+ *
+ * Copyright (C) 2022 by
+ * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+#ifndef SVGTYPES_H_
+#define SVGTYPES_H_
+
+#include <ft2build.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/ftrender.h>
+#include <freetype/otsvg.h>
+
+
+  typedef struct SVG_RendererRec_
+  {
+    FT_RendererRec     root;   /* this inherits FT_RendererRec                */
+    FT_Bool            loaded;
+    FT_Bool            hooks_set;
+    SVG_RendererHooks  hooks;  /* this holds hooks for SVG rendering          */
+    FT_Pointer         state;  /* a place for hooks to store state, if needed */
+
+  } SVG_RendererRec;
+
+  typedef struct SVG_RendererRec_*  SVG_Renderer;
+
+#endif /* SVGTYPES_H_ */
+
+
+/* EOF */