1 /* 2 * Copyright 2012 Mozilla Foundation. 3 * Copyright 2012 Google, Inc. 4 * 5 * This is part of HarfBuzz, a text shaping library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 * 25 * Mozilla Author(s): Jonathan Kew 26 * Google Author(s): Behdad Esfahbod 27 */ 28 29 #define HB_SHAPER coretext 30 #include "hb-shaper-impl-private.hh" 31 32 #include "hb-coretext.h" 33 34 35 #ifndef HB_DEBUG_CORETEXT 36 #define HB_DEBUG_CORETEXT (HB_DEBUG+0) 37 #endif 38 39 40 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) 41 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) 42 43 44 /* 45 * shaper face data 46 */ 47 48 struct hb_coretext_shaper_face_data_t { 49 CGFontRef cg_font; 50 }; 51 52 static void 53 release_data (void *info, const void *data, size_t size) 54 { 55 assert (hb_blob_get_length ((hb_blob_t *) info) == size && 56 hb_blob_get_data ((hb_blob_t *) info, NULL) == data); 57 58 hb_blob_destroy ((hb_blob_t *) info); 59 } 60 61 hb_coretext_shaper_face_data_t * 62 _hb_coretext_shaper_face_data_create (hb_face_t *face) 63 { 64 hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t)); 65 if (unlikely (!data)) 66 return NULL; 67 68 hb_blob_t *blob = hb_face_reference_blob (face); 69 unsigned int blob_length; 70 const char *blob_data = hb_blob_get_data (blob, &blob_length); 71 if (unlikely (!blob_length)) 72 DEBUG_MSG (CORETEXT, face, "Face has empty blob"); 73 74 CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data); 75 data->cg_font = CGFontCreateWithDataProvider (provider); 76 CGDataProviderRelease (provider); 77 78 if (unlikely (!data->cg_font)) { 79 DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); 80 free (data); 81 return NULL; 82 } 83 84 return data; 85 } 86 87 void 88 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) 89 { 90 CFRelease (data->cg_font); 91 free (data); 92 } 93 94 CGFontRef 95 hb_coretext_face_get_cg_font (hb_face_t *face) 96 { 97 if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; 98 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 99 return face_data->cg_font; 100 } 101 102 103 /* 104 * shaper font data 105 */ 106 107 struct hb_coretext_shaper_font_data_t { 108 CTFontRef ct_font; 109 }; 110 111 hb_coretext_shaper_font_data_t * 112 _hb_coretext_shaper_font_data_create (hb_font_t *font) 113 { 114 if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL; 115 116 hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t)); 117 if (unlikely (!data)) 118 return NULL; 119 120 hb_face_t *face = font->face; 121 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 122 123 data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL); 124 if (unlikely (!data->ct_font)) { 125 DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); 126 free (data); 127 return NULL; 128 } 129 130 return data; 131 } 132 133 void 134 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data) 135 { 136 CFRelease (data->ct_font); 137 free (data); 138 } 139 140 141 /* 142 * shaper shape_plan data 143 */ 144 145 struct hb_coretext_shaper_shape_plan_data_t {}; 146 147 hb_coretext_shaper_shape_plan_data_t * 148 _hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 149 const hb_feature_t *user_features HB_UNUSED, 150 unsigned int num_user_features HB_UNUSED) 151 { 152 return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 153 } 154 155 void 156 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED) 157 { 158 } 159 160 CTFontRef 161 hb_coretext_font_get_ct_font (hb_font_t *font) 162 { 163 if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL; 164 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 165 return font_data->ct_font; 166 } 167 168 169 /* 170 * shaper 171 */ 172 173 hb_bool_t 174 _hb_coretext_shape (hb_shape_plan_t *shape_plan, 175 hb_font_t *font, 176 hb_buffer_t *buffer, 177 const hb_feature_t *features, 178 unsigned int num_features) 179 { 180 hb_face_t *face = font->face; 181 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 182 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 183 184 #define FAIL(...) \ 185 HB_STMT_START { \ 186 DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \ 187 return false; \ 188 } HB_STMT_END; 189 190 unsigned int scratch_size; 191 char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size); 192 193 #define utf16_index() var1.u32 194 195 UniChar *pchars = (UniChar *) scratch; 196 unsigned int chars_len = 0; 197 for (unsigned int i = 0; i < buffer->len; i++) { 198 hb_codepoint_t c = buffer->info[i].codepoint; 199 buffer->info[i].utf16_index() = chars_len; 200 if (likely (c < 0x10000)) 201 pchars[chars_len++] = c; 202 else if (unlikely (c >= 0x110000)) 203 pchars[chars_len++] = 0xFFFD; 204 else { 205 pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); 206 pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); 207 } 208 } 209 210 #undef utf16_index 211 212 CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (kCFAllocatorDefault, 213 pchars, chars_len, 214 kCFAllocatorNull); 215 216 CFDictionaryRef attrs = CFDictionaryCreate (kCFAllocatorDefault, 217 (const void**) &kCTFontAttributeName, 218 (const void**) &font_data->ct_font, 219 1, /* count of attributes */ 220 &kCFTypeDictionaryKeyCallBacks, 221 &kCFTypeDictionaryValueCallBacks); 222 223 /* TODO: support features */ 224 225 CFAttributedStringRef attr_string = CFAttributedStringCreate (kCFAllocatorDefault, string_ref, attrs); 226 CFRelease (string_ref); 227 CFRelease (attrs); 228 229 CTLineRef line = CTLineCreateWithAttributedString (attr_string); 230 CFRelease (attr_string); 231 232 CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); 233 unsigned int num_runs = CFArrayGetCount (glyph_runs); 234 235 bool success = true; 236 buffer->len = 0; 237 238 const CFRange range_all = CFRangeMake (0, 0); 239 240 for (unsigned int i = 0; i < num_runs; i++) { 241 CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i); 242 243 unsigned int num_glyphs = CTRunGetGlyphCount (run); 244 if (num_glyphs == 0) 245 continue; 246 247 buffer->ensure (buffer->len + num_glyphs); 248 249 /* Testing indicates that CTRunGetGlyphsPtr (almost?) always succeeds, 250 * and so copying data to our own buffer with CTRunGetGlyphs will be 251 * extremely rare. */ 252 253 unsigned int scratch_size; 254 char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size); 255 256 #define ALLOCATE_ARRAY(Type, name, len) \ 257 Type *name = (Type *) scratch; \ 258 scratch += (len) * sizeof ((name)[0]); \ 259 scratch_size -= (len) * sizeof ((name)[0]); 260 261 const CGGlyph* glyphs = CTRunGetGlyphsPtr (run); 262 if (!glyphs) { 263 ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs); 264 CTRunGetGlyphs (run, range_all, glyph_buf); 265 glyphs = glyph_buf; 266 } 267 268 const CGPoint* positions = CTRunGetPositionsPtr (run); 269 if (!positions) { 270 ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs); 271 CTRunGetPositions (run, range_all, position_buf); 272 positions = position_buf; 273 } 274 275 const CFIndex* string_indices = CTRunGetStringIndicesPtr (run); 276 if (!string_indices) { 277 ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs); 278 CTRunGetStringIndices (run, range_all, index_buf); 279 string_indices = index_buf; 280 } 281 282 #undef ALLOCATE_ARRAY 283 284 double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL); 285 286 for (unsigned int j = 0; j < num_glyphs; j++) { 287 double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x; 288 289 hb_glyph_info_t *info = &buffer->info[buffer->len]; 290 hb_glyph_position_t *pos = &buffer->pos[buffer->len]; 291 292 info->codepoint = glyphs[j]; 293 info->cluster = string_indices[j]; 294 295 /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */ 296 info->mask = advance; 297 info->var1.u32 = 0; 298 info->var2.u32 = positions[j].y; 299 300 buffer->len++; 301 } 302 } 303 304 buffer->clear_positions (); 305 306 unsigned int count = buffer->len; 307 for (unsigned int i = 0; i < count; ++i) { 308 hb_glyph_info_t *info = &buffer->info[i]; 309 hb_glyph_position_t *pos = &buffer->pos[i]; 310 311 /* TODO vertical */ 312 pos->x_advance = info->mask; 313 pos->x_offset = info->var1.u32; 314 pos->y_offset = info->var2.u32; 315 } 316 317 /* Fix up clusters so that we never return out-of-order indices; 318 * if core text has reordered glyphs, we'll merge them to the 319 * beginning of the reordered cluster. 320 * 321 * This does *not* mean we'll form the same clusters as Uniscribe 322 * or the native OT backend, only that the cluster indices will be 323 * monotonic in the output buffer. */ 324 if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { 325 unsigned int prev_cluster = 0; 326 for (unsigned int i = 0; i < count; i++) { 327 unsigned int curr_cluster = buffer->info[i].cluster; 328 if (curr_cluster < prev_cluster) { 329 for (unsigned int j = i; j > 0; j--) { 330 if (buffer->info[j - 1].cluster > curr_cluster) 331 buffer->info[j - 1].cluster = curr_cluster; 332 else 333 break; 334 } 335 } 336 prev_cluster = curr_cluster; 337 } 338 } else { 339 unsigned int prev_cluster = (unsigned int)-1; 340 for (unsigned int i = 0; i < count; i++) { 341 unsigned int curr_cluster = buffer->info[i].cluster; 342 if (curr_cluster > prev_cluster) { 343 for (unsigned int j = i; j > 0; j--) { 344 if (buffer->info[j - 1].cluster < curr_cluster) 345 buffer->info[j - 1].cluster = curr_cluster; 346 else 347 break; 348 } 349 } 350 prev_cluster = curr_cluster; 351 } 352 } 353 354 return true; 355 } 356