Subversion Repositories Scribus

Rev

Rev 14952 | Details | Compare with Previous | Last modification | View Log | RSS feed

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