1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/harfbuzz/src/hb-coretext.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,812 @@ 1.4 +/* 1.5 + * Copyright © 2012,2013 Mozilla Foundation. 1.6 + * Copyright © 2012,2013 Google, Inc. 1.7 + * 1.8 + * This is part of HarfBuzz, a text shaping library. 1.9 + * 1.10 + * Permission is hereby granted, without written agreement and without 1.11 + * license or royalty fees, to use, copy, modify, and distribute this 1.12 + * software and its documentation for any purpose, provided that the 1.13 + * above copyright notice and the following two paragraphs appear in 1.14 + * all copies of this software. 1.15 + * 1.16 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1.17 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1.18 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1.19 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1.20 + * DAMAGE. 1.21 + * 1.22 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1.23 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.24 + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 1.25 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 1.26 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 1.27 + * 1.28 + * Mozilla Author(s): Jonathan Kew 1.29 + * Google Author(s): Behdad Esfahbod 1.30 + */ 1.31 + 1.32 +#define HB_SHAPER coretext 1.33 +#include "hb-shaper-impl-private.hh" 1.34 + 1.35 +#include "hb-coretext.h" 1.36 + 1.37 + 1.38 +#ifndef HB_DEBUG_CORETEXT 1.39 +#define HB_DEBUG_CORETEXT (HB_DEBUG+0) 1.40 +#endif 1.41 + 1.42 + 1.43 +HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) 1.44 +HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) 1.45 + 1.46 + 1.47 +/* 1.48 + * shaper face data 1.49 + */ 1.50 + 1.51 +struct hb_coretext_shaper_face_data_t { 1.52 + CGFontRef cg_font; 1.53 +}; 1.54 + 1.55 +static void 1.56 +release_data (void *info, const void *data, size_t size) 1.57 +{ 1.58 + assert (hb_blob_get_length ((hb_blob_t *) info) == size && 1.59 + hb_blob_get_data ((hb_blob_t *) info, NULL) == data); 1.60 + 1.61 + hb_blob_destroy ((hb_blob_t *) info); 1.62 +} 1.63 + 1.64 +hb_coretext_shaper_face_data_t * 1.65 +_hb_coretext_shaper_face_data_create (hb_face_t *face) 1.66 +{ 1.67 + hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t)); 1.68 + if (unlikely (!data)) 1.69 + return NULL; 1.70 + 1.71 + hb_blob_t *blob = hb_face_reference_blob (face); 1.72 + unsigned int blob_length; 1.73 + const char *blob_data = hb_blob_get_data (blob, &blob_length); 1.74 + if (unlikely (!blob_length)) 1.75 + DEBUG_MSG (CORETEXT, face, "Face has empty blob"); 1.76 + 1.77 + CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data); 1.78 + data->cg_font = CGFontCreateWithDataProvider (provider); 1.79 + CGDataProviderRelease (provider); 1.80 + 1.81 + if (unlikely (!data->cg_font)) { 1.82 + DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); 1.83 + free (data); 1.84 + return NULL; 1.85 + } 1.86 + 1.87 + return data; 1.88 +} 1.89 + 1.90 +void 1.91 +_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) 1.92 +{ 1.93 + CFRelease (data->cg_font); 1.94 + free (data); 1.95 +} 1.96 + 1.97 +CGFontRef 1.98 +hb_coretext_face_get_cg_font (hb_face_t *face) 1.99 +{ 1.100 + if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; 1.101 + hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 1.102 + return face_data->cg_font; 1.103 +} 1.104 + 1.105 + 1.106 +/* 1.107 + * shaper font data 1.108 + */ 1.109 + 1.110 +struct hb_coretext_shaper_font_data_t { 1.111 + CTFontRef ct_font; 1.112 +}; 1.113 + 1.114 +hb_coretext_shaper_font_data_t * 1.115 +_hb_coretext_shaper_font_data_create (hb_font_t *font) 1.116 +{ 1.117 + if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL; 1.118 + 1.119 + hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t)); 1.120 + if (unlikely (!data)) 1.121 + return NULL; 1.122 + 1.123 + hb_face_t *face = font->face; 1.124 + hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 1.125 + 1.126 + data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL); 1.127 + if (unlikely (!data->ct_font)) { 1.128 + DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); 1.129 + free (data); 1.130 + return NULL; 1.131 + } 1.132 + 1.133 + return data; 1.134 +} 1.135 + 1.136 +void 1.137 +_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data) 1.138 +{ 1.139 + CFRelease (data->ct_font); 1.140 + free (data); 1.141 +} 1.142 + 1.143 + 1.144 +/* 1.145 + * shaper shape_plan data 1.146 + */ 1.147 + 1.148 +struct hb_coretext_shaper_shape_plan_data_t {}; 1.149 + 1.150 +hb_coretext_shaper_shape_plan_data_t * 1.151 +_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, 1.152 + const hb_feature_t *user_features HB_UNUSED, 1.153 + unsigned int num_user_features HB_UNUSED) 1.154 +{ 1.155 + return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; 1.156 +} 1.157 + 1.158 +void 1.159 +_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED) 1.160 +{ 1.161 +} 1.162 + 1.163 +CTFontRef 1.164 +hb_coretext_font_get_ct_font (hb_font_t *font) 1.165 +{ 1.166 + if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL; 1.167 + hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 1.168 + return font_data->ct_font; 1.169 +} 1.170 + 1.171 + 1.172 +/* 1.173 + * shaper 1.174 + */ 1.175 + 1.176 +struct feature_record_t { 1.177 + unsigned int feature; 1.178 + unsigned int setting; 1.179 +}; 1.180 + 1.181 +struct active_feature_t { 1.182 + feature_record_t rec; 1.183 + unsigned int order; 1.184 + 1.185 + static int cmp (const active_feature_t *a, const active_feature_t *b) { 1.186 + return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 : 1.187 + a->order < b->order ? -1 : a->order > b->order ? 1 : 1.188 + a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 : 1.189 + 0; 1.190 + } 1.191 + bool operator== (const active_feature_t *f) { 1.192 + return cmp (this, f) == 0; 1.193 + } 1.194 +}; 1.195 + 1.196 +struct feature_event_t { 1.197 + unsigned int index; 1.198 + bool start; 1.199 + active_feature_t feature; 1.200 + 1.201 + static int cmp (const feature_event_t *a, const feature_event_t *b) { 1.202 + return a->index < b->index ? -1 : a->index > b->index ? 1 : 1.203 + a->start < b->start ? -1 : a->start > b->start ? 1 : 1.204 + active_feature_t::cmp (&a->feature, &b->feature); 1.205 + } 1.206 +}; 1.207 + 1.208 +struct range_record_t { 1.209 + CTFontRef font; 1.210 + unsigned int index_first; /* == start */ 1.211 + unsigned int index_last; /* == end - 1 */ 1.212 +}; 1.213 + 1.214 + 1.215 +/* The following enum members are added in OS X 10.8. */ 1.216 +#define kAltHalfWidthTextSelector 6 1.217 +#define kAltProportionalTextSelector 5 1.218 +#define kAlternateHorizKanaOffSelector 1 1.219 +#define kAlternateHorizKanaOnSelector 0 1.220 +#define kAlternateKanaType 34 1.221 +#define kAlternateVertKanaOffSelector 3 1.222 +#define kAlternateVertKanaOnSelector 2 1.223 +#define kCaseSensitiveLayoutOffSelector 1 1.224 +#define kCaseSensitiveLayoutOnSelector 0 1.225 +#define kCaseSensitiveLayoutType 33 1.226 +#define kCaseSensitiveSpacingOffSelector 3 1.227 +#define kCaseSensitiveSpacingOnSelector 2 1.228 +#define kContextualAlternatesOffSelector 1 1.229 +#define kContextualAlternatesOnSelector 0 1.230 +#define kContextualAlternatesType 36 1.231 +#define kContextualLigaturesOffSelector 19 1.232 +#define kContextualLigaturesOnSelector 18 1.233 +#define kContextualSwashAlternatesOffSelector 5 1.234 +#define kContextualSwashAlternatesOnSelector 4 1.235 +#define kDefaultLowerCaseSelector 0 1.236 +#define kDefaultUpperCaseSelector 0 1.237 +#define kHistoricalLigaturesOffSelector 21 1.238 +#define kHistoricalLigaturesOnSelector 20 1.239 +#define kHojoCharactersSelector 12 1.240 +#define kJIS2004CharactersSelector 11 1.241 +#define kLowerCasePetiteCapsSelector 2 1.242 +#define kLowerCaseSmallCapsSelector 1 1.243 +#define kLowerCaseType 37 1.244 +#define kMathematicalGreekOffSelector 11 1.245 +#define kMathematicalGreekOnSelector 10 1.246 +#define kNLCCharactersSelector 13 1.247 +#define kQuarterWidthTextSelector 4 1.248 +#define kScientificInferiorsSelector 4 1.249 +#define kStylisticAltEightOffSelector 17 1.250 +#define kStylisticAltEightOnSelector 16 1.251 +#define kStylisticAltEighteenOffSelector 37 1.252 +#define kStylisticAltEighteenOnSelector 36 1.253 +#define kStylisticAltElevenOffSelector 23 1.254 +#define kStylisticAltElevenOnSelector 22 1.255 +#define kStylisticAltFifteenOffSelector 31 1.256 +#define kStylisticAltFifteenOnSelector 30 1.257 +#define kStylisticAltFiveOffSelector 11 1.258 +#define kStylisticAltFiveOnSelector 10 1.259 +#define kStylisticAltFourOffSelector 9 1.260 +#define kStylisticAltFourOnSelector 8 1.261 +#define kStylisticAltFourteenOffSelector 29 1.262 +#define kStylisticAltFourteenOnSelector 28 1.263 +#define kStylisticAltNineOffSelector 19 1.264 +#define kStylisticAltNineOnSelector 18 1.265 +#define kStylisticAltNineteenOffSelector 39 1.266 +#define kStylisticAltNineteenOnSelector 38 1.267 +#define kStylisticAltOneOffSelector 3 1.268 +#define kStylisticAltOneOnSelector 2 1.269 +#define kStylisticAltSevenOffSelector 15 1.270 +#define kStylisticAltSevenOnSelector 14 1.271 +#define kStylisticAltSeventeenOffSelector 35 1.272 +#define kStylisticAltSeventeenOnSelector 34 1.273 +#define kStylisticAltSixOffSelector 13 1.274 +#define kStylisticAltSixOnSelector 12 1.275 +#define kStylisticAltSixteenOffSelector 33 1.276 +#define kStylisticAltSixteenOnSelector 32 1.277 +#define kStylisticAltTenOffSelector 21 1.278 +#define kStylisticAltTenOnSelector 20 1.279 +#define kStylisticAltThirteenOffSelector 27 1.280 +#define kStylisticAltThirteenOnSelector 26 1.281 +#define kStylisticAltThreeOffSelector 7 1.282 +#define kStylisticAltThreeOnSelector 6 1.283 +#define kStylisticAltTwelveOffSelector 25 1.284 +#define kStylisticAltTwelveOnSelector 24 1.285 +#define kStylisticAltTwentyOffSelector 41 1.286 +#define kStylisticAltTwentyOnSelector 40 1.287 +#define kStylisticAltTwoOffSelector 5 1.288 +#define kStylisticAltTwoOnSelector 4 1.289 +#define kStylisticAlternativesType 35 1.290 +#define kSwashAlternatesOffSelector 3 1.291 +#define kSwashAlternatesOnSelector 2 1.292 +#define kThirdWidthTextSelector 3 1.293 +#define kTraditionalNamesCharactersSelector 14 1.294 +#define kUpperCasePetiteCapsSelector 2 1.295 +#define kUpperCaseSmallCapsSelector 1 1.296 +#define kUpperCaseType 38 1.297 + 1.298 +/* Table data courtesy of Apple. */ 1.299 +struct feature_mapping_t { 1.300 + FourCharCode otFeatureTag; 1.301 + uint16_t aatFeatureType; 1.302 + uint16_t selectorToEnable; 1.303 + uint16_t selectorToDisable; 1.304 +} feature_mappings[] = { 1.305 + { 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector, kDefaultUpperCaseSelector }, 1.306 + { 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector, kDefaultUpperCaseSelector }, 1.307 + { 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector }, 1.308 + { 'case', kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOffSelector }, 1.309 + { 'clig', kLigaturesType, kContextualLigaturesOnSelector, kContextualLigaturesOffSelector }, 1.310 + { 'cpsp', kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOffSelector }, 1.311 + { 'cswh', kContextualAlternatesType, kContextualSwashAlternatesOnSelector, kContextualSwashAlternatesOffSelector }, 1.312 + { 'dlig', kLigaturesType, kRareLigaturesOnSelector, kRareLigaturesOffSelector }, 1.313 + { 'expt', kCharacterShapeType, kExpertCharactersSelector, 16 }, 1.314 + { 'frac', kFractionsType, kDiagonalFractionsSelector, kNoFractionsSelector }, 1.315 + { 'fwid', kTextSpacingType, kMonospacedTextSelector, 7 }, 1.316 + { 'halt', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, 1.317 + { 'hist', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, 1.318 + { 'hkna', kAlternateKanaType, kAlternateHorizKanaOnSelector, kAlternateHorizKanaOffSelector, }, 1.319 + { 'hlig', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, 1.320 + { 'hngl', kTransliterationType, kHanjaToHangulSelector, kNoTransliterationSelector }, 1.321 + { 'hojo', kCharacterShapeType, kHojoCharactersSelector, 16 }, 1.322 + { 'hwid', kTextSpacingType, kHalfWidthTextSelector, 7 }, 1.323 + { 'ital', kItalicCJKRomanType, kCJKItalicRomanOnSelector, kCJKItalicRomanOffSelector }, 1.324 + { 'jp04', kCharacterShapeType, kJIS2004CharactersSelector, 16 }, 1.325 + { 'jp78', kCharacterShapeType, kJIS1978CharactersSelector, 16 }, 1.326 + { 'jp83', kCharacterShapeType, kJIS1983CharactersSelector, 16 }, 1.327 + { 'jp90', kCharacterShapeType, kJIS1990CharactersSelector, 16 }, 1.328 + { 'liga', kLigaturesType, kCommonLigaturesOnSelector, kCommonLigaturesOffSelector }, 1.329 + { 'lnum', kNumberCaseType, kUpperCaseNumbersSelector, 2 }, 1.330 + { 'mgrk', kMathematicalExtrasType, kMathematicalGreekOnSelector, kMathematicalGreekOffSelector }, 1.331 + { 'nlck', kCharacterShapeType, kNLCCharactersSelector, 16 }, 1.332 + { 'onum', kNumberCaseType, kLowerCaseNumbersSelector, 2 }, 1.333 + { 'ordn', kVerticalPositionType, kOrdinalsSelector, kNormalPositionSelector }, 1.334 + { 'palt', kTextSpacingType, kAltProportionalTextSelector, 7 }, 1.335 + { 'pcap', kLowerCaseType, kLowerCasePetiteCapsSelector, kDefaultLowerCaseSelector }, 1.336 + { 'pkna', kTextSpacingType, kProportionalTextSelector, 7 }, 1.337 + { 'pnum', kNumberSpacingType, kProportionalNumbersSelector, 4 }, 1.338 + { 'pwid', kTextSpacingType, kProportionalTextSelector, 7 }, 1.339 + { 'qwid', kTextSpacingType, kQuarterWidthTextSelector, 7 }, 1.340 + { 'ruby', kRubyKanaType, kRubyKanaOnSelector, kRubyKanaOffSelector }, 1.341 + { 'sinf', kVerticalPositionType, kScientificInferiorsSelector, kNormalPositionSelector }, 1.342 + { 'smcp', kLowerCaseType, kLowerCaseSmallCapsSelector, kDefaultLowerCaseSelector }, 1.343 + { 'smpl', kCharacterShapeType, kSimplifiedCharactersSelector, 16 }, 1.344 + { 'ss01', kStylisticAlternativesType, kStylisticAltOneOnSelector, kStylisticAltOneOffSelector }, 1.345 + { 'ss02', kStylisticAlternativesType, kStylisticAltTwoOnSelector, kStylisticAltTwoOffSelector }, 1.346 + { 'ss03', kStylisticAlternativesType, kStylisticAltThreeOnSelector, kStylisticAltThreeOffSelector }, 1.347 + { 'ss04', kStylisticAlternativesType, kStylisticAltFourOnSelector, kStylisticAltFourOffSelector }, 1.348 + { 'ss05', kStylisticAlternativesType, kStylisticAltFiveOnSelector, kStylisticAltFiveOffSelector }, 1.349 + { 'ss06', kStylisticAlternativesType, kStylisticAltSixOnSelector, kStylisticAltSixOffSelector }, 1.350 + { 'ss07', kStylisticAlternativesType, kStylisticAltSevenOnSelector, kStylisticAltSevenOffSelector }, 1.351 + { 'ss08', kStylisticAlternativesType, kStylisticAltEightOnSelector, kStylisticAltEightOffSelector }, 1.352 + { 'ss09', kStylisticAlternativesType, kStylisticAltNineOnSelector, kStylisticAltNineOffSelector }, 1.353 + { 'ss10', kStylisticAlternativesType, kStylisticAltTenOnSelector, kStylisticAltTenOffSelector }, 1.354 + { 'ss11', kStylisticAlternativesType, kStylisticAltElevenOnSelector, kStylisticAltElevenOffSelector }, 1.355 + { 'ss12', kStylisticAlternativesType, kStylisticAltTwelveOnSelector, kStylisticAltTwelveOffSelector }, 1.356 + { 'ss13', kStylisticAlternativesType, kStylisticAltThirteenOnSelector, kStylisticAltThirteenOffSelector }, 1.357 + { 'ss14', kStylisticAlternativesType, kStylisticAltFourteenOnSelector, kStylisticAltFourteenOffSelector }, 1.358 + { 'ss15', kStylisticAlternativesType, kStylisticAltFifteenOnSelector, kStylisticAltFifteenOffSelector }, 1.359 + { 'ss16', kStylisticAlternativesType, kStylisticAltSixteenOnSelector, kStylisticAltSixteenOffSelector }, 1.360 + { 'ss17', kStylisticAlternativesType, kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOffSelector }, 1.361 + { 'ss18', kStylisticAlternativesType, kStylisticAltEighteenOnSelector, kStylisticAltEighteenOffSelector }, 1.362 + { 'ss19', kStylisticAlternativesType, kStylisticAltNineteenOnSelector, kStylisticAltNineteenOffSelector }, 1.363 + { 'ss20', kStylisticAlternativesType, kStylisticAltTwentyOnSelector, kStylisticAltTwentyOffSelector }, 1.364 + { 'subs', kVerticalPositionType, kInferiorsSelector, kNormalPositionSelector }, 1.365 + { 'sups', kVerticalPositionType, kSuperiorsSelector, kNormalPositionSelector }, 1.366 + { 'swsh', kContextualAlternatesType, kSwashAlternatesOnSelector, kSwashAlternatesOffSelector }, 1.367 + { 'titl', kStyleOptionsType, kTitlingCapsSelector, kNoStyleOptionsSelector }, 1.368 + { 'tnam', kCharacterShapeType, kTraditionalNamesCharactersSelector, 16 }, 1.369 + { 'tnum', kNumberSpacingType, kMonospacedNumbersSelector, 4 }, 1.370 + { 'trad', kCharacterShapeType, kTraditionalCharactersSelector, 16 }, 1.371 + { 'twid', kTextSpacingType, kThirdWidthTextSelector, 7 }, 1.372 + { 'unic', kLetterCaseType, 14, 15 }, 1.373 + { 'valt', kTextSpacingType, kAltProportionalTextSelector, 7 }, 1.374 + { 'vert', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, 1.375 + { 'vhal', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, 1.376 + { 'vkna', kAlternateKanaType, kAlternateVertKanaOnSelector, kAlternateVertKanaOffSelector }, 1.377 + { 'vpal', kTextSpacingType, kAltProportionalTextSelector, 7 }, 1.378 + { 'vrt2', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, 1.379 + { 'zero', kTypographicExtrasType, kSlashedZeroOnSelector, kSlashedZeroOffSelector }, 1.380 +}; 1.381 + 1.382 +static int 1.383 +_hb_feature_mapping_cmp (const void *key_, const void *entry_) 1.384 +{ 1.385 + unsigned int key = * (unsigned int *) key_; 1.386 + const feature_mapping_t * entry = (const feature_mapping_t *) entry_; 1.387 + return key < entry->otFeatureTag ? -1 : 1.388 + key > entry->otFeatureTag ? 1 : 1.389 + 0; 1.390 +} 1.391 + 1.392 +hb_bool_t 1.393 +_hb_coretext_shape (hb_shape_plan_t *shape_plan, 1.394 + hb_font_t *font, 1.395 + hb_buffer_t *buffer, 1.396 + const hb_feature_t *features, 1.397 + unsigned int num_features) 1.398 +{ 1.399 + hb_face_t *face = font->face; 1.400 + hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 1.401 + hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 1.402 + 1.403 + /* 1.404 + * Set up features. 1.405 + * (copied + modified from code from hb-uniscribe.cc) 1.406 + */ 1.407 + hb_auto_array_t<feature_record_t> feature_records; 1.408 + hb_auto_array_t<range_record_t> range_records; 1.409 + if (num_features) 1.410 + { 1.411 + /* Sort features by start/end events. */ 1.412 + hb_auto_array_t<feature_event_t> feature_events; 1.413 + for (unsigned int i = 0; i < num_features; i++) 1.414 + { 1.415 + const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag, 1.416 + feature_mappings, 1.417 + ARRAY_LENGTH (feature_mappings), 1.418 + sizeof (feature_mappings[0]), 1.419 + _hb_feature_mapping_cmp); 1.420 + if (!mapping) 1.421 + continue; 1.422 + 1.423 + active_feature_t feature; 1.424 + feature.rec.feature = mapping->aatFeatureType; 1.425 + feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable; 1.426 + feature.order = i; 1.427 + 1.428 + feature_event_t *event; 1.429 + 1.430 + event = feature_events.push (); 1.431 + if (unlikely (!event)) 1.432 + goto fail_features; 1.433 + event->index = features[i].start; 1.434 + event->start = true; 1.435 + event->feature = feature; 1.436 + 1.437 + event = feature_events.push (); 1.438 + if (unlikely (!event)) 1.439 + goto fail_features; 1.440 + event->index = features[i].end; 1.441 + event->start = false; 1.442 + event->feature = feature; 1.443 + } 1.444 + feature_events.sort (); 1.445 + /* Add a strategic final event. */ 1.446 + { 1.447 + active_feature_t feature; 1.448 + feature.rec.feature = HB_TAG_NONE; 1.449 + feature.rec.setting = 0; 1.450 + feature.order = num_features + 1; 1.451 + 1.452 + feature_event_t *event = feature_events.push (); 1.453 + if (unlikely (!event)) 1.454 + goto fail_features; 1.455 + event->index = 0; /* This value does magic. */ 1.456 + event->start = false; 1.457 + event->feature = feature; 1.458 + } 1.459 + 1.460 + /* Scan events and save features for each range. */ 1.461 + hb_auto_array_t<active_feature_t> active_features; 1.462 + unsigned int last_index = 0; 1.463 + for (unsigned int i = 0; i < feature_events.len; i++) 1.464 + { 1.465 + feature_event_t *event = &feature_events[i]; 1.466 + 1.467 + if (event->index != last_index) 1.468 + { 1.469 + /* Save a snapshot of active features and the range. */ 1.470 + range_record_t *range = range_records.push (); 1.471 + if (unlikely (!range)) 1.472 + goto fail_features; 1.473 + 1.474 + unsigned int offset = feature_records.len; 1.475 + 1.476 + if (active_features.len) 1.477 + { 1.478 + CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 1.479 + 1.480 + /* TODO sort and resolve conflicting features? */ 1.481 + /* active_features.sort (); */ 1.482 + for (unsigned int j = 0; j < active_features.len; j++) 1.483 + { 1.484 + CFStringRef keys[2] = { 1.485 + kCTFontFeatureTypeIdentifierKey, 1.486 + kCTFontFeatureSelectorIdentifierKey 1.487 + }; 1.488 + CFNumberRef values[2] = { 1.489 + CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature), 1.490 + CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting) 1.491 + }; 1.492 + CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault, 1.493 + (const void **) keys, 1.494 + (const void **) values, 1.495 + 2, 1.496 + &kCFTypeDictionaryKeyCallBacks, 1.497 + &kCFTypeDictionaryValueCallBacks); 1.498 + CFRelease (values[0]); 1.499 + CFRelease (values[1]); 1.500 + 1.501 + CFArrayAppendValue (features_array, dict); 1.502 + CFRelease (dict); 1.503 + 1.504 + } 1.505 + 1.506 + CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault, 1.507 + (const void **) &kCTFontFeatureSettingsAttribute, 1.508 + (const void **) &features_array, 1.509 + 1, 1.510 + &kCFTypeDictionaryKeyCallBacks, 1.511 + &kCFTypeDictionaryValueCallBacks); 1.512 + CFRelease (features_array); 1.513 + 1.514 + CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes); 1.515 + CFRelease (attributes); 1.516 + 1.517 + range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc); 1.518 + 1.519 + CFRelease (font_desc); 1.520 + } 1.521 + else 1.522 + { 1.523 + range->font = NULL; 1.524 + } 1.525 + 1.526 + range->index_first = last_index; 1.527 + range->index_last = event->index - 1; 1.528 + 1.529 + last_index = event->index; 1.530 + } 1.531 + 1.532 + if (event->start) { 1.533 + active_feature_t *feature = active_features.push (); 1.534 + if (unlikely (!feature)) 1.535 + goto fail_features; 1.536 + *feature = event->feature; 1.537 + } else { 1.538 + active_feature_t *feature = active_features.find (&event->feature); 1.539 + if (feature) 1.540 + active_features.remove (feature - active_features.array); 1.541 + } 1.542 + } 1.543 + 1.544 + if (!range_records.len) /* No active feature found. */ 1.545 + goto fail_features; 1.546 + } 1.547 + else 1.548 + { 1.549 + fail_features: 1.550 + num_features = 0; 1.551 + } 1.552 + 1.553 +#define FAIL(...) \ 1.554 + HB_STMT_START { \ 1.555 + DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \ 1.556 + return false; \ 1.557 + } HB_STMT_END; 1.558 + 1.559 + unsigned int scratch_size; 1.560 + hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); 1.561 + 1.562 +#define ALLOCATE_ARRAY(Type, name, len) \ 1.563 + Type *name = (Type *) scratch; \ 1.564 + { \ 1.565 + unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ 1.566 + assert (_consumed <= scratch_size); \ 1.567 + scratch += _consumed; \ 1.568 + scratch_size -= _consumed; \ 1.569 + } 1.570 + 1.571 +#define utf16_index() var1.u32 1.572 + 1.573 + ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2); 1.574 + 1.575 + unsigned int chars_len = 0; 1.576 + for (unsigned int i = 0; i < buffer->len; i++) { 1.577 + hb_codepoint_t c = buffer->info[i].codepoint; 1.578 + buffer->info[i].utf16_index() = chars_len; 1.579 + if (likely (c < 0x10000)) 1.580 + pchars[chars_len++] = c; 1.581 + else if (unlikely (c >= 0x110000)) 1.582 + pchars[chars_len++] = 0xFFFD; 1.583 + else { 1.584 + pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); 1.585 + pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); 1.586 + } 1.587 + } 1.588 + 1.589 +#undef utf16_index 1.590 + 1.591 + CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL, 1.592 + pchars, chars_len, 1.593 + kCFAllocatorNull); 1.594 + 1.595 + CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NULL, chars_len); 1.596 + CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref); 1.597 + CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), 1.598 + kCTFontAttributeName, font_data->ct_font); 1.599 + 1.600 + if (num_features) 1.601 + { 1.602 + ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len); 1.603 + 1.604 + /* Need log_clusters to assign features. */ 1.605 + chars_len = 0; 1.606 + for (unsigned int i = 0; i < buffer->len; i++) 1.607 + { 1.608 + hb_codepoint_t c = buffer->info[i].codepoint; 1.609 + unsigned int cluster = buffer->info[i].cluster; 1.610 + log_clusters[chars_len++] = cluster; 1.611 + if (c >= 0x10000 && c < 0x110000) 1.612 + log_clusters[chars_len++] = cluster; /* Surrogates. */ 1.613 + } 1.614 + 1.615 + unsigned int start = 0; 1.616 + range_record_t *last_range = &range_records[0]; 1.617 + for (unsigned int k = 0; k < chars_len; k++) 1.618 + { 1.619 + range_record_t *range = last_range; 1.620 + while (log_clusters[k] < range->index_first) 1.621 + range--; 1.622 + while (log_clusters[k] > range->index_last) 1.623 + range++; 1.624 + if (range != last_range) 1.625 + { 1.626 + if (last_range->font) 1.627 + CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start), 1.628 + kCTFontAttributeName, last_range->font); 1.629 + 1.630 + start = k; 1.631 + } 1.632 + 1.633 + last_range = range; 1.634 + } 1.635 + if (start != chars_len && last_range->font) 1.636 + CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start - 1), 1.637 + kCTFontAttributeName, last_range->font); 1.638 + 1.639 + for (unsigned int i = 0; i < range_records.len; i++) 1.640 + if (range_records[i].font) 1.641 + CFRelease (range_records[i].font); 1.642 + } 1.643 + 1.644 + CTLineRef line = CTLineCreateWithAttributedString (attr_string); 1.645 + CFRelease (attr_string); 1.646 + 1.647 + CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); 1.648 + unsigned int num_runs = CFArrayGetCount (glyph_runs); 1.649 + 1.650 + buffer->len = 0; 1.651 + 1.652 + const CFRange range_all = CFRangeMake (0, 0); 1.653 + 1.654 + for (unsigned int i = 0; i < num_runs; i++) 1.655 + { 1.656 + CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i); 1.657 + 1.658 + /* CoreText does automatic font fallback (AKA "cascading") for characters 1.659 + * not supported by the requested font, and provides no way to turn it off, 1.660 + * so we detect if the returned run uses a font other than the requested 1.661 + * one and fill in the buffer with .notdef glyphs instead of random glyph 1.662 + * indices from a different font. 1.663 + */ 1.664 + CFDictionaryRef attributes = CTRunGetAttributes (run); 1.665 + CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName)); 1.666 + CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0); 1.667 + if (!CFEqual (run_cg_font, face_data->cg_font)) 1.668 + { 1.669 + CFRelease (run_cg_font); 1.670 + 1.671 + CFRange range = CTRunGetStringRange (run); 1.672 + buffer->ensure (buffer->len + range.length); 1.673 + if (buffer->in_error) 1.674 + FAIL ("Buffer resize failed"); 1.675 + hb_glyph_info_t *info = buffer->info + buffer->len; 1.676 + 1.677 + CGGlyph notdef = 0; 1.678 + double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, ¬def, NULL, 1); 1.679 + 1.680 + for (CFIndex j = range.location; j < range.location + range.length; j++) 1.681 + { 1.682 + UniChar ch = CFStringGetCharacterAtIndex (string_ref, j); 1.683 + if (hb_in_range<UniChar> (ch, 0xDC00, 0xDFFF) && range.location < j) 1.684 + { 1.685 + ch = CFStringGetCharacterAtIndex (string_ref, j - 1); 1.686 + if (hb_in_range<UniChar> (ch, 0xD800, 0xDBFF)) 1.687 + /* This is the second of a surrogate pair. Don't need .notdef 1.688 + * for this one. */ 1.689 + continue; 1.690 + } 1.691 + 1.692 + info->codepoint = notdef; 1.693 + /* TODO We have to fixup clusters later. See vis_clusters in 1.694 + * hb-uniscribe.cc for example. */ 1.695 + info->cluster = j; 1.696 + 1.697 + info->mask = advance; 1.698 + info->var1.u32 = 0; 1.699 + info->var2.u32 = 0; 1.700 + 1.701 + info++; 1.702 + buffer->len++; 1.703 + } 1.704 + continue; 1.705 + } 1.706 + CFRelease (run_cg_font); 1.707 + 1.708 + unsigned int num_glyphs = CTRunGetGlyphCount (run); 1.709 + if (num_glyphs == 0) 1.710 + continue; 1.711 + 1.712 + buffer->ensure (buffer->len + num_glyphs); 1.713 + 1.714 + scratch = buffer->get_scratch_buffer (&scratch_size); 1.715 + 1.716 + /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always 1.717 + * succeed, and so copying data to our own buffer will be rare. */ 1.718 + 1.719 + const CGGlyph* glyphs = CTRunGetGlyphsPtr (run); 1.720 + if (!glyphs) { 1.721 + ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs); 1.722 + CTRunGetGlyphs (run, range_all, glyph_buf); 1.723 + glyphs = glyph_buf; 1.724 + } 1.725 + 1.726 + const CGPoint* positions = CTRunGetPositionsPtr (run); 1.727 + if (!positions) { 1.728 + ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs); 1.729 + CTRunGetPositions (run, range_all, position_buf); 1.730 + positions = position_buf; 1.731 + } 1.732 + 1.733 + const CFIndex* string_indices = CTRunGetStringIndicesPtr (run); 1.734 + if (!string_indices) { 1.735 + ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs); 1.736 + CTRunGetStringIndices (run, range_all, index_buf); 1.737 + string_indices = index_buf; 1.738 + } 1.739 + 1.740 +#undef ALLOCATE_ARRAY 1.741 + 1.742 + double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL); 1.743 + 1.744 + for (unsigned int j = 0; j < num_glyphs; j++) { 1.745 + double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x; 1.746 + 1.747 + hb_glyph_info_t *info = &buffer->info[buffer->len]; 1.748 + 1.749 + info->codepoint = glyphs[j]; 1.750 + info->cluster = string_indices[j]; 1.751 + 1.752 + /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */ 1.753 + info->mask = advance; 1.754 + info->var1.u32 = 0; 1.755 + info->var2.u32 = positions[j].y; 1.756 + 1.757 + buffer->len++; 1.758 + } 1.759 + } 1.760 + 1.761 + buffer->clear_positions (); 1.762 + 1.763 + unsigned int count = buffer->len; 1.764 + for (unsigned int i = 0; i < count; ++i) { 1.765 + hb_glyph_info_t *info = &buffer->info[i]; 1.766 + hb_glyph_position_t *pos = &buffer->pos[i]; 1.767 + 1.768 + /* TODO vertical */ 1.769 + pos->x_advance = info->mask; 1.770 + pos->x_offset = info->var1.u32; 1.771 + pos->y_offset = info->var2.u32; 1.772 + } 1.773 + 1.774 + /* Fix up clusters so that we never return out-of-order indices; 1.775 + * if core text has reordered glyphs, we'll merge them to the 1.776 + * beginning of the reordered cluster. 1.777 + * 1.778 + * This does *not* mean we'll form the same clusters as Uniscribe 1.779 + * or the native OT backend, only that the cluster indices will be 1.780 + * monotonic in the output buffer. */ 1.781 + if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { 1.782 + unsigned int prev_cluster = 0; 1.783 + for (unsigned int i = 0; i < count; i++) { 1.784 + unsigned int curr_cluster = buffer->info[i].cluster; 1.785 + if (curr_cluster < prev_cluster) { 1.786 + for (unsigned int j = i; j > 0; j--) { 1.787 + if (buffer->info[j - 1].cluster > curr_cluster) 1.788 + buffer->info[j - 1].cluster = curr_cluster; 1.789 + else 1.790 + break; 1.791 + } 1.792 + } 1.793 + prev_cluster = curr_cluster; 1.794 + } 1.795 + } else { 1.796 + unsigned int prev_cluster = (unsigned int)-1; 1.797 + for (unsigned int i = 0; i < count; i++) { 1.798 + unsigned int curr_cluster = buffer->info[i].cluster; 1.799 + if (curr_cluster > prev_cluster) { 1.800 + for (unsigned int j = i; j > 0; j--) { 1.801 + if (buffer->info[j - 1].cluster < curr_cluster) 1.802 + buffer->info[j - 1].cluster = curr_cluster; 1.803 + else 1.804 + break; 1.805 + } 1.806 + } 1.807 + prev_cluster = curr_cluster; 1.808 + } 1.809 + } 1.810 + 1.811 + CFRelease (string_ref); 1.812 + CFRelease (line); 1.813 + 1.814 + return true; 1.815 +}