Here it is, the actuall code diff for adding skia as a ot-svg renderer hook to 
freetype, as an alternative to rsvg/cairo. There is a new file "README.skia". I 
fixed the color change and the intermittent crash, so as far as I know the only 
thing is that it is occasionally 1-pixel off compared to rsvg/cairo.

This can be somewhat corrected by changing these two lines:

    x = bounds.left();      -> floor(bounds.left());
    y = bounds.top();      -> floor(boulds.left());

I am not convinced that skia is entirey wrong, actually; the equivalent rsvg 
location has some comments on doubts about rounding.

I thought of switching the hooks dynamically (between 3, rsvg_hook, skia_hook, 
and a new null_hook), but running init of one hook , switch in the middle and 
run the free of another hook is dangerous. So this is still done as a 
build-time change. Otherwise it would be great to switch dynamically to 
investigate the 1-pixel-difference problem.

For now, if somebody else wants to give this a try, especially a mac user or a 
windows user, and/or somebody want to build skia (I am lazy and just downloaded 
a not-too-old pre-built binaries), I like to hear about 1st-hand experience on 
that too.

The rest, please have a thought how to  switch the hook dynamically, without 
crashing....

will probably post this up at 
https://github.com/HinTak/harfbuzz-python-demos/ under a new directory 
"skia-adventure" and write there. Thanks for reading this far :-).









On Wednesday, 12 July 2023 at 07:28:15 BST, Hin-Tak Leung 
<ht...@users.sourceforge.net> wrote:


See attached screenshot. Left is skia-based ftview/ftgrid, right is my 
system-wide ftview/ftgrid 2.13.0 (based on rsvg/cairo). The default zoom level 
for ftgrid seems to have changed between 2.13.0 and 2.13.1  from 4 to 6?

There are 3 issues I see

- the first one is of course the color - seems to be a rgba vs bgra difference? 
i.e. the Alpha channel is the same, but red and blue swapped.
- 2nd one is not very noticeable on ftview but more on ftgrid - the glyph is 
shifted down by one pixel. Probably a rounding error somewhere.
- I have intermitent crashes from 'include/core/SkRefCnt.h:72: fatal error: 
"assert(this->getRefCnt() > 0)" ' . Prove I don't know Skia well enough yet. ( 
That's one week of learning Skia ...)

On the way also learns a few things - this is based on m110 . I see that even 
with main (close to m116), one of the headers I am using have changed location.

I tried updating skia-python 's bundled skia from m87 to m88 - just 1 
milestone, or roughly 4 weeks, to get a feel of how easy/hard it is. The main 
reason is that m88 is the first where the SVGDOM class is declared 
non-experimental. So I expect the SVG related headers to move. But the actual 
diff is close to about 1000 lines, took me a whole day. (by comparison, the 
fontval diff is a little over 4000 lines, and took 3 years). The amount of 
changes in skia per milestone is just alarming. That explains why nobody wants 
to ship skia shared libraries, and why skia-python is stuck at m87 for 2 years. 
Skia is just contantly changing from milestone to milstone.

That said, I think somebody should update skia-python's bundled skia from m87 
to m98 (COLRv1) and perhaps even m103 (OT-SVG). Google folks?

One milestone is about 1000 lines of code difference and a whole day,  I reckon 
it will take somebody working full time for 2 months to update skia-python to 
current-ish. (116 - 87 = 29 working days..., by the time one gets to m116, 
m117/m118 would be out...). If google folks are not moving a finger, and 
somebody else wants to fund me to tackle this, please feel free to get in touch.


I'll tidy the diff up and send it to freetype-devel at some point. At the 
moment it is just replacing all contents of rsvg-port.{c,h}. with

-#ifdef HAVE_LIBRSVG
+#ifdef HAVE_SKIA
...

-  SVG_RendererHooks  rsvg_hooks = { NULL, NULL, NULL, NULL };
+  SVG_RendererHooks  skia_hooks = { NULL, NULL, NULL, NULL };
...
    (void)FT_Property_Set( handle->library,
-                          "ot-svg", "svg-hooks", &rsvg_hooks );
+                          "ot-svg", "svg-hooks", &skia_hooks );
...

So potentionally I can add a toggle key to dynamically switch between 
rsvg/cairo to skia rendering by just swapping  &rsvg_hooks with &skia_hooks on 
the fly.
diff --git a/Makefile b/Makefile
index cded506..019e04d 100644
--- a/Makefile
+++ b/Makefile
@@ -61,6 +61,9 @@ ifeq ($(wildcard $(CONFIG_MK)),)
   no_config_mk := 1
 endif
 
+# Skia definitely want c++, and clang++ does not like -std=99
+# Why does this line has no effect?
+CC=g++
 ifdef no_config_mk
 
   exes:
@@ -136,8 +139,8 @@ else
     #
     # For the pure `make` call (without using `configure`) we have to add
     # all needed cflags manually.
-    FT_DEMO_CFLAGS := $(shell pkg-config --cflags librsvg-2.0) \
-                      -DHAVE_LIBRSVG
+    FT_DEMO_CFLAGS := -I$(TOP_DIR_2)/skia/ \
+                      -DHAVE_SKIA
   endif
 
   FT_INCLUDES := $(OBJ_BUILD) \
@@ -145,10 +148,13 @@ else
                  $(TOP_DIR)/include \
                  $(SRC_DIR)
 
+  # Skia definitely want c++, and clang++ does not like -std=99
+  CC=g++
   COMPILE = $(CC) $(ANSIFLAGS) \
                   $(INCLUDES:%=$I%) \
                   $(CFLAGS) \
-                  $(FT_DEMO_CFLAGS)
+                  $(FT_DEMO_CFLAGS) -I$(TOP_DIR_2)/skia/ -DHAVE_SKIA
+
 
   # Enable C99 for gcc to avoid warnings.
   # Note that clang++ aborts with an error if we use `-std=C99',
@@ -186,8 +192,10 @@ else
     # `FT_DEMO_LDFLAGS` has been set in `unix-cc.mk`, too.
     override CC = $(CCraw)
     LINK_CMD    = $(LIBTOOL) --mode=link $(CC) \
-                  $(subst /,$(COMPILER_SEP),$(LDFLAGS))
+                  -L$(TOP_DIR_2)/skia/out/Release/ -lsvg -lskia -lskshaper -lskunicode -lGL -lfontconfig -lharfbuzz \
+	          $(subst /,$(COMPILER_SEP),$(LDFLAGS))
     LINK_LIBS   = $(subst /,$(COMPILER_SEP),$(FTLIB) $(EFENCE)) \
+                  -L$(TOP_DIR_2)/skia/out/Release/ -lsvg -lskia -lskshaper -lskunicode -lGL -lfontconfig -lharfbuzz \
                   $(FT_DEMO_LDFLAGS)
   else
     LINK_CMD = $(CC) $(subst /,$(COMPILER_SEP),$(LDFLAGS))
@@ -196,10 +204,10 @@ else
       # all needed libraries manually.
       LINK_LIBS := $(subst /,$(COMPILER_SEP),$(FTLIB) $(EFENCE)) \
                    -lm -lrt -lz -lbz2 -lpthread
+      LINK_LIBS += -L$(TOP_DIR_2)/skia/out/Release/ -lsvg -lskia
       LINK_LIBS += $(shell pkg-config --libs libpng)
       LINK_LIBS += $(shell pkg-config --libs harfbuzz)
       LINK_LIBS += $(shell pkg-config --libs libbrotlidec)
-      LINK_LIBS += $(shell pkg-config --libs librsvg-2.0)
     else
       LINK_LIBS = $(subst /,$(COMPILER_SEP),$(FTLIB) $(EFENCE))
     endif
@@ -469,9 +477,13 @@ else
   $(OBJ_DIR_2)/rsvg-port.$(SO): $(SRC_DIR)/rsvg-port.c $(SRC_DIR)/rsvg-port.h
 	  $(COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
 
+  $(OBJ_DIR_2)/skia-port.$(SO): $(SRC_DIR)/skia-port.c $(SRC_DIR)/skia-port.h
+	  $(COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
+
   FTCOMMON_OBJ := $(OBJ_DIR_2)/ftcommon.$(SO) \
                   $(OBJ_DIR_2)/ftpngout.$(SO) \
-                  $(OBJ_DIR_2)/rsvg-port.$(SO)
+                  $(OBJ_DIR_2)/rsvg-port.$(SO) \
+                  $(OBJ_DIR_2)/skia-port.$(SO)
 
 
   ####################################################################
diff --git a/README.skia b/README.skia
new file mode 100644
index 0000000..35c9185
--- /dev/null
+++ b/README.skia
@@ -0,0 +1,59 @@
+Using Skia instead of Rsvg for rendering OT-SVG
+===============================================
+
+Skia has a large code base and a long history, and moving very fast.
+There is no official prebuilt binaries AFAIK. The official
+build procedure, does a 900MB+ clone, then fetches at least another
+1GB of third-party dependencies by clone'ing on the fly. I gave up
+after seeing it downloading 2GB+ without doing anything else (yet)!
+
+So I scouted around for reasonably up-to-date unofficial builds.
+This seems to be close enough for this purpose:
+
+    https://github.com/JetBrains/skia-pack/releases/
+
+At the time of writing, official skia is at m116, they have
+lightly patched m110. Another closely related place,
+seems to have unpatched m109:
+
+    https://github.com/HumbleUI/SkiaBuild
+
+skia-python bundles m87; m98 introduces COLRv1, and m103 introduces
+OT-SVG. For this purpose, m103+ is the minimum.
+
+
+PREPARATION:
+
+    mkdir skia/
+    pushd skia/
+         unzip "<downloaded>"/Skia-m110-d88a7b5-linux-Release-x64.zip
+    popd
+
+# This is just mirroring the layout of a submodule-based self-build
+# using the official procedure.
+
+    ln -s Release-linux-x64 skia/out/Release
+
+# Since we set "-Lskia/out/Release/" in the linker, we want to avoid
+# picking up those same bundled libraries, but let the linker pick
+# up the system versions of these libraries.
+
+    rm skia/out/Release/libharfbuzz.a
+    rm skia/out/Release/libzlib.a
+    rm skia/out/Release/libpng.a
+    rm skia/out/Release/libfreetype2.a
+    rm skia/out/Release/libjpeg.a
+
+
+BUILDING:
+
+Run:
+   CC=c++ ./configure --with-librsvg=no
+
+in freetype2. Using a C++ compiler is necessary (Skia is heavy-duty
+c++ code). Co-existence with librsvg and runtime-switching is
+still being looked at.
+
+Then just build as normal. The main noticeable outcome is that a few
+files in "bin/.libs" are 25MB+ (because linking with libskia.a),
+instead of a few MB in size.
diff --git a/skia/out/Release b/skia/out/Release
new file mode 120000
index 0000000..9f40889
--- /dev/null
+++ b/skia/out/Release
@@ -0,0 +1 @@
+Release-linux-x64
\ No newline at end of file
diff --git a/src/ftcommon.c b/src/ftcommon.c
index 74553aa..7d8a72e 100644
--- a/src/ftcommon.c
+++ b/src/ftcommon.c
@@ -29,6 +29,7 @@
 #include "strbuf.h"
 #include "ftcommon.h"
 #include "rsvg-port.h"
+#include "skia-port.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -360,7 +361,7 @@
 
     /* The use of an external SVG rendering library is optional. */
     (void)FT_Property_Set( handle->library,
-                           "ot-svg", "svg-hooks", &rsvg_hooks );
+                           "ot-svg", "svg-hooks", &skia_hooks );
 
     error = FTC_Manager_New( handle->library, 0, 0, 0,
                              my_face_requester, 0, &handle->cache_manager );
diff --git a/src/skia-port.c b/src/skia-port.c
new file mode 100644
index 0000000..961c705
--- /dev/null
+++ b/src/skia-port.c
@@ -0,0 +1,356 @@
+/****************************************************************************
+ *
+ * skia-port.c
+ *
+ *
+ * Copyright (C) 2022-2023 by
+ * Hin-Tak Leung, based on rsvg-port.c
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Main reference, this landed in Skia m103:
+ * https://github.com/google/skia/commit/9cbadcd9280dc139af2f4d41d25a6c9a750e0302.patch
+
+ * From 9cbadcd9280dc139af2f4d41d25a6c9a750e0302 Mon Sep 17 00:00:00 2001
+ * From: Ben Wagner <bunge...@google.com>
+ * Date: Wed, 20 Apr 2022 17:52:50 -0400
+ * Subject: [PATCH] Add optional OT-SVG support to FreeType
+
+ * In particular,
+       src/ports/SkFontHost_FreeType_common.cpp:
+           SkScalerContext_FreeType_Base::drawSVGGlyph()
+       src/ports/SkFontHost_FreeType.cpp:
+           SkScalerContext_FreeType::generateMetrics()
+
+   Unrelated but good-side reading:
+       src/ports/SkFontHost_FreeType_common.cpp:
+           SkScalerContext_FreeType_Base::computeColrV1GlyphBoundingBox()
+*/
+#include <ft2build.h>
+#include <freetype/otsvg.h>
+
+#ifdef HAVE_SKIA
+
+#include "modules/svg/include/SkSVGDOM.h"
+#include "modules/svg/include/SkSVGNode.h"
+#include "modules/svg/include/SkSVGRenderContext.h" // SkSVGPresentationContext
+#include "include/core/SkBitmap.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkMatrix.h"
+#include "include/core/SkStream.h"
+#include "include/private/SkFixed.h" // SkFixedToFloat(x) // relocated between m110 and main to "include/private/base/SkFixed.h"
+#include <stdlib.h>
+#include <math.h>
+
+#include <freetype/freetype.h>
+#include <freetype/ftbbox.h>
+
+#include "skia-port.h"
+
+
+  /*
+   * The init hook is called when the first OT-SVG glyph is rendered.  All
+   * we do is to allocate an internal state structure and set the pointer in
+   * `library->svg_renderer_state`.  This state structure becomes very
+   * useful to cache some of the results obtained by one hook function that
+   * the other one might use.
+   */
+  FT_Error
+  skia_port_init( FT_Pointer  *state )
+  {
+    /* allocate the memory upon initialization */
+    *state = calloc( sizeof( Skia_Port_StateRec ), 1 ); /* XXX error handling */
+    // Skia pointers are reference-counted, so
+    // malloc seems to be buggy and calloc is needed here.
+    // Unlike rsvg.
+
+    return FT_Err_Ok;
+  }
+
+
+  /*
+   * Deallocate the state structure.
+   */
+  void
+  skia_port_free( FT_Pointer  *state )
+  {
+    free( *state );
+  }
+
+
+  /*
+   * The render hook.  The job of this hook is to simply render the glyph in
+   * the buffer that has been allocated on the FreeType side.  Here we
+   * simply use the recording surface by playing it back against the
+   * surface.
+   */
+  FT_Error
+  skia_port_render( FT_GlyphSlot  slot,
+                    FT_Pointer   *_state )
+  {
+    FT_Error  error = FT_Err_Ok;
+
+    Skia_Port_State   state;
+
+    state = *(Skia_Port_State*)_state;
+
+    /* Create a SkBitmap to store the rendered image.  However,         */
+    /* don't allocate memory; instead use the space already provided in */
+    /* `slot->bitmap.buffer`.                                           */
+    SkBitmap dstBitmap;
+    dstBitmap.setInfo(SkImageInfo::Make(slot->bitmap.width, slot->bitmap.rows,
+                                        kBGRA_8888_SkColorType, // Not kN32 - FT_Bitmap are platform-neutral
+                                        kPremul_SkAlphaType),
+                      slot->bitmap.pitch);
+    dstBitmap.setPixels(slot->bitmap.buffer);
+
+    SkCanvas canvas(dstBitmap);
+
+    canvas.clear(SK_ColorTRANSPARENT);
+
+    /* Set a translate transform that translates the points in such a way */
+    /* that we get a tight rendering with least redundant white spac.     */
+    canvas.translate( -state->x, -state->y );
+
+    /* Replay from state->picture. This saves us from parsing        the */
+    /* document again and redoing what was already done in the preset    */
+    /* hook.                                                             */
+    canvas.drawPicture( state->picture );
+
+    slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
+    slot->bitmap.num_grays  = 256;
+    slot->format            = FT_GLYPH_FORMAT_BITMAP;
+
+    /* Clean up everything. */
+    state->picture = nullptr;
+
+    return error;
+  }
+
+
+  /*
+   * This hook is called at two different locations.  Firstly, it is called
+   * when presetting the glyphslot when `FT_Load_Glyph` is called.
+   * Secondly, it is called right before the render hook is called.  When
+   * `cache` is false, it is the former, when `cache` is true, it is the
+   * latter.
+   *
+   * The job of this function is to preset the slot setting the width,
+   * height, pitch, `bitmap.left`, and `bitmap.top`.  These are all
+   * necessary for appropriate memory allocation, as well as ultimately
+   * compositing the glyph later on by client applications.
+   */
+  FT_Error
+  skia_port_preset_slot( FT_GlyphSlot  slot,
+                         FT_Bool       cache,
+                         FT_Pointer   *_state )
+  {
+    /* FreeType variables. */
+    FT_Error  error = FT_Err_Ok;
+
+    FT_SVG_Document  document = (FT_SVG_Document)slot->other;
+
+    FT_UShort  units_per_EM   = document->units_per_EM;
+    FT_UShort  end_glyph_id   = document->end_glyph_id;
+    FT_UShort  start_glyph_id = document->start_glyph_id;
+
+    SkCanvas        *recordingCanvas;
+    SkMatrix  m;
+
+    /* Rendering port's state. */
+    Skia_Port_State     state;
+    Skia_Port_StateRec  state_dummy;
+
+    /* General variables. */
+    double  x, y;
+    double  width, height;
+
+    float metrics_width, metrics_height;
+    float horiBearingX, horiBearingY;
+    float vertBearingX, vertBearingY;
+    float tmpf;
+
+    /* If `cache` is `TRUE` we store calculations in the actual port */
+    /* state variable, otherwise we just create a dummy variable and */
+    /* store there.  This saves us from too many 'if' statements.    */
+    if ( cache )
+      state = *(Skia_Port_State*)_state;
+    else
+      state = &state_dummy;
+
+    /* Form an `sk_sp<SkSVGDOM>` by loading the SVG document. */
+    SkMemoryStream svgmem(document->svg_document,
+                          document->svg_document_length, false /*not copying */);
+    sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromStream(svgmem);
+
+    //svg->getRoot()->intrinsicSize();
+    if (svg->containerSize().isEmpty()) {
+      SkSize size = SkSize::Make(units_per_EM, units_per_EM);
+      svg->setContainerSize(size);
+    }
+    // Do we care about the viewBox attribute? It is auto I think, anyway.
+
+    /*
+     * Create a SkPictureRecorder.  This is done for two reasons.
+     * Firstly, it is required to get the bounding box of the final drawing
+     * so we can use an appropriate translate transform to get a tight
+     * rendering.  Secondly, if `cache` is true, we can save this surface
+     * and later replay it against an image surface for the final rendering.
+     * This saves us from loading and parsing the document again.
+     */
+    SkPictureRecorder recorder;
+
+    SkRect infiniteRect = SkRect::MakeLTRB(-SK_ScalarInfinity, -SK_ScalarInfinity,
+                                            SK_ScalarInfinity,  SK_ScalarInfinity);
+    sk_sp<SkBBoxHierarchy> bboxh = SkRTreeFactory()();
+
+    recordingCanvas = recorder.beginRecording(infiniteRect, bboxh);
+
+    /*
+     * Borrow heavily from:
+     *     src/ports/SkFontHost_FreeType_common.cpp:
+     *         SkScalerContext_FreeType_Base::drawSVGGlyph()
+     */
+    SkASSERT(slot->format == FT_GLYPH_FORMAT_SVG);
+
+    /*
+     * We need to take into account any transformations applied.  The end
+     * user who applied the transformation doesn't know the internal details
+     * of the SVG document.  Thus, we expect that the end user should just
+     * write the transformation as if the glyph is a traditional one.  We
+     * then do some maths on this to get the equivalent transformation in
+     * SVG coordinates.
+     */
+    FT_Matrix ftMatrix = document->transform;
+    FT_Vector ftOffset = document->delta;
+
+    /* Skia stores both transformation and translation in one matrix. */
+    m.setAll(
+        SkFixedToFloat(ftMatrix.xx), -SkFixedToFloat(ftMatrix.xy),  SkFixedToFloat(ftOffset.x),
+       -SkFixedToFloat(ftMatrix.yx),  SkFixedToFloat(ftMatrix.yy), -SkFixedToFloat(ftOffset.y),
+        0                          ,  0                          ,  1                        );
+
+    /* Set up a scale transformation to scale up the document to the */
+    /* required output size.                                         */
+    m.postScale(SkFixedToFloat(document->metrics.x_scale) / 64.0f,
+                SkFixedToFloat(document->metrics.y_scale) / 64.0f);
+
+    /* Set up a transformation matrix. */
+    recordingCanvas->concat(m);
+
+    /* If the document contains only one glyph, `start_glyph_id` and */
+    /* `end_glyph_id` have the same value.  Otherwise `end_glyph_id` */
+    /* is larger.                                                    */
+    if ( start_glyph_id < end_glyph_id )
+    {
+      SkSVGPresentationContext pctx;
+      char  id[32];
+      /* Render only the element with its ID equal to `glyph<ID>`. */
+      sprintf( id, "glyph%u", slot->glyph_index );
+
+      /*
+       * Unlike Rsvg, Skia's renderNode() takes an extra
+       * SkSVGPresentationContext argument, which sets foreground
+       * colors, palettes, etc, and does not take NULL to render
+       * whole. In the case of OT-SVG, there is no extra
+       * Context, so leaving it as default is fine.
+       */
+      svg->renderNode(recordingCanvas, pctx, id);
+    }
+    else
+    {
+      /* Render the whole document */
+      svg->render(recordingCanvas);
+    }
+
+    /* Get the bounding box of the drawing. */
+    state->picture = recorder.finishRecordingAsPicture();
+    SkRect bounds = state->picture->cullRect();
+    SkASSERT(bounds.isFinite());
+
+    width = bounds.width();
+    height = bounds.height();
+    x = bounds.left();
+    y = bounds.top();
+
+    /* We store the bounding box's `x` and `y` values so that the render */
+    /* hook can apply a translation to get a tight rendering.            */
+    state->x = x;
+    state->y = y;
+
+    /* Preset the values. */
+    slot->bitmap_left = (FT_Int) state->x;  /* XXX rounding? */
+    slot->bitmap_top  = (FT_Int)-state->y;
+
+    slot->bitmap.rows  = ceil( height );
+    slot->bitmap.width = ceil( width );
+
+    slot->bitmap.pitch = (int)slot->bitmap.width * 4;
+
+    slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
+
+    /* Compute all the bearings and set them correctly.  The outline is */
+    /* scaled already, we just need to use the bounding box.            */
+    metrics_width  = (float)width;
+    metrics_height = (float)height;
+
+    horiBearingX = (float) state->x;
+    horiBearingY = (float)-state->y;
+
+    vertBearingX = slot->metrics.horiBearingX / 64.0f -
+                     slot->metrics.horiAdvance / 64.0f / 2;
+    vertBearingY = ( slot->metrics.vertAdvance / 64.0f -
+                       slot->metrics.height / 64.0f ) / 2; /* XXX parentheses correct? */
+
+    /* Do conversion in two steps to avoid 'bad function cast' warning. */
+    tmpf                 = roundf( metrics_width * 64 );
+    slot->metrics.width  = (FT_Pos)tmpf;
+    tmpf                 = roundf( metrics_height * 64 );
+    slot->metrics.height = (FT_Pos)tmpf;
+
+    slot->metrics.horiBearingX = (FT_Pos)( horiBearingX * 64 ); /* XXX rounding? */
+    slot->metrics.horiBearingY = (FT_Pos)( horiBearingY * 64 );
+    slot->metrics.vertBearingX = (FT_Pos)( vertBearingX * 64 );
+    slot->metrics.vertBearingY = (FT_Pos)( vertBearingY * 64 );
+
+    if ( slot->metrics.vertAdvance == 0 )
+      slot->metrics.vertAdvance = (FT_Pos)( metrics_height * 1.2f * 64 );
+
+    /* If a render call is to follow, just destroy the canvas for the  */
+    /* SkPictureRecorder since no more drawing will be done on it.     */
+    /* However, keep the Picture itself for use by the render hook.    */
+    // TRUE defined in /usr/include/glib-2.0/glib/gmacros.h
+    // TRUE/FALSE not in c++, defined in include/freetype/internal/ftobjs.h (not used)
+    // but defined indirectly in librsvg. Its header to refer to it (from glib).
+    if ( !cache )
+    {
+      /* We don't have to do this; just being pedantic */
+      state->picture = nullptr;
+    }
+
+    return error;
+  }
+
+
+  SVG_RendererHooks  skia_hooks = {
+                       (SVG_Lib_Init_Func)skia_port_init,
+                       (SVG_Lib_Free_Func)skia_port_free,
+                       (SVG_Lib_Render_Func)skia_port_render,
+                       (SVG_Lib_Preset_Slot_Func)skia_port_preset_slot
+                     };
+
+#else /* !HAVE_SKIA */
+
+  SVG_RendererHooks  skia_hooks = { NULL, NULL, NULL, NULL };
+
+#endif /* !HAVE_SKIA */
+
+
+/* End */
diff --git a/src/skia-port.h b/src/skia-port.h
new file mode 100644
index 0000000..75c2d5a
--- /dev/null
+++ b/src/skia-port.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+ *
+ * skia-port.h
+ *
+ *   Skia based hook functions for OT-SVG rendering in FreeType
+ *   (headers).
+ *
+ * Copyright (C) 2022-2023 by
+ * Hin-Tak Leung, based on rsvg-port.h
+ *
+ * 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 SKIA_PORT_H
+#define SKIA_PORT_H
+
+#include <ft2build.h>
+#include <freetype/otsvg.h>
+
+#ifdef HAVE_SKIA
+
+#include "include/core/SkPictureRecorder.h"
+#include <freetype/freetype.h>
+
+
+  /*
+   * Different hook functions can access persisting data by creating a state
+   * structure and putting its address in `library->svg_renderer_state`.
+   * Functions can then store and retrieve data from this structure.
+   */
+  typedef struct  Skia_Port_StateRec_
+  {
+    sk_sp<SkPicture> picture;
+
+    double  x;
+    double  y;
+
+  } Skia_Port_StateRec;
+
+  typedef struct Skia_Port_StateRec_*  Skia_Port_State;
+
+
+  FT_Error
+  skia_port_init( FT_Pointer  *state );
+
+  void
+  skia_port_free( FT_Pointer  *state );
+
+  FT_Error
+  skia_port_render( FT_GlyphSlot  slot,
+                    FT_Pointer   *state );
+
+  FT_Error
+  skia_port_preset_slot( FT_GlyphSlot  slot,
+                         FT_Bool       cache,
+                         FT_Pointer   *state );
+
+#endif /* HAVE_SKAI */
+
+
+  extern SVG_RendererHooks  skia_hooks;
+
+#endif /* SKIA_PORT_H */
+
+
+/* End */

Reply via email to