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