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 "cairo-test.h"
29

            
30
#include <stdlib.h>
31
#include <stdio.h>
32

            
33
/*#define ROTATED 1*/
34

            
35
#define BORDER 10
36
#define TEXT_SIZE 64
37
#define WIDTH  (TEXT_SIZE * 12 + 2*BORDER)
38
#ifndef ROTATED
39
 #define HEIGHT ((TEXT_SIZE + 2*BORDER)*2)
40
#else
41
 #define HEIGHT WIDTH
42
#endif
43

            
44
#define TEXT1   "cairo user-font."
45
#define TEXT2   " zg"
46

            
47
static cairo_user_data_key_t fallback_font_key;
48

            
49
static cairo_status_t
50
3
test_scaled_font_init (cairo_scaled_font_t  *scaled_font,
51
		       cairo_t              *cr,
52
		       cairo_font_extents_t *extents)
53
{
54
    cairo_status_t status;
55

            
56
3
    cairo_set_font_face (cr,
57
3
			 cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
58
							&fallback_font_key));
59

            
60
3
    status = cairo_scaled_font_set_user_data (scaled_font,
61
					      &fallback_font_key,
62
3
					      cairo_scaled_font_reference (cairo_get_scaled_font (cr)),
63
					      (cairo_destroy_func_t) cairo_scaled_font_destroy);
64
3
    if (unlikely (status)) {
65
	cairo_scaled_font_destroy (cairo_get_scaled_font (cr));
66
	return status;
67
    }
68

            
69
3
    cairo_font_extents (cr, extents);
70

            
71
3
    return CAIRO_STATUS_SUCCESS;
72
}
73

            
74
static cairo_status_t
75
48
test_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
76
			       unsigned long         glyph,
77
			       cairo_t              *cr,
78
			       cairo_text_extents_t *extents)
79
{
80
    cairo_glyph_t cairo_glyph;
81

            
82
48
    cairo_glyph.index = glyph;
83
48
    cairo_glyph.x = 0;
84
48
    cairo_glyph.y = 0;
85

            
86
48
    cairo_set_font_face (cr,
87
48
			 cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
88
							&fallback_font_key));
89

            
90
48
    cairo_show_glyphs (cr, &cairo_glyph, 1);
91
48
    cairo_glyph_extents (cr, &cairo_glyph, 1, extents);
92

            
93
48
    return CAIRO_STATUS_SUCCESS;
94
}
95

            
96
static cairo_status_t
97
18
test_scaled_font_text_to_glyphs (cairo_scaled_font_t        *scaled_font,
98
				 const char	            *utf8,
99
				 int		             utf8_len,
100
				 cairo_glyph_t	           **glyphs,
101
				 int		            *num_glyphs,
102
				 cairo_text_cluster_t      **clusters,
103
				 int		            *num_clusters,
104
				 cairo_text_cluster_flags_t *cluster_flags)
105
{
106
  cairo_scaled_font_t *fallback_scaled_font;
107

            
108
18
  fallback_scaled_font = cairo_scaled_font_get_user_data (scaled_font,
109
							  &fallback_font_key);
110

            
111
18
  return cairo_scaled_font_text_to_glyphs (fallback_scaled_font, 0, 0,
112
					   utf8, utf8_len,
113
					   glyphs, num_glyphs,
114
					   clusters, num_clusters, cluster_flags);
115
}
116

            
117
static cairo_status_t
118
3
_user_font_face_create (cairo_font_face_t **out)
119
{
120
    cairo_font_face_t *user_font_face;
121
    cairo_font_face_t *fallback_font_face;
122
    cairo_status_t status;
123

            
124
3
    user_font_face = cairo_user_font_face_create ();
125
3
    cairo_user_font_face_set_init_func             (user_font_face, test_scaled_font_init);
126
3
    cairo_user_font_face_set_render_glyph_func     (user_font_face, test_scaled_font_render_glyph);
127
3
    cairo_user_font_face_set_text_to_glyphs_func   (user_font_face, test_scaled_font_text_to_glyphs);
128

            
129
    /* This also happens to be default font face on cairo_t, so does
130
     * not make much sense here.  For demonstration only.
131
     */
132
3
    fallback_font_face = cairo_toy_font_face_create (CAIRO_TEST_FONT_FAMILY " Sans",
133
						     CAIRO_FONT_SLANT_NORMAL,
134
						     CAIRO_FONT_WEIGHT_NORMAL);
135

            
136
3
    status = cairo_font_face_set_user_data (user_font_face,
137
					    &fallback_font_key,
138
					    fallback_font_face,
139
					    (cairo_destroy_func_t) cairo_font_face_destroy);
140
3
    if (status) {
141
	cairo_font_face_destroy (fallback_font_face);
142
	cairo_font_face_destroy (user_font_face);
143
	return status;
144
    }
145

            
146
3
    *out = user_font_face;
147
3
    return CAIRO_STATUS_SUCCESS;
148
}
149

            
150
static cairo_test_status_t
151
3
draw (cairo_t *cr, int width, int height)
152
{
153
    cairo_font_extents_t font_extents;
154
    cairo_text_extents_t extents;
155
    cairo_font_face_t *font_face;
156
    cairo_status_t status;
157
    char full_text[100];
158

            
159
3
    strcpy(full_text, TEXT1);
160
3
    strcat(full_text, TEXT2);
161
3
    strcat(full_text, TEXT2);
162
3
    strcat(full_text, TEXT2);
163

            
164
3
    cairo_set_source_rgb (cr, 1, 1, 1);
165
3
    cairo_paint (cr);
166

            
167
#ifdef ROTATED
168
    cairo_translate (cr, TEXT_SIZE, 0);
169
    cairo_rotate (cr, .6);
170
#endif
171

            
172
3
    status = _user_font_face_create (&font_face);
173
3
    if (status) {
174
	return cairo_test_status_from_status (cairo_test_get_context (cr),
175
					      status);
176
    }
177

            
178
3
    cairo_set_font_face (cr, font_face);
179
3
    cairo_font_face_destroy (font_face);
180

            
181
3
    cairo_set_font_size (cr, TEXT_SIZE);
182

            
183
3
    cairo_font_extents (cr, &font_extents);
184
3
    cairo_text_extents (cr, full_text, &extents);
185

            
186
    /* logical boundaries in red */
187
3
    cairo_move_to (cr, 0, BORDER);
188
3
    cairo_rel_line_to (cr, WIDTH, 0);
189
3
    cairo_move_to (cr, 0, BORDER + font_extents.ascent);
190
3
    cairo_rel_line_to (cr, WIDTH, 0);
191
3
    cairo_move_to (cr, 0, BORDER + font_extents.ascent + font_extents.descent);
192
3
    cairo_rel_line_to (cr, WIDTH, 0);
193
3
    cairo_move_to (cr, BORDER, 0);
194
3
    cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE);
195
3
    cairo_move_to (cr, BORDER + extents.x_advance, 0);
196
3
    cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE);
197
3
    cairo_set_source_rgb (cr, 1, 0, 0);
198
3
    cairo_set_line_width (cr, 2);
199
3
    cairo_stroke (cr);
200

            
201
    /* ink boundaries in green */
202
3
    cairo_rectangle (cr,
203
3
		     BORDER + extents.x_bearing, BORDER + font_extents.ascent + extents.y_bearing,
204
		     extents.width, extents.height);
205
3
    cairo_set_source_rgb (cr, 0, 1, 0);
206
3
    cairo_set_line_width (cr, 2);
207
3
    cairo_stroke (cr);
208

            
209

            
210
    /* TEXT1 in black */
211
3
    cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
212
3
    cairo_set_source_rgb (cr, 0, 0, 0);
213
3
    cairo_show_text (cr, TEXT1);
214

            
215
    /* Draw TEXT2 three times with three different foreground colors.
216
     * This checks that cairo uses the foreground color and does not cache
217
     * glyph images when the foreground color changes.
218
     */
219
3
    cairo_show_text (cr, TEXT2);
220
3
    cairo_set_source_rgb (cr, 0, 0.5, 0);
221
3
    cairo_show_text (cr, TEXT2);
222
3
    cairo_set_source_rgb (cr, 0.2, 0.5, 0.5);
223
3
    cairo_show_text (cr, TEXT2);
224

            
225
    /* filled version of text in light blue */
226
3
    cairo_set_source_rgb (cr, 0, 0, 1);
227
3
    cairo_move_to (cr, BORDER, BORDER + font_extents.height + BORDER + font_extents.ascent);
228
3
    cairo_text_path (cr, full_text);
229
3
    cairo_fill (cr);
230

            
231
3
    return CAIRO_TEST_SUCCESS;
232
}
233

            
234
1
CAIRO_TEST (user_font_proxy,
235
	    "Tests a user-font using a native font in its render_glyph",
236
	    "font, user-font", /* keywords */
237
	    "cairo >= 1.7.4", /* requirements */
238
	    WIDTH, HEIGHT,
239
	    NULL, draw)