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 
39 typedef bool (*qt_get_font_table_func_t) (void *user_data, unsigned int tag, unsigned char *buffer, unsigned int *length);
40 
41 struct FontEngineFaceData {
42   void *user_data;
43   qt_get_font_table_func_t get_font_table;
44 };
45 
46 struct CoreTextFontEngineData {
47   CTFontRef ctFont;
48   CGFontRef cgFont;
49 };
50 
51 
52 /* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
53 #define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
54 
55 static void
release_table_data(void * user_data)56 release_table_data (void *user_data)
57 {
58   CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
59   CFRelease(cf_data);
60 }
61 
62 static hb_blob_t *
reference_table(hb_face_t * face HB_UNUSED,hb_tag_t tag,void * user_data)63 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
64 {
65   CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
66   CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
67   if (unlikely (!cf_data))
68     return nullptr;
69 
70   const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
71   const size_t length = CFDataGetLength (cf_data);
72   if (!data || !length)
73     return nullptr;
74 
75   return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
76 			 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
77 			 release_table_data);
78 }
79 
80 static void
_hb_cg_font_release(void * data)81 _hb_cg_font_release (void *data)
82 {
83   CGFontRelease ((CGFontRef) data);
84 }
85 
86 
HB_SHAPER_DATA_ENSURE_DEFINE(coretext,face)87 HB_SHAPER_DATA_ENSURE_DEFINE(coretext, face)
88 HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(coretext, font,
89 	fabs (CTFontGetSize ((CTFontRef) data) - font->ptem) <= .5
90 )
91 
92 static CTFontDescriptorRef
93 get_last_resort_font_desc (void)
94 {
95   // TODO Handle allocation failures?
96   CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
97   CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
98 					   (const void **) &last_resort,
99 					   1,
100 					   &kCFTypeArrayCallBacks);
101   CFRelease (last_resort);
102   CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
103 						   (const void **) &kCTFontCascadeListAttribute,
104 						   (const void **) &cascade_list,
105 						   1,
106 						   &kCFTypeDictionaryKeyCallBacks,
107 						   &kCFTypeDictionaryValueCallBacks);
108   CFRelease (cascade_list);
109 
110   CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
111   CFRelease (attributes);
112   return font_desc;
113 }
114 
115 static void
release_data(void * info,const void * data,size_t size)116 release_data (void *info, const void *data, size_t size)
117 {
118   assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
119           hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
120 
121   hb_blob_destroy ((hb_blob_t *) info);
122 }
123 
124 static CGFontRef
create_cg_font(hb_face_t * face)125 create_cg_font (hb_face_t *face)
126 {
127   CGFontRef cg_font = nullptr;
128   if (face->destroy == _hb_cg_font_release)
129   {
130     cg_font = CGFontRetain ((CGFontRef) face->user_data);
131   }
132   else
133   {
134 #if 0
135     hb_blob_t *blob = hb_face_reference_blob (face);
136     unsigned int blob_length;
137     const char *blob_data = hb_blob_get_data (blob, &blob_length);
138     if (unlikely (!blob_length))
139       DEBUG_MSG (CORETEXT, face, "Face has empty blob");
140 
141     CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
142     if (likely (provider))
143     {
144       cg_font = CGFontCreateWithDataProvider (provider);
145       if (unlikely (!cg_font))
146 	DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
147       CGDataProviderRelease (provider);
148     }
149 #else
150     FontEngineFaceData *fontEngineFaceData = (FontEngineFaceData *) face->user_data;
151     CoreTextFontEngineData *coreTextFontEngineData = (CoreTextFontEngineData *) fontEngineFaceData->user_data;
152     cg_font = CGFontRetain (coreTextFontEngineData->cgFont);
153 #endif
154   }
155   return cg_font;
156 }
157 
158 static CTFontRef
create_ct_font(CGFontRef cg_font,CGFloat font_size)159 create_ct_font (CGFontRef cg_font, CGFloat font_size)
160 {
161   CTFontRef ct_font = nullptr;
162 
163   /* CoreText does not enable trak table usage / tracking when creating a CTFont
164    * using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
165    * to be through the CTFontCreateUIFontForLanguage call. */
166   CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
167   if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
168       CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
169   {
170     CTFontUIFontType font_type = kCTFontUIFontSystem;
171     if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
172       font_type = kCTFontUIFontEmphasizedSystem;
173 
174     ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
175     CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
176     if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
177     {
178       CFRelease(ct_font);
179       ct_font = nullptr;
180     }
181     CFRelease (ct_result_name);
182   }
183   CFRelease (cg_postscript_name);
184 
185   if (!ct_font)
186     ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
187 
188   if (unlikely (!ct_font)) {
189     DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
190     return nullptr;
191   }
192 
193   /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
194    * bug indicate that the cascade list reconfiguration occasionally causes
195    * crashes in CoreText on OS X 10.9, thus let's skip this step on older
196    * operating system versions. Except for the emoji font, where _not_
197    * reconfiguring the cascade list causes CoreText crashes. For details, see
198    * crbug.com/549610 */
199   // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
200   if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
201     CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
202     bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
203     CFRelease (fontName);
204     if (!isEmojiFont)
205       return ct_font;
206   }
207 
208   CFURLRef original_url = (CFURLRef)CTFontCopyAttribute(ct_font, kCTFontURLAttribute);
209 
210   /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
211    * font fallback which we don't need anyway. */
212   {
213     CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
214     CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
215     CFRelease (last_resort_font_desc);
216     if (new_ct_font)
217     {
218       /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
219        * when reconfiguring the cascade list and may switch to a different font
220        * when there are fonts that go by the same name, since the descriptor is
221        * just name and size.
222        *
223        * Avoid reconfiguring the cascade lists if the new font is outside the
224        * system locations that we cannot access from the sandboxed renderer
225        * process in Blink. This can be detected by the new file URL location
226        * that the newly found font points to. */
227       CFURLRef new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
228       // Keep reconfigured font if URL cannot be retrieved (seems to be the case
229       // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
230       if (!original_url || !new_url || CFEqual (original_url, new_url)) {
231         CFRelease (ct_font);
232         ct_font = new_ct_font;
233       } else {
234         CFRelease (new_ct_font);
235         DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
236       }
237       if (new_url)
238         CFRelease (new_url);
239     }
240     else
241       DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
242   }
243 
244   if (original_url)
245     CFRelease (original_url);
246   return ct_font;
247 }
248 
249 hb_coretext_shaper_face_data_t *
_hb_coretext_shaper_face_data_create(hb_face_t * face)250 _hb_coretext_shaper_face_data_create (hb_face_t *face)
251 {
252   CGFontRef cg_font = create_cg_font (face);
253 
254   if (unlikely (!cg_font))
255   {
256     DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
257     return nullptr;
258   }
259 
260   return (hb_coretext_shaper_face_data_t *) cg_font;
261 }
262 
263 void
_hb_coretext_shaper_face_data_destroy(hb_coretext_shaper_face_data_t * data)264 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
265 {
266   CFRelease ((CGFontRef) data);
267 }
268 
269 hb_face_t *
hb_coretext_face_create(CGFontRef cg_font)270 hb_coretext_face_create (CGFontRef cg_font)
271 {
272   return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
273 }
274 
275 /*
276  * Since: 0.9.10
277  */
278 CGFontRef
hb_coretext_face_get_cg_font(hb_face_t * face)279 hb_coretext_face_get_cg_font (hb_face_t *face)
280 {
281   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
282   return (CGFontRef) HB_SHAPER_DATA_GET (face);
283 }
284 
285 
286 hb_coretext_shaper_font_data_t *
_hb_coretext_shaper_font_data_create(hb_font_t * font)287 _hb_coretext_shaper_font_data_create (hb_font_t *font)
288 {
289   hb_face_t *face = font->face;
290   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
291   CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
292 
293   CGFloat font_size = font->ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : font->ptem;
294   CTFontRef ct_font = create_ct_font (cg_font, font_size);
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
_hb_coretext_shaper_font_data_destroy(hb_coretext_shaper_font_data_t * data)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 *
hb_coretext_font_create(CTFontRef ct_font)315 hb_coretext_font_create (CTFontRef ct_font)
316 {
317   CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, 0);
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, 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
hb_coretext_font_get_ct_font(hb_font_t * font)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 *
_hb_coretext_shaper_shape_plan_data_create(hb_shape_plan_t * shape_plan HB_UNUSED,const hb_feature_t * user_features HB_UNUSED,unsigned int num_user_features HB_UNUSED,const int * coords HB_UNUSED,unsigned int num_coords HB_UNUSED)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
_hb_coretext_shaper_shape_plan_data_destroy(hb_coretext_shaper_shape_plan_data_t * data HB_UNUSED)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 
cmpactive_feature_t378   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   }
operator ==active_feature_t386   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 
cmpfeature_event_t396   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
_hb_feature_mapping_cmp(const void * key_,const void * entry_)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
_hb_coretext_shape(hb_shape_plan_t * shape_plan,hb_font_t * font,hb_buffer_t * buffer,const hb_feature_t * features,unsigned int num_features)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 	  FAIL ("CFStringCreateWithCStringNoCopy failed");
884 	CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
885 					kCTLanguageAttributeName, lang);
886 	CFRelease (lang);
887       }
888       CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
889 				      kCTFontAttributeName, ct_font);
890 
891       if (num_features && range_records.len)
892       {
893 	unsigned int start = 0;
894 	range_record_t *last_range = &range_records[0];
895 	for (unsigned int k = 0; k < chars_len; k++)
896 	{
897 	  range_record_t *range = last_range;
898 	  while (log_clusters[k] < range->index_first)
899 	    range--;
900 	  while (log_clusters[k] > range->index_last)
901 	    range++;
902 	  if (range != last_range)
903 	  {
904 	    if (last_range->font)
905 	      CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
906 					      kCTFontAttributeName, last_range->font);
907 
908 	    start = k;
909 	  }
910 
911 	  last_range = range;
912 	}
913 	if (start != chars_len && last_range->font)
914 	  CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start),
915 					  kCTFontAttributeName, last_range->font);
916       }
917       /* Enable/disable kern if requested.
918        *
919        * Note: once kern is disabled, reenabling it doesn't currently seem to work in CoreText.
920        */
921       if (num_features)
922       {
923 	unsigned int zeroint = 0;
924 	CFNumberRef zero = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &zeroint);
925 	for (unsigned int i = 0; i < num_features; i++)
926 	{
927 	  const hb_feature_t &feature = features[i];
928 	  if (feature.tag == HB_TAG('k','e','r','n') &&
929 	      feature.start < chars_len && feature.start < feature.end)
930 	  {
931 	    CFRange feature_range = CFRangeMake (feature.start,
932 	                                         MIN (feature.end, chars_len) - feature.start);
933 	    if (feature.value)
934 	      CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
935 	    else
936 	      CFAttributedStringSetAttribute (attr_string, feature_range, kCTKernAttributeName, zero);
937 	  }
938 	}
939 	CFRelease (zero);
940       }
941 
942       int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
943       CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
944       CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
945 						    (const void **) &kCTTypesetterOptionForcedEmbeddingLevel,
946 						    (const void **) &level_number,
947 						    1,
948 						    &kCFTypeDictionaryKeyCallBacks,
949 						    &kCFTypeDictionaryValueCallBacks);
950       CFRelease (level_number);
951       if (unlikely (!options))
952         FAIL ("CFDictionaryCreate failed");
953 
954       CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options);
955       CFRelease (options);
956       CFRelease (attr_string);
957       if (unlikely (!typesetter))
958 	FAIL ("CTTypesetterCreateWithAttributedStringAndOptions failed");
959 
960       line = CTTypesetterCreateLine (typesetter, CFRangeMake(0, 0));
961       CFRelease (typesetter);
962       if (unlikely (!line))
963 	FAIL ("CTTypesetterCreateLine failed");
964     }
965 
966     CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
967     unsigned int num_runs = CFArrayGetCount (glyph_runs);
968     DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
969 
970     buffer->len = 0;
971     uint32_t status_and = ~0, status_or = 0;
972     double advances_so_far = 0;
973     /* For right-to-left runs, CoreText returns the glyphs positioned such that
974      * any trailing whitespace is to the left of (0,0).  Adjust coordinate system
975      * to fix for that.  Test with any RTL string with trailing spaces.
976      * https://code.google.com/p/chromium/issues/detail?id=469028
977      */
978     if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
979     {
980       advances_so_far -= CTLineGetTrailingWhitespaceWidth (line);
981       if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
982 	  advances_so_far = -advances_so_far;
983     }
984 
985     const CFRange range_all = CFRangeMake (0, 0);
986 
987     for (unsigned int i = 0; i < num_runs; i++)
988     {
989       CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
990       CTRunStatus run_status = CTRunGetStatus (run);
991       status_or  |= run_status;
992       status_and &= run_status;
993       DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
994       double run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
995       if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
996 	  run_advance = -run_advance;
997       DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
998 
999       /* CoreText does automatic font fallback (AKA "cascading") for  characters
1000        * not supported by the requested font, and provides no way to turn it off,
1001        * so we must detect if the returned run uses a font other than the requested
1002        * one and fill in the buffer with .notdef glyphs instead of random glyph
1003        * indices from a different font.
1004        */
1005       CFDictionaryRef attributes = CTRunGetAttributes (run);
1006       CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
1007       if (!CFEqual (run_ct_font, ct_font))
1008       {
1009 	/* The run doesn't use our main font instance.  We have to figure out
1010 	 * whether font fallback happened, or this is just CoreText giving us
1011 	 * another CTFont using the same underlying CGFont.  CoreText seems
1012 	 * to do that in a variety of situations, one of which being vertical
1013 	 * text, but also perhaps for caching reasons.
1014 	 *
1015 	 * First, see if it uses any of our subfonts created to set font features...
1016 	 *
1017 	 * Next, compare the CGFont to the one we used to create our fonts.
1018 	 * Even this doesn't work all the time.
1019 	 *
1020 	 * Finally, we compare PS names, which I don't think are unique...
1021 	 *
1022 	 * Looks like if we really want to be sure here we have to modify the
1023 	 * font to change the name table, similar to what we do in the uniscribe
1024 	 * backend.
1025 	 *
1026 	 * However, even that wouldn't work if we were passed in the CGFont to
1027 	 * construct a hb_face to begin with.
1028 	 *
1029 	 * See: http://github.com/harfbuzz/harfbuzz/pull/36
1030 	 *
1031 	 * Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
1032 	 */
1033 	bool matched = false;
1034 	for (unsigned int i = 0; i < range_records.len; i++)
1035 	  if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
1036 	  {
1037 	    matched = true;
1038 	    break;
1039 	  }
1040 	if (!matched)
1041 	{
1042 	  CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
1043 	  if (run_cg_font)
1044 	  {
1045 	    matched = CFEqual (run_cg_font, cg_font);
1046 	    CFRelease (run_cg_font);
1047 	  }
1048 	}
1049 	if (!matched)
1050 	{
1051 	  CFStringRef font_ps_name = CTFontCopyName (ct_font, kCTFontPostScriptNameKey);
1052 	  CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
1053 	  CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
1054 	  CFRelease (run_ps_name);
1055 	  CFRelease (font_ps_name);
1056 	  if (result == kCFCompareEqualTo)
1057 	    matched = true;
1058 	}
1059 	if (!matched)
1060 	{
1061 	  CFRange range = CTRunGetStringRange (run);
1062           DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
1063 		     range.location, range.location + range.length);
1064 	  if (!buffer->ensure_inplace (buffer->len + range.length))
1065 	    goto resize_and_retry;
1066 	  hb_glyph_info_t *info = buffer->info + buffer->len;
1067 
1068 	  hb_codepoint_t notdef = 0;
1069 	  hb_direction_t dir = buffer->props.direction;
1070 	  hb_position_t x_advance, y_advance, x_offset, y_offset;
1071 	  hb_font_get_glyph_advance_for_direction (font, notdef, dir, &x_advance, &y_advance);
1072 	  hb_font_get_glyph_origin_for_direction (font, notdef, dir, &x_offset, &y_offset);
1073 	  hb_position_t advance = x_advance + y_advance;
1074 	  x_offset = -x_offset;
1075 	  y_offset = -y_offset;
1076 
1077 	  unsigned int old_len = buffer->len;
1078 	  for (CFIndex j = range.location; j < range.location + range.length; j++)
1079 	  {
1080 	      UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
1081 	      if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
1082 	      {
1083 		ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
1084 		if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
1085 		  /* This is the second of a surrogate pair.  Don't need .notdef
1086 		   * for this one. */
1087 		  continue;
1088 	      }
1089 	      if (buffer->unicode->is_default_ignorable (ch))
1090 	        continue;
1091 
1092 	      info->codepoint = notdef;
1093 	      info->cluster = log_clusters[j];
1094 
1095 	      info->mask = advance;
1096 	      info->var1.i32 = x_offset;
1097 	      info->var2.i32 = y_offset;
1098 
1099 	      info++;
1100 	      buffer->len++;
1101 	  }
1102 	  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
1103 	    buffer->reverse_range (old_len, buffer->len);
1104 	  advances_so_far += run_advance;
1105 	  continue;
1106 	}
1107       }
1108 
1109       unsigned int num_glyphs = CTRunGetGlyphCount (run);
1110       if (num_glyphs == 0)
1111 	continue;
1112 
1113       if (!buffer->ensure_inplace (buffer->len + num_glyphs))
1114 	goto resize_and_retry;
1115 
1116       hb_glyph_info_t *run_info = buffer->info + buffer->len;
1117 
1118       /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
1119        * succeed, and so copying data to our own buffer will be rare.  Reports
1120        * have it that this changed in OS X 10.10 Yosemite, and nullptr is returned
1121        * frequently.  At any rate, we can test that codepath by setting USE_PTR
1122        * to false. */
1123 
1124 #define USE_PTR true
1125 
1126 #define SCRATCH_SAVE() \
1127   unsigned int scratch_size_saved = scratch_size; \
1128   hb_buffer_t::scratch_buffer_t *scratch_saved = scratch
1129 
1130 #define SCRATCH_RESTORE() \
1131   scratch_size = scratch_size_saved; \
1132   scratch = scratch_saved;
1133 
1134       { /* Setup glyphs */
1135         SCRATCH_SAVE();
1136 	const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : nullptr;
1137 	if (!glyphs) {
1138 	  ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
1139 	  CTRunGetGlyphs (run, range_all, glyph_buf);
1140 	  glyphs = glyph_buf;
1141 	}
1142 	const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : nullptr;
1143 	if (!string_indices) {
1144 	  ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry);
1145 	  CTRunGetStringIndices (run, range_all, index_buf);
1146 	  string_indices = index_buf;
1147 	}
1148 	hb_glyph_info_t *info = run_info;
1149 	for (unsigned int j = 0; j < num_glyphs; j++)
1150 	{
1151 	  info->codepoint = glyphs[j];
1152 	  info->cluster = log_clusters[string_indices[j]];
1153 	  info++;
1154 	}
1155 	SCRATCH_RESTORE();
1156       }
1157       {
1158         /* Setup positions.
1159 	 * Note that CoreText does not return advances for glyphs.  As such,
1160 	 * for all but last glyph, we use the delta position to next glyph as
1161 	 * advance (in the advance direction only), and for last glyph we set
1162 	 * whatever is needed to make the whole run's advance add up. */
1163         SCRATCH_SAVE();
1164 	const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : nullptr;
1165 	if (!positions) {
1166 	  ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
1167 	  CTRunGetPositions (run, range_all, position_buf);
1168 	  positions = position_buf;
1169 	}
1170 	hb_glyph_info_t *info = run_info;
1171 	if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
1172 	{
1173 	  hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
1174 	  for (unsigned int j = 0; j < num_glyphs; j++)
1175 	  {
1176 	    double advance;
1177 	    if (likely (j + 1 < num_glyphs))
1178 	      advance = positions[j + 1].x - positions[j].x;
1179 	    else /* last glyph */
1180 	      advance = run_advance - (positions[j].x - positions[0].x);
1181 	    info->mask = advance * x_mult;
1182 	    info->var1.i32 = x_offset;
1183 	    info->var2.i32 = positions[j].y * y_mult;
1184 	    info++;
1185 	  }
1186 	}
1187 	else
1188 	{
1189 	  hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
1190 	  for (unsigned int j = 0; j < num_glyphs; j++)
1191 	  {
1192 	    double advance;
1193 	    if (likely (j + 1 < num_glyphs))
1194 	      advance = positions[j + 1].y - positions[j].y;
1195 	    else /* last glyph */
1196 	      advance = run_advance - (positions[j].y - positions[0].y);
1197 	    info->mask = advance * y_mult;
1198 	    info->var1.i32 = positions[j].x * x_mult;
1199 	    info->var2.i32 = y_offset;
1200 	    info++;
1201 	  }
1202 	}
1203 	SCRATCH_RESTORE();
1204 	advances_so_far += run_advance;
1205       }
1206 #undef SCRATCH_RESTORE
1207 #undef SCRATCH_SAVE
1208 #undef USE_PTR
1209 #undef ALLOCATE_ARRAY
1210 
1211       buffer->len += num_glyphs;
1212     }
1213 
1214     /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
1215      * or if it does, it doesn't resepct it.  So we get runs with wrong
1216      * directions.  As such, disable the assert...  It wouldn't crash, but
1217      * cursoring will be off...
1218      *
1219      * http://crbug.com/419769
1220      */
1221     if (0)
1222     {
1223       /* Make sure all runs had the expected direction. */
1224       bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
1225       assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
1226       assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
1227     }
1228 
1229     buffer->clear_positions ();
1230 
1231     unsigned int count = buffer->len;
1232     hb_glyph_info_t *info = buffer->info;
1233     hb_glyph_position_t *pos = buffer->pos;
1234     if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
1235       for (unsigned int i = 0; i < count; i++)
1236       {
1237 	pos->x_advance = info->mask;
1238 	pos->x_offset = info->var1.i32;
1239 	pos->y_offset = info->var2.i32;
1240 
1241 	info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
1242 
1243 	info++, pos++;
1244       }
1245     else
1246       for (unsigned int i = 0; i < count; i++)
1247       {
1248 	pos->y_advance = info->mask;
1249 	pos->x_offset = info->var1.i32;
1250 	pos->y_offset = info->var2.i32;
1251 
1252 	info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
1253 
1254 	info++, pos++;
1255       }
1256 
1257     /* Fix up clusters so that we never return out-of-order indices;
1258      * if core text has reordered glyphs, we'll merge them to the
1259      * beginning of the reordered cluster.  CoreText is nice enough
1260      * to tell us whenever it has produced nonmonotonic results...
1261      * Note that we assume the input clusters were nonmonotonic to
1262      * begin with.
1263      *
1264      * This does *not* mean we'll form the same clusters as Uniscribe
1265      * or the native OT backend, only that the cluster indices will be
1266      * monotonic in the output buffer. */
1267     if (count > 1 && (status_or & kCTRunStatusNonMonotonic))
1268     {
1269       hb_glyph_info_t *info = buffer->info;
1270       if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
1271       {
1272 	unsigned int cluster = info[count - 1].cluster;
1273 	for (unsigned int i = count - 1; i > 0; i--)
1274 	{
1275 	  cluster = MIN (cluster, info[i - 1].cluster);
1276 	  info[i - 1].cluster = cluster;
1277 	}
1278       }
1279       else
1280       {
1281 	unsigned int cluster = info[0].cluster;
1282 	for (unsigned int i = 1; i < count; i++)
1283 	{
1284 	  cluster = MIN (cluster, info[i].cluster);
1285 	  info[i].cluster = cluster;
1286 	}
1287       }
1288     }
1289   }
1290 
1291   buffer->unsafe_to_break_all ();
1292 
1293 #undef FAIL
1294 
1295 fail:
1296   if (string_ref)
1297     CFRelease (string_ref);
1298   if (line)
1299     CFRelease (line);
1300 
1301   for (unsigned int i = 0; i < range_records.len; i++)
1302     if (range_records[i].font)
1303       CFRelease (range_records[i].font);
1304 
1305   return ret;
1306 }
1307 
1308 
1309 /*
1310  * AAT shaper
1311  */
1312 
1313 HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, face)
1314 HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, font)
1315 
1316 /*
1317  * shaper face data
1318  */
1319 
1320 struct hb_coretext_aat_shaper_face_data_t {};
1321 
1322 hb_coretext_aat_shaper_face_data_t *
_hb_coretext_aat_shaper_face_data_create(hb_face_t * face)1323 _hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
1324 {
1325   static const hb_tag_t tags[] = {HB_CORETEXT_TAG_MORX, HB_CORETEXT_TAG_MORT, HB_CORETEXT_TAG_KERX, HB_CORETEXT_TAG_TRAK};
1326 
1327   for (unsigned int i = 0; i < ARRAY_LENGTH (tags); i++)
1328   {
1329     hb_blob_t *blob = face->reference_table (tags[i]);
1330     if (hb_blob_get_length (blob))
1331     {
1332       hb_blob_destroy (blob);
1333       return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
1334     }
1335     hb_blob_destroy (blob);
1336   }
1337 
1338   return nullptr;
1339 }
1340 
1341 void
_hb_coretext_aat_shaper_face_data_destroy(hb_coretext_aat_shaper_face_data_t * data HB_UNUSED)1342 _hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
1343 {
1344 }
1345 
1346 
1347 /*
1348  * shaper font data
1349  */
1350 
1351 struct hb_coretext_aat_shaper_font_data_t {};
1352 
1353 hb_coretext_aat_shaper_font_data_t *
_hb_coretext_aat_shaper_font_data_create(hb_font_t * font)1354 _hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
1355 {
1356   return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
1357 }
1358 
1359 void
_hb_coretext_aat_shaper_font_data_destroy(hb_coretext_aat_shaper_font_data_t * data HB_UNUSED)1360 _hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
1361 {
1362 }
1363 
1364 
1365 /*
1366  * shaper shape_plan data
1367  */
1368 
1369 struct hb_coretext_aat_shaper_shape_plan_data_t {};
1370 
1371 hb_coretext_aat_shaper_shape_plan_data_t *
_hb_coretext_aat_shaper_shape_plan_data_create(hb_shape_plan_t * shape_plan HB_UNUSED,const hb_feature_t * user_features HB_UNUSED,unsigned int num_user_features HB_UNUSED,const int * coords HB_UNUSED,unsigned int num_coords HB_UNUSED)1372 _hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
1373 					     const hb_feature_t *user_features HB_UNUSED,
1374 					     unsigned int        num_user_features HB_UNUSED,
1375 					     const int          *coords HB_UNUSED,
1376 					     unsigned int        num_coords HB_UNUSED)
1377 {
1378   return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
1379 }
1380 
1381 void
_hb_coretext_aat_shaper_shape_plan_data_destroy(hb_coretext_aat_shaper_shape_plan_data_t * data HB_UNUSED)1382 _hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
1383 {
1384 }
1385 
1386 
1387 /*
1388  * shaper
1389  */
1390 
1391 hb_bool_t
_hb_coretext_aat_shape(hb_shape_plan_t * shape_plan,hb_font_t * font,hb_buffer_t * buffer,const hb_feature_t * features,unsigned int num_features)1392 _hb_coretext_aat_shape (hb_shape_plan_t    *shape_plan,
1393 			hb_font_t          *font,
1394 			hb_buffer_t        *buffer,
1395 			const hb_feature_t *features,
1396 			unsigned int        num_features)
1397 {
1398   return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
1399 }
1400