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., 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
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
33 * Keith Packard <keithp@keithp.com>
34 * Behdad Esfahbod <behdad@behdad.org>
38 #include "cairo-error-private.h"
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
47 * Ported to cairo user font and extended by Behdad Esfahbod.
52 static cairo_user_data_key_t twin_properties_key
;
59 /* We synthesize multiple faces from the twin data. Here is the parameters. */
61 /* The following tables and matching code are copied from Pango */
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
80 TWIN_STRETCH_ULTRA_CONDENSED
,
81 TWIN_STRETCH_EXTRA_CONDENSED
,
82 TWIN_STRETCH_CONDENSED
,
83 TWIN_STRETCH_SEMI_CONDENSED
,
85 TWIN_STRETCH_SEMI_EXPANDED
,
86 TWIN_STRETCH_EXPANDED
,
87 TWIN_STRETCH_EXTRA_EXPANDED
,
88 TWIN_STRETCH_ULTRA_EXPANDED
89 } twin_face_stretch_t
;
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" }
104 static const FieldMap smallcaps_map
[] = {
106 { TRUE
, "Small-Caps" }
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" }
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" }
143 static const FieldMap monospace_map
[] = {
146 { TRUE
, "Monospace" }
150 typedef struct _twin_face_properties
{
151 cairo_font_slant_t slant
;
152 twin_face_weight_t weight
;
153 twin_face_stretch_t stretch
;
155 /* lets have some fun */
156 cairo_bool_t monospace
;
157 cairo_bool_t smallcaps
;
158 } twin_face_properties_t
;
161 field_matches (const char *s1
,
167 while (len
&& *s1
&& *s2
)
170 (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
185 return len
== 0 && *s1
== '\0';
189 parse_int (const char *word
,
194 long val
= strtol (word
, &end
, 10);
197 if (end
!= word
&& (end
== word
+ wordlen
) && val
>= 0 && val
== i
)
209 find_field (const char *what
,
217 cairo_bool_t had_prefix
= FALSE
;
222 if (len
> i
&& 0 == strncmp (what
, str
, i
) && str
[i
] == '=')
230 for (i
=0; i
<n_elements
; i
++)
232 if (map
[i
].str
[0] && field_matches (map
[i
].str
, str
, len
))
240 if (!what
|| had_prefix
)
241 return parse_int (str
, len
, val
);
247 parse_field (twin_face_properties_t
*props
,
251 if (field_matches ("Normal", str
, len
))
254 #define FIELD(NAME) \
255 if (find_field (STRINGIFY (NAME), NAME##_map, ARRAY_LENGTH (NAME##_map), str, len, \
256 (int *)(void *)&props->NAME)) \
269 face_props_parse (twin_face_properties_t
*props
,
272 const char *start
, *end
;
274 for (start
= end
= s
; *end
; end
++) {
275 if (*end
!= ' ' && *end
!= ':')
279 parse_field (props
, start
, end
- start
);
283 parse_field (props
, start
, end
- start
);
286 static twin_face_properties_t
*
287 twin_font_face_create_properties (cairo_font_face_t
*twin_face
)
289 twin_face_properties_t
*props
;
291 props
= malloc (sizeof (twin_face_properties_t
));
292 if (unlikely (props
== NULL
))
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
;
301 if (unlikely (cairo_font_face_set_user_data (twin_face
,
302 &twin_properties_key
,
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
)
315 twin_face_properties_t
*props
;
317 props
= twin_font_face_create_properties (twin_face
);
318 if (unlikely (props
== NULL
))
319 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
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
);
326 return CAIRO_STATUS_SUCCESS
;
334 typedef struct _twin_scaled_properties
{
335 twin_face_properties_t
*face_props
;
337 cairo_bool_t snap
; /* hint outlines */
339 double weight
; /* unhinted pen width */
340 double penx
, peny
; /* hinted pen width */
341 double marginl
, marginr
; /* hinted side margins */
343 double stretch
; /* stretch factor */
344 } twin_scaled_properties_t
;
347 compute_hinting_scale (cairo_t
*cr
,
349 double *scale
, double *inv
)
351 cairo_user_to_device_distance (cr
, &x
, &y
);
352 *scale
= x
== 0 ? y
: y
== 0 ? x
:sqrt (x
*x
+ y
*y
);
357 compute_hinting_scales (cairo_t
*cr
,
358 double *x_scale
, double *x_scale_inv
,
359 double *y_scale
, double *y_scale_inv
)
364 compute_hinting_scale (cr
, x
, y
, x_scale
, x_scale_inv
);
367 compute_hinting_scale (cr
, x
, y
, y_scale
, y_scale_inv
);
370 #define SNAPXI(p) (_cairo_round ((p) * x_scale) * x_scale_inv)
371 #define SNAPYI(p) (_cairo_round ((p) * y_scale) * y_scale_inv)
373 /* This controls the global font size */
374 #define F(g) ((g) / 72.)
377 twin_hint_pen_and_margins(cairo_t
*cr
,
378 double *penx
, double *peny
,
379 double *marginl
, double *marginr
)
381 double x_scale
, x_scale_inv
;
382 double y_scale
, y_scale_inv
;
385 compute_hinting_scales (cr
,
386 &x_scale
, &x_scale_inv
,
387 &y_scale
, &y_scale_inv
);
389 *penx
= SNAPXI (*penx
);
390 if (*penx
< x_scale_inv
)
393 *peny
= SNAPYI (*peny
);
394 if (*peny
< y_scale_inv
)
397 margin
= *marginl
+ *marginr
;
398 *marginl
= SNAPXI (*marginl
);
399 if (*marginl
< x_scale_inv
)
400 *marginl
= x_scale_inv
;
402 *marginr
= margin
- *marginl
;
405 *marginr
= SNAPXI (*marginr
);
408 static cairo_status_t
409 twin_scaled_font_compute_properties (cairo_scaled_font_t
*scaled_font
,
412 cairo_status_t status
;
413 twin_scaled_properties_t
*props
;
415 props
= malloc (sizeof (twin_scaled_properties_t
));
416 if (unlikely (props
== NULL
))
417 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
420 props
->face_props
= cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font
),
421 &twin_properties_key
);
423 props
->snap
= scaled_font
->options
.hint_style
> CAIRO_HINT_STYLE_NONE
;
426 props
->weight
= props
->face_props
->weight
* (F (4) / TWIN_WEIGHT_NORMAL
);
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
);
437 props
->stretch
= 1 + .1 * ((int) props
->face_props
->stretch
- (int) TWIN_STRETCH_NORMAL
);
441 status
= cairo_scaled_font_set_user_data (scaled_font
,
442 &twin_properties_key
,
444 if (unlikely (status
))
447 return CAIRO_STATUS_SUCCESS
;
456 * User-font implementation
459 static cairo_status_t
460 twin_scaled_font_init (cairo_scaled_font_t
*scaled_font
,
462 cairo_font_extents_t
*metrics
)
464 metrics
->ascent
= F (54);
465 metrics
->descent
= 1 - metrics
->ascent
;
467 return twin_scaled_font_compute_properties (scaled_font
, cr
);
470 #define TWIN_GLYPH_MAX_SNAP_X 4
471 #define TWIN_GLYPH_MAX_SNAP_Y 7
475 int8_t snap_x
[TWIN_GLYPH_MAX_SNAP_X
];
476 double snapped_x
[TWIN_GLYPH_MAX_SNAP_X
];
478 int8_t snap_y
[TWIN_GLYPH_MAX_SNAP_Y
];
479 double snapped_y
[TWIN_GLYPH_MAX_SNAP_Y
];
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])
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))
494 twin_compute_snap (cairo_t
*cr
,
495 twin_snap_info_t
*info
,
496 const signed char *b
)
499 const signed char *snap
;
500 double x_scale
, x_scale_inv
;
501 double y_scale
, y_scale_inv
;
503 compute_hinting_scales (cr
,
504 &x_scale
, &x_scale_inv
,
505 &y_scale
, &y_scale_inv
);
507 snap
= twin_glyph_snap_x (b
);
508 n
= twin_glyph_n_snap_x (b
);
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
]));
516 snap
= twin_glyph_snap_y (b
);
517 n
= twin_glyph_n_snap_y (b
);
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
]));
527 twin_snap (int8_t v
, int n
, int8_t *snap
, double *snapped
)
537 for (s
= 0; s
< n
- 1; s
++)
542 if (snap
[s
] <= v
&& v
<= snap
[s
+1])
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
;
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)
559 static cairo_status_t
560 twin_scaled_font_render_glyph (cairo_scaled_font_t
*scaled_font
,
563 cairo_text_extents_t
*metrics
)
565 double x1
, y1
, x2
, y2
, x3
, y3
;
567 twin_scaled_properties_t
*props
;
568 twin_snap_info_t info
;
574 props
= cairo_scaled_font_get_user_data (scaled_font
, &twin_properties_key
);
576 /* Save glyph space, we need it when stroking */
580 cairo_translate (cr
, props
->penx
* .5, -props
->peny
* .5);
583 if (props
->face_props
->smallcaps
&& glyph
>= 'a' && glyph
<= 'z') {
585 /* 28 and 42 are small and capital letter heights of the glyph data */
586 cairo_scale (cr
, 1, 28. / 42);
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
);
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
);
601 marginl
= props
->marginl
;
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);
610 /* resnap margin for new transform */
612 double x
, y
, x_scale
, x_scale_inv
;
614 compute_hinting_scale (cr
, x
, y
, &x_scale
, &x_scale_inv
);
615 marginl
= SNAPXI (marginl
);
619 cairo_translate (cr
, marginl
, 0);
622 cairo_scale (cr
, props
->stretch
, 1);
625 twin_compute_snap (cr
, &info
, b
);
627 info
.n_snap_x
= info
.n_snap_y
= 0;
630 metrics
->x_advance
= gw
* props
->stretch
+ props
->penx
+ props
->marginl
+ props
->marginr
;
636 cairo_close_path (cr
);
641 cairo_move_to (cr
, x1
, y1
);
644 cairo_close_path (cr
);
649 cairo_line_to (cr
, x1
, y1
);
652 cairo_close_path (cr
);
661 cairo_curve_to (cr
, x1
, y1
, x2
, y2
, x3
, y3
);
664 cairo_close_path (cr
);
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
);
682 return CAIRO_STATUS_SUCCESS
;
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
)
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. */
695 if (likely (unicode
< ARRAY_LENGTH (_cairo_twin_charmap
)))
700 return CAIRO_STATUS_SUCCESS
;
708 static cairo_font_face_t
*
709 _cairo_font_face_twin_create_internal (void)
711 cairo_font_face_t
*twin_font_face
;
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
);
718 return twin_font_face
;
722 _cairo_font_face_twin_create_fallback (void)
724 cairo_font_face_t
*twin_font_face
;
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
;
732 return twin_font_face
;
736 _cairo_font_face_twin_create_for_toy (cairo_toy_font_face_t
*toy_face
,
737 cairo_font_face_t
**font_face
)
739 cairo_status_t status
;
740 cairo_font_face_t
*twin_font_face
;
742 twin_font_face
= _cairo_font_face_twin_create_internal ();
743 status
= twin_font_face_set_properties_from_toy (twin_font_face
, toy_face
);
745 cairo_font_face_destroy (twin_font_face
);
749 *font_face
= twin_font_face
;
751 return CAIRO_STATUS_SUCCESS
;