text.c revision 5d64a06a6322b6e6f88233e79c6431e96eda7de6
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
37struct vg_font {
38   struct vg_object base;
39   struct cso_hash *glyphs;
40};
41
42struct 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
49static 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
62static 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
83static 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
92static 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
116static 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
133struct 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
147void 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
165void 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
176void 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
186void 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
195void 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
213void 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
245VGint font_num_glyphs(struct vg_font *font)
246{
247   return cso_hash_size(font->glyphs);
248}
249
250#endif /* OPENVG_VERSION_1_1 */
251