LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-font-face-twin.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 251 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 : field_matches (const char *s1,
     162             :                const char *s2,
     163             :                int len)
     164             : {
     165             :   int c1, c2;
     166             : 
     167           0 :   while (len && *s1 && *s2)
     168             :     {
     169             : #define TOLOWER(c) \
     170             :    (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
     171             : 
     172           0 :       c1 = TOLOWER (*s1);
     173           0 :       c2 = TOLOWER (*s2);
     174           0 :       if (c1 != c2) {
     175           0 :         if (c1 == '-') {
     176           0 :           s1++;
     177           0 :           continue;
     178             :         }
     179           0 :         return FALSE;
     180             :       }
     181           0 :       s1++; s2++;
     182           0 :       len--;
     183             :     }
     184             : 
     185           0 :   return len == 0 && *s1 == '\0';
     186             : }
     187             : 
     188             : static cairo_bool_t
     189           0 : parse_int (const char *word,
     190             :            size_t      wordlen,
     191             :            int        *out)
     192             : {
     193             :   char *end;
     194           0 :   long val = strtol (word, &end, 10);
     195           0 :   int i = val;
     196             : 
     197           0 :   if (end != word && (end == word + wordlen) && val >= 0 && val == i)
     198             :     {
     199           0 :       if (out)
     200           0 :         *out = i;
     201             : 
     202           0 :       return TRUE;
     203             :     }
     204             : 
     205           0 :   return FALSE;
     206             : }
     207             : 
     208             : static cairo_bool_t
     209           0 : 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           0 :   cairo_bool_t had_prefix = FALSE;
     218             : 
     219           0 :   if (what)
     220             :     {
     221           0 :       i = strlen (what);
     222           0 :       if (len > i && 0 == strncmp (what, str, i) && str[i] == '=')
     223             :         {
     224           0 :           str += i + 1;
     225           0 :           len -= i + 1;
     226           0 :           had_prefix = TRUE;
     227             :         }
     228             :     }
     229             : 
     230           0 :   for (i=0; i<n_elements; i++)
     231             :     {
     232           0 :       if (map[i].str[0] && field_matches (map[i].str, str, len))
     233             :         {
     234           0 :           if (val)
     235           0 :             *val = map[i].value;
     236           0 :           return TRUE;
     237             :         }
     238             :     }
     239             : 
     240           0 :   if (!what || had_prefix)
     241           0 :     return parse_int (str, len, val);
     242             : 
     243           0 :   return FALSE;
     244             : }
     245             : 
     246             : static void
     247           0 : parse_field (twin_face_properties_t *props,
     248             :              const char *str,
     249             :              int len)
     250             : {
     251           0 :   if (field_matches ("Normal", str, len))
     252           0 :     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           0 :   FIELD (weight);
     260           0 :   FIELD (slant);
     261           0 :   FIELD (stretch);
     262           0 :   FIELD (smallcaps);
     263           0 :   FIELD (monospace);
     264             : 
     265             : #undef FIELD
     266             : }
     267             : 
     268             : static void
     269           0 : face_props_parse (twin_face_properties_t *props,
     270             :              const char *s)
     271             : {
     272             :     const char *start, *end;
     273             : 
     274           0 :     for (start = end = s; *end; end++) {
     275           0 :         if (*end != ' ' && *end != ':')
     276           0 :             continue;
     277             : 
     278           0 :         if (start < end)
     279           0 :                 parse_field (props, start, end - start);
     280           0 :         start = end + 1;
     281             :     }
     282           0 :     if (start < end)
     283           0 :             parse_field (props, start, end - start);
     284           0 : }
     285             : 
     286             : static cairo_status_t
     287           0 : 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           0 :     props = malloc (sizeof (twin_face_properties_t));
     294           0 :     if (unlikely (props == NULL))
     295           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     296             : 
     297           0 :     props->stretch  = TWIN_STRETCH_NORMAL;
     298           0 :     props->slant = CAIRO_FONT_SLANT_NORMAL;
     299           0 :     props->weight = TWIN_WEIGHT_NORMAL;
     300           0 :     props->monospace = FALSE;
     301           0 :     props->smallcaps = FALSE;
     302             : 
     303           0 :     status = cairo_font_face_set_user_data (twin_face,
     304             :                                             &twin_properties_key,
     305             :                                             props, free);
     306           0 :     if (unlikely (status)) {
     307           0 :         free (props);
     308           0 :         return status;
     309             :     }
     310             : 
     311           0 :     if (props_out)
     312           0 :         *props_out = props;
     313             : 
     314           0 :     return CAIRO_STATUS_SUCCESS;
     315             : }
     316             : 
     317             : static cairo_status_t
     318           0 : 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           0 :     status = twin_font_face_create_properties (twin_face, &props);
     325           0 :     if (unlikely (status))
     326           0 :         return status;
     327             : 
     328           0 :     props->slant = toy_face->slant;
     329           0 :     props->weight = toy_face->weight == CAIRO_FONT_WEIGHT_NORMAL ?
     330           0 :                     TWIN_WEIGHT_NORMAL : TWIN_WEIGHT_BOLD;
     331           0 :     face_props_parse (props, toy_face->family);
     332             : 
     333           0 :     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           0 : compute_hinting_scale (cairo_t *cr,
     355             :                        double x, double y,
     356             :                        double *scale, double *inv)
     357             : {
     358           0 :     cairo_user_to_device_distance (cr, &x, &y);
     359           0 :     *scale = x == 0 ? y : y == 0 ? x :sqrt (x*x + y*y);
     360           0 :     *inv = 1 / *scale;
     361           0 : }
     362             : 
     363             : static void
     364           0 : 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           0 :     x = 1; y = 0;
     371           0 :     compute_hinting_scale (cr, x, y, x_scale, x_scale_inv);
     372             : 
     373           0 :     x = 0; y = 1;
     374           0 :     compute_hinting_scale (cr, x, y, y_scale, y_scale_inv);
     375           0 : }
     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           0 : 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           0 :     compute_hinting_scales (cr,
     393             :                             &x_scale, &x_scale_inv,
     394             :                             &y_scale, &y_scale_inv);
     395             : 
     396           0 :     *penx = SNAPXI (*penx);
     397           0 :     if (*penx < x_scale_inv)
     398           0 :         *penx = x_scale_inv;
     399             : 
     400           0 :     *peny = SNAPYI (*peny);
     401           0 :     if (*peny < y_scale_inv)
     402           0 :         *peny = y_scale_inv;
     403             : 
     404           0 :     margin = *marginl + *marginr;
     405           0 :     *marginl = SNAPXI (*marginl);
     406           0 :     if (*marginl < x_scale_inv)
     407           0 :         *marginl = x_scale_inv;
     408             : 
     409           0 :     *marginr = margin - *marginl;
     410           0 :     if (*marginr < 0)
     411           0 :         *marginr = 0;
     412           0 :     *marginr = SNAPXI (*marginr);
     413           0 : }
     414             : 
     415             : static cairo_status_t
     416           0 : 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           0 :     props = malloc (sizeof (twin_scaled_properties_t));
     423           0 :     if (unlikely (props == NULL))
     424           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     425             : 
     426             : 
     427           0 :     props->face_props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
     428             :                                                        &twin_properties_key);
     429             : 
     430           0 :     props->snap = scaled_font->options.hint_style > CAIRO_HINT_STYLE_NONE;
     431             : 
     432             :     /* weight */
     433           0 :     props->weight = props->face_props->weight * (F (4) / TWIN_WEIGHT_NORMAL);
     434             : 
     435             :     /* pen & margins */
     436           0 :     props->penx = props->peny = props->weight;
     437           0 :     props->marginl = props->marginr = F (4);
     438           0 :     if (scaled_font->options.hint_style > CAIRO_HINT_STYLE_SLIGHT)
     439           0 :         twin_hint_pen_and_margins(cr,
     440             :                                   &props->penx, &props->peny,
     441             :                                   &props->marginl, &props->marginr);
     442             : 
     443             :     /* stretch */
     444           0 :     props->stretch = 1 + .1 * ((int) props->face_props->stretch - (int) TWIN_STRETCH_NORMAL);
     445             : 
     446             : 
     447             :     /* Save it */
     448           0 :     status = cairo_scaled_font_set_user_data (scaled_font,
     449             :                                               &twin_properties_key,
     450             :                                               props, free);
     451           0 :     if (unlikely (status))
     452           0 :         goto FREE_PROPS;
     453             : 
     454           0 :     return CAIRO_STATUS_SUCCESS;
     455             : 
     456             : FREE_PROPS:
     457           0 :     free (props);
     458           0 :     return status;
     459             : }
     460             : 
     461             : 
     462             : /*
     463             :  * User-font implementation
     464             :  */
     465             : 
     466             : static cairo_status_t
     467           0 : twin_scaled_font_init (cairo_scaled_font_t  *scaled_font,
     468             :                        cairo_t              *cr,
     469             :                        cairo_font_extents_t *metrics)
     470             : {
     471           0 :   metrics->ascent  = F (54);
     472           0 :   metrics->descent = 1 - metrics->ascent;
     473             : 
     474           0 :   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           0 : 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           0 :     compute_hinting_scales (cr,
     511             :                             &x_scale, &x_scale_inv,
     512             :                             &y_scale, &y_scale_inv);
     513             : 
     514           0 :     snap = twin_glyph_snap_x (b);
     515           0 :     n = twin_glyph_n_snap_x (b);
     516           0 :     info->n_snap_x = n;
     517           0 :     assert (n <= TWIN_GLYPH_MAX_SNAP_X);
     518           0 :     for (s = 0; s < n; s++) {
     519           0 :         info->snap_x[s] = snap[s];
     520           0 :         info->snapped_x[s] = SNAPXI (F (snap[s]));
     521             :     }
     522             : 
     523           0 :     snap = twin_glyph_snap_y (b);
     524           0 :     n = twin_glyph_n_snap_y (b);
     525           0 :     info->n_snap_y = n;
     526           0 :     assert (n <= TWIN_GLYPH_MAX_SNAP_Y);
     527           0 :     for (s = 0; s < n; s++) {
     528           0 :         info->snap_y[s] = snap[s];
     529           0 :         info->snapped_y[s] = SNAPYI (F (snap[s]));
     530             :     }
     531           0 : }
     532             : 
     533             : static double
     534           0 : twin_snap (int8_t v, int n, int8_t *snap, double *snapped)
     535             : {
     536             :     int s;
     537             : 
     538           0 :     if (!n)
     539           0 :         return F(v);
     540             : 
     541           0 :     if (snap[0] == v)
     542           0 :         return snapped[0];
     543             : 
     544           0 :     for (s = 0; s < n - 1; s++)
     545             :     {
     546           0 :         if (snap[s+1] == v)
     547           0 :             return snapped[s+1];
     548             : 
     549           0 :         if (snap[s] <= v && v <= snap[s+1])
     550             :         {
     551           0 :             int before = snap[s];
     552           0 :             int after = snap[s+1];
     553           0 :             int dist = after - before;
     554           0 :             double snap_before = snapped[s];
     555           0 :             double snap_after = snapped[s+1];
     556           0 :             double dist_before = v - before;
     557           0 :             return snap_before + (snap_after - snap_before) * dist_before / dist;
     558             :         }
     559             :     }
     560           0 :     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           0 : 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           0 :     props = cairo_scaled_font_get_user_data (scaled_font, &twin_properties_key);
     582             : 
     583             :     /* Save glyph space, we need it when stroking */
     584           0 :     cairo_save (cr);
     585             : 
     586             :     /* center the pen */
     587           0 :     cairo_translate (cr, props->penx * .5, -props->peny * .5);
     588             : 
     589             :     /* small-caps */
     590           0 :     if (props->face_props->smallcaps && glyph >= 'a' && glyph <= 'z') {
     591           0 :         glyph += 'A' - 'a';
     592             :         /* 28 and 42 are small and capital letter heights of the glyph data */
     593           0 :         cairo_scale (cr, 1, 28. / 42);
     594             :     }
     595             : 
     596             :     /* slant */
     597           0 :     if (props->face_props->slant != CAIRO_FONT_SLANT_NORMAL) {
     598           0 :         cairo_matrix_t shear = { 1, 0, -.2, 1, 0, 0};
     599           0 :         cairo_transform (cr, &shear);
     600             :     }
     601             : 
     602           0 :     b = _cairo_twin_outlines +
     603           0 :         _cairo_twin_charmap[unlikely (glyph >= ARRAY_LENGTH (_cairo_twin_charmap)) ? 0 : glyph];
     604           0 :     g = twin_glyph_draw(b);
     605           0 :     w = twin_glyph_right(b);
     606           0 :     gw = F(w);
     607             : 
     608           0 :     marginl = props->marginl;
     609             : 
     610             :     /* monospace */
     611           0 :     if (props->face_props->monospace) {
     612           0 :         double monow = F(24);
     613           0 :         double extra =  props->penx + props->marginl + props->marginr;
     614           0 :         cairo_scale (cr, (monow + extra) / (gw + extra), 1);
     615           0 :         gw = monow;
     616             : 
     617             :         /* resnap margin for new transform */
     618             :         {
     619             :             double x, y, x_scale, x_scale_inv;
     620           0 :             x = 1; y = 0;
     621           0 :             compute_hinting_scale (cr, x, y, &x_scale, &x_scale_inv);
     622           0 :             marginl = SNAPXI (marginl);
     623             :         }
     624             :     }
     625             : 
     626           0 :     cairo_translate (cr, marginl, 0);
     627             : 
     628             :     /* stretch */
     629           0 :     cairo_scale (cr, props->stretch, 1);
     630             : 
     631           0 :     if (props->snap)
     632           0 :         twin_compute_snap (cr, &info, b);
     633             :     else
     634           0 :         info.n_snap_x = info.n_snap_y = 0;
     635             : 
     636             :     /* advance width */
     637           0 :     metrics->x_advance = gw * props->stretch + props->penx + props->marginl + props->marginr;
     638             : 
     639             :     /* glyph shape */
     640             :     for (;;) {
     641           0 :         switch (*g++) {
     642             :         case 'M':
     643           0 :             cairo_close_path (cr);
     644             :             /* fall through */
     645             :         case 'm':
     646           0 :             x1 = SNAPX(*g++);
     647           0 :             y1 = SNAPY(*g++);
     648           0 :             cairo_move_to (cr, x1, y1);
     649           0 :             continue;
     650             :         case 'L':
     651           0 :             cairo_close_path (cr);
     652             :             /* fall through */
     653             :         case 'l':
     654           0 :             x1 = SNAPX(*g++);
     655           0 :             y1 = SNAPY(*g++);
     656           0 :             cairo_line_to (cr, x1, y1);
     657           0 :             continue;
     658             :         case 'C':
     659           0 :             cairo_close_path (cr);
     660             :             /* fall through */
     661             :         case 'c':
     662           0 :             x1 = SNAPX(*g++);
     663           0 :             y1 = SNAPY(*g++);
     664           0 :             x2 = SNAPX(*g++);
     665           0 :             y2 = SNAPY(*g++);
     666           0 :             x3 = SNAPX(*g++);
     667           0 :             y3 = SNAPY(*g++);
     668           0 :             cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
     669           0 :             continue;
     670             :         case 'E':
     671           0 :             cairo_close_path (cr);
     672             :             /* fall through */
     673             :         case 'e':
     674           0 :             cairo_restore (cr); /* restore glyph space */
     675           0 :             cairo_set_tolerance (cr, 0.01);
     676           0 :             cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
     677           0 :             cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
     678           0 :             cairo_set_line_width (cr, 1);
     679           0 :             cairo_scale (cr, props->penx, props->peny);
     680           0 :             cairo_stroke (cr);
     681           0 :             break;
     682             :         case 'X':
     683             :             /* filler */
     684           0 :             continue;
     685             :         }
     686           0 :         break;
     687             :     }
     688             : 
     689           0 :     return CAIRO_STATUS_SUCCESS;
     690             : }
     691             : 
     692             : static cairo_status_t
     693           0 : 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           0 :     if (likely (unicode < ARRAY_LENGTH (_cairo_twin_charmap)))
     703           0 :         *glyph = unicode;
     704             :     else
     705           0 :         *glyph = 0;
     706             : 
     707           0 :     return CAIRO_STATUS_SUCCESS;
     708             : }
     709             : 
     710             : 
     711             : /*
     712             :  * Face constructor
     713             :  */
     714             : 
     715             : static cairo_font_face_t *
     716           0 : _cairo_font_face_twin_create_internal (void)
     717             : {
     718             :     cairo_font_face_t *twin_font_face;
     719             : 
     720           0 :     twin_font_face = cairo_user_font_face_create ();
     721           0 :     cairo_user_font_face_set_init_func             (twin_font_face, twin_scaled_font_init);
     722           0 :     cairo_user_font_face_set_render_glyph_func     (twin_font_face, twin_scaled_font_render_glyph);
     723           0 :     cairo_user_font_face_set_unicode_to_glyph_func (twin_font_face, twin_scaled_font_unicode_to_glyph);
     724             : 
     725           0 :     return twin_font_face;
     726             : }
     727             : 
     728             : cairo_font_face_t *
     729           0 : _cairo_font_face_twin_create_fallback (void)
     730             : {
     731             :     cairo_font_face_t *twin_font_face;
     732             :     cairo_status_t status;
     733             : 
     734           0 :     twin_font_face = _cairo_font_face_twin_create_internal ();
     735           0 :     status = twin_font_face_create_properties (twin_font_face, NULL);
     736           0 :     if (status) {
     737           0 :         cairo_font_face_destroy (twin_font_face);
     738           0 :         return (cairo_font_face_t *) &_cairo_font_face_nil;
     739             :     }
     740             : 
     741           0 :     return twin_font_face;
     742             : }
     743             : 
     744             : cairo_status_t
     745           0 : _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           0 :     twin_font_face = _cairo_font_face_twin_create_internal ();
     752           0 :     status = twin_font_face_set_properties_from_toy (twin_font_face, toy_face);
     753           0 :     if (status) {
     754           0 :         cairo_font_face_destroy (twin_font_face);
     755           0 :         return status;
     756             :     }
     757             : 
     758           0 :     *font_face = twin_font_face;
     759             : 
     760           0 :     return CAIRO_STATUS_SUCCESS;
     761             : }

Generated by: LCOV version 1.13