2 * Copyright © 2012,2013 Mozilla Foundation.
3 * Copyright © 2012,2013 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 * Mozilla Author(s): Jonathan Kew
26 * Google Author(s): Behdad Esfahbod
29 #define HB_SHAPER coretext
30 #include "hb-shaper-impl-private.hh"
32 #include "hb-coretext.h"
35 #ifndef HB_DEBUG_CORETEXT
36 #define HB_DEBUG_CORETEXT (HB_DEBUG+0)
40 HB_SHAPER_DATA_ENSURE_DECLARE(coretext
, face
)
41 HB_SHAPER_DATA_ENSURE_DECLARE(coretext
, font
)
48 struct hb_coretext_shaper_face_data_t
{
53 release_data (void *info
, const void *data
, size_t size
)
55 assert (hb_blob_get_length ((hb_blob_t
*) info
) == size
&&
56 hb_blob_get_data ((hb_blob_t
*) info
, NULL
) == data
);
58 hb_blob_destroy ((hb_blob_t
*) info
);
61 hb_coretext_shaper_face_data_t
*
62 _hb_coretext_shaper_face_data_create (hb_face_t
*face
)
64 hb_coretext_shaper_face_data_t
*data
= (hb_coretext_shaper_face_data_t
*) calloc (1, sizeof (hb_coretext_shaper_face_data_t
));
68 hb_blob_t
*blob
= hb_face_reference_blob (face
);
69 unsigned int blob_length
;
70 const char *blob_data
= hb_blob_get_data (blob
, &blob_length
);
71 if (unlikely (!blob_length
))
72 DEBUG_MSG (CORETEXT
, face
, "Face has empty blob");
74 CGDataProviderRef provider
= CGDataProviderCreateWithData (blob
, blob_data
, blob_length
, &release_data
);
75 data
->cg_font
= CGFontCreateWithDataProvider (provider
);
76 CGDataProviderRelease (provider
);
78 if (unlikely (!data
->cg_font
)) {
79 DEBUG_MSG (CORETEXT
, face
, "Face CGFontCreateWithDataProvider() failed");
88 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t
*data
)
90 CFRelease (data
->cg_font
);
95 hb_coretext_face_get_cg_font (hb_face_t
*face
)
97 if (unlikely (!hb_coretext_shaper_face_data_ensure (face
))) return NULL
;
98 hb_coretext_shaper_face_data_t
*face_data
= HB_SHAPER_DATA_GET (face
);
99 return face_data
->cg_font
;
107 struct hb_coretext_shaper_font_data_t
{
111 hb_coretext_shaper_font_data_t
*
112 _hb_coretext_shaper_font_data_create (hb_font_t
*font
)
114 if (unlikely (!hb_coretext_shaper_face_data_ensure (font
->face
))) return NULL
;
116 hb_coretext_shaper_font_data_t
*data
= (hb_coretext_shaper_font_data_t
*) calloc (1, sizeof (hb_coretext_shaper_font_data_t
));
117 if (unlikely (!data
))
120 hb_face_t
*face
= font
->face
;
121 hb_coretext_shaper_face_data_t
*face_data
= HB_SHAPER_DATA_GET (face
);
123 data
->ct_font
= CTFontCreateWithGraphicsFont (face_data
->cg_font
, font
->y_scale
, NULL
, NULL
);
124 if (unlikely (!data
->ct_font
)) {
125 DEBUG_MSG (CORETEXT
, font
, "Font CTFontCreateWithGraphicsFont() failed");
134 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t
*data
)
136 CFRelease (data
->ct_font
);
142 * shaper shape_plan data
145 struct hb_coretext_shaper_shape_plan_data_t
{};
147 hb_coretext_shaper_shape_plan_data_t
*
148 _hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t
*shape_plan HB_UNUSED
,
149 const hb_feature_t
*user_features HB_UNUSED
,
150 unsigned int num_user_features HB_UNUSED
)
152 return (hb_coretext_shaper_shape_plan_data_t
*) HB_SHAPER_DATA_SUCCEEDED
;
156 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t
*data HB_UNUSED
)
161 hb_coretext_font_get_ct_font (hb_font_t
*font
)
163 if (unlikely (!hb_coretext_shaper_font_data_ensure (font
))) return NULL
;
164 hb_coretext_shaper_font_data_t
*font_data
= HB_SHAPER_DATA_GET (font
);
165 return font_data
->ct_font
;
173 struct feature_record_t
{
174 unsigned int feature
;
175 unsigned int setting
;
178 struct active_feature_t
{
179 feature_record_t rec
;
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
.feature
? 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
.setting
? 1 :
188 bool operator== (const active_feature_t
*f
) {
189 return cmp (this, f
) == 0;
193 struct feature_event_t
{
196 active_feature_t feature
;
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
);
205 struct range_record_t
{
207 unsigned int index_first
; /* == start */
208 unsigned int index_last
; /* == end - 1 */
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
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
},
380 _hb_feature_mapping_cmp (const void *key_
, const void *entry_
)
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 :
390 _hb_coretext_shape (hb_shape_plan_t
*shape_plan
,
393 const hb_feature_t
*features
,
394 unsigned int num_features
)
396 hb_face_t
*face
= font
->face
;
397 hb_coretext_shaper_font_data_t
*font_data
= HB_SHAPER_DATA_GET (font
);
401 * (copied + modified from code from hb-uniscribe.cc)
403 hb_auto_array_t
<feature_record_t
> feature_records
;
404 hb_auto_array_t
<range_record_t
> range_records
;
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
++)
411 const feature_mapping_t
* mapping
= (const feature_mapping_t
*) bsearch (&features
[i
].tag
,
413 ARRAY_LENGTH (feature_mappings
),
414 sizeof (feature_mappings
[0]),
415 _hb_feature_mapping_cmp
);
419 active_feature_t feature
;
420 feature
.rec
.feature
= mapping
->aatFeatureType
;
421 feature
.rec
.setting
= features
[i
].value
? mapping
->selectorToEnable
: mapping
->selectorToDisable
;
424 feature_event_t
*event
;
426 event
= feature_events
.push ();
427 if (unlikely (!event
))
429 event
->index
= features
[i
].start
;
431 event
->feature
= feature
;
433 event
= feature_events
.push ();
434 if (unlikely (!event
))
436 event
->index
= features
[i
].end
;
437 event
->start
= false;
438 event
->feature
= feature
;
440 feature_events
.sort ();
441 /* Add a strategic final event. */
443 active_feature_t feature
;
444 feature
.rec
.feature
= HB_TAG_NONE
;
445 feature
.rec
.setting
= 0;
446 feature
.order
= num_features
+ 1;
448 feature_event_t
*event
= feature_events
.push ();
449 if (unlikely (!event
))
451 event
->index
= 0; /* This value does magic. */
452 event
->start
= false;
453 event
->feature
= feature
;
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
++)
461 feature_event_t
*event
= &feature_events
[i
];
463 if (event
->index
!= last_index
)
465 /* Save a snapshot of active features and the range. */
466 range_record_t
*range
= range_records
.push ();
467 if (unlikely (!range
))
470 unsigned int offset
= feature_records
.len
;
472 if (active_features
.len
)
474 CFMutableArrayRef features_array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
476 /* TODO sort and resolve conflicting features? */
477 /* active_features.sort (); */
478 for (unsigned int j
= 0; j
< active_features
.len
; j
++)
480 CFStringRef keys
[2] = {
481 kCTFontFeatureTypeIdentifierKey
,
482 kCTFontFeatureSelectorIdentifierKey
484 CFNumberRef values
[2] = {
485 CFNumberCreate (kCFAllocatorDefault
, kCFNumberIntType
, &active_features
[j
].rec
.feature
),
486 CFNumberCreate (kCFAllocatorDefault
, kCFNumberIntType
, &active_features
[j
].rec
.setting
)
488 CFDictionaryRef dict
= CFDictionaryCreate (kCFAllocatorDefault
,
489 (const void **) keys
,
490 (const void **) values
,
492 &kCFTypeDictionaryKeyCallBacks
,
493 &kCFTypeDictionaryValueCallBacks
);
494 CFRelease (values
[0]);
495 CFRelease (values
[1]);
497 CFArrayAppendValue (features_array
, dict
);
502 CFDictionaryRef attributes
= CFDictionaryCreate (kCFAllocatorDefault
,
503 (const void **) &kCTFontFeatureSettingsAttribute
,
504 (const void **) &features_array
,
506 &kCFTypeDictionaryKeyCallBacks
,
507 &kCFTypeDictionaryValueCallBacks
);
508 CFRelease (features_array
);
510 CTFontDescriptorRef font_desc
= CTFontDescriptorCreateWithAttributes (attributes
);
511 CFRelease (attributes
);
513 range
->font
= CTFontCreateCopyWithAttributes (font_data
->ct_font
, 0.0, NULL
, font_desc
);
515 CFRelease (font_desc
);
522 range
->index_first
= last_index
;
523 range
->index_last
= event
->index
- 1;
525 last_index
= event
->index
;
529 active_feature_t
*feature
= active_features
.push ();
530 if (unlikely (!feature
))
532 *feature
= event
->feature
;
534 active_feature_t
*feature
= active_features
.find (&event
->feature
);
536 active_features
.remove (feature
- active_features
.array
);
540 if (!range_records
.len
) /* No active feature found. */
551 DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
555 unsigned int scratch_size
;
556 hb_buffer_t::scratch_buffer_t
*scratch
= buffer
->get_scratch_buffer (&scratch_size
);
558 #define ALLOCATE_ARRAY(Type, name, len) \
559 Type *name = (Type *) scratch; \
561 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
562 assert (_consumed <= scratch_size); \
563 scratch += _consumed; \
564 scratch_size -= _consumed; \
567 #define utf16_index() var1.u32
569 ALLOCATE_ARRAY (UniChar
, pchars
, buffer
->len
* 2);
571 unsigned int chars_len
= 0;
572 for (unsigned int i
= 0; i
< buffer
->len
; i
++) {
573 hb_codepoint_t c
= buffer
->info
[i
].codepoint
;
574 buffer
->info
[i
].utf16_index() = chars_len
;
575 if (likely (c
< 0x10000))
576 pchars
[chars_len
++] = c
;
577 else if (unlikely (c
>= 0x110000))
578 pchars
[chars_len
++] = 0xFFFD;
580 pchars
[chars_len
++] = 0xD800 + ((c
- 0x10000) >> 10);
581 pchars
[chars_len
++] = 0xDC00 + ((c
- 0x10000) & ((1 << 10) - 1));
587 CFStringRef string_ref
= CFStringCreateWithCharactersNoCopy (NULL
,
591 CFMutableAttributedStringRef attr_string
= CFAttributedStringCreateMutable (NULL
, chars_len
);
592 CFAttributedStringReplaceString (attr_string
, CFRangeMake (0, 0), string_ref
);
593 CFRelease (string_ref
);
594 CFAttributedStringSetAttribute (attr_string
, CFRangeMake (0, chars_len
),
595 kCTFontAttributeName
, font_data
->ct_font
);
599 ALLOCATE_ARRAY (unsigned int, log_clusters
, chars_len
);
601 /* Need log_clusters to assign features. */
603 for (unsigned int i
= 0; i
< buffer
->len
; i
++)
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. */
612 unsigned int start
= 0;
613 range_record_t
*last_range
= &range_records
[0];
614 for (unsigned int k
= 0; k
< chars_len
; k
++)
616 range_record_t
*range
= last_range
;
617 while (log_clusters
[k
] < range
->index_first
)
619 while (log_clusters
[k
] > range
->index_last
)
621 if (range
!= last_range
)
623 if (last_range
->font
)
624 CFAttributedStringSetAttribute (attr_string
, CFRangeMake (start
, k
- start
),
625 kCTFontAttributeName
, last_range
->font
);
632 if (start
!= chars_len
&& last_range
->font
)
633 CFAttributedStringSetAttribute (attr_string
, CFRangeMake (start
, chars_len
- start
- 1),
634 kCTFontAttributeName
, last_range
->font
);
636 for (unsigned int i
= 0; i
< range_records
.len
; i
++)
637 if (range_records
[i
].font
)
638 CFRelease (range_records
[i
].font
);
641 CTLineRef line
= CTLineCreateWithAttributedString (attr_string
);
642 CFRelease (attr_string
);
644 CFArrayRef glyph_runs
= CTLineGetGlyphRuns (line
);
645 unsigned int num_runs
= CFArrayGetCount (glyph_runs
);
649 const CFRange range_all
= CFRangeMake (0, 0);
651 for (unsigned int i
= 0; i
< num_runs
; i
++) {
652 CTRunRef run
= (CTRunRef
) CFArrayGetValueAtIndex (glyph_runs
, i
);
654 unsigned int num_glyphs
= CTRunGetGlyphCount (run
);
658 buffer
->ensure (buffer
->len
+ num_glyphs
);
660 scratch
= buffer
->get_scratch_buffer (&scratch_size
);
662 /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always
663 * succeed, and so copying data to our own buffer will be rare. */
665 const CGGlyph
* glyphs
= CTRunGetGlyphsPtr (run
);
667 ALLOCATE_ARRAY (CGGlyph
, glyph_buf
, num_glyphs
);
668 CTRunGetGlyphs (run
, range_all
, glyph_buf
);
672 const CGPoint
* positions
= CTRunGetPositionsPtr (run
);
674 ALLOCATE_ARRAY (CGPoint
, position_buf
, num_glyphs
);
675 CTRunGetPositions (run
, range_all
, position_buf
);
676 positions
= position_buf
;
679 const CFIndex
* string_indices
= CTRunGetStringIndicesPtr (run
);
680 if (!string_indices
) {
681 ALLOCATE_ARRAY (CFIndex
, index_buf
, num_glyphs
);
682 CTRunGetStringIndices (run
, range_all
, index_buf
);
683 string_indices
= index_buf
;
686 #undef ALLOCATE_ARRAY
688 double run_width
= CTRunGetTypographicBounds (run
, range_all
, NULL
, NULL
, NULL
);
690 for (unsigned int j
= 0; j
< num_glyphs
; j
++) {
691 double advance
= (j
+ 1 < num_glyphs
? positions
[j
+ 1].x
: positions
[0].x
+ run_width
) - positions
[j
].x
;
693 hb_glyph_info_t
*info
= &buffer
->info
[buffer
->len
];
695 info
->codepoint
= glyphs
[j
];
696 info
->cluster
= string_indices
[j
];
698 /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
699 info
->mask
= advance
;
701 info
->var2
.u32
= positions
[j
].y
;
707 buffer
->clear_positions ();
709 unsigned int count
= buffer
->len
;
710 for (unsigned int i
= 0; i
< count
; ++i
) {
711 hb_glyph_info_t
*info
= &buffer
->info
[i
];
712 hb_glyph_position_t
*pos
= &buffer
->pos
[i
];
715 pos
->x_advance
= info
->mask
;
716 pos
->x_offset
= info
->var1
.u32
;
717 pos
->y_offset
= info
->var2
.u32
;
720 /* Fix up clusters so that we never return out-of-order indices;
721 * if core text has reordered glyphs, we'll merge them to the
722 * beginning of the reordered cluster.
724 * This does *not* mean we'll form the same clusters as Uniscribe
725 * or the native OT backend, only that the cluster indices will be
726 * monotonic in the output buffer. */
727 if (HB_DIRECTION_IS_FORWARD (buffer
->props
.direction
)) {
728 unsigned int prev_cluster
= 0;
729 for (unsigned int i
= 0; i
< count
; i
++) {
730 unsigned int curr_cluster
= buffer
->info
[i
].cluster
;
731 if (curr_cluster
< prev_cluster
) {
732 for (unsigned int j
= i
; j
> 0; j
--) {
733 if (buffer
->info
[j
- 1].cluster
> curr_cluster
)
734 buffer
->info
[j
- 1].cluster
= curr_cluster
;
739 prev_cluster
= curr_cluster
;
742 unsigned int prev_cluster
= (unsigned int)-1;
743 for (unsigned int i
= 0; i
< count
; i
++) {
744 unsigned int curr_cluster
= buffer
->info
[i
].cluster
;
745 if (curr_cluster
> prev_cluster
) {
746 for (unsigned int j
= i
; j
> 0; j
--) {
747 if (buffer
->info
[j
- 1].cluster
< curr_cluster
)
748 buffer
->info
[j
- 1].cluster
= curr_cluster
;
753 prev_cluster
= curr_cluster
;