1 /* 2 * Copyright 2012,2013 Mozilla Foundation. 3 * Copyright 2012,2013 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 static void 41 release_table_data (void *user_data) 42 { 43 CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data); 44 CFRelease(cf_data); 45 } 46 47 static hb_blob_t * 48 reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) 49 { 50 CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data); 51 CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag); 52 if (unlikely (!cf_data)) 53 return NULL; 54 55 const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data)); 56 const size_t length = CFDataGetLength (cf_data); 57 if (!data || !length) 58 return NULL; 59 60 return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY, 61 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)), 62 release_table_data); 63 } 64 65 hb_face_t * 66 hb_coretext_face_create (CGFontRef cg_font) 67 { 68 return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease); 69 } 70 71 72 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) 73 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) 74 75 76 /* 77 * shaper face data 78 */ 79 80 struct hb_coretext_shaper_face_data_t { 81 CGFontRef cg_font; 82 }; 83 84 static void 85 release_data (void *info, const void *data, size_t size) 86 { 87 assert (hb_blob_get_length ((hb_blob_t *) info) == size && 88 hb_blob_get_data ((hb_blob_t *) info, NULL) == data); 89 90 hb_blob_destroy ((hb_blob_t *) info); 91 } 92 93 hb_coretext_shaper_face_data_t * 94 _hb_coretext_shaper_face_data_create (hb_face_t *face) 95 { 96 hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t)); 97 if (unlikely (!data)) 98 return NULL; 99 100 if (face->destroy == (hb_destroy_func_t) CGFontRelease) 101 { 102 data->cg_font = CGFontRetain ((CGFontRef) face->user_data); 103 } 104 else 105 { 106 hb_blob_t *blob = hb_face_reference_blob (face); 107 unsigned int blob_length; 108 const char *blob_data = hb_blob_get_data (blob, &blob_length); 109 if (unlikely (!blob_length)) 110 DEBUG_MSG (CORETEXT, face, "Face has empty blob"); 111 112 CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data); 113 data->cg_font = CGFontCreateWithDataProvider (provider); 114 CGDataProviderRelease (provider); 115 } 116 117 if (unlikely (!data->cg_font)) { 118 DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); 119 free (data); 120 return NULL; 121 } 122 123 return data; 124 } 125 126 void 127 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) 128 { 129 CFRelease (data->cg_font); 130 free (data); 131 } 132 133 CGFontRef 134 hb_coretext_face_get_cg_font (hb_face_t *face) 135 { 136 if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; 137 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 138 return face_data->cg_font; 139 } 140 141 142 /* 143 * shaper font data 144 */ 145 146 struct hb_coretext_shaper_font_data_t { 147 CTFontRef ct_font; 148 }; 149 150 hb_coretext_shaper_font_data_t * 151 _hb_coretext_shaper_font_data_create (hb_font_t *font) 152 { 153 if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL; 154 155 hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t)); 156 if (unlikely (!data)) 157 return NULL; 158 159 hb_face_t *face = font->face; 160 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 161 162 data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL); 163 if (unlikely (!data->ct_font)) { 164 DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); 165 free (data); 166 return NULL; 167 } 168 169 return data; 170 } 171 172 void 173 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data) 174 { 175 CFRelease (data->ct_font); 176 free (data); 177 } 178 179 180 /* 181 * shaper shape_plan data 182 */ 183 184 struct hb_coretext_shaper_shape_plan_data_t {}; 185 186 hb_coretext_shaper_shape_plan_data_t * 187 _hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 188 const hb_feature_t *user_features HB_UNUSED, 189 unsigned int num_user_features HB_UNUSED) 190 { 191 return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 192 } 193 194 void 195 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED) 196 { 197 } 198 199 CTFontRef 200 hb_coretext_font_get_ct_font (hb_font_t *font) 201 { 202 if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL; 203 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 204 return font_data->ct_font; 205 } 206 207 208 /* 209 * shaper 210 */ 211 212 struct feature_record_t { 213 unsigned int feature; 214 unsigned int setting; 215 }; 216 217 struct active_feature_t { 218 feature_record_t rec; 219 unsigned int order; 220 221 static int cmp (const active_feature_t *a, const active_feature_t *b) { 222 return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 : 223 a->order < b->order ? -1 : a->order > b->order ? 1 : 224 a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 : 225 0; 226 } 227 bool operator== (const active_feature_t *f) { 228 return cmp (this, f) == 0; 229 } 230 }; 231 232 struct feature_event_t { 233 unsigned int index; 234 bool start; 235 active_feature_t feature; 236 237 static int cmp (const feature_event_t *a, const feature_event_t *b) { 238 return a->index < b->index ? -1 : a->index > b->index ? 1 : 239 a->start < b->start ? -1 : a->start > b->start ? 1 : 240 active_feature_t::cmp (&a->feature, &b->feature); 241 } 242 }; 243 244 struct range_record_t { 245 CTFontRef font; 246 unsigned int index_first; /* == start */ 247 unsigned int index_last; /* == end - 1 */ 248 }; 249 250 251 /* The following enum members are added in OS X 10.8. */ 252 #define kAltHalfWidthTextSelector 6 253 #define kAltProportionalTextSelector 5 254 #define kAlternateHorizKanaOffSelector 1 255 #define kAlternateHorizKanaOnSelector 0 256 #define kAlternateKanaType 34 257 #define kAlternateVertKanaOffSelector 3 258 #define kAlternateVertKanaOnSelector 2 259 #define kCaseSensitiveLayoutOffSelector 1 260 #define kCaseSensitiveLayoutOnSelector 0 261 #define kCaseSensitiveLayoutType 33 262 #define kCaseSensitiveSpacingOffSelector 3 263 #define kCaseSensitiveSpacingOnSelector 2 264 #define kContextualAlternatesOffSelector 1 265 #define kContextualAlternatesOnSelector 0 266 #define kContextualAlternatesType 36 267 #define kContextualLigaturesOffSelector 19 268 #define kContextualLigaturesOnSelector 18 269 #define kContextualSwashAlternatesOffSelector 5 270 #define kContextualSwashAlternatesOnSelector 4 271 #define kDefaultLowerCaseSelector 0 272 #define kDefaultUpperCaseSelector 0 273 #define kHistoricalLigaturesOffSelector 21 274 #define kHistoricalLigaturesOnSelector 20 275 #define kHojoCharactersSelector 12 276 #define kJIS2004CharactersSelector 11 277 #define kLowerCasePetiteCapsSelector 2 278 #define kLowerCaseSmallCapsSelector 1 279 #define kLowerCaseType 37 280 #define kMathematicalGreekOffSelector 11 281 #define kMathematicalGreekOnSelector 10 282 #define kNLCCharactersSelector 13 283 #define kQuarterWidthTextSelector 4 284 #define kScientificInferiorsSelector 4 285 #define kStylisticAltEightOffSelector 17 286 #define kStylisticAltEightOnSelector 16 287 #define kStylisticAltEighteenOffSelector 37 288 #define kStylisticAltEighteenOnSelector 36 289 #define kStylisticAltElevenOffSelector 23 290 #define kStylisticAltElevenOnSelector 22 291 #define kStylisticAltFifteenOffSelector 31 292 #define kStylisticAltFifteenOnSelector 30 293 #define kStylisticAltFiveOffSelector 11 294 #define kStylisticAltFiveOnSelector 10 295 #define kStylisticAltFourOffSelector 9 296 #define kStylisticAltFourOnSelector 8 297 #define kStylisticAltFourteenOffSelector 29 298 #define kStylisticAltFourteenOnSelector 28 299 #define kStylisticAltNineOffSelector 19 300 #define kStylisticAltNineOnSelector 18 301 #define kStylisticAltNineteenOffSelector 39 302 #define kStylisticAltNineteenOnSelector 38 303 #define kStylisticAltOneOffSelector 3 304 #define kStylisticAltOneOnSelector 2 305 #define kStylisticAltSevenOffSelector 15 306 #define kStylisticAltSevenOnSelector 14 307 #define kStylisticAltSeventeenOffSelector 35 308 #define kStylisticAltSeventeenOnSelector 34 309 #define kStylisticAltSixOffSelector 13 310 #define kStylisticAltSixOnSelector 12 311 #define kStylisticAltSixteenOffSelector 33 312 #define kStylisticAltSixteenOnSelector 32 313 #define kStylisticAltTenOffSelector 21 314 #define kStylisticAltTenOnSelector 20 315 #define kStylisticAltThirteenOffSelector 27 316 #define kStylisticAltThirteenOnSelector 26 317 #define kStylisticAltThreeOffSelector 7 318 #define kStylisticAltThreeOnSelector 6 319 #define kStylisticAltTwelveOffSelector 25 320 #define kStylisticAltTwelveOnSelector 24 321 #define kStylisticAltTwentyOffSelector 41 322 #define kStylisticAltTwentyOnSelector 40 323 #define kStylisticAltTwoOffSelector 5 324 #define kStylisticAltTwoOnSelector 4 325 #define kStylisticAlternativesType 35 326 #define kSwashAlternatesOffSelector 3 327 #define kSwashAlternatesOnSelector 2 328 #define kThirdWidthTextSelector 3 329 #define kTraditionalNamesCharactersSelector 14 330 #define kUpperCasePetiteCapsSelector 2 331 #define kUpperCaseSmallCapsSelector 1 332 #define kUpperCaseType 38 333 334 /* Table data courtesy of Apple. */ 335 struct feature_mapping_t { 336 FourCharCode otFeatureTag; 337 uint16_t aatFeatureType; 338 uint16_t selectorToEnable; 339 uint16_t selectorToDisable; 340 } feature_mappings[] = { 341 { 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector, kDefaultUpperCaseSelector }, 342 { 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector, kDefaultUpperCaseSelector }, 343 { 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector }, 344 { 'case', kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOffSelector }, 345 { 'clig', kLigaturesType, kContextualLigaturesOnSelector, kContextualLigaturesOffSelector }, 346 { 'cpsp', kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOffSelector }, 347 { 'cswh', kContextualAlternatesType, kContextualSwashAlternatesOnSelector, kContextualSwashAlternatesOffSelector }, 348 { 'dlig', kLigaturesType, kRareLigaturesOnSelector, kRareLigaturesOffSelector }, 349 { 'expt', kCharacterShapeType, kExpertCharactersSelector, 16 }, 350 { 'frac', kFractionsType, kDiagonalFractionsSelector, kNoFractionsSelector }, 351 { 'fwid', kTextSpacingType, kMonospacedTextSelector, 7 }, 352 { 'halt', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, 353 { 'hist', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, 354 { 'hkna', kAlternateKanaType, kAlternateHorizKanaOnSelector, kAlternateHorizKanaOffSelector, }, 355 { 'hlig', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, 356 { 'hngl', kTransliterationType, kHanjaToHangulSelector, kNoTransliterationSelector }, 357 { 'hojo', kCharacterShapeType, kHojoCharactersSelector, 16 }, 358 { 'hwid', kTextSpacingType, kHalfWidthTextSelector, 7 }, 359 { 'ital', kItalicCJKRomanType, kCJKItalicRomanOnSelector, kCJKItalicRomanOffSelector }, 360 { 'jp04', kCharacterShapeType, kJIS2004CharactersSelector, 16 }, 361 { 'jp78', kCharacterShapeType, kJIS1978CharactersSelector, 16 }, 362 { 'jp83', kCharacterShapeType, kJIS1983CharactersSelector, 16 }, 363 { 'jp90', kCharacterShapeType, kJIS1990CharactersSelector, 16 }, 364 { 'liga', kLigaturesType, kCommonLigaturesOnSelector, kCommonLigaturesOffSelector }, 365 { 'lnum', kNumberCaseType, kUpperCaseNumbersSelector, 2 }, 366 { 'mgrk', kMathematicalExtrasType, kMathematicalGreekOnSelector, kMathematicalGreekOffSelector }, 367 { 'nlck', kCharacterShapeType, kNLCCharactersSelector, 16 }, 368 { 'onum', kNumberCaseType, kLowerCaseNumbersSelector, 2 }, 369 { 'ordn', kVerticalPositionType, kOrdinalsSelector, kNormalPositionSelector }, 370 { 'palt', kTextSpacingType, kAltProportionalTextSelector, 7 }, 371 { 'pcap', kLowerCaseType, kLowerCasePetiteCapsSelector, kDefaultLowerCaseSelector }, 372 { 'pkna', kTextSpacingType, kProportionalTextSelector, 7 }, 373 { 'pnum', kNumberSpacingType, kProportionalNumbersSelector, 4 }, 374 { 'pwid', kTextSpacingType, kProportionalTextSelector, 7 }, 375 { 'qwid', kTextSpacingType, kQuarterWidthTextSelector, 7 }, 376 { 'ruby', kRubyKanaType, kRubyKanaOnSelector, kRubyKanaOffSelector }, 377 { 'sinf', kVerticalPositionType, kScientificInferiorsSelector, kNormalPositionSelector }, 378 { 'smcp', kLowerCaseType, kLowerCaseSmallCapsSelector, kDefaultLowerCaseSelector }, 379 { 'smpl', kCharacterShapeType, kSimplifiedCharactersSelector, 16 }, 380 { 'ss01', kStylisticAlternativesType, kStylisticAltOneOnSelector, kStylisticAltOneOffSelector }, 381 { 'ss02', kStylisticAlternativesType, kStylisticAltTwoOnSelector, kStylisticAltTwoOffSelector }, 382 { 'ss03', kStylisticAlternativesType, kStylisticAltThreeOnSelector, kStylisticAltThreeOffSelector }, 383 { 'ss04', kStylisticAlternativesType, kStylisticAltFourOnSelector, kStylisticAltFourOffSelector }, 384 { 'ss05', kStylisticAlternativesType, kStylisticAltFiveOnSelector, kStylisticAltFiveOffSelector }, 385 { 'ss06', kStylisticAlternativesType, kStylisticAltSixOnSelector, kStylisticAltSixOffSelector }, 386 { 'ss07', kStylisticAlternativesType, kStylisticAltSevenOnSelector, kStylisticAltSevenOffSelector }, 387 { 'ss08', kStylisticAlternativesType, kStylisticAltEightOnSelector, kStylisticAltEightOffSelector }, 388 { 'ss09', kStylisticAlternativesType, kStylisticAltNineOnSelector, kStylisticAltNineOffSelector }, 389 { 'ss10', kStylisticAlternativesType, kStylisticAltTenOnSelector, kStylisticAltTenOffSelector }, 390 { 'ss11', kStylisticAlternativesType, kStylisticAltElevenOnSelector, kStylisticAltElevenOffSelector }, 391 { 'ss12', kStylisticAlternativesType, kStylisticAltTwelveOnSelector, kStylisticAltTwelveOffSelector }, 392 { 'ss13', kStylisticAlternativesType, kStylisticAltThirteenOnSelector, kStylisticAltThirteenOffSelector }, 393 { 'ss14', kStylisticAlternativesType, kStylisticAltFourteenOnSelector, kStylisticAltFourteenOffSelector }, 394 { 'ss15', kStylisticAlternativesType, kStylisticAltFifteenOnSelector, kStylisticAltFifteenOffSelector }, 395 { 'ss16', kStylisticAlternativesType, kStylisticAltSixteenOnSelector, kStylisticAltSixteenOffSelector }, 396 { 'ss17', kStylisticAlternativesType, kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOffSelector }, 397 { 'ss18', kStylisticAlternativesType, kStylisticAltEighteenOnSelector, kStylisticAltEighteenOffSelector }, 398 { 'ss19', kStylisticAlternativesType, kStylisticAltNineteenOnSelector, kStylisticAltNineteenOffSelector }, 399 { 'ss20', kStylisticAlternativesType, kStylisticAltTwentyOnSelector, kStylisticAltTwentyOffSelector }, 400 { 'subs', kVerticalPositionType, kInferiorsSelector, kNormalPositionSelector }, 401 { 'sups', kVerticalPositionType, kSuperiorsSelector, kNormalPositionSelector }, 402 { 'swsh', kContextualAlternatesType, kSwashAlternatesOnSelector, kSwashAlternatesOffSelector }, 403 { 'titl', kStyleOptionsType, kTitlingCapsSelector, kNoStyleOptionsSelector }, 404 { 'tnam', kCharacterShapeType, kTraditionalNamesCharactersSelector, 16 }, 405 { 'tnum', kNumberSpacingType, kMonospacedNumbersSelector, 4 }, 406 { 'trad', kCharacterShapeType, kTraditionalCharactersSelector, 16 }, 407 { 'twid', kTextSpacingType, kThirdWidthTextSelector, 7 }, 408 { 'unic', kLetterCaseType, 14, 15 }, 409 { 'valt', kTextSpacingType, kAltProportionalTextSelector, 7 }, 410 { 'vert', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, 411 { 'vhal', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, 412 { 'vkna', kAlternateKanaType, kAlternateVertKanaOnSelector, kAlternateVertKanaOffSelector }, 413 { 'vpal', kTextSpacingType, kAltProportionalTextSelector, 7 }, 414 { 'vrt2', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, 415 { 'zero', kTypographicExtrasType, kSlashedZeroOnSelector, kSlashedZeroOffSelector }, 416 }; 417 418 static int 419 _hb_feature_mapping_cmp (const void *key_, const void *entry_) 420 { 421 unsigned int key = * (unsigned int *) key_; 422 const feature_mapping_t * entry = (const feature_mapping_t *) entry_; 423 return key < entry->otFeatureTag ? -1 : 424 key > entry->otFeatureTag ? 1 : 425 0; 426 } 427 428 hb_bool_t 429 _hb_coretext_shape (hb_shape_plan_t *shape_plan, 430 hb_font_t *font, 431 hb_buffer_t *buffer, 432 const hb_feature_t *features, 433 unsigned int num_features) 434 { 435 hb_face_t *face = font->face; 436 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 437 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 438 439 /* 440 * Set up features. 441 * (copied + modified from code from hb-uniscribe.cc) 442 */ 443 hb_auto_array_t<feature_record_t> feature_records; 444 hb_auto_array_t<range_record_t> range_records; 445 if (num_features) 446 { 447 /* Sort features by start/end events. */ 448 hb_auto_array_t<feature_event_t> feature_events; 449 for (unsigned int i = 0; i < num_features; i++) 450 { 451 const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag, 452 feature_mappings, 453 ARRAY_LENGTH (feature_mappings), 454 sizeof (feature_mappings[0]), 455 _hb_feature_mapping_cmp); 456 if (!mapping) 457 continue; 458 459 active_feature_t feature; 460 feature.rec.feature = mapping->aatFeatureType; 461 feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable; 462 feature.order = i; 463 464 feature_event_t *event; 465 466 event = feature_events.push (); 467 if (unlikely (!event)) 468 goto fail_features; 469 event->index = features[i].start; 470 event->start = true; 471 event->feature = feature; 472 473 event = feature_events.push (); 474 if (unlikely (!event)) 475 goto fail_features; 476 event->index = features[i].end; 477 event->start = false; 478 event->feature = feature; 479 } 480 feature_events.sort (); 481 /* Add a strategic final event. */ 482 { 483 active_feature_t feature; 484 feature.rec.feature = HB_TAG_NONE; 485 feature.rec.setting = 0; 486 feature.order = num_features + 1; 487 488 feature_event_t *event = feature_events.push (); 489 if (unlikely (!event)) 490 goto fail_features; 491 event->index = 0; /* This value does magic. */ 492 event->start = false; 493 event->feature = feature; 494 } 495 496 /* Scan events and save features for each range. */ 497 hb_auto_array_t<active_feature_t> active_features; 498 unsigned int last_index = 0; 499 for (unsigned int i = 0; i < feature_events.len; i++) 500 { 501 feature_event_t *event = &feature_events[i]; 502 503 if (event->index != last_index) 504 { 505 /* Save a snapshot of active features and the range. */ 506 range_record_t *range = range_records.push (); 507 if (unlikely (!range)) 508 goto fail_features; 509 510 unsigned int offset = feature_records.len; 511 512 if (active_features.len) 513 { 514 CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 515 516 /* TODO sort and resolve conflicting features? */ 517 /* active_features.sort (); */ 518 for (unsigned int j = 0; j < active_features.len; j++) 519 { 520 CFStringRef keys[2] = { 521 kCTFontFeatureTypeIdentifierKey, 522 kCTFontFeatureSelectorIdentifierKey 523 }; 524 CFNumberRef values[2] = { 525 CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature), 526 CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting) 527 }; 528 CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault, 529 (const void **) keys, 530 (const void **) values, 531 2, 532 &kCFTypeDictionaryKeyCallBacks, 533 &kCFTypeDictionaryValueCallBacks); 534 CFRelease (values[0]); 535 CFRelease (values[1]); 536 537 CFArrayAppendValue (features_array, dict); 538 CFRelease (dict); 539 540 } 541 542 CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault, 543 (const void **) &kCTFontFeatureSettingsAttribute, 544 (const void **) &features_array, 545 1, 546 &kCFTypeDictionaryKeyCallBacks, 547 &kCFTypeDictionaryValueCallBacks); 548 CFRelease (features_array); 549 550 CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes); 551 CFRelease (attributes); 552 553 range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc); 554 555 CFRelease (font_desc); 556 } 557 else 558 { 559 range->font = NULL; 560 } 561 562 range->index_first = last_index; 563 range->index_last = event->index - 1; 564 565 last_index = event->index; 566 } 567 568 if (event->start) { 569 active_feature_t *feature = active_features.push (); 570 if (unlikely (!feature)) 571 goto fail_features; 572 *feature = event->feature; 573 } else { 574 active_feature_t *feature = active_features.find (&event->feature); 575 if (feature) 576 active_features.remove (feature - active_features.array); 577 } 578 } 579 580 if (!range_records.len) /* No active feature found. */ 581 goto fail_features; 582 } 583 else 584 { 585 fail_features: 586 num_features = 0; 587 } 588 589 #define FAIL(...) \ 590 HB_STMT_START { \ 591 DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \ 592 return false; \ 593 } HB_STMT_END; 594 595 unsigned int scratch_size; 596 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); 597 598 #define ALLOCATE_ARRAY(Type, name, len) \ 599 Type *name = (Type *) scratch; \ 600 { \ 601 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ 602 assert (_consumed <= scratch_size); \ 603 scratch += _consumed; \ 604 scratch_size -= _consumed; \ 605 } 606 607 #define utf16_index() var1.u32 608 609 ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2); 610 611 unsigned int chars_len = 0; 612 for (unsigned int i = 0; i < buffer->len; i++) { 613 hb_codepoint_t c = buffer->info[i].codepoint; 614 buffer->info[i].utf16_index() = chars_len; 615 if (likely (c < 0x10000)) 616 pchars[chars_len++] = c; 617 else if (unlikely (c >= 0x110000)) 618 pchars[chars_len++] = 0xFFFD; 619 else { 620 pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); 621 pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); 622 } 623 } 624 625 #undef utf16_index 626 627 CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL, 628 pchars, chars_len, 629 kCFAllocatorNull); 630 631 CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NULL, chars_len); 632 CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref); 633 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), 634 kCTFontAttributeName, font_data->ct_font); 635 636 if (num_features) 637 { 638 ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len); 639 640 /* Need log_clusters to assign features. */ 641 chars_len = 0; 642 for (unsigned int i = 0; i < buffer->len; i++) 643 { 644 hb_codepoint_t c = buffer->info[i].codepoint; 645 unsigned int cluster = buffer->info[i].cluster; 646 log_clusters[chars_len++] = cluster; 647 if (c >= 0x10000 && c < 0x110000) 648 log_clusters[chars_len++] = cluster; /* Surrogates. */ 649 } 650 651 unsigned int start = 0; 652 range_record_t *last_range = &range_records[0]; 653 for (unsigned int k = 0; k < chars_len; k++) 654 { 655 range_record_t *range = last_range; 656 while (log_clusters[k] < range->index_first) 657 range--; 658 while (log_clusters[k] > range->index_last) 659 range++; 660 if (range != last_range) 661 { 662 if (last_range->font) 663 CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start), 664 kCTFontAttributeName, last_range->font); 665 666 start = k; 667 } 668 669 last_range = range; 670 } 671 if (start != chars_len && last_range->font) 672 CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start - 1), 673 kCTFontAttributeName, last_range->font); 674 675 for (unsigned int i = 0; i < range_records.len; i++) 676 if (range_records[i].font) 677 CFRelease (range_records[i].font); 678 } 679 680 CTLineRef line = CTLineCreateWithAttributedString (attr_string); 681 CFRelease (attr_string); 682 683 CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); 684 unsigned int num_runs = CFArrayGetCount (glyph_runs); 685 686 buffer->len = 0; 687 688 const CFRange range_all = CFRangeMake (0, 0); 689 690 for (unsigned int i = 0; i < num_runs; i++) 691 { 692 CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i); 693 694 /* CoreText does automatic font fallback (AKA "cascading") for characters 695 * not supported by the requested font, and provides no way to turn it off, 696 * so we detect if the returned run uses a font other than the requested 697 * one and fill in the buffer with .notdef glyphs instead of random glyph 698 * indices from a different font. 699 */ 700 CFDictionaryRef attributes = CTRunGetAttributes (run); 701 CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName)); 702 CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0); 703 if (!CFEqual (run_cg_font, face_data->cg_font)) 704 { 705 CFRelease (run_cg_font); 706 707 CFRange range = CTRunGetStringRange (run); 708 buffer->ensure (buffer->len + range.length); 709 if (buffer->in_error) 710 FAIL ("Buffer resize failed"); 711 hb_glyph_info_t *info = buffer->info + buffer->len; 712 713 CGGlyph notdef = 0; 714 double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, ¬def, NULL, 1); 715 716 for (CFIndex j = range.location; j < range.location + range.length; j++) 717 { 718 UniChar ch = CFStringGetCharacterAtIndex (string_ref, j); 719 if (hb_in_range<UniChar> (ch, 0xDC00, 0xDFFF) && range.location < j) 720 { 721 ch = CFStringGetCharacterAtIndex (string_ref, j - 1); 722 if (hb_in_range<UniChar> (ch, 0xD800, 0xDBFF)) 723 /* This is the second of a surrogate pair. Don't need .notdef 724 * for this one. */ 725 continue; 726 } 727 728 info->codepoint = notdef; 729 /* TODO We have to fixup clusters later. See vis_clusters in 730 * hb-uniscribe.cc for example. */ 731 info->cluster = j; 732 733 info->mask = advance; 734 info->var1.u32 = 0; 735 info->var2.u32 = 0; 736 737 info++; 738 buffer->len++; 739 } 740 continue; 741 } 742 CFRelease (run_cg_font); 743 744 unsigned int num_glyphs = CTRunGetGlyphCount (run); 745 if (num_glyphs == 0) 746 continue; 747 748 buffer->ensure (buffer->len + num_glyphs); 749 750 scratch = buffer->get_scratch_buffer (&scratch_size); 751 752 /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always 753 * succeed, and so copying data to our own buffer will be rare. */ 754 755 const CGGlyph* glyphs = CTRunGetGlyphsPtr (run); 756 if (!glyphs) { 757 ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs); 758 CTRunGetGlyphs (run, range_all, glyph_buf); 759 glyphs = glyph_buf; 760 } 761 762 const CGPoint* positions = CTRunGetPositionsPtr (run); 763 if (!positions) { 764 ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs); 765 CTRunGetPositions (run, range_all, position_buf); 766 positions = position_buf; 767 } 768 769 const CFIndex* string_indices = CTRunGetStringIndicesPtr (run); 770 if (!string_indices) { 771 ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs); 772 CTRunGetStringIndices (run, range_all, index_buf); 773 string_indices = index_buf; 774 } 775 776 #undef ALLOCATE_ARRAY 777 778 double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL); 779 780 for (unsigned int j = 0; j < num_glyphs; j++) { 781 double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x; 782 783 hb_glyph_info_t *info = &buffer->info[buffer->len]; 784 785 info->codepoint = glyphs[j]; 786 info->cluster = string_indices[j]; 787 788 /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */ 789 info->mask = advance; 790 info->var1.u32 = 0; 791 info->var2.u32 = positions[j].y; 792 793 buffer->len++; 794 } 795 } 796 797 buffer->clear_positions (); 798 799 unsigned int count = buffer->len; 800 for (unsigned int i = 0; i < count; ++i) { 801 hb_glyph_info_t *info = &buffer->info[i]; 802 hb_glyph_position_t *pos = &buffer->pos[i]; 803 804 /* TODO vertical */ 805 pos->x_advance = info->mask; 806 pos->x_offset = info->var1.u32; 807 pos->y_offset = info->var2.u32; 808 } 809 810 /* Fix up clusters so that we never return out-of-order indices; 811 * if core text has reordered glyphs, we'll merge them to the 812 * beginning of the reordered cluster. 813 * 814 * This does *not* mean we'll form the same clusters as Uniscribe 815 * or the native OT backend, only that the cluster indices will be 816 * monotonic in the output buffer. */ 817 if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { 818 unsigned int prev_cluster = 0; 819 for (unsigned int i = 0; i < count; i++) { 820 unsigned int curr_cluster = buffer->info[i].cluster; 821 if (curr_cluster < prev_cluster) { 822 for (unsigned int j = i; j > 0; j--) { 823 if (buffer->info[j - 1].cluster > curr_cluster) 824 buffer->info[j - 1].cluster = curr_cluster; 825 else 826 break; 827 } 828 } 829 prev_cluster = curr_cluster; 830 } 831 } else { 832 unsigned int prev_cluster = (unsigned int)-1; 833 for (unsigned int i = 0; i < count; i++) { 834 unsigned int curr_cluster = buffer->info[i].cluster; 835 if (curr_cluster > prev_cluster) { 836 for (unsigned int j = i; j > 0; j--) { 837 if (buffer->info[j - 1].cluster < curr_cluster) 838 buffer->info[j - 1].cluster = curr_cluster; 839 else 840 break; 841 } 842 } 843 prev_cluster = curr_cluster; 844 } 845 } 846 847 CFRelease (string_ref); 848 CFRelease (line); 849 850 return true; 851 } 852 853 854 /* 855 * AAT shaper 856 */ 857 858 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face) 859 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font) 860 861 862 /* 863 * shaper face data 864 */ 865 866 struct hb_coretext_aat_shaper_face_data_t {}; 867 868 hb_coretext_aat_shaper_face_data_t * 869 _hb_coretext_aat_shaper_face_data_create (hb_face_t *face) 870 { 871 hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT); 872 /* Umm, we just reference the table to check whether it exists. 873 * Maybe add better API for this? */ 874 if (!hb_blob_get_length (mort_blob)) 875 { 876 hb_blob_destroy (mort_blob); 877 mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX); 878 if (!hb_blob_get_length (mort_blob)) 879 { 880 hb_blob_destroy (mort_blob); 881 return NULL; 882 } 883 } 884 hb_blob_destroy (mort_blob); 885 886 return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL; 887 } 888 889 void 890 _hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED) 891 { 892 } 893 894 895 /* 896 * shaper font data 897 */ 898 899 struct hb_coretext_aat_shaper_font_data_t {}; 900 901 hb_coretext_aat_shaper_font_data_t * 902 _hb_coretext_aat_shaper_font_data_create (hb_font_t *font) 903 { 904 return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL; 905 } 906 907 void 908 _hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED) 909 { 910 } 911 912 913 /* 914 * shaper shape_plan data 915 */ 916 917 struct hb_coretext_aat_shaper_shape_plan_data_t {}; 918 919 hb_coretext_aat_shaper_shape_plan_data_t * 920 _hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 921 const hb_feature_t *user_features HB_UNUSED, 922 unsigned int num_user_features HB_UNUSED) 923 { 924 return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 925 } 926 927 void 928 _hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED) 929 { 930 } 931 932 933 /* 934 * shaper 935 */ 936 937 hb_bool_t 938 _hb_coretext_aat_shape (hb_shape_plan_t *shape_plan, 939 hb_font_t *font, 940 hb_buffer_t *buffer, 941 const hb_feature_t *features, 942 unsigned int num_features) 943 { 944 return _hb_coretext_shape (shape_plan, font, buffer, features, num_features); 945 } 946