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
33 * Keith Packard <keithp@keithp.com>
34 * Behdad Esfahbod <behdad@behdad.org>
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
;
58 /* We synthesize multiple faces from the twin data. Here is the parameters. */
60 /* The following tables and matching code are copied from Pango */
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
79 TWIN_STRETCH_ULTRA_CONDENSED
,
80 TWIN_STRETCH_EXTRA_CONDENSED
,
81 TWIN_STRETCH_CONDENSED
,
82 TWIN_STRETCH_SEMI_CONDENSED
,
84 TWIN_STRETCH_SEMI_EXPANDED
,
85 TWIN_STRETCH_EXPANDED
,
86 TWIN_STRETCH_EXTRA_EXPANDED
,
87 TWIN_STRETCH_ULTRA_EXPANDED
88 } twin_face_stretch_t
;
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
[] = {
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
[] = {
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
;
160 field_matches (const char *s1
,
166 while (len
&& *s1
&& *s2
)
169 (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
184 return len
== 0 && *s1
== '\0';
188 parse_int (const char *word
,
193 long val
= strtol (word
, &end
, 10);
196 if (end
!= word
&& (end
== word
+ wordlen
) && val
>= 0 && val
== i
)
208 find_field (const char *what
,
216 cairo_bool_t had_prefix
= FALSE
;
221 if (len
> i
&& 0 == strncmp (what
, str
, i
) && str
[i
] == '=')
229 for (i
=0; i
<n_elements
; i
++)
231 if (map
[i
].str
[0] && field_matches (map
[i
].str
, str
, len
))
239 if (!what
|| had_prefix
)
240 return parse_int (str
, len
, val
);
246 parse_field (twin_face_properties_t
*props
,
250 if (field_matches ("Normal", str
, len
))
253 #define FIELD(NAME) \
254 if (find_field (STRINGIFY (NAME), NAME##_map, ARRAY_LENGTH (NAME##_map), str, len, \
255 (int *)(void *)&props->NAME)) \
268 face_props_parse (twin_face_properties_t
*props
,
271 const char *start
, *end
;
273 for (start
= end
= s
; *end
; end
++) {
274 if (*end
!= ' ' && *end
!= ':')
278 parse_field (props
, start
, end
- start
);
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
,
303 if (unlikely (status
)) {
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
))
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
;
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
;
351 compute_hinting_scale (cairo_t
*cr
,
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
);
361 compute_hinting_scales (cairo_t
*cr
,
362 double *x_scale
, double *x_scale_inv
,
363 double *y_scale
, double *y_scale_inv
)
368 compute_hinting_scale (cr
, x
, y
, x_scale
, x_scale_inv
);
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.)
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
;
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
)
397 *peny
= SNAPYI (*peny
);
398 if (*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
;
409 *marginr
= SNAPXI (*marginr
);
412 static cairo_status_t
413 twin_scaled_font_compute_properties (cairo_scaled_font_t
*scaled_font
,
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
;
430 props
->weight
= props
->face_props
->weight
* (F (4) / TWIN_WEIGHT_NORMAL
);
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
);
441 props
->stretch
= 1 + .1 * ((int) props
->face_props
->stretch
- (int) TWIN_STRETCH_NORMAL
);
445 status
= cairo_scaled_font_set_user_data (scaled_font
,
446 &twin_properties_key
,
448 if (unlikely (status
))
451 return CAIRO_STATUS_SUCCESS
;
460 * User-font implementation
463 static cairo_status_t
464 twin_scaled_font_init (cairo_scaled_font_t
*scaled_font
,
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
479 int8_t snap_x
[TWIN_GLYPH_MAX_SNAP_X
];
480 double snapped_x
[TWIN_GLYPH_MAX_SNAP_X
];
482 int8_t snap_y
[TWIN_GLYPH_MAX_SNAP_Y
];
483 double snapped_y
[TWIN_GLYPH_MAX_SNAP_Y
];
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))
498 twin_compute_snap (cairo_t
*cr
,
499 twin_snap_info_t
*info
,
500 const signed char *b
)
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
);
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
);
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
]));
531 twin_snap (int8_t v
, int n
, int8_t *snap
, double *snapped
)
541 for (s
= 0; s
< n
- 1; s
++)
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
;
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
,
567 cairo_text_extents_t
*metrics
)
569 double x1
, y1
, x2
, y2
, x3
, y3
;
571 twin_scaled_properties_t
*props
;
572 twin_snap_info_t info
;
578 props
= cairo_scaled_font_get_user_data (scaled_font
, &twin_properties_key
);
580 /* Save glyph space, we need it when stroking */
584 cairo_translate (cr
, props
->penx
* .5, -props
->peny
* .5);
587 if (props
->face_props
->smallcaps
&& glyph
>= 'a' && glyph
<= 'z') {
589 /* 28 and 42 are small and capital letter heights of the glyph data */
590 cairo_scale (cr
, 1, 28. / 42);
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
);
605 marginl
= props
->marginl
;
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);
614 /* resnap margin for new transform */
616 double x
, y
, x_scale
, x_scale_inv
;
618 compute_hinting_scale (cr
, x
, y
, &x_scale
, &x_scale_inv
);
619 marginl
= SNAPXI (marginl
);
623 cairo_translate (cr
, marginl
, 0);
626 cairo_scale (cr
, props
->stretch
, 1);
629 twin_compute_snap (cr
, &info
, b
);
631 info
.n_snap_x
= info
.n_snap_y
= 0;
634 metrics
->x_advance
= gw
* props
->stretch
+ props
->penx
+ props
->marginl
+ props
->marginr
;
640 cairo_close_path (cr
);
645 cairo_move_to (cr
, x1
, y1
);
648 cairo_close_path (cr
);
653 cairo_line_to (cr
, x1
, y1
);
656 cairo_close_path (cr
);
665 cairo_curve_to (cr
, x1
, y1
, x2
, y2
, x3
, y3
);
668 cairo_close_path (cr
);
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
);
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
)))
704 return CAIRO_STATUS_SUCCESS
;
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
;
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
);
734 cairo_font_face_destroy (twin_font_face
);
735 return (cairo_font_face_t
*) &_cairo_font_face_nil
;
738 return twin_font_face
;
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
);
751 cairo_font_face_destroy (twin_font_face
);
755 *font_face
= twin_font_face
;
757 return CAIRO_STATUS_SUCCESS
;