hb-coretext.cc revision c29993a181c2139eaec97b5f6225824040ca3ac9
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
40301168dae77a63ee25adfb26ce2b54a708f83791Behdad EsfahbodHB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
41301168dae77a63ee25adfb26ce2b54a708f83791Behdad EsfahbodHB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
42aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
43aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
44301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod/*
45301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod * shaper face data
46301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod */
47301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
48301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodstruct hb_coretext_shaper_face_data_t {
49301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  CGFontRef cg_font;
50301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod};
51aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
52aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewstatic void
53aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewrelease_data (void *info, const void *data, size_t size)
54aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
55aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
56aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew          hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
57aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
58aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  hb_blob_destroy ((hb_blob_t *) info);
59aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
60aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
61301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodhb_coretext_shaper_face_data_t *
62301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod_hb_coretext_shaper_face_data_create (hb_face_t *face)
63aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
64301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
65aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!data))
66301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    return NULL;
67aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
68aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  hb_blob_t *blob = hb_face_reference_blob (face);
69aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int blob_length;
70aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  const char *blob_data = hb_blob_get_data (blob, &blob_length);
71aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!blob_length))
72aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    DEBUG_MSG (CORETEXT, face, "Face has empty blob");
73aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
74aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
75aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  data->cg_font = CGFontCreateWithDataProvider (provider);
76aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CGDataProviderRelease (provider);
77aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
78301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  if (unlikely (!data->cg_font)) {
79aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
80301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    free (data);
81301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    return NULL;
82aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
83aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
84aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return data;
85aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
86aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
87301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodvoid
88301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
89aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
90301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  CFRelease (data->cg_font);
91aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  free (data);
92aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
93aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
949a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad EsfahbodCGFontRef
95e923e6487b25ab86f6f629af480b291e8e5407b5Behdad Esfahbodhb_coretext_face_get_cg_font (hb_face_t *face)
969a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod{
979a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
989a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
999a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod  return face_data->cg_font;
1009a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod}
1019a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod
102301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
103301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod/*
104301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod * shaper font data
105301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod */
106301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
107301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodstruct hb_coretext_shaper_font_data_t {
108301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  CTFontRef ct_font;
109301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod};
110301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
111301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodhb_coretext_shaper_font_data_t *
112301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod_hb_coretext_shaper_font_data_create (hb_font_t *font)
113aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
114301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
115aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
116301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
117aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!data))
118301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    return NULL;
119aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
120301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_face_t *face = font->face;
121301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
122aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
123aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL);
124301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  if (unlikely (!data->ct_font)) {
125aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
126301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    free (data);
127301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod    return NULL;
128aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
129aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
130aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return data;
131aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
132aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
133301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodvoid
134301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
135301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod{
136301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  CFRelease (data->ct_font);
137301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  free (data);
138301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod}
139301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
140301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
141301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod/*
142301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod * shaper shape_plan data
143301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod */
144301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
145301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodstruct hb_coretext_shaper_shape_plan_data_t {};
146301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
147301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodhb_coretext_shaper_shape_plan_data_t *
14845c1383cc7315f89c23c0ed388b99e87224884e7Behdad Esfahbod_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
14945c1383cc7315f89c23c0ed388b99e87224884e7Behdad Esfahbod					     const hb_feature_t *user_features HB_UNUSED,
15045c1383cc7315f89c23c0ed388b99e87224884e7Behdad Esfahbod					     unsigned int        num_user_features HB_UNUSED)
151301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod{
152301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
153301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod}
154301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
155301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbodvoid
15645c1383cc7315f89c23c0ed388b99e87224884e7Behdad Esfahbod_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
157301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod{
158301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod}
159301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod
160aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan KewCTFontRef
161aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewhb_coretext_font_get_ct_font (hb_font_t *font)
162aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
1639a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
164301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
165aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return font_data->ct_font;
166aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
167aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
1689a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod
1699a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod/*
1709a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod * shaper
1719a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod */
1729a8395824bf51c2ff2cfe0887ecad52b3d2c02e2Behdad Esfahbod
1733613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstruct feature_record_t {
1743613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int feature;
1753613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int setting;
1763613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod};
1773613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
1783613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstruct active_feature_t {
1793613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  feature_record_t rec;
1803613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int order;
1813613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
1823613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  static int cmp (const active_feature_t *a, const active_feature_t *b) {
1833613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
1843613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	   a->order < b->order ? -1 : a->order > b->order ? 1 :
1853613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	   a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
1863613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	   0;
1873613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  }
1883613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  bool operator== (const active_feature_t *f) {
1893613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    return cmp (this, f) == 0;
1903613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  }
1913613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod};
1923613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
1933613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstruct feature_event_t {
1943613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int index;
1953613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  bool start;
1963613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  active_feature_t feature;
1973613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
1983613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  static int cmp (const feature_event_t *a, const feature_event_t *b) {
1993613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    return a->index < b->index ? -1 : a->index > b->index ? 1 :
2003613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	   a->start < b->start ? -1 : a->start > b->start ? 1 :
2013613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	   active_feature_t::cmp (&a->feature, &b->feature);
2023613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  }
2033613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod};
2043613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
2053613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstruct range_record_t {
2063613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  CTFontRef font;
2073613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int index_first; /* == start */
2083613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int index_last;  /* == end - 1 */
2093613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod};
2103613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
2113613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
2123613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod/* The following enum members are added in OS X 10.8. */
2133613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAltHalfWidthTextSelector		6
2143613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAltProportionalTextSelector		5
2153613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAlternateHorizKanaOffSelector		1
2163613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAlternateHorizKanaOnSelector		0
2173613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAlternateKanaType			34
2183613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAlternateVertKanaOffSelector		3
2193613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kAlternateVertKanaOnSelector		2
2203613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kCaseSensitiveLayoutOffSelector		1
2213613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kCaseSensitiveLayoutOnSelector		0
2223613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kCaseSensitiveLayoutType		33
2233613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kCaseSensitiveSpacingOffSelector	3
2243613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kCaseSensitiveSpacingOnSelector		2
2253613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualAlternatesOffSelector	1
2263613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualAlternatesOnSelector		0
2273613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualAlternatesType		36
2283613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualLigaturesOffSelector		19
2293613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualLigaturesOnSelector		18
2303613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualSwashAlternatesOffSelector	5
2313613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kContextualSwashAlternatesOnSelector	4
2323613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kDefaultLowerCaseSelector		0
2333613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kDefaultUpperCaseSelector		0
2343613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kHistoricalLigaturesOffSelector		21
2353613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kHistoricalLigaturesOnSelector		20
2363613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kHojoCharactersSelector			12
2373613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kJIS2004CharactersSelector		11
2383613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kLowerCasePetiteCapsSelector		2
2393613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kLowerCaseSmallCapsSelector		1
2403613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kLowerCaseType				37
2413613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kMathematicalGreekOffSelector		11
2423613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kMathematicalGreekOnSelector		10
2433613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kNLCCharactersSelector			13
2443613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kQuarterWidthTextSelector		4
2453613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kScientificInferiorsSelector		4
2463613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltEightOffSelector		17
2473613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltEightOnSelector		16
2483613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltEighteenOffSelector	37
2493613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltEighteenOnSelector		36
2503613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltElevenOffSelector		23
2513613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltElevenOnSelector		22
2523613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFifteenOffSelector		31
2533613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFifteenOnSelector		30
2543613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFiveOffSelector		11
2553613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFiveOnSelector		10
2563613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFourOffSelector		9
2573613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFourOnSelector		8
2583613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFourteenOffSelector	29
2593613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltFourteenOnSelector		28
2603613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltNineOffSelector		19
2613613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltNineOnSelector		18
2623613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltNineteenOffSelector	39
2633613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltNineteenOnSelector		38
2643613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltOneOffSelector		3
2653613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltOneOnSelector		2
2663613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSevenOffSelector		15
2673613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSevenOnSelector		14
2683613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSeventeenOffSelector	35
2693613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSeventeenOnSelector	34
2703613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSixOffSelector		13
2713613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSixOnSelector		12
2723613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSixteenOffSelector		33
2733613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltSixteenOnSelector		32
2743613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTenOffSelector		21
2753613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTenOnSelector		20
2763613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltThirteenOffSelector	27
2773613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltThirteenOnSelector		26
2783613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltThreeOffSelector		7
2793613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltThreeOnSelector		6
2803613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwelveOffSelector		25
2813613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwelveOnSelector		24
2823613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwentyOffSelector		41
2833613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwentyOnSelector		40
2843613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwoOffSelector		5
2853613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAltTwoOnSelector		4
2863613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kStylisticAlternativesType		35
2873613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kSwashAlternatesOffSelector		3
2883613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kSwashAlternatesOnSelector		2
2893613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kThirdWidthTextSelector			3
2903613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kTraditionalNamesCharactersSelector	14
2913613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kUpperCasePetiteCapsSelector		2
2923613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kUpperCaseSmallCapsSelector		1
2933613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod#define kUpperCaseType				38
2943613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
2953613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod/* Table data courtesy of Apple. */
2963613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstruct feature_mapping_t {
2973613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    FourCharCode otFeatureTag;
2983613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    uint16_t aatFeatureType;
2993613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    uint16_t selectorToEnable;
3003613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    uint16_t selectorToDisable;
3013613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod} feature_mappings[] = {
3023613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'c2pc',   kUpperCaseType,             kUpperCasePetiteCapsSelector,           kDefaultUpperCaseSelector },
3033613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'c2sc',   kUpperCaseType,             kUpperCaseSmallCapsSelector,            kDefaultUpperCaseSelector },
3043613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'calt',   kContextualAlternatesType,  kContextualAlternatesOnSelector,        kContextualAlternatesOffSelector },
3053613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'case',   kCaseSensitiveLayoutType,   kCaseSensitiveLayoutOnSelector,         kCaseSensitiveLayoutOffSelector },
3063613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'clig',   kLigaturesType,             kContextualLigaturesOnSelector,         kContextualLigaturesOffSelector },
3073613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'cpsp',   kCaseSensitiveLayoutType,   kCaseSensitiveSpacingOnSelector,        kCaseSensitiveSpacingOffSelector },
3083613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'cswh',   kContextualAlternatesType,  kContextualSwashAlternatesOnSelector,   kContextualSwashAlternatesOffSelector },
3093613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'dlig',   kLigaturesType,             kRareLigaturesOnSelector,               kRareLigaturesOffSelector },
3103613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'expt',   kCharacterShapeType,        kExpertCharactersSelector,              16 },
3113613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'frac',   kFractionsType,             kDiagonalFractionsSelector,             kNoFractionsSelector },
3123613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'fwid',   kTextSpacingType,           kMonospacedTextSelector,                7 },
3133613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'halt',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
3143613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hist',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
3153613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hkna',   kAlternateKanaType,         kAlternateHorizKanaOnSelector,          kAlternateHorizKanaOffSelector, },
3163613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hlig',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
3173613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hngl',   kTransliterationType,       kHanjaToHangulSelector,                 kNoTransliterationSelector },
3183613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hojo',   kCharacterShapeType,        kHojoCharactersSelector,                16 },
3193613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'hwid',   kTextSpacingType,           kHalfWidthTextSelector,                 7 },
3203613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ital',   kItalicCJKRomanType,        kCJKItalicRomanOnSelector,              kCJKItalicRomanOffSelector },
3213613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'jp04',   kCharacterShapeType,        kJIS2004CharactersSelector,             16 },
3223613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'jp78',   kCharacterShapeType,        kJIS1978CharactersSelector,             16 },
3233613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'jp83',   kCharacterShapeType,        kJIS1983CharactersSelector,             16 },
3243613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'jp90',   kCharacterShapeType,        kJIS1990CharactersSelector,             16 },
3253613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'liga',   kLigaturesType,             kCommonLigaturesOnSelector,             kCommonLigaturesOffSelector },
3263613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'lnum',   kNumberCaseType,            kUpperCaseNumbersSelector,              2 },
3273613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'mgrk',   kMathematicalExtrasType,    kMathematicalGreekOnSelector,           kMathematicalGreekOffSelector },
3283613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'nlck',   kCharacterShapeType,        kNLCCharactersSelector,                 16 },
3293613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'onum',   kNumberCaseType,            kLowerCaseNumbersSelector,              2 },
3303613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ordn',   kVerticalPositionType,      kOrdinalsSelector,                      kNormalPositionSelector },
3313613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'palt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
3323613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'pcap',   kLowerCaseType,             kLowerCasePetiteCapsSelector,           kDefaultLowerCaseSelector },
3333613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'pkna',   kTextSpacingType,           kProportionalTextSelector,              7 },
3343613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'pnum',   kNumberSpacingType,         kProportionalNumbersSelector,           4 },
3353613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'pwid',   kTextSpacingType,           kProportionalTextSelector,              7 },
3363613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'qwid',   kTextSpacingType,           kQuarterWidthTextSelector,              7 },
3373613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ruby',   kRubyKanaType,              kRubyKanaOnSelector,                    kRubyKanaOffSelector },
3383613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'sinf',   kVerticalPositionType,      kScientificInferiorsSelector,           kNormalPositionSelector },
3393613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'smcp',   kLowerCaseType,             kLowerCaseSmallCapsSelector,            kDefaultLowerCaseSelector },
3403613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'smpl',   kCharacterShapeType,        kSimplifiedCharactersSelector,          16 },
3413613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss01',   kStylisticAlternativesType, kStylisticAltOneOnSelector,             kStylisticAltOneOffSelector },
3423613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss02',   kStylisticAlternativesType, kStylisticAltTwoOnSelector,             kStylisticAltTwoOffSelector },
3433613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss03',   kStylisticAlternativesType, kStylisticAltThreeOnSelector,           kStylisticAltThreeOffSelector },
3443613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss04',   kStylisticAlternativesType, kStylisticAltFourOnSelector,            kStylisticAltFourOffSelector },
3453613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss05',   kStylisticAlternativesType, kStylisticAltFiveOnSelector,            kStylisticAltFiveOffSelector },
3463613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss06',   kStylisticAlternativesType, kStylisticAltSixOnSelector,             kStylisticAltSixOffSelector },
3473613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss07',   kStylisticAlternativesType, kStylisticAltSevenOnSelector,           kStylisticAltSevenOffSelector },
3483613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss08',   kStylisticAlternativesType, kStylisticAltEightOnSelector,           kStylisticAltEightOffSelector },
3493613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss09',   kStylisticAlternativesType, kStylisticAltNineOnSelector,            kStylisticAltNineOffSelector },
3503613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss10',   kStylisticAlternativesType, kStylisticAltTenOnSelector,             kStylisticAltTenOffSelector },
3513613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss11',   kStylisticAlternativesType, kStylisticAltElevenOnSelector,          kStylisticAltElevenOffSelector },
3523613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss12',   kStylisticAlternativesType, kStylisticAltTwelveOnSelector,          kStylisticAltTwelveOffSelector },
3533613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss13',   kStylisticAlternativesType, kStylisticAltThirteenOnSelector,        kStylisticAltThirteenOffSelector },
3543613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss14',   kStylisticAlternativesType, kStylisticAltFourteenOnSelector,        kStylisticAltFourteenOffSelector },
3553613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss15',   kStylisticAlternativesType, kStylisticAltFifteenOnSelector,         kStylisticAltFifteenOffSelector },
3563613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss16',   kStylisticAlternativesType, kStylisticAltSixteenOnSelector,         kStylisticAltSixteenOffSelector },
3573613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss17',   kStylisticAlternativesType, kStylisticAltSeventeenOnSelector,       kStylisticAltSeventeenOffSelector },
3583613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss18',   kStylisticAlternativesType, kStylisticAltEighteenOnSelector,        kStylisticAltEighteenOffSelector },
3593613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss19',   kStylisticAlternativesType, kStylisticAltNineteenOnSelector,        kStylisticAltNineteenOffSelector },
3603613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'ss20',   kStylisticAlternativesType, kStylisticAltTwentyOnSelector,          kStylisticAltTwentyOffSelector },
3613613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'subs',   kVerticalPositionType,      kInferiorsSelector,                     kNormalPositionSelector },
3623613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'sups',   kVerticalPositionType,      kSuperiorsSelector,                     kNormalPositionSelector },
3633613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'swsh',   kContextualAlternatesType,  kSwashAlternatesOnSelector,             kSwashAlternatesOffSelector },
3643613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'titl',   kStyleOptionsType,          kTitlingCapsSelector,                   kNoStyleOptionsSelector },
3653613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'tnam',   kCharacterShapeType,        kTraditionalNamesCharactersSelector,    16 },
3663613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'tnum',   kNumberSpacingType,         kMonospacedNumbersSelector,             4 },
3673613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'trad',   kCharacterShapeType,        kTraditionalCharactersSelector,         16 },
3683613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'twid',   kTextSpacingType,           kThirdWidthTextSelector,                7 },
3693613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'unic',   kLetterCaseType,            14,                                     15 },
3703613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'valt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
3713613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'vert',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
3723613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'vhal',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
3733613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'vkna',   kAlternateKanaType,         kAlternateVertKanaOnSelector,           kAlternateVertKanaOffSelector },
3743613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'vpal',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
3753613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'vrt2',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
3763613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    { 'zero',   kTypographicExtrasType,     kSlashedZeroOnSelector,                 kSlashedZeroOffSelector },
3773613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod};
3783613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
3793613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbodstatic int
3803613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod_hb_feature_mapping_cmp (const void *key_, const void *entry_)
3813613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod{
3823613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  unsigned int key = * (unsigned int *) key_;
3833613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
3843613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  return key < entry->otFeatureTag ? -1 :
3853613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	 key > entry->otFeatureTag ? 1 :
3863613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	 0;
3873613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod}
3883613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
389aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewhb_bool_t
390301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod_hb_coretext_shape (hb_shape_plan_t    *shape_plan,
391301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod		    hb_font_t          *font,
392aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                    hb_buffer_t        *buffer,
393aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                    const hb_feature_t *features,
394aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                    unsigned int        num_features)
395aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
396301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_face_t *face = font->face;
39758cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
398301168dae77a63ee25adfb26ce2b54a708f83791Behdad Esfahbod  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
399aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
4003613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  /*
4013613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod   * Set up features.
4023613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod   * (copied + modified from code from hb-uniscribe.cc)
4033613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod   */
4043613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  hb_auto_array_t<feature_record_t> feature_records;
4053613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  hb_auto_array_t<range_record_t> range_records;
4063613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  if (num_features)
4073613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  {
4083613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    /* Sort features by start/end events. */
4093613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    hb_auto_array_t<feature_event_t> feature_events;
4103613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    for (unsigned int i = 0; i < num_features; i++)
4113613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    {
4123613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
4133613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod									       feature_mappings,
4143613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod									       ARRAY_LENGTH (feature_mappings),
4153613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod									       sizeof (feature_mappings[0]),
4163613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod									       _hb_feature_mapping_cmp);
4173613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (!mapping)
4183613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod        continue;
4193613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4203613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      active_feature_t feature;
4213613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.rec.feature = mapping->aatFeatureType;
4223613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
4233613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.order = i;
4243613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4253613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature_event_t *event;
4263613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4273613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event = feature_events.push ();
4283613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (unlikely (!event))
4293613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	goto fail_features;
4303613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->index = features[i].start;
4313613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->start = true;
4323613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->feature = feature;
4333613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4343613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event = feature_events.push ();
4353613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (unlikely (!event))
4363613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	goto fail_features;
4373613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->index = features[i].end;
4383613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->start = false;
4393613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->feature = feature;
4403613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    }
4413613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    feature_events.sort ();
4423613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    /* Add a strategic final event. */
4433613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    {
4443613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      active_feature_t feature;
4453613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.rec.feature = HB_TAG_NONE;
4463613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.rec.setting = 0;
4473613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature.order = num_features + 1;
4483613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4493613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature_event_t *event = feature_events.push ();
4503613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (unlikely (!event))
4513613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	goto fail_features;
4523613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->index = 0; /* This value does magic. */
4533613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->start = false;
4543613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      event->feature = feature;
4553613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    }
4563613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4573613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    /* Scan events and save features for each range. */
4583613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    hb_auto_array_t<active_feature_t> active_features;
4593613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    unsigned int last_index = 0;
4603613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    for (unsigned int i = 0; i < feature_events.len; i++)
4613613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    {
4623613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      feature_event_t *event = &feature_events[i];
4633613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4643613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (event->index != last_index)
4653613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      {
4663613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod        /* Save a snapshot of active features and the range. */
4673613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	range_record_t *range = range_records.push ();
4683613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	if (unlikely (!range))
4693613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  goto fail_features;
4703613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4713613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	unsigned int offset = feature_records.len;
4723613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4733613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	if (active_features.len)
4743613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	{
4753613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
4763613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4773613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  /* TODO sort and resolve conflicting features? */
4783613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  /* active_features.sort (); */
4793613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  for (unsigned int j = 0; j < active_features.len; j++)
4803613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  {
4813613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFStringRef keys[2] = {
4823613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	      kCTFontFeatureTypeIdentifierKey,
4833613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	      kCTFontFeatureSelectorIdentifierKey
4843613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    };
4853613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFNumberRef values[2] = {
4863613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
4873613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
4883613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    };
4893613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
4903613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod						       (const void **) keys,
4913613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod						       (const void **) values,
4923613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod						       2,
4933613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod						       &kCFTypeDictionaryKeyCallBacks,
4943613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod						       &kCFTypeDictionaryValueCallBacks);
4953613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFRelease (values[0]);
4963613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFRelease (values[1]);
4973613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
4983613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFArrayAppendValue (features_array, dict);
4993613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	    CFRelease (dict);
5003613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5013613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  }
5023613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5033613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
5043613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod							   (const void **) &kCTFontFeatureSettingsAttribute,
5053613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod							   (const void **) &features_array,
5063613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod							   1,
5073613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod							   &kCFTypeDictionaryKeyCallBacks,
5083613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod							   &kCFTypeDictionaryValueCallBacks);
5093613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFRelease (features_array);
5103613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5113613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
5123613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFRelease (attributes);
5133613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5143613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
5153613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5163613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFRelease (font_desc);
5173613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	}
5183613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	else
5193613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	{
5203613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  range->font = NULL;
5213613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	}
5223613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5233613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	range->index_first = last_index;
5243613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	range->index_last  = event->index - 1;
5253613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5263613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	last_index = event->index;
5273613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      }
5283613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5293613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (event->start) {
5303613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod        active_feature_t *feature = active_features.push ();
5313613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	if (unlikely (!feature))
5323613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  goto fail_features;
5333613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	*feature = event->feature;
5343613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      } else {
5353613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod        active_feature_t *feature = active_features.find (&event->feature);
5363613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	if (feature)
5373613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  active_features.remove (feature - active_features.array);
5383613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      }
5393613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    }
5403613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
5413613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    if (!range_records.len) /* No active feature found. */
5423613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      goto fail_features;
5433613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  }
5443613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  else
5453613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  {
5463613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  fail_features:
5473613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    num_features = 0;
5483613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  }
5493613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
550aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#define FAIL(...) \
551aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  HB_STMT_START { \
552aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
553aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    return false; \
554aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  } HB_STMT_END;
555aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
556aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int scratch_size;
55768c372ed2eac76a6d347811293fe2ba2fd6a1eedBehdad Esfahbod  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
5588fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod
5598fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod#define ALLOCATE_ARRAY(Type, name, len) \
5608fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod  Type *name = (Type *) scratch; \
5618fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod  { \
5628fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
5638fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod    assert (_consumed <= scratch_size); \
5648fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod    scratch += _consumed; \
5658fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod    scratch_size -= _consumed; \
5668fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod  }
567aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
568aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#define utf16_index() var1.u32
569aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
5708fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod  ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2);
5718fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod
572aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int chars_len = 0;
573aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  for (unsigned int i = 0; i < buffer->len; i++) {
574aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    hb_codepoint_t c = buffer->info[i].codepoint;
575aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    buffer->info[i].utf16_index() = chars_len;
576aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (likely (c < 0x10000))
577aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      pchars[chars_len++] = c;
578aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    else if (unlikely (c >= 0x110000))
579aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      pchars[chars_len++] = 0xFFFD;
580aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    else {
581aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
582aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
583aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
584aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
585aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
586aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#undef utf16_index
587aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
588a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL,
589aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                                               pchars, chars_len,
590aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                                               kCFAllocatorNull);
591aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
592a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NULL, chars_len);
593a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
594a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
595a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod				  kCTFontAttributeName, font_data->ct_font);
596a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod
5973613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod  if (num_features)
598a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  {
5998fcadb9cf9418345610e3f4e38c28c12b768b589Behdad Esfahbod    ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len);
600a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod
6013613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    /* Need log_clusters to assign features. */
6023613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    chars_len = 0;
6033613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    for (unsigned int i = 0; i < buffer->len; i++)
604a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod    {
6053613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      hb_codepoint_t c = buffer->info[i].codepoint;
6063613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      unsigned int cluster = buffer->info[i].cluster;
6073613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      log_clusters[chars_len++] = cluster;
6083613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (c >= 0x10000 && c < 0x110000)
6093613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	log_clusters[chars_len++] = cluster; /* Surrogates. */
610a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod    }
611aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
6123613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    unsigned int start = 0;
6133613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    range_record_t *last_range = &range_records[0];
6143613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    for (unsigned int k = 0; k < chars_len; k++)
615a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod    {
6163613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      range_record_t *range = last_range;
6173613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      while (log_clusters[k] < range->index_first)
6183613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	range--;
6193613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      while (log_clusters[k] > range->index_last)
6203613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	range++;
6213613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (range != last_range)
6223613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      {
6233613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod        if (last_range->font)
6243613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	  CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
6253613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod					  kCTFontAttributeName, last_range->font);
6263613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
6273613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	start = k;
6283613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      }
6293613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
6303613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      last_range = range;
631a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod    }
6323613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    if (start != chars_len && last_range->font)
6333613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start - 1),
6343613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod				      kCTFontAttributeName, last_range->font);
6353613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod
6363613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod    for (unsigned int i = 0; i < range_records.len; i++)
6373613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod      if (range_records[i].font)
6383613696b57225111507a3f4263f5fa6937d0bc72Behdad Esfahbod	CFRelease (range_records[i].font);
639a782a5e9a37c8733ac2830410a514d38635b543aBehdad Esfahbod  }
640aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
641aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CTLineRef line = CTLineCreateWithAttributedString (attr_string);
642aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CFRelease (attr_string);
643aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
644aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
645aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int num_runs = CFArrayGetCount (glyph_runs);
646aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
647aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  buffer->len = 0;
648aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
649aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  const CFRange range_all = CFRangeMake (0, 0);
650aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
65158cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod  for (unsigned int i = 0; i < num_runs; i++)
65258cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod  {
653aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i);
654aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
655c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    /* CoreText does automatic font fallback (AKA "cascading") for  characters
656c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny     * not supported by the requested font, and provides no way to turn it off,
657c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny     * so we detect if the returned run uses a font other than the requested
658c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny     * one and fill in the buffer with .notdef glyphs instead of random glyph
659c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny     * indices from a different font.
660c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny     */
661c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    CFDictionaryRef attributes = CTRunGetAttributes (run);
662c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
663c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
66458cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod    if (!CFEqual (run_cg_font, face_data->cg_font))
66558cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod    {
666c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny        CFRelease (run_cg_font);
66758cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod
66858cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	CFRange range = CTRunGetStringRange (run);
66958cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	buffer->ensure (buffer->len + range.length);
67058cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	if (buffer->in_error)
67158cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	  FAIL ("Buffer resize failed");
67258cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	hb_glyph_info_t *info = buffer->info + buffer->len;
67358cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod
674748b2782e4898420003a3bbc041dcccbe9e3edc2Behdad Esfahbod	CGGlyph notdef = 0;
675748b2782e4898420003a3bbc041dcccbe9e3edc2Behdad Esfahbod	double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, &notdef, NULL, 1);
676748b2782e4898420003a3bbc041dcccbe9e3edc2Behdad Esfahbod
677c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod        for (CFIndex j = range.location; j < range.location + range.length; j++)
67858cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	{
679c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	    UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
680c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	    if (hb_in_range<UniChar> (ch, 0xDC00, 0xDFFF) && range.location < j)
681c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	    {
682c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	      ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
683c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	      if (hb_in_range<UniChar> (ch, 0xD800, 0xDBFF))
684c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	        /* This is the second of a surrogate pair.  Don't need .notdef
685c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod		 * for this one. */
686c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	        continue;
687c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	    }
688c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod
689c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny            info->codepoint = notdef;
690aec468f01e866c99e65a8f764a792c74c96840d7Behdad Esfahbod	    /* TODO We have to fixup clusters later.  See vis_clusters in
691aec468f01e866c99e65a8f764a792c74c96840d7Behdad Esfahbod	     * hb-uniscribe.cc for example. */
692c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod            info->cluster = j;
693c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny
694c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny            info->mask = advance;
695c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny            info->var1.u32 = 0;
696c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny            info->var2.u32 = 0;
697c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny
69858cc233e8b5fdc9dce603acc1b968540a2dea3e1Behdad Esfahbod	    info++;
699c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod	    buffer->len++;
700c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny        }
701c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny        continue;
702c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    }
703c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny    CFRelease (run_cg_font);
704c8213c6198abff97822e29a6d565722cfbb43832Khaled Hosny
705aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    unsigned int num_glyphs = CTRunGetGlyphCount (run);
706aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (num_glyphs == 0)
707aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      continue;
708aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
709aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    buffer->ensure (buffer->len + num_glyphs);
710aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
71168c372ed2eac76a6d347811293fe2ba2fd6a1eedBehdad Esfahbod    scratch = buffer->get_scratch_buffer (&scratch_size);
712aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
71316f175cb2e081e605fe7f9cd01bbe8c24380278aBehdad Esfahbod    /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always
71416f175cb2e081e605fe7f9cd01bbe8c24380278aBehdad Esfahbod     * succeed, and so copying data to our own buffer will be rare. */
715aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
716aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    const CGGlyph* glyphs = CTRunGetGlyphsPtr (run);
717aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (!glyphs) {
718aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs);
719aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      CTRunGetGlyphs (run, range_all, glyph_buf);
720aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      glyphs = glyph_buf;
721aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
722aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
723aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    const CGPoint* positions = CTRunGetPositionsPtr (run);
724aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (!positions) {
725aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs);
726aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      CTRunGetPositions (run, range_all, position_buf);
727aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      positions = position_buf;
728aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
729aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
730aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    const CFIndex* string_indices = CTRunGetStringIndicesPtr (run);
731aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (!string_indices) {
732aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs);
733aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      CTRunGetStringIndices (run, range_all, index_buf);
734aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      string_indices = index_buf;
735aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
736aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
737aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#undef ALLOCATE_ARRAY
738aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
739aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
740aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
741aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    for (unsigned int j = 0; j < num_glyphs; j++) {
742aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x;
743aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
744aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      hb_glyph_info_t *info = &buffer->info[buffer->len];
745aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
746aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->codepoint = glyphs[j];
747aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->cluster = string_indices[j];
748aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
7497d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod      /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
750aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->mask = advance;
751aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->var1.u32 = 0;
752aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->var2.u32 = positions[j].y;
753aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
754aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      buffer->len++;
755aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
756aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
757aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
758aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  buffer->clear_positions ();
759aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
760aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int count = buffer->len;
761aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  for (unsigned int i = 0; i < count; ++i) {
762aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    hb_glyph_info_t *info = &buffer->info[i];
763aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    hb_glyph_position_t *pos = &buffer->pos[i];
764aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
765aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    /* TODO vertical */
766aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    pos->x_advance = info->mask;
767aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    pos->x_offset = info->var1.u32;
768aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    pos->y_offset = info->var2.u32;
769aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
770aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
7717d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod  /* Fix up clusters so that we never return out-of-order indices;
7727d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   * if core text has reordered glyphs, we'll merge them to the
7737d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   * beginning of the reordered cluster.
7747d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   *
7757d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   * This does *not* mean we'll form the same clusters as Uniscribe
7767d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   * or the native OT backend, only that the cluster indices will be
7777d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod   * monotonic in the output buffer. */
778ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
779ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    unsigned int prev_cluster = 0;
780ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    for (unsigned int i = 0; i < count; i++) {
781ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      unsigned int curr_cluster = buffer->info[i].cluster;
782ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      if (curr_cluster < prev_cluster) {
783ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        for (unsigned int j = i; j > 0; j--) {
784ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          if (buffer->info[j - 1].cluster > curr_cluster)
785ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            buffer->info[j - 1].cluster = curr_cluster;
786ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          else
787ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            break;
788ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        }
789ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      }
790ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      prev_cluster = curr_cluster;
791ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    }
792ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  } else {
793ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    unsigned int prev_cluster = (unsigned int)-1;
794ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    for (unsigned int i = 0; i < count; i++) {
795ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      unsigned int curr_cluster = buffer->info[i].cluster;
796ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      if (curr_cluster > prev_cluster) {
797ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        for (unsigned int j = i; j > 0; j--) {
798ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          if (buffer->info[j - 1].cluster < curr_cluster)
799ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            buffer->info[j - 1].cluster = curr_cluster;
800ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          else
801ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            break;
802ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        }
803ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      }
804ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      prev_cluster = curr_cluster;
805ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    }
806ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  }
807ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew
808c29993a181c2139eaec97b5f6225824040ca3ac9Behdad Esfahbod  CFRelease (string_ref);
809c461371419d186811d4bfc768e26535f48a807f4Behdad Esfahbod  CFRelease (line);
810c461371419d186811d4bfc768e26535f48a807f4Behdad Esfahbod
811aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return true;
812aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
813