Changes.
[cairo/gpu.git] / src / cairo-font-face-twin.c
blob3f82733245ad7a3bb0fd80390b4a253ff6bd1764
1 /*
2 * Copyright © 2004 Keith Packard
3 * Copyright © 2008 Red Hat, Inc.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
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/
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.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is Keith Packard
32 * Contributor(s):
33 * Keith Packard <keithp@keithp.com>
34 * Behdad Esfahbod <behdad@behdad.org>
37 #include "cairoint.h"
39 #include <math.h>
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
46 * Ported to cairo user font and extended by Behdad Esfahbod.
51 static cairo_user_data_key_t twin_properties_key;
55 * Face properties
58 /* We synthesize multiple faces from the twin data. Here is the parameters. */
60 /* The following tables and matching code are copied from Pango */
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;
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;
90 typedef struct
92 int value;
93 const char str[16];
94 } FieldMap;
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" }
103 static const FieldMap smallcaps_map[] = {
104 { FALSE, "" },
105 { TRUE, "Small-Caps" }
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" }
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" }
142 static const FieldMap monospace_map[] = {
143 { FALSE, "" },
144 { TRUE, "Mono" },
145 { TRUE, "Monospace" }
149 typedef struct _twin_face_properties {
150 cairo_font_slant_t slant;
151 twin_face_weight_t weight;
152 twin_face_stretch_t stretch;
154 /* lets have some fun */
155 cairo_bool_t monospace;
156 cairo_bool_t smallcaps;
157 } twin_face_properties_t;
159 static cairo_bool_t
160 field_matches (const char *s1,
161 const char *s2,
162 int len)
164 int c1, c2;
166 while (len && *s1 && *s2)
168 #define TOLOWER(c) \
169 (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
171 c1 = TOLOWER (*s1);
172 c2 = TOLOWER (*s2);
173 if (c1 != c2) {
174 if (c1 == '-') {
175 s1++;
176 continue;
178 return FALSE;
180 s1++; s2++;
181 len--;
184 return len == 0 && *s1 == '\0';
187 static cairo_bool_t
188 parse_int (const char *word,
189 size_t wordlen,
190 int *out)
192 char *end;
193 long val = strtol (word, &end, 10);
194 int i = val;
196 if (end != word && (end == word + wordlen) && val >= 0 && val == i)
198 if (out)
199 *out = i;
201 return TRUE;
204 return FALSE;
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)
215 int i;
216 cairo_bool_t had_prefix = FALSE;
218 if (what)
220 i = strlen (what);
221 if (len > i && 0 == strncmp (what, str, i) && str[i] == '=')
223 str += i + 1;
224 len -= i + 1;
225 had_prefix = TRUE;
229 for (i=0; i<n_elements; i++)
231 if (map[i].str[0] && field_matches (map[i].str, str, len))
233 if (val)
234 *val = map[i].value;
235 return TRUE;
239 if (!what || had_prefix)
240 return parse_int (str, len, val);
242 return FALSE;
245 static void
246 parse_field (twin_face_properties_t *props,
247 const char *str,
248 int len)
250 if (field_matches ("Normal", str, len))
251 return;
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; \
258 FIELD (weight);
259 FIELD (slant);
260 FIELD (stretch);
261 FIELD (smallcaps);
262 FIELD (monospace);
264 #undef FIELD
267 static void
268 face_props_parse (twin_face_properties_t *props,
269 const char *s)
271 const char *start, *end;
273 for (start = end = s; *end; end++) {
274 if (*end != ' ' && *end != ':')
275 continue;
277 if (start < end)
278 parse_field (props, start, end - start);
279 start = end + 1;
281 if (start < end)
282 parse_field (props, start, end - start);
285 static cairo_status_t
286 twin_font_face_create_properties (cairo_font_face_t *twin_face,
287 twin_face_properties_t **props_out)
289 twin_face_properties_t *props;
290 cairo_status_t status;
292 props = malloc (sizeof (twin_face_properties_t));
293 if (unlikely (props == NULL))
294 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
296 props->stretch = TWIN_STRETCH_NORMAL;
297 props->monospace = FALSE;
298 props->smallcaps = FALSE;
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;
308 if (props_out)
309 *props_out = props;
311 return CAIRO_STATUS_SUCCESS;
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)
318 cairo_status_t status;
319 twin_face_properties_t *props;
321 status = twin_font_face_create_properties (twin_face, &props);
322 if (unlikely (status))
323 return status;
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);
330 return CAIRO_STATUS_SUCCESS;
335 * Scaled properties
338 typedef struct _twin_scaled_properties {
339 twin_face_properties_t *face_props;
341 cairo_bool_t snap; /* hint outlines */
343 double weight; /* unhinted pen width */
344 double penx, peny; /* hinted pen width */
345 double marginl, marginr; /* hinted side margins */
347 double stretch; /* stretch factor */
348 } twin_scaled_properties_t;
350 static void
351 compute_hinting_scale (cairo_t *cr,
352 double x, double y,
353 double *scale, double *inv)
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;
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)
365 double x, y;
367 x = 1; y = 0;
368 compute_hinting_scale (cr, x, y, x_scale, x_scale_inv);
370 x = 0; y = 1;
371 compute_hinting_scale (cr, x, y, y_scale, y_scale_inv);
374 #define SNAPXI(p) (_cairo_round ((p) * x_scale) * x_scale_inv)
375 #define SNAPYI(p) (_cairo_round ((p) * y_scale) * y_scale_inv)
377 /* This controls the global font size */
378 #define F(g) ((g) / 72.)
380 static void
381 twin_hint_pen_and_margins(cairo_t *cr,
382 double *penx, double *peny,
383 double *marginl, double *marginr)
385 double x_scale, x_scale_inv;
386 double y_scale, y_scale_inv;
387 double margin;
389 compute_hinting_scales (cr,
390 &x_scale, &x_scale_inv,
391 &y_scale, &y_scale_inv);
393 *penx = SNAPXI (*penx);
394 if (*penx < x_scale_inv)
395 *penx = x_scale_inv;
397 *peny = SNAPYI (*peny);
398 if (*peny < y_scale_inv)
399 *peny = y_scale_inv;
401 margin = *marginl + *marginr;
402 *marginl = SNAPXI (*marginl);
403 if (*marginl < x_scale_inv)
404 *marginl = x_scale_inv;
406 *marginr = margin - *marginl;
407 if (*marginr < 0)
408 *marginr = 0;
409 *marginr = SNAPXI (*marginr);
412 static cairo_status_t
413 twin_scaled_font_compute_properties (cairo_scaled_font_t *scaled_font,
414 cairo_t *cr)
416 cairo_status_t status;
417 twin_scaled_properties_t *props;
419 props = malloc (sizeof (twin_scaled_properties_t));
420 if (unlikely (props == NULL))
421 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
424 props->face_props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
425 &twin_properties_key);
427 props->snap = scaled_font->options.hint_style > CAIRO_HINT_STYLE_NONE;
429 /* weight */
430 props->weight = props->face_props->weight * (F (4) / TWIN_WEIGHT_NORMAL);
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);
440 /* stretch */
441 props->stretch = 1 + .1 * ((int) props->face_props->stretch - (int) TWIN_STRETCH_NORMAL);
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;
451 return CAIRO_STATUS_SUCCESS;
453 FREE_PROPS:
454 free (props);
455 return status;
460 * User-font implementation
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)
468 metrics->ascent = F (54);
469 metrics->descent = 1 - metrics->ascent;
471 return twin_scaled_font_compute_properties (scaled_font, cr);
474 #define TWIN_GLYPH_MAX_SNAP_X 4
475 #define TWIN_GLYPH_MAX_SNAP_Y 7
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;
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])
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))
497 static void
498 twin_compute_snap (cairo_t *cr,
499 twin_snap_info_t *info,
500 const signed char *b)
502 int s, n;
503 const signed char *snap;
504 double x_scale, x_scale_inv;
505 double y_scale, y_scale_inv;
507 compute_hinting_scales (cr,
508 &x_scale, &x_scale_inv,
509 &y_scale, &y_scale_inv);
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]));
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]));
530 static double
531 twin_snap (int8_t v, int n, int8_t *snap, double *snapped)
533 int s;
535 if (!n)
536 return F(v);
538 if (snap[0] == v)
539 return snapped[0];
541 for (s = 0; s < n - 1; s++)
543 if (snap[s+1] == v)
544 return snapped[s+1];
546 if (snap[s] <= v && v <= snap[s+1])
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;
557 return F(v);
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)
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)
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;
578 props = cairo_scaled_font_get_user_data (scaled_font, &twin_properties_key);
580 /* Save glyph space, we need it when stroking */
581 cairo_save (cr);
583 /* center the pen */
584 cairo_translate (cr, props->penx * .5, -props->peny * .5);
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);
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);
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);
605 marginl = props->marginl;
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;
614 /* resnap margin for new transform */
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);
623 cairo_translate (cr, marginl, 0);
625 /* stretch */
626 cairo_scale (cr, props->stretch, 1);
628 if (props->snap)
629 twin_compute_snap (cr, &info, b);
630 else
631 info.n_snap_x = info.n_snap_y = 0;
633 /* advance width */
634 metrics->x_advance = gw * props->stretch + props->penx + props->marginl + props->marginr;
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;
683 break;
686 return CAIRO_STATUS_SUCCESS;
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)
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. */
699 if (likely (unicode < ARRAY_LENGTH (_cairo_twin_charmap)))
700 *glyph = unicode;
701 else
702 *glyph = 0;
704 return CAIRO_STATUS_SUCCESS;
709 * Face constructor
712 static cairo_font_face_t *
713 _cairo_font_face_twin_create_internal (void)
715 cairo_font_face_t *twin_font_face;
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);
722 return twin_font_face;
725 cairo_font_face_t *
726 _cairo_font_face_twin_create_fallback (void)
728 cairo_font_face_t *twin_font_face;
729 cairo_status_t status;
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;
738 return twin_font_face;
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)
745 cairo_status_t status;
746 cairo_font_face_t *twin_font_face;
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;
755 *font_face = twin_font_face;
757 return CAIRO_STATUS_SUCCESS;