1 /* 2 * Copyright 2012 Google, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Google Author(s): Behdad Esfahbod 25 */ 26 27 #define HB_SHAPER old 28 #define hb_old_shaper_face_data_t HB_FaceRec_ 29 #define hb_old_shaper_font_data_t HB_Font_ 30 #include "hb-shaper-impl-private.hh" 31 32 #include <harfbuzz.h> 33 34 35 #ifndef HB_DEBUG_OLD 36 #define HB_DEBUG_OLD (HB_DEBUG+0) 37 #endif 38 39 40 static HB_Script 41 hb_old_script_from_script (hb_script_t script) 42 { 43 switch ((hb_tag_t) script) 44 { 45 default: 46 case HB_SCRIPT_COMMON: return HB_Script_Common; 47 case HB_SCRIPT_GREEK: return HB_Script_Greek; 48 case HB_SCRIPT_CYRILLIC: return HB_Script_Cyrillic; 49 case HB_SCRIPT_ARMENIAN: return HB_Script_Armenian; 50 case HB_SCRIPT_HEBREW: return HB_Script_Hebrew; 51 case HB_SCRIPT_ARABIC: return HB_Script_Arabic; 52 case HB_SCRIPT_SYRIAC: return HB_Script_Syriac; 53 case HB_SCRIPT_THAANA: return HB_Script_Thaana; 54 case HB_SCRIPT_DEVANAGARI: return HB_Script_Devanagari; 55 case HB_SCRIPT_BENGALI: return HB_Script_Bengali; 56 case HB_SCRIPT_GURMUKHI: return HB_Script_Gurmukhi; 57 case HB_SCRIPT_GUJARATI: return HB_Script_Gujarati; 58 case HB_SCRIPT_ORIYA: return HB_Script_Oriya; 59 case HB_SCRIPT_TAMIL: return HB_Script_Tamil; 60 case HB_SCRIPT_TELUGU: return HB_Script_Telugu; 61 case HB_SCRIPT_KANNADA: return HB_Script_Kannada; 62 case HB_SCRIPT_MALAYALAM: return HB_Script_Malayalam; 63 case HB_SCRIPT_SINHALA: return HB_Script_Sinhala; 64 case HB_SCRIPT_THAI: return HB_Script_Thai; 65 case HB_SCRIPT_LAO: return HB_Script_Lao; 66 case HB_SCRIPT_TIBETAN: return HB_Script_Tibetan; 67 case HB_SCRIPT_MYANMAR: return HB_Script_Myanmar; 68 case HB_SCRIPT_GEORGIAN: return HB_Script_Georgian; 69 case HB_SCRIPT_HANGUL: return HB_Script_Hangul; 70 case HB_SCRIPT_OGHAM: return HB_Script_Ogham; 71 case HB_SCRIPT_RUNIC: return HB_Script_Runic; 72 case HB_SCRIPT_KHMER: return HB_Script_Khmer; 73 case HB_SCRIPT_NKO: return HB_Script_Nko; 74 case HB_SCRIPT_INHERITED: return HB_Script_Inherited; 75 } 76 } 77 78 79 static HB_Bool 80 hb_old_convertStringToGlyphIndices (HB_Font old_font, 81 const HB_UChar16 *string, 82 hb_uint32 length, 83 HB_Glyph *glyphs, 84 hb_uint32 *numGlyphs, 85 HB_Bool rightToLeft) 86 { 87 hb_font_t *font = (hb_font_t *) old_font->userData; 88 89 for (unsigned int i = 0; i < length; i++) 90 { 91 hb_codepoint_t u; 92 93 /* XXX Handle UTF-16. Ugh */ 94 u = string[i]; 95 96 if (rightToLeft) 97 u = hb_unicode_funcs_get_default ()->mirroring (u); 98 99 font->get_glyph (u, 0, &u); /* TODO Variation selectors */ 100 101 glyphs[i] = u; 102 } 103 *numGlyphs = length; /* XXX */ 104 105 return true; 106 } 107 108 static void 109 hb_old_getGlyphAdvances (HB_Font old_font, 110 const HB_Glyph *glyphs, 111 hb_uint32 numGlyphs, 112 HB_Fixed *advances, 113 int flags /*HB_ShaperFlag*/ HB_UNUSED) 114 { 115 hb_font_t *font = (hb_font_t *) old_font->userData; 116 117 for (unsigned int i = 0; i < numGlyphs; i++) 118 advances[i] = font->get_glyph_h_advance (glyphs[i]); 119 } 120 121 static HB_Bool 122 hb_old_canRender (HB_Font old_font, 123 const HB_UChar16 *string, 124 hb_uint32 length) 125 { 126 return true; /* TODO */ 127 } 128 129 static HB_Error 130 hb_old_getPointInOutline (HB_Font old_font, 131 HB_Glyph glyph, 132 int flags /*HB_ShaperFlag*/, 133 hb_uint32 point, 134 HB_Fixed *xpos, 135 HB_Fixed *ypos, 136 hb_uint32 *nPoints) 137 { 138 return HB_Err_Ok; /* TODO */ 139 } 140 141 static void 142 hb_old_getGlyphMetrics (HB_Font old_font, 143 HB_Glyph glyph, 144 HB_GlyphMetrics *metrics) 145 { 146 hb_font_t *font = (hb_font_t *) old_font->userData; 147 148 hb_glyph_extents_t extents; 149 150 font->get_glyph_extents (glyph, &extents); 151 152 metrics->x = extents.x_bearing; 153 metrics->y = extents.y_bearing; 154 metrics->width = extents.width; 155 metrics->height = extents.height; 156 metrics->xOffset = font->get_glyph_h_advance (glyph); 157 metrics->yOffset = 0; 158 } 159 160 static HB_Fixed 161 hb_old_getFontMetric (HB_Font old_font, 162 HB_FontMetric metric) 163 { 164 hb_font_t *font = (hb_font_t *) old_font->userData; 165 166 switch (metric) 167 { 168 case HB_FontAscent: 169 return font->y_scale; /* XXX We don't have ascent data yet. */ 170 171 default: 172 return 0; 173 } 174 } 175 176 static const HB_FontClass hb_old_font_class = { 177 hb_old_convertStringToGlyphIndices, 178 hb_old_getGlyphAdvances, 179 hb_old_canRender, 180 hb_old_getPointInOutline, 181 hb_old_getGlyphMetrics, 182 hb_old_getFontMetric 183 }; 184 185 186 187 static HB_Error 188 table_func (void *font, HB_Tag tag, HB_Byte *buffer, HB_UInt *length) 189 { 190 hb_face_t *face = (hb_face_t *) font; 191 hb_blob_t *blob = face->reference_table ((hb_tag_t) tag); 192 unsigned int capacity = *length; 193 *length = hb_blob_get_length (blob); 194 memcpy (buffer, hb_blob_get_data (blob, NULL), MIN (capacity, *length)); 195 hb_blob_destroy (blob); 196 return HB_Err_Ok; 197 } 198 199 200 /* 201 * shaper face data 202 */ 203 204 hb_old_shaper_face_data_t * 205 _hb_old_shaper_face_data_create (hb_face_t *face) 206 { 207 return HB_NewFace (face, table_func); 208 } 209 210 void 211 _hb_old_shaper_face_data_destroy (hb_old_shaper_face_data_t *data) 212 { 213 HB_FreeFace (data); 214 } 215 216 217 /* 218 * shaper font data 219 */ 220 221 hb_old_shaper_font_data_t * 222 _hb_old_shaper_font_data_create (hb_font_t *font) 223 { 224 HB_FontRec *data = (HB_FontRec *) calloc (1, sizeof (HB_FontRec)); 225 if (unlikely (!data)) { 226 DEBUG_MSG (OLD, font, "malloc()ing HB_Font failed"); 227 return NULL; 228 } 229 230 data->klass = &hb_old_font_class; 231 data->x_ppem = font->x_ppem; 232 data->y_ppem = font->y_ppem; 233 data->x_scale = font->x_scale; /* XXX */ 234 data->y_scale = font->y_scale; /* XXX */ 235 data->userData = font; 236 237 return data; 238 } 239 240 void 241 _hb_old_shaper_font_data_destroy (hb_old_shaper_font_data_t *data) 242 { 243 free (data); 244 } 245 246 247 /* 248 * shaper shape_plan data 249 */ 250 251 struct hb_old_shaper_shape_plan_data_t {}; 252 253 hb_old_shaper_shape_plan_data_t * 254 _hb_old_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 255 const hb_feature_t *user_features HB_UNUSED, 256 unsigned int num_user_features HB_UNUSED) 257 { 258 return (hb_old_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 259 } 260 261 void 262 _hb_old_shaper_shape_plan_data_destroy (hb_old_shaper_shape_plan_data_t *data HB_UNUSED) 263 { 264 } 265 266 267 /* 268 * shaper 269 */ 270 271 hb_bool_t 272 _hb_old_shape (hb_shape_plan_t *shape_plan HB_UNUSED, 273 hb_font_t *font, 274 hb_buffer_t *buffer, 275 const hb_feature_t *features, 276 unsigned int num_features) 277 { 278 hb_face_t *face = font->face; 279 HB_Face old_face = HB_SHAPER_DATA_GET (face); 280 HB_Font old_font = HB_SHAPER_DATA_GET (font); 281 282 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 283 284 retry: 285 286 unsigned int scratch_size; 287 char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size); 288 289 #define utf16_index() var1.u32 290 HB_UChar16 *pchars = (HB_UChar16 *) scratch; 291 unsigned int chars_len = 0; 292 for (unsigned int i = 0; i < buffer->len; i++) { 293 hb_codepoint_t c = buffer->info[i].codepoint; 294 buffer->info[i].utf16_index() = chars_len; 295 if (likely (c < 0x10000)) 296 pchars[chars_len++] = c; 297 else if (unlikely (c >= 0x110000)) 298 pchars[chars_len++] = 0xFFFD; 299 else { 300 pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); 301 pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); 302 } 303 } 304 305 306 #define ALLOCATE_ARRAY(Type, name, len) \ 307 name = (Type *) scratch; \ 308 scratch += (len) * sizeof ((name)[0]); \ 309 scratch_size -= (len) * sizeof ((name)[0]); 310 311 312 HB_ShaperItem item = {0}; 313 314 ALLOCATE_ARRAY (const HB_UChar16, item.string, chars_len); 315 ALLOCATE_ARRAY (unsigned short, item.log_clusters, chars_len + 2); 316 item.stringLength = chars_len; 317 item.item.pos = 0; 318 item.item.length = item.stringLength; 319 item.item.script = hb_old_script_from_script (buffer->props.script); 320 item.item.bidiLevel = backward ? 1 : 0; 321 322 item.font = old_font; 323 item.face = old_face; 324 item.shaperFlags = 0; 325 326 item.glyphIndicesPresent = false; 327 328 /* TODO Alignment. */ 329 unsigned int num_glyphs = scratch_size / (sizeof (HB_Glyph) + 330 sizeof (HB_GlyphAttributes) + 331 sizeof (HB_Fixed) + 332 sizeof (HB_FixedPoint) + 333 sizeof (uint32_t)); 334 335 item.num_glyphs = num_glyphs; 336 ALLOCATE_ARRAY (HB_Glyph, item.glyphs, num_glyphs); 337 ALLOCATE_ARRAY (HB_GlyphAttributes, item.attributes, num_glyphs); 338 ALLOCATE_ARRAY (HB_Fixed, item.advances, num_glyphs); 339 ALLOCATE_ARRAY (HB_FixedPoint, item.offsets, num_glyphs); 340 /* Apparently in some cases the offsets array will not be fully assigned to. 341 * Clear it. */ 342 memset (item.offsets, 0, num_glyphs * sizeof (item.offsets[0])); 343 uint32_t *vis_clusters; 344 ALLOCATE_ARRAY (uint32_t, vis_clusters, num_glyphs); 345 346 #undef ALLOCATE_ARRAY 347 348 if (!HB_ShapeItem (&item)) 349 { 350 if (unlikely (item.num_glyphs > num_glyphs)) 351 { 352 buffer->ensure (buffer->allocated * 2); 353 if (buffer->in_error) 354 return false; 355 goto retry; 356 } 357 return false; 358 } 359 num_glyphs = item.num_glyphs; 360 361 /* Ok, we've got everything we need, now compose output buffer, 362 * very, *very*, carefully! */ 363 364 /* Calculate visual-clusters. That's what we ship. */ 365 for (unsigned int i = 0; i < num_glyphs; i++) 366 vis_clusters[i] = -1; 367 for (unsigned int i = 0; i < buffer->len; i++) { 368 uint32_t *p = &vis_clusters[item.log_clusters[buffer->info[i].utf16_index()]]; 369 *p = MIN (*p, buffer->info[i].cluster); 370 } 371 for (unsigned int i = 1; i < num_glyphs; i++) 372 if (vis_clusters[i] == (uint32_t) -1) 373 vis_clusters[i] = vis_clusters[i - 1]; 374 375 #undef utf16_index 376 377 buffer->ensure (num_glyphs); 378 if (buffer->in_error) 379 return false; 380 381 382 buffer->len = num_glyphs; 383 hb_glyph_info_t *info = buffer->info; 384 for (unsigned int i = 0; i < num_glyphs; i++) 385 { 386 info[i].codepoint = item.glyphs[i]; 387 info[i].cluster = vis_clusters[i]; 388 389 info[i].mask = item.advances[i]; 390 info[i].var1.u32 = item.offsets[i].x; 391 info[i].var2.u32 = item.offsets[i].y; 392 } 393 394 buffer->clear_positions (); 395 396 for (unsigned int i = 0; i < num_glyphs; ++i) { 397 hb_glyph_info_t *info = &buffer->info[i]; 398 hb_glyph_position_t *pos = &buffer->pos[i]; 399 400 /* TODO vertical */ 401 pos->x_advance = info->mask; 402 pos->x_offset = info->var1.u32; 403 pos->y_offset = info->var2.u32; 404 } 405 406 if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) 407 buffer->reverse (); 408 409 return true; 410 } 411