Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | 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 cairo_status_t
  287. twin_font_face_create_properties (cairo_font_face_t *twin_face,
  288.                                   twin_face_properties_t **props_out)
  289. {
  290.     twin_face_properties_t *props;
  291.     cairo_status_t status;
  292.  
  293.     props = malloc (sizeof (twin_face_properties_t));
  294.     if (unlikely (props == NULL))
  295.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  296.  
  297.     props->stretch  = TWIN_STRETCH_NORMAL;
  298.     props->slant = CAIRO_FONT_SLANT_NORMAL;
  299.     props->weight = TWIN_WEIGHT_NORMAL;
  300.     props->monospace = FALSE;
  301.     props->smallcaps = FALSE;
  302.  
  303.     status = cairo_font_face_set_user_data (twin_face,
  304.                                             &twin_properties_key,
  305.                                             props, free);
  306.     if (unlikely (status)) {
  307.         free (props);
  308.         return status;
  309.     }
  310.  
  311.     if (props_out)
  312.         *props_out = props;
  313.  
  314.     return CAIRO_STATUS_SUCCESS;
  315. }
  316.  
  317. static cairo_status_t
  318. twin_font_face_set_properties_from_toy (cairo_font_face_t *twin_face,
  319.                                         cairo_toy_font_face_t *toy_face)
  320. {
  321.     cairo_status_t status;
  322.     twin_face_properties_t *props;
  323.  
  324.     status = twin_font_face_create_properties (twin_face, &props);
  325.     if (unlikely (status))
  326.         return status;
  327.  
  328.     props->slant = toy_face->slant;
  329.     props->weight = toy_face->weight == CAIRO_FONT_WEIGHT_NORMAL ?
  330.                     TWIN_WEIGHT_NORMAL : TWIN_WEIGHT_BOLD;
  331.     face_props_parse (props, toy_face->family);
  332.  
  333.     return CAIRO_STATUS_SUCCESS;
  334. }
  335.  
  336.  
  337. /*
  338.  * Scaled properties
  339.  */
  340.  
  341. typedef struct _twin_scaled_properties {
  342.         twin_face_properties_t *face_props;
  343.  
  344.         cairo_bool_t snap; /* hint outlines */
  345.  
  346.         double weight; /* unhinted pen width */
  347.         double penx, peny; /* hinted pen width */
  348.         double marginl, marginr; /* hinted side margins */
  349.  
  350.         double stretch; /* stretch factor */
  351. } twin_scaled_properties_t;
  352.  
  353. static void
  354. compute_hinting_scale (cairo_t *cr,
  355.                        double x, double y,
  356.                        double *scale, double *inv)
  357. {
  358.     cairo_user_to_device_distance (cr, &x, &y);
  359.     *scale = x == 0 ? y : y == 0 ? x :sqrt (x*x + y*y);
  360.     *inv = 1 / *scale;
  361. }
  362.  
  363. static void
  364. compute_hinting_scales (cairo_t *cr,
  365.                         double *x_scale, double *x_scale_inv,
  366.                         double *y_scale, double *y_scale_inv)
  367. {
  368.     double x, y;
  369.  
  370.     x = 1; y = 0;
  371.     compute_hinting_scale (cr, x, y, x_scale, x_scale_inv);
  372.  
  373.     x = 0; y = 1;
  374.     compute_hinting_scale (cr, x, y, y_scale, y_scale_inv);
  375. }
  376.  
  377. #define SNAPXI(p)       (_cairo_round ((p) * x_scale) * x_scale_inv)
  378. #define SNAPYI(p)       (_cairo_round ((p) * y_scale) * y_scale_inv)
  379.  
  380. /* This controls the global font size */
  381. #define F(g)            ((g) / 72.)
  382.  
  383. static void
  384. twin_hint_pen_and_margins(cairo_t *cr,
  385.                           double *penx, double *peny,
  386.                           double *marginl, double *marginr)
  387. {
  388.     double x_scale, x_scale_inv;
  389.     double y_scale, y_scale_inv;
  390.     double margin;
  391.  
  392.     compute_hinting_scales (cr,
  393.                             &x_scale, &x_scale_inv,
  394.                             &y_scale, &y_scale_inv);
  395.  
  396.     *penx = SNAPXI (*penx);
  397.     if (*penx < x_scale_inv)
  398.         *penx = x_scale_inv;
  399.  
  400.     *peny = SNAPYI (*peny);
  401.     if (*peny < y_scale_inv)
  402.         *peny = y_scale_inv;
  403.  
  404.     margin = *marginl + *marginr;
  405.     *marginl = SNAPXI (*marginl);
  406.     if (*marginl < x_scale_inv)
  407.         *marginl = x_scale_inv;
  408.  
  409.     *marginr = margin - *marginl;
  410.     if (*marginr < 0)
  411.         *marginr = 0;
  412.     *marginr = SNAPXI (*marginr);
  413. }
  414.  
  415. static cairo_status_t
  416. twin_scaled_font_compute_properties (cairo_scaled_font_t *scaled_font,
  417.                                      cairo_t           *cr)
  418. {
  419.     cairo_status_t status;
  420.     twin_scaled_properties_t *props;
  421.  
  422.     props = malloc (sizeof (twin_scaled_properties_t));
  423.     if (unlikely (props == NULL))
  424.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  425.  
  426.  
  427.     props->face_props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
  428.                                                        &twin_properties_key);
  429.  
  430.     props->snap = scaled_font->options.hint_style > CAIRO_HINT_STYLE_NONE;
  431.  
  432.     /* weight */
  433.     props->weight = props->face_props->weight * (F (4) / TWIN_WEIGHT_NORMAL);
  434.  
  435.     /* pen & margins */
  436.     props->penx = props->peny = props->weight;
  437.     props->marginl = props->marginr = F (4);
  438.     if (scaled_font->options.hint_style > CAIRO_HINT_STYLE_SLIGHT)
  439.         twin_hint_pen_and_margins(cr,
  440.                                   &props->penx, &props->peny,
  441.                                   &props->marginl, &props->marginr);
  442.  
  443.     /* stretch */
  444.     props->stretch = 1 + .1 * ((int) props->face_props->stretch - (int) TWIN_STRETCH_NORMAL);
  445.  
  446.  
  447.     /* Save it */
  448.     status = cairo_scaled_font_set_user_data (scaled_font,
  449.                                               &twin_properties_key,
  450.                                               props, free);
  451.     if (unlikely (status))
  452.         goto FREE_PROPS;
  453.  
  454.     return CAIRO_STATUS_SUCCESS;
  455.  
  456. FREE_PROPS:
  457.     free (props);
  458.     return status;
  459. }
  460.  
  461.  
  462. /*
  463.  * User-font implementation
  464.  */
  465.  
  466. static cairo_status_t
  467. twin_scaled_font_init (cairo_scaled_font_t  *scaled_font,
  468.                        cairo_t              *cr,
  469.                        cairo_font_extents_t *metrics)
  470. {
  471.   metrics->ascent  = F (54);
  472.   metrics->descent = 1 - metrics->ascent;
  473.  
  474.   return twin_scaled_font_compute_properties (scaled_font, cr);
  475. }
  476.  
  477. #define TWIN_GLYPH_MAX_SNAP_X 4
  478. #define TWIN_GLYPH_MAX_SNAP_Y 7
  479.  
  480. typedef struct {
  481.     int n_snap_x;
  482.     int8_t snap_x[TWIN_GLYPH_MAX_SNAP_X];
  483.     double snapped_x[TWIN_GLYPH_MAX_SNAP_X];
  484.     int n_snap_y;
  485.     int8_t snap_y[TWIN_GLYPH_MAX_SNAP_Y];
  486.     double snapped_y[TWIN_GLYPH_MAX_SNAP_Y];
  487. } twin_snap_info_t;
  488.  
  489. #define twin_glyph_left(g)      ((g)[0])
  490. #define twin_glyph_right(g)     ((g)[1])
  491. #define twin_glyph_ascent(g)    ((g)[2])
  492. #define twin_glyph_descent(g)   ((g)[3])
  493.  
  494. #define twin_glyph_n_snap_x(g)  ((g)[4])
  495. #define twin_glyph_n_snap_y(g)  ((g)[5])
  496. #define twin_glyph_snap_x(g)    (&g[6])
  497. #define twin_glyph_snap_y(g)    (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
  498. #define twin_glyph_draw(g)      (twin_glyph_snap_y(g) + twin_glyph_n_snap_y(g))
  499.  
  500. static void
  501. twin_compute_snap (cairo_t             *cr,
  502.                    twin_snap_info_t    *info,
  503.                    const signed char   *b)
  504. {
  505.     int                 s, n;
  506.     const signed char   *snap;
  507.     double x_scale, x_scale_inv;
  508.     double y_scale, y_scale_inv;
  509.  
  510.     compute_hinting_scales (cr,
  511.                             &x_scale, &x_scale_inv,
  512.                             &y_scale, &y_scale_inv);
  513.  
  514.     snap = twin_glyph_snap_x (b);
  515.     n = twin_glyph_n_snap_x (b);
  516.     info->n_snap_x = n;
  517.     assert (n <= TWIN_GLYPH_MAX_SNAP_X);
  518.     for (s = 0; s < n; s++) {
  519.         info->snap_x[s] = snap[s];
  520.         info->snapped_x[s] = SNAPXI (F (snap[s]));
  521.     }
  522.  
  523.     snap = twin_glyph_snap_y (b);
  524.     n = twin_glyph_n_snap_y (b);
  525.     info->n_snap_y = n;
  526.     assert (n <= TWIN_GLYPH_MAX_SNAP_Y);
  527.     for (s = 0; s < n; s++) {
  528.         info->snap_y[s] = snap[s];
  529.         info->snapped_y[s] = SNAPYI (F (snap[s]));
  530.     }
  531. }
  532.  
  533. static double
  534. twin_snap (int8_t v, int n, int8_t *snap, double *snapped)
  535. {
  536.     int s;
  537.  
  538.     if (!n)
  539.         return F(v);
  540.  
  541.     if (snap[0] == v)
  542.         return snapped[0];
  543.  
  544.     for (s = 0; s < n - 1; s++)
  545.     {
  546.         if (snap[s+1] == v)
  547.             return snapped[s+1];
  548.  
  549.         if (snap[s] <= v && v <= snap[s+1])
  550.         {
  551.             int before = snap[s];
  552.             int after = snap[s+1];
  553.             int dist = after - before;
  554.             double snap_before = snapped[s];
  555.             double snap_after = snapped[s+1];
  556.             double dist_before = v - before;
  557.             return snap_before + (snap_after - snap_before) * dist_before / dist;
  558.         }
  559.     }
  560.     return F(v);
  561. }
  562.  
  563. #define SNAPX(p)        twin_snap (p, info.n_snap_x, info.snap_x, info.snapped_x)
  564. #define SNAPY(p)        twin_snap (p, info.n_snap_y, info.snap_y, info.snapped_y)
  565.  
  566. static cairo_status_t
  567. twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
  568.                                unsigned long         glyph,
  569.                                cairo_t              *cr,
  570.                                cairo_text_extents_t *metrics)
  571. {
  572.     double x1, y1, x2, y2, x3, y3;
  573.     double marginl;
  574.     twin_scaled_properties_t *props;
  575.     twin_snap_info_t info;
  576.     const int8_t *b;
  577.     const int8_t *g;
  578.     int8_t w;
  579.     double gw;
  580.  
  581.     props = cairo_scaled_font_get_user_data (scaled_font, &twin_properties_key);
  582.  
  583.     /* Save glyph space, we need it when stroking */
  584.     cairo_save (cr);
  585.  
  586.     /* center the pen */
  587.     cairo_translate (cr, props->penx * .5, -props->peny * .5);
  588.  
  589.     /* small-caps */
  590.     if (props->face_props->smallcaps && glyph >= 'a' && glyph <= 'z') {
  591.         glyph += 'A' - 'a';
  592.         /* 28 and 42 are small and capital letter heights of the glyph data */
  593.         cairo_scale (cr, 1, 28. / 42);
  594.     }
  595.  
  596.     /* slant */
  597.     if (props->face_props->slant != CAIRO_FONT_SLANT_NORMAL) {
  598.         cairo_matrix_t shear = { 1, 0, -.2, 1, 0, 0};
  599.         cairo_transform (cr, &shear);
  600.     }
  601.  
  602.     b = _cairo_twin_outlines +
  603.         _cairo_twin_charmap[unlikely (glyph >= ARRAY_LENGTH (_cairo_twin_charmap)) ? 0 : glyph];
  604.     g = twin_glyph_draw(b);
  605.     w = twin_glyph_right(b);
  606.     gw = F(w);
  607.  
  608.     marginl = props->marginl;
  609.  
  610.     /* monospace */
  611.     if (props->face_props->monospace) {
  612.         double monow = F(24);
  613.         double extra =  props->penx + props->marginl + props->marginr;
  614.         cairo_scale (cr, (monow + extra) / (gw + extra), 1);
  615.         gw = monow;
  616.  
  617.         /* resnap margin for new transform */
  618.         {
  619.             double x, y, x_scale, x_scale_inv;
  620.             x = 1; y = 0;
  621.             compute_hinting_scale (cr, x, y, &x_scale, &x_scale_inv);
  622.             marginl = SNAPXI (marginl);
  623.         }
  624.     }
  625.  
  626.     cairo_translate (cr, marginl, 0);
  627.  
  628.     /* stretch */
  629.     cairo_scale (cr, props->stretch, 1);
  630.  
  631.     if (props->snap)
  632.         twin_compute_snap (cr, &info, b);
  633.     else
  634.         info.n_snap_x = info.n_snap_y = 0;
  635.  
  636.     /* advance width */
  637.     metrics->x_advance = gw * props->stretch + props->penx + props->marginl + props->marginr;
  638.  
  639.     /* glyph shape */
  640.     for (;;) {
  641.         switch (*g++) {
  642.         case 'M':
  643.             cairo_close_path (cr);
  644.             /* fall through */
  645.         case 'm':
  646.             x1 = SNAPX(*g++);
  647.             y1 = SNAPY(*g++);
  648.             cairo_move_to (cr, x1, y1);
  649.             continue;
  650.         case 'L':
  651.             cairo_close_path (cr);
  652.             /* fall through */
  653.         case 'l':
  654.             x1 = SNAPX(*g++);
  655.             y1 = SNAPY(*g++);
  656.             cairo_line_to (cr, x1, y1);
  657.             continue;
  658.         case 'C':
  659.             cairo_close_path (cr);
  660.             /* fall through */
  661.         case 'c':
  662.             x1 = SNAPX(*g++);
  663.             y1 = SNAPY(*g++);
  664.             x2 = SNAPX(*g++);
  665.             y2 = SNAPY(*g++);
  666.             x3 = SNAPX(*g++);
  667.             y3 = SNAPY(*g++);
  668.             cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
  669.             continue;
  670.         case 'E':
  671.             cairo_close_path (cr);
  672.             /* fall through */
  673.         case 'e':
  674.             cairo_restore (cr); /* restore glyph space */
  675.             cairo_set_tolerance (cr, 0.01);
  676.             cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
  677.             cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
  678.             cairo_set_line_width (cr, 1);
  679.             cairo_scale (cr, props->penx, props->peny);
  680.             cairo_stroke (cr);
  681.             break;
  682.         case 'X':
  683.             /* filler */
  684.             continue;
  685.         }
  686.         break;
  687.     }
  688.  
  689.     return CAIRO_STATUS_SUCCESS;
  690. }
  691.  
  692. static cairo_status_t
  693. twin_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font,
  694.                                    unsigned long        unicode,
  695.                                    unsigned long       *glyph)
  696. {
  697.     /* We use an identity charmap.  Which means we could live
  698.      * with no unicode_to_glyph method too.  But we define this
  699.      * to map all unknown chars to a single unknown glyph to
  700.      * reduce pressure on cache. */
  701.  
  702.     if (likely (unicode < ARRAY_LENGTH (_cairo_twin_charmap)))
  703.         *glyph = unicode;
  704.     else
  705.         *glyph = 0;
  706.  
  707.     return CAIRO_STATUS_SUCCESS;
  708. }
  709.  
  710.  
  711. /*
  712.  * Face constructor
  713.  */
  714.  
  715. static cairo_font_face_t *
  716. _cairo_font_face_twin_create_internal (void)
  717. {
  718.     cairo_font_face_t *twin_font_face;
  719.  
  720.     twin_font_face = cairo_user_font_face_create ();
  721.     cairo_user_font_face_set_init_func             (twin_font_face, twin_scaled_font_init);
  722.     cairo_user_font_face_set_render_glyph_func     (twin_font_face, twin_scaled_font_render_glyph);
  723.     cairo_user_font_face_set_unicode_to_glyph_func (twin_font_face, twin_scaled_font_unicode_to_glyph);
  724.  
  725.     return twin_font_face;
  726. }
  727.  
  728. cairo_font_face_t *
  729. _cairo_font_face_twin_create_fallback (void)
  730. {
  731.     cairo_font_face_t *twin_font_face;
  732.     cairo_status_t status;
  733.  
  734.     twin_font_face = _cairo_font_face_twin_create_internal ();
  735.     status = twin_font_face_create_properties (twin_font_face, NULL);
  736.     if (status) {
  737.         cairo_font_face_destroy (twin_font_face);
  738.         return (cairo_font_face_t *) &_cairo_font_face_nil;
  739.     }
  740.  
  741.     return twin_font_face;
  742. }
  743.  
  744. cairo_status_t
  745. _cairo_font_face_twin_create_for_toy (cairo_toy_font_face_t   *toy_face,
  746.                                       cairo_font_face_t      **font_face)
  747. {
  748.     cairo_status_t status;
  749.     cairo_font_face_t *twin_font_face;
  750.  
  751.     twin_font_face = _cairo_font_face_twin_create_internal ();
  752.     status = twin_font_face_set_properties_from_toy (twin_font_face, toy_face);
  753.     if (status) {
  754.         cairo_font_face_destroy (twin_font_face);
  755.         return status;
  756.     }
  757.  
  758.     *font_face = twin_font_face;
  759.  
  760.     return CAIRO_STATUS_SUCCESS;
  761. }
  762.