Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2004 Keith Packard
  3.  * Copyright © 2008 Red Hat, Inc.
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it either under the terms of the GNU Lesser General Public
  7.  * License version 2.1 as published by the Free Software Foundation
  8.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  9.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  10.  * notice, a recipient may use your version of this file under either
  11.  * the MPL or the LGPL.
  12.  *
  13.  * You should have received a copy of the LGPL along with this library
  14.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  15.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  16.  * You should have received a copy of the MPL along with this library
  17.  * in the file COPYING-MPL-1.1
  18.  *
  19.  * The contents of this file are subject to the Mozilla Public License
  20.  * Version 1.1 (the "License"); you may not use this file except in
  21.  * compliance with the License. You may obtain a copy of the License at
  22.  * http://www.mozilla.org/MPL/
  23.  *
  24.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  25.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  26.  * the specific language governing rights and limitations.
  27.  *
  28.  * The Original Code is the cairo graphics library.
  29.  *
  30.  * The Initial Developer of the Original Code is Keith Packard
  31.  *
  32.  * Contributor(s):
  33.  *      Keith Packard <keithp@keithp.com>
  34.  *      Behdad Esfahbod <behdad@behdad.org>
  35.  */
  36.  
  37. #include "cairoint.h"
  38. #include "cairo-error-private.h"
  39.  
  40. #include <math.h>
  41.  
  42. /*
  43.  * This file implements a user-font rendering the descendant of the Hershey
  44.  * font coded by Keith Packard for use in the Twin window system.
  45.  * The actual font data is in cairo-font-face-twin-data.c
  46.  *
  47.  * Ported to cairo user font and extended by Behdad Esfahbod.
  48.  */
  49.  
  50.  
  51.  
  52. static cairo_user_data_key_t twin_properties_key;
  53.  
  54.  
  55. /*
  56.  * Face properties
  57.  */
  58.  
  59. /* We synthesize multiple faces from the twin data.  Here is the parameters. */
  60.  
  61. /* The following tables and matching code are copied from Pango */
  62.  
  63. /* CSS weight */
  64. typedef enum {
  65.   TWIN_WEIGHT_THIN = 100,
  66.   TWIN_WEIGHT_ULTRALIGHT = 200,
  67.   TWIN_WEIGHT_LIGHT = 300,
  68.   TWIN_WEIGHT_BOOK = 380,
  69.   TWIN_WEIGHT_NORMAL = 400,
  70.   TWIN_WEIGHT_MEDIUM = 500,
  71.   TWIN_WEIGHT_SEMIBOLD = 600,
  72.   TWIN_WEIGHT_BOLD = 700,
  73.   TWIN_WEIGHT_ULTRABOLD = 800,
  74.   TWIN_WEIGHT_HEAVY = 900,
  75.   TWIN_WEIGHT_ULTRAHEAVY = 1000
  76. } twin_face_weight_t;
  77.  
  78. /* CSS stretch */
  79. typedef enum {
  80.   TWIN_STRETCH_ULTRA_CONDENSED,
  81.   TWIN_STRETCH_EXTRA_CONDENSED,
  82.   TWIN_STRETCH_CONDENSED,
  83.   TWIN_STRETCH_SEMI_CONDENSED,
  84.   TWIN_STRETCH_NORMAL,
  85.   TWIN_STRETCH_SEMI_EXPANDED,
  86.   TWIN_STRETCH_EXPANDED,
  87.   TWIN_STRETCH_EXTRA_EXPANDED,
  88.   TWIN_STRETCH_ULTRA_EXPANDED
  89. } twin_face_stretch_t;
  90.  
  91. typedef struct
  92. {
  93.   int value;
  94.   const char str[16];
  95. } FieldMap;
  96.  
  97. static const FieldMap slant_map[] = {
  98.   { CAIRO_FONT_SLANT_NORMAL, "" },
  99.   { CAIRO_FONT_SLANT_NORMAL, "Roman" },
  100.   { CAIRO_FONT_SLANT_OBLIQUE, "Oblique" },
  101.   { CAIRO_FONT_SLANT_ITALIC, "Italic" }
  102. };
  103.  
  104. static const FieldMap smallcaps_map[] = {
  105.   { FALSE, "" },
  106.   { TRUE, "Small-Caps" }
  107. };
  108.  
  109. static const FieldMap weight_map[] = {
  110.   { TWIN_WEIGHT_THIN, "Thin" },
  111.   { TWIN_WEIGHT_ULTRALIGHT, "Ultra-Light" },
  112.   { TWIN_WEIGHT_ULTRALIGHT, "Extra-Light" },
  113.   { TWIN_WEIGHT_LIGHT, "Light" },
  114.   { TWIN_WEIGHT_BOOK, "Book" },
  115.   { TWIN_WEIGHT_NORMAL, "" },
  116.   { TWIN_WEIGHT_NORMAL, "Regular" },
  117.   { TWIN_WEIGHT_MEDIUM, "Medium" },
  118.   { TWIN_WEIGHT_SEMIBOLD, "Semi-Bold" },
  119.   { TWIN_WEIGHT_SEMIBOLD, "Demi-Bold" },
  120.   { TWIN_WEIGHT_BOLD, "Bold" },
  121.   { TWIN_WEIGHT_ULTRABOLD, "Ultra-Bold" },
  122.   { TWIN_WEIGHT_ULTRABOLD, "Extra-Bold" },
  123.   { TWIN_WEIGHT_HEAVY, "Heavy" },
  124.   { TWIN_WEIGHT_HEAVY, "Black" },
  125.   { TWIN_WEIGHT_ULTRAHEAVY, "Ultra-Heavy" },
  126.   { TWIN_WEIGHT_ULTRAHEAVY, "Extra-Heavy" },
  127.   { TWIN_WEIGHT_ULTRAHEAVY, "Ultra-Black" },
  128.   { TWIN_WEIGHT_ULTRAHEAVY, "Extra-Black" }
  129. };
  130.  
  131. static const FieldMap stretch_map[] = {
  132.   { TWIN_STRETCH_ULTRA_CONDENSED, "Ultra-Condensed" },
  133.   { TWIN_STRETCH_EXTRA_CONDENSED, "Extra-Condensed" },
  134.   { TWIN_STRETCH_CONDENSED,       "Condensed" },
  135.   { TWIN_STRETCH_SEMI_CONDENSED,  "Semi-Condensed" },
  136.   { TWIN_STRETCH_NORMAL,          "" },
  137.   { TWIN_STRETCH_SEMI_EXPANDED,   "Semi-Expanded" },
  138.   { TWIN_STRETCH_EXPANDED,        "Expanded" },
  139.   { TWIN_STRETCH_EXTRA_EXPANDED,  "Extra-Expanded" },
  140.   { TWIN_STRETCH_ULTRA_EXPANDED,  "Ultra-Expanded" }
  141. };
  142.  
  143. static const FieldMap monospace_map[] = {
  144.   { FALSE, "" },
  145.   { TRUE, "Mono" },
  146.   { TRUE, "Monospace" }
  147. };
  148.  
  149.  
  150. typedef struct _twin_face_properties {
  151.     cairo_font_slant_t  slant;
  152.     twin_face_weight_t  weight;
  153.     twin_face_stretch_t stretch;
  154.  
  155.     /* lets have some fun */
  156.     cairo_bool_t monospace;
  157.     cairo_bool_t smallcaps;
  158. } twin_face_properties_t;
  159.  
  160. static cairo_bool_t
  161. field_matches (const char *s1,
  162.                const char *s2,
  163.                int len)
  164. {
  165.   int c1, c2;
  166.  
  167.   while (len && *s1 && *s2)
  168.     {
  169. #define TOLOWER(c) \
  170.    (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
  171.  
  172.       c1 = TOLOWER (*s1);
  173.       c2 = TOLOWER (*s2);
  174.       if (c1 != c2) {
  175.         if (c1 == '-') {
  176.           s1++;
  177.           continue;
  178.         }
  179.         return FALSE;
  180.       }
  181.       s1++; s2++;
  182.       len--;
  183.     }
  184.  
  185.   return len == 0 && *s1 == '\0';
  186. }
  187.  
  188. static cairo_bool_t
  189. parse_int (const char *word,
  190.            size_t      wordlen,
  191.            int        *out)
  192. {
  193.   char *end;
  194.   long val = strtol (word, &end, 10);
  195.   int i = val;
  196.  
  197.   if (end != word && (end == word + wordlen) && val >= 0 && val == i)
  198.     {
  199.       if (out)
  200.         *out = i;
  201.  
  202.       return TRUE;
  203.     }
  204.  
  205.   return FALSE;
  206. }
  207.  
  208. static cairo_bool_t
  209. find_field (const char *what,
  210.             const FieldMap *map,
  211.             int n_elements,
  212.             const char *str,
  213.             int len,
  214.             int *val)
  215. {
  216.   int i;
  217.   cairo_bool_t had_prefix = FALSE;
  218.  
  219.   if (what)
  220.     {
  221.       i = strlen (what);
  222.       if (len > i && 0 == strncmp (what, str, i) && str[i] == '=')
  223.         {
  224.           str += i + 1;
  225.           len -= i + 1;
  226.           had_prefix = TRUE;
  227.         }
  228.     }
  229.  
  230.   for (i=0; i<n_elements; i++)
  231.     {
  232.       if (map[i].str[0] && field_matches (map[i].str, str, len))
  233.         {
  234.           if (val)
  235.             *val = map[i].value;
  236.           return TRUE;
  237.         }
  238.     }
  239.  
  240.   if (!what || had_prefix)
  241.     return parse_int (str, len, val);
  242.  
  243.   return FALSE;
  244. }
  245.  
  246. static void
  247. parse_field (twin_face_properties_t *props,
  248.              const char *str,
  249.              int len)
  250. {
  251.   if (field_matches ("Normal", str, len))
  252.     return;
  253.  
  254. #define FIELD(NAME) \
  255.   if (find_field (STRINGIFY (NAME), NAME##_map, ARRAY_LENGTH (NAME##_map), str, len, \
  256.                   (int *)(void *)&props->NAME)) \
  257.       return; \
  258.  
  259.   FIELD (weight);
  260.   FIELD (slant);
  261.   FIELD (stretch);
  262.   FIELD (smallcaps);
  263.   FIELD (monospace);
  264.  
  265. #undef FIELD
  266. }
  267.  
  268. static void
  269. face_props_parse (twin_face_properties_t *props,
  270.              const char *s)
  271. {
  272.     const char *start, *end;
  273.  
  274.     for (start = end = s; *end; end++) {
  275.         if (*end != ' ' && *end != ':')
  276.             continue;
  277.  
  278.         if (start < end)
  279.                 parse_field (props, start, end - start);
  280.         start = end + 1;
  281.     }
  282.     if (start < end)
  283.             parse_field (props, start, end - start);
  284. }
  285.  
  286. static twin_face_properties_t *
  287. twin_font_face_create_properties (cairo_font_face_t *twin_face)
  288. {
  289.     twin_face_properties_t *props;
  290.  
  291.     props = malloc (sizeof (twin_face_properties_t));
  292.     if (unlikely (props == NULL))
  293.         return NULL;
  294.  
  295.     props->stretch  = TWIN_STRETCH_NORMAL;
  296.     props->slant = CAIRO_FONT_SLANT_NORMAL;
  297.     props->weight = TWIN_WEIGHT_NORMAL;
  298.     props->monospace = FALSE;
  299.     props->smallcaps = FALSE;
  300.  
  301.     if (unlikely (cairo_font_face_set_user_data (twin_face,
  302.                                             &twin_properties_key,
  303.                                             props, free))) {
  304.         free (props);
  305.         return NULL;
  306.     }
  307.  
  308.     return props;
  309. }
  310.  
  311. static cairo_status_t
  312. twin_font_face_set_properties_from_toy (cairo_font_face_t *twin_face,
  313.                                         cairo_toy_font_face_t *toy_face)
  314. {
  315.     twin_face_properties_t *props;
  316.  
  317.     props = twin_font_face_create_properties (twin_face);
  318.     if (unlikely (props == NULL))
  319.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  320.  
  321.     props->slant = toy_face->slant;
  322.     props->weight = toy_face->weight == CAIRO_FONT_WEIGHT_NORMAL ?
  323.                     TWIN_WEIGHT_NORMAL : TWIN_WEIGHT_BOLD;
  324.     face_props_parse (props, toy_face->family);
  325.  
  326.     return CAIRO_STATUS_SUCCESS;
  327. }
  328.  
  329.  
  330. /*
  331.  * Scaled properties
  332.  */
  333.  
  334. typedef struct _twin_scaled_properties {
  335.         twin_face_properties_t *face_props;
  336.  
  337.         cairo_bool_t snap; /* hint outlines */
  338.  
  339.         double weight; /* unhinted pen width */
  340.         double penx, peny; /* hinted pen width */
  341.         double marginl, marginr; /* hinted side margins */
  342.  
  343.         double stretch; /* stretch factor */
  344. } twin_scaled_properties_t;
  345.  
  346. static void
  347. compute_hinting_scale (cairo_t *cr,
  348.                        double x, double y,
  349.                        double *scale, double *inv)
  350. {
  351.     cairo_user_to_device_distance (cr, &x, &y);
  352.     *scale = x == 0 ? y : y == 0 ? x :sqrt (x*x + y*y);
  353.     *inv = 1 / *scale;
  354. }
  355.  
  356. static void
  357. compute_hinting_scales (cairo_t *cr,
  358.                         double *x_scale, double *x_scale_inv,
  359.                         double *y_scale, double *y_scale_inv)
  360. {
  361.     double x, y;
  362.  
  363.     x = 1; y = 0;
  364.     compute_hinting_scale (cr, x, y, x_scale, x_scale_inv);
  365.  
  366.     x = 0; y = 1;
  367.     compute_hinting_scale (cr, x, y, y_scale, y_scale_inv);
  368. }
  369.  
  370. #define SNAPXI(p)       (_cairo_round ((p) * x_scale) * x_scale_inv)
  371. #define SNAPYI(p)       (_cairo_round ((p) * y_scale) * y_scale_inv)
  372.  
  373. /* This controls the global font size */
  374. #define F(g)            ((g) / 72.)
  375.  
  376. static void
  377. twin_hint_pen_and_margins(cairo_t *cr,
  378.                           double *penx, double *peny,
  379.                           double *marginl, double *marginr)
  380. {
  381.     double x_scale, x_scale_inv;
  382.     double y_scale, y_scale_inv;
  383.     double margin;
  384.  
  385.     compute_hinting_scales (cr,
  386.                             &x_scale, &x_scale_inv,
  387.                             &y_scale, &y_scale_inv);
  388.  
  389.     *penx = SNAPXI (*penx);
  390.     if (*penx < x_scale_inv)
  391.         *penx = x_scale_inv;
  392.  
  393.     *peny = SNAPYI (*peny);
  394.     if (*peny < y_scale_inv)
  395.         *peny = y_scale_inv;
  396.  
  397.     margin = *marginl + *marginr;
  398.     *marginl = SNAPXI (*marginl);
  399.     if (*marginl < x_scale_inv)
  400.         *marginl = x_scale_inv;
  401.  
  402.     *marginr = margin - *marginl;
  403.     if (*marginr < 0)
  404.         *marginr = 0;
  405.     *marginr = SNAPXI (*marginr);
  406. }
  407.  
  408. static cairo_status_t
  409. twin_scaled_font_compute_properties (cairo_scaled_font_t *scaled_font,
  410.                                      cairo_t           *cr)
  411. {
  412.     cairo_status_t status;
  413.     twin_scaled_properties_t *props;
  414.  
  415.     props = malloc (sizeof (twin_scaled_properties_t));
  416.     if (unlikely (props == NULL))
  417.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  418.  
  419.  
  420.     props->face_props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
  421.                                                        &twin_properties_key);
  422.  
  423.     props->snap = scaled_font->options.hint_style > CAIRO_HINT_STYLE_NONE;
  424.  
  425.     /* weight */
  426.     props->weight = props->face_props->weight * (F (4) / TWIN_WEIGHT_NORMAL);
  427.  
  428.     /* pen & margins */
  429.     props->penx = props->peny = props->weight;
  430.     props->marginl = props->marginr = F (4);
  431.     if (scaled_font->options.hint_style > CAIRO_HINT_STYLE_SLIGHT)
  432.         twin_hint_pen_and_margins(cr,
  433.                                   &props->penx, &props->peny,
  434.                                   &props->marginl, &props->marginr);
  435.  
  436.     /* stretch */
  437.     props->stretch = 1 + .1 * ((int) props->face_props->stretch - (int) TWIN_STRETCH_NORMAL);
  438.  
  439.  
  440.     /* Save it */
  441.     status = cairo_scaled_font_set_user_data (scaled_font,
  442.                                               &twin_properties_key,
  443.                                               props, free);
  444.     if (unlikely (status))
  445.         goto FREE_PROPS;
  446.  
  447.     return CAIRO_STATUS_SUCCESS;
  448.  
  449. FREE_PROPS:
  450.     free (props);
  451.     return status;
  452. }
  453.  
  454.  
  455. /*
  456.  * User-font implementation
  457.  */
  458.  
  459. static cairo_status_t
  460. twin_scaled_font_init (cairo_scaled_font_t  *scaled_font,
  461.                        cairo_t              *cr,
  462.                        cairo_font_extents_t *metrics)
  463. {
  464.   metrics->ascent  = F (54);
  465.   metrics->descent = 1 - metrics->ascent;
  466.  
  467.   return twin_scaled_font_compute_properties (scaled_font, cr);
  468. }
  469.  
  470. #define TWIN_GLYPH_MAX_SNAP_X 4
  471. #define TWIN_GLYPH_MAX_SNAP_Y 7
  472.  
  473. typedef struct {
  474.     int n_snap_x;
  475.     int8_t snap_x[TWIN_GLYPH_MAX_SNAP_X];
  476.     double snapped_x[TWIN_GLYPH_MAX_SNAP_X];
  477.     int n_snap_y;
  478.     int8_t snap_y[TWIN_GLYPH_MAX_SNAP_Y];
  479.     double snapped_y[TWIN_GLYPH_MAX_SNAP_Y];
  480. } twin_snap_info_t;
  481.  
  482. #define twin_glyph_left(g)      ((g)[0])
  483. #define twin_glyph_right(g)     ((g)[1])
  484. #define twin_glyph_ascent(g)    ((g)[2])
  485. #define twin_glyph_descent(g)   ((g)[3])
  486.  
  487. #define twin_glyph_n_snap_x(g)  ((g)[4])
  488. #define twin_glyph_n_snap_y(g)  ((g)[5])
  489. #define twin_glyph_snap_x(g)    (&g[6])
  490. #define twin_glyph_snap_y(g)    (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
  491. #define twin_glyph_draw(g)      (twin_glyph_snap_y(g) + twin_glyph_n_snap_y(g))
  492.  
  493. static void
  494. twin_compute_snap (cairo_t             *cr,
  495.                    twin_snap_info_t    *info,
  496.                    const signed char   *b)
  497. {
  498.     int                 s, n;
  499.     const signed char   *snap;
  500.     double x_scale, x_scale_inv;
  501.     double y_scale, y_scale_inv;
  502.  
  503.     compute_hinting_scales (cr,
  504.                             &x_scale, &x_scale_inv,
  505.                             &y_scale, &y_scale_inv);
  506.  
  507.     snap = twin_glyph_snap_x (b);
  508.     n = twin_glyph_n_snap_x (b);
  509.     info->n_snap_x = n;
  510.     assert (n <= TWIN_GLYPH_MAX_SNAP_X);
  511.     for (s = 0; s < n; s++) {
  512.         info->snap_x[s] = snap[s];
  513.         info->snapped_x[s] = SNAPXI (F (snap[s]));
  514.     }
  515.  
  516.     snap = twin_glyph_snap_y (b);
  517.     n = twin_glyph_n_snap_y (b);
  518.     info->n_snap_y = n;
  519.     assert (n <= TWIN_GLYPH_MAX_SNAP_Y);
  520.     for (s = 0; s < n; s++) {
  521.         info->snap_y[s] = snap[s];
  522.         info->snapped_y[s] = SNAPYI (F (snap[s]));
  523.     }
  524. }
  525.  
  526. static double
  527. twin_snap (int8_t v, int n, int8_t *snap, double *snapped)
  528. {
  529.     int s;
  530.  
  531.     if (!n)
  532.         return F(v);
  533.  
  534.     if (snap[0] == v)
  535.         return snapped[0];
  536.  
  537.     for (s = 0; s < n - 1; s++)
  538.     {
  539.         if (snap[s+1] == v)
  540.             return snapped[s+1];
  541.  
  542.         if (snap[s] <= v && v <= snap[s+1])
  543.         {
  544.             int before = snap[s];
  545.             int after = snap[s+1];
  546.             int dist = after - before;
  547.             double snap_before = snapped[s];
  548.             double snap_after = snapped[s+1];
  549.             double dist_before = v - before;
  550.             return snap_before + (snap_after - snap_before) * dist_before / dist;
  551.         }
  552.     }
  553.     return F(v);
  554. }
  555.  
  556. #define SNAPX(p)        twin_snap (p, info.n_snap_x, info.snap_x, info.snapped_x)
  557. #define SNAPY(p)        twin_snap (p, info.n_snap_y, info.snap_y, info.snapped_y)
  558.  
  559. static cairo_status_t
  560. twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
  561.                                unsigned long         glyph,
  562.                                cairo_t              *cr,
  563.                                cairo_text_extents_t *metrics)
  564. {
  565.     double x1, y1, x2, y2, x3, y3;
  566.     double marginl;
  567.     twin_scaled_properties_t *props;
  568.     twin_snap_info_t info;
  569.     const int8_t *b;
  570.     const int8_t *g;
  571.     int8_t w;
  572.     double gw;
  573.  
  574.     props = cairo_scaled_font_get_user_data (scaled_font, &twin_properties_key);
  575.  
  576.     /* Save glyph space, we need it when stroking */
  577.     cairo_save (cr);
  578.  
  579.     /* center the pen */
  580.     cairo_translate (cr, props->penx * .5, -props->peny * .5);
  581.  
  582.     /* small-caps */
  583.     if (props->face_props->smallcaps && glyph >= 'a' && glyph <= 'z') {
  584.         glyph += 'A' - 'a';
  585.         /* 28 and 42 are small and capital letter heights of the glyph data */
  586.         cairo_scale (cr, 1, 28. / 42);
  587.     }
  588.  
  589.     /* slant */
  590.     if (props->face_props->slant != CAIRO_FONT_SLANT_NORMAL) {
  591.         cairo_matrix_t shear = { 1, 0, -.2, 1, 0, 0};
  592.         cairo_transform (cr, &shear);
  593.     }
  594.  
  595.     b = _cairo_twin_outlines +
  596.         _cairo_twin_charmap[unlikely (glyph >= ARRAY_LENGTH (_cairo_twin_charmap)) ? 0 : glyph];
  597.     g = twin_glyph_draw(b);
  598.     w = twin_glyph_right(b);
  599.     gw = F(w);
  600.  
  601.     marginl = props->marginl;
  602.  
  603.     /* monospace */
  604.     if (props->face_props->monospace) {
  605.         double monow = F(24);
  606.         double extra =  props->penx + props->marginl + props->marginr;
  607.         cairo_scale (cr, (monow + extra) / (gw + extra), 1);
  608.         gw = monow;
  609.  
  610.         /* resnap margin for new transform */
  611.         {
  612.             double x, y, x_scale, x_scale_inv;
  613.             x = 1; y = 0;
  614.             compute_hinting_scale (cr, x, y, &x_scale, &x_scale_inv);
  615.             marginl = SNAPXI (marginl);
  616.         }
  617.     }
  618.  
  619.     cairo_translate (cr, marginl, 0);
  620.  
  621.     /* stretch */
  622.     cairo_scale (cr, props->stretch, 1);
  623.  
  624.     if (props->snap)
  625.         twin_compute_snap (cr, &info, b);
  626.     else
  627.         info.n_snap_x = info.n_snap_y = 0;
  628.  
  629.     /* advance width */
  630.     metrics->x_advance = gw * props->stretch + props->penx + props->marginl + props->marginr;
  631.  
  632.     /* glyph shape */
  633.     for (;;) {
  634.         switch (*g++) {
  635.         case 'M':
  636.             cairo_close_path (cr);
  637.             /* fall through */
  638.         case 'm':
  639.             x1 = SNAPX(*g++);
  640.             y1 = SNAPY(*g++);
  641.             cairo_move_to (cr, x1, y1);
  642.             continue;
  643.         case 'L':
  644.             cairo_close_path (cr);
  645.             /* fall through */
  646.         case 'l':
  647.             x1 = SNAPX(*g++);
  648.             y1 = SNAPY(*g++);
  649.             cairo_line_to (cr, x1, y1);
  650.             continue;
  651.         case 'C':
  652.             cairo_close_path (cr);
  653.             /* fall through */
  654.         case 'c':
  655.             x1 = SNAPX(*g++);
  656.             y1 = SNAPY(*g++);
  657.             x2 = SNAPX(*g++);
  658.             y2 = SNAPY(*g++);
  659.             x3 = SNAPX(*g++);
  660.             y3 = SNAPY(*g++);
  661.             cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
  662.             continue;
  663.         case 'E':
  664.             cairo_close_path (cr);
  665.             /* fall through */
  666.         case 'e':
  667.             cairo_restore (cr); /* restore glyph space */
  668.             cairo_set_tolerance (cr, 0.01);
  669.             cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
  670.             cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
  671.             cairo_set_line_width (cr, 1);
  672.             cairo_scale (cr, props->penx, props->peny);
  673.             cairo_stroke (cr);
  674.             break;
  675.         case 'X':
  676.             /* filler */
  677.             continue;
  678.         }
  679.         break;
  680.     }
  681.  
  682.     return CAIRO_STATUS_SUCCESS;
  683. }
  684.  
  685. static cairo_status_t
  686. twin_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font,
  687.                                    unsigned long        unicode,
  688.                                    unsigned long       *glyph)
  689. {
  690.     /* We use an identity charmap.  Which means we could live
  691.      * with no unicode_to_glyph method too.  But we define this
  692.      * to map all unknown chars to a single unknown glyph to
  693.      * reduce pressure on cache. */
  694.  
  695.     if (likely (unicode < ARRAY_LENGTH (_cairo_twin_charmap)))
  696.         *glyph = unicode;
  697.     else
  698.         *glyph = 0;
  699.  
  700.     return CAIRO_STATUS_SUCCESS;
  701. }
  702.  
  703.  
  704. /*
  705.  * Face constructor
  706.  */
  707.  
  708. static cairo_font_face_t *
  709. _cairo_font_face_twin_create_internal (void)
  710. {
  711.     cairo_font_face_t *twin_font_face;
  712.  
  713.     twin_font_face = cairo_user_font_face_create ();
  714.     cairo_user_font_face_set_init_func             (twin_font_face, twin_scaled_font_init);
  715.     cairo_user_font_face_set_render_glyph_func     (twin_font_face, twin_scaled_font_render_glyph);
  716.     cairo_user_font_face_set_unicode_to_glyph_func (twin_font_face, twin_scaled_font_unicode_to_glyph);
  717.  
  718.     return twin_font_face;
  719. }
  720.  
  721. cairo_font_face_t *
  722. _cairo_font_face_twin_create_fallback (void)
  723. {
  724.     cairo_font_face_t *twin_font_face;
  725.  
  726.     twin_font_face = _cairo_font_face_twin_create_internal ();
  727.     if (! twin_font_face_create_properties (twin_font_face)) {
  728.         cairo_font_face_destroy (twin_font_face);
  729.         return (cairo_font_face_t *) &_cairo_font_face_nil;
  730.     }
  731.  
  732.     return twin_font_face;
  733. }
  734.  
  735. cairo_status_t
  736. _cairo_font_face_twin_create_for_toy (cairo_toy_font_face_t   *toy_face,
  737.                                       cairo_font_face_t      **font_face)
  738. {
  739.     cairo_status_t status;
  740.     cairo_font_face_t *twin_font_face;
  741.  
  742.     twin_font_face = _cairo_font_face_twin_create_internal ();
  743.     status = twin_font_face_set_properties_from_toy (twin_font_face, toy_face);
  744.     if (status) {
  745.         cairo_font_face_destroy (twin_font_face);
  746.         return status;
  747.     }
  748.  
  749.     *font_face = twin_font_face;
  750.  
  751.     return CAIRO_STATUS_SUCCESS;
  752. }
  753.