Tizen 2.0 Release
[framework/graphics/cairo.git] / test / user-font.c
1 /*
2  * Copyright © 2006, 2008 Red Hat, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software
5  * and its documentation for any purpose is hereby granted without
6  * fee, provided that the above copyright notice appear in all copies
7  * and that both that copyright notice and this permission notice
8  * appear in supporting documentation, and that the name of
9  * Red Hat, Inc. not be used in advertising or publicity pertaining to
10  * distribution of the software without specific, written prior
11  * permission. Red Hat, Inc. makes no representations about the
12  * suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
18  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
21  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Contributor(s):
24  *      Kristian Høgsberg <krh@redhat.com>
25  *      Behdad Esfahbod <behdad@behdad.org>
26  */
27
28 #include <stdlib.h>
29 #include <stdio.h>
30
31 #include "cairo-test.h"
32
33 /*#define ROTATED 1*/
34
35 #define BORDER 10
36 #define TEXT_SIZE 64
37 #define WIDTH  (TEXT_SIZE * 15 + 2*BORDER)
38 #ifndef ROTATED
39  #define HEIGHT ((TEXT_SIZE + 2*BORDER)*2)
40 #else
41  #define HEIGHT WIDTH
42 #endif
43 #define TEXT   "geez... cairo user-font"
44
45 #define END_GLYPH 0
46 #define STROKE 126
47 #define CLOSE 127
48
49 /* Simple glyph definition: 1 - 15 means lineto (or moveto for first
50  * point) for one of the points on this grid:
51  *
52  *      1  2  3
53  *      4  5  6
54  *      7  8  9
55  * ----10 11 12----(baseline)
56  *     13 14 15
57  */
58 typedef struct {
59     unsigned long ucs4;
60     int width;
61     char data[16];
62 } test_scaled_font_glyph_t;
63
64 static cairo_user_data_key_t test_font_face_glyphs_key;
65
66 static cairo_status_t
67 test_scaled_font_init (cairo_scaled_font_t  *scaled_font,
68                        cairo_t              *cr,
69                        cairo_font_extents_t *metrics)
70 {
71   metrics->ascent  = .75;
72   metrics->descent = .25;
73   return CAIRO_STATUS_SUCCESS;
74 }
75
76 static cairo_status_t
77 test_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font,
78                                    unsigned long        unicode,
79                                    unsigned long       *glyph)
80 {
81     test_scaled_font_glyph_t *glyphs = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
82                                                                       &test_font_face_glyphs_key);
83     int i;
84
85     for (i = 0; glyphs[i].ucs4 != (unsigned long) -1; i++)
86         if (glyphs[i].ucs4 == unicode) {
87             *glyph = i;
88             return CAIRO_STATUS_SUCCESS;
89         }
90
91     /* Not found.  Default to glyph 0 */
92     return CAIRO_STATUS_SUCCESS;
93 }
94
95 static cairo_status_t
96 test_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
97                                unsigned long         glyph,
98                                cairo_t              *cr,
99                                cairo_text_extents_t *metrics)
100 {
101     test_scaled_font_glyph_t *glyphs = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
102                                                                       &test_font_face_glyphs_key);
103     int i;
104     const char *data;
105     div_t d;
106     double x, y;
107
108     /* FIXME: We simply crash on out-of-bound glyph indices */
109
110     metrics->x_advance = glyphs[glyph].width / 4.0;
111
112     cairo_set_line_width (cr, 0.1);
113     cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
114     cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
115
116     data = glyphs[glyph].data;
117     for (i = 0; data[i] != END_GLYPH; i++) {
118         switch (data[i]) {
119         case STROKE:
120             cairo_new_sub_path (cr);
121             break;
122
123         case CLOSE:
124             cairo_close_path (cr);
125             break;
126
127         default:
128             d = div (data[i] - 1, 3);
129             x = d.rem / 4.0 + 0.125;
130             y = d.quot / 5.0 + 0.4 - 1.0;
131             cairo_line_to (cr, x, y);
132         }
133     }
134     cairo_stroke (cr);
135
136     return CAIRO_STATUS_SUCCESS;
137 }
138
139 static cairo_status_t
140 _user_font_face_create (cairo_font_face_t **out)
141 {
142     /* Simple glyph definition: 1 - 15 means lineto (or moveto for first
143      * point) for one of the points on this grid:
144      *
145      *      1  2  3
146      *      4  5  6
147      *      7  8  9
148      * ----10 11 12----(baseline)
149      *     13 14 15
150      */
151     static const test_scaled_font_glyph_t glyphs [] = {
152         { 'a',  3, { 4, 6, 12, 10, 7, 9, STROKE, END_GLYPH } },
153         { 'c',  3, { 6, 4, 10, 12, STROKE, END_GLYPH } },
154         { 'e',  3, { 12, 10, 4, 6, 9, 7, STROKE, END_GLYPH } },
155         { 'f',  3, { 3, 2, 11, STROKE, 4, 6, STROKE, END_GLYPH } },
156         { 'g',  3, { 12, 10, 4, 6, 15, 13, STROKE, END_GLYPH } },
157         { 'h',  3, { 1, 10, STROKE, 7, 5, 6, 12, STROKE, END_GLYPH } },
158         { 'i',  1, { 1, 1, STROKE, 4, 10, STROKE, END_GLYPH } },
159         { 'l',  1, { 1, 10, STROKE, END_GLYPH } },
160         { 'n',  3, { 10, 4, STROKE, 7, 5, 6, 12, STROKE, END_GLYPH } },
161         { 'o',  3, { 4, 10, 12, 6, CLOSE, END_GLYPH } },
162         { 'r',  3, { 4, 10, STROKE, 7, 5, 6, STROKE, END_GLYPH } },
163         { 's',  3, { 6, 4, 7, 9, 12, 10, STROKE, END_GLYPH } },
164         { 't',  3, { 2, 11, 12, STROKE, 4, 6, STROKE, END_GLYPH } },
165         { 'u',  3, { 4, 10, 12, 6, STROKE, END_GLYPH } },
166         { 'z',  3, { 4, 6, 10, 12, STROKE, END_GLYPH } },
167         { ' ',  1, { END_GLYPH } },
168         { '-',  2, { 7, 8, STROKE, END_GLYPH } },
169         { '.',  1, { 10, 10, STROKE, END_GLYPH } },
170         {  -1,  0, { END_GLYPH } },
171     };
172
173     cairo_font_face_t *user_font_face;
174     cairo_status_t status;
175
176     user_font_face = cairo_user_font_face_create ();
177     cairo_user_font_face_set_init_func             (user_font_face, test_scaled_font_init);
178     cairo_user_font_face_set_render_glyph_func     (user_font_face, test_scaled_font_render_glyph);
179     cairo_user_font_face_set_unicode_to_glyph_func (user_font_face, test_scaled_font_unicode_to_glyph);
180
181     status = cairo_font_face_set_user_data (user_font_face,
182                                             &test_font_face_glyphs_key,
183                                             (void*) glyphs, NULL);
184     if (status) {
185         cairo_font_face_destroy (user_font_face);
186         return status;
187     }
188
189     *out = user_font_face;
190     return CAIRO_STATUS_SUCCESS;
191 }
192
193 static cairo_test_status_t
194 draw (cairo_t *cr, int width, int height)
195 {
196     cairo_font_face_t *font_face;
197     const char text[] = TEXT;
198     cairo_font_extents_t font_extents;
199     cairo_text_extents_t extents;
200     cairo_status_t status;
201
202     cairo_set_source_rgb (cr, 1, 1, 1);
203     cairo_paint (cr);
204
205 #ifdef ROTATED
206     cairo_translate (cr, TEXT_SIZE, 0);
207     cairo_rotate (cr, .6);
208 #endif
209
210     status = _user_font_face_create (&font_face);
211     if (status) {
212         return cairo_test_status_from_status (cairo_test_get_context (cr),
213                                               status);
214     }
215
216     cairo_set_font_face (cr, font_face);
217     cairo_font_face_destroy (font_face);
218
219     cairo_set_font_size (cr, TEXT_SIZE);
220
221     cairo_font_extents (cr, &font_extents);
222     cairo_text_extents (cr, text, &extents);
223
224     /* logical boundaries in red */
225     cairo_move_to (cr, 0, BORDER);
226     cairo_rel_line_to (cr, WIDTH, 0);
227     cairo_move_to (cr, 0, BORDER + font_extents.ascent);
228     cairo_rel_line_to (cr, WIDTH, 0);
229     cairo_move_to (cr, 0, BORDER + font_extents.ascent + font_extents.descent);
230     cairo_rel_line_to (cr, WIDTH, 0);
231     cairo_move_to (cr, BORDER, 0);
232     cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE);
233     cairo_move_to (cr, BORDER + extents.x_advance, 0);
234     cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE);
235     cairo_set_source_rgb (cr, 1, 0, 0);
236     cairo_set_line_width (cr, 2);
237     cairo_stroke (cr);
238
239     /* ink boundaries in green */
240     cairo_rectangle (cr,
241                      BORDER + extents.x_bearing, BORDER + font_extents.ascent + extents.y_bearing,
242                      extents.width, extents.height);
243     cairo_set_source_rgb (cr, 0, 1, 0);
244     cairo_set_line_width (cr, 2);
245     cairo_stroke (cr);
246
247     /* text in black */
248     cairo_set_source_rgb (cr, 0, 0, 0);
249     cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
250     cairo_show_text (cr, text);
251
252
253     /* filled version of text in blue */
254     cairo_set_source_rgb (cr, 0, 0, 1);
255     cairo_move_to (cr, BORDER, BORDER + font_extents.height + 2*BORDER + font_extents.ascent);
256     cairo_text_path (cr, text);
257     cairo_fill (cr);
258
259     return CAIRO_TEST_SUCCESS;
260 }
261
262 CAIRO_TEST (user_font,
263             "Tests user font feature",
264             "font, user-font", /* keywords */
265             "cairo >= 1.7.4", /* requirements */
266             WIDTH, HEIGHT,
267             NULL, draw)