OLD | NEW |
1 /* | 1 /* |
2 * Copyright © 2012 Mozilla Foundation. | 2 * Copyright © 2012,2013 Mozilla Foundation. |
3 * Copyright © 2012 Google, Inc. | 3 * Copyright © 2012,2013 Google, Inc. |
4 * | 4 * |
5 * This is part of HarfBuzz, a text shaping library. | 5 * This is part of HarfBuzz, a text shaping library. |
6 * | 6 * |
7 * Permission is hereby granted, without written agreement and without | 7 * Permission is hereby granted, without written agreement and without |
8 * license or royalty fees, to use, copy, modify, and distribute this | 8 * license or royalty fees, to use, copy, modify, and distribute this |
9 * software and its documentation for any purpose, provided that the | 9 * software and its documentation for any purpose, provided that the |
10 * above copyright notice and the following two paragraphs appear in | 10 * above copyright notice and the following two paragraphs appear in |
11 * all copies of this software. | 11 * all copies of this software. |
12 * | 12 * |
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL; | 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); | 164 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); |
165 return font_data->ct_font; | 165 return font_data->ct_font; |
166 } | 166 } |
167 | 167 |
168 | 168 |
169 /* | 169 /* |
170 * shaper | 170 * shaper |
171 */ | 171 */ |
172 | 172 |
| 173 struct feature_record_t { |
| 174 unsigned int feature; |
| 175 unsigned int setting; |
| 176 }; |
| 177 |
| 178 struct active_feature_t { |
| 179 feature_record_t rec; |
| 180 unsigned int order; |
| 181 |
| 182 static int cmp (const active_feature_t *a, const active_feature_t *b) { |
| 183 return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.featur
e ? 1 : |
| 184 a->order < b->order ? -1 : a->order > b->order ? 1 : |
| 185 a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.settin
g ? 1 : |
| 186 0; |
| 187 } |
| 188 bool operator== (const active_feature_t *f) { |
| 189 return cmp (this, f) == 0; |
| 190 } |
| 191 }; |
| 192 |
| 193 struct feature_event_t { |
| 194 unsigned int index; |
| 195 bool start; |
| 196 active_feature_t feature; |
| 197 |
| 198 static int cmp (const feature_event_t *a, const feature_event_t *b) { |
| 199 return a->index < b->index ? -1 : a->index > b->index ? 1 : |
| 200 a->start < b->start ? -1 : a->start > b->start ? 1 : |
| 201 active_feature_t::cmp (&a->feature, &b->feature); |
| 202 } |
| 203 }; |
| 204 |
| 205 struct range_record_t { |
| 206 CTFontRef font; |
| 207 unsigned int index_first; /* == start */ |
| 208 unsigned int index_last; /* == end - 1 */ |
| 209 }; |
| 210 |
| 211 |
| 212 /* The following enum members are added in OS X 10.8. */ |
| 213 #define kAltHalfWidthTextSelector 6 |
| 214 #define kAltProportionalTextSelector 5 |
| 215 #define kAlternateHorizKanaOffSelector 1 |
| 216 #define kAlternateHorizKanaOnSelector 0 |
| 217 #define kAlternateKanaType 34 |
| 218 #define kAlternateVertKanaOffSelector 3 |
| 219 #define kAlternateVertKanaOnSelector 2 |
| 220 #define kCaseSensitiveLayoutOffSelector 1 |
| 221 #define kCaseSensitiveLayoutOnSelector 0 |
| 222 #define kCaseSensitiveLayoutType 33 |
| 223 #define kCaseSensitiveSpacingOffSelector 3 |
| 224 #define kCaseSensitiveSpacingOnSelector 2 |
| 225 #define kContextualAlternatesOffSelector 1 |
| 226 #define kContextualAlternatesOnSelector 0 |
| 227 #define kContextualAlternatesType 36 |
| 228 #define kContextualLigaturesOffSelector 19 |
| 229 #define kContextualLigaturesOnSelector 18 |
| 230 #define kContextualSwashAlternatesOffSelector 5 |
| 231 #define kContextualSwashAlternatesOnSelector 4 |
| 232 #define kDefaultLowerCaseSelector 0 |
| 233 #define kDefaultUpperCaseSelector 0 |
| 234 #define kHistoricalLigaturesOffSelector 21 |
| 235 #define kHistoricalLigaturesOnSelector 20 |
| 236 #define kHojoCharactersSelector 12 |
| 237 #define kJIS2004CharactersSelector 11 |
| 238 #define kLowerCasePetiteCapsSelector 2 |
| 239 #define kLowerCaseSmallCapsSelector 1 |
| 240 #define kLowerCaseType 37 |
| 241 #define kMathematicalGreekOffSelector 11 |
| 242 #define kMathematicalGreekOnSelector 10 |
| 243 #define kNLCCharactersSelector 13 |
| 244 #define kQuarterWidthTextSelector 4 |
| 245 #define kScientificInferiorsSelector 4 |
| 246 #define kStylisticAltEightOffSelector 17 |
| 247 #define kStylisticAltEightOnSelector 16 |
| 248 #define kStylisticAltEighteenOffSelector 37 |
| 249 #define kStylisticAltEighteenOnSelector 36 |
| 250 #define kStylisticAltElevenOffSelector 23 |
| 251 #define kStylisticAltElevenOnSelector 22 |
| 252 #define kStylisticAltFifteenOffSelector 31 |
| 253 #define kStylisticAltFifteenOnSelector 30 |
| 254 #define kStylisticAltFiveOffSelector 11 |
| 255 #define kStylisticAltFiveOnSelector 10 |
| 256 #define kStylisticAltFourOffSelector 9 |
| 257 #define kStylisticAltFourOnSelector 8 |
| 258 #define kStylisticAltFourteenOffSelector 29 |
| 259 #define kStylisticAltFourteenOnSelector 28 |
| 260 #define kStylisticAltNineOffSelector 19 |
| 261 #define kStylisticAltNineOnSelector 18 |
| 262 #define kStylisticAltNineteenOffSelector 39 |
| 263 #define kStylisticAltNineteenOnSelector 38 |
| 264 #define kStylisticAltOneOffSelector 3 |
| 265 #define kStylisticAltOneOnSelector 2 |
| 266 #define kStylisticAltSevenOffSelector 15 |
| 267 #define kStylisticAltSevenOnSelector 14 |
| 268 #define kStylisticAltSeventeenOffSelector 35 |
| 269 #define kStylisticAltSeventeenOnSelector 34 |
| 270 #define kStylisticAltSixOffSelector 13 |
| 271 #define kStylisticAltSixOnSelector 12 |
| 272 #define kStylisticAltSixteenOffSelector 33 |
| 273 #define kStylisticAltSixteenOnSelector 32 |
| 274 #define kStylisticAltTenOffSelector 21 |
| 275 #define kStylisticAltTenOnSelector 20 |
| 276 #define kStylisticAltThirteenOffSelector 27 |
| 277 #define kStylisticAltThirteenOnSelector 26 |
| 278 #define kStylisticAltThreeOffSelector 7 |
| 279 #define kStylisticAltThreeOnSelector 6 |
| 280 #define kStylisticAltTwelveOffSelector 25 |
| 281 #define kStylisticAltTwelveOnSelector 24 |
| 282 #define kStylisticAltTwentyOffSelector 41 |
| 283 #define kStylisticAltTwentyOnSelector 40 |
| 284 #define kStylisticAltTwoOffSelector 5 |
| 285 #define kStylisticAltTwoOnSelector 4 |
| 286 #define kStylisticAlternativesType 35 |
| 287 #define kSwashAlternatesOffSelector 3 |
| 288 #define kSwashAlternatesOnSelector 2 |
| 289 #define kThirdWidthTextSelector 3 |
| 290 #define kTraditionalNamesCharactersSelector 14 |
| 291 #define kUpperCasePetiteCapsSelector 2 |
| 292 #define kUpperCaseSmallCapsSelector 1 |
| 293 #define kUpperCaseType 38 |
| 294 |
| 295 /* Table data courtesy of Apple. */ |
| 296 struct feature_mapping_t { |
| 297 FourCharCode otFeatureTag; |
| 298 uint16_t aatFeatureType; |
| 299 uint16_t selectorToEnable; |
| 300 uint16_t selectorToDisable; |
| 301 } feature_mappings[] = { |
| 302 { 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector,
kDefaultUpperCaseSelector }, |
| 303 { 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector,
kDefaultUpperCaseSelector }, |
| 304 { 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector,
kContextualAlternatesOffSelector }, |
| 305 { 'case', kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector,
kCaseSensitiveLayoutOffSelector }, |
| 306 { 'clig', kLigaturesType, kContextualLigaturesOnSelector,
kContextualLigaturesOffSelector }, |
| 307 { 'cpsp', kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector,
kCaseSensitiveSpacingOffSelector }, |
| 308 { 'cswh', kContextualAlternatesType, kContextualSwashAlternatesOnSelector
, kContextualSwashAlternatesOffSelector }, |
| 309 { 'dlig', kLigaturesType, kRareLigaturesOnSelector,
kRareLigaturesOffSelector }, |
| 310 { 'expt', kCharacterShapeType, kExpertCharactersSelector,
16 }, |
| 311 { 'frac', kFractionsType, kDiagonalFractionsSelector,
kNoFractionsSelector }, |
| 312 { 'fwid', kTextSpacingType, kMonospacedTextSelector,
7 }, |
| 313 { 'halt', kTextSpacingType, kAltHalfWidthTextSelector,
7 }, |
| 314 { 'hist', kLigaturesType, kHistoricalLigaturesOnSelector,
kHistoricalLigaturesOffSelector }, |
| 315 { 'hkna', kAlternateKanaType, kAlternateHorizKanaOnSelector,
kAlternateHorizKanaOffSelector, }, |
| 316 { 'hlig', kLigaturesType, kHistoricalLigaturesOnSelector,
kHistoricalLigaturesOffSelector }, |
| 317 { 'hngl', kTransliterationType, kHanjaToHangulSelector,
kNoTransliterationSelector }, |
| 318 { 'hojo', kCharacterShapeType, kHojoCharactersSelector,
16 }, |
| 319 { 'hwid', kTextSpacingType, kHalfWidthTextSelector,
7 }, |
| 320 { 'ital', kItalicCJKRomanType, kCJKItalicRomanOnSelector,
kCJKItalicRomanOffSelector }, |
| 321 { 'jp04', kCharacterShapeType, kJIS2004CharactersSelector,
16 }, |
| 322 { 'jp78', kCharacterShapeType, kJIS1978CharactersSelector,
16 }, |
| 323 { 'jp83', kCharacterShapeType, kJIS1983CharactersSelector,
16 }, |
| 324 { 'jp90', kCharacterShapeType, kJIS1990CharactersSelector,
16 }, |
| 325 { 'liga', kLigaturesType, kCommonLigaturesOnSelector,
kCommonLigaturesOffSelector }, |
| 326 { 'lnum', kNumberCaseType, kUpperCaseNumbersSelector,
2 }, |
| 327 { 'mgrk', kMathematicalExtrasType, kMathematicalGreekOnSelector,
kMathematicalGreekOffSelector }, |
| 328 { 'nlck', kCharacterShapeType, kNLCCharactersSelector,
16 }, |
| 329 { 'onum', kNumberCaseType, kLowerCaseNumbersSelector,
2 }, |
| 330 { 'ordn', kVerticalPositionType, kOrdinalsSelector,
kNormalPositionSelector }, |
| 331 { 'palt', kTextSpacingType, kAltProportionalTextSelector,
7 }, |
| 332 { 'pcap', kLowerCaseType, kLowerCasePetiteCapsSelector,
kDefaultLowerCaseSelector }, |
| 333 { 'pkna', kTextSpacingType, kProportionalTextSelector,
7 }, |
| 334 { 'pnum', kNumberSpacingType, kProportionalNumbersSelector,
4 }, |
| 335 { 'pwid', kTextSpacingType, kProportionalTextSelector,
7 }, |
| 336 { 'qwid', kTextSpacingType, kQuarterWidthTextSelector,
7 }, |
| 337 { 'ruby', kRubyKanaType, kRubyKanaOnSelector,
kRubyKanaOffSelector }, |
| 338 { 'sinf', kVerticalPositionType, kScientificInferiorsSelector,
kNormalPositionSelector }, |
| 339 { 'smcp', kLowerCaseType, kLowerCaseSmallCapsSelector,
kDefaultLowerCaseSelector }, |
| 340 { 'smpl', kCharacterShapeType, kSimplifiedCharactersSelector,
16 }, |
| 341 { 'ss01', kStylisticAlternativesType, kStylisticAltOneOnSelector,
kStylisticAltOneOffSelector }, |
| 342 { 'ss02', kStylisticAlternativesType, kStylisticAltTwoOnSelector,
kStylisticAltTwoOffSelector }, |
| 343 { 'ss03', kStylisticAlternativesType, kStylisticAltThreeOnSelector,
kStylisticAltThreeOffSelector }, |
| 344 { 'ss04', kStylisticAlternativesType, kStylisticAltFourOnSelector,
kStylisticAltFourOffSelector }, |
| 345 { 'ss05', kStylisticAlternativesType, kStylisticAltFiveOnSelector,
kStylisticAltFiveOffSelector }, |
| 346 { 'ss06', kStylisticAlternativesType, kStylisticAltSixOnSelector,
kStylisticAltSixOffSelector }, |
| 347 { 'ss07', kStylisticAlternativesType, kStylisticAltSevenOnSelector,
kStylisticAltSevenOffSelector }, |
| 348 { 'ss08', kStylisticAlternativesType, kStylisticAltEightOnSelector,
kStylisticAltEightOffSelector }, |
| 349 { 'ss09', kStylisticAlternativesType, kStylisticAltNineOnSelector,
kStylisticAltNineOffSelector }, |
| 350 { 'ss10', kStylisticAlternativesType, kStylisticAltTenOnSelector,
kStylisticAltTenOffSelector }, |
| 351 { 'ss11', kStylisticAlternativesType, kStylisticAltElevenOnSelector,
kStylisticAltElevenOffSelector }, |
| 352 { 'ss12', kStylisticAlternativesType, kStylisticAltTwelveOnSelector,
kStylisticAltTwelveOffSelector }, |
| 353 { 'ss13', kStylisticAlternativesType, kStylisticAltThirteenOnSelector,
kStylisticAltThirteenOffSelector }, |
| 354 { 'ss14', kStylisticAlternativesType, kStylisticAltFourteenOnSelector,
kStylisticAltFourteenOffSelector }, |
| 355 { 'ss15', kStylisticAlternativesType, kStylisticAltFifteenOnSelector,
kStylisticAltFifteenOffSelector }, |
| 356 { 'ss16', kStylisticAlternativesType, kStylisticAltSixteenOnSelector,
kStylisticAltSixteenOffSelector }, |
| 357 { 'ss17', kStylisticAlternativesType, kStylisticAltSeventeenOnSelector,
kStylisticAltSeventeenOffSelector }, |
| 358 { 'ss18', kStylisticAlternativesType, kStylisticAltEighteenOnSelector,
kStylisticAltEighteenOffSelector }, |
| 359 { 'ss19', kStylisticAlternativesType, kStylisticAltNineteenOnSelector,
kStylisticAltNineteenOffSelector }, |
| 360 { 'ss20', kStylisticAlternativesType, kStylisticAltTwentyOnSelector,
kStylisticAltTwentyOffSelector }, |
| 361 { 'subs', kVerticalPositionType, kInferiorsSelector,
kNormalPositionSelector }, |
| 362 { 'sups', kVerticalPositionType, kSuperiorsSelector,
kNormalPositionSelector }, |
| 363 { 'swsh', kContextualAlternatesType, kSwashAlternatesOnSelector,
kSwashAlternatesOffSelector }, |
| 364 { 'titl', kStyleOptionsType, kTitlingCapsSelector,
kNoStyleOptionsSelector }, |
| 365 { 'tnam', kCharacterShapeType, kTraditionalNamesCharactersSelector,
16 }, |
| 366 { 'tnum', kNumberSpacingType, kMonospacedNumbersSelector,
4 }, |
| 367 { 'trad', kCharacterShapeType, kTraditionalCharactersSelector,
16 }, |
| 368 { 'twid', kTextSpacingType, kThirdWidthTextSelector,
7 }, |
| 369 { 'unic', kLetterCaseType, 14,
15 }, |
| 370 { 'valt', kTextSpacingType, kAltProportionalTextSelector,
7 }, |
| 371 { 'vert', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector,
kSubstituteVerticalFormsOffSelector }, |
| 372 { 'vhal', kTextSpacingType, kAltHalfWidthTextSelector,
7 }, |
| 373 { 'vkna', kAlternateKanaType, kAlternateVertKanaOnSelector,
kAlternateVertKanaOffSelector }, |
| 374 { 'vpal', kTextSpacingType, kAltProportionalTextSelector,
7 }, |
| 375 { 'vrt2', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector,
kSubstituteVerticalFormsOffSelector }, |
| 376 { 'zero', kTypographicExtrasType, kSlashedZeroOnSelector,
kSlashedZeroOffSelector }, |
| 377 }; |
| 378 |
| 379 static int |
| 380 _hb_feature_mapping_cmp (const void *key_, const void *entry_) |
| 381 { |
| 382 unsigned int key = * (unsigned int *) key_; |
| 383 const feature_mapping_t * entry = (const feature_mapping_t *) entry_; |
| 384 return key < entry->otFeatureTag ? -1 : |
| 385 key > entry->otFeatureTag ? 1 : |
| 386 0; |
| 387 } |
| 388 |
173 hb_bool_t | 389 hb_bool_t |
174 _hb_coretext_shape (hb_shape_plan_t *shape_plan, | 390 _hb_coretext_shape (hb_shape_plan_t *shape_plan, |
175 hb_font_t *font, | 391 hb_font_t *font, |
176 hb_buffer_t *buffer, | 392 hb_buffer_t *buffer, |
177 const hb_feature_t *features, | 393 const hb_feature_t *features, |
178 unsigned int num_features) | 394 unsigned int num_features) |
179 { | 395 { |
180 hb_face_t *face = font->face; | 396 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); | 397 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); |
183 | 398 |
| 399 /* |
| 400 * Set up features. |
| 401 * (copied + modified from code from hb-uniscribe.cc) |
| 402 */ |
| 403 hb_auto_array_t<feature_record_t> feature_records; |
| 404 hb_auto_array_t<range_record_t> range_records; |
| 405 if (num_features) |
| 406 { |
| 407 /* Sort features by start/end events. */ |
| 408 hb_auto_array_t<feature_event_t> feature_events; |
| 409 for (unsigned int i = 0; i < num_features; i++) |
| 410 { |
| 411 const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&
features[i].tag, |
| 412 f
eature_mappings, |
| 413 A
RRAY_LENGTH (feature_mappings), |
| 414 s
izeof (feature_mappings[0]), |
| 415 _
hb_feature_mapping_cmp); |
| 416 if (!mapping) |
| 417 continue; |
| 418 |
| 419 active_feature_t feature; |
| 420 feature.rec.feature = mapping->aatFeatureType; |
| 421 feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapp
ing->selectorToDisable; |
| 422 feature.order = i; |
| 423 |
| 424 feature_event_t *event; |
| 425 |
| 426 event = feature_events.push (); |
| 427 if (unlikely (!event)) |
| 428 goto fail_features; |
| 429 event->index = features[i].start; |
| 430 event->start = true; |
| 431 event->feature = feature; |
| 432 |
| 433 event = feature_events.push (); |
| 434 if (unlikely (!event)) |
| 435 goto fail_features; |
| 436 event->index = features[i].end; |
| 437 event->start = false; |
| 438 event->feature = feature; |
| 439 } |
| 440 feature_events.sort (); |
| 441 /* Add a strategic final event. */ |
| 442 { |
| 443 active_feature_t feature; |
| 444 feature.rec.feature = HB_TAG_NONE; |
| 445 feature.rec.setting = 0; |
| 446 feature.order = num_features + 1; |
| 447 |
| 448 feature_event_t *event = feature_events.push (); |
| 449 if (unlikely (!event)) |
| 450 goto fail_features; |
| 451 event->index = 0; /* This value does magic. */ |
| 452 event->start = false; |
| 453 event->feature = feature; |
| 454 } |
| 455 |
| 456 /* Scan events and save features for each range. */ |
| 457 hb_auto_array_t<active_feature_t> active_features; |
| 458 unsigned int last_index = 0; |
| 459 for (unsigned int i = 0; i < feature_events.len; i++) |
| 460 { |
| 461 feature_event_t *event = &feature_events[i]; |
| 462 |
| 463 if (event->index != last_index) |
| 464 { |
| 465 /* Save a snapshot of active features and the range. */ |
| 466 range_record_t *range = range_records.push (); |
| 467 if (unlikely (!range)) |
| 468 goto fail_features; |
| 469 |
| 470 unsigned int offset = feature_records.len; |
| 471 |
| 472 if (active_features.len) |
| 473 { |
| 474 CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDe
fault, 0, &kCFTypeArrayCallBacks); |
| 475 |
| 476 /* TODO sort and resolve conflicting features? */ |
| 477 /* active_features.sort (); */ |
| 478 for (unsigned int j = 0; j < active_features.len; j++) |
| 479 { |
| 480 CFStringRef keys[2] = { |
| 481 kCTFontFeatureTypeIdentifierKey, |
| 482 kCTFontFeatureSelectorIdentifierKey |
| 483 }; |
| 484 CFNumberRef values[2] = { |
| 485 CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_fea
tures[j].rec.feature), |
| 486 CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_fea
tures[j].rec.setting) |
| 487 }; |
| 488 CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault, |
| 489 (const void **) keys, |
| 490 (const void **) values, |
| 491 2, |
| 492 &kCFTypeDictionaryKeyCall
Backs, |
| 493 &kCFTypeDictionaryValueCa
llBacks); |
| 494 CFRelease (values[0]); |
| 495 CFRelease (values[1]); |
| 496 |
| 497 CFArrayAppendValue (features_array, dict); |
| 498 CFRelease (dict); |
| 499 |
| 500 } |
| 501 |
| 502 CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault, |
| 503 (const void **) &kCTF
ontFeatureSettingsAttribute, |
| 504 (const void **) &feat
ures_array, |
| 505 1, |
| 506 &kCFTypeDictionaryKey
CallBacks, |
| 507 &kCFTypeDictionaryVal
ueCallBacks); |
| 508 CFRelease (features_array); |
| 509 |
| 510 CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (
attributes); |
| 511 CFRelease (attributes); |
| 512 |
| 513 range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0,
NULL, font_desc); |
| 514 |
| 515 CFRelease (font_desc); |
| 516 } |
| 517 else |
| 518 { |
| 519 range->font = NULL; |
| 520 } |
| 521 |
| 522 range->index_first = last_index; |
| 523 range->index_last = event->index - 1; |
| 524 |
| 525 last_index = event->index; |
| 526 } |
| 527 |
| 528 if (event->start) { |
| 529 active_feature_t *feature = active_features.push (); |
| 530 if (unlikely (!feature)) |
| 531 goto fail_features; |
| 532 *feature = event->feature; |
| 533 } else { |
| 534 active_feature_t *feature = active_features.find (&event->feature); |
| 535 if (feature) |
| 536 active_features.remove (feature - active_features.array); |
| 537 } |
| 538 } |
| 539 |
| 540 if (!range_records.len) /* No active feature found. */ |
| 541 goto fail_features; |
| 542 } |
| 543 else |
| 544 { |
| 545 fail_features: |
| 546 num_features = 0; |
| 547 } |
| 548 |
184 #define FAIL(...) \ | 549 #define FAIL(...) \ |
185 HB_STMT_START { \ | 550 HB_STMT_START { \ |
186 DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \ | 551 DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \ |
187 return false; \ | 552 return false; \ |
188 } HB_STMT_END; | 553 } HB_STMT_END; |
189 | 554 |
190 unsigned int scratch_size; | 555 unsigned int scratch_size; |
191 char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size); | 556 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_
size); |
| 557 |
| 558 #define ALLOCATE_ARRAY(Type, name, len) \ |
| 559 Type *name = (Type *) scratch; \ |
| 560 { \ |
| 561 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch))
; \ |
| 562 assert (_consumed <= scratch_size); \ |
| 563 scratch += _consumed; \ |
| 564 scratch_size -= _consumed; \ |
| 565 } |
192 | 566 |
193 #define utf16_index() var1.u32 | 567 #define utf16_index() var1.u32 |
194 | 568 |
195 UniChar *pchars = (UniChar *) scratch; | 569 ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2); |
| 570 |
196 unsigned int chars_len = 0; | 571 unsigned int chars_len = 0; |
197 for (unsigned int i = 0; i < buffer->len; i++) { | 572 for (unsigned int i = 0; i < buffer->len; i++) { |
198 hb_codepoint_t c = buffer->info[i].codepoint; | 573 hb_codepoint_t c = buffer->info[i].codepoint; |
199 buffer->info[i].utf16_index() = chars_len; | 574 buffer->info[i].utf16_index() = chars_len; |
200 if (likely (c < 0x10000)) | 575 if (likely (c < 0x10000)) |
201 pchars[chars_len++] = c; | 576 pchars[chars_len++] = c; |
202 else if (unlikely (c >= 0x110000)) | 577 else if (unlikely (c >= 0x110000)) |
203 pchars[chars_len++] = 0xFFFD; | 578 pchars[chars_len++] = 0xFFFD; |
204 else { | 579 else { |
205 pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); | 580 pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); |
206 pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); | 581 pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); |
207 } | 582 } |
208 } | 583 } |
209 | 584 |
210 #undef utf16_index | 585 #undef utf16_index |
211 | 586 |
212 CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (kCFAllocatorDefau
lt, | 587 CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL, |
213 pchars, chars_len
, | 588 pchars, chars_len
, |
214 kCFAllocatorNull)
; | 589 kCFAllocatorNull)
; |
215 | 590 |
216 CFDictionaryRef attrs = CFDictionaryCreate (kCFAllocatorDefault, | 591 CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NU
LL, chars_len); |
217 (const void**) &kCTFontAttributeNa
me, | 592 CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref); |
218 (const void**) &font_data->ct_font
, | 593 CFRelease (string_ref); |
219 1, /* count of attributes */ | 594 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), |
220 &kCFTypeDictionaryKeyCallBacks, | 595 » » » » kCTFontAttributeName, font_data->ct_font); |
221 &kCFTypeDictionaryValueCallBacks); | |
222 | 596 |
223 /* TODO: support features */ | 597 if (num_features) |
| 598 { |
| 599 ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len); |
224 | 600 |
225 CFAttributedStringRef attr_string = CFAttributedStringCreate (kCFAllocatorDefa
ult, string_ref, attrs); | 601 /* Need log_clusters to assign features. */ |
226 CFRelease (string_ref); | 602 chars_len = 0; |
227 CFRelease (attrs); | 603 for (unsigned int i = 0; i < buffer->len; i++) |
| 604 { |
| 605 hb_codepoint_t c = buffer->info[i].codepoint; |
| 606 unsigned int cluster = buffer->info[i].cluster; |
| 607 log_clusters[chars_len++] = cluster; |
| 608 if (c >= 0x10000 && c < 0x110000) |
| 609 » log_clusters[chars_len++] = cluster; /* Surrogates. */ |
| 610 } |
| 611 |
| 612 unsigned int start = 0; |
| 613 range_record_t *last_range = &range_records[0]; |
| 614 for (unsigned int k = 0; k < chars_len; k++) |
| 615 { |
| 616 range_record_t *range = last_range; |
| 617 while (log_clusters[k] < range->index_first) |
| 618 » range--; |
| 619 while (log_clusters[k] > range->index_last) |
| 620 » range++; |
| 621 if (range != last_range) |
| 622 { |
| 623 if (last_range->font) |
| 624 » CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - s
tart), |
| 625 » » » » » kCTFontAttributeName, last_range->font
); |
| 626 |
| 627 » start = k; |
| 628 } |
| 629 |
| 630 last_range = range; |
| 631 } |
| 632 if (start != chars_len && last_range->font) |
| 633 CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len
- start - 1), |
| 634 » » » » kCTFontAttributeName, last_range->font); |
| 635 |
| 636 for (unsigned int i = 0; i < range_records.len; i++) |
| 637 if (range_records[i].font) |
| 638 » CFRelease (range_records[i].font); |
| 639 } |
228 | 640 |
229 CTLineRef line = CTLineCreateWithAttributedString (attr_string); | 641 CTLineRef line = CTLineCreateWithAttributedString (attr_string); |
230 CFRelease (attr_string); | 642 CFRelease (attr_string); |
231 | 643 |
232 CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); | 644 CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); |
233 unsigned int num_runs = CFArrayGetCount (glyph_runs); | 645 unsigned int num_runs = CFArrayGetCount (glyph_runs); |
234 | 646 |
235 bool success = true; | |
236 buffer->len = 0; | 647 buffer->len = 0; |
237 | 648 |
238 const CFRange range_all = CFRangeMake (0, 0); | 649 const CFRange range_all = CFRangeMake (0, 0); |
239 | 650 |
240 for (unsigned int i = 0; i < num_runs; i++) { | 651 for (unsigned int i = 0; i < num_runs; i++) { |
241 CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i); | 652 CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i); |
242 | 653 |
243 unsigned int num_glyphs = CTRunGetGlyphCount (run); | 654 unsigned int num_glyphs = CTRunGetGlyphCount (run); |
244 if (num_glyphs == 0) | 655 if (num_glyphs == 0) |
245 continue; | 656 continue; |
246 | 657 |
247 buffer->ensure (buffer->len + num_glyphs); | 658 buffer->ensure (buffer->len + num_glyphs); |
248 | 659 |
249 /* Testing indicates that CTRunGetGlyphsPtr (almost?) always succeeds, | 660 scratch = buffer->get_scratch_buffer (&scratch_size); |
250 * and so copying data to our own buffer with CTRunGetGlyphs will be | |
251 * extremely rare. */ | |
252 | 661 |
253 unsigned int scratch_size; | 662 /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always |
254 char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size); | 663 * succeed, and so copying data to our own buffer will be rare. */ |
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 | 664 |
261 const CGGlyph* glyphs = CTRunGetGlyphsPtr (run); | 665 const CGGlyph* glyphs = CTRunGetGlyphsPtr (run); |
262 if (!glyphs) { | 666 if (!glyphs) { |
263 ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs); | 667 ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs); |
264 CTRunGetGlyphs (run, range_all, glyph_buf); | 668 CTRunGetGlyphs (run, range_all, glyph_buf); |
265 glyphs = glyph_buf; | 669 glyphs = glyph_buf; |
266 } | 670 } |
267 | 671 |
268 const CGPoint* positions = CTRunGetPositionsPtr (run); | 672 const CGPoint* positions = CTRunGetPositionsPtr (run); |
269 if (!positions) { | 673 if (!positions) { |
(...skipping 10 matching lines...) Expand all Loading... |
280 } | 684 } |
281 | 685 |
282 #undef ALLOCATE_ARRAY | 686 #undef ALLOCATE_ARRAY |
283 | 687 |
284 double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NU
LL); | 688 double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NU
LL); |
285 | 689 |
286 for (unsigned int j = 0; j < num_glyphs; j++) { | 690 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; | 691 double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x
+ run_width) - positions[j].x; |
288 | 692 |
289 hb_glyph_info_t *info = &buffer->info[buffer->len]; | 693 hb_glyph_info_t *info = &buffer->info[buffer->len]; |
290 hb_glyph_position_t *pos = &buffer->pos[buffer->len]; | |
291 | 694 |
292 info->codepoint = glyphs[j]; | 695 info->codepoint = glyphs[j]; |
293 info->cluster = string_indices[j]; | 696 info->cluster = string_indices[j]; |
294 | 697 |
295 /* Currently, we do all x-positioning by setting the advance, we never use
x-offset. */ | 698 /* Currently, we do all x-positioning by setting the advance, we never use
x-offset. */ |
296 info->mask = advance; | 699 info->mask = advance; |
297 info->var1.u32 = 0; | 700 info->var1.u32 = 0; |
298 info->var2.u32 = positions[j].y; | 701 info->var2.u32 = positions[j].y; |
299 | 702 |
300 buffer->len++; | 703 buffer->len++; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 if (buffer->info[j - 1].cluster < curr_cluster) | 747 if (buffer->info[j - 1].cluster < curr_cluster) |
345 buffer->info[j - 1].cluster = curr_cluster; | 748 buffer->info[j - 1].cluster = curr_cluster; |
346 else | 749 else |
347 break; | 750 break; |
348 } | 751 } |
349 } | 752 } |
350 prev_cluster = curr_cluster; | 753 prev_cluster = curr_cluster; |
351 } | 754 } |
352 } | 755 } |
353 | 756 |
| 757 CFRelease (line); |
| 758 |
354 return true; | 759 return true; |
355 } | 760 } |
OLD | NEW |