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