LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-font-face-twin.c (source / functions) Found Hit Coverage
Test: app.info Lines: 250 0 0.0 %
Date: 2012-06-02 Functions: 19 0 0.0 %

       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                 :                     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                 :         break;
     687               0 :     }
     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.7