[librsvg: 2/6] New chapter for the docs, migrating from old APIs
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 2/6] New chapter for the docs, migrating from old APIs
- Date: Thu, 16 Sep 2021 00:09:04 +0000 (UTC)
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><svg></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><svg></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, &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]