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#include "hb-shaper-impl-private.hh"
31
32#include "hb-coretext.h"
33
34
35#ifndef HB_DEBUG_CORETEXT
36#define HB_DEBUG_CORETEXT (HB_DEBUG+0)
37#endif
38
39
40static void
41release_table_data (void *user_data)
42{
43  CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
44  CFRelease(cf_data);
45}
46
47static hb_blob_t *
48reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
49{
50  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
51  CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
52  if (unlikely (!cf_data))
53    return NULL;
54
55  const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
56  const size_t length = CFDataGetLength (cf_data);
57  if (!data || !length)
58    return NULL;
59
60  return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
61			 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
62			 release_table_data);
63}
64
65hb_face_t *
66hb_coretext_face_create (CGFontRef cg_font)
67{
68  return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease);
69}
70
71
72HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
73HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
74
75
76/*
77 * shaper face data
78 */
79
80struct hb_coretext_shaper_face_data_t {
81  CGFontRef cg_font;
82};
83
84static void
85release_data (void *info, const void *data, size_t size)
86{
87  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
88          hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
89
90  hb_blob_destroy ((hb_blob_t *) info);
91}
92
93hb_coretext_shaper_face_data_t *
94_hb_coretext_shaper_face_data_create (hb_face_t *face)
95{
96  hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
97  if (unlikely (!data))
98    return NULL;
99
100  if (face->destroy == (hb_destroy_func_t) CGFontRelease)
101  {
102    data->cg_font = CGFontRetain ((CGFontRef) face->user_data);
103  }
104  else
105  {
106    hb_blob_t *blob = hb_face_reference_blob (face);
107    unsigned int blob_length;
108    const char *blob_data = hb_blob_get_data (blob, &blob_length);
109    if (unlikely (!blob_length))
110      DEBUG_MSG (CORETEXT, face, "Face has empty blob");
111
112    CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
113    data->cg_font = CGFontCreateWithDataProvider (provider);
114    CGDataProviderRelease (provider);
115  }
116
117  if (unlikely (!data->cg_font)) {
118    DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
119    free (data);
120    return NULL;
121  }
122
123  return data;
124}
125
126void
127_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
128{
129  CFRelease (data->cg_font);
130  free (data);
131}
132
133CGFontRef
134hb_coretext_face_get_cg_font (hb_face_t *face)
135{
136  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
137  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
138  return face_data->cg_font;
139}
140
141
142/*
143 * shaper font data
144 */
145
146struct hb_coretext_shaper_font_data_t {
147  CTFontRef ct_font;
148};
149
150hb_coretext_shaper_font_data_t *
151_hb_coretext_shaper_font_data_create (hb_font_t *font)
152{
153  if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
154
155  hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
156  if (unlikely (!data))
157    return NULL;
158
159  hb_face_t *face = font->face;
160  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
161
162  data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL);
163  if (unlikely (!data->ct_font)) {
164    DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
165    free (data);
166    return NULL;
167  }
168
169  return data;
170}
171
172void
173_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
174{
175  CFRelease (data->ct_font);
176  free (data);
177}
178
179
180/*
181 * shaper shape_plan data
182 */
183
184struct hb_coretext_shaper_shape_plan_data_t {};
185
186hb_coretext_shaper_shape_plan_data_t *
187_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
188					     const hb_feature_t *user_features HB_UNUSED,
189					     unsigned int        num_user_features HB_UNUSED)
190{
191  return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
192}
193
194void
195_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
196{
197}
198
199CTFontRef
200hb_coretext_font_get_ct_font (hb_font_t *font)
201{
202  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
203  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
204  return font_data->ct_font;
205}
206
207
208/*
209 * shaper
210 */
211
212struct feature_record_t {
213  unsigned int feature;
214  unsigned int setting;
215};
216
217struct active_feature_t {
218  feature_record_t rec;
219  unsigned int order;
220
221  static int cmp (const active_feature_t *a, const active_feature_t *b) {
222    return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
223	   a->order < b->order ? -1 : a->order > b->order ? 1 :
224	   a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
225	   0;
226  }
227  bool operator== (const active_feature_t *f) {
228    return cmp (this, f) == 0;
229  }
230};
231
232struct feature_event_t {
233  unsigned int index;
234  bool start;
235  active_feature_t feature;
236
237  static int cmp (const feature_event_t *a, const feature_event_t *b) {
238    return a->index < b->index ? -1 : a->index > b->index ? 1 :
239	   a->start < b->start ? -1 : a->start > b->start ? 1 :
240	   active_feature_t::cmp (&a->feature, &b->feature);
241  }
242};
243
244struct range_record_t {
245  CTFontRef font;
246  unsigned int index_first; /* == start */
247  unsigned int index_last;  /* == end - 1 */
248};
249
250
251/* The following enum members are added in OS X 10.8. */
252#define kAltHalfWidthTextSelector		6
253#define kAltProportionalTextSelector		5
254#define kAlternateHorizKanaOffSelector		1
255#define kAlternateHorizKanaOnSelector		0
256#define kAlternateKanaType			34
257#define kAlternateVertKanaOffSelector		3
258#define kAlternateVertKanaOnSelector		2
259#define kCaseSensitiveLayoutOffSelector		1
260#define kCaseSensitiveLayoutOnSelector		0
261#define kCaseSensitiveLayoutType		33
262#define kCaseSensitiveSpacingOffSelector	3
263#define kCaseSensitiveSpacingOnSelector		2
264#define kContextualAlternatesOffSelector	1
265#define kContextualAlternatesOnSelector		0
266#define kContextualAlternatesType		36
267#define kContextualLigaturesOffSelector		19
268#define kContextualLigaturesOnSelector		18
269#define kContextualSwashAlternatesOffSelector	5
270#define kContextualSwashAlternatesOnSelector	4
271#define kDefaultLowerCaseSelector		0
272#define kDefaultUpperCaseSelector		0
273#define kHistoricalLigaturesOffSelector		21
274#define kHistoricalLigaturesOnSelector		20
275#define kHojoCharactersSelector			12
276#define kJIS2004CharactersSelector		11
277#define kLowerCasePetiteCapsSelector		2
278#define kLowerCaseSmallCapsSelector		1
279#define kLowerCaseType				37
280#define kMathematicalGreekOffSelector		11
281#define kMathematicalGreekOnSelector		10
282#define kNLCCharactersSelector			13
283#define kQuarterWidthTextSelector		4
284#define kScientificInferiorsSelector		4
285#define kStylisticAltEightOffSelector		17
286#define kStylisticAltEightOnSelector		16
287#define kStylisticAltEighteenOffSelector	37
288#define kStylisticAltEighteenOnSelector		36
289#define kStylisticAltElevenOffSelector		23
290#define kStylisticAltElevenOnSelector		22
291#define kStylisticAltFifteenOffSelector		31
292#define kStylisticAltFifteenOnSelector		30
293#define kStylisticAltFiveOffSelector		11
294#define kStylisticAltFiveOnSelector		10
295#define kStylisticAltFourOffSelector		9
296#define kStylisticAltFourOnSelector		8
297#define kStylisticAltFourteenOffSelector	29
298#define kStylisticAltFourteenOnSelector		28
299#define kStylisticAltNineOffSelector		19
300#define kStylisticAltNineOnSelector		18
301#define kStylisticAltNineteenOffSelector	39
302#define kStylisticAltNineteenOnSelector		38
303#define kStylisticAltOneOffSelector		3
304#define kStylisticAltOneOnSelector		2
305#define kStylisticAltSevenOffSelector		15
306#define kStylisticAltSevenOnSelector		14
307#define kStylisticAltSeventeenOffSelector	35
308#define kStylisticAltSeventeenOnSelector	34
309#define kStylisticAltSixOffSelector		13
310#define kStylisticAltSixOnSelector		12
311#define kStylisticAltSixteenOffSelector		33
312#define kStylisticAltSixteenOnSelector		32
313#define kStylisticAltTenOffSelector		21
314#define kStylisticAltTenOnSelector		20
315#define kStylisticAltThirteenOffSelector	27
316#define kStylisticAltThirteenOnSelector		26
317#define kStylisticAltThreeOffSelector		7
318#define kStylisticAltThreeOnSelector		6
319#define kStylisticAltTwelveOffSelector		25
320#define kStylisticAltTwelveOnSelector		24
321#define kStylisticAltTwentyOffSelector		41
322#define kStylisticAltTwentyOnSelector		40
323#define kStylisticAltTwoOffSelector		5
324#define kStylisticAltTwoOnSelector		4
325#define kStylisticAlternativesType		35
326#define kSwashAlternatesOffSelector		3
327#define kSwashAlternatesOnSelector		2
328#define kThirdWidthTextSelector			3
329#define kTraditionalNamesCharactersSelector	14
330#define kUpperCasePetiteCapsSelector		2
331#define kUpperCaseSmallCapsSelector		1
332#define kUpperCaseType				38
333
334/* Table data courtesy of Apple. */
335struct feature_mapping_t {
336    FourCharCode otFeatureTag;
337    uint16_t aatFeatureType;
338    uint16_t selectorToEnable;
339    uint16_t selectorToDisable;
340} feature_mappings[] = {
341    { 'c2pc',   kUpperCaseType,             kUpperCasePetiteCapsSelector,           kDefaultUpperCaseSelector },
342    { 'c2sc',   kUpperCaseType,             kUpperCaseSmallCapsSelector,            kDefaultUpperCaseSelector },
343    { 'calt',   kContextualAlternatesType,  kContextualAlternatesOnSelector,        kContextualAlternatesOffSelector },
344    { 'case',   kCaseSensitiveLayoutType,   kCaseSensitiveLayoutOnSelector,         kCaseSensitiveLayoutOffSelector },
345    { 'clig',   kLigaturesType,             kContextualLigaturesOnSelector,         kContextualLigaturesOffSelector },
346    { 'cpsp',   kCaseSensitiveLayoutType,   kCaseSensitiveSpacingOnSelector,        kCaseSensitiveSpacingOffSelector },
347    { 'cswh',   kContextualAlternatesType,  kContextualSwashAlternatesOnSelector,   kContextualSwashAlternatesOffSelector },
348    { 'dlig',   kLigaturesType,             kRareLigaturesOnSelector,               kRareLigaturesOffSelector },
349    { 'expt',   kCharacterShapeType,        kExpertCharactersSelector,              16 },
350    { 'frac',   kFractionsType,             kDiagonalFractionsSelector,             kNoFractionsSelector },
351    { 'fwid',   kTextSpacingType,           kMonospacedTextSelector,                7 },
352    { 'halt',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
353    { 'hist',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
354    { 'hkna',   kAlternateKanaType,         kAlternateHorizKanaOnSelector,          kAlternateHorizKanaOffSelector, },
355    { 'hlig',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
356    { 'hngl',   kTransliterationType,       kHanjaToHangulSelector,                 kNoTransliterationSelector },
357    { 'hojo',   kCharacterShapeType,        kHojoCharactersSelector,                16 },
358    { 'hwid',   kTextSpacingType,           kHalfWidthTextSelector,                 7 },
359    { 'ital',   kItalicCJKRomanType,        kCJKItalicRomanOnSelector,              kCJKItalicRomanOffSelector },
360    { 'jp04',   kCharacterShapeType,        kJIS2004CharactersSelector,             16 },
361    { 'jp78',   kCharacterShapeType,        kJIS1978CharactersSelector,             16 },
362    { 'jp83',   kCharacterShapeType,        kJIS1983CharactersSelector,             16 },
363    { 'jp90',   kCharacterShapeType,        kJIS1990CharactersSelector,             16 },
364    { 'liga',   kLigaturesType,             kCommonLigaturesOnSelector,             kCommonLigaturesOffSelector },
365    { 'lnum',   kNumberCaseType,            kUpperCaseNumbersSelector,              2 },
366    { 'mgrk',   kMathematicalExtrasType,    kMathematicalGreekOnSelector,           kMathematicalGreekOffSelector },
367    { 'nlck',   kCharacterShapeType,        kNLCCharactersSelector,                 16 },
368    { 'onum',   kNumberCaseType,            kLowerCaseNumbersSelector,              2 },
369    { 'ordn',   kVerticalPositionType,      kOrdinalsSelector,                      kNormalPositionSelector },
370    { 'palt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
371    { 'pcap',   kLowerCaseType,             kLowerCasePetiteCapsSelector,           kDefaultLowerCaseSelector },
372    { 'pkna',   kTextSpacingType,           kProportionalTextSelector,              7 },
373    { 'pnum',   kNumberSpacingType,         kProportionalNumbersSelector,           4 },
374    { 'pwid',   kTextSpacingType,           kProportionalTextSelector,              7 },
375    { 'qwid',   kTextSpacingType,           kQuarterWidthTextSelector,              7 },
376    { 'ruby',   kRubyKanaType,              kRubyKanaOnSelector,                    kRubyKanaOffSelector },
377    { 'sinf',   kVerticalPositionType,      kScientificInferiorsSelector,           kNormalPositionSelector },
378    { 'smcp',   kLowerCaseType,             kLowerCaseSmallCapsSelector,            kDefaultLowerCaseSelector },
379    { 'smpl',   kCharacterShapeType,        kSimplifiedCharactersSelector,          16 },
380    { 'ss01',   kStylisticAlternativesType, kStylisticAltOneOnSelector,             kStylisticAltOneOffSelector },
381    { 'ss02',   kStylisticAlternativesType, kStylisticAltTwoOnSelector,             kStylisticAltTwoOffSelector },
382    { 'ss03',   kStylisticAlternativesType, kStylisticAltThreeOnSelector,           kStylisticAltThreeOffSelector },
383    { 'ss04',   kStylisticAlternativesType, kStylisticAltFourOnSelector,            kStylisticAltFourOffSelector },
384    { 'ss05',   kStylisticAlternativesType, kStylisticAltFiveOnSelector,            kStylisticAltFiveOffSelector },
385    { 'ss06',   kStylisticAlternativesType, kStylisticAltSixOnSelector,             kStylisticAltSixOffSelector },
386    { 'ss07',   kStylisticAlternativesType, kStylisticAltSevenOnSelector,           kStylisticAltSevenOffSelector },
387    { 'ss08',   kStylisticAlternativesType, kStylisticAltEightOnSelector,           kStylisticAltEightOffSelector },
388    { 'ss09',   kStylisticAlternativesType, kStylisticAltNineOnSelector,            kStylisticAltNineOffSelector },
389    { 'ss10',   kStylisticAlternativesType, kStylisticAltTenOnSelector,             kStylisticAltTenOffSelector },
390    { 'ss11',   kStylisticAlternativesType, kStylisticAltElevenOnSelector,          kStylisticAltElevenOffSelector },
391    { 'ss12',   kStylisticAlternativesType, kStylisticAltTwelveOnSelector,          kStylisticAltTwelveOffSelector },
392    { 'ss13',   kStylisticAlternativesType, kStylisticAltThirteenOnSelector,        kStylisticAltThirteenOffSelector },
393    { 'ss14',   kStylisticAlternativesType, kStylisticAltFourteenOnSelector,        kStylisticAltFourteenOffSelector },
394    { 'ss15',   kStylisticAlternativesType, kStylisticAltFifteenOnSelector,         kStylisticAltFifteenOffSelector },
395    { 'ss16',   kStylisticAlternativesType, kStylisticAltSixteenOnSelector,         kStylisticAltSixteenOffSelector },
396    { 'ss17',   kStylisticAlternativesType, kStylisticAltSeventeenOnSelector,       kStylisticAltSeventeenOffSelector },
397    { 'ss18',   kStylisticAlternativesType, kStylisticAltEighteenOnSelector,        kStylisticAltEighteenOffSelector },
398    { 'ss19',   kStylisticAlternativesType, kStylisticAltNineteenOnSelector,        kStylisticAltNineteenOffSelector },
399    { 'ss20',   kStylisticAlternativesType, kStylisticAltTwentyOnSelector,          kStylisticAltTwentyOffSelector },
400    { 'subs',   kVerticalPositionType,      kInferiorsSelector,                     kNormalPositionSelector },
401    { 'sups',   kVerticalPositionType,      kSuperiorsSelector,                     kNormalPositionSelector },
402    { 'swsh',   kContextualAlternatesType,  kSwashAlternatesOnSelector,             kSwashAlternatesOffSelector },
403    { 'titl',   kStyleOptionsType,          kTitlingCapsSelector,                   kNoStyleOptionsSelector },
404    { 'tnam',   kCharacterShapeType,        kTraditionalNamesCharactersSelector,    16 },
405    { 'tnum',   kNumberSpacingType,         kMonospacedNumbersSelector,             4 },
406    { 'trad',   kCharacterShapeType,        kTraditionalCharactersSelector,         16 },
407    { 'twid',   kTextSpacingType,           kThirdWidthTextSelector,                7 },
408    { 'unic',   kLetterCaseType,            14,                                     15 },
409    { 'valt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
410    { 'vert',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
411    { 'vhal',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
412    { 'vkna',   kAlternateKanaType,         kAlternateVertKanaOnSelector,           kAlternateVertKanaOffSelector },
413    { 'vpal',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
414    { 'vrt2',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
415    { 'zero',   kTypographicExtrasType,     kSlashedZeroOnSelector,                 kSlashedZeroOffSelector },
416};
417
418static int
419_hb_feature_mapping_cmp (const void *key_, const void *entry_)
420{
421  unsigned int key = * (unsigned int *) key_;
422  const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
423  return key < entry->otFeatureTag ? -1 :
424	 key > entry->otFeatureTag ? 1 :
425	 0;
426}
427
428hb_bool_t
429_hb_coretext_shape (hb_shape_plan_t    *shape_plan,
430		    hb_font_t          *font,
431                    hb_buffer_t        *buffer,
432                    const hb_feature_t *features,
433                    unsigned int        num_features)
434{
435  hb_face_t *face = font->face;
436  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
437  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
438
439  /*
440   * Set up features.
441   * (copied + modified from code from hb-uniscribe.cc)
442   */
443  hb_auto_array_t<feature_record_t> feature_records;
444  hb_auto_array_t<range_record_t> range_records;
445  if (num_features)
446  {
447    /* Sort features by start/end events. */
448    hb_auto_array_t<feature_event_t> feature_events;
449    for (unsigned int i = 0; i < num_features; i++)
450    {
451      const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
452									       feature_mappings,
453									       ARRAY_LENGTH (feature_mappings),
454									       sizeof (feature_mappings[0]),
455									       _hb_feature_mapping_cmp);
456      if (!mapping)
457        continue;
458
459      active_feature_t feature;
460      feature.rec.feature = mapping->aatFeatureType;
461      feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
462      feature.order = i;
463
464      feature_event_t *event;
465
466      event = feature_events.push ();
467      if (unlikely (!event))
468	goto fail_features;
469      event->index = features[i].start;
470      event->start = true;
471      event->feature = feature;
472
473      event = feature_events.push ();
474      if (unlikely (!event))
475	goto fail_features;
476      event->index = features[i].end;
477      event->start = false;
478      event->feature = feature;
479    }
480    feature_events.qsort ();
481    /* Add a strategic final event. */
482    {
483      active_feature_t feature;
484      feature.rec.feature = HB_TAG_NONE;
485      feature.rec.setting = 0;
486      feature.order = num_features + 1;
487
488      feature_event_t *event = feature_events.push ();
489      if (unlikely (!event))
490	goto fail_features;
491      event->index = 0; /* This value does magic. */
492      event->start = false;
493      event->feature = feature;
494    }
495
496    /* Scan events and save features for each range. */
497    hb_auto_array_t<active_feature_t> active_features;
498    unsigned int last_index = 0;
499    for (unsigned int i = 0; i < feature_events.len; i++)
500    {
501      feature_event_t *event = &feature_events[i];
502
503      if (event->index != last_index)
504      {
505        /* Save a snapshot of active features and the range. */
506	range_record_t *range = range_records.push ();
507	if (unlikely (!range))
508	  goto fail_features;
509
510	if (active_features.len)
511	{
512	  CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
513
514	  /* TODO sort and resolve conflicting features? */
515	  /* active_features.qsort (); */
516	  for (unsigned int j = 0; j < active_features.len; j++)
517	  {
518	    CFStringRef keys[2] = {
519	      kCTFontFeatureTypeIdentifierKey,
520	      kCTFontFeatureSelectorIdentifierKey
521	    };
522	    CFNumberRef values[2] = {
523	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
524	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
525	    };
526	    CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
527						       (const void **) keys,
528						       (const void **) values,
529						       2,
530						       &kCFTypeDictionaryKeyCallBacks,
531						       &kCFTypeDictionaryValueCallBacks);
532	    CFRelease (values[0]);
533	    CFRelease (values[1]);
534
535	    CFArrayAppendValue (features_array, dict);
536	    CFRelease (dict);
537
538	  }
539
540	  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
541							   (const void **) &kCTFontFeatureSettingsAttribute,
542							   (const void **) &features_array,
543							   1,
544							   &kCFTypeDictionaryKeyCallBacks,
545							   &kCFTypeDictionaryValueCallBacks);
546	  CFRelease (features_array);
547
548	  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
549	  CFRelease (attributes);
550
551	  range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
552
553	  CFRelease (font_desc);
554	}
555	else
556	{
557	  range->font = NULL;
558	}
559
560	range->index_first = last_index;
561	range->index_last  = event->index - 1;
562
563	last_index = event->index;
564      }
565
566      if (event->start) {
567        active_feature_t *feature = active_features.push ();
568	if (unlikely (!feature))
569	  goto fail_features;
570	*feature = event->feature;
571      } else {
572        active_feature_t *feature = active_features.find (&event->feature);
573	if (feature)
574	  active_features.remove (feature - active_features.array);
575      }
576    }
577
578    if (!range_records.len) /* No active feature found. */
579      goto fail_features;
580  }
581  else
582  {
583  fail_features:
584    num_features = 0;
585  }
586
587#define FAIL(...) \
588  HB_STMT_START { \
589    DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
590    return false; \
591  } HB_STMT_END;
592
593  unsigned int scratch_size;
594  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
595
596#define ALLOCATE_ARRAY(Type, name, len) \
597  Type *name = (Type *) scratch; \
598  { \
599    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
600    assert (_consumed <= scratch_size); \
601    scratch += _consumed; \
602    scratch_size -= _consumed; \
603  }
604
605#define utf16_index() var1.u32
606
607  ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2);
608
609  unsigned int chars_len = 0;
610  for (unsigned int i = 0; i < buffer->len; i++) {
611    hb_codepoint_t c = buffer->info[i].codepoint;
612    buffer->info[i].utf16_index() = chars_len;
613    if (likely (c <= 0xFFFFu))
614      pchars[chars_len++] = c;
615    else if (unlikely (c > 0x10FFFFu))
616      pchars[chars_len++] = 0xFFFDu;
617    else {
618      pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
619      pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
620    }
621  }
622
623#undef utf16_index
624
625  CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL,
626                                                               pchars, chars_len,
627                                                               kCFAllocatorNull);
628
629  CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NULL, chars_len);
630  CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
631  CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
632				  kCTFontAttributeName, font_data->ct_font);
633
634  if (num_features)
635  {
636    ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len);
637
638    /* Need log_clusters to assign features. */
639    chars_len = 0;
640    for (unsigned int i = 0; i < buffer->len; i++)
641    {
642      hb_codepoint_t c = buffer->info[i].codepoint;
643      unsigned int cluster = buffer->info[i].cluster;
644      log_clusters[chars_len++] = cluster;
645      if (hb_in_range (c, 0x10000u, 0x10FFFFu))
646	log_clusters[chars_len++] = cluster; /* Surrogates. */
647    }
648
649    unsigned int start = 0;
650    range_record_t *last_range = &range_records[0];
651    for (unsigned int k = 0; k < chars_len; k++)
652    {
653      range_record_t *range = last_range;
654      while (log_clusters[k] < range->index_first)
655	range--;
656      while (log_clusters[k] > range->index_last)
657	range++;
658      if (range != last_range)
659      {
660        if (last_range->font)
661	  CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
662					  kCTFontAttributeName, last_range->font);
663
664	start = k;
665      }
666
667      last_range = range;
668    }
669    if (start != chars_len && last_range->font)
670      CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start - 1),
671				      kCTFontAttributeName, last_range->font);
672
673    for (unsigned int i = 0; i < range_records.len; i++)
674      if (range_records[i].font)
675	CFRelease (range_records[i].font);
676  }
677
678  CTLineRef line = CTLineCreateWithAttributedString (attr_string);
679  CFRelease (attr_string);
680
681  CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
682  unsigned int num_runs = CFArrayGetCount (glyph_runs);
683
684  buffer->len = 0;
685
686  const CFRange range_all = CFRangeMake (0, 0);
687
688  for (unsigned int i = 0; i < num_runs; i++)
689  {
690    CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i);
691
692    /* CoreText does automatic font fallback (AKA "cascading") for  characters
693     * not supported by the requested font, and provides no way to turn it off,
694     * so we detect if the returned run uses a font other than the requested
695     * one and fill in the buffer with .notdef glyphs instead of random glyph
696     * indices from a different font.
697     */
698    CFDictionaryRef attributes = CTRunGetAttributes (run);
699    CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
700    CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
701    if (!CFEqual (run_cg_font, face_data->cg_font))
702    {
703        CFRelease (run_cg_font);
704
705	CFRange range = CTRunGetStringRange (run);
706	buffer->ensure (buffer->len + range.length);
707	if (buffer->in_error)
708	  FAIL ("Buffer resize failed");
709	hb_glyph_info_t *info = buffer->info + buffer->len;
710
711	CGGlyph notdef = 0;
712	double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, &notdef, NULL, 1);
713
714        for (CFIndex j = range.location; j < range.location + range.length; j++)
715	{
716	    UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
717	    if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
718	    {
719	      ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
720	      if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
721	        /* This is the second of a surrogate pair.  Don't need .notdef
722		 * for this one. */
723	        continue;
724	    }
725
726            info->codepoint = notdef;
727	    /* TODO We have to fixup clusters later.  See vis_clusters in
728	     * hb-uniscribe.cc for example. */
729            info->cluster = j;
730
731            info->mask = advance;
732            info->var1.u32 = 0;
733            info->var2.u32 = 0;
734
735	    info++;
736	    buffer->len++;
737        }
738        continue;
739    }
740    CFRelease (run_cg_font);
741
742    unsigned int num_glyphs = CTRunGetGlyphCount (run);
743    if (num_glyphs == 0)
744      continue;
745
746    buffer->ensure (buffer->len + num_glyphs);
747
748    scratch = buffer->get_scratch_buffer (&scratch_size);
749
750    /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always
751     * succeed, and so copying data to our own buffer will be rare. */
752
753    const CGGlyph* glyphs = CTRunGetGlyphsPtr (run);
754    if (!glyphs) {
755      ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs);
756      CTRunGetGlyphs (run, range_all, glyph_buf);
757      glyphs = glyph_buf;
758    }
759
760    const CGPoint* positions = CTRunGetPositionsPtr (run);
761    if (!positions) {
762      ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs);
763      CTRunGetPositions (run, range_all, position_buf);
764      positions = position_buf;
765    }
766
767    const CFIndex* string_indices = CTRunGetStringIndicesPtr (run);
768    if (!string_indices) {
769      ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs);
770      CTRunGetStringIndices (run, range_all, index_buf);
771      string_indices = index_buf;
772    }
773
774#undef ALLOCATE_ARRAY
775
776    double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
777
778    for (unsigned int j = 0; j < num_glyphs; j++) {
779      double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x;
780
781      hb_glyph_info_t *info = &buffer->info[buffer->len];
782
783      info->codepoint = glyphs[j];
784      info->cluster = string_indices[j];
785
786      /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
787      info->mask = advance;
788      info->var1.u32 = 0;
789      info->var2.u32 = positions[j].y;
790
791      buffer->len++;
792    }
793  }
794
795  buffer->clear_positions ();
796
797  unsigned int count = buffer->len;
798  for (unsigned int i = 0; i < count; ++i) {
799    hb_glyph_info_t *info = &buffer->info[i];
800    hb_glyph_position_t *pos = &buffer->pos[i];
801
802    /* TODO vertical */
803    pos->x_advance = info->mask;
804    pos->x_offset = info->var1.u32;
805    pos->y_offset = info->var2.u32;
806  }
807
808  /* Fix up clusters so that we never return out-of-order indices;
809   * if core text has reordered glyphs, we'll merge them to the
810   * beginning of the reordered cluster.
811   *
812   * This does *not* mean we'll form the same clusters as Uniscribe
813   * or the native OT backend, only that the cluster indices will be
814   * monotonic in the output buffer. */
815  if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
816    unsigned int prev_cluster = 0;
817    for (unsigned int i = 0; i < count; i++) {
818      unsigned int curr_cluster = buffer->info[i].cluster;
819      if (curr_cluster < prev_cluster) {
820        for (unsigned int j = i; j > 0; j--) {
821          if (buffer->info[j - 1].cluster > curr_cluster)
822            buffer->info[j - 1].cluster = curr_cluster;
823          else
824            break;
825        }
826      }
827      prev_cluster = curr_cluster;
828    }
829  } else {
830    unsigned int prev_cluster = (unsigned int)-1;
831    for (unsigned int i = 0; i < count; i++) {
832      unsigned int curr_cluster = buffer->info[i].cluster;
833      if (curr_cluster > prev_cluster) {
834        for (unsigned int j = i; j > 0; j--) {
835          if (buffer->info[j - 1].cluster < curr_cluster)
836            buffer->info[j - 1].cluster = curr_cluster;
837          else
838            break;
839        }
840      }
841      prev_cluster = curr_cluster;
842    }
843  }
844
845  CFRelease (string_ref);
846  CFRelease (line);
847
848  return true;
849}
850
851
852/*
853 * AAT shaper
854 */
855
856HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
857HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
858
859
860/*
861 * shaper face data
862 */
863
864struct hb_coretext_aat_shaper_face_data_t {};
865
866hb_coretext_aat_shaper_face_data_t *
867_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
868{
869  hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
870  /* Umm, we just reference the table to check whether it exists.
871   * Maybe add better API for this? */
872  if (!hb_blob_get_length (mort_blob))
873  {
874    hb_blob_destroy (mort_blob);
875    mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
876    if (!hb_blob_get_length (mort_blob))
877    {
878      hb_blob_destroy (mort_blob);
879      return NULL;
880    }
881  }
882  hb_blob_destroy (mort_blob);
883
884  return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
885}
886
887void
888_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
889{
890}
891
892
893/*
894 * shaper font data
895 */
896
897struct hb_coretext_aat_shaper_font_data_t {};
898
899hb_coretext_aat_shaper_font_data_t *
900_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
901{
902  return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
903}
904
905void
906_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
907{
908}
909
910
911/*
912 * shaper shape_plan data
913 */
914
915struct hb_coretext_aat_shaper_shape_plan_data_t {};
916
917hb_coretext_aat_shaper_shape_plan_data_t *
918_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
919					     const hb_feature_t *user_features HB_UNUSED,
920					     unsigned int        num_user_features HB_UNUSED)
921{
922  return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
923}
924
925void
926_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
927{
928}
929
930
931/*
932 * shaper
933 */
934
935hb_bool_t
936_hb_coretext_aat_shape (hb_shape_plan_t    *shape_plan,
937			hb_font_t          *font,
938			hb_buffer_t        *buffer,
939			const hb_feature_t *features,
940			unsigned int        num_features)
941{
942  return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
943}
944