hb-coretext.cc revision ac2085d4b391b0a72473ecac3dd6c22efe66833f
1aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew/*
2aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * Copyright © 2012  Mozilla Foundation.
3aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *
4aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *  This is part of HarfBuzz, a text shaping library.
5aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *
6aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * Permission is hereby granted, without written agreement and without
7aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * license or royalty fees, to use, copy, modify, and distribute this
8aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * software and its documentation for any purpose, provided that the
9aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * above copyright notice and the following two paragraphs appear in
10aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * all copies of this software.
11aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *
12aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * DAMAGE.
17aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *
18aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew *
24aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew * Mozilla Author(s): Jonathan Kew
25aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew */
26aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
27aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#include "hb-private.hh"
28aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
29aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#define GlyphID GlyphID_mac
30aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#include <ApplicationServices/ApplicationServices.h>
31aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#undef GlyphID
32aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
33aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#include "hb-coretext.h"
34aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
35aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#include "hb-ot-name-table.hh"
36aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#include "hb-ot-tag.h"
37aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
38aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#include "hb-font-private.hh"
39aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#include "hb-buffer-private.hh"
40aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
41aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
42aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#ifndef HB_DEBUG_CORETEXT
43aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#define HB_DEBUG_CORETEXT (HB_DEBUG+0)
44aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#endif
45aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
46aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
47aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewstatic hb_user_data_key_t hb_coretext_data_key;
48aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
49aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewstatic struct hb_coretext_face_data_t {
50aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CGFontRef  cg_font;
51aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew} _hb_coretext_face_data_nil = {0};
52aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
53aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewstatic void
54aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew_hb_coretext_face_data_destroy (hb_coretext_face_data_t *data)
55aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
56aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (data->cg_font)
57aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    CFRelease (data->cg_font);
58aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  free (data);
59aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
60aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
61aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewstatic void
62aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewrelease_data (void *info, const void *data, size_t size)
63aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
64aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
65aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew          hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
66aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
67aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  hb_blob_destroy ((hb_blob_t *) info);
68aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
69aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
70aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewstatic hb_coretext_face_data_t *
71aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew_hb_coretext_face_get_data (hb_face_t *face)
72aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
73aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  hb_coretext_face_data_t *data = (hb_coretext_face_data_t *) hb_face_get_user_data (face, &hb_coretext_data_key);
74aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (likely (data)) return data;
75aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
76aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  data = (hb_coretext_face_data_t *) calloc (1, sizeof (hb_coretext_face_data_t));
77aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!data))
78aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    return &_hb_coretext_face_data_nil;
79aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
80aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
81aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  hb_blob_t *blob = hb_face_reference_blob (face);
82aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int blob_length;
83aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  const char *blob_data = hb_blob_get_data (blob, &blob_length);
84aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!blob_length))
85aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    DEBUG_MSG (CORETEXT, face, "Face has empty blob");
86aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
87aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
88aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  data->cg_font = CGFontCreateWithDataProvider (provider);
89aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CGDataProviderRelease (provider);
90aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
91aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!data->cg_font))
92aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
93aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
94aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
95aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!hb_face_set_user_data (face, &hb_coretext_data_key, data,
96aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                        (hb_destroy_func_t) _hb_coretext_face_data_destroy,
97aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                        false)))
98aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  {
99aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    _hb_coretext_face_data_destroy (data);
100aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    data = (hb_coretext_face_data_t *) hb_face_get_user_data (face, &hb_coretext_data_key);
101aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (data)
102aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      return data;
103aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    else
104aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      return &_hb_coretext_face_data_nil;
105aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
106aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
107aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return data;
108aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
109aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
110aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
111aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewstatic struct hb_coretext_font_data_t {
112aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CTFontRef ct_font;
113aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew} _hb_coretext_font_data_nil = {0};
114aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
115aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewstatic void
116aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew_hb_coretext_font_data_destroy (hb_coretext_font_data_t *data)
117aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
118aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (data->ct_font)
119aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    CFRelease (data->ct_font);
120aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  free (data);
121aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
122aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
123aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewstatic hb_coretext_font_data_t *
124aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew_hb_coretext_font_get_data (hb_font_t *font)
125aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
126aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  hb_coretext_font_data_t *data = (hb_coretext_font_data_t *) hb_font_get_user_data (font, &hb_coretext_data_key);
127aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (likely (data)) return data;
128aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
129aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  data = (hb_coretext_font_data_t *) calloc (1, sizeof (hb_coretext_font_data_t));
130aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!data))
131aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    return &_hb_coretext_font_data_nil;
132aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
133aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  hb_coretext_face_data_t *face_data = _hb_coretext_face_get_data (font->face);
134aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
135aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL);
136aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!data->ct_font))
137aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
138aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
139aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!hb_font_set_user_data (font, &hb_coretext_data_key, data,
140aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                        (hb_destroy_func_t) _hb_coretext_font_data_destroy,
141aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                        false)))
142aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  {
143aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    _hb_coretext_font_data_destroy (data);
144aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    data = (hb_coretext_font_data_t *) hb_font_get_user_data (font, &hb_coretext_data_key);
145aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (data)
146aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      return data;
147aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    else
148aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      return &_hb_coretext_font_data_nil;
149aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
150aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
151aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return data;
152aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
153aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
154aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan KewCTFontRef
155aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewhb_coretext_font_get_ct_font (hb_font_t *font)
156aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
157aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  hb_coretext_font_data_t *font_data = _hb_coretext_font_get_data (font);
158aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!font_data))
159aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    return 0;
160aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return font_data->ct_font;
161aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
162aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
163aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
164aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kewhb_bool_t
165aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew_hb_coretext_shape (hb_font_t          *font,
166aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                    hb_buffer_t        *buffer,
167aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                    const hb_feature_t *features,
168aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                    unsigned int        num_features)
169aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew{
170aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  buffer->guess_properties ();
171aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
172aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#define FAIL(...) \
173aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  HB_STMT_START { \
174aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
175aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    return false; \
176aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  } HB_STMT_END;
177aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
178aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  hb_coretext_face_data_t *face_data = _hb_coretext_face_get_data (font->face);
179aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!face_data->cg_font))
180aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    FAIL ("Couldn't get face data");
181aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
182aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  hb_coretext_font_data_t *font_data = _hb_coretext_font_get_data (font);
183aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!font_data->ct_font))
184aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    FAIL ("Couldn't get font font");
185aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
186aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  if (unlikely (!buffer->len))
187aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    return true;
188aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
189aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int scratch_size;
190aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
191aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
192aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#define utf16_index() var1.u32
193aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
194aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  UniChar *pchars = (UniChar *) scratch;
195aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int chars_len = 0;
196aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  for (unsigned int i = 0; i < buffer->len; i++) {
197aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    hb_codepoint_t c = buffer->info[i].codepoint;
198aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    buffer->info[i].utf16_index() = chars_len;
199aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (likely (c < 0x10000))
200aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      pchars[chars_len++] = c;
201aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    else if (unlikely (c >= 0x110000))
202aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      pchars[chars_len++] = 0xFFFD;
203aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    else {
204aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
205aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
206aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
207aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
208aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
209aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#undef utf16_index
210aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
211aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (kCFAllocatorDefault,
212aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                                               pchars, chars_len,
213aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                                               kCFAllocatorNull);
214aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
215aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CFDictionaryRef attrs = CFDictionaryCreate (kCFAllocatorDefault,
216aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                              (const void**) &kCTFontAttributeName,
217aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                              (const void**) &font_data->ct_font,
218aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                              1, // count of attributes
219aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                              &kCFTypeDictionaryKeyCallBacks,
220aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew                                              &kCFTypeDictionaryValueCallBacks);
221aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
222aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  // TODO: support features
223aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
224aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  // Now we can create an attributed string
225aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CFAttributedStringRef attr_string = CFAttributedStringCreate (kCFAllocatorDefault, string_ref, attrs);
226aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CFRelease (string_ref);
227aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CFRelease (attrs);
228aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
229aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  // Create the CoreText line from our string, then we're done with it
230aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CTLineRef line = CTLineCreateWithAttributedString (attr_string);
231aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CFRelease (attr_string);
232aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
233aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  // and finally retrieve the glyph data and store into the gfxTextRun
234aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
235aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int num_runs = CFArrayGetCount (glyph_runs);
236aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
237aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  // Iterate through the glyph runs.
238aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  bool success = true;
239aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  buffer->len = 0;
240aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
241aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  const CFRange range_all = CFRangeMake (0, 0);
242aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
243aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  for (unsigned int i = 0; i < num_runs; i++) {
244aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i);
245aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
246aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    unsigned int num_glyphs = CTRunGetGlyphCount (run);
247aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (num_glyphs == 0)
248aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      continue;
249aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
250aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    buffer->ensure (buffer->len + num_glyphs);
251aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
252aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    // retrieve the laid-out glyph data from the CTRun
253aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
254aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    // Testing indicates that CTRunGetGlyphsPtr (almost?) always succeeds,
255aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    // and so copying data to our own buffer with CTRunGetGlyphs will be
256aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    // extremely rare.
257aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
258aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    unsigned int scratch_size;
259aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
260aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
261aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#define ALLOCATE_ARRAY(Type, name, len) \
262aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  Type *name = (Type *) scratch; \
263441d3bb7de311d54b9f0a5210344f9a96e97e153Behdad Esfahbod  scratch += (len) * sizeof ((name)[0]); \
264441d3bb7de311d54b9f0a5210344f9a96e97e153Behdad Esfahbod  scratch_size -= (len) * sizeof ((name)[0]);
265aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
266aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    const CGGlyph* glyphs = CTRunGetGlyphsPtr (run);
267aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (!glyphs) {
268aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs);
269aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      CTRunGetGlyphs (run, range_all, glyph_buf);
270aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      glyphs = glyph_buf;
271aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
272aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
273aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    const CGPoint* positions = CTRunGetPositionsPtr (run);
274aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (!positions) {
275aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs);
276aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      CTRunGetPositions (run, range_all, position_buf);
277aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      positions = position_buf;
278aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
279aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
280aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    const CFIndex* string_indices = CTRunGetStringIndicesPtr (run);
281aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    if (!string_indices) {
282aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs);
283aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      CTRunGetStringIndices (run, range_all, index_buf);
284aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      string_indices = index_buf;
285aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
286aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
287aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew#undef ALLOCATE_ARRAY
288aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
289aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
290aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
291aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    for (unsigned int j = 0; j < num_glyphs; j++) {
292aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x;
293aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
294aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      hb_glyph_info_t *info = &buffer->info[buffer->len];
295aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      hb_glyph_position_t *pos = &buffer->pos[buffer->len];
296aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
297aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->codepoint = glyphs[j];
298aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->cluster = string_indices[j];
299aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
300aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      // currently, we do all x-positioning by setting the advance, we never use x-offset
301aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->mask = advance;
302aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->var1.u32 = 0;
303aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      info->var2.u32 = positions[j].y;
304aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
305aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew      buffer->len++;
306aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    }
307aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
308aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
309aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  buffer->clear_positions ();
310aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
311aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  unsigned int count = buffer->len;
312aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  for (unsigned int i = 0; i < count; ++i) {
313aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    hb_glyph_info_t *info = &buffer->info[i];
314aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    hb_glyph_position_t *pos = &buffer->pos[i];
315aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
316aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    /* TODO vertical */
317aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    pos->x_advance = info->mask;
318aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    pos->x_offset = info->var1.u32;
319aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew    pos->y_offset = info->var2.u32;
320aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  }
321aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew
322ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  // Fix up clusters so that we never return out-of-order indices;
323ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  // if core text has reordered glyphs, we'll merge them to the
324ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  // beginning of the reordered cluster.
325ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  // This does *not* mean we'll form the same clusters as Uniscribe
326ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  // or the native OT backend, only that the cluster indices will be
327ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  // non-decreasing in the output buffer.
328ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
329ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    unsigned int prev_cluster = 0;
330ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    for (unsigned int i = 0; i < count; i++) {
331ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      unsigned int curr_cluster = buffer->info[i].cluster;
332ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      if (curr_cluster < prev_cluster) {
333ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        for (unsigned int j = i; j > 0; j--) {
334ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          if (buffer->info[j - 1].cluster > curr_cluster)
335ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            buffer->info[j - 1].cluster = curr_cluster;
336ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          else
337ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            break;
338ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        }
339ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      }
340ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      prev_cluster = curr_cluster;
341ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    }
342ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  } else {
343ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    // For RTL runs, we make them non-increasing instead.
344ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    unsigned int prev_cluster = (unsigned int)-1;
345ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    for (unsigned int i = 0; i < count; i++) {
346ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      unsigned int curr_cluster = buffer->info[i].cluster;
347ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      if (curr_cluster > prev_cluster) {
348ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        for (unsigned int j = i; j > 0; j--) {
349ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          if (buffer->info[j - 1].cluster < curr_cluster)
350ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            buffer->info[j - 1].cluster = curr_cluster;
351ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew          else
352ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew            break;
353ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew        }
354ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      }
355ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew      prev_cluster = curr_cluster;
356ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew    }
357ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew  }
358ac2085d4b391b0a72473ecac3dd6c22efe66833fJonathan Kew
359aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew  return true;
360aa6d849838d5231465ae1a25a4dd5ea1e9380ff9Jonathan Kew}
361