1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 // This file is available under and governed by the GNU General Public 26 // License version 2 only, as published by the Free Software Foundation. 27 // However, the following notice accompanied the original version of this 28 // file: 29 // 30 /* 31 * Copyright © 2012,2013 Mozilla Foundation. 32 * Copyright © 2012,2013 Google, Inc. 33 * 34 * This is part of HarfBuzz, a text shaping library. 35 * 36 * Permission is hereby granted, without written agreement and without 37 * license or royalty fees, to use, copy, modify, and distribute this 38 * software and its documentation for any purpose, provided that the 39 * above copyright notice and the following two paragraphs appear in 40 * all copies of this software. 41 * 42 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 43 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 44 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 45 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 46 * DAMAGE. 47 * 48 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 49 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 50 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 51 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 52 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 53 * 54 * Mozilla Author(s): Jonathan Kew 55 * Google Author(s): Behdad Esfahbod 56 */ 57 58 #define HB_SHAPER coretext 59 #define hb_coretext_shaper_face_data_t CGFont 60 #include "hb-shaper-impl-private.hh" 61 62 #include "hb-coretext.h" 63 64 65 #ifndef HB_DEBUG_CORETEXT 66 #define HB_DEBUG_CORETEXT (HB_DEBUG+0) 67 #endif 68 69 70 static void 71 release_table_data (void *user_data) 72 { 73 CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data); 74 CFRelease(cf_data); 75 } 76 77 static hb_blob_t * 78 reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) 79 { 80 CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data); 81 CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag); 82 if (unlikely (!cf_data)) 83 return NULL; 84 85 const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data)); 86 const size_t length = CFDataGetLength (cf_data); 87 if (!data || !length) 88 return NULL; 89 90 return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY, 91 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)), 92 release_table_data); 93 } 94 95 hb_face_t * 96 hb_coretext_face_create (CGFontRef cg_font) 97 { 98 return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease); 99 } 100 101 102 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) 103 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) 104 105 106 /* 107 * shaper face data 108 */ 109 110 static void 111 release_data (void *info, const void *data, size_t size) 112 { 113 assert (hb_blob_get_length ((hb_blob_t *) info) == size && 114 hb_blob_get_data ((hb_blob_t *) info, NULL) == data); 115 116 hb_blob_destroy ((hb_blob_t *) info); 117 } 118 119 hb_coretext_shaper_face_data_t * 120 _hb_coretext_shaper_face_data_create (hb_face_t *face) 121 { 122 hb_coretext_shaper_face_data_t *data = NULL; 123 124 if (face->destroy == (hb_destroy_func_t) CGFontRelease) 125 { 126 data = CGFontRetain ((CGFontRef) face->user_data); 127 } 128 else 129 { 130 hb_blob_t *blob = hb_face_reference_blob (face); 131 unsigned int blob_length; 132 const char *blob_data = hb_blob_get_data (blob, &blob_length); 133 if (unlikely (!blob_length)) 134 DEBUG_MSG (CORETEXT, face, "Face has empty blob"); 135 136 CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data); 137 if (likely (provider)) 138 { 139 data = CGFontCreateWithDataProvider (provider); 140 CGDataProviderRelease (provider); 141 } 142 } 143 144 if (unlikely (!data)) { 145 DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); 146 } 147 148 return data; 149 } 150 151 void 152 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) 153 { 154 CFRelease (data); 155 } 156 157 /* 158 * Since: 0.9.10 159 */ 160 CGFontRef 161 hb_coretext_face_get_cg_font (hb_face_t *face) 162 { 163 if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; 164 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 165 return face_data; 166 } 167 168 169 /* 170 * shaper font data 171 */ 172 173 struct hb_coretext_shaper_font_data_t { 174 CTFontRef ct_font; 175 CGFloat x_mult, y_mult; /* From CT space to HB space. */ 176 }; 177 178 hb_coretext_shaper_font_data_t * 179 _hb_coretext_shaper_font_data_create (hb_font_t *font) 180 { 181 if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL; 182 183 hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t)); 184 if (unlikely (!data)) 185 return NULL; 186 187 hb_face_t *face = font->face; 188 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 189 190 /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */ 191 /* TODO: use upem instead of 36? */ 192 CGFloat font_size = 36.; /* Default... */ 193 /* No idea if the following is even a good idea. */ 194 if (font->y_ppem) 195 font_size = font->y_ppem; 196 197 if (font_size < 0) 198 font_size = -font_size; 199 data->x_mult = (CGFloat) font->x_scale / font_size; 200 data->y_mult = (CGFloat) font->y_scale / font_size; 201 data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL); 202 if (unlikely (!data->ct_font)) { 203 DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); 204 free (data); 205 return NULL; 206 } 207 208 return data; 209 } 210 211 void 212 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data) 213 { 214 CFRelease (data->ct_font); 215 free (data); 216 } 217 218 219 /* 220 * shaper shape_plan data 221 */ 222 223 struct hb_coretext_shaper_shape_plan_data_t {}; 224 225 hb_coretext_shaper_shape_plan_data_t * 226 _hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 227 const hb_feature_t *user_features HB_UNUSED, 228 unsigned int num_user_features HB_UNUSED) 229 { 230 return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 231 } 232 233 void 234 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED) 235 { 236 } 237 238 CTFontRef 239 hb_coretext_font_get_ct_font (hb_font_t *font) 240 { 241 if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL; 242 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 243 return font_data->ct_font; 244 } 245 246 247 /* 248 * shaper 249 */ 250 251 struct feature_record_t { 252 unsigned int feature; 253 unsigned int setting; 254 }; 255 256 struct active_feature_t { 257 feature_record_t rec; 258 unsigned int order; 259 260 static int cmp (const active_feature_t *a, const active_feature_t *b) { 261 return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 : 262 a->order < b->order ? -1 : a->order > b->order ? 1 : 263 a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 : 264 0; 265 } 266 bool operator== (const active_feature_t *f) { 267 return cmp (this, f) == 0; 268 } 269 }; 270 271 struct feature_event_t { 272 unsigned int index; 273 bool start; 274 active_feature_t feature; 275 276 static int cmp (const feature_event_t *a, const feature_event_t *b) { 277 return a->index < b->index ? -1 : a->index > b->index ? 1 : 278 a->start < b->start ? -1 : a->start > b->start ? 1 : 279 active_feature_t::cmp (&a->feature, &b->feature); 280 } 281 }; 282 283 struct range_record_t { 284 CTFontRef font; 285 unsigned int index_first; /* == start */ 286 unsigned int index_last; /* == end - 1 */ 287 }; 288 289 290 /* The following enum members are added in OS X 10.8. */ 291 #define kAltHalfWidthTextSelector 6 292 #define kAltProportionalTextSelector 5 293 #define kAlternateHorizKanaOffSelector 1 294 #define kAlternateHorizKanaOnSelector 0 295 #define kAlternateKanaType 34 296 #define kAlternateVertKanaOffSelector 3 297 #define kAlternateVertKanaOnSelector 2 298 #define kCaseSensitiveLayoutOffSelector 1 299 #define kCaseSensitiveLayoutOnSelector 0 300 #define kCaseSensitiveLayoutType 33 301 #define kCaseSensitiveSpacingOffSelector 3 302 #define kCaseSensitiveSpacingOnSelector 2 303 #define kContextualAlternatesOffSelector 1 304 #define kContextualAlternatesOnSelector 0 305 #define kContextualAlternatesType 36 306 #define kContextualLigaturesOffSelector 19 307 #define kContextualLigaturesOnSelector 18 308 #define kContextualSwashAlternatesOffSelector 5 309 #define kContextualSwashAlternatesOnSelector 4 310 #define kDefaultLowerCaseSelector 0 311 #define kDefaultUpperCaseSelector 0 312 #define kHistoricalLigaturesOffSelector 21 313 #define kHistoricalLigaturesOnSelector 20 314 #define kHojoCharactersSelector 12 315 #define kJIS2004CharactersSelector 11 316 #define kLowerCasePetiteCapsSelector 2 317 #define kLowerCaseSmallCapsSelector 1 318 #define kLowerCaseType 37 319 #define kMathematicalGreekOffSelector 11 320 #define kMathematicalGreekOnSelector 10 321 #define kNLCCharactersSelector 13 322 #define kQuarterWidthTextSelector 4 323 #define kScientificInferiorsSelector 4 324 #define kStylisticAltEightOffSelector 17 325 #define kStylisticAltEightOnSelector 16 326 #define kStylisticAltEighteenOffSelector 37 327 #define kStylisticAltEighteenOnSelector 36 328 #define kStylisticAltElevenOffSelector 23 329 #define kStylisticAltElevenOnSelector 22 330 #define kStylisticAltFifteenOffSelector 31 331 #define kStylisticAltFifteenOnSelector 30 332 #define kStylisticAltFiveOffSelector 11 333 #define kStylisticAltFiveOnSelector 10 334 #define kStylisticAltFourOffSelector 9 335 #define kStylisticAltFourOnSelector 8 336 #define kStylisticAltFourteenOffSelector 29 337 #define kStylisticAltFourteenOnSelector 28 338 #define kStylisticAltNineOffSelector 19 339 #define kStylisticAltNineOnSelector 18 340 #define kStylisticAltNineteenOffSelector 39 341 #define kStylisticAltNineteenOnSelector 38 342 #define kStylisticAltOneOffSelector 3 343 #define kStylisticAltOneOnSelector 2 344 #define kStylisticAltSevenOffSelector 15 345 #define kStylisticAltSevenOnSelector 14 346 #define kStylisticAltSeventeenOffSelector 35 347 #define kStylisticAltSeventeenOnSelector 34 348 #define kStylisticAltSixOffSelector 13 349 #define kStylisticAltSixOnSelector 12 350 #define kStylisticAltSixteenOffSelector 33 351 #define kStylisticAltSixteenOnSelector 32 352 #define kStylisticAltTenOffSelector 21 353 #define kStylisticAltTenOnSelector 20 354 #define kStylisticAltThirteenOffSelector 27 355 #define kStylisticAltThirteenOnSelector 26 356 #define kStylisticAltThreeOffSelector 7 357 #define kStylisticAltThreeOnSelector 6 358 #define kStylisticAltTwelveOffSelector 25 359 #define kStylisticAltTwelveOnSelector 24 360 #define kStylisticAltTwentyOffSelector 41 361 #define kStylisticAltTwentyOnSelector 40 362 #define kStylisticAltTwoOffSelector 5 363 #define kStylisticAltTwoOnSelector 4 364 #define kStylisticAlternativesType 35 365 #define kSwashAlternatesOffSelector 3 366 #define kSwashAlternatesOnSelector 2 367 #define kThirdWidthTextSelector 3 368 #define kTraditionalNamesCharactersSelector 14 369 #define kUpperCasePetiteCapsSelector 2 370 #define kUpperCaseSmallCapsSelector 1 371 #define kUpperCaseType 38 372 373 /* Table data courtesy of Apple. */ 374 static const struct feature_mapping_t { 375 FourCharCode otFeatureTag; 376 uint16_t aatFeatureType; 377 uint16_t selectorToEnable; 378 uint16_t selectorToDisable; 379 } feature_mappings[] = { 380 { 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector, kDefaultUpperCaseSelector }, 381 { 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector, kDefaultUpperCaseSelector }, 382 { 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector }, 383 { 'case', kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOffSelector }, 384 { 'clig', kLigaturesType, kContextualLigaturesOnSelector, kContextualLigaturesOffSelector }, 385 { 'cpsp', kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOffSelector }, 386 { 'cswh', kContextualAlternatesType, kContextualSwashAlternatesOnSelector, kContextualSwashAlternatesOffSelector }, 387 { 'dlig', kLigaturesType, kRareLigaturesOnSelector, kRareLigaturesOffSelector }, 388 { 'expt', kCharacterShapeType, kExpertCharactersSelector, 16 }, 389 { 'frac', kFractionsType, kDiagonalFractionsSelector, kNoFractionsSelector }, 390 { 'fwid', kTextSpacingType, kMonospacedTextSelector, 7 }, 391 { 'halt', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, 392 { 'hist', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, 393 { 'hkna', kAlternateKanaType, kAlternateHorizKanaOnSelector, kAlternateHorizKanaOffSelector, }, 394 { 'hlig', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, 395 { 'hngl', kTransliterationType, kHanjaToHangulSelector, kNoTransliterationSelector }, 396 { 'hojo', kCharacterShapeType, kHojoCharactersSelector, 16 }, 397 { 'hwid', kTextSpacingType, kHalfWidthTextSelector, 7 }, 398 { 'ital', kItalicCJKRomanType, kCJKItalicRomanOnSelector, kCJKItalicRomanOffSelector }, 399 { 'jp04', kCharacterShapeType, kJIS2004CharactersSelector, 16 }, 400 { 'jp78', kCharacterShapeType, kJIS1978CharactersSelector, 16 }, 401 { 'jp83', kCharacterShapeType, kJIS1983CharactersSelector, 16 }, 402 { 'jp90', kCharacterShapeType, kJIS1990CharactersSelector, 16 }, 403 { 'liga', kLigaturesType, kCommonLigaturesOnSelector, kCommonLigaturesOffSelector }, 404 { 'lnum', kNumberCaseType, kUpperCaseNumbersSelector, 2 }, 405 { 'mgrk', kMathematicalExtrasType, kMathematicalGreekOnSelector, kMathematicalGreekOffSelector }, 406 { 'nlck', kCharacterShapeType, kNLCCharactersSelector, 16 }, 407 { 'onum', kNumberCaseType, kLowerCaseNumbersSelector, 2 }, 408 { 'ordn', kVerticalPositionType, kOrdinalsSelector, kNormalPositionSelector }, 409 { 'palt', kTextSpacingType, kAltProportionalTextSelector, 7 }, 410 { 'pcap', kLowerCaseType, kLowerCasePetiteCapsSelector, kDefaultLowerCaseSelector }, 411 { 'pkna', kTextSpacingType, kProportionalTextSelector, 7 }, 412 { 'pnum', kNumberSpacingType, kProportionalNumbersSelector, 4 }, 413 { 'pwid', kTextSpacingType, kProportionalTextSelector, 7 }, 414 { 'qwid', kTextSpacingType, kQuarterWidthTextSelector, 7 }, 415 { 'ruby', kRubyKanaType, kRubyKanaOnSelector, kRubyKanaOffSelector }, 416 { 'sinf', kVerticalPositionType, kScientificInferiorsSelector, kNormalPositionSelector }, 417 { 'smcp', kLowerCaseType, kLowerCaseSmallCapsSelector, kDefaultLowerCaseSelector }, 418 { 'smpl', kCharacterShapeType, kSimplifiedCharactersSelector, 16 }, 419 { 'ss01', kStylisticAlternativesType, kStylisticAltOneOnSelector, kStylisticAltOneOffSelector }, 420 { 'ss02', kStylisticAlternativesType, kStylisticAltTwoOnSelector, kStylisticAltTwoOffSelector }, 421 { 'ss03', kStylisticAlternativesType, kStylisticAltThreeOnSelector, kStylisticAltThreeOffSelector }, 422 { 'ss04', kStylisticAlternativesType, kStylisticAltFourOnSelector, kStylisticAltFourOffSelector }, 423 { 'ss05', kStylisticAlternativesType, kStylisticAltFiveOnSelector, kStylisticAltFiveOffSelector }, 424 { 'ss06', kStylisticAlternativesType, kStylisticAltSixOnSelector, kStylisticAltSixOffSelector }, 425 { 'ss07', kStylisticAlternativesType, kStylisticAltSevenOnSelector, kStylisticAltSevenOffSelector }, 426 { 'ss08', kStylisticAlternativesType, kStylisticAltEightOnSelector, kStylisticAltEightOffSelector }, 427 { 'ss09', kStylisticAlternativesType, kStylisticAltNineOnSelector, kStylisticAltNineOffSelector }, 428 { 'ss10', kStylisticAlternativesType, kStylisticAltTenOnSelector, kStylisticAltTenOffSelector }, 429 { 'ss11', kStylisticAlternativesType, kStylisticAltElevenOnSelector, kStylisticAltElevenOffSelector }, 430 { 'ss12', kStylisticAlternativesType, kStylisticAltTwelveOnSelector, kStylisticAltTwelveOffSelector }, 431 { 'ss13', kStylisticAlternativesType, kStylisticAltThirteenOnSelector, kStylisticAltThirteenOffSelector }, 432 { 'ss14', kStylisticAlternativesType, kStylisticAltFourteenOnSelector, kStylisticAltFourteenOffSelector }, 433 { 'ss15', kStylisticAlternativesType, kStylisticAltFifteenOnSelector, kStylisticAltFifteenOffSelector }, 434 { 'ss16', kStylisticAlternativesType, kStylisticAltSixteenOnSelector, kStylisticAltSixteenOffSelector }, 435 { 'ss17', kStylisticAlternativesType, kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOffSelector }, 436 { 'ss18', kStylisticAlternativesType, kStylisticAltEighteenOnSelector, kStylisticAltEighteenOffSelector }, 437 { 'ss19', kStylisticAlternativesType, kStylisticAltNineteenOnSelector, kStylisticAltNineteenOffSelector }, 438 { 'ss20', kStylisticAlternativesType, kStylisticAltTwentyOnSelector, kStylisticAltTwentyOffSelector }, 439 { 'subs', kVerticalPositionType, kInferiorsSelector, kNormalPositionSelector }, 440 { 'sups', kVerticalPositionType, kSuperiorsSelector, kNormalPositionSelector }, 441 { 'swsh', kContextualAlternatesType, kSwashAlternatesOnSelector, kSwashAlternatesOffSelector }, 442 { 'titl', kStyleOptionsType, kTitlingCapsSelector, kNoStyleOptionsSelector }, 443 { 'tnam', kCharacterShapeType, kTraditionalNamesCharactersSelector, 16 }, 444 { 'tnum', kNumberSpacingType, kMonospacedNumbersSelector, 4 }, 445 { 'trad', kCharacterShapeType, kTraditionalCharactersSelector, 16 }, 446 { 'twid', kTextSpacingType, kThirdWidthTextSelector, 7 }, 447 { 'unic', kLetterCaseType, 14, 15 }, 448 { 'valt', kTextSpacingType, kAltProportionalTextSelector, 7 }, 449 { 'vert', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, 450 { 'vhal', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, 451 { 'vkna', kAlternateKanaType, kAlternateVertKanaOnSelector, kAlternateVertKanaOffSelector }, 452 { 'vpal', kTextSpacingType, kAltProportionalTextSelector, 7 }, 453 { 'vrt2', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, 454 { 'zero', kTypographicExtrasType, kSlashedZeroOnSelector, kSlashedZeroOffSelector }, 455 }; 456 457 static int 458 _hb_feature_mapping_cmp (const void *key_, const void *entry_) 459 { 460 unsigned int key = * (unsigned int *) key_; 461 const feature_mapping_t * entry = (const feature_mapping_t *) entry_; 462 return key < entry->otFeatureTag ? -1 : 463 key > entry->otFeatureTag ? 1 : 464 0; 465 } 466 467 hb_bool_t 468 _hb_coretext_shape (hb_shape_plan_t *shape_plan, 469 hb_font_t *font, 470 hb_buffer_t *buffer, 471 const hb_feature_t *features, 472 unsigned int num_features) 473 { 474 hb_face_t *face = font->face; 475 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 476 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 477 478 /* Attach marks to their bases, to match the 'ot' shaper. 479 * Adapted from hb-ot-shape:hb_form_clusters(). 480 * Note that this only makes us be closer to the 'ot' shaper, 481 * but by no means the same. For example, if there's 482 * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will 483 * continue pointing to B2 even though B2 was merged into B1's 484 * cluster... */ 485 { 486 hb_unicode_funcs_t *unicode = buffer->unicode; 487 unsigned int count = buffer->len; 488 hb_glyph_info_t *info = buffer->info; 489 for (unsigned int i = 1; i < count; i++) 490 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i].codepoint))) 491 buffer->merge_clusters (i - 1, i + 1); 492 } 493 494 hb_auto_array_t<feature_record_t> feature_records; 495 hb_auto_array_t<range_record_t> range_records; 496 497 /* 498 * Set up features. 499 * (copied + modified from code from hb-uniscribe.cc) 500 */ 501 if (num_features) 502 { 503 /* Sort features by start/end events. */ 504 hb_auto_array_t<feature_event_t> feature_events; 505 for (unsigned int i = 0; i < num_features; i++) 506 { 507 const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag, 508 feature_mappings, 509 ARRAY_LENGTH (feature_mappings), 510 sizeof (feature_mappings[0]), 511 _hb_feature_mapping_cmp); 512 if (!mapping) 513 continue; 514 515 active_feature_t feature; 516 feature.rec.feature = mapping->aatFeatureType; 517 feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable; 518 feature.order = i; 519 520 feature_event_t *event; 521 522 event = feature_events.push (); 523 if (unlikely (!event)) 524 goto fail_features; 525 event->index = features[i].start; 526 event->start = true; 527 event->feature = feature; 528 529 event = feature_events.push (); 530 if (unlikely (!event)) 531 goto fail_features; 532 event->index = features[i].end; 533 event->start = false; 534 event->feature = feature; 535 } 536 feature_events.qsort (); 537 /* Add a strategic final event. */ 538 { 539 active_feature_t feature; 540 feature.rec.feature = HB_TAG_NONE; 541 feature.rec.setting = 0; 542 feature.order = num_features + 1; 543 544 feature_event_t *event = feature_events.push (); 545 if (unlikely (!event)) 546 goto fail_features; 547 event->index = 0; /* This value does magic. */ 548 event->start = false; 549 event->feature = feature; 550 } 551 552 /* Scan events and save features for each range. */ 553 hb_auto_array_t<active_feature_t> active_features; 554 unsigned int last_index = 0; 555 for (unsigned int i = 0; i < feature_events.len; i++) 556 { 557 feature_event_t *event = &feature_events[i]; 558 559 if (event->index != last_index) 560 { 561 /* Save a snapshot of active features and the range. */ 562 range_record_t *range = range_records.push (); 563 if (unlikely (!range)) 564 goto fail_features; 565 566 if (active_features.len) 567 { 568 CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 569 570 /* TODO sort and resolve conflicting features? */ 571 /* active_features.qsort (); */ 572 for (unsigned int j = 0; j < active_features.len; j++) 573 { 574 CFStringRef keys[2] = { 575 kCTFontFeatureTypeIdentifierKey, 576 kCTFontFeatureSelectorIdentifierKey 577 }; 578 CFNumberRef values[2] = { 579 CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature), 580 CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting) 581 }; 582 CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault, 583 (const void **) keys, 584 (const void **) values, 585 2, 586 &kCFTypeDictionaryKeyCallBacks, 587 &kCFTypeDictionaryValueCallBacks); 588 CFRelease (values[0]); 589 CFRelease (values[1]); 590 591 CFArrayAppendValue (features_array, dict); 592 CFRelease (dict); 593 594 } 595 596 CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault, 597 (const void **) &kCTFontFeatureSettingsAttribute, 598 (const void **) &features_array, 599 1, 600 &kCFTypeDictionaryKeyCallBacks, 601 &kCFTypeDictionaryValueCallBacks); 602 CFRelease (features_array); 603 604 CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes); 605 CFRelease (attributes); 606 607 range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc); 608 CFRelease (font_desc); 609 } 610 else 611 { 612 range->font = NULL; 613 } 614 615 range->index_first = last_index; 616 range->index_last = event->index - 1; 617 618 last_index = event->index; 619 } 620 621 if (event->start) { 622 active_feature_t *feature = active_features.push (); 623 if (unlikely (!feature)) 624 goto fail_features; 625 *feature = event->feature; 626 } else { 627 active_feature_t *feature = active_features.find (&event->feature); 628 if (feature) 629 active_features.remove (feature - active_features.array); 630 } 631 } 632 633 if (!range_records.len) /* No active feature found. */ 634 goto fail_features; 635 } 636 else 637 { 638 fail_features: 639 num_features = 0; 640 } 641 642 unsigned int scratch_size; 643 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); 644 645 #define ALLOCATE_ARRAY(Type, name, len, on_no_room) \ 646 Type *name = (Type *) scratch; \ 647 { \ 648 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ 649 if (unlikely (_consumed > scratch_size)) \ 650 { \ 651 on_no_room; \ 652 assert (0); \ 653 } \ 654 scratch += _consumed; \ 655 scratch_size -= _consumed; \ 656 } 657 658 ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/); 659 unsigned int chars_len = 0; 660 for (unsigned int i = 0; i < buffer->len; i++) { 661 hb_codepoint_t c = buffer->info[i].codepoint; 662 if (likely (c <= 0xFFFFu)) 663 pchars[chars_len++] = c; 664 else if (unlikely (c > 0x10FFFFu)) 665 pchars[chars_len++] = 0xFFFDu; 666 else { 667 pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10); 668 pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1)); 669 } 670 } 671 672 ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/); 673 chars_len = 0; 674 for (unsigned int i = 0; i < buffer->len; i++) 675 { 676 hb_codepoint_t c = buffer->info[i].codepoint; 677 unsigned int cluster = buffer->info[i].cluster; 678 log_clusters[chars_len++] = cluster; 679 if (hb_in_range (c, 0x10000u, 0x10FFFFu)) 680 log_clusters[chars_len++] = cluster; /* Surrogates. */ 681 } 682 683 #define FAIL(...) \ 684 HB_STMT_START { \ 685 DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \ 686 ret = false; \ 687 goto fail; \ 688 } HB_STMT_END; 689 690 bool ret = true; 691 CFStringRef string_ref = NULL; 692 CTLineRef line = NULL; 693 694 if (0) 695 { 696 resize_and_retry: 697 DEBUG_MSG (CORETEXT, buffer, "Buffer resize"); 698 /* string_ref uses the scratch-buffer for backing store, and line references 699 * string_ref (via attr_string). We must release those before resizing buffer. */ 700 assert (string_ref); 701 assert (line); 702 CFRelease (string_ref); 703 CFRelease (line); 704 string_ref = NULL; 705 line = NULL; 706 707 /* Get previous start-of-scratch-area, that we use later for readjusting 708 * our existing scratch arrays. */ 709 unsigned int old_scratch_used; 710 hb_buffer_t::scratch_buffer_t *old_scratch; 711 old_scratch = buffer->get_scratch_buffer (&old_scratch_used); 712 old_scratch_used = scratch - old_scratch; 713 714 if (unlikely (!buffer->ensure (buffer->allocated * 2))) 715 FAIL ("Buffer resize failed"); 716 717 /* Adjust scratch, pchars, and log_cluster arrays. This is ugly, but really the 718 * cleanest way to do without completely restructuring the rest of this shaper. */ 719 scratch = buffer->get_scratch_buffer (&scratch_size); 720 pchars = reinterpret_cast<UniChar *> (((char *) scratch + ((char *) pchars - (char *) old_scratch))); 721 log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch))); 722 scratch += old_scratch_used; 723 scratch_size -= old_scratch_used; 724 } 725 retry: 726 { 727 string_ref = CFStringCreateWithCharactersNoCopy (NULL, 728 pchars, chars_len, 729 kCFAllocatorNull); 730 if (unlikely (!string_ref)) 731 FAIL ("CFStringCreateWithCharactersNoCopy failed"); 732 733 /* Create an attributed string, populate it, and create a line from it, then release attributed string. */ 734 { 735 CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (kCFAllocatorDefault, 736 chars_len); 737 if (unlikely (!attr_string)) 738 FAIL ("CFAttributedStringCreateMutable failed"); 739 CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref); 740 if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) 741 { 742 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), 743 kCTVerticalFormsAttributeName, kCFBooleanTrue); 744 } 745 746 if (buffer->props.language) 747 { 748 /* What's the iOS equivalent of this check? 749 * The symbols was introduced in iOS 7.0. 750 * At any rate, our fallback is safe and works fine. */ 751 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 752 # define kCTLanguageAttributeName CFSTR ("NSLanguage") 753 #endif 754 CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault, 755 hb_language_to_string (buffer->props.language), 756 kCFStringEncodingUTF8, 757 kCFAllocatorNull); 758 if (unlikely (!lang)) 759 FAIL ("CFStringCreateWithCStringNoCopy failed"); 760 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), 761 kCTLanguageAttributeName, lang); 762 CFRelease (lang); 763 } 764 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), 765 kCTFontAttributeName, font_data->ct_font); 766 767 if (num_features) 768 { 769 unsigned int start = 0; 770 range_record_t *last_range = &range_records[0]; 771 for (unsigned int k = 0; k < chars_len; k++) 772 { 773 range_record_t *range = last_range; 774 while (log_clusters[k] < range->index_first) 775 range--; 776 while (log_clusters[k] > range->index_last) 777 range++; 778 if (range != last_range) 779 { 780 if (last_range->font) 781 CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start), 782 kCTFontAttributeName, last_range->font); 783 784 start = k; 785 } 786 787 last_range = range; 788 } 789 if (start != chars_len && last_range->font) 790 CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start), 791 kCTFontAttributeName, last_range->font); 792 } 793 794 int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; 795 CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level); 796 CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault, 797 (const void **) &kCTTypesetterOptionForcedEmbeddingLevel, 798 (const void **) &level_number, 799 1, 800 &kCFTypeDictionaryKeyCallBacks, 801 &kCFTypeDictionaryValueCallBacks); 802 if (unlikely (!options)) 803 FAIL ("CFDictionaryCreate failed"); 804 805 CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options); 806 CFRelease (options); 807 CFRelease (attr_string); 808 if (unlikely (!typesetter)) 809 FAIL ("CTTypesetterCreateWithAttributedStringAndOptions failed"); 810 811 line = CTTypesetterCreateLine (typesetter, CFRangeMake(0, 0)); 812 CFRelease (typesetter); 813 if (unlikely (!line)) 814 FAIL ("CTTypesetterCreateLine failed"); 815 } 816 817 CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); 818 unsigned int num_runs = CFArrayGetCount (glyph_runs); 819 DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs); 820 821 buffer->len = 0; 822 uint32_t status_and = ~0, status_or = 0; 823 double advances_so_far = 0; 824 /* For right-to-left runs, CoreText returns the glyphs positioned such that 825 * any trailing whitespace is to the left of (0,0). Adjust coordinate system 826 * to fix for that. Test with any RTL string with trailing spaces. 827 * https://code.google.com/p/chromium/issues/detail?id=469028 828 */ 829 if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) 830 { 831 advances_so_far -= CTLineGetTrailingWhitespaceWidth (line); 832 if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) 833 advances_so_far = -advances_so_far; 834 } 835 836 const CFRange range_all = CFRangeMake (0, 0); 837 838 for (unsigned int i = 0; i < num_runs; i++) 839 { 840 CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i)); 841 CTRunStatus run_status = CTRunGetStatus (run); 842 status_or |= run_status; 843 status_and &= run_status; 844 DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status); 845 double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL); 846 if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) 847 run_advance = -run_advance; 848 DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance); 849 850 /* CoreText does automatic font fallback (AKA "cascading") for characters 851 * not supported by the requested font, and provides no way to turn it off, 852 * so we must detect if the returned run uses a font other than the requested 853 * one and fill in the buffer with .notdef glyphs instead of random glyph 854 * indices from a different font. 855 */ 856 CFDictionaryRef attributes = CTRunGetAttributes (run); 857 CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName)); 858 if (!CFEqual (run_ct_font, font_data->ct_font)) 859 { 860 /* The run doesn't use our main font instance. We have to figure out 861 * whether font fallback happened, or this is just CoreText giving us 862 * another CTFont using the same underlying CGFont. CoreText seems 863 * to do that in a variety of situations, one of which being vertical 864 * text, but also perhaps for caching reasons. 865 * 866 * First, see if it uses any of our subfonts created to set font features... 867 * 868 * Next, compare the CGFont to the one we used to create our fonts. 869 * Even this doesn't work all the time. 870 * 871 * Finally, we compare PS names, which I don't think are unique... 872 * 873 * Looks like if we really want to be sure here we have to modify the 874 * font to change the name table, similar to what we do in the uniscribe 875 * backend. 876 * 877 * However, even that wouldn't work if we were passed in the CGFont to 878 * begin with. 879 * 880 * Webkit uses a slightly different approach: it installs LastResort 881 * as fallback chain, and then checks PS name of used font against 882 * LastResort. That one is safe for any font except for LastResort, 883 * as opposed to ours, which can fail if we are using any uninstalled 884 * font that has the same name as an installed font. 885 * 886 * See: http://github.com/behdad/harfbuzz/pull/36 887 */ 888 bool matched = false; 889 for (unsigned int i = 0; i < range_records.len; i++) 890 if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font)) 891 { 892 matched = true; 893 break; 894 } 895 if (!matched) 896 { 897 CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0); 898 if (run_cg_font) 899 { 900 matched = CFEqual (run_cg_font, face_data); 901 CFRelease (run_cg_font); 902 } 903 } 904 if (!matched) 905 { 906 CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey); 907 CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey); 908 CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0); 909 CFRelease (run_ps_name); 910 CFRelease (font_ps_name); 911 if (result == kCFCompareEqualTo) 912 matched = true; 913 } 914 if (!matched) 915 { 916 CFRange range = CTRunGetStringRange (run); 917 DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld", 918 range.location, range.location + range.length); 919 if (!buffer->ensure_inplace (buffer->len + range.length)) 920 goto resize_and_retry; 921 hb_glyph_info_t *info = buffer->info + buffer->len; 922 923 hb_codepoint_t notdef = 0; 924 hb_direction_t dir = buffer->props.direction; 925 hb_position_t x_advance, y_advance, x_offset, y_offset; 926 hb_font_get_glyph_advance_for_direction (font, notdef, dir, &x_advance, &y_advance); 927 hb_font_get_glyph_origin_for_direction (font, notdef, dir, &x_offset, &y_offset); 928 hb_position_t advance = x_advance + y_advance; 929 x_offset = -x_offset; 930 y_offset = -y_offset; 931 932 unsigned int old_len = buffer->len; 933 for (CFIndex j = range.location; j < range.location + range.length; j++) 934 { 935 UniChar ch = CFStringGetCharacterAtIndex (string_ref, j); 936 if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j) 937 { 938 ch = CFStringGetCharacterAtIndex (string_ref, j - 1); 939 if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu)) 940 /* This is the second of a surrogate pair. Don't need .notdef 941 * for this one. */ 942 continue; 943 } 944 if (buffer->unicode->is_default_ignorable (ch)) 945 continue; 946 947 info->codepoint = notdef; 948 info->cluster = log_clusters[j]; 949 950 info->mask = advance; 951 info->var1.i32 = x_offset; 952 info->var2.i32 = y_offset; 953 954 info++; 955 buffer->len++; 956 } 957 if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) 958 buffer->reverse_range (old_len, buffer->len); 959 advances_so_far += run_advance; 960 continue; 961 } 962 } 963 964 unsigned int num_glyphs = CTRunGetGlyphCount (run); 965 if (num_glyphs == 0) 966 continue; 967 968 if (!buffer->ensure_inplace (buffer->len + num_glyphs)) 969 goto resize_and_retry; 970 971 hb_glyph_info_t *run_info = buffer->info + buffer->len; 972 973 /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always 974 * succeed, and so copying data to our own buffer will be rare. Reports 975 * have it that this changed in OS X 10.10 Yosemite, and NULL is returned 976 * frequently. At any rate, we can test that codepath by setting USE_PTR 977 * to false. */ 978 979 #define USE_PTR true 980 981 #define SCRATCH_SAVE() \ 982 unsigned int scratch_size_saved = scratch_size; \ 983 hb_buffer_t::scratch_buffer_t *scratch_saved = scratch 984 985 #define SCRATCH_RESTORE() \ 986 scratch_size = scratch_size_saved; \ 987 scratch = scratch_saved; 988 989 { /* Setup glyphs */ 990 SCRATCH_SAVE(); 991 const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL; 992 if (!glyphs) { 993 ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry); 994 CTRunGetGlyphs (run, range_all, glyph_buf); 995 glyphs = glyph_buf; 996 } 997 const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL; 998 if (!string_indices) { 999 ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry); 1000 CTRunGetStringIndices (run, range_all, index_buf); 1001 string_indices = index_buf; 1002 } 1003 hb_glyph_info_t *info = run_info; 1004 for (unsigned int j = 0; j < num_glyphs; j++) 1005 { 1006 info->codepoint = glyphs[j]; 1007 info->cluster = log_clusters[string_indices[j]]; 1008 info++; 1009 } 1010 SCRATCH_RESTORE(); 1011 } 1012 { 1013 /* Setup positions. 1014 * Note that CoreText does not return advances for glyphs. As such, 1015 * for all but last glyph, we use the delta position to next glyph as 1016 * advance (in the advance direction only), and for last glyph we set 1017 * whatever is needed to make the whole run's advance add up. */ 1018 SCRATCH_SAVE(); 1019 const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL; 1020 if (!positions) { 1021 ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry); 1022 CTRunGetPositions (run, range_all, position_buf); 1023 positions = position_buf; 1024 } 1025 hb_glyph_info_t *info = run_info; 1026 CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult; 1027 if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) 1028 { 1029 hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult; 1030 for (unsigned int j = 0; j < num_glyphs; j++) 1031 { 1032 double advance; 1033 if (likely (j + 1 < num_glyphs)) 1034 advance = positions[j + 1].x - positions[j].x; 1035 else /* last glyph */ 1036 advance = run_advance - (positions[j].x - positions[0].x); 1037 info->mask = advance * x_mult; 1038 info->var1.i32 = x_offset; 1039 info->var2.i32 = positions[j].y * y_mult; 1040 info++; 1041 } 1042 } 1043 else 1044 { 1045 hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult; 1046 for (unsigned int j = 0; j < num_glyphs; j++) 1047 { 1048 double advance; 1049 if (likely (j + 1 < num_glyphs)) 1050 advance = positions[j + 1].y - positions[j].y; 1051 else /* last glyph */ 1052 advance = run_advance - (positions[j].y - positions[0].y); 1053 info->mask = advance * y_mult; 1054 info->var1.i32 = positions[j].x * x_mult; 1055 info->var2.i32 = y_offset; 1056 info++; 1057 } 1058 } 1059 SCRATCH_RESTORE(); 1060 advances_so_far += run_advance; 1061 } 1062 #undef SCRATCH_RESTORE 1063 #undef SCRATCH_SAVE 1064 #undef USE_PTR 1065 #undef ALLOCATE_ARRAY 1066 1067 buffer->len += num_glyphs; 1068 } 1069 1070 /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel, 1071 * or if it does, it doesn't resepct it. So we get runs with wrong 1072 * directions. As such, disable the assert... It wouldn't crash, but 1073 * cursoring will be off... 1074 * 1075 * http://crbug.com/419769 1076 */ 1077 if (0) 1078 { 1079 /* Make sure all runs had the expected direction. */ 1080 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); 1081 assert (bool (status_and & kCTRunStatusRightToLeft) == backward); 1082 assert (bool (status_or & kCTRunStatusRightToLeft) == backward); 1083 } 1084 1085 buffer->clear_positions (); 1086 1087 unsigned int count = buffer->len; 1088 hb_glyph_info_t *info = buffer->info; 1089 hb_glyph_position_t *pos = buffer->pos; 1090 if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) 1091 for (unsigned int i = 0; i < count; i++) 1092 { 1093 pos->x_advance = info->mask; 1094 pos->x_offset = info->var1.i32; 1095 pos->y_offset = info->var2.i32; 1096 info++, pos++; 1097 } 1098 else 1099 for (unsigned int i = 0; i < count; i++) 1100 { 1101 pos->y_advance = info->mask; 1102 pos->x_offset = info->var1.i32; 1103 pos->y_offset = info->var2.i32; 1104 info++, pos++; 1105 } 1106 1107 /* Fix up clusters so that we never return out-of-order indices; 1108 * if core text has reordered glyphs, we'll merge them to the 1109 * beginning of the reordered cluster. CoreText is nice enough 1110 * to tell us whenever it has produced nonmonotonic results... 1111 * Note that we assume the input clusters were nonmonotonic to 1112 * begin with. 1113 * 1114 * This does *not* mean we'll form the same clusters as Uniscribe 1115 * or the native OT backend, only that the cluster indices will be 1116 * monotonic in the output buffer. */ 1117 if (count > 1 && (status_or & kCTRunStatusNonMonotonic)) 1118 { 1119 hb_glyph_info_t *info = buffer->info; 1120 if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) 1121 { 1122 unsigned int cluster = info[count - 1].cluster; 1123 for (unsigned int i = count - 1; i > 0; i--) 1124 { 1125 cluster = MIN (cluster, info[i - 1].cluster); 1126 info[i - 1].cluster = cluster; 1127 } 1128 } 1129 else 1130 { 1131 unsigned int cluster = info[0].cluster; 1132 for (unsigned int i = 1; i < count; i++) 1133 { 1134 cluster = MIN (cluster, info[i].cluster); 1135 info[i].cluster = cluster; 1136 } 1137 } 1138 } 1139 } 1140 1141 #undef FAIL 1142 1143 fail: 1144 if (string_ref) 1145 CFRelease (string_ref); 1146 if (line) 1147 CFRelease (line); 1148 1149 for (unsigned int i = 0; i < range_records.len; i++) 1150 if (range_records[i].font) 1151 CFRelease (range_records[i].font); 1152 1153 return ret; 1154 } 1155 1156 1157 /* 1158 * AAT shaper 1159 */ 1160 1161 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face) 1162 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font) 1163 1164 1165 /* 1166 * shaper face data 1167 */ 1168 1169 struct hb_coretext_aat_shaper_face_data_t {}; 1170 1171 hb_coretext_aat_shaper_face_data_t * 1172 _hb_coretext_aat_shaper_face_data_create (hb_face_t *face) 1173 { 1174 hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT); 1175 /* Umm, we just reference the table to check whether it exists. 1176 * Maybe add better API for this? */ 1177 if (!hb_blob_get_length (mort_blob)) 1178 { 1179 hb_blob_destroy (mort_blob); 1180 mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX); 1181 if (!hb_blob_get_length (mort_blob)) 1182 { 1183 hb_blob_destroy (mort_blob); 1184 return NULL; 1185 } 1186 } 1187 hb_blob_destroy (mort_blob); 1188 1189 return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL; 1190 } 1191 1192 void 1193 _hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED) 1194 { 1195 } 1196 1197 1198 /* 1199 * shaper font data 1200 */ 1201 1202 struct hb_coretext_aat_shaper_font_data_t {}; 1203 1204 hb_coretext_aat_shaper_font_data_t * 1205 _hb_coretext_aat_shaper_font_data_create (hb_font_t *font) 1206 { 1207 return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL; 1208 } 1209 1210 void 1211 _hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED) 1212 { 1213 } 1214 1215 1216 /* 1217 * shaper shape_plan data 1218 */ 1219 1220 struct hb_coretext_aat_shaper_shape_plan_data_t {}; 1221 1222 hb_coretext_aat_shaper_shape_plan_data_t * 1223 _hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 1224 const hb_feature_t *user_features HB_UNUSED, 1225 unsigned int num_user_features HB_UNUSED) 1226 { 1227 return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 1228 } 1229 1230 void 1231 _hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED) 1232 { 1233 } 1234 1235 1236 /* 1237 * shaper 1238 */ 1239 1240 hb_bool_t 1241 _hb_coretext_aat_shape (hb_shape_plan_t *shape_plan, 1242 hb_font_t *font, 1243 hb_buffer_t *buffer, 1244 const hb_feature_t *features, 1245 unsigned int num_features) 1246 { 1247 return _hb_coretext_shape (shape_plan, font, buffer, features, num_features); 1248 }