[cairo-commit] 2 commits - build/configure.ac.features doc/tutorial src/cairo-font-face.c src/cairo-font-face-twin.c src/cairo-font-face-twin-data.c src/cairoint.h src/cairo-user-font.c src/Makefile.sources

Behdad Esfahbod behdad at kemper.freedesktop.org
Thu Sep 25 17:05:39 PDT 2008


 build/configure.ac.features     |   26 -
 doc/tutorial/src/twin.c         |   39 +
 src/Makefile.sources            |    2 
 src/cairo-font-face-twin-data.c | 1030 ++++++++++++++++++++++++++++++++++++++++
 src/cairo-font-face-twin.c      |  209 ++++++++
 src/cairo-font-face.c           |   33 +
 src/cairo-user-font.c           |   53 +-
 src/cairoint.h                  |   18 
 8 files changed, 1381 insertions(+), 29 deletions(-)

New commits:
commit f8542dc9dd4dd0685f68381f21fa72dbddd8d682
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Sep 25 19:08:24 2008 -0400

    [twin-font] Clean up font data by joining lines and closing paths
    
    Two changes here:
    
      * Replace move_to;line_to;move_to;line_to sequences with
        move_to;line_to;line_to when feasible.
    
      * Close paths for round glyphs.
    
    Both improve the stroke rendering of the joint.
    
    The first change also saves 3 bytes per joint (33 such joints).
    Which we have just left unused for now.  To reclaim them one need
    to update the charset table.  Something for a lazy Sunday afternoon
    scripting task.
    
    In the saving department, we can save further by:
    
      - Getting rid of the left/ascent/descent values as we compute
        glyph bounding box automatically.  Then we can liberally use
        the right value to adjust glyph advance width.  Saves three
        bytes per glyph (there's 96 glyphs in the font).
    
      - First operation is always a move_to.  So we can remove the 'm'
        for that.  Ugly though.
    
    And the charset has zeros for the first 32 entries.  Can get rid of
    that too at the expense of handling it in the code...
    
    In total, combining the above we can save some 500 bytes.  The font
    currently takes about 3.7kb.

diff --git a/src/cairo-font-face-twin-data.c b/src/cairo-font-face-twin-data.c
index fdd697a..7a70324 100644
--- a/src/cairo-font-face-twin-data.c
+++ b/src/cairo-font-face-twin-data.c
@@ -72,8 +72,6 @@ const int8_t _cairo_twin_outlines[] = {
     0, 36, 42, 0, 4, 7,
     0, 14, 22, 36, /* snap_x */
     -42, -38, -28, -21, -15, -14, 0, /* snap_y */
-    'm', 36, -42,
-    'l', 0, 0,
     'm', 10, -42,
     'c', 12, -41, 14, -40, 14, -36,
     'c', 14, -30, 11, -28, 6, -28,
@@ -81,6 +79,7 @@ const int8_t _cairo_twin_outlines[] = {
     'c', 0, -39, 3, -42, 8, -42,
     'l', 10, -42,
     'c', 18, -37, 28, -37, 36, -42,
+    'l', 0, 0,
     'm', 28, -14,
     'c', 24, -14, 22, -11, 22, -6,
     'c', 22, -2, 24, 0, 28, 0,
@@ -88,6 +87,7 @@ const int8_t _cairo_twin_outlines[] = {
     'c', 36, -12, 34, -14, 30, -14,
     'l', 28, -14,
     'e',
+    'X', 'X', 'X',
 /* 0x26 '&'  offset 323 */
     0, 40, 42, 0, 4, 4,
     0, 10, 22, 40, /* snap_x */
@@ -183,7 +183,7 @@ const int8_t _cairo_twin_outlines[] = {
     'c', 0, 0, 9, 0, 14, 0,
     'c', 19, 0, 28, 0, 28, -21,
     'c', 28, -42, 19, -42, 14, -42,
-    'e',
+    'E',
 /* 0x31 '1'  offset 666 */
     0, 28, 42, 0, 2, 3,
     0, 17, 28 /* snap_x */
@@ -218,12 +218,12 @@ const int8_t _cairo_twin_outlines[] = {
     0, 28, 42, 0, 3, 4,
     0, 20, 30, /* snap_x */
     -21, -15, -14, 0, /* snap_y */
-    'm', 20, -42,
+    'm', 20, 0,
+    'l', 20, -42,
     'l', 0, -14,
     'l', 30, -14,
-    'm', 20, -42,
-    'l', 20, 0,
     'e',
+    'X', 'X', 'X',
 /* 0x35 '5'  offset 809 */
     0, 28, 42, 0, 2, 5,
     0, 28, /* snap_x */
@@ -252,11 +252,11 @@ const int8_t _cairo_twin_outlines[] = {
     0, 28, 42, 0, 2, 4,
     0, 28, /* snap_x */
     -42, -21, -15, 0, /* snap_y */
-    'm', 28, -42,
-    'l', 8, 0,
     'm', 0, -42,
     'l', 28, -42,
+    'l', 8, 0,
     'e',
+    'X', 'X', 'X',
 /* 0x38 '8'  offset 944 */
     0, 28, 42, 0, 4, 4,
     0, 2, 26, 28, /* snap_x */
@@ -268,7 +268,7 @@ const int8_t _cairo_twin_outlines[] = {
     'c', 10, 0, 0, 0, 0, -11,
     'c', 0, -32, 26, -18, 26, -34,
     'c', 26, -40, 23, -42, 14, -42,
-    'e',
+    'E',
 /* 0x39 '9'  offset 1004 */
     0, 28, 42, 0, 2, 5,
     0, 26, /* snap_x */
@@ -362,27 +362,27 @@ const int8_t _cairo_twin_outlines[] = {
     0, 32, 42, 0, 2, 4,
     0, 32, /* snap_x */
     -21, -15, -14, 0, /* snap_y */
-    'm', 16, -42,
-    'l', 0, 0,
-    'm', 16, -42,
+    'm', 0, 0,
+    'l', 16, -42,
     'l', 32, 0,
     'm', 6, -14,
     'l', 26, -14,
     'e',
+    'X', 'X', 'X',
 /* 0x42 'B'  offset 1406 */
     0, 28, 42, 0, 2, 5,
     0, 28, /* snap_x */
     -42, -22, -21, -15, 0, /* snap_y */
-    'm', 0, -42,
-    'l', 0, 0,
-    'm', 0, -42,
+    'm', 0, 0,
+    'l', 0, -42,
     'l', 18, -42,
     'c', 32, -42, 32, -22, 18, -22,
-    'm', 0, -22,
+    'l', 0, -22,
     'l', 18, -22,
     'c', 32, -22, 32, 0, 18, 0,
-    'l', 0, 0,
-    'e',
+    'E',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
 /* 0x43 'C'  offset 1455 */
     0, 30, 42, 0, 2, 4,
     0, 30, /* snap_x */
@@ -397,37 +397,37 @@ const int8_t _cairo_twin_outlines[] = {
     0, 28, 42, 0, 2, 4,
     0, 28, /* snap_x */
     -42, -21, -15, 0, /* snap_y */
-    'm', 0, -42,
-    'l', 0, 0,
-    'm', 0, -42,
+    'm', 0, 0,
+    'l', 0, -42,
     'l', 14, -42,
     'c', 33, -42, 33, 0, 14, 0,
-    'l', 0, 0,
-    'e',
+    'E',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
 /* 0x45 'E'  offset 1534 */
     0, 26, 42, 0, 2, 5,
     0, 26, /* snap_x */
     -42, -22, -21, -15, 0, /* snap_y */
-    'm', 0, -42,
+    'm', 26, -42,
+    'l', 0, -42,
     'l', 0, 0,
-    'm', 0, -42,
-    'l', 26, -42,
+    'l', 26, 0,
     'm', 0, -22,
     'l', 16, -22,
-    'm', 0, 0,
-    'l', 26, 0,
     'e',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
 /* 0x46 'F'  offset 1572 */
     0, 26, 42, 0, 2, 5,
     0, 26, /* snap_x */
     -42, -22, -21, -15, 0, /* snap_y */
-    'm', 0, -42,
-    'l', 0, 0,
-    'm', 0, -42,
+    'm', 0, 0,
+    'l', 0, -42,
     'l', 26, -42,
     'm', 0, -22,
     'l', 16, -22,
     'e',
+    'X', 'X', 'X',
 /* 0x47 'G'  offset 1604 */
     0, 30, 42, 0, 2, 5,
     0, 30, /* snap_x */
@@ -437,9 +437,9 @@ const int8_t _cairo_twin_outlines[] = {
     'c', 2, -42, 0, -29, 0, -21,
     'c', 0, -13, 2, 0, 16, 0,
     'c', 28, 0, 30, -7, 30, -16,
-    'm', 20, -16,
-    'l', 30, -16,
+    'l', 20, -16,
     'e',
+    'X', 'X', 'X',
 /* 0x48 'H'  offset 1655 */
     0, 28, 42, 0, 2, 4,
     0, 28, /* snap_x */
@@ -484,33 +484,33 @@ const int8_t _cairo_twin_outlines[] = {
     -21, -15, 0, /* snap_y */
     'm', 0, -42,
     'l', 0, 0,
-    'm', 0, 0,
     'l', 24, 0,
     'e',
+    'X', 'X', 'X',
 /* 0x4d 'M'  offset 1785 */
     0, 32, 42, 0, 2, 3,
     0, 32, /* snap_x */
     -21, -15, 0, /* snap_y */
-    'm', 0, -42,
-    'l', 0, 0,
-    'm', 0, -42,
-    'l', 16, 0,
-    'm', 32, -42,
+    'm', 0, 0,
+    'l', 0, -42,
     'l', 16, 0,
-    'm', 32, -42,
+    'l', 32, -42,
     'l', 32, 0,
     'e',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
 /* 0x4e 'N'  offset 1821 */
     0, 28, 42, 0, 2, 3,
     0, 28, /* snap_x */
     -21, -15, 0, /* snap_y */
-    'm', 0, -42,
-    'l', 0, 0,
-    'm', 0, -42,
-    'l', 28, 0,
-    'm', 28, -42,
+    'm', 0, 0,
+    'l', 0, -42,
     'l', 28, 0,
+    'l', 28, -42,
     'e',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
 /* 0x4f 'O'  offset 1851 */
     0, 32, 42, 0, 2, 4,
     0, 32, /* snap_x */
@@ -520,18 +520,18 @@ const int8_t _cairo_twin_outlines[] = {
     'c', 0, -13, 2, 0, 16, 0,
     'c', 30, 0, 32, -13, 32, -21,
     'c', 32, -29, 30, -42, 16, -42,
-    'e',
+    'E',
 /* 0x50 'P'  offset 1895 */
     0, 28, 42, 0, 2, 5,
     0, 28, /* snap_x */
     -42, -21, -20, -15, 0, /* snap_y */
-    'm', 0, -42,
-    'l', 0, 0,
-    'm', 0, -42,
+    'm', 0, 0,
+    'l', 0, -42,
     'l', 18, -42,
     'c', 32, -42, 32, -20, 18, -20,
     'l', 0, -20,
     'e',
+    'X', 'X', 'X',
 /* 0x51 'Q'  offset 1931 */
     0, 32, 42, 4, 2, 4,
     0, 32, /* snap_x */
@@ -548,15 +548,15 @@ const int8_t _cairo_twin_outlines[] = {
     0, 28, 42, 0, 2, 5,
     0, 28, /* snap_x */
     -42, -22, -21, -15, 0, /* snap_y */
-    'm', 0, -42,
-    'l', 0, 0,
-    'm', 0, -42,
+    'm', 0, 0,
+    'l', 0, -42,
     'l', 18, -42,
     'c', 32, -42, 31, -22, 18, -22,
     'l', 0, -22,
     'm', 14, -22,
     'l', 28, 0,
     'e',
+    'X', 'X', 'X',
 /* 0x53 'S'  offset 2023 */
     0, 28, 42, 0, 2, 4,
     0, 28, /* snap_x */
@@ -592,22 +592,22 @@ const int8_t _cairo_twin_outlines[] = {
     -21, -15, 0, /* snap_y */
     'm', 0, -42,
     'l', 16, 0,
-    'm', 32, -42,
-    'l', 16, 0,
+    'l', 32, -42,
     'e',
+    'X', 'X', 'X',
 /* 0x57 'W'  offset 2152 */
     0, 40, 42, 0, 2, 3,
     0, 40, /* snap_x */
     -21, -15, 0, /* snap_y */
     'm', 0, -42,
     'l', 10, 0,
-    'm', 20, -42,
-    'l', 10, 0,
-    'm', 20, -42,
-    'l', 30, 0,
-    'm', 40, -42,
+    'l', 20, -42,
     'l', 30, 0,
+    'l', 40, -42,
     'e',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
 /* 0x58 'X'  offset 2188 */
     0, 28, 42, 0, 2, 3,
     0, 28, /* snap_x */
@@ -631,13 +631,13 @@ const int8_t _cairo_twin_outlines[] = {
     0, 28, 42, 0, 2, 4,
     0, 28, /* snap_x */
     -42, -21, -15, 0, /* snap_y */
-    'm', 28, -42,
+    'm', 28, 0,
     'l', 0, 0,
-    'm', 0, -42,
     'l', 28, -42,
-    'm', 0, 0,
-    'l', 28, 0,
+    'l', 0, -42,
     'e',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
 /* 0x5b '['  offset 2271 */
     0, 14, 44, 0, 2, 4,
     0, 14, /* snap_x */
@@ -667,11 +667,11 @@ const int8_t _cairo_twin_outlines[] = {
     0, 32, 46, -18, 2, 3,
     0, 32, /* snap_x */
     -21, -15, 0, /* snap_y */
-    'm', 16, -46,
-    'l', 0, -18,
-    'm', 16, -46,
+    'm', 0, -18,
+    'l', 16, -46,
     'l', 32, -18,
     'e',
+    'X', 'X', 'X',
 /* 0x5f '_'  offset 2363 */
     0, 36, 0, 0, 2, 3,
     0, 36, /* snap_x */
@@ -921,22 +921,22 @@ const int8_t _cairo_twin_outlines[] = {
     -21, -15, 0, /* snap_y */
     'm', 0, -28,
     'l', 12, 0,
-    'm', 24, -28,
-    'l', 12, 0,
+    'l', 24, -28,
     'e',
+    'X', 'X', 'X',
 /* 0x77 'w'  offset 3307 */
     0, 32, 28, 0, 2, 3,
     0, 32, /* snap_x */
     -21, -15, 0, /* snap_y */
     'm', 0, -28,
     'l', 8, 0,
-    'm', 16, -28,
-    'l', 8, 0,
-    'm', 16, -28,
-    'l', 24, 0,
-    'm', 32, -28,
+    'l', 16, -28,
     'l', 24, 0,
+    'l', 32, -28,
     'e',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
 /* 0x78 'x'  offset 3343 */
     0, 22, 28, 0, 2, 3,
     0, 22, /* snap_x */
@@ -960,13 +960,13 @@ const int8_t _cairo_twin_outlines[] = {
     0, 22, 28, 0, 2, 4,
     0, 22, /* snap_x */
     -28, -21, -15, 0, /* snap_y */
-    'm', 22, -28,
+    'm', 22, 0,
     'l', 0, 0,
-    'm', 0, -28,
     'l', 22, -28,
-    'm', 0, 0,
-    'l', 22, 0,
+    'l', 0, -28,
     'e',
+    'X', 'X', 'X',
+    'X', 'X', 'X',
 /* 0x7b '{'  offset 3430 */
     0, 16, 44, 0, 3, 5,
     0, 6, 16, /* snap_x */
diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c
index 86e083d..75669a5 100644
--- a/src/cairo-font-face-twin.c
+++ b/src/cairo-font-face-twin.c
@@ -125,6 +125,9 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
 
     for (;;) {
 	switch (*g++) {
+	case 'M':
+	    cairo_close_path (cr);
+	    /* fall through */
 	case 'm':
 	    x1 = FX(*g++);
 	    y1 = FY(*g++);
@@ -135,6 +138,9 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
 	    }
 	    cairo_move_to (cr, x1, y1);
 	    continue;
+	case 'L':
+	    cairo_close_path (cr);
+	    /* fall through */
 	case 'l':
 	    x1 = FX(*g++);
 	    y1 = FY(*g++);
@@ -145,6 +151,9 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
 	    }
 	    cairo_line_to (cr, x1, y1);
 	    continue;
+	case 'C':
+	    cairo_close_path (cr);
+	    /* fall through */
 	case 'c':
 	    x1 = FX(*g++);
 	    y1 = FY(*g++);
@@ -163,18 +172,19 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
 	    }
 	    cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
 	    continue;
-	case 'o':
+	case 'E':
 	    cairo_close_path (cr);
-	    break;
+	    /* fall through */
 	case 'e':
 	    cairo_stroke (cr);
 	    break;
+	case 'X':
+	    /* filler */
+	    continue;
 	}
 	break;
     }
 
-    cairo_stroke (cr);
-
     metrics->x_advance = FX(twin_glyph_right(b)) + cairo_get_line_width (cr);
     metrics->x_advance +=  cairo_get_line_width (cr)/* XXX 2*x.margin */;
     if (info.snap)
commit d5a998387bcee6569d33375d592190f480f12712
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Sep 25 04:27:11 2008 -0400

    Add an internal font face
    
    The font data and rendering is adapted from Keith Packard's Twin
    window system.  The hinting stuff is not ported yet, but hey, it renders!
    
    The implementation uses user fonts, and the user font backend is modified
    to use this font face (which we call "twin" font face internally) when
    a toy font is needed.
    
    The font face layer is then modified to use this font if:
    
      - The toy font face "cairo" is asked for, or
    
      - No native font backend is available, or
    
      - The preferred native font backend fails to return a font with
        STATUS_UNSUPPORTED.  No font backend does this right now but
        the idea is to change FreeType to return it if no fonts found
        on the system.
    
    We also allow building with no font backends now!
    
    The new doc/tutorial/src/twin.c file tests the twin face at various
    sizes.

diff --git a/build/configure.ac.features b/build/configure.ac.features
index 5d5a388..d1be92a 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -322,29 +322,29 @@ CAIRO_FEATURE_HOOK_REGISTER(no,yes,*,
 ])dnl
 
 
-dnl Collect enabled native surface backend features
+dnl Collect enabled native surface/font backend features
 CAIRO_ACCUMULATORS_REGISTER([NATIVE_SURFACE_BACKENDS])dnl
+CAIRO_ACCUMULATORS_REGISTER([NATIVE_FONT_BACKENDS])dnl
 CAIRO_FEATURE_HOOK_REGISTER(yes,auto,surface,
 [dnl
 	CAIRO_ACCUMULATE([NATIVE_SURFACE_BACKENDS], [$1])
 ])dnl
+CAIRO_FEATURE_HOOK_REGISTER(yes,auto,font,
+[dnl
+	CAIRO_ACCUMULATE([NATIVE_FONT_BACKENDS], [$1])
+])dnl
 
-dnl Collect warning message if no native surface backend feature enabled
+dnl Collect warning message if no native surface/font backend feature enabled
 AC_CONFIG_COMMANDS_PRE(dnl
 [dnl
 	AS_IF([test -z "$CAIRO_NATIVE_SURFACE_BACKENDS"],dnl
 	[dnl
 		CAIRO_ACCUMULATE([WARNING_MESSAGE], CAIRO_TEXT_WRAP([It is strictly recommended that you enable the native surface backend feature for your platform.], [*** ]))
 	])
-])dnl
-
-
-
-dnl Collect enabled native font backend features
-CAIRO_ACCUMULATORS_REGISTER([NATIVE_FONT_BACKENDS])dnl
-CAIRO_FEATURE_HOOK_REGISTER(yes,auto,font,
-[dnl
-	CAIRO_ACCUMULATE([NATIVE_FONT_BACKENDS], [$1])
+	AS_IF([test -z "$CAIRO_NATIVE_FONT_BACKENDS"],dnl
+	[dnl
+		CAIRO_ACCUMULATE([WARNING_MESSAGE], CAIRO_TEXT_WRAP([It is strictly recommended that you enable the native font backend feature for your platform.], [*** ]))
+	])
 ])dnl
 
 
@@ -394,9 +394,5 @@ AC_DEFUN([CAIRO_REPORT],
 	fi
 	echo "$CAIRO_WARNING_MESSAGE"
 	echo ""
-	AS_IF([test -z "$CAIRO_NATIVE_FONT_BACKENDS"],dnl
-	[dnl
-		AC_MSG_ERROR([Cairo requires at least one native font backend.  Please install FreeType and fontconfig and try again.])
-	])
 ])dnl
 
diff --git a/doc/tutorial/src/twin.c b/doc/tutorial/src/twin.c
new file mode 100644
index 0000000..fe0e90e
--- /dev/null
+++ b/doc/tutorial/src/twin.c
@@ -0,0 +1,39 @@
+/**
+ * Put this file in cairo/doc/tutorial/src and type "make"
+ */
+
+#define WIDTH 1350
+#define HEIGHT 900
+
+#include "cairo-tutorial.h"
+
+
+static void
+draw (cairo_t *cr, int width, int height)
+{
+    int i, j, h;
+    unsigned char s[2] = {0, 0};
+
+    /* clear background */
+    cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+    cairo_paint (cr);
+
+    cairo_set_source_rgb (cr, 0, 0, 0);
+    cairo_select_font_face (cr,
+			    "cairo",
+			    CAIRO_FONT_SLANT_NORMAL,
+			    CAIRO_FONT_WEIGHT_NORMAL);
+
+    h = 2;
+    for (i = 8; i < 48; i >= 24 ? i+=3 : i++) {
+	cairo_set_font_size (cr, i);
+	for (j = 33; j < 128; j++) {
+	    if (j == 33 || (j == 80 && i > 24)) {
+		h += i + 2;
+		cairo_move_to (cr, 10, h);
+	    }
+	    s[0] = j;
+	    cairo_show_text (cr, (const char *) s);
+	}
+    }
+}
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 2c3b468..e7ad395 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -100,6 +100,8 @@ cairo_sources = \
 	cairo-debug.c \
 	cairo-fixed.c \
 	cairo-font-face.c \
+	cairo-font-face-twin.c \
+	cairo-font-face-twin-data.c \
 	cairo-font-options.c \
 	cairo-freelist.c \
 	cairo-gstate.c \
diff --git a/src/cairo-font-face-twin-data.c b/src/cairo-font-face-twin-data.c
new file mode 100644
index 0000000..fdd697a
--- /dev/null
+++ b/src/cairo-font-face-twin-data.c
@@ -0,0 +1,1030 @@
+/* See cairo-font-face-twin.c for copyright info */
+
+#include "cairoint.h"
+
+const int8_t _cairo_twin_outlines[] = {
+/* 0x0 '\0'  offset 0 */
+    0, 24, 42, 0, 2, 4,
+    0, 24, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 0, 0,
+    'l', 0, -42,
+    'l', 24, -42,
+    'l', 24, 0,
+    'l', 0, 0,
+    'e',
+/* 0x20 ' '  offset 28 */
+    0, 4, 0, 0, 2, 3,
+    -128, 0, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'e',
+/* 0x21 '!'  offset 40 */
+    0, 4, 42, 0, 3, 3,
+    0, 2, 4, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 2, -42,
+    'l', 2, -14,
+    'm', 2, -4,
+    'c', 1, -4, 0, -3, 0, -2,
+    'c', 0, -1, 1, 0, 2, 0,
+    'c', 3, 0, 4, -1, 4, -2,
+    'c', 4, -3, 3, -4, 2, -4,
+    'e',
+/* 0x22 '"'  offset 90 */
+    0, 16, 42, -28, 2, 3,
+    0, 16, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, -28,
+    'm', 16, -42,
+    'l', 16, -28,
+    'e',
+/* 0x23 '#'  offset 114 */
+    0, 30, 50, 14, 2, 5,
+    0, 30, /* snap_x */
+    -24, -21, -15, -12, 0, /* snap_y */
+    'm', 16, -50,
+    'l', 2, 14,
+    'm', 28, -50,
+    'l', 14, 14,
+    'm', 2, -24,
+    'l', 30, -24,
+    'm', 0, -12,
+    'l', 28, -12,
+    'e',
+/* 0x24 '$'  offset 152 */
+    0, 28, 50, 8, 4, 4,
+    0, 10, 18, 28, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 10, -50,
+    'l', 10, 8,
+    'm', 18, -50,
+    'l', 18, 8,
+    'm', 28, -36,
+    'c', 24, -42, 18, -42, 14, -42,
+    'c', 10, -42, 0, -42, 0, -34,
+    'c', 0, -25, 8, -24, 14, -22,
+    'c', 20, -20, 28, -19, 28, -9,
+    'c', 28, 0, 18, 0, 14, 0,
+    'c', 10, 0, 4, 0, 0, -6,
+    'e',
+/* 0x25 '%'  offset 224 */
+    0, 36, 42, 0, 4, 7,
+    0, 14, 22, 36, /* snap_x */
+    -42, -38, -28, -21, -15, -14, 0, /* snap_y */
+    'm', 36, -42,
+    'l', 0, 0,
+    'm', 10, -42,
+    'c', 12, -41, 14, -40, 14, -36,
+    'c', 14, -30, 11, -28, 6, -28,
+    'c', 2, -28, 0, -30, 0, -34,
+    'c', 0, -39, 3, -42, 8, -42,
+    'l', 10, -42,
+    'c', 18, -37, 28, -37, 36, -42,
+    'm', 28, -14,
+    'c', 24, -14, 22, -11, 22, -6,
+    'c', 22, -2, 24, 0, 28, 0,
+    'c', 33, 0, 36, -2, 36, -8,
+    'c', 36, -12, 34, -14, 30, -14,
+    'l', 28, -14,
+    'e',
+/* 0x26 '&'  offset 323 */
+    0, 40, 42, 0, 4, 4,
+    0, 10, 22, 40, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 40, -24,
+    'c', 40, -27, 39, -28, 37, -28,
+    'c', 29, -28, 32, 0, 12, 0,
+    'c', 0, 0, 0, -8, 0, -10,
+    'c', 0, -24, 22, -20, 22, -34,
+    'c', 22, -45, 10, -45, 10, -34,
+    'c', 10, -27, 25, 0, 36, 0,
+    'c', 39, 0, 40, -1, 40, -4,
+    'e',
+/* 0x27 '''  offset 390 */
+    0, 4, 42, -30, 2, 3,
+    0, 4, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 2, -38,
+    'c', -1, -38, -1, -42, 2, -42,
+    'c', 6, -42, 5, -33, 0, -30,
+    'e',
+/* 0x28 '('  offset 419 */
+    0, 14, 50, 14, 2, 3,
+    0, 14, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 14, -50,
+    'c', -5, -32, -5, -5, 14, 14,
+    'e',
+/* 0x29 ')'  offset 441 */
+    0, 14, 50, 14, 2, 3,
+    0, 14, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -50,
+    'c', 19, -34, 19, -2, 0, 14,
+    'e',
+/* 0x2a '*'  offset 463 */
+    0, 20, 30, -6, 3, 3,
+    0, 10, 20, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 10, -30,
+    'l', 10, -6,
+    'm', 0, -24,
+    'l', 20, -12,
+    'm', 20, -24,
+    'l', 0, -12,
+    'e',
+/* 0x2b '+'  offset 494 */
+    0, 36, 36, 0, 3, 4,
+    0, 18, 36, /* snap_x */
+    -21, -18, -15, 0, /* snap_y */
+    'm', 18, -36,
+    'l', 18, 0,
+    'm', 0, -18,
+    'l', 36, -18,
+    'e',
+/* 0x2c ','  offset 520 */
+    0, 4, 4, 8, 2, 3,
+    0, 4, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 4, -2,
+    'c', 4, 1, 0, 1, 0, -2,
+    'c', 0, -5, 4, -5, 4, -2,
+    'c', 4, 4, 2, 6, 0, 8,
+    'e',
+/* 0x2d '-'  offset 556 */
+    0, 36, 18, -18, 2, 4,
+    0, 36, /* snap_x */
+    -21, -18, -15, 0, /* snap_y */
+    'm', 0, -18,
+    'l', 36, -18,
+    'e',
+/* 0x2e '.'  offset 575 */
+    0, 4, 4, 0, 2, 3,
+    0, 4, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 2, -4,
+    'c', -1, -4, -1, 0, 2, 0,
+    'c', 5, 0, 5, -4, 2, -4,
+    'e',
+/* 0x2f '/'  offset 604 */
+    0, 36, 50, 14, 2, 3,
+    0, 36, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 36, -50,
+    'l', 0, 14,
+    'e',
+/* 0x30 '0'  offset 622 */
+    0, 28, 42, 0, 2, 4,
+    0, 28, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 14, -42,
+    'c', 9, -42, 0, -42, 0, -21,
+    'c', 0, 0, 9, 0, 14, 0,
+    'c', 19, 0, 28, 0, 28, -21,
+    'c', 28, -42, 19, -42, 14, -42,
+    'e',
+/* 0x31 '1'  offset 666 */
+    0, 28, 42, 0, 2, 3,
+    0, 17, 28 /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 7, -34,
+    'c', 11, -35, 15, -38, 17, -42,
+    'l', 17, 0,
+    'e',
+/* 0x32 '2'  offset 691 */
+    0, 28, 42, 0, 4, 4,
+    0, 2, 26, 28, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 2, -32,
+    'c', 2, -34, 2, -42, 14, -42,
+    'c', 26, -42, 26, -34, 26, -32,
+    'c', 26, -30, 25, -25, 10, -10,
+    'l', 0, 0,
+    'l', 28, 0,
+    'e',
+/* 0x33 '3'  offset 736 */
+    0, 28, 42, 0, 2, 5,
+    0, 28, /* snap_x */
+    -42, -26, -21, -15, 0, /* snap_y */
+    'm', 4, -42,
+    'l', 26, -42,
+    'l', 14, -26,
+    'c', 21, -26, 28, -26, 28, -14,
+    'c', 28, 0, 17, 0, 13, 0,
+    'c', 8, 0, 3, -1, 0, -8,
+    'e',
+/* 0x34 '4'  offset 780 */
+    0, 28, 42, 0, 3, 4,
+    0, 20, 30, /* snap_x */
+    -21, -15, -14, 0, /* snap_y */
+    'm', 20, -42,
+    'l', 0, -14,
+    'l', 30, -14,
+    'm', 20, -42,
+    'l', 20, 0,
+    'e',
+/* 0x35 '5'  offset 809 */
+    0, 28, 42, 0, 2, 5,
+    0, 28, /* snap_x */
+    -42, -28, -21, -15, 0, /* snap_y */
+    'm', 24, -42,
+    'l', 4, -42,
+    'l', 2, -24,
+    'c', 5, -27, 10, -28, 13, -28,
+    'c', 16, -28, 28, -28, 28, -14,
+    'c', 28, 0, 16, 0, 13, 0,
+    'c', 10, 0, 3, 0, 0, -8,
+    'e',
+/* 0x36 '6'  offset 860 */
+    0, 28, 42, 0, 2, 5,
+    0, 26, /* snap_x */
+    -42, -26, -21, -15, 0, /* snap_y */
+    'm', 24, -36,
+    'c', 22, -41, 19, -42, 14, -42,
+    'c', 9, -42, 0, -41, 0, -19,
+    'c', 0, -1, 9, 0, 13, 0,
+    'c', 18, 0, 26, -3, 26, -13,
+    'c', 26, -18, 23, -26, 13, -26,
+    'c', 10, -26, 1, -24, 0, -14,
+    'e',
+/* 0x37 '7'  offset 919 */
+    0, 28, 42, 0, 2, 4,
+    0, 28, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 28, -42,
+    'l', 8, 0,
+    'm', 0, -42,
+    'l', 28, -42,
+    'e',
+/* 0x38 '8'  offset 944 */
+    0, 28, 42, 0, 4, 4,
+    0, 2, 26, 28, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 14, -42,
+    'c', 5, -42, 2, -40, 2, -34,
+    'c', 2, -18, 28, -32, 28, -11,
+    'c', 28, 0, 18, 0, 14, 0,
+    'c', 10, 0, 0, 0, 0, -11,
+    'c', 0, -32, 26, -18, 26, -34,
+    'c', 26, -40, 23, -42, 14, -42,
+    'e',
+/* 0x39 '9'  offset 1004 */
+    0, 28, 42, 0, 2, 5,
+    0, 26, /* snap_x */
+    -42, -21, -16, -15, 0, /* snap_y */
+    'm', 26, -28,
+    'c', 25, -16, 13, -16, 13, -16,
+    'c', 8, -16, 0, -19, 0, -29,
+    'c', 0, -34, 3, -42, 13, -42,
+    'c', 24, -42, 26, -32, 26, -23,
+    'c', 26, -14, 24, 0, 12, 0,
+    'c', 7, 0, 4, -2, 2, -6,
+    'e',
+/* 0x3a ':'  offset 1063 */
+    0, 4, 28, 0, 2, 3,
+    0, 4, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 2, -28,
+    'c', -1, -28, -1, -24, 2, -24,
+    'c', 5, -24, 5, -28, 2, -28,
+    'm', 2, -4,
+    'c', -1, -4, -1, 0, 2, 0,
+    'c', 5, 0, 5, -4, 2, -4,
+    'e',
+/* 0x3b ';'  offset 1109 */
+    0, 4, 28, 8, 2, 3,
+    0, 4, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 2, -28,
+    'c', -1, -28, -1, -24, 2, -24,
+    'c', 5, -24, 5, -28, 2, -28,
+    'm', 4, -2,
+    'c', 4, 1, 0, 1, 0, -2,
+    'c', 0, -5, 4, -5, 4, -2,
+    'c', 4, 3, 2, 6, 0, 8,
+    'e',
+/* 0x3c '<'  offset 1162 */
+    0, 32, 36, 0, 2, 3,
+    0, 32, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 32, -36,
+    'l', 0, -18,
+    'l', 32, 0,
+    'e',
+/* 0x3d '='  offset 1183 */
+    0, 36, 24, -12, 2, 5,
+    0, 36, /* snap_x */
+    -24, -21, -15, -12, 0, /* snap_y */
+    'm', 0, -24,
+    'l', 36, -24,
+    'm', 0, -12,
+    'l', 36, -12,
+    'e',
+/* 0x3e '>'  offset 1209 */
+    0, 32, 36, 0, 2, 3,
+    0, 32, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -36,
+    'l', 32, -18,
+    'l', 0, 0,
+    'e',
+/* 0x3f '?'  offset 1230 */
+    0, 24, 42, 0, 3, 4,
+    0, 12, 24, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 0, -32,
+    'c', 0, -34, 0, -42, 12, -42,
+    'c', 24, -42, 24, -34, 24, -32,
+    'c', 24, -29, 24, -24, 12, -20,
+    'l', 12, -14,
+    'm', 12, -4,
+    'c', 9, -4, 9, 0, 12, 0,
+    'c', 15, 0, 15, -4, 12, -4,
+    'e',
+/* 0x40 '@'  offset 1288 */
+    0, 42, 42, 0, 1, 6,
+    30, /* snap_x */
+    -42, -32, -21, -15, -10, 0, /* snap_y */
+    'm', 30, -26,
+    'c', 28, -31, 24, -32, 21, -32,
+    'c', 10, -32, 10, -23, 10, -19,
+    'c', 10, -13, 11, -10, 19, -10,
+    'c', 30, -10, 28, -21, 30, -32,
+    'c', 27, -10, 30, -10, 34, -10,
+    'c', 41, -10, 42, -19, 42, -22,
+    'c', 42, -34, 34, -42, 21, -42,
+    'c', 9, -42, 0, -34, 0, -21,
+    'c', 0, -9, 8, 0, 21, 0,
+    'c', 30, 0, 34, -3, 36, -6,
+    'e',
+/* 0x41 'A'  offset 1375 */
+    0, 32, 42, 0, 2, 4,
+    0, 32, /* snap_x */
+    -21, -15, -14, 0, /* snap_y */
+    'm', 16, -42,
+    'l', 0, 0,
+    'm', 16, -42,
+    'l', 32, 0,
+    'm', 6, -14,
+    'l', 26, -14,
+    'e',
+/* 0x42 'B'  offset 1406 */
+    0, 28, 42, 0, 2, 5,
+    0, 28, /* snap_x */
+    -42, -22, -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 0, -42,
+    'l', 18, -42,
+    'c', 32, -42, 32, -22, 18, -22,
+    'm', 0, -22,
+    'l', 18, -22,
+    'c', 32, -22, 32, 0, 18, 0,
+    'l', 0, 0,
+    'e',
+/* 0x43 'C'  offset 1455 */
+    0, 30, 42, 0, 2, 4,
+    0, 30, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 30, -32,
+    'c', 26, -42, 21, -42, 16, -42,
+    'c', 2, -42, 0, -29, 0, -21,
+    'c', 0, -13, 2, 0, 16, 0,
+    'c', 21, 0, 26, 0, 30, -10,
+    'e',
+/* 0x44 'D'  offset 1499 */
+    0, 28, 42, 0, 2, 4,
+    0, 28, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 0, -42,
+    'l', 14, -42,
+    'c', 33, -42, 33, 0, 14, 0,
+    'l', 0, 0,
+    'e',
+/* 0x45 'E'  offset 1534 */
+    0, 26, 42, 0, 2, 5,
+    0, 26, /* snap_x */
+    -42, -22, -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 0, -42,
+    'l', 26, -42,
+    'm', 0, -22,
+    'l', 16, -22,
+    'm', 0, 0,
+    'l', 26, 0,
+    'e',
+/* 0x46 'F'  offset 1572 */
+    0, 26, 42, 0, 2, 5,
+    0, 26, /* snap_x */
+    -42, -22, -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 0, -42,
+    'l', 26, -42,
+    'm', 0, -22,
+    'l', 16, -22,
+    'e',
+/* 0x47 'G'  offset 1604 */
+    0, 30, 42, 0, 2, 5,
+    0, 30, /* snap_x */
+    -42, -21, -16, -15, 0, /* snap_y */
+    'm', 30, -32,
+    'c', 26, -42, 21, -42, 16, -42,
+    'c', 2, -42, 0, -29, 0, -21,
+    'c', 0, -13, 2, 0, 16, 0,
+    'c', 28, 0, 30, -7, 30, -16,
+    'm', 20, -16,
+    'l', 30, -16,
+    'e',
+/* 0x48 'H'  offset 1655 */
+    0, 28, 42, 0, 2, 4,
+    0, 28, /* snap_x */
+    -22, -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 28, -42,
+    'l', 28, 0,
+    'm', 0, -22,
+    'l', 28, -22,
+    'e',
+/* 0x49 'I'  offset 1686 */
+    0, 0, 42, 0, 1, 3,
+    0, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'e',
+/* 0x4a 'J'  offset 1703 */
+    0, 20, 42, 0, 2, 3,
+    0, 20, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 20, -42,
+    'l', 20, -10,
+    'c', 20, 3, 0, 3, 0, -10,
+    'l', 0, -14,
+    'e',
+/* 0x4b 'K'  offset 1731 */
+    0, 28, 42, 0, 2, 3,
+    0, 28, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 28, -42,
+    'l', 0, -14,
+    'm', 10, -24,
+    'l', 28, 0,
+    'e',
+/* 0x4c 'L'  offset 1761 */
+    0, 24, 42, 0, 2, 3,
+    0, 24, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 0, 0,
+    'l', 24, 0,
+    'e',
+/* 0x4d 'M'  offset 1785 */
+    0, 32, 42, 0, 2, 3,
+    0, 32, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 0, -42,
+    'l', 16, 0,
+    'm', 32, -42,
+    'l', 16, 0,
+    'm', 32, -42,
+    'l', 32, 0,
+    'e',
+/* 0x4e 'N'  offset 1821 */
+    0, 28, 42, 0, 2, 3,
+    0, 28, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 0, -42,
+    'l', 28, 0,
+    'm', 28, -42,
+    'l', 28, 0,
+    'e',
+/* 0x4f 'O'  offset 1851 */
+    0, 32, 42, 0, 2, 4,
+    0, 32, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 16, -42,
+    'c', 2, -42, 0, -29, 0, -21,
+    'c', 0, -13, 2, 0, 16, 0,
+    'c', 30, 0, 32, -13, 32, -21,
+    'c', 32, -29, 30, -42, 16, -42,
+    'e',
+/* 0x50 'P'  offset 1895 */
+    0, 28, 42, 0, 2, 5,
+    0, 28, /* snap_x */
+    -42, -21, -20, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 0, -42,
+    'l', 18, -42,
+    'c', 32, -42, 32, -20, 18, -20,
+    'l', 0, -20,
+    'e',
+/* 0x51 'Q'  offset 1931 */
+    0, 32, 42, 4, 2, 4,
+    0, 32, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 16, -42,
+    'c', 2, -42, 0, -29, 0, -21,
+    'c', 0, -13, 2, 0, 16, 0,
+    'c', 30, 0, 32, -13, 32, -21,
+    'c', 32, -29, 30, -42, 16, -42,
+    'm', 18, -8,
+    'l', 30, 4,
+    'e',
+/* 0x52 'R'  offset 1981 */
+    0, 28, 42, 0, 2, 5,
+    0, 28, /* snap_x */
+    -42, -22, -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 0, -42,
+    'l', 18, -42,
+    'c', 32, -42, 31, -22, 18, -22,
+    'l', 0, -22,
+    'm', 14, -22,
+    'l', 28, 0,
+    'e',
+/* 0x53 'S'  offset 2023 */
+    0, 28, 42, 0, 2, 4,
+    0, 28, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 28, -36,
+    'c', 25, -41, 21, -42, 14, -42,
+    'c', 10, -42, 0, -42, 0, -34,
+    'c', 0, -17, 28, -28, 28, -9,
+    'c', 28, 0, 19, 0, 14, 0,
+    'c', 7, 0, 3, -1, 0, -6,
+    'e',
+/* 0x54 'T'  offset 2074 */
+    0, 28, 42, 0, 3, 4,
+    0, 14, 28, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 14, -42,
+    'l', 14, 0,
+    'm', 0, -42,
+    'l', 28, -42,
+    'e',
+/* 0x55 'U'  offset 2100 */
+    0, 28, 42, 0, 2, 3,
+    0, 28, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, -12,
+    'c', 0, 4, 28, 4, 28, -12,
+    'l', 28, -42,
+    'e',
+/* 0x56 'V'  offset 2128 */
+    0, 32, 42, 0, 2, 3,
+    0, 32, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 16, 0,
+    'm', 32, -42,
+    'l', 16, 0,
+    'e',
+/* 0x57 'W'  offset 2152 */
+    0, 40, 42, 0, 2, 3,
+    0, 40, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 10, 0,
+    'm', 20, -42,
+    'l', 10, 0,
+    'm', 20, -42,
+    'l', 30, 0,
+    'm', 40, -42,
+    'l', 30, 0,
+    'e',
+/* 0x58 'X'  offset 2188 */
+    0, 28, 42, 0, 2, 3,
+    0, 28, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 28, 0,
+    'm', 28, -42,
+    'l', 0, 0,
+    'e',
+/* 0x59 'Y'  offset 2212 */
+    0, 32, 42, 0, 3, 3,
+    0, 16, 32, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 16, -22,
+    'l', 16, 0,
+    'm', 32, -42,
+    'l', 16, -22,
+    'e',
+/* 0x5a 'Z'  offset 2240 */
+    0, 28, 42, 0, 2, 4,
+    0, 28, /* snap_x */
+    -42, -21, -15, 0, /* snap_y */
+    'm', 28, -42,
+    'l', 0, 0,
+    'm', 0, -42,
+    'l', 28, -42,
+    'm', 0, 0,
+    'l', 28, 0,
+    'e',
+/* 0x5b '['  offset 2271 */
+    0, 14, 44, 0, 2, 4,
+    0, 14, /* snap_x */
+    -44, -21, -15, 0, /* snap_y */
+    'm', 14, -44,
+    'l', 0, -44,
+    'l', 0, 0,
+    'l', 14, 0,
+    'e',
+/* 0x5c '\'  offset 2296 */
+    0, 36, 50, 14, 2, 3,
+    0, 36, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -50,
+    'l', 36, 14,
+    'e',
+/* 0x5d ']'  offset 2314 */
+    0, 14, 44, 0, 2, 4,
+    0, 14, /* snap_x */
+    -44, -21, -15, 0, /* snap_y */
+    'm', 0, -44,
+    'l', 14, -44,
+    'l', 14, 0,
+    'l', 0, 0,
+    'e',
+/* 0x5e '^'  offset 2339 */
+    0, 32, 46, -18, 2, 3,
+    0, 32, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 16, -46,
+    'l', 0, -18,
+    'm', 16, -46,
+    'l', 32, -18,
+    'e',
+/* 0x5f '_'  offset 2363 */
+    0, 36, 0, 0, 2, 3,
+    0, 36, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, 0,
+    'l', 36, 0,
+    'e',
+/* 0x60 '`'  offset 2381 */
+    0, 4, 42, -30, 2, 3,
+    0, 4, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 4, -42,
+    'c', 2, -40, 0, -39, 0, -32,
+    'c', 0, -31, 1, -30, 2, -30,
+    'c', 5, -30, 5, -34, 2, -34,
+    'e',
+/* 0x61 'a'  offset 2417 */
+    0, 24, 28, 0, 2, 4,
+    0, 24, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 24, -28,
+    'l', 24, 0,
+    'm', 24, -22,
+    'c', 21, -27, 18, -28, 13, -28,
+    'c', 2, -28, 0, -19, 0, -14,
+    'c', 0, -9, 2, 0, 13, 0,
+    'c', 18, 0, 21, -1, 24, -6,
+    'e',
+/* 0x62 'b'  offset 2467 */
+    0, 24, 42, 0, 2, 4,
+    0, 24, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 0, -22,
+    'c', 3, -26, 6, -28, 11, -28,
+    'c', 22, -28, 24, -19, 24, -14,
+    'c', 24, -9, 22, 0, 11, 0,
+    'c', 6, 0, 3, -2, 0, -6,
+    'e',
+/* 0x63 'c'  offset 2517 */
+    0, 24, 28, 0, 2, 4,
+    0, 24, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 24, -22,
+    'c', 21, -26, 18, -28, 13, -28,
+    'c', 2, -28, 0, -19, 0, -14,
+    'c', 0, -9, 2, 0, 13, 0,
+    'c', 18, 0, 21, -2, 24, -6,
+    'e',
+/* 0x64 'd'  offset 2561 */
+    0, 24, 42, 0, 2, 4,
+    0, 24, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 24, -42,
+    'l', 24, 0,
+    'm', 24, -22,
+    'c', 21, -26, 18, -28, 13, -28,
+    'c', 2, -28, 0, -19, 0, -14,
+    'c', 0, -9, 2, 0, 13, 0,
+    'c', 18, 0, 21, -2, 24, -6,
+    'e',
+/* 0x65 'e'  offset 2611 */
+    0, 24, 28, 0, 2, 5,
+    0, 24, /* snap_x */
+    -28, -21, -16, -15, 0, /* snap_y */
+    'm', 0, -16,
+    'l', 24, -16,
+    'c', 24, -20, 24, -28, 13, -28,
+    'c', 2, -28, 0, -19, 0, -14,
+    'c', 0, -9, 2, 0, 13, 0,
+    'c', 18, 0, 21, -2, 24, -6,
+    'e',
+/* 0x66 'f'  offset 2659 */
+    0, 16, 42, 0, 3, 5,
+    0, 6, 16, /* snap_x */
+    -42, -28, -21, -15, 0, /* snap_y */
+    'm', 16, -42,
+    'c', 8, -42, 6, -40, 6, -34,
+    'l', 6, 0,
+    'm', 0, -28,
+    'l', 14, -28,
+    'e',
+/* 0x67 'g'  offset 2693 */
+    0, 24, 28, 14, 2, 5,
+    0, 24, /* snap_x */
+    -28, -21, -15, 0, 14, /* snap_y */
+    'm', 24, -28,
+    'l', 24, 4,
+    'c', 23, 14, 16, 14, 13, 14,
+    'c', 10, 14, 8, 14, 6, 12,
+    'm', 24, -22,
+    'c', 21, -26, 18, -28, 13, -28,
+    'c', 2, -28, 0, -19, 0, -14,
+    'c', 0, -9, 2, 0, 13, 0,
+    'c', 18, 0, 21, -2, 24, -6,
+    'e',
+/* 0x68 'h'  offset 2758 */
+    0, 22, 42, 0, 2, 4,
+    0, 22, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 0, -20,
+    'c', 8, -32, 22, -31, 22, -20,
+    'l', 22, 0,
+    'e',
+/* 0x69 'i'  offset 2790 */
+    0, 4, 44, 0, 3, 3,
+    0, 2, 4, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'c', 0, -39, 4, -39, 4, -42,
+    'c', 4, -45, 0, -45, 0, -42,
+    'm', 2, -28,
+    'l', 2, 0,
+    'e',
+/* 0x6a 'j'  offset 2826 */
+    -8, 4, 44, 14, 3, 4,
+    0, 2, 4, /* snap_x */
+    -21, -15, 0, 14, /* snap_y */
+    'm', 0, -42,
+    'c', 0, -39, 4, -39, 4, -42,
+    'c', 4, -45, 0, -45, 0, -42,
+    'm', 2, -28,
+    'l', 2, 6,
+    'c', 2, 13, -1, 14, -8, 14,
+    'e',
+/* 0x6b 'k'  offset 2870 */
+    0, 22, 42, 0, 2, 3,
+    0, 22, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'm', 20, -28,
+    'l', 0, -8,
+    'm', 8, -16,
+    'l', 22, 0,
+    'e',
+/* 0x6c 'l'  offset 2900 */
+    0, 0, 42, 0, 1, 3,
+    0, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -42,
+    'l', 0, 0,
+    'e',
+/* 0x6d 'm'  offset 2917 */
+    0, 44, 28, 0, 3, 4,
+    0, 22, 44, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 0, -28,
+    'l', 0, 0,
+    'm', 0, -20,
+    'c', 5, -29, 22, -33, 22, -20,
+    'l', 22, 0,
+    'm', 22, -20,
+    'c', 27, -29, 44, -33, 44, -20,
+    'l', 44, 0,
+    'e',
+/* 0x6e 'n'  offset 2963 */
+    0, 22, 28, 0, 2, 4,
+    0, 22, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 0, -28,
+    'l', 0, 0,
+    'm', 0, -20,
+    'c', 4, -28, 22, -34, 22, -20,
+    'l', 22, 0,
+    'e',
+/* 0x6f 'o'  offset 2995 */
+    0, 26, 28, 0, 2, 4,
+    0, 26, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 13, -28,
+    'c', 2, -28, 0, -19, 0, -14,
+    'c', 0, -9, 2, 0, 13, 0,
+    'c', 24, 0, 26, -9, 26, -14,
+    'c', 26, -19, 24, -28, 13, -28,
+    'e',
+/* 0x70 'p'  offset 3039 */
+    0, 24, 28, 14, 2, 4,
+    0, 24, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 0, -28,
+    'l', 0, 14,
+    'm', 0, -22,
+    'c', 3, -26, 6, -28, 11, -28,
+    'c', 22, -28, 24, -19, 24, -14,
+    'c', 24, -9, 22, 0, 11, 0,
+    'c', 6, 0, 3, -2, 0, -6,
+    'e',
+/* 0x71 'q'  offset 3089 */
+    0, 24, 28, 14, 2, 4,
+    0, 24, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 24, -28,
+    'l', 24, 14,
+    'm', 24, -22,
+    'c', 21, -26, 18, -28, 13, -28,
+    'c', 2, -28, 0, -19, 0, -14,
+    'c', 0, -9, 2, 0, 13, 0,
+    'c', 18, 0, 21, -2, 24, -6,
+    'e',
+/* 0x72 'r'  offset 3139 */
+    0, 16, 28, 0, 2, 4,
+    0, 16, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 0, -28,
+    'l', 0, 0,
+    'm', 0, -16,
+    'c', 2, -27, 7, -28, 16, -28,
+    'e',
+/* 0x73 's'  offset 3168 */
+    0, 22, 28, 0, 2, 4,
+    0, 22, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 22, -22,
+    'c', 22, -27, 16, -28, 11, -28,
+    'c', 4, -28, 0, -26, 0, -22,
+    'c', 0, -11, 22, -20, 22, -7,
+    'c', 22, 0, 17, 0, 11, 0,
+    'c', 6, 0, 0, -1, 0, -6,
+    'e',
+/* 0x74 't'  offset 3219 */
+    0, 16, 42, 0, 3, 4,
+    0, 6, 16, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 6, -42,
+    'l', 6, -8,
+    'c', 6, -2, 8, 0, 16, 0,
+    'm', 0, -28,
+    'l', 14, -28,
+    'e',
+/* 0x75 'u'  offset 3252 */
+    0, 22, 28, 0, 2, 3,
+    0, 22, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -28,
+    'l', 0, -8,
+    'c', 0, 6, 18, 0, 22, -8,
+    'm', 22, -28,
+    'l', 22, 0,
+    'e',
+/* 0x76 'v'  offset 3283 */
+    0, 24, 28, 0, 2, 3,
+    0, 24, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -28,
+    'l', 12, 0,
+    'm', 24, -28,
+    'l', 12, 0,
+    'e',
+/* 0x77 'w'  offset 3307 */
+    0, 32, 28, 0, 2, 3,
+    0, 32, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -28,
+    'l', 8, 0,
+    'm', 16, -28,
+    'l', 8, 0,
+    'm', 16, -28,
+    'l', 24, 0,
+    'm', 32, -28,
+    'l', 24, 0,
+    'e',
+/* 0x78 'x'  offset 3343 */
+    0, 22, 28, 0, 2, 3,
+    0, 22, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -28,
+    'l', 22, 0,
+    'm', 22, -28,
+    'l', 0, 0,
+    'e',
+/* 0x79 'y'  offset 3367 */
+    -2, 24, 28, 14, 2, 4,
+    0, 24, /* snap_x */
+    -21, -15, 0, 14, /* snap_y */
+    'm', 0, -28,
+    'l', 12, 0,
+    'm', 24, -28,
+    'l', 12, 0,
+    'c', 6, 13, 0, 14, -2, 14,
+    'e',
+/* 0x7a 'z'  offset 3399 */
+    0, 22, 28, 0, 2, 4,
+    0, 22, /* snap_x */
+    -28, -21, -15, 0, /* snap_y */
+    'm', 22, -28,
+    'l', 0, 0,
+    'm', 0, -28,
+    'l', 22, -28,
+    'm', 0, 0,
+    'l', 22, 0,
+    'e',
+/* 0x7b '{'  offset 3430 */
+    0, 16, 44, 0, 3, 5,
+    0, 6, 16, /* snap_x */
+    -44, -24, -21, -15, 0, /* snap_y */
+    'm', 16, -44,
+    'c', 10, -44, 6, -42, 6, -36,
+    'l', 6, -24,
+    'l', 0, -24,
+    'l', 6, -24,
+    'l', 6, -8,
+    'c', 6, -2, 10, 0, 16, 0,
+    'e',
+/* 0x7c '|'  offset 3474 */
+    0, 0, 50, 14, 1, 3,
+    0, /* snap_x */
+    -21, -15, 0, /* snap_y */
+    'm', 0, -50,
+    'l', 0, 14,
+    'e',
+/* 0x7d '}'  offset 3491 */
+    0, 16, 44, 0, 3, 5,
+    0, 10, 16, /* snap_x */
+    -44, -24, -21, -15, 0, /* snap_y */
+    'm', 0, -44,
+    'c', 6, -44, 10, -42, 10, -36,
+    'l', 10, -24,
+    'l', 16, -24,
+    'l', 10, -24,
+    'l', 10, -8,
+    'c', 10, -2, 6, 0, 0, 0,
+    'e',
+/* 0x7e '~'  offset 3535 */
+    0, 36, 24, -12, 2, 5,
+    0, 36, /* snap_x */
+    -24, -21, -15, -12, 0, /* snap_y */
+    'm', 0, -14,
+    'c', 1, -21, 4, -24, 8, -24,
+    'c', 18, -24, 18, -12, 28, -12,
+    'c', 32, -12, 35, -15, 36, -22,
+    'e',
+};
+
+const uint16_t _cairo_twin_charmap[128] = {
+    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,
+    28,   40,   90,  114,  152,  224,  323,  390,
+    419,  441,  463,  494,  520,  556,  575,  604,
+    622,  666,  691,  736,  780,  809,  860,  919,
+    944, 1004, 1063, 1109, 1162, 1183, 1209, 1230,
+    1288, 1375, 1406, 1455, 1499, 1534, 1572, 1604,
+    1655, 1686, 1703, 1731, 1761, 1785, 1821, 1851,
+    1895, 1931, 1981, 2023, 2074, 2100, 2128, 2152,
+    2188, 2212, 2240, 2271, 2296, 2314, 2339, 2363,
+    2381, 2417, 2467, 2517, 2561, 2611, 2659, 2693,
+    2758, 2790, 2826, 2870, 2900, 2917, 2963, 2995,
+    3039, 3089, 3139, 3168, 3219, 3252, 3283, 3307,
+    3343, 3367, 3399, 3430, 3474, 3491, 3535,    0,
+};
+
diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c
new file mode 100644
index 0000000..86e083d
--- /dev/null
+++ b/src/cairo-font-face-twin.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright © 2004 Keith Packard
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Keith Packard
+ *
+ * Contributor(s):
+ *      Keith Packard <keithp at keithp.com>
+ *      Behdad Esfahbod <behdad at behdad.org>
+ */
+
+#include "cairoint.h"
+
+/*
+ * This file implements a user-font rendering the decendant of the Hershey
+ * font coded by Keith Packard for use in the Twin window system.
+ * The actual font data is in cairo-font-face-twin-data.c
+ *
+ * Ported to cairo user font by Behdad Esfahbod.
+ */
+
+
+#define twin_glyph_left(g)      ((g)[0])
+#define twin_glyph_right(g)     ((g)[1])
+#define twin_glyph_ascent(g)    ((g)[2])
+#define twin_glyph_descent(g)   ((g)[3])
+
+#define twin_glyph_n_snap_x(g)  ((g)[4])
+#define twin_glyph_n_snap_y(g)  ((g)[5])
+#define twin_glyph_snap_x(g)    (&g[6])
+#define twin_glyph_snap_y(g)    (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
+#define twin_glyph_draw(g)      (twin_glyph_snap_y(g) + twin_glyph_n_snap_y(g))
+
+#define SNAPI(p)	(p)
+#define SNAPH(p)	(p)
+
+#define FX(g)		((g) / 64.)
+#define FY(g)		((g) / 64.)
+
+
+static cairo_status_t
+twin_scaled_font_init (cairo_scaled_font_t  *scaled_font,
+		       cairo_t              *cr,
+		       cairo_font_extents_t *metrics)
+{
+  metrics->ascent  = .67;
+  metrics->descent = .33;
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+twin_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font,
+				   unsigned long        unicode,
+				   unsigned long       *glyph)
+{
+    /* We use an indentity charmap.  Which means we could live
+     * with no unicode_to_glyph method too.  But we define this
+     * to map all unknown chars to a single unknown glyph to
+     * reduce pressure on cache. */
+
+    if (unicode < ARRAY_LENGTH (_cairo_twin_charmap))
+	*glyph = unicode;
+    else
+	*glyph = 0;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+#define SNAPX(p)	_twin_snap (p, info.snap_x, info.n_snap_x)
+#define SNAPY(p)	_twin_snap (p, info.snap_y, info.n_snap_y)
+
+static double
+_twin_snap (double v, int a, int b)
+{
+    return v; /* XXX */
+}
+
+static cairo_status_t
+twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
+			       unsigned long         glyph,
+			       cairo_t              *cr,
+			       cairo_text_extents_t *metrics)
+{
+    double x1, y1, x2, y2, x3, y3;
+    const int8_t *b = _cairo_twin_outlines +
+		      _cairo_twin_charmap[glyph >= ARRAY_LENGTH (_cairo_twin_charmap) ? 0 : glyph];
+    const int8_t *g = twin_glyph_draw(b);
+
+    struct {
+      cairo_bool_t snap;
+      int snap_x;
+      int snap_y;
+      int n_snap_x;
+      int n_snap_y;
+    } info = {FALSE};
+
+    cairo_set_line_width (cr, 0.1);
+    cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+    cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+
+    for (;;) {
+	switch (*g++) {
+	case 'm':
+	    x1 = FX(*g++);
+	    y1 = FY(*g++);
+	    if (info.snap)
+	    {
+		x1 = SNAPX (x1);
+		y1 = SNAPY (y1);
+	    }
+	    cairo_move_to (cr, x1, y1);
+	    continue;
+	case 'l':
+	    x1 = FX(*g++);
+	    y1 = FY(*g++);
+	    if (info.snap)
+	    {
+		x1 = SNAPX (x1);
+		y1 = SNAPY (y1);
+	    }
+	    cairo_line_to (cr, x1, y1);
+	    continue;
+	case 'c':
+	    x1 = FX(*g++);
+	    y1 = FY(*g++);
+	    x2 = FX(*g++);
+	    y2 = FY(*g++);
+	    x3 = FX(*g++);
+	    y3 = FY(*g++);
+	    if (info.snap)
+	    {
+		x1 = SNAPX (x1);
+		y1 = SNAPY (y1);
+		x2 = SNAPX (x2);
+		y2 = SNAPY (y2);
+		x3 = SNAPX (x3);
+		y3 = SNAPY (y3);
+	    }
+	    cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
+	    continue;
+	case 'o':
+	    cairo_close_path (cr);
+	    break;
+	case 'e':
+	    cairo_stroke (cr);
+	    break;
+	}
+	break;
+    }
+
+    cairo_stroke (cr);
+
+    metrics->x_advance = FX(twin_glyph_right(b)) + cairo_get_line_width (cr);
+    metrics->x_advance +=  cairo_get_line_width (cr)/* XXX 2*x.margin */;
+    if (info.snap)
+	metrics->x_advance = SNAPI (SNAPX (metrics->x_advance));
+
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_font_face_t *
+_cairo_font_face_twin_create (cairo_font_slant_t slant,
+			      cairo_font_weight_t weight)
+{
+    cairo_font_face_t *twin_font_face;
+
+    twin_font_face = cairo_user_font_face_create ();
+    cairo_user_font_face_set_init_func             (twin_font_face, twin_scaled_font_init);
+    cairo_user_font_face_set_render_glyph_func     (twin_font_face, twin_scaled_font_render_glyph);
+    cairo_user_font_face_set_unicode_to_glyph_func (twin_font_face, twin_scaled_font_unicode_to_glyph);
+
+    return twin_font_face;
+}
diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c
index 5af0c63..02ad7c3 100644
--- a/src/cairo-font-face.c
+++ b/src/cairo-font-face.c
@@ -574,7 +574,6 @@ _cairo_toy_font_face_scaled_font_create (void                *abstract_font_face
 					 cairo_scaled_font_t	   **scaled_font)
 {
     cairo_toy_font_face_t *font_face = abstract_font_face;
-    const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT;
     cairo_status_t status;
 
     if (font_face->base.status)
@@ -584,12 +583,32 @@ _cairo_toy_font_face_scaled_font_create (void                *abstract_font_face
     if (status)
 	return status;
 
-    return _cairo_font_face_set_error (&font_face->base,
-	                               backend->create_toy (font_face,
-				                            font_matrix,
-							    ctm,
-							    options,
-							    scaled_font));
+    if (CAIRO_SCALED_FONT_BACKEND_DEFAULT != &_cairo_user_scaled_font_backend &&
+	0 != strcmp (font_face->family, CAIRO_USER_FONT_FAMILY_DEFAULT))
+    {
+	const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT;
+
+	*scaled_font = NULL;
+	status =  backend->create_toy (font_face,
+				       font_matrix,
+				       ctm,
+				       options,
+				       scaled_font);
+
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return _cairo_font_face_set_error (&font_face->base, status);
+
+	if (*scaled_font)
+	    cairo_scaled_font_destroy (*scaled_font);
+    }
+
+    status = _cairo_user_scaled_font_backend.create_toy (font_face,
+							 font_matrix,
+							 ctm,
+							 options,
+							 scaled_font);
+
+    return _cairo_font_face_set_error (&font_face->base, status);
 }
 
 static cairo_bool_t
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index 0f46c58..40b2a2f 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -96,8 +96,6 @@ _cairo_user_scaled_font_create_meta_context (cairo_user_scaled_font_t *scaled_fo
     return cr;
 }
 
-static const cairo_scaled_font_backend_t cairo_user_scaled_font_backend;
-
 static cairo_int_status_t
 _cairo_user_scaled_glyph_init (void			 *abstract_font,
 			       cairo_scaled_glyph_t	 *scaled_glyph,
@@ -321,9 +319,54 @@ _cairo_user_text_to_glyphs (void		      *abstract_font,
     return status;
 }
 
-static const cairo_scaled_font_backend_t cairo_user_scaled_font_backend = {
+static cairo_status_t
+_cairo_user_font_face_scaled_font_create (void                        *abstract_face,
+					  const cairo_matrix_t        *font_matrix,
+					  const cairo_matrix_t        *ctm,
+					  const cairo_font_options_t  *options,
+					  cairo_scaled_font_t        **scaled_font);
+
+static cairo_status_t
+_cairo_user_scaled_font_create_toy (cairo_toy_font_face_t     *toy_face,
+				    const cairo_matrix_t      *font_matrix,
+				    const cairo_matrix_t      *ctm,
+				    const cairo_font_options_t *font_options,
+				    cairo_scaled_font_t	     **font)
+{
+    cairo_status_t status;
+    cairo_font_face_t *face;
+
+    static cairo_user_data_key_t twin_font_face_key;
+
+    face = cairo_font_face_get_user_data (&toy_face->base,
+					  &twin_font_face_key);
+    if (!face) {
+	face = _cairo_font_face_twin_create (cairo_toy_font_face_get_slant (&toy_face->base),
+					     cairo_toy_font_face_get_weight (&toy_face->base));
+
+	status = cairo_font_face_set_user_data (&toy_face->base,
+						&twin_font_face_key,
+						face,
+						(cairo_destroy_func_t) cairo_font_face_destroy);
+
+	if (status) {
+	    cairo_font_face_destroy (face);
+	    return status;
+	}
+    }
+
+    status = _cairo_user_font_face_scaled_font_create (face,
+						       font_matrix,
+						       ctm,
+						       font_options,
+						       font);
+
+    return status;
+}
+
+const cairo_scaled_font_backend_t _cairo_user_scaled_font_backend = {
     CAIRO_FONT_TYPE_USER,
-    NULL,	/* create_toy */
+    _cairo_user_scaled_font_create_toy,	/* create_toy */
     NULL,	/* scaled_font_fini */
     _cairo_user_scaled_glyph_init,
     _cairo_user_text_to_glyphs,
@@ -356,7 +399,7 @@ _cairo_user_font_face_scaled_font_create (void                        *abstract_
     status = _cairo_scaled_font_init (&user_scaled_font->base,
 				      &font_face->base,
 				      font_matrix, ctm, options,
-				      &cairo_user_scaled_font_backend);
+				      &_cairo_user_scaled_font_backend);
 
     if (status) {
 	free (user_scaled_font);
diff --git a/src/cairoint.h b/src/cairoint.h
index 51d4674..1a3d164 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -488,6 +488,8 @@ struct _cairo_font_face_backend {
 			   cairo_scaled_font_t	       **scaled_font);
 };
 
+extern const cairo_private struct _cairo_scaled_font_backend _cairo_user_scaled_font_backend;
+
 /* concrete font backends */
 #if CAIRO_HAS_FT_FONT
 
@@ -920,6 +922,7 @@ typedef struct _cairo_traps {
 #define CAIRO_WIN32_FONT_FAMILY_DEFAULT "Arial"
 #define CAIRO_QUARTZ_FONT_FAMILY_DEFAULT  "Helvetica"
 #define CAIRO_FT_FONT_FAMILY_DEFAULT     ""
+#define CAIRO_USER_FONT_FAMILY_DEFAULT     "cairo"
 
 #if   CAIRO_HAS_WIN32_FONT
 
@@ -938,8 +941,8 @@ typedef struct _cairo_traps {
 
 #else
 
-/* Paranoia: this should have been caught by configure. */
-#error No font backends are available.
+#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_FT_FONT_FAMILY_DEFAULT
+#define CAIRO_SCALED_FONT_BACKEND_DEFAULT &_cairo_user_scaled_font_backend
 
 #endif
 
@@ -1327,6 +1330,17 @@ _cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
 cairo_private void
 _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
 
+/* cairo-font-face-twin.c */
+
+cairo_private cairo_font_face_t *
+_cairo_font_face_twin_create (cairo_font_slant_t slant,
+			      cairo_font_weight_t weight);
+
+/* cairo-font-face-twin-data.c */
+
+extern const cairo_private int8_t _cairo_twin_outlines[];
+extern const cairo_private uint16_t _cairo_twin_charmap[128];
+
 /* cairo-font-options.c */
 
 cairo_private void


More information about the cairo-commit mailing list