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 icu_le 28 #define hb_icu_le_shaper_font_data_t PortableFontInstance 29 #include "hb-shaper-impl-private.hh" 30 31 #include "hb-icu-le/PortableFontInstance.h" 32 33 #include "layout/loengine.h" 34 #include "unicode/unistr.h" 35 36 #include "hb-icu.h" 37 38 39 /* 40 * shaper face data 41 */ 42 43 struct hb_icu_le_shaper_face_data_t {}; 44 45 hb_icu_le_shaper_face_data_t * 46 _hb_icu_le_shaper_face_data_create (hb_face_t *face HB_UNUSED) 47 { 48 return (hb_icu_le_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED; 49 } 50 51 void 52 _hb_icu_le_shaper_face_data_destroy (hb_icu_le_shaper_face_data_t *data HB_UNUSED) 53 { 54 } 55 56 57 /* 58 * shaper font data 59 */ 60 61 hb_icu_le_shaper_font_data_t * 62 _hb_icu_le_shaper_font_data_create (hb_font_t *font) 63 { 64 LEErrorCode status = LE_NO_ERROR; 65 hb_icu_le_shaper_font_data_t *data = new PortableFontInstance (font->face, 66 font->x_scale, 67 font->y_scale, 68 status); 69 if (status != LE_NO_ERROR) { 70 delete (data); 71 return NULL; 72 } 73 74 return data; 75 } 76 77 void 78 _hb_icu_le_shaper_font_data_destroy (hb_icu_le_shaper_font_data_t *data) 79 { 80 delete (data); 81 } 82 83 84 /* 85 * shaper shape_plan data 86 */ 87 88 struct hb_icu_le_shaper_shape_plan_data_t {}; 89 90 hb_icu_le_shaper_shape_plan_data_t * 91 _hb_icu_le_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 92 const hb_feature_t *user_features, 93 unsigned int num_user_features) 94 { 95 return (hb_icu_le_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 96 } 97 98 void 99 _hb_icu_le_shaper_shape_plan_data_destroy (hb_icu_le_shaper_shape_plan_data_t *data) 100 { 101 } 102 103 104 /* 105 * shaper 106 */ 107 108 hb_bool_t 109 _hb_icu_le_shape (hb_shape_plan_t *shape_plan, 110 hb_font_t *font, 111 hb_buffer_t *buffer, 112 const hb_feature_t *features, 113 unsigned int num_features) 114 { 115 LEFontInstance *font_instance = HB_SHAPER_DATA_GET (font); 116 le_int32 script_code = hb_icu_script_from_script (shape_plan->props.script); 117 le_int32 language_code = -1 /* TODO */; 118 le_int32 typography_flags = 3; /* Needed for ligatures and kerning */ 119 LEErrorCode status = LE_NO_ERROR; 120 le_engine *le = le_create ((const le_font *) font_instance, 121 script_code, 122 language_code, 123 typography_flags, 124 &status); 125 if (status != LE_NO_ERROR) 126 { le_close (le); return false; } 127 128 retry: 129 130 unsigned int scratch_size; 131 char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size); 132 133 #define ALLOCATE_ARRAY(Type, name, len) \ 134 Type *name = (Type *) scratch; \ 135 scratch += (len) * sizeof ((name)[0]); \ 136 scratch_size -= (len) * sizeof ((name)[0]); 137 138 ALLOCATE_ARRAY (LEUnicode, chars, buffer->len); 139 ALLOCATE_ARRAY (unsigned int, clusters, buffer->len); 140 141 /* XXX Use UTF-16 decoder! */ 142 for (unsigned int i = 0; i < buffer->len; i++) { 143 chars[i] = buffer->info[i].codepoint; 144 clusters[i] = buffer->info[i].cluster; 145 } 146 147 unsigned int glyph_count = le_layoutChars (le, 148 chars, 149 0, 150 buffer->len, 151 buffer->len, 152 HB_DIRECTION_IS_BACKWARD (buffer->props.direction), 153 0., 0., 154 &status); 155 if (status != LE_NO_ERROR) 156 { le_close (le); return false; } 157 158 unsigned int num_glyphs = scratch_size / (sizeof (LEGlyphID) + 159 sizeof (le_int32) + 160 sizeof (float) * 2); 161 162 if (unlikely (glyph_count >= num_glyphs || glyph_count > buffer->allocated)) { 163 buffer->ensure (buffer->allocated * 2); 164 if (buffer->in_error) 165 { le_close (le); return false; } 166 goto retry; 167 } 168 169 ALLOCATE_ARRAY (LEGlyphID, glyphs, glyph_count); 170 ALLOCATE_ARRAY (le_int32, indices, glyph_count); 171 ALLOCATE_ARRAY (float, positions, glyph_count * 2 + 2); 172 173 le_getGlyphs (le, glyphs, &status); 174 le_getCharIndices (le, indices, &status); 175 le_getGlyphPositions (le, positions, &status); 176 177 #undef ALLOCATE_ARRAY 178 179 /* Ok, we've got everything we need, now compose output buffer, 180 * very, *very*, carefully! */ 181 182 unsigned int j = 0; 183 hb_glyph_info_t *info = buffer->info; 184 for (unsigned int i = 0; i < glyph_count; i++) 185 { 186 if (glyphs[i] >= 0xFFFE) 187 continue; 188 189 info[j].codepoint = glyphs[i]; 190 info[j].cluster = clusters[indices[i]]; 191 192 /* icu-le doesn't seem to have separate advance values. */ 193 info[j].mask = positions[2 * i + 2] - positions[2 * i]; 194 info[j].var1.u32 = 0; 195 info[j].var2.u32 = -positions[2 * i + 1]; 196 197 j++; 198 } 199 buffer->len = j; 200 201 buffer->clear_positions (); 202 203 for (unsigned int i = 0; i < buffer->len; i++) { 204 hb_glyph_info_t *info = &buffer->info[i]; 205 hb_glyph_position_t *pos = &buffer->pos[i]; 206 207 /* TODO vertical */ 208 pos->x_advance = info->mask; 209 pos->x_offset = info->var1.u32; 210 pos->y_offset = info->var2.u32; 211 } 212 213 le_close (le); 214 return true; 215 } 216