Merge remote branch 'origin/master' into nvc0-new
[mesa.git] / src / gallium / state_trackers / vega / text.c
1 /**************************************************************************
2 *
3 * Copyright 2010 LunarG, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27 #include "util/u_memory.h"
28 #include "cso_cache/cso_hash.h"
29
30 #include "text.h"
31 #include "image.h"
32 #include "path.h"
33 #include "api.h"
34
35 #ifdef OPENVG_VERSION_1_1
36
37 struct vg_font {
38 struct vg_object base;
39 struct cso_hash *glyphs;
40 };
41
42 struct vg_glyph {
43 struct vg_object *object; /* it could be NULL */
44 VGboolean is_hinted;
45 VGfloat glyph_origin[2];
46 VGfloat escapement[2];
47 };
48
49 static VGboolean del_glyph(struct vg_font *font,
50 VGuint glyphIndex)
51 {
52 struct vg_glyph *glyph;
53
54 glyph = (struct vg_glyph *)
55 cso_hash_take(font->glyphs, (unsigned) glyphIndex);
56 if (glyph)
57 FREE(glyph);
58
59 return (glyph != NULL);
60 }
61
62 static void add_glyph(struct vg_font *font,
63 VGuint glyphIndex,
64 struct vg_object *obj,
65 VGboolean isHinted,
66 const VGfloat glyphOrigin[2],
67 const VGfloat escapement[2])
68 {
69 struct vg_glyph *glyph;
70
71 /* remove the existing one */
72 del_glyph(font, glyphIndex);
73
74 glyph = CALLOC_STRUCT(vg_glyph);
75 glyph->object = obj;
76 glyph->is_hinted = isHinted;
77 memcpy(glyph->glyph_origin, glyphOrigin, sizeof(glyphOrigin));
78 memcpy(glyph->escapement, escapement, sizeof(escapement));
79
80 cso_hash_insert(font->glyphs, (unsigned) glyphIndex, glyph);
81 }
82
83 static struct vg_glyph *get_glyph(struct vg_font *font,
84 VGuint glyphIndex)
85 {
86 struct cso_hash_iter iter;
87
88 iter = cso_hash_find(font->glyphs, (unsigned) glyphIndex);
89 return (struct vg_glyph *) cso_hash_iter_data(iter);
90 }
91
92 static void vg_render_glyph(struct vg_context *ctx,
93 struct vg_glyph *glyph,
94 VGbitfield paintModes,
95 VGboolean allowAutoHinting)
96 {
97 if (glyph->object && paintModes) {
98 struct vg_state *state = &ctx->state.vg;
99 struct matrix m;
100
101 m = state->glyph_user_to_surface_matrix;
102 matrix_translate(&m,
103 state->glyph_origin[0].f - glyph->glyph_origin[0],
104 state->glyph_origin[1].f - glyph->glyph_origin[1]);
105
106 if (glyph->object->type == VG_OBJECT_PATH) {
107 path_render((struct path *) glyph->object, paintModes, &m);
108 }
109 else {
110 assert(glyph->object->type == VG_OBJECT_IMAGE);
111 image_draw((struct vg_image *) glyph->object, &m);
112 }
113 }
114 }
115
116 static void vg_advance_glyph(struct vg_context *ctx,
117 struct vg_glyph *glyph,
118 VGfloat adjustment_x,
119 VGfloat adjustment_y,
120 VGboolean last)
121 {
122 struct vg_value *glyph_origin = ctx->state.vg.glyph_origin;
123
124 glyph_origin[0].f += glyph->escapement[0] + adjustment_x;
125 glyph_origin[1].f += glyph->escapement[1] + adjustment_y;
126
127 if (last) {
128 glyph_origin[0].i = float_to_int_floor(glyph_origin[0].f);
129 glyph_origin[1].i = float_to_int_floor(glyph_origin[1].f);
130 }
131 }
132
133 struct vg_font *font_create(VGint glyphCapacityHint)
134 {
135 struct vg_context *ctx = vg_current_context();
136 struct vg_font *font;
137
138 font = CALLOC_STRUCT(vg_font);
139 vg_init_object(&font->base, ctx, VG_OBJECT_FONT);
140 font->glyphs = cso_hash_create();
141
142 vg_context_add_object(ctx, VG_OBJECT_FONT, font);
143
144 return font;
145 }
146
147 void font_destroy(struct vg_font *font)
148 {
149 struct vg_context *ctx = vg_current_context();
150 struct cso_hash_iter iter;
151
152 vg_context_remove_object(ctx, VG_OBJECT_FONT, font);
153
154 iter = cso_hash_first_node(font->glyphs);
155 while (!cso_hash_iter_is_null(iter)) {
156 struct vg_glyph *glyph = (struct vg_glyph *) cso_hash_iter_data(iter);
157 FREE(glyph);
158 iter = cso_hash_iter_next(iter);
159 }
160 cso_hash_delete(font->glyphs);
161
162 FREE(font);
163 }
164
165 void font_set_glyph_to_path(struct vg_font *font,
166 VGuint glyphIndex,
167 struct path *path,
168 VGboolean isHinted,
169 const VGfloat glyphOrigin[2],
170 const VGfloat escapement[2])
171 {
172 add_glyph(font, glyphIndex, (struct vg_object *) path,
173 isHinted, glyphOrigin, escapement);
174 }
175
176 void font_set_glyph_to_image(struct vg_font *font,
177 VGuint glyphIndex,
178 struct vg_image *image,
179 const VGfloat glyphOrigin[2],
180 const VGfloat escapement[2])
181 {
182 add_glyph(font, glyphIndex, (struct vg_object *) image,
183 VG_TRUE, glyphOrigin, escapement);
184 }
185
186 void font_clear_glyph(struct vg_font *font,
187 VGuint glyphIndex)
188 {
189 if (!del_glyph(font, glyphIndex)) {
190 struct vg_context *ctx = vg_current_context();
191 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
192 }
193 }
194
195 void font_draw_glyph(struct vg_font *font,
196 VGuint glyphIndex,
197 VGbitfield paintModes,
198 VGboolean allowAutoHinting)
199 {
200 struct vg_context *ctx = vg_current_context();
201 struct vg_glyph *glyph;
202
203 glyph = get_glyph(font, glyphIndex);
204 if (!glyph) {
205 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
206 return;
207 }
208
209 vg_render_glyph(ctx, glyph, paintModes, allowAutoHinting);
210 vg_advance_glyph(ctx, glyph, 0.0f, 0.0f, VG_TRUE);
211 }
212
213 void font_draw_glyphs(struct vg_font *font,
214 VGint glyphCount,
215 const VGuint *glyphIndices,
216 const VGfloat *adjustments_x,
217 const VGfloat *adjustments_y,
218 VGbitfield paintModes,
219 VGboolean allowAutoHinting)
220 {
221 struct vg_context *ctx = vg_current_context();
222 VGint i;
223
224 for (i = 0; i < glyphCount; ++i) {
225 if (!get_glyph(font, glyphIndices[i])) {
226 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
227 return;
228 }
229 }
230
231 for (i = 0; i < glyphCount; ++i) {
232 struct vg_glyph *glyph;
233 VGfloat adj_x, adj_y;
234
235 glyph = get_glyph(font, glyphIndices[i]);
236
237 vg_render_glyph(ctx, glyph, paintModes, allowAutoHinting);
238
239 adj_x = (adjustments_x) ? adjustments_x[i] : 0.0f;
240 adj_y = (adjustments_y) ? adjustments_y[i] : 0.0f;
241 vg_advance_glyph(ctx, glyph, adj_x, adj_y, (i == glyphCount - 1));
242 }
243 }
244
245 VGint font_num_glyphs(struct vg_font *font)
246 {
247 return cso_hash_size(font->glyphs);
248 }
249
250 #endif /* OPENVG_VERSION_1_1 */