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 34 #ifdef OPENVG_VERSION_1_1 35 36 struct vg_font { 37 struct vg_object base; 38 struct cso_hash *glyphs; 39 }; 40 41 struct vg_glyph { 42 struct vg_object *object; /* it could be NULL */ 43 VGboolean is_hinted; 44 VGfloat glyph_origin[2]; 45 VGfloat escapement[2]; 46 }; 47 48 static VGboolean del_glyph(struct vg_font *font, 49 VGuint glyphIndex) 50 { 51 struct vg_glyph *glyph; 52 53 glyph = (struct vg_glyph *) 54 cso_hash_take(font->glyphs, (unsigned) glyphIndex); 55 if (glyph) 56 FREE(glyph); 57 58 return (glyph != NULL); 59 } 60 61 static void add_glyph(struct vg_font *font, 62 VGuint glyphIndex, 63 struct vg_object *obj, 64 VGboolean isHinted, 65 const VGfloat glyphOrigin[2], 66 const VGfloat escapement[2]) 67 { 68 struct vg_glyph *glyph; 69 70 /* remove the existing one */ 71 del_glyph(font, glyphIndex); 72 73 glyph = CALLOC_STRUCT(vg_glyph); 74 glyph->object = obj; 75 glyph->is_hinted = isHinted; 76 memcpy(glyph->glyph_origin, glyphOrigin, sizeof(glyph->glyph_origin)); 77 memcpy(glyph->escapement, escapement, sizeof(glyph->glyph_origin)); 78 79 cso_hash_insert(font->glyphs, (unsigned) glyphIndex, glyph); 80 } 81 82 static struct vg_glyph *get_glyph(struct vg_font *font, 83 VGuint glyphIndex) 84 { 85 struct cso_hash_iter iter; 86 87 iter = cso_hash_find(font->glyphs, (unsigned) glyphIndex); 88 return (struct vg_glyph *) cso_hash_iter_data(iter); 89 } 90 91 static void vg_render_glyph(struct vg_context *ctx, 92 struct vg_glyph *glyph, 93 VGbitfield paintModes, 94 VGboolean allowAutoHinting) 95 { 96 if (glyph->object && paintModes) { 97 struct vg_state *state = &ctx->state.vg; 98 struct matrix m; 99 100 m = state->glyph_user_to_surface_matrix; 101 matrix_translate(&m, 102 state->glyph_origin[0].f - glyph->glyph_origin[0], 103 state->glyph_origin[1].f - glyph->glyph_origin[1]); 104 105 if (glyph->object->type == VG_OBJECT_PATH) { 106 path_render((struct path *) glyph->object, paintModes, &m); 107 } 108 else { 109 assert(glyph->object->type == VG_OBJECT_IMAGE); 110 image_draw((struct vg_image *) glyph->object, &m); 111 } 112 } 113 } 114 115 static void vg_advance_glyph(struct vg_context *ctx, 116 struct vg_glyph *glyph, 117 VGfloat adjustment_x, 118 VGfloat adjustment_y, 119 VGboolean last) 120 { 121 struct vg_value *glyph_origin = ctx->state.vg.glyph_origin; 122 123 glyph_origin[0].f += glyph->escapement[0] + adjustment_x; 124 glyph_origin[1].f += glyph->escapement[1] + adjustment_y; 125 126 if (last) { 127 glyph_origin[0].i = float_to_int_floor(glyph_origin[0].f); 128 glyph_origin[1].i = float_to_int_floor(glyph_origin[1].f); 129 } 130 } 131 132 struct vg_font *font_create(VGint glyphCapacityHint) 133 { 134 struct vg_context *ctx = vg_current_context(); 135 struct vg_font *font; 136 137 font = CALLOC_STRUCT(vg_font); 138 vg_init_object(&font->base, ctx, VG_OBJECT_FONT); 139 font->glyphs = cso_hash_create(); 140 141 vg_context_add_object(ctx, &font->base); 142 143 return font; 144 } 145 146 void font_destroy(struct vg_font *font) 147 { 148 struct vg_context *ctx = vg_current_context(); 149 struct cso_hash_iter iter; 150 151 vg_context_remove_object(ctx, &font->base); 152 153 iter = cso_hash_first_node(font->glyphs); 154 while (!cso_hash_iter_is_null(iter)) { 155 struct vg_glyph *glyph = (struct vg_glyph *) cso_hash_iter_data(iter); 156 FREE(glyph); 157 iter = cso_hash_iter_next(iter); 158 } 159 cso_hash_delete(font->glyphs); 160 161 FREE(font); 162 } 163 164 void font_set_glyph_to_path(struct vg_font *font, 165 VGuint glyphIndex, 166 struct path *path, 167 VGboolean isHinted, 168 const VGfloat glyphOrigin[2], 169 const VGfloat escapement[2]) 170 { 171 add_glyph(font, glyphIndex, (struct vg_object *) path, 172 isHinted, glyphOrigin, escapement); 173 } 174 175 void font_set_glyph_to_image(struct vg_font *font, 176 VGuint glyphIndex, 177 struct vg_image *image, 178 const VGfloat glyphOrigin[2], 179 const VGfloat escapement[2]) 180 { 181 add_glyph(font, glyphIndex, (struct vg_object *) image, 182 VG_TRUE, glyphOrigin, escapement); 183 } 184 185 void font_clear_glyph(struct vg_font *font, 186 VGuint glyphIndex) 187 { 188 if (!del_glyph(font, glyphIndex)) { 189 struct vg_context *ctx = vg_current_context(); 190 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 191 } 192 } 193 194 void font_draw_glyph(struct vg_font *font, 195 VGuint glyphIndex, 196 VGbitfield paintModes, 197 VGboolean allowAutoHinting) 198 { 199 struct vg_context *ctx = vg_current_context(); 200 struct vg_glyph *glyph; 201 202 glyph = get_glyph(font, glyphIndex); 203 if (!glyph) { 204 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 205 return; 206 } 207 208 vg_render_glyph(ctx, glyph, paintModes, allowAutoHinting); 209 vg_advance_glyph(ctx, glyph, 0.0f, 0.0f, VG_TRUE); 210 } 211 212 void font_draw_glyphs(struct vg_font *font, 213 VGint glyphCount, 214 const VGuint *glyphIndices, 215 const VGfloat *adjustments_x, 216 const VGfloat *adjustments_y, 217 VGbitfield paintModes, 218 VGboolean allowAutoHinting) 219 { 220 struct vg_context *ctx = vg_current_context(); 221 VGint i; 222 223 for (i = 0; i < glyphCount; ++i) { 224 if (!get_glyph(font, glyphIndices[i])) { 225 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 226 return; 227 } 228 } 229 230 for (i = 0; i < glyphCount; ++i) { 231 struct vg_glyph *glyph; 232 VGfloat adj_x, adj_y; 233 234 glyph = get_glyph(font, glyphIndices[i]); 235 236 vg_render_glyph(ctx, glyph, paintModes, allowAutoHinting); 237 238 adj_x = (adjustments_x) ? adjustments_x[i] : 0.0f; 239 adj_y = (adjustments_y) ? adjustments_y[i] : 0.0f; 240 vg_advance_glyph(ctx, glyph, adj_x, adj_y, (i == glyphCount - 1)); 241 } 242 } 243 244 VGint font_num_glyphs(struct vg_font *font) 245 { 246 return cso_hash_size(font->glyphs); 247 } 248 249 #endif /* OPENVG_VERSION_1_1 */ 250