diff --git a/test/cairo-svg-test-doc.ttx b/test/cairo-svg-test-doc.ttx
new file mode 100644
index 000000000..c2cdb2817
--- /dev/null
+++ b/test/cairo-svg-test-doc.ttx
@@ -0,0 +1,689 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cairo Svg Test Doc
+
+
+ Regular
+
+
+ Cairo Svg Test Doc Regular
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
diff --git a/test/cairo-svg-test-fill.ttx b/test/cairo-svg-test-fill.ttx
new file mode 100644
index 000000000..b6867ec8f
--- /dev/null
+++ b/test/cairo-svg-test-fill.ttx
@@ -0,0 +1,365 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cairo Svg Test Fill
+
+
+ Regular
+
+
+ Cairo Svg Test Fill Regular
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+
+
+
+]]>
+
+
+
+
diff --git a/test/cairo-svg-test-gradient.ttx b/test/cairo-svg-test-gradient.ttx
new file mode 100644
index 000000000..4a7a22175
--- /dev/null
+++ b/test/cairo-svg-test-gradient.ttx
@@ -0,0 +1,441 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cairo Svg Test Gradient
+
+
+ Regular
+
+
+ Cairo Svg Test Gradient Regular
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
diff --git a/test/cairo-svg-test-path.ttx b/test/cairo-svg-test-path.ttx
new file mode 100644
index 000000000..9173a537d
--- /dev/null
+++ b/test/cairo-svg-test-path.ttx
@@ -0,0 +1,281 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cairo Svg Test Path
+
+
+ Regular
+
+
+ Cairo Svg Test Path Regular
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
diff --git a/test/cairo-svg-test-shapes.ttx b/test/cairo-svg-test-shapes.ttx
new file mode 100644
index 000000000..15a573a64
--- /dev/null
+++ b/test/cairo-svg-test-shapes.ttx
@@ -0,0 +1,333 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cairo Svg Test Shapes
+
+
+ Regular
+
+
+ Cairo Svg Test Shapes Regular
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
diff --git a/test/cairo-svg-test-stroke.ttx b/test/cairo-svg-test-stroke.ttx
new file mode 100644
index 000000000..a403da928
--- /dev/null
+++ b/test/cairo-svg-test-stroke.ttx
@@ -0,0 +1,608 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cairo Svg Test Stroke
+
+
+ Regular
+
+
+ Cairo Svg Test Stroke Regular
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
+]]>
+
+
+
+
diff --git a/test/cairo-svg-test-transform.ttx b/test/cairo-svg-test-transform.ttx
new file mode 100644
index 000000000..1f07c05ad
--- /dev/null
+++ b/test/cairo-svg-test-transform.ttx
@@ -0,0 +1,403 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cairo Svg Test Transform
+
+
+ Regular
+
+
+ Cairo Svg Test Transform Regular
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+
+
+
diff --git a/test/ft-svg-render.c b/test/ft-svg-render.c
new file mode 100644
index 000000000..9b0351b10
--- /dev/null
+++ b/test/ft-svg-render.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright © 2022 Adrian Johnson
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Adrian Johnson
+ */
+
+#include "cairo-test.h"
+#include
+
+#define GLYPH_SIZE 50
+#define PAD 5
+#define WIDTH (4*(GLYPH_SIZE + PAD) + PAD)
+#define HEIGHT WIDTH
+
+//#define CLIP 1
+#define LOG_EXTENTS 1
+
+static cairo_test_status_t
+draw_font (cairo_t *cr, int width, int height, const char *font_file)
+{
+ cairo_test_status_t result;
+ char buf[10];
+ cairo_text_extents_t extents;
+ cairo_font_options_t *font_options;
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+
+ result = cairo_test_ft_select_font_from_file (cr, font_file);
+ if (result)
+ return result;
+
+ font_options = cairo_font_options_create ();
+ cairo_font_options_set_color_mode (font_options, CAIRO_COLOR_MODE_NO_COLOR);
+// cairo_set_font_options (cr, font_options);
+ cairo_font_options_destroy (font_options);
+
+ cairo_set_font_size (cr, GLYPH_SIZE);
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ int x = j * (GLYPH_SIZE + PAD) + PAD;
+ int y = i * (GLYPH_SIZE + PAD) + PAD;
+ int glyph_number = 4*i + j;
+ buf[0] = glyph_number < 10 ? '0' + glyph_number : 'A' + glyph_number - 10;
+ buf[1] = 0;
+ cairo_save (cr);
+ cairo_text_extents (cr, buf, &extents);
+#if LOG_EXTENTS
+ cairo_test_log (cairo_test_get_context (cr),
+ "Char '%c' extents: x_bearing: %f y_bearing: %f width: %f height: %f x_advance: %f y_advance: %f\n",
+ buf[0],
+ extents.x_bearing,
+ extents.y_bearing,
+ extents.width,
+ extents.height,
+ extents.x_advance,
+ extents.y_advance);
+#endif
+#if CLIP
+ cairo_rectangle (cr, x, y, GLYPH_SIZE, GLYPH_SIZE);
+ cairo_clip (cr);
+#endif
+ cairo_move_to (cr, x, y + GLYPH_SIZE);
+ cairo_show_text (cr, buf);
+ cairo_restore (cr);
+ if (cairo_status (cr)) {
+ cairo_test_log (cairo_test_get_context (cr),
+ "cairo_show_text() failed with \"%s\"\n",
+ buf);
+ return CAIRO_TEST_FAILURE;
+ }
+ }
+ }
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+#define DRAW_FUNC(name) \
+static cairo_test_status_t \
+draw_##name (cairo_t *cr, int width, int height) { \
+ return draw_font (cr, width, height, "cairo-svg-test-" #name ".ttf"); \
+}
+
+DRAW_FUNC(doc)
+CAIRO_TEST (ft_svg_render_doc,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_doc)
+
+DRAW_FUNC(fill)
+CAIRO_TEST (ft_svg_render_fill,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_fill)
+
+DRAW_FUNC(gradient)
+CAIRO_TEST (ft_svg_render_gradient,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_gradient)
+
+DRAW_FUNC(path)
+CAIRO_TEST (ft_svg_render_path,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_path)
+
+DRAW_FUNC(shapes)
+CAIRO_TEST (ft_svg_render_shapes,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_shapes)
+
+DRAW_FUNC(stroke)
+CAIRO_TEST (ft_svg_render_stroke,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_stroke)
+
+DRAW_FUNC(transform)
+CAIRO_TEST (ft_svg_render_transform,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_transform)
diff --git a/test/meson.build b/test/meson.build
index 3071ac6ca..3606bfc27 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -431,6 +431,7 @@ test_ft_svg_font_sources = [
test_ft_svg_ttx_font_sources = [
'ft-svg-cairo-logo.c',
+ 'ft-svg-render.c'
]
test_gl_sources = [
@@ -525,6 +526,13 @@ ps2png_sources = [
test_ttx_fonts = [
'cairo-logo-font.ttx',
+ 'cairo-svg-test-doc.ttx',
+ 'cairo-svg-test-fill.ttx',
+ 'cairo-svg-test-gradient.ttx',
+ 'cairo-svg-test-path.ttx',
+ 'cairo-svg-test-shapes.ttx',
+ 'cairo-svg-test-stroke.ttx',
+ 'cairo-svg-test-transform.ttx',
]
build_any2ppm = false
@@ -681,3 +689,9 @@ test('cairo', exe,
suite: ['cairo-test-suite', 'slow'],
workdir: meson.current_build_dir(),
depends: test_depends)
+
+# The SVG renderer debug tools can only be built if the _cairo_debug_svg_render()
+# function has been exposed by defining DEBUG_SVG_RENDER
+if conf.get('HAVE_FT_SVG_DOCUMENT', 0) == 1 and cc.get_define('DEBUG_SVG_RENDER') != ''
+ subdir('svg')
+endif
diff --git a/test/reference/ft-svg-render-doc.ref.png b/test/reference/ft-svg-render-doc.ref.png
new file mode 100644
index 000000000..e7ecf7f1a
Binary files /dev/null and b/test/reference/ft-svg-render-doc.ref.png differ
diff --git a/test/reference/ft-svg-render-fill.ref.png b/test/reference/ft-svg-render-fill.ref.png
new file mode 100644
index 000000000..a72cdd1f2
Binary files /dev/null and b/test/reference/ft-svg-render-fill.ref.png differ
diff --git a/test/reference/ft-svg-render-gradient.ref.png b/test/reference/ft-svg-render-gradient.ref.png
new file mode 100644
index 000000000..d647dc06a
Binary files /dev/null and b/test/reference/ft-svg-render-gradient.ref.png differ
diff --git a/test/reference/ft-svg-render-path.ref.png b/test/reference/ft-svg-render-path.ref.png
new file mode 100644
index 000000000..2667059cc
Binary files /dev/null and b/test/reference/ft-svg-render-path.ref.png differ
diff --git a/test/reference/ft-svg-render-shapes.ref.png b/test/reference/ft-svg-render-shapes.ref.png
new file mode 100644
index 000000000..209e0ddb3
Binary files /dev/null and b/test/reference/ft-svg-render-shapes.ref.png differ
diff --git a/test/reference/ft-svg-render-stroke.ref.png b/test/reference/ft-svg-render-stroke.ref.png
new file mode 100644
index 000000000..86f1ab9b6
Binary files /dev/null and b/test/reference/ft-svg-render-stroke.ref.png differ
diff --git a/test/reference/ft-svg-render-transform.ref.png b/test/reference/ft-svg-render-transform.ref.png
new file mode 100644
index 000000000..dcc372aac
Binary files /dev/null and b/test/reference/ft-svg-render-transform.ref.png differ
diff --git a/test/svg/README b/test/svg/README
new file mode 100644
index 000000000..c4504dc9b
--- /dev/null
+++ b/test/svg/README
@@ -0,0 +1,22 @@
+build_ttx_fonts.py
+==================
+Is used to create the test/*.ttx files used for testing the SVG glyph renderer.
+
+build_ttx_fonts.py will look for files of the form
+
+...svg
+
+in the input directory, and using svg-font-template.ttx, create .ttx
+files that contain one glyph for each svg file. Each .ttx will contain
+a glyph for each svg with the matching prefix. Each glyphs will be mapped
+to the i nthe svg filename. The must be one of 0-9,A-F.
+
+svg-render.c
+============
+svg-render renders SVG files using both librsvg and cairo-svg-glyph-render.c.
+It is used for testing cairo-svg-glyph-render.c during development.
+
+To use svg-render, cairo must be built with CFLAGS="-DDEBUG_SVG_RENDER" to enable the
+_cairo_debug_svg_render() function.
+
+
diff --git a/test/svg/build_ttx_fonts.py b/test/svg/build_ttx_fonts.py
new file mode 100755
index 000000000..d7e7f5b8f
--- /dev/null
+++ b/test/svg/build_ttx_fonts.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python3
+
+# Build the ttx cairo svg test fonts from svg files
+# The svg files use the naming convention
+# ...svg
+# eg "circle.A.cx_cy_r.svg"
+#
+# is use to create the name of the ttx font.
+# is a ascii hex character (uppercase) that the font fill map to the SVG description.
+# is a descriptive name of the SVG file and is not used to build the font…
+#
+# This script looks for all files matching the above pattern and
+# creates one ttx font for each unique . Each font will
+# contain up to 16 characters. The SVG description of each character
+# and the character that maps to the SVG description is obtained from
+# the SVG file beginning with ..
+
+import argparse
+import os
+import re
+import sys
+import xml.dom.minidom
+
+TEMPLATE_FILE="svg-font-template.ttx"
+
+glyph_names = {
+ '0': 'zero',
+ '1': 'one',
+ '2': 'two',
+ '3': 'three',
+ '4': 'four',
+ '5': 'five',
+ '6': 'six',
+ '7': 'seven',
+ '8': 'eight',
+ '9': 'nine',
+ 'A': 'A',
+ 'B': 'B',
+ 'C': 'C',
+ 'D': 'D',
+ 'E': 'E',
+ 'F': 'F'
+}
+
+# files is list of (char, filename)
+def build_font(font_name, files, in_dir, out_dir, no_reformat):
+ name = "cairo-svg-test-" + font_name
+ doc = xml.dom.minidom.parse(os.path.join(in_dir, TEMPLATE_FILE))
+ glyph_id = 1
+ text_nl = doc.createTextNode('\n\n')
+ for f in sorted(files):
+ glyph_name = glyph_names[f[0]]
+
+ glyph_order = doc.getElementsByTagName('GlyphOrder')[0]
+ glyph_id_elem = doc.createElement('GlyphID')
+ glyph_id_elem.setAttribute('id', str(glyph_id))
+ glyph_id_elem.setAttribute('name', glyph_name)
+ glyph_order.appendChild(glyph_id_elem)
+ glyph_order.appendChild(text_nl)
+
+ hmtx = doc.getElementsByTagName('hmtx')[0]
+ mtx = doc.createElement('mtx')
+ mtx.setAttribute('name', glyph_name)
+ mtx.setAttribute('width', '1100')
+ mtx.setAttribute('lsb', '0')
+ hmtx.appendChild(mtx)
+
+ cmap_format = doc.getElementsByTagName('cmap_format_4')[0]
+ map = doc.createElement('map')
+ map.setAttribute('code', hex(ord(f[0])))
+ map.setAttribute('name', glyph_name)
+ cmap_format.appendChild(map)
+
+ glyf = doc.getElementsByTagName('glyf')[0]
+ tt_glyph = doc.createElement('TTGlyph')
+ tt_glyph.setAttribute('name', glyph_name)
+ glyf.appendChild(tt_glyph)
+ contour = doc.createElement('contour')
+ tt_glyph.appendChild(contour)
+ pt = doc.createElement('pt')
+ pt.setAttribute('x', "0")
+ pt.setAttribute('y', "0")
+ pt.setAttribute('on', "1")
+ contour.appendChild(pt)
+ pt = doc.createElement('pt')
+ pt.setAttribute('x', "0")
+ pt.setAttribute('y', "1000")
+ pt.setAttribute('on', "1")
+ contour.appendChild(pt)
+ pt = doc.createElement('pt')
+ pt.setAttribute('x', "1000")
+ pt.setAttribute('y', "1000")
+ pt.setAttribute('on', "1")
+ contour.appendChild(pt)
+ pt = doc.createElement('pt')
+ pt.setAttribute('x', "1000")
+ pt.setAttribute('y', "0")
+ pt.setAttribute('on', "1")
+ contour.appendChild(pt)
+ instructions = doc.createElement('instructions')
+ tt_glyph.appendChild(instructions)
+
+ svg = doc.getElementsByTagName('SVG')[0]
+ svgdoc = doc.createElement('svgDoc')
+ svgdoc.setAttribute('startGlyphID', str(glyph_id))
+ svgdoc.setAttribute('endGlyphID', str(glyph_id))
+ with open(os.path.join(in_dir, f[1]), 'r') as svg_file:
+ svg_data = svg_file.read()
+ cdata = doc.createCDATASection(svg_data)
+ svgdoc.appendChild(cdata)
+ svg.appendChild(svgdoc)
+ glyph_id += 1
+
+ name_record = doc.getElementsByTagName('namerecord')[0]
+ name_record.firstChild.replaceWholeText(name.replace("-", " ").title())
+ name_record = doc.getElementsByTagName('namerecord')[2]
+ name_record.firstChild.replaceWholeText(name.replace("-", " ").title() + " Regular")
+
+ ttx_filename = os.path.join(out_dir, name + '.ttx')
+ ttf_filename = os.path.join(out_dir, name + '.ttf')
+ with open(ttx_filename, 'w') as ttx_file:
+ doc.writexml(ttx_file)
+
+ if not no_reformat:
+ # Convert to ttf and back to ttx. This reformats the ttx file
+ # which allows better quality diffs.
+ if os.path.exists(ttf_filename):
+ os.remove(ttf_filename)
+ os.system("ttx " + ttx_filename)
+ os.remove(ttx_filename)
+ os.system("ttx " + ttf_filename)
+ os.remove(ttf_filename)
+
+def build_file_list(in_dir):
+ dict = {}
+ regex_prog = re.compile(r"([^\.]+)\.(.)\.[^\.]+\.svg", re.ASCII)
+ files = os.listdir(in_dir)
+ for f in files:
+ match = regex_prog.fullmatch(f)
+ if match:
+ fontname = match.group(1)
+ character = match.group(2)
+ if (fontname not in dict):
+ dict[fontname] = [(character, f)];
+ else:
+ dict[fontname].append((character, f))
+ return dict
+
+if __name__=='__main__':
+ parser = argparse.ArgumentParser(description='Build ttx fonts.')
+ parser.add_argument("-i", nargs=1, metavar="indir", default=["."], help="Input directory")
+ parser.add_argument("-o", nargs=1, metavar="outdir", default=["."], help="Output directory")
+ parser.add_argument("-n", action='store_true', help="Don't reformat the output.")
+ args = parser.parse_args()
+ in_dir = args.i[0]
+ out_dir = args.o[0]
+ no_reformat = args.n
+ file_list = build_file_list(in_dir)
+ font_name = None
+ for key, value in file_list.items():
+ build_font(key, value, in_dir, out_dir, no_reformat)
diff --git a/test/svg/doc.0.viewBox1.svg b/test/svg/doc.0.viewBox1.svg
new file mode 100644
index 000000000..c1f55a4eb
--- /dev/null
+++ b/test/svg/doc.0.viewBox1.svg
@@ -0,0 +1,4 @@
+
diff --git a/test/svg/doc.1.viewBox2.svg b/test/svg/doc.1.viewBox2.svg
new file mode 100644
index 000000000..b8f976ba9
--- /dev/null
+++ b/test/svg/doc.1.viewBox2.svg
@@ -0,0 +1,4 @@
+
diff --git a/test/svg/doc.2.image.svg b/test/svg/doc.2.image.svg
new file mode 100644
index 000000000..1d03842a9
--- /dev/null
+++ b/test/svg/doc.2.image.svg
@@ -0,0 +1,121 @@
+
diff --git a/test/svg/doc.3.image-transform.svg b/test/svg/doc.3.image-transform.svg
new file mode 100644
index 000000000..90e5ecb1a
--- /dev/null
+++ b/test/svg/doc.3.image-transform.svg
@@ -0,0 +1,122 @@
+
diff --git a/test/svg/doc.4.clip-user.svg b/test/svg/doc.4.clip-user.svg
new file mode 100644
index 000000000..26cdd818a
--- /dev/null
+++ b/test/svg/doc.4.clip-user.svg
@@ -0,0 +1,9 @@
+
diff --git a/test/svg/doc.5.clip-object.svg b/test/svg/doc.5.clip-object.svg
new file mode 100644
index 000000000..732911590
--- /dev/null
+++ b/test/svg/doc.5.clip-object.svg
@@ -0,0 +1,10 @@
+
diff --git a/test/svg/doc.6.clip-user2.svg b/test/svg/doc.6.clip-user2.svg
new file mode 100644
index 000000000..a68c1c42f
--- /dev/null
+++ b/test/svg/doc.6.clip-user2.svg
@@ -0,0 +1,10 @@
+
diff --git a/test/svg/doc.7.clip-object2.svg b/test/svg/doc.7.clip-object2.svg
new file mode 100644
index 000000000..f5c153dd1
--- /dev/null
+++ b/test/svg/doc.7.clip-object2.svg
@@ -0,0 +1,11 @@
+
diff --git a/test/svg/doc.8.clip-user3.svg b/test/svg/doc.8.clip-user3.svg
new file mode 100644
index 000000000..8ff61d593
--- /dev/null
+++ b/test/svg/doc.8.clip-user3.svg
@@ -0,0 +1,15 @@
+
diff --git a/test/svg/doc.9.clip-object3.svg b/test/svg/doc.9.clip-object3.svg
new file mode 100644
index 000000000..b291df79f
--- /dev/null
+++ b/test/svg/doc.9.clip-object3.svg
@@ -0,0 +1,15 @@
+
diff --git a/test/svg/doc.A.g.svg b/test/svg/doc.A.g.svg
new file mode 100644
index 000000000..bdaade725
--- /dev/null
+++ b/test/svg/doc.A.g.svg
@@ -0,0 +1,14 @@
+
diff --git a/test/svg/fill.0.name.svg b/test/svg/fill.0.name.svg
new file mode 100644
index 000000000..e377b8827
--- /dev/null
+++ b/test/svg/fill.0.name.svg
@@ -0,0 +1,4 @@
+
diff --git a/test/svg/fill.1.hex6.svg b/test/svg/fill.1.hex6.svg
new file mode 100644
index 000000000..04759d78a
--- /dev/null
+++ b/test/svg/fill.1.hex6.svg
@@ -0,0 +1,4 @@
+
diff --git a/test/svg/fill.2.hex3.svg b/test/svg/fill.2.hex3.svg
new file mode 100644
index 000000000..9f9bce580
--- /dev/null
+++ b/test/svg/fill.2.hex3.svg
@@ -0,0 +1,4 @@
+
diff --git a/test/svg/fill.3.rgb.svg b/test/svg/fill.3.rgb.svg
new file mode 100644
index 000000000..c18b03bb5
--- /dev/null
+++ b/test/svg/fill.3.rgb.svg
@@ -0,0 +1,4 @@
+
diff --git a/test/svg/fill.4.current-color.svg b/test/svg/fill.4.current-color.svg
new file mode 100644
index 000000000..cf77d65a6
--- /dev/null
+++ b/test/svg/fill.4.current-color.svg
@@ -0,0 +1,4 @@
+
diff --git a/test/svg/fill.5.palette.svg b/test/svg/fill.5.palette.svg
new file mode 100644
index 000000000..53ea97512
--- /dev/null
+++ b/test/svg/fill.5.palette.svg
@@ -0,0 +1,4 @@
+
diff --git a/test/svg/fill.6.opacity.svg b/test/svg/fill.6.opacity.svg
new file mode 100644
index 000000000..59b4eb41f
--- /dev/null
+++ b/test/svg/fill.6.opacity.svg
@@ -0,0 +1,4 @@
+
diff --git a/test/svg/fill.7.color.svg b/test/svg/fill.7.color.svg
new file mode 100644
index 000000000..745b2e881
--- /dev/null
+++ b/test/svg/fill.7.color.svg
@@ -0,0 +1,5 @@
+
diff --git a/test/svg/fill.8.rule.svg b/test/svg/fill.8.rule.svg
new file mode 100644
index 000000000..366ff6760
--- /dev/null
+++ b/test/svg/fill.8.rule.svg
@@ -0,0 +1,8 @@
+
diff --git a/test/svg/gradient.0.lin-pad.svg b/test/svg/gradient.0.lin-pad.svg
new file mode 100644
index 000000000..0ec54092f
--- /dev/null
+++ b/test/svg/gradient.0.lin-pad.svg
@@ -0,0 +1,10 @@
+
+
diff --git a/test/svg/gradient.1.lin-reflect.svg b/test/svg/gradient.1.lin-reflect.svg
new file mode 100644
index 000000000..9e3e50cb9
--- /dev/null
+++ b/test/svg/gradient.1.lin-reflect.svg
@@ -0,0 +1,11 @@
+
+
diff --git a/test/svg/gradient.2.lin-repeat.svg b/test/svg/gradient.2.lin-repeat.svg
new file mode 100644
index 000000000..1f023f5e1
--- /dev/null
+++ b/test/svg/gradient.2.lin-repeat.svg
@@ -0,0 +1,11 @@
+
+
diff --git a/test/svg/gradient.3.lin-user.svg b/test/svg/gradient.3.lin-user.svg
new file mode 100644
index 000000000..fc90328f0
--- /dev/null
+++ b/test/svg/gradient.3.lin-user.svg
@@ -0,0 +1,11 @@
+
+
diff --git a/test/svg/gradient.4.lin-transform.svg b/test/svg/gradient.4.lin-transform.svg
new file mode 100644
index 000000000..bc8f5b622
--- /dev/null
+++ b/test/svg/gradient.4.lin-transform.svg
@@ -0,0 +1,10 @@
+
+
diff --git a/test/svg/gradient.5.rad-pad.svg b/test/svg/gradient.5.rad-pad.svg
new file mode 100644
index 000000000..b631ddc73
--- /dev/null
+++ b/test/svg/gradient.5.rad-pad.svg
@@ -0,0 +1,10 @@
+
diff --git a/test/svg/gradient.6.rad-reflect.svg b/test/svg/gradient.6.rad-reflect.svg
new file mode 100644
index 000000000..b6fea76be
--- /dev/null
+++ b/test/svg/gradient.6.rad-reflect.svg
@@ -0,0 +1,11 @@
+
diff --git a/test/svg/gradient.7.rad-repeat.svg b/test/svg/gradient.7.rad-repeat.svg
new file mode 100644
index 000000000..63d138d2a
--- /dev/null
+++ b/test/svg/gradient.7.rad-repeat.svg
@@ -0,0 +1,11 @@
+
diff --git a/test/svg/gradient.8.rad-user.svg b/test/svg/gradient.8.rad-user.svg
new file mode 100644
index 000000000..e1d9c61f0
--- /dev/null
+++ b/test/svg/gradient.8.rad-user.svg
@@ -0,0 +1,11 @@
+
diff --git a/test/svg/gradient.9.rad-transform.svg b/test/svg/gradient.9.rad-transform.svg
new file mode 100644
index 000000000..4b90aaaf6
--- /dev/null
+++ b/test/svg/gradient.9.rad-transform.svg
@@ -0,0 +1,11 @@
+
diff --git a/test/svg/meson.build b/test/svg/meson.build
new file mode 100644
index 000000000..b2b017d79
--- /dev/null
+++ b/test/svg/meson.build
@@ -0,0 +1,5 @@
+if librsvg_dep.found()
+ executable('svg-render',
+ 'svg-render.c',
+ dependencies: [libcairo_dep, librsvg_dep])
+endif
diff --git a/test/svg/path.0.line.svg b/test/svg/path.0.line.svg
new file mode 100644
index 000000000..19d50914a
--- /dev/null
+++ b/test/svg/path.0.line.svg
@@ -0,0 +1,8 @@
+
diff --git a/test/svg/path.1.curve.svg b/test/svg/path.1.curve.svg
new file mode 100644
index 000000000..49c252ac8
--- /dev/null
+++ b/test/svg/path.1.curve.svg
@@ -0,0 +1,9 @@
+
diff --git a/test/svg/path.2.quad.svg b/test/svg/path.2.quad.svg
new file mode 100644
index 000000000..00a0dde57
--- /dev/null
+++ b/test/svg/path.2.quad.svg
@@ -0,0 +1,8 @@
+
diff --git a/test/svg/path.3.arc.svg b/test/svg/path.3.arc.svg
new file mode 100644
index 000000000..f177a72af
--- /dev/null
+++ b/test/svg/path.3.arc.svg
@@ -0,0 +1,7 @@
+
diff --git a/test/svg/shapes.0.rect.svg b/test/svg/shapes.0.rect.svg
new file mode 100644
index 000000000..17db34649
--- /dev/null
+++ b/test/svg/shapes.0.rect.svg
@@ -0,0 +1,3 @@
+
diff --git a/test/svg/shapes.1.rounded-rect.svg b/test/svg/shapes.1.rounded-rect.svg
new file mode 100644
index 000000000..717470bee
--- /dev/null
+++ b/test/svg/shapes.1.rounded-rect.svg
@@ -0,0 +1,3 @@
+
diff --git a/test/svg/shapes.2.circle.svg b/test/svg/shapes.2.circle.svg
new file mode 100644
index 000000000..3c07bad83
--- /dev/null
+++ b/test/svg/shapes.2.circle.svg
@@ -0,0 +1,3 @@
+
diff --git a/test/svg/shapes.3.ellipse.svg b/test/svg/shapes.3.ellipse.svg
new file mode 100644
index 000000000..67260a404
--- /dev/null
+++ b/test/svg/shapes.3.ellipse.svg
@@ -0,0 +1,3 @@
+
diff --git a/test/svg/shapes.4.line.svg b/test/svg/shapes.4.line.svg
new file mode 100644
index 000000000..58de42947
--- /dev/null
+++ b/test/svg/shapes.4.line.svg
@@ -0,0 +1,3 @@
+
diff --git a/test/svg/shapes.5.polyline.svg b/test/svg/shapes.5.polyline.svg
new file mode 100644
index 000000000..0cc5c383c
--- /dev/null
+++ b/test/svg/shapes.5.polyline.svg
@@ -0,0 +1,12 @@
+
diff --git a/test/svg/shapes.6.polygon.svg b/test/svg/shapes.6.polygon.svg
new file mode 100644
index 000000000..56bda0705
--- /dev/null
+++ b/test/svg/shapes.6.polygon.svg
@@ -0,0 +1,12 @@
+
diff --git a/test/svg/stroke.0.name.svg b/test/svg/stroke.0.name.svg
new file mode 100644
index 000000000..f2a926475
--- /dev/null
+++ b/test/svg/stroke.0.name.svg
@@ -0,0 +1,6 @@
+
diff --git a/test/svg/stroke.1.hex6.svg b/test/svg/stroke.1.hex6.svg
new file mode 100644
index 000000000..89f2b1b38
--- /dev/null
+++ b/test/svg/stroke.1.hex6.svg
@@ -0,0 +1,6 @@
+
diff --git a/test/svg/stroke.2.hex3.svg b/test/svg/stroke.2.hex3.svg
new file mode 100644
index 000000000..a8565a7b6
--- /dev/null
+++ b/test/svg/stroke.2.hex3.svg
@@ -0,0 +1,6 @@
+
diff --git a/test/svg/stroke.3.rgb.svg b/test/svg/stroke.3.rgb.svg
new file mode 100644
index 000000000..42e7514e4
--- /dev/null
+++ b/test/svg/stroke.3.rgb.svg
@@ -0,0 +1,6 @@
+
diff --git a/test/svg/stroke.4.current-color.svg b/test/svg/stroke.4.current-color.svg
new file mode 100644
index 000000000..9d645b881
--- /dev/null
+++ b/test/svg/stroke.4.current-color.svg
@@ -0,0 +1,6 @@
+
diff --git a/test/svg/stroke.5.palette.svg b/test/svg/stroke.5.palette.svg
new file mode 100644
index 000000000..1262a7ba0
--- /dev/null
+++ b/test/svg/stroke.5.palette.svg
@@ -0,0 +1,6 @@
+
diff --git a/test/svg/stroke.6.opacity.svg b/test/svg/stroke.6.opacity.svg
new file mode 100644
index 000000000..b84d1bdc9
--- /dev/null
+++ b/test/svg/stroke.6.opacity.svg
@@ -0,0 +1,6 @@
+
diff --git a/test/svg/stroke.7.color.svg b/test/svg/stroke.7.color.svg
new file mode 100644
index 000000000..952f48261
--- /dev/null
+++ b/test/svg/stroke.7.color.svg
@@ -0,0 +1,7 @@
+
diff --git a/test/svg/stroke.8.width.svg b/test/svg/stroke.8.width.svg
new file mode 100644
index 000000000..bb9edea90
--- /dev/null
+++ b/test/svg/stroke.8.width.svg
@@ -0,0 +1,14 @@
+
diff --git a/test/svg/stroke.9.cap.svg b/test/svg/stroke.9.cap.svg
new file mode 100644
index 000000000..35046446c
--- /dev/null
+++ b/test/svg/stroke.9.cap.svg
@@ -0,0 +1,17 @@
+
diff --git a/test/svg/stroke.A.dash.svg b/test/svg/stroke.A.dash.svg
new file mode 100644
index 000000000..2be5a1d90
--- /dev/null
+++ b/test/svg/stroke.A.dash.svg
@@ -0,0 +1,27 @@
+
diff --git a/test/svg/stroke.B.dash-offset.svg b/test/svg/stroke.B.dash-offset.svg
new file mode 100644
index 000000000..f7623ea84
--- /dev/null
+++ b/test/svg/stroke.B.dash-offset.svg
@@ -0,0 +1,31 @@
+
diff --git a/test/svg/stroke.C.miter.svg b/test/svg/stroke.C.miter.svg
new file mode 100644
index 000000000..1dc4ee6a7
--- /dev/null
+++ b/test/svg/stroke.C.miter.svg
@@ -0,0 +1,10 @@
+
diff --git a/test/svg/stroke.D.round.svg b/test/svg/stroke.D.round.svg
new file mode 100644
index 000000000..3e4c6236f
--- /dev/null
+++ b/test/svg/stroke.D.round.svg
@@ -0,0 +1,10 @@
+
diff --git a/test/svg/stroke.E.bevel.svg b/test/svg/stroke.E.bevel.svg
new file mode 100644
index 000000000..25d9e3803
--- /dev/null
+++ b/test/svg/stroke.E.bevel.svg
@@ -0,0 +1,10 @@
+
diff --git a/test/svg/stroke.F.miter-limit.svg b/test/svg/stroke.F.miter-limit.svg
new file mode 100644
index 000000000..14357f0b4
--- /dev/null
+++ b/test/svg/stroke.F.miter-limit.svg
@@ -0,0 +1,11 @@
+
diff --git a/test/svg/svg-font-template.ttx b/test/svg/svg-font-template.ttx
new file mode 100644
index 000000000..715074dda
--- /dev/null
+++ b/test/svg/svg-font-template.ttx
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cairo Font Template
+
+
+ Regular
+
+
+ Cairo Font Template Regular
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
diff --git a/test/svg/svg-render.c b/test/svg/svg-render.c
new file mode 100644
index 000000000..8f67ebdc2
--- /dev/null
+++ b/test/svg/svg-render.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright © 2016 Adrian Johnson
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Adrian Johnson
+ */
+
+/* Compilation:
+ * Build cairo with -DDEBUG_SVG_RENDER
+ * gcc -o svg-render svg-render.c `pkg-config --cflags --libs cairo librsvg`
+ */
+
+/* svg-render - render SVG files using both the cairo glyph renderer and librsvg.
+ *
+ * This allows testing the cairo SVG test cases before assembling them into an SVG font.
+ * Usage:
+ * svg-render [-b] [-s] [-g ] [-e ] input.svg
+ *
+ * Output is written to input.cairo.png and input.rsvg.png.
+ *
+ * -b print bounding box.
+ * -s Use standard SVG viewport. See below.
+ * -g render glyph with id
+ * -e set the EM size. The default is 1000.
+ *
+ * SVG Glyphs are assumed to be wholely within the view port.
+ */
+
+#include
+#include
+#include
+#include
+
+typedef enum { CAIRO_SVG, LIBRSVG } svg_renderer_t;
+
+/* output image size */
+#define WIDTH 1000
+#define HEIGHT 1000
+
+static cairo_bool_t bbox = FALSE;
+static cairo_bool_t standard_svg = FALSE;
+static const char *glyph_id = NULL;
+static int em_size = 1000;
+
+cairo_bool_t
+_cairo_debug_svg_render (cairo_t *cr,
+ const char *svg_document,
+ const char *element,
+ double units_per_em,
+ int debug_level);
+
+static void
+cairo_render (const char *svg_document, cairo_t *cr)
+{
+ if (!_cairo_debug_svg_render (cr, svg_document, glyph_id, em_size, 2))
+ printf("_cairo_debug_svg_render() failed\n");
+}
+
+static void
+librsvg_render (const char *svg_document, cairo_t *cr)
+{
+ gboolean has_width;
+ gboolean has_height;
+ gboolean has_viewbox;
+ RsvgLength svg_width;
+ RsvgLength svg_height;
+ RsvgRectangle svg_viewbox;
+ RsvgRectangle viewport;
+ double width, height;
+ GError *error = NULL;
+
+ RsvgHandle *handle = rsvg_handle_new_from_data ((guint8 *)svg_document,
+ strlen(svg_document),
+ &error);
+ if (!handle) {
+ printf ("Could not load: %s", error->message);
+ return;
+ }
+
+ /* Default width if not specified is EM Square */
+ width = em_size;
+ height = em_size;
+
+ /* Get width/height if specified. */
+ rsvg_handle_get_intrinsic_dimensions(handle,
+ &has_width,
+ &svg_width,
+ &has_height,
+ &svg_height,
+ &has_viewbox,
+ &svg_viewbox);
+ if (has_width)
+ width = svg_width.length;
+
+ if (has_height)
+ height = svg_height.length;
+
+ /* We set the viewport for the call rsvg_handle_render_layer() to
+ * width/height. That way if either dimension is not specified in
+ * the SVG it will be inherited from the viewport we provide.
+ *
+ * As this scales up the rendered dimensions by width/height we
+ * need to undo this scaling to get a unit square scale that
+ * matches the cairo SVG renderer scale. The OpenType SVG spec
+ * does not say what to do if width != height. In this case we
+ * will just use a uniform scale that ensures the viewport fits in
+ * the unit square and also center it.
+ */
+
+ if (width > height) {
+ cairo_scale (cr, 1.0/width, 1.0/width);
+ cairo_translate (cr, 0, (width - height)/2.0);
+ } else {
+ cairo_scale (cr, 1.0/height, 1.0/height);
+ cairo_translate (cr, (height - width)/2.0, 0);
+ }
+
+ viewport.x = 0;
+ viewport.y = 0;
+ viewport.width = width;
+ viewport.height = height;
+ if (!rsvg_handle_render_layer (handle, cr, glyph_id, &viewport, &error)) {
+ printf ("librsvg render failed: %s", error->message);
+ return;
+ }
+}
+
+static void
+render_svg (const char *svg_document, svg_renderer_t renderer, const char* out_file)
+{
+ double x, y, w, h;
+
+ cairo_surface_t *recording = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
+ cairo_t *cr = cairo_create (recording);
+
+ /* Scale up to image size when recording to reduce rounding errors
+ * in cairo_recording_surface_ink_extents()
+ */
+ cairo_scale (cr, WIDTH, HEIGHT);
+
+ if (renderer == CAIRO_SVG) {
+ cairo_render (svg_document, cr);
+ } else {
+ librsvg_render (svg_document, cr);
+ }
+ cairo_destroy (cr);
+
+ if (bbox) {
+ cairo_recording_surface_ink_extents (recording, &x, &y, &w, &h);
+ if (renderer == CAIRO_SVG)
+ printf("cairo ");
+ else
+ printf("librsvg");
+
+ printf(" bbox left: %d right: %d top: %d bottom: %d\n",
+ (int)floor(x),
+ (int)ceil(x + w),
+ (int)floor(y),
+ (int)ceil(y + h));
+ }
+
+ cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
+ cr = cairo_create (surface);
+
+ /* If rendering a glyph need to translate base line to bottom of image */
+ if (standard_svg)
+ cairo_set_source_surface (cr, recording, 0, 0);
+ else
+ cairo_set_source_surface (cr, recording, 0, HEIGHT);
+
+ cairo_paint (cr);
+
+ cairo_surface_write_to_png (surface, out_file);
+ cairo_surface_destroy (surface);
+}
+
+static char *
+create_output_name (const char *svg_file, svg_renderer_t renderer)
+{
+ char buf[1000];
+ int len;
+
+ strcpy (buf, svg_file);
+ len = strlen (buf);
+
+ if (strlen (buf) > 5 && strcmp (buf + len - 4, ".svg") == 0)
+ buf[len - 4] = 0;
+
+ if (renderer == CAIRO_SVG)
+ strcat (buf, ".cairo.png");
+ else
+ strcat (buf, ".rsvg.png");
+
+ return strdup (buf);
+}
+
+static char *
+read_file(const char *filename)
+{
+ FILE *fp;
+ int len;
+ char *data;
+
+ fp = fopen (filename, "r");
+ if (fp == NULL)
+ return NULL;
+
+ fseek (fp, 0, SEEK_END);
+ len = ftell(fp);
+ rewind (fp);
+ data = malloc (len + 1);
+ if (fread(data, len, 1, fp) != 1)
+ return NULL;
+ data[len] = 0;
+ fclose(fp);
+ return data;
+}
+
+static void
+usage_and_exit()
+{
+ printf ("svg-render [-b] [-s] [-g ] [-e ] input.svg\n");
+ exit (1);
+}
+
+int
+main(int argc, char **argv)
+{
+ const char *input_file = NULL;
+ char *svg_document;
+ char *output_file;
+
+ argc--;
+ argv++;
+ while (argc > 0) {
+ if (strcmp (argv[0], "-b") == 0) {
+ bbox = TRUE;
+ argc--;
+ argv++;
+ } else if (strcmp (argv[0], "-s") == 0) {
+ standard_svg = TRUE;
+ argc--;
+ argv++;
+ } else if (strcmp (argv[0], "-g") == 0) {
+ if (argc > 1) {
+ glyph_id = argv[1];
+ argc -= 2;
+ argv += 2;
+ } else {
+ usage_and_exit();
+ }
+ } else if (strcmp (argv[0], "-e") == 0) {
+ if (argc > 1) {
+ em_size = atoi (argv[1]);
+ if (em_size <= 0) {
+ usage_and_exit();
+ }
+ argc -= 2;
+ argv += 2;
+ } else {
+ usage_and_exit();
+ }
+ } else {
+ input_file = argv[0];
+ argc--;
+ argv++;
+ }
+ }
+ if (!input_file)
+ usage_and_exit();
+
+ svg_document = read_file (input_file);
+ if (!svg_document) {
+ printf("error reading file %s\n", input_file);
+ exit (1);
+ }
+
+ output_file = create_output_name (input_file, CAIRO_SVG);
+ render_svg (svg_document, CAIRO_SVG, output_file);
+ free (output_file);
+
+ output_file = create_output_name (input_file, LIBRSVG);
+ render_svg (svg_document, LIBRSVG, output_file);
+ free (output_file);
+
+ free (svg_document);
+
+ return 0;
+}
diff --git a/test/svg/transform.0.translate.svg b/test/svg/transform.0.translate.svg
new file mode 100644
index 000000000..5d9555673
--- /dev/null
+++ b/test/svg/transform.0.translate.svg
@@ -0,0 +1,8 @@
+
diff --git a/test/svg/transform.1.scale.svg b/test/svg/transform.1.scale.svg
new file mode 100644
index 000000000..b7742fc80
--- /dev/null
+++ b/test/svg/transform.1.scale.svg
@@ -0,0 +1,10 @@
+
diff --git a/test/svg/transform.2.rotate.svg b/test/svg/transform.2.rotate.svg
new file mode 100644
index 000000000..926ae63fc
--- /dev/null
+++ b/test/svg/transform.2.rotate.svg
@@ -0,0 +1,10 @@
+
diff --git a/test/svg/transform.3.skewX.svg b/test/svg/transform.3.skewX.svg
new file mode 100644
index 000000000..f7555534d
--- /dev/null
+++ b/test/svg/transform.3.skewX.svg
@@ -0,0 +1,10 @@
+
diff --git a/test/svg/transform.4.skewY.svg b/test/svg/transform.4.skewY.svg
new file mode 100644
index 000000000..cd62c8a8a
--- /dev/null
+++ b/test/svg/transform.4.skewY.svg
@@ -0,0 +1,10 @@
+
diff --git a/test/svg/transform.5.matrix.svg b/test/svg/transform.5.matrix.svg
new file mode 100644
index 000000000..643fbe36b
--- /dev/null
+++ b/test/svg/transform.5.matrix.svg
@@ -0,0 +1,10 @@
+
diff --git a/test/svg/transform.6.multiple.svg b/test/svg/transform.6.multiple.svg
new file mode 100644
index 000000000..90c7b3054
--- /dev/null
+++ b/test/svg/transform.6.multiple.svg
@@ -0,0 +1,16 @@
+
diff --git a/test/svg/transform.7.stroke.svg b/test/svg/transform.7.stroke.svg
new file mode 100644
index 000000000..f56b24dfe
--- /dev/null
+++ b/test/svg/transform.7.stroke.svg
@@ -0,0 +1,20 @@
+