[librsvg: 2/6] New chapter for the docs, migrating from old APIs




commit bb743e0717b7c006b9b1676060802cd1ed663fc7
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Sep 13 20:43:14 2021 -0500

    New chapter for the docs, migrating from old APIs
    
    Fixes #643
    
    Part-of: <https://gitlab.gnome.org/GNOME/librsvg/-/merge_requests/588>

 doc/Makefile.am   |   2 +
 doc/migrating.xml | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 doc/rsvg-docs.xml |   1 +
 3 files changed, 267 insertions(+)
---
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 63f6701d..05044255 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -71,6 +71,8 @@ HTML_IMAGES =
 # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
 # e.g. content_files=running.sgml building.sgml changes-2.0.sgml
 content_files =                        \
+       load-and-render.c       \
+       migrating.xml           \
        overview.xml            \
        recommendations.xml     \
        version.xml
diff --git a/doc/migrating.xml b/doc/migrating.xml
new file mode 100644
index 00000000..42264f41
--- /dev/null
+++ b/doc/migrating.xml
@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<chapter>
+  <title>Migrating from old APIs</title>
+
+  <section id="migrating-from-non-viewport">
+    <title>Migrating from the deprecated API that does not use viewports</title>
+
+    <para>
+      First, some context.  Until librsvg version 2.44, the only way
+      to render an RsvgHandle into a Cairo context was with the
+      functions <function>rsvg_handle_render_cairo(handle, cairo_t)</function> and
+      <function>rsvg_handle_render_cairo_sub(handle, cairo_t, id)</function> —
+      respectively, to render the whole document, and to render a
+      single "layer" from it.  Both functions assumed that the SVG
+      document was to be rendered at its "natural size", or to the
+      size overriden with
+      <function>rsvg_handle_set_size_callback()</function>.  Since the
+      Cairo context can already have an affine transform applied to
+      it, that transform can further change the size of the rendered
+      image.
+    </para>
+
+    <para>
+      Librsvg 2.46 introduced the following functions, designed to replace the 
<function>render_cairo</function> ones:
+    </para>
+
+    <itemizedlist>
+      <listitem><function>rsvg_handle_render_document()</function> - renders the whole document</listitem>
+      <listitem><function>rsvg_handle_render_layer()</function> - renders a single layer</listitem>
+      <listitem><function>rsvg_handle_render_element()</function> - renders a single element</listitem>
+      <listitem>Plus corresponding functions to get the geometries of the document/layer/element.</listitem>
+    </itemizedlist>
+
+    <para>
+      All of those functions take a <firstterm>viewport</firstterm>
+      argument.  Let's see what this means.  But first, some history.
+    </para>
+
+    <section>
+      <title>Historical note: before librsvg supported viewports</title>
+
+      <para>
+        When librsvg was first written, its API basically consisted of
+        only functions to load an RsvgHandle, plus
+        <function>rsvg_handle_get_pixbuf()</function> to render it
+        directly to a GdkPixbuf image.  Internally the library used
+        libart (a pre-Cairo 2D rendering library), but did not expose
+        it in the public API.
+      </para>
+
+      <para>
+        The only way to specify a size at which to render an
+        RsvgHandle was with
+        <function>rsvg_handle_set_size_callback()</function>, and the
+        callback would run at an unspecified time during
+        <emphasis>loading</emphasis>: when just enough of the SVG
+        document had been loaded to read in the
+        <literal>width/height</literal> attributes of the toplevel
+        <literal>&lt;svg&gt;</literal> element, the callback would let
+        the application override these values with its own desired
+        size.
+      </para>
+
+      <para>
+        Some years later, Cairo was introduced, and it started to
+        replace libart.  Unlike libart, which could only render to
+        in-memory RGBA buffers, Cairo had a notion of "backends": it
+        could render to RGBA buffers, or it could translate its
+        drawing model commands into PDF or PostScript.  In Cairo's
+        terms, one creates a <type>cairo_surface_t</type> of a
+        particular kind (in-memory image surface, PDF surface, EPS
+        surface, etc.), and then a <type>cairo_t</type> context for
+        the surface.  The context is what makes the drawing commands
+        available.
+      </para>
+
+      <para>
+        Being able to render SVG documents directly to PDF or
+        PostScript was clearly attractive, so librsvg's API of
+        <function>rsvg_handle_get_pixbuf()</function> would clearly
+        not be enough.  It would be better to pass a
+        <type>cairo_t</type> for an already-created surface, and have
+        librsvg issue its drawing commands to it.  Then the
+        application would be in control of the surface type, or in the
+        case of GTK widgets, they would already get a
+        <type>cairo_t</type> passed to their drawing functions.
+        Librsvg got modified to export a
+        <function>rsvg_handle_render_cairo(handle,
+        cairo_t)</function>, and then it reimplemented the old
+        <function>rsvg_handle_get_pixbuf()</function> in terms of
+        Cairo.
+      </para>
+
+      <para>
+        At this point, librsvg still kept the notion of rendering SVG
+        documents at their "natural size": the
+        <literal>&lt;svg&gt;</literal> element's
+        <literal>width</literal> and <literal>height</literal>
+        attributes converted to pixels (e.g. converting from
+        <literal>width="5cm"</literal> by using the dots-per-inch
+        value from the RsvgHandle), or if those attributes don't
+        exist, by using the <literal>viewBox</literal> as a pixel
+        size.  The assumption was that if you needed a different size,
+        you could always start by setting the transformation matrix on
+        your <type>cairo_t</type> and then rendering to that.
+      </para>
+    </section>
+
+    <section>
+      <title>The problem with not having viewports</title>
+
+      <para>
+        Most applications which use librsvg to render SVG assets for
+        their user interface generally work in the same way.  For
+        example, to take an SVG icon and render it, they do something
+        like this:
+      </para>
+
+      <orderedlist>
+        <listitem>
+          <para>
+            Create an <type>RsvgHandle</type> by loading it from the SVG icon data.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Ask the <type>RsvgHandle</type> for its dimensions.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Divide the dimensions by the GUI's preferred size for icons.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Scale a Cairo context by the result of the previous step.
+            Translate the Cairo context so the icon will appear at the
+            desired location.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Render the <type>RsvgHandle</type> in that Cairo context.
+          </para>
+        </listitem>
+      </orderedlist>
+
+      <para>
+        This is... too much work.  The web world has moved on to using
+        the CSS box model practically everywhere.  To embed an image
+        you specify <emphasis>where</emphasis> and at <emphasis>what
+        size</emphasis> you want to place it, and it gets done
+        automatically.  You actually have to do extra work if you want
+        to do non-standard things like scale an image
+        non-proportionally.
+      </para>
+    </section>
+
+    <section>
+      <title>The new rendering API that uses viewports</title>
+
+      <para>
+        These are the <emphasis>deprecated</emphasis> drawing functions that do not take viewports:
+      </para>
+
+      <programlisting lang="c">
+gboolean rsvg_handle_render_cairo     (RsvgHandle *handle,
+                                       cairo_t    *cr);
+
+gboolean rsvg_handle_render_cairo_sub (RsvgHandle *handle,
+                                       cairo_t    *cr,
+                                       const char *id);
+      </programlisting>
+
+      <para>
+        Starting with librsvg 2.46, the following functions are available:
+      </para>
+
+      <programlisting lang="c">
+gboolean rsvg_handle_render_document (RsvgHandle           *handle,
+                                      cairo_t              *cr,
+                                      const RsvgRectangle  *viewport,
+                                      GError              **error);
+
+gboolean rsvg_handle_render_layer    (RsvgHandle           *handle,
+                                      cairo_t              *cr,
+                                      const char           *id,
+                                      const RsvgRectangle  *viewport,
+                                      GError              **error);
+
+gboolean rsvg_handle_render_element  (RsvgHandle           *handle,
+                                      cairo_t              *cr,
+                                      const char           *id,
+                                      const RsvgRectangle  *element_viewport,
+                                      GError              **error);
+      </programlisting>
+
+      <para>
+        For brevity we'll omit the <literal>rsvg_handle</literal>
+        namespace prefix, and just talk about the actual function
+        names.  You can see that <function>render_document</function>
+        is basically the same as <function>render_cairo</function>,
+        but it has an extra <parameter>viewport</parameter> argument.
+        The same occurs in <function>render_layer</function> versus
+        <function>render_cairo_sub</function>.
+      </para>
+
+      <para>
+        In both of those cases — <function>render_document</function>
+        and <function>render_layer</function> —, the
+        <parameter>viewport</parameter> argument specifies a rectangle
+        into which the SVG will be positioned and scaled to fit.
+        Consider something like this:
+      </para>
+
+      <programlisting lang="c">
+RsvgRectangle viewport = {
+    .x = 10.0,
+    .y = 20.0,
+    .width = 640.0,
+    .height = 480.0,
+};
+
+rsvg_handle_render_document (handle, cr, &amp;viewport, NULL);
+      </programlisting>
+
+      <para>
+        This is equivalent to first figuring out the scaling factor to
+        make the SVG fit proportionally in 640x480 pixels, then
+        translating the <varname>cr</varname> by (10, 20) pixels, and
+        then calling <function>rsvg_handle_render_cairo</function>.
+        If the SVG has different proportions than the width and height
+        of the rectangle, it will be rendered and centered to fit the
+        rectangle.
+      </para>
+
+      <para>
+        Even better: the old functions to get an SVG's natural
+        dimensions, like
+        <function>rsvg_handle_get_dimensions</function>, returned
+        integers instead of floating-point numbers, so you could not
+        always get an exact fit.  Please use the new functions that
+        take viewports; they will give you easier and better results.
+      </para>
+
+      <note>
+        <para>
+          <function>rsvg_handle_render_element</function> is new in
+          librsvg 2.46.  It extracts a single element from the SVG
+          and renders it scaled to the viewport you specify.  It is
+          different from <function>render_layer</function> (or the
+          old-style <function>render_cairo_sub</function>) in that
+          those ones act as if they rendered the whole document's
+          area, but they only paint the element you specify.
+        </para>
+      </note>
+    </section>
+  </section>
+</chapter>
diff --git a/doc/rsvg-docs.xml b/doc/rsvg-docs.xml
index 3268aeba..61d9f3c5 100644
--- a/doc/rsvg-docs.xml
+++ b/doc/rsvg-docs.xml
@@ -88,6 +88,7 @@
 
     <xi:include href="overview.xml"/>
     <xi:include href="recommendations.xml"/>
+    <xi:include href="migrating.xml"/>
 
     <xi:include href="xml/rsvg-handle.xml"/>
     <xi:include href="xml/rsvg-gio.xml"/>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]