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