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 : }
|