1aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew/*
23613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod * Copyright © 2012,2013  Mozilla Foundation.
33613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod * Copyright © 2012,2013  Google, Inc.
4aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *
5aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *  This is part of HarfBuzz, a text shaping library.
6aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *
7aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * Permission is hereby granted, without written agreement and without
8aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * license or royalty fees, to use, copy, modify, and distribute this
9aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * software and its documentation for any purpose, provided that the
10aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * above copyright notice and the following two paragraphs appear in
11aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * all copies of this software.
12aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *
13aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * DAMAGE.
18aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *
19aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *
25aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * Mozilla Author(s): Jonathan Kew
26301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod * Google Author(s): Behdad Esfahbod
27aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew */
28aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
29027857d0412477fb4427dcb8a8c45287c272e143Behdad Esfahbod#define HB_SHAPER coretext
30301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod#include "hb-shaper-impl-private.hh"
31aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
32aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#include "hb-coretext.h"
33aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
34aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
35aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#ifndef HB_DEBUG_CORETEXT
36aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#define HB_DEBUG_CORETEXT (HB_DEBUG+0)
37aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#endif
38aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
39aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
40a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbodstatic void
41a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbodrelease_table_data (void *user_data)
42a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod{
43a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
44a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  CFRelease(cf_data);
45a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod}
46a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod
47a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbodstatic hb_blob_t *
48a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbodreference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
49a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod{
50a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
51a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
52a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  if (unlikely (!cf_data))
53a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod    return NULL;
54a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod
55a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
56a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  const size_t length = CFDataGetLength (cf_data);
57a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  if (!data || !length)
58a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod    return NULL;
59a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod
60a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
61a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod			 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
62a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod			 release_table_data);
63a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod}
64a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod
65a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbodhb_face_t *
66a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbodhb_coretext_face_create (CGFontRef cg_font)
67a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod{
68a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease);
69a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod}
70a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod
71a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod
72301168dae77a63ee25adfb26ce2b54a708f83791Behdad EsfahbodHB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
73301168dae77a63ee25adfb26ce2b54a708f83791Behdad EsfahbodHB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
74aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
75aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
76301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod/*
77301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod * shaper face data
78301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod */
79301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
80301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodstruct hb_coretext_shaper_face_data_t {
81301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  CGFontRef cg_font;
82301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod};
83aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
84aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewstatic void
85aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewrelease_data (void *info, const void *data, size_t size)
86aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
87aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
88aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew          hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
89aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
90aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  hb_blob_destroy ((hb_blob_t *) info);
91aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
92aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
93301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodhb_coretext_shaper_face_data_t *
94301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod_hb_coretext_shaper_face_data_create (hb_face_t *face)
95aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
96301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
97aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!data))
98301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    return NULL;
99aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
100a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  if (face->destroy == (hb_destroy_func_t) CGFontRelease)
101a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  {
102a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod    data->cg_font = CGFontRetain ((CGFontRef) face->user_data);
103a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  }
104a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  else
105a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  {
106a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod    hb_blob_t *blob = hb_face_reference_blob (face);
107a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod    unsigned int blob_length;
108a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod    const char *blob_data = hb_blob_get_data (blob, &blob_length);
109a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod    if (unlikely (!blob_length))
110a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod      DEBUG_MSG (CORETEXT, face, "Face has empty blob");
111a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod
112a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod    CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
113a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod    data->cg_font = CGFontCreateWithDataProvider (provider);
114a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod    CGDataProviderRelease (provider);
115a9e25e90a4ca05746fda4a598ad698db1d2c5c1aBehdad Esfahbod  }
116aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
117301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  if (unlikely (!data->cg_font)) {
118aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
119301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    free (data);
120301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    return NULL;
121aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
122aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
123aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return data;
124aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
125aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
126301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodvoid
127301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
128aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
129301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  CFRelease (data->cg_font);
130aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  free (data);
131aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
132aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
1339a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad EsfahbodCGFontRef
134e923e6487b25ab86f6f629af480b291e8e5407b5Behdad Esfahbodhb_coretext_face_get_cg_font (hb_face_t *face)
1359a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod{
1369a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
1379a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
1389a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod  return face_data->cg_font;
1399a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod}
1409a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod
141301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
142301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod/*
143301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod * shaper font data
144301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod */
145301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
146301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodstruct hb_coretext_shaper_font_data_t {
147301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  CTFontRef ct_font;
148301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod};
149301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
150301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodhb_coretext_shaper_font_data_t *
151301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod_hb_coretext_shaper_font_data_create (hb_font_t *font)
152aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
153301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
154aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
155301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
156aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!data))
157301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    return NULL;
158aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
159301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_face_t *face = font->face;
160301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
161aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
162aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL);
163301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  if (unlikely (!data->ct_font)) {
164aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
165301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    free (data);
166301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    return NULL;
167aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
168aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
169aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return data;
170aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
171aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
172301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodvoid
173301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
174301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod{
175301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  CFRelease (data->ct_font);
176301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  free (data);
177301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod}
178301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
179301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
180301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod/*
181301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod * shaper shape_plan data
182301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod */
183301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
184301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodstruct hb_coretext_shaper_shape_plan_data_t {};
185301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
186301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodhb_coretext_shaper_shape_plan_data_t *
18745c1383cc7315f89c23c0ed388b99e87224884e7Behdad Esfahbod_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
18845c1383cc7315f89c23c0ed388b99e87224884e7Behdad Esfahbod					     const hb_feature_t *user_features HB_UNUSED,
18945c1383cc7315f89c23c0ed388b99e87224884e7Behdad Esfahbod					     unsigned int        num_user_features HB_UNUSED)
190301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod{
191301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
192301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod}
193301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
194301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodvoid
19545c1383cc7315f89c23c0ed388b99e87224884e7Behdad Esfahbod_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
196301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod{
197301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod}
198301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
199aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan KewCTFontRef
200aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewhb_coretext_font_get_ct_font (hb_font_t *font)
201aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
2029a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
203301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
204aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return font_data->ct_font;
205aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
206aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
2079a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod
2089a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod/*
2099a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod * shaper
2109a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod */
2119a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod
2123613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstruct feature_record_t {
2133613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int feature;
2143613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int setting;
2153613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod};
2163613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
2173613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstruct active_feature_t {
2183613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  feature_record_t rec;
2193613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int order;
2203613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
2213613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  static int cmp (const active_feature_t *a, const active_feature_t *b) {
2223613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
2233613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	   a->order < b->order ? -1 : a->order > b->order ? 1 :
2243613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	   a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
2253613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	   0;
2263613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  }
2273613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  bool operator== (const active_feature_t *f) {
2283613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    return cmp (this, f) == 0;
2293613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  }
2303613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod};
2313613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
2323613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstruct feature_event_t {
2333613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int index;
2343613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  bool start;
2353613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  active_feature_t feature;
2363613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
2373613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  static int cmp (const feature_event_t *a, const feature_event_t *b) {
2383613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    return a->index < b->index ? -1 : a->index > b->index ? 1 :
2393613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	   a->start < b->start ? -1 : a->start > b->start ? 1 :
2403613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	   active_feature_t::cmp (&a->feature, &b->feature);
2413613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  }
2423613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod};
2433613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
2443613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstruct range_record_t {
2453613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  CTFontRef font;
2463613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int index_first; /* == start */
2473613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int index_last;  /* == end - 1 */
2483613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod};
2493613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
2503613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
2513613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod/* The following enum members are added in OS X 10.8. */
2523613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAltHalfWidthTextSelector		6
2533613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAltProportionalTextSelector		5
2543613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAlternateHorizKanaOffSelector		1
2553613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAlternateHorizKanaOnSelector		0
2563613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAlternateKanaType			34
2573613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAlternateVertKanaOffSelector		3
2583613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAlternateVertKanaOnSelector		2
2593613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kCaseSensitiveLayoutOffSelector		1
2603613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kCaseSensitiveLayoutOnSelector		0
2613613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kCaseSensitiveLayoutType		33
2623613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kCaseSensitiveSpacingOffSelector	3
2633613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kCaseSensitiveSpacingOnSelector		2
2643613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualAlternatesOffSelector	1
2653613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualAlternatesOnSelector		0
2663613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualAlternatesType		36
2673613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualLigaturesOffSelector		19
2683613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualLigaturesOnSelector		18
2693613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualSwashAlternatesOffSelector	5
2703613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualSwashAlternatesOnSelector	4
2713613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kDefaultLowerCaseSelector		0
2723613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kDefaultUpperCaseSelector		0
2733613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kHistoricalLigaturesOffSelector		21
2743613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kHistoricalLigaturesOnSelector		20
2753613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kHojoCharactersSelector			12
2763613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kJIS2004CharactersSelector		11
2773613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kLowerCasePetiteCapsSelector		2
2783613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kLowerCaseSmallCapsSelector		1
2793613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kLowerCaseType				37
2803613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kMathematicalGreekOffSelector		11
2813613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kMathematicalGreekOnSelector		10
2823613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kNLCCharactersSelector			13
2833613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kQuarterWidthTextSelector		4
2843613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kScientificInferiorsSelector		4
2853613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltEightOffSelector		17
2863613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltEightOnSelector		16
2873613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltEighteenOffSelector	37
2883613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltEighteenOnSelector		36
2893613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltElevenOffSelector		23
2903613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltElevenOnSelector		22
2913613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFifteenOffSelector		31
2923613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFifteenOnSelector		30
2933613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFiveOffSelector		11
2943613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFiveOnSelector		10
2953613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFourOffSelector		9
2963613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFourOnSelector		8
2973613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFourteenOffSelector	29
2983613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFourteenOnSelector		28
2993613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltNineOffSelector		19
3003613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltNineOnSelector		18
3013613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltNineteenOffSelector	39
3023613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltNineteenOnSelector		38
3033613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltOneOffSelector		3
3043613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltOneOnSelector		2
3053613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSevenOffSelector		15
3063613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSevenOnSelector		14
3073613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSeventeenOffSelector	35
3083613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSeventeenOnSelector	34
3093613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSixOffSelector		13
3103613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSixOnSelector		12
3113613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSixteenOffSelector		33
3123613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSixteenOnSelector		32
3133613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTenOffSelector		21
3143613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTenOnSelector		20
3153613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltThirteenOffSelector	27
3163613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltThirteenOnSelector		26
3173613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltThreeOffSelector		7
3183613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltThreeOnSelector		6
3193613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwelveOffSelector		25
3203613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwelveOnSelector		24
3213613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwentyOffSelector		41
3223613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwentyOnSelector		40
3233613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwoOffSelector		5
3243613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwoOnSelector		4
3253613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAlternativesType		35
3263613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kSwashAlternatesOffSelector		3
3273613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kSwashAlternatesOnSelector		2
3283613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kThirdWidthTextSelector			3
3293613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kTraditionalNamesCharactersSelector	14
3303613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kUpperCasePetiteCapsSelector		2
3313613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kUpperCaseSmallCapsSelector		1
3323613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kUpperCaseType				38
3333613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
3343613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod/* Table data courtesy of Apple. */
3353613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstruct feature_mapping_t {
3363613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    FourCharCode otFeatureTag;
3373613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    uint16_t aatFeatureType;
3383613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    uint16_t selectorToEnable;
3393613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    uint16_t selectorToDisable;
3403613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod} feature_mappings[] = {
3413613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'c2pc',   kUpperCaseType,             kUpperCasePetiteCapsSelector,           kDefaultUpperCaseSelector },
3423613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'c2sc',   kUpperCaseType,             kUpperCaseSmallCapsSelector,            kDefaultUpperCaseSelector },
3433613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'calt',   kContextualAlternatesType,  kContextualAlternatesOnSelector,        kContextualAlternatesOffSelector },
3443613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'case',   kCaseSensitiveLayoutType,   kCaseSensitiveLayoutOnSelector,         kCaseSensitiveLayoutOffSelector },
3453613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'clig',   kLigaturesType,             kContextualLigaturesOnSelector,         kContextualLigaturesOffSelector },
3463613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'cpsp',   kCaseSensitiveLayoutType,   kCaseSensitiveSpacingOnSelector,        kCaseSensitiveSpacingOffSelector },
3473613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'cswh',   kContextualAlternatesType,  kContextualSwashAlternatesOnSelector,   kContextualSwashAlternatesOffSelector },
3483613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'dlig',   kLigaturesType,             kRareLigaturesOnSelector,               kRareLigaturesOffSelector },
3493613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'expt',   kCharacterShapeType,        kExpertCharactersSelector,              16 },
3503613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'frac',   kFractionsType,             kDiagonalFractionsSelector,             kNoFractionsSelector },
3513613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'fwid',   kTextSpacingType,           kMonospacedTextSelector,                7 },
3523613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'halt',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
3533613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hist',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
3543613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hkna',   kAlternateKanaType,         kAlternateHorizKanaOnSelector,          kAlternateHorizKanaOffSelector, },
3553613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hlig',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
3563613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hngl',   kTransliterationType,       kHanjaToHangulSelector,                 kNoTransliterationSelector },
3573613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hojo',   kCharacterShapeType,        kHojoCharactersSelector,                16 },
3583613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hwid',   kTextSpacingType,           kHalfWidthTextSelector,                 7 },
3593613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ital',   kItalicCJKRomanType,        kCJKItalicRomanOnSelector,              kCJKItalicRomanOffSelector },
3603613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'jp04',   kCharacterShapeType,        kJIS2004CharactersSelector,             16 },
3613613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'jp78',   kCharacterShapeType,        kJIS1978CharactersSelector,             16 },
3623613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'jp83',   kCharacterShapeType,        kJIS1983CharactersSelector,             16 },
3633613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'jp90',   kCharacterShapeType,        kJIS1990CharactersSelector,             16 },
3643613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'liga',   kLigaturesType,             kCommonLigaturesOnSelector,             kCommonLigaturesOffSelector },
3653613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'lnum',   kNumberCaseType,            kUpperCaseNumbersSelector,              2 },
3663613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'mgrk',   kMathematicalExtrasType,    kMathematicalGreekOnSelector,           kMathematicalGreekOffSelector },
3673613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'nlck',   kCharacterShapeType,        kNLCCharactersSelector,                 16 },
3683613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'onum',   kNumberCaseType,            kLowerCaseNumbersSelector,              2 },
3693613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ordn',   kVerticalPositionType,      kOrdinalsSelector,                      kNormalPositionSelector },
3703613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'palt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
3713613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'pcap',   kLowerCaseType,             kLowerCasePetiteCapsSelector,           kDefaultLowerCaseSelector },
3723613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'pkna',   kTextSpacingType,           kProportionalTextSelector,              7 },
3733613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'pnum',   kNumberSpacingType,         kProportionalNumbersSelector,           4 },
3743613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'pwid',   kTextSpacingType,           kProportionalTextSelector,              7 },
3753613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'qwid',   kTextSpacingType,           kQuarterWidthTextSelector,              7 },
3763613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ruby',   kRubyKanaType,              kRubyKanaOnSelector,                    kRubyKanaOffSelector },
3773613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'sinf',   kVerticalPositionType,      kScientificInferiorsSelector,           kNormalPositionSelector },
3783613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'smcp',   kLowerCaseType,             kLowerCaseSmallCapsSelector,            kDefaultLowerCaseSelector },
3793613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'smpl',   kCharacterShapeType,        kSimplifiedCharactersSelector,          16 },
3803613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss01',   kStylisticAlternativesType, kStylisticAltOneOnSelector,             kStylisticAltOneOffSelector },
3813613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss02',   kStylisticAlternativesType, kStylisticAltTwoOnSelector,             kStylisticAltTwoOffSelector },
3823613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss03',   kStylisticAlternativesType, kStylisticAltThreeOnSelector,           kStylisticAltThreeOffSelector },
3833613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss04',   kStylisticAlternativesType, kStylisticAltFourOnSelector,            kStylisticAltFourOffSelector },
3843613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss05',   kStylisticAlternativesType, kStylisticAltFiveOnSelector,            kStylisticAltFiveOffSelector },
3853613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss06',   kStylisticAlternativesType, kStylisticAltSixOnSelector,             kStylisticAltSixOffSelector },
3863613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss07',   kStylisticAlternativesType, kStylisticAltSevenOnSelector,           kStylisticAltSevenOffSelector },
3873613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss08',   kStylisticAlternativesType, kStylisticAltEightOnSelector,           kStylisticAltEightOffSelector },
3883613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss09',   kStylisticAlternativesType, kStylisticAltNineOnSelector,            kStylisticAltNineOffSelector },
3893613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss10',   kStylisticAlternativesType, kStylisticAltTenOnSelector,             kStylisticAltTenOffSelector },
3903613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss11',   kStylisticAlternativesType, kStylisticAltElevenOnSelector,          kStylisticAltElevenOffSelector },
3913613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss12',   kStylisticAlternativesType, kStylisticAltTwelveOnSelector,          kStylisticAltTwelveOffSelector },
3923613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss13',   kStylisticAlternativesType, kStylisticAltThirteenOnSelector,        kStylisticAltThirteenOffSelector },
3933613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss14',   kStylisticAlternativesType, kStylisticAltFourteenOnSelector,        kStylisticAltFourteenOffSelector },
3943613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss15',   kStylisticAlternativesType, kStylisticAltFifteenOnSelector,         kStylisticAltFifteenOffSelector },
3953613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss16',   kStylisticAlternativesType, kStylisticAltSixteenOnSelector,         kStylisticAltSixteenOffSelector },
3963613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss17',   kStylisticAlternativesType, kStylisticAltSeventeenOnSelector,       kStylisticAltSeventeenOffSelector },
3973613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss18',   kStylisticAlternativesType, kStylisticAltEighteenOnSelector,        kStylisticAltEighteenOffSelector },
3983613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss19',   kStylisticAlternativesType, kStylisticAltNineteenOnSelector,        kStylisticAltNineteenOffSelector },
3993613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss20',   kStylisticAlternativesType, kStylisticAltTwentyOnSelector,          kStylisticAltTwentyOffSelector },
4003613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'subs',   kVerticalPositionType,      kInferiorsSelector,                     kNormalPositionSelector },
4013613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'sups',   kVerticalPositionType,      kSuperiorsSelector,                     kNormalPositionSelector },
4023613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'swsh',   kContextualAlternatesType,  kSwashAlternatesOnSelector,             kSwashAlternatesOffSelector },
4033613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'titl',   kStyleOptionsType,          kTitlingCapsSelector,                   kNoStyleOptionsSelector },
4043613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'tnam',   kCharacterShapeType,        kTraditionalNamesCharactersSelector,    16 },
4053613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'tnum',   kNumberSpacingType,         kMonospacedNumbersSelector,             4 },
4063613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'trad',   kCharacterShapeType,        kTraditionalCharactersSelector,         16 },
4073613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'twid',   kTextSpacingType,           kThirdWidthTextSelector,                7 },
4083613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'unic',   kLetterCaseType,            14,                                     15 },
4093613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'valt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
4103613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'vert',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
4113613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'vhal',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
4123613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'vkna',   kAlternateKanaType,         kAlternateVertKanaOnSelector,           kAlternateVertKanaOffSelector },
4133613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'vpal',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
4143613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'vrt2',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
4153613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'zero',   kTypographicExtrasType,     kSlashedZeroOnSelector,                 kSlashedZeroOffSelector },
4163613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod};
4173613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4183613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstatic int
4193613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod_hb_feature_mapping_cmp (const void *key_, const void *entry_)
4203613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod{
4213613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int key = * (unsigned int *) key_;
4223613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
4233613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  return key < entry->otFeatureTag ? -1 :
4243613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	 key > entry->otFeatureTag ? 1 :
4253613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	 0;
4263613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod}
4273613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
428aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewhb_bool_t
429301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod_hb_coretext_shape (hb_shape_plan_t    *shape_plan,
430301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod		    hb_font_t          *font,
431aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                    hb_buffer_t        *buffer,
432aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                    const hb_feature_t *features,
433aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                    unsigned int        num_features)
434aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
435301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_face_t *face = font->face;
43658cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
437301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
438aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
4393613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  /*
4403613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod   * Set up features.
4413613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod   * (copied + modified from code from hb-uniscribe.cc)
4423613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod   */
4433613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  hb_auto_array_t<feature_record_t> feature_records;
4443613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  hb_auto_array_t<range_record_t> range_records;
4453613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  if (num_features)
4463613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  {
4473613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    /* Sort features by start/end events. */
4483613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    hb_auto_array_t<feature_event_t> feature_events;
4493613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    for (unsigned int i = 0; i < num_features; i++)
4503613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    {
4513613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
4523613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod									       feature_mappings,
4533613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod									       ARRAY_LENGTH (feature_mappings),
4543613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod									       sizeof (feature_mappings[0]),
4553613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod									       _hb_feature_mapping_cmp);
4563613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (!mapping)
4573613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod        continue;
4583613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4593613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      active_feature_t feature;
4603613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.rec.feature = mapping->aatFeatureType;
4613613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
4623613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.order = i;
4633613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4643613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature_event_t *event;
4653613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4663613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event = feature_events.push ();
4673613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (unlikely (!event))
4683613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	goto fail_features;
4693613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->index = features[i].start;
4703613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->start = true;
4713613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->feature = feature;
4723613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4733613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event = feature_events.push ();
4743613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (unlikely (!event))
4753613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	goto fail_features;
4763613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->index = features[i].end;
4773613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->start = false;
4783613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->feature = feature;
4793613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    }
480fb8cc86ff99c08064ac58a559bb66cc340693b92Behdad Esfahbod    feature_events.qsort ();
4813613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    /* Add a strategic final event. */
4823613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    {
4833613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      active_feature_t feature;
4843613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.rec.feature = HB_TAG_NONE;
4853613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.rec.setting = 0;
4863613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.order = num_features + 1;
4873613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4883613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature_event_t *event = feature_events.push ();
4893613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (unlikely (!event))
4903613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	goto fail_features;
4913613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->index = 0; /* This value does magic. */
4923613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->start = false;
4933613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->feature = feature;
4943613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    }
4953613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4963613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    /* Scan events and save features for each range. */
4973613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    hb_auto_array_t<active_feature_t> active_features;
4983613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    unsigned int last_index = 0;
4993613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    for (unsigned int i = 0; i < feature_events.len; i++)
5003613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    {
5013613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature_event_t *event = &feature_events[i];
5023613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5033613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (event->index != last_index)
5043613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      {
5053613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod        /* Save a snapshot of active features and the range. */
5063613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	range_record_t *range = range_records.push ();
5073613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	if (unlikely (!range))
5083613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  goto fail_features;
5093613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5103613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	if (active_features.len)
5113613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	{
5123613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
5133613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5143613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  /* TODO sort and resolve conflicting features? */
515fb8cc86ff99c08064ac58a559bb66cc340693b92Behdad Esfahbod	  /* active_features.qsort (); */
5163613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  for (unsigned int j = 0; j < active_features.len; j++)
5173613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  {
5183613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFStringRef keys[2] = {
5193613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	      kCTFontFeatureTypeIdentifierKey,
5203613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	      kCTFontFeatureSelectorIdentifierKey
5213613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    };
5223613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFNumberRef values[2] = {
5233613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
5243613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
5253613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    };
5263613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
5273613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod						       (const void **) keys,
5283613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod						       (const void **) values,
5293613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod						       2,
5303613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod						       &kCFTypeDictionaryKeyCallBacks,
5313613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod						       &kCFTypeDictionaryValueCallBacks);
5323613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFRelease (values[0]);
5333613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFRelease (values[1]);
5343613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5353613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFArrayAppendValue (features_array, dict);
5363613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFRelease (dict);
5373613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5383613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  }
5393613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5403613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
5413613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod							   (const void **) &kCTFontFeatureSettingsAttribute,
5423613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod							   (const void **) &features_array,
5433613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod							   1,
5443613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod							   &kCFTypeDictionaryKeyCallBacks,
5453613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod							   &kCFTypeDictionaryValueCallBacks);
5463613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFRelease (features_array);
5473613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5483613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
5493613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFRelease (attributes);
5503613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5513613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
5523613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5533613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFRelease (font_desc);
5543613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	}
5553613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	else
5563613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	{
5573613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  range->font = NULL;
5583613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	}
5593613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5603613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	range->index_first = last_index;
5613613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	range->index_last  = event->index - 1;
5623613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5633613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	last_index = event->index;
5643613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      }
5653613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5663613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (event->start) {
5673613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod        active_feature_t *feature = active_features.push ();
5683613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	if (unlikely (!feature))
5693613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  goto fail_features;
5703613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	*feature = event->feature;
5713613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      } else {
5723613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod        active_feature_t *feature = active_features.find (&event->feature);
5733613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	if (feature)
5743613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  active_features.remove (feature - active_features.array);
5753613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      }
5763613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    }
5773613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5783613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    if (!range_records.len) /* No active feature found. */
5793613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      goto fail_features;
5803613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  }
5813613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  else
5823613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  {
5833613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  fail_features:
5843613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    num_features = 0;
5853613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  }
5863613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
587aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#define FAIL(...) \
588aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  HB_STMT_START { \
589aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
590aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    return false; \
591aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  } HB_STMT_END;
592aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
593aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int scratch_size;
59468c372ed2eac76a6d347811293fe2ba2fd6a1eedBehdad Esfahbod  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
5958fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod
5968fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod#define ALLOCATE_ARRAY(Type, name, len) \
5978fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod  Type *name = (Type *) scratch; \
5988fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod  { \
5998fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
6008fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod    assert (_consumed <= scratch_size); \
6018fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod    scratch += _consumed; \
6028fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod    scratch_size -= _consumed; \
6038fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod  }
604aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
605aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#define utf16_index() var1.u32
606aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
6078fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod  ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2);
6088fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod
609aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int chars_len = 0;
610aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  for (unsigned int i = 0; i < buffer->len; i++) {
611aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    hb_codepoint_t c = buffer->info[i].codepoint;
612aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    buffer->info[i].utf16_index() = chars_len;
6137627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod    if (likely (c <= 0xFFFFu))
614aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      pchars[chars_len++] = c;
6157627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod    else if (unlikely (c > 0x10FFFFu))
6167627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod      pchars[chars_len++] = 0xFFFDu;
617aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    else {
6187627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod      pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
6197627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod      pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
620aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
621aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
622aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
623aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#undef utf16_index
624aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
625a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL,
626aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                                               pchars, chars_len,
627aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                                               kCFAllocatorNull);
628aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
629a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NULL, chars_len);
630a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
631a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
632a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod				  kCTFontAttributeName, font_data->ct_font);
633a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod
6343613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  if (num_features)
635a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  {
6368fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod    ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len);
637a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod
6383613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    /* Need log_clusters to assign features. */
6393613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    chars_len = 0;
6403613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    for (unsigned int i = 0; i < buffer->len; i++)
641a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod    {
6423613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      hb_codepoint_t c = buffer->info[i].codepoint;
6433613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      unsigned int cluster = buffer->info[i].cluster;
6443613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      log_clusters[chars_len++] = cluster;
6457627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod      if (hb_in_range (c, 0x10000u, 0x10FFFFu))
6463613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	log_clusters[chars_len++] = cluster; /* Surrogates. */
647a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod    }
648aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
6493613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    unsigned int start = 0;
6503613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    range_record_t *last_range = &range_records[0];
6513613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    for (unsigned int k = 0; k < chars_len; k++)
652a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod    {
6533613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      range_record_t *range = last_range;
6543613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      while (log_clusters[k] < range->index_first)
6553613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	range--;
6563613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      while (log_clusters[k] > range->index_last)
6573613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	range++;
6583613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (range != last_range)
6593613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      {
6603613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod        if (last_range->font)
6613613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
6623613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod					  kCTFontAttributeName, last_range->font);
6633613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
6643613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	start = k;
6653613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      }
6663613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
6673613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      last_range = range;
668a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod    }
6693613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    if (start != chars_len && last_range->font)
6703613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start - 1),
6713613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod				      kCTFontAttributeName, last_range->font);
6723613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
6733613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    for (unsigned int i = 0; i < range_records.len; i++)
6743613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (range_records[i].font)
6753613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	CFRelease (range_records[i].font);
676a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  }
677aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
678aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CTLineRef line = CTLineCreateWithAttributedString (attr_string);
679aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CFRelease (attr_string);
680aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
681aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
682aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int num_runs = CFArrayGetCount (glyph_runs);
683aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
684aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  buffer->len = 0;
685aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
686aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  const CFRange range_all = CFRangeMake (0, 0);
687aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
68858cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod  for (unsigned int i = 0; i < num_runs; i++)
68958cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod  {
690aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i);
691aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
692c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    /* CoreText does automatic font fallback (AKA "cascading") for  characters
693c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny     * not supported by the requested font, and provides no way to turn it off,
694c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny     * so we detect if the returned run uses a font other than the requested
695c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny     * one and fill in the buffer with .notdef glyphs instead of random glyph
696c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny     * indices from a different font.
697c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny     */
698c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    CFDictionaryRef attributes = CTRunGetAttributes (run);
699c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
700c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
70158cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod    if (!CFEqual (run_cg_font, face_data->cg_font))
70258cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod    {
703c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny        CFRelease (run_cg_font);
70458cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod
70558cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	CFRange range = CTRunGetStringRange (run);
70658cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	buffer->ensure (buffer->len + range.length);
70758cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	if (buffer->in_error)
70858cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	  FAIL ("Buffer resize failed");
70958cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	hb_glyph_info_t *info = buffer->info + buffer->len;
71058cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod
711748b2782e4898420003a3bbc041dcccbe9e3edc2Behdad Esfahbod	CGGlyph notdef = 0;
712748b2782e4898420003a3bbc041dcccbe9e3edc2Behdad Esfahbod	double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, &notdef, NULL, 1);
713748b2782e4898420003a3bbc041dcccbe9e3edc2Behdad Esfahbod
714c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod        for (CFIndex j = range.location; j < range.location + range.length; j++)
71558cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	{
716c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	    UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
7177627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod	    if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
718c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	    {
719c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	      ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
7207627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod	      if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
721c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	        /* This is the second of a surrogate pair.  Don't need .notdef
722c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod		 * for this one. */
723c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	        continue;
724c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	    }
725c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod
726c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny            info->codepoint = notdef;
727aec468f01e866c99e65a8f764a792c74c96840d7Behdad Esfahbod	    /* TODO We have to fixup clusters later.  See vis_clusters in
728aec468f01e866c99e65a8f764a792c74c96840d7Behdad Esfahbod	     * hb-uniscribe.cc for example. */
729c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod            info->cluster = j;
730c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny
731c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny            info->mask = advance;
732c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny            info->var1.u32 = 0;
733c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny            info->var2.u32 = 0;
734c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny
73558cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	    info++;
736c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	    buffer->len++;
737c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny        }
738c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny        continue;
739c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    }
740c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    CFRelease (run_cg_font);
741c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny
742aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    unsigned int num_glyphs = CTRunGetGlyphCount (run);
743aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (num_glyphs == 0)
744aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      continue;
745aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
746aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    buffer->ensure (buffer->len + num_glyphs);
747aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
74868c372ed2eac76a6d347811293fe2ba2fd6a1eedBehdad Esfahbod    scratch = buffer->get_scratch_buffer (&scratch_size);
749aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
75016f175cb2e081e605fe7f9cd01bbe8c24380278aBehdad Esfahbod    /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always
75116f175cb2e081e605fe7f9cd01bbe8c24380278aBehdad Esfahbod     * succeed, and so copying data to our own buffer will be rare. */
752aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
753aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    const CGGlyph* glyphs = CTRunGetGlyphsPtr (run);
754aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (!glyphs) {
755aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs);
756aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      CTRunGetGlyphs (run, range_all, glyph_buf);
757aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      glyphs = glyph_buf;
758aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
759aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
760aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    const CGPoint* positions = CTRunGetPositionsPtr (run);
761aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (!positions) {
762aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs);
763aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      CTRunGetPositions (run, range_all, position_buf);
764aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      positions = position_buf;
765aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
766aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
767aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    const CFIndex* string_indices = CTRunGetStringIndicesPtr (run);
768aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (!string_indices) {
769aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs);
770aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      CTRunGetStringIndices (run, range_all, index_buf);
771aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      string_indices = index_buf;
772aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
773aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
774aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#undef ALLOCATE_ARRAY
775aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
776aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
777aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
778aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    for (unsigned int j = 0; j < num_glyphs; j++) {
779aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x;
780aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
781aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      hb_glyph_info_t *info = &buffer->info[buffer->len];
782aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
783aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->codepoint = glyphs[j];
784aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->cluster = string_indices[j];
785aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
7867d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod      /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
787aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->mask = advance;
788aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->var1.u32 = 0;
789aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->var2.u32 = positions[j].y;
790aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
791aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      buffer->len++;
792aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
793aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
794aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
795aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  buffer->clear_positions ();
796aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
797aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int count = buffer->len;
798aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  for (unsigned int i = 0; i < count; ++i) {
799aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    hb_glyph_info_t *info = &buffer->info[i];
800aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    hb_glyph_position_t *pos = &buffer->pos[i];
801aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
802aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    /* TODO vertical */
803aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    pos->x_advance = info->mask;
804aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    pos->x_offset = info->var1.u32;
805aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    pos->y_offset = info->var2.u32;
806aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
807aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
8087d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod  /* Fix up clusters so that we never return out-of-order indices;
8097d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   * if core text has reordered glyphs, we'll merge them to the
8107d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   * beginning of the reordered cluster.
8117d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   *
8127d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   * This does *not* mean we'll form the same clusters as Uniscribe
8137d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   * or the native OT backend, only that the cluster indices will be
8147d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   * monotonic in the output buffer. */
815ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
816ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    unsigned int prev_cluster = 0;
817ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    for (unsigned int i = 0; i < count; i++) {
818ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      unsigned int curr_cluster = buffer->info[i].cluster;
819ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      if (curr_cluster < prev_cluster) {
820ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        for (unsigned int j = i; j > 0; j--) {
821ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          if (buffer->info[j - 1].cluster > curr_cluster)
822ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            buffer->info[j - 1].cluster = curr_cluster;
823ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          else
824ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            break;
825ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        }
826ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      }
827ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      prev_cluster = curr_cluster;
828ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    }
829ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  } else {
830ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    unsigned int prev_cluster = (unsigned int)-1;
831ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    for (unsigned int i = 0; i < count; i++) {
832ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      unsigned int curr_cluster = buffer->info[i].cluster;
833ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      if (curr_cluster > prev_cluster) {
834ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        for (unsigned int j = i; j > 0; j--) {
835ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          if (buffer->info[j - 1].cluster < curr_cluster)
836ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            buffer->info[j - 1].cluster = curr_cluster;
837ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          else
838ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            break;
839ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        }
840ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      }
841ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      prev_cluster = curr_cluster;
842ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    }
843ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  }
844ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew
845c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod  CFRelease (string_ref);
846c461371419d186811d4bfc768e26535f48a807f4Behdad Esfahbod  CFRelease (line);
847c461371419d186811d4bfc768e26535f48a807f4Behdad Esfahbod
848aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return true;
849aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
850c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
851c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
852c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod/*
853c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod * AAT shaper
854c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod */
855c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
856c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad EsfahbodHB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
857c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad EsfahbodHB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
858c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
859c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
860c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod/*
861c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod * shaper face data
862c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod */
863c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
864c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbodstruct hb_coretext_aat_shaper_face_data_t {};
865c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
866c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbodhb_coretext_aat_shaper_face_data_t *
867c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
868c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod{
869c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod  hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
870c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod  /* Umm, we just reference the table to check whether it exists.
871c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod   * Maybe add better API for this? */
872c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod  if (!hb_blob_get_length (mort_blob))
873c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod  {
874c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod    hb_blob_destroy (mort_blob);
875c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod    mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
876c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod    if (!hb_blob_get_length (mort_blob))
877c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod    {
878c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod      hb_blob_destroy (mort_blob);
879c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod      return NULL;
880c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod    }
881c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod  }
882c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod  hb_blob_destroy (mort_blob);
883c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
884c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod  return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
885c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod}
886c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
887c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbodvoid
888c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
889c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod{
890c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod}
891c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
892c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
893c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod/*
894c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod * shaper font data
895c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod */
896c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
897c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbodstruct hb_coretext_aat_shaper_font_data_t {};
898c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
899c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbodhb_coretext_aat_shaper_font_data_t *
900c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
901c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod{
902c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod  return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
903c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod}
904c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
905c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbodvoid
906c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
907c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod{
908c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod}
909c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
910c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
911c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod/*
912c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod * shaper shape_plan data
913c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod */
914c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
915c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbodstruct hb_coretext_aat_shaper_shape_plan_data_t {};
916c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
917c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbodhb_coretext_aat_shaper_shape_plan_data_t *
918c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
919c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod					     const hb_feature_t *user_features HB_UNUSED,
920c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod					     unsigned int        num_user_features HB_UNUSED)
921c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod{
922c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod  return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
923c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod}
924c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
925c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbodvoid
926c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
927c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod{
928c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod}
929c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
930c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
931c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod/*
932c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod * shaper
933c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod */
934c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod
935c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbodhb_bool_t
936c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod_hb_coretext_aat_shape (hb_shape_plan_t    *shape_plan,
937c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod			hb_font_t          *font,
938c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod			hb_buffer_t        *buffer,
939c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod			const hb_feature_t *features,
940c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod			unsigned int        num_features)
941c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod{
942c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod  return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
943c79865f90f62309dc64c8d3f2f503ec2aa4b7ec1Behdad Esfahbod}
944