OLD | NEW |
1 /* | 1 /* |
2 * Copyright © 2012,2013 Mozilla Foundation. | 2 * Copyright © 2012,2013 Mozilla Foundation. |
3 * Copyright © 2012,2013 Google, Inc. | 3 * Copyright © 2012,2013 Google, Inc. |
4 * | 4 * |
5 * This is part of HarfBuzz, a text shaping library. | 5 * This is part of HarfBuzz, a text shaping library. |
6 * | 6 * |
7 * Permission is hereby granted, without written agreement and without | 7 * Permission is hereby granted, without written agreement and without |
8 * license or royalty fees, to use, copy, modify, and distribute this | 8 * license or royalty fees, to use, copy, modify, and distribute this |
9 * software and its documentation for any purpose, provided that the | 9 * software and its documentation for any purpose, provided that the |
10 * above copyright notice and the following two paragraphs appear in | 10 * above copyright notice and the following two paragraphs appear in |
11 * all copies of this software. | 11 * all copies of this software. |
12 * | 12 * |
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
17 * DAMAGE. | 17 * DAMAGE. |
18 * | 18 * |
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
24 * | 24 * |
25 * Mozilla Author(s): Jonathan Kew | 25 * Mozilla Author(s): Jonathan Kew |
26 * Google Author(s): Behdad Esfahbod | 26 * Google Author(s): Behdad Esfahbod |
27 */ | 27 */ |
28 | 28 |
29 #define HB_SHAPER coretext | 29 #define HB_SHAPER coretext |
30 #define hb_coretext_shaper_face_data_t CGFont | |
31 #include "hb-shaper-impl-private.hh" | 30 #include "hb-shaper-impl-private.hh" |
32 | 31 |
33 #include "hb-coretext.h" | 32 #include "hb-coretext.h" |
34 | 33 |
35 | 34 |
36 #ifndef HB_DEBUG_CORETEXT | 35 #ifndef HB_DEBUG_CORETEXT |
37 #define HB_DEBUG_CORETEXT (HB_DEBUG+0) | 36 #define HB_DEBUG_CORETEXT (HB_DEBUG+0) |
38 #endif | 37 #endif |
39 | 38 |
40 | 39 |
(...skipping 30 matching lines...) Expand all Loading... |
71 | 70 |
72 | 71 |
73 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) | 72 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) |
74 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) | 73 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) |
75 | 74 |
76 | 75 |
77 /* | 76 /* |
78 * shaper face data | 77 * shaper face data |
79 */ | 78 */ |
80 | 79 |
| 80 static CTFontDescriptorRef |
| 81 get_last_resort_font_desc (void) |
| 82 { |
| 83 // TODO Handle allocation failures? |
| 84 CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR
("LastResort"), 0); |
| 85 CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault, |
| 86 (const void **) &last_resort, |
| 87 1, |
| 88 &kCFTypeArrayCallBacks); |
| 89 CFRelease (last_resort); |
| 90 CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault, |
| 91 (const void **) &kCTFontCasca
deListAttribute, |
| 92 (const void **) &cascade_list
, |
| 93 1, |
| 94 &kCFTypeDictionaryKeyCallBack
s, |
| 95 &kCFTypeDictionaryValueCallBa
cks); |
| 96 CFRelease (cascade_list); |
| 97 |
| 98 CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attribut
es); |
| 99 CFRelease (attributes); |
| 100 return font_desc; |
| 101 } |
| 102 |
81 static void | 103 static void |
82 release_data (void *info, const void *data, size_t size) | 104 release_data (void *info, const void *data, size_t size) |
83 { | 105 { |
84 assert (hb_blob_get_length ((hb_blob_t *) info) == size && | 106 assert (hb_blob_get_length ((hb_blob_t *) info) == size && |
85 hb_blob_get_data ((hb_blob_t *) info, NULL) == data); | 107 hb_blob_get_data ((hb_blob_t *) info, NULL) == data); |
86 | 108 |
87 hb_blob_destroy ((hb_blob_t *) info); | 109 hb_blob_destroy ((hb_blob_t *) info); |
88 } | 110 } |
89 | 111 |
90 hb_coretext_shaper_face_data_t * | 112 static CGFontRef |
91 _hb_coretext_shaper_face_data_create (hb_face_t *face) | 113 create_cg_font (hb_face_t *face) |
92 { | 114 { |
93 hb_coretext_shaper_face_data_t *data = NULL; | 115 CGFontRef cg_font = NULL; |
94 | |
95 if (face->destroy == (hb_destroy_func_t) CGFontRelease) | 116 if (face->destroy == (hb_destroy_func_t) CGFontRelease) |
96 { | 117 { |
97 data = CGFontRetain ((CGFontRef) face->user_data); | 118 cg_font = CGFontRetain ((CGFontRef) face->user_data); |
98 } | 119 } |
99 else | 120 else |
100 { | 121 { |
101 hb_blob_t *blob = hb_face_reference_blob (face); | 122 hb_blob_t *blob = hb_face_reference_blob (face); |
102 unsigned int blob_length; | 123 unsigned int blob_length; |
103 const char *blob_data = hb_blob_get_data (blob, &blob_length); | 124 const char *blob_data = hb_blob_get_data (blob, &blob_length); |
104 if (unlikely (!blob_length)) | 125 if (unlikely (!blob_length)) |
105 DEBUG_MSG (CORETEXT, face, "Face has empty blob"); | 126 DEBUG_MSG (CORETEXT, face, "Face has empty blob"); |
106 | 127 |
107 CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data,
blob_length, &release_data); | 128 CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data,
blob_length, &release_data); |
108 if (likely (provider)) | 129 if (likely (provider)) |
109 { | 130 { |
110 data = CGFontCreateWithDataProvider (provider); | 131 cg_font = CGFontCreateWithDataProvider (provider); |
| 132 if (unlikely (!cg_font)) |
| 133 » DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed")
; |
111 CGDataProviderRelease (provider); | 134 CGDataProviderRelease (provider); |
112 } | 135 } |
113 } | 136 } |
| 137 return cg_font; |
| 138 } |
114 | 139 |
115 if (unlikely (!data)) { | 140 static CTFontRef |
116 DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); | 141 create_ct_font (CGFontRef cg_font, CGFloat font_size) |
| 142 { |
| 143 CTFontRef ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, NULL, NU
LL); |
| 144 if (unlikely (!ct_font)) { |
| 145 DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed"); |
| 146 return NULL; |
| 147 } |
| 148 |
| 149 /* Create font copy with cascade list that has LastResort first; this speeds u
p CoreText |
| 150 * font fallback which we don't need anyway. */ |
| 151 { |
| 152 CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc (); |
| 153 CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, NULL,
last_resort_font_desc); |
| 154 CFRelease (last_resort_font_desc); |
| 155 if (new_ct_font) |
| 156 { |
| 157 CFRelease (ct_font); |
| 158 ct_font = new_ct_font; |
| 159 } |
| 160 else |
| 161 DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed"); |
| 162 } |
| 163 |
| 164 return ct_font; |
| 165 } |
| 166 |
| 167 struct hb_coretext_shaper_face_data_t { |
| 168 CGFontRef cg_font; |
| 169 CTFontRef ct_font; |
| 170 }; |
| 171 |
| 172 hb_coretext_shaper_face_data_t * |
| 173 _hb_coretext_shaper_face_data_create (hb_face_t *face) |
| 174 { |
| 175 hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) call
oc (1, sizeof (hb_coretext_shaper_face_data_t)); |
| 176 if (unlikely (!data)) |
| 177 return NULL; |
| 178 |
| 179 data->cg_font = create_cg_font (face); |
| 180 if (unlikely (!data->cg_font)) |
| 181 { |
| 182 DEBUG_MSG (CORETEXT, face, "CGFont creation failed.."); |
| 183 free (data); |
| 184 return NULL; |
| 185 } |
| 186 |
| 187 /* We use 36pt size instead of UPEM, because CoreText implements the 'trak' ta
ble, |
| 188 * which can make the font too tight at large sizes. 36pt should be a good se
mi-neutral |
| 189 * size. |
| 190 * |
| 191 * Since we always create CTFont at a fixed size, our CTFont lives in face_dat
a |
| 192 * instead of font_data. Which is good, because when people change scale on |
| 193 * hb_font_t, we won't need to update our CTFont. */ |
| 194 data->ct_font = create_ct_font (data->cg_font, 36.); |
| 195 if (unlikely (!data->ct_font)) |
| 196 { |
| 197 DEBUG_MSG (CORETEXT, face, "CTFont creation failed."); |
| 198 CFRelease (data->cg_font); |
| 199 free (data); |
| 200 return NULL; |
117 } | 201 } |
118 | 202 |
119 return data; | 203 return data; |
120 } | 204 } |
121 | 205 |
122 void | 206 void |
123 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) | 207 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) |
124 { | 208 { |
125 CFRelease (data); | 209 CFRelease (data->ct_font); |
| 210 CFRelease (data->cg_font); |
| 211 free (data); |
126 } | 212 } |
127 | 213 |
128 /* | 214 /* |
129 * Since: 0.9.10 | 215 * Since: 0.9.10 |
130 */ | 216 */ |
131 CGFontRef | 217 CGFontRef |
132 hb_coretext_face_get_cg_font (hb_face_t *face) | 218 hb_coretext_face_get_cg_font (hb_face_t *face) |
133 { | 219 { |
134 if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; | 220 if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; |
135 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); | 221 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); |
136 return face_data; | 222 return face_data->cg_font; |
137 } | 223 } |
138 | 224 |
139 | 225 |
140 /* | 226 /* |
141 * shaper font data | 227 * shaper font data |
142 */ | 228 */ |
143 | 229 |
144 struct hb_coretext_shaper_font_data_t { | 230 struct hb_coretext_shaper_font_data_t {}; |
145 CTFontRef ct_font; | |
146 CGFloat x_mult, y_mult; /* From CT space to HB space. */ | |
147 }; | |
148 | 231 |
149 hb_coretext_shaper_font_data_t * | 232 hb_coretext_shaper_font_data_t * |
150 _hb_coretext_shaper_font_data_create (hb_font_t *font) | 233 _hb_coretext_shaper_font_data_create (hb_font_t *font HB_UNUSED) |
151 { | 234 { |
152 if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL; | 235 return (hb_coretext_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; |
153 | |
154 hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) call
oc (1, sizeof (hb_coretext_shaper_font_data_t)); | |
155 if (unlikely (!data)) | |
156 return NULL; | |
157 | |
158 hb_face_t *face = font->face; | |
159 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); | |
160 | |
161 /* Choose a CoreText font size and calculate multipliers to convert to HarfBuz
z space. */ | |
162 /* TODO: use upem instead of 36? */ | |
163 CGFloat font_size = 36.; /* Default... */ | |
164 /* No idea if the following is even a good idea. */ | |
165 if (font->y_ppem) | |
166 font_size = font->y_ppem; | |
167 | |
168 if (font_size < 0) | |
169 font_size = -font_size; | |
170 data->x_mult = (CGFloat) font->x_scale / font_size; | |
171 data->y_mult = (CGFloat) font->y_scale / font_size; | |
172 data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL
); | |
173 if (unlikely (!data->ct_font)) { | |
174 DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); | |
175 free (data); | |
176 return NULL; | |
177 } | |
178 | |
179 /* Create font copy with cascade list that has LastResort first; this speeds u
p CoreText | |
180 * font fallback which we don't need anyway. */ | |
181 { | |
182 // TODO Handle allocation failures? | |
183 CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize(CFST
R("LastResort"), 0); | |
184 CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault, | |
185 » » » » » (const void **) &last_resort, | |
186 » » » » » 1, | |
187 » » » » » &kCFTypeArrayCallBacks); | |
188 CFRelease (last_resort); | |
189 CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault, | |
190 » » » » » » (const void **) &kCTFontCas
cadeListAttribute, | |
191 » » » » » » (const void **) &cascade_li
st, | |
192 » » » » » » 1, | |
193 » » » » » » &kCFTypeDictionaryKeyCallBa
cks, | |
194 » » » » » » &kCFTypeDictionaryValueCall
Backs); | |
195 CFRelease (cascade_list); | |
196 | |
197 CTFontDescriptorRef new_font_desc = CTFontDescriptorCreateWithAttributes (at
tributes); | |
198 CFRelease (attributes); | |
199 | |
200 CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (data->ct_font, 0.0,
NULL, new_font_desc); | |
201 if (new_ct_font) | |
202 { | |
203 CFRelease (data->ct_font); | |
204 data->ct_font = new_ct_font; | |
205 } | |
206 else | |
207 DEBUG_MSG (CORETEXT, font, "Font copy with empty cascade list failed"); | |
208 } | |
209 | |
210 if (unlikely (!data->ct_font)) { | |
211 DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); | |
212 free (data); | |
213 return NULL; | |
214 } | |
215 | |
216 return data; | |
217 } | 236 } |
218 | 237 |
219 void | 238 void |
220 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data) | 239 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data) |
221 { | 240 { |
222 CFRelease (data->ct_font); | |
223 free (data); | |
224 } | 241 } |
225 | 242 |
226 | 243 |
227 /* | 244 /* |
228 * shaper shape_plan data | 245 * shaper shape_plan data |
229 */ | 246 */ |
230 | 247 |
231 struct hb_coretext_shaper_shape_plan_data_t {}; | 248 struct hb_coretext_shaper_shape_plan_data_t {}; |
232 | 249 |
233 hb_coretext_shaper_shape_plan_data_t * | 250 hb_coretext_shaper_shape_plan_data_t * |
234 _hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UN
USED, | 251 _hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UN
USED, |
235 const hb_feature_t *user_features H
B_UNUSED, | 252 const hb_feature_t *user_features H
B_UNUSED, |
236 unsigned int num_user_featur
es HB_UNUSED) | 253 unsigned int num_user_featur
es HB_UNUSED) |
237 { | 254 { |
238 return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; | 255 return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; |
239 } | 256 } |
240 | 257 |
241 void | 258 void |
242 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_
t *data HB_UNUSED) | 259 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_
t *data HB_UNUSED) |
243 { | 260 { |
244 } | 261 } |
245 | 262 |
246 CTFontRef | 263 CTFontRef |
247 hb_coretext_font_get_ct_font (hb_font_t *font) | 264 hb_coretext_font_get_ct_font (hb_font_t *font) |
248 { | 265 { |
249 if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL; | 266 hb_face_t *face = font->face; |
250 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); | 267 if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; |
251 return font_data->ct_font; | 268 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); |
| 269 return face_data->ct_font; |
252 } | 270 } |
253 | 271 |
254 | 272 |
255 /* | 273 /* |
256 * shaper | 274 * shaper |
257 */ | 275 */ |
258 | 276 |
259 struct feature_record_t { | 277 struct feature_record_t { |
260 unsigned int feature; | 278 unsigned int feature; |
261 unsigned int setting; | 279 unsigned int setting; |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 | 492 |
475 hb_bool_t | 493 hb_bool_t |
476 _hb_coretext_shape (hb_shape_plan_t *shape_plan, | 494 _hb_coretext_shape (hb_shape_plan_t *shape_plan, |
477 hb_font_t *font, | 495 hb_font_t *font, |
478 hb_buffer_t *buffer, | 496 hb_buffer_t *buffer, |
479 const hb_feature_t *features, | 497 const hb_feature_t *features, |
480 unsigned int num_features) | 498 unsigned int num_features) |
481 { | 499 { |
482 hb_face_t *face = font->face; | 500 hb_face_t *face = font->face; |
483 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); | 501 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); |
484 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); | 502 |
| 503 CGFloat ct_font_size = CTFontGetSize (face_data->ct_font); |
| 504 CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size; |
| 505 CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size; |
485 | 506 |
486 /* Attach marks to their bases, to match the 'ot' shaper. | 507 /* Attach marks to their bases, to match the 'ot' shaper. |
487 * Adapted from hb-ot-shape:hb_form_clusters(). | 508 * Adapted from hb-ot-shape:hb_form_clusters(). |
488 * Note that this only makes us be closer to the 'ot' shaper, | 509 * Note that this only makes us be closer to the 'ot' shaper, |
489 * but by no means the same. For example, if there's | 510 * but by no means the same. For example, if there's |
490 * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will | 511 * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will |
491 * continue pointing to B2 even though B2 was merged into B1's | 512 * continue pointing to B2 even though B2 was merged into B1's |
492 * cluster... */ | 513 * cluster... */ |
| 514 if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) |
493 { | 515 { |
494 hb_unicode_funcs_t *unicode = buffer->unicode; | 516 hb_unicode_funcs_t *unicode = buffer->unicode; |
495 unsigned int count = buffer->len; | 517 unsigned int count = buffer->len; |
496 hb_glyph_info_t *info = buffer->info; | 518 hb_glyph_info_t *info = buffer->info; |
497 for (unsigned int i = 1; i < count; i++) | 519 for (unsigned int i = 1; i < count; i++) |
498 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i
].codepoint))) | 520 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i
].codepoint))) |
499 buffer->merge_clusters (i - 1, i + 1); | 521 buffer->merge_clusters (i - 1, i + 1); |
500 } | 522 } |
501 | 523 |
502 hb_auto_array_t<feature_record_t> feature_records; | 524 hb_auto_array_t<feature_record_t> feature_records; |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 (const void **) &kCTF
ontFeatureSettingsAttribute, | 627 (const void **) &kCTF
ontFeatureSettingsAttribute, |
606 (const void **) &feat
ures_array, | 628 (const void **) &feat
ures_array, |
607 1, | 629 1, |
608 &kCFTypeDictionaryKey
CallBacks, | 630 &kCFTypeDictionaryKey
CallBacks, |
609 &kCFTypeDictionaryVal
ueCallBacks); | 631 &kCFTypeDictionaryVal
ueCallBacks); |
610 CFRelease (features_array); | 632 CFRelease (features_array); |
611 | 633 |
612 CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (
attributes); | 634 CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (
attributes); |
613 CFRelease (attributes); | 635 CFRelease (attributes); |
614 | 636 |
615 » range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0,
NULL, font_desc); | 637 » range->font = CTFontCreateCopyWithAttributes (face_data->ct_font, 0.0,
NULL, font_desc); |
616 CFRelease (font_desc); | 638 CFRelease (font_desc); |
617 } | 639 } |
618 else | 640 else |
619 { | 641 { |
620 range->font = NULL; | 642 range->font = NULL; |
621 } | 643 } |
622 | 644 |
623 range->index_first = last_index; | 645 range->index_first = last_index; |
624 range->index_last = event->index - 1; | 646 range->index_last = event->index - 1; |
625 | 647 |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
762 hb_language_to_strin
g (buffer->props.language), | 784 hb_language_to_strin
g (buffer->props.language), |
763 kCFStringEncodingUTF
8, | 785 kCFStringEncodingUTF
8, |
764 kCFAllocatorNull); | 786 kCFAllocatorNull); |
765 if (unlikely (!lang)) | 787 if (unlikely (!lang)) |
766 FAIL ("CFStringCreateWithCStringNoCopy failed"); | 788 FAIL ("CFStringCreateWithCStringNoCopy failed"); |
767 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), | 789 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), |
768 kCTLanguageAttributeName, lang); | 790 kCTLanguageAttributeName, lang); |
769 CFRelease (lang); | 791 CFRelease (lang); |
770 } | 792 } |
771 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), | 793 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), |
772 » » » » kCTFontAttributeName, font_data->ct_font); | 794 » » » » kCTFontAttributeName, face_data->ct_font); |
773 | 795 |
774 if (num_features) | 796 if (num_features) |
775 { | 797 { |
776 unsigned int start = 0; | 798 unsigned int start = 0; |
777 range_record_t *last_range = &range_records[0]; | 799 range_record_t *last_range = &range_records[0]; |
778 for (unsigned int k = 0; k < chars_len; k++) | 800 for (unsigned int k = 0; k < chars_len; k++) |
779 { | 801 { |
780 range_record_t *range = last_range; | 802 range_record_t *range = last_range; |
781 while (log_clusters[k] < range->index_first) | 803 while (log_clusters[k] < range->index_first) |
782 range--; | 804 range--; |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
855 DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance); | 877 DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance); |
856 | 878 |
857 /* CoreText does automatic font fallback (AKA "cascading") for characters | 879 /* CoreText does automatic font fallback (AKA "cascading") for characters |
858 * not supported by the requested font, and provides no way to turn it off
, | 880 * not supported by the requested font, and provides no way to turn it off
, |
859 * so we must detect if the returned run uses a font other than the reques
ted | 881 * so we must detect if the returned run uses a font other than the reques
ted |
860 * one and fill in the buffer with .notdef glyphs instead of random glyph | 882 * one and fill in the buffer with .notdef glyphs instead of random glyph |
861 * indices from a different font. | 883 * indices from a different font. |
862 */ | 884 */ |
863 CFDictionaryRef attributes = CTRunGetAttributes (run); | 885 CFDictionaryRef attributes = CTRunGetAttributes (run); |
864 CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attri
butes, kCTFontAttributeName)); | 886 CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attri
butes, kCTFontAttributeName)); |
865 if (!CFEqual (run_ct_font, font_data->ct_font)) | 887 if (!CFEqual (run_ct_font, face_data->ct_font)) |
866 { | 888 { |
867 /* The run doesn't use our main font instance. We have to figure out | 889 /* The run doesn't use our main font instance. We have to figure out |
868 * whether font fallback happened, or this is just CoreText giving us | 890 * whether font fallback happened, or this is just CoreText giving us |
869 * another CTFont using the same underlying CGFont. CoreText seems | 891 * another CTFont using the same underlying CGFont. CoreText seems |
870 * to do that in a variety of situations, one of which being vertical | 892 * to do that in a variety of situations, one of which being vertical |
871 * text, but also perhaps for caching reasons. | 893 * text, but also perhaps for caching reasons. |
872 * | 894 * |
873 * First, see if it uses any of our subfonts created to set font feature
s... | 895 * First, see if it uses any of our subfonts created to set font feature
s... |
874 * | 896 * |
875 * Next, compare the CGFont to the one we used to create our fonts. | 897 * Next, compare the CGFont to the one we used to create our fonts. |
(...skipping 19 matching lines...) Expand all Loading... |
895 if (range_records[i].font && CFEqual (run_ct_font, range_records[i].fo
nt)) | 917 if (range_records[i].font && CFEqual (run_ct_font, range_records[i].fo
nt)) |
896 { | 918 { |
897 matched = true; | 919 matched = true; |
898 break; | 920 break; |
899 } | 921 } |
900 if (!matched) | 922 if (!matched) |
901 { | 923 { |
902 CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0); | 924 CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0); |
903 if (run_cg_font) | 925 if (run_cg_font) |
904 { | 926 { |
905 » matched = CFEqual (run_cg_font, face_data); | 927 » matched = CFEqual (run_cg_font, face_data->cg_font); |
906 CFRelease (run_cg_font); | 928 CFRelease (run_cg_font); |
907 } | 929 } |
908 } | 930 } |
909 if (!matched) | 931 if (!matched) |
910 { | 932 { |
911 » CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFont
PostScriptNameKey); | 933 » CFStringRef font_ps_name = CTFontCopyName (face_data->ct_font, kCTFont
PostScriptNameKey); |
912 CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScri
ptNameKey); | 934 CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScri
ptNameKey); |
913 CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name
, 0); | 935 CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name
, 0); |
914 CFRelease (run_ps_name); | 936 CFRelease (run_ps_name); |
915 CFRelease (font_ps_name); | 937 CFRelease (font_ps_name); |
916 if (result == kCFCompareEqualTo) | 938 if (result == kCFCompareEqualTo) |
917 matched = true; | 939 matched = true; |
918 } | 940 } |
919 if (!matched) | 941 if (!matched) |
920 { | 942 { |
921 CFRange range = CTRunGetStringRange (run); | 943 CFRange range = CTRunGetStringRange (run); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1021 * advance (in the advance direction only), and for last glyph we set | 1043 * advance (in the advance direction only), and for last glyph we set |
1022 * whatever is needed to make the whole run's advance add up. */ | 1044 * whatever is needed to make the whole run's advance add up. */ |
1023 SCRATCH_SAVE(); | 1045 SCRATCH_SAVE(); |
1024 const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL; | 1046 const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL; |
1025 if (!positions) { | 1047 if (!positions) { |
1026 ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_ret
ry); | 1048 ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_ret
ry); |
1027 CTRunGetPositions (run, range_all, position_buf); | 1049 CTRunGetPositions (run, range_all, position_buf); |
1028 positions = position_buf; | 1050 positions = position_buf; |
1029 } | 1051 } |
1030 hb_glyph_info_t *info = run_info; | 1052 hb_glyph_info_t *info = run_info; |
1031 CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult; | |
1032 if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) | 1053 if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) |
1033 { | 1054 { |
1034 hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult; | 1055 hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult; |
1035 for (unsigned int j = 0; j < num_glyphs; j++) | 1056 for (unsigned int j = 0; j < num_glyphs; j++) |
1036 { | 1057 { |
1037 double advance; | 1058 double advance; |
1038 if (likely (j + 1 < num_glyphs)) | 1059 if (likely (j + 1 < num_glyphs)) |
1039 advance = positions[j + 1].x - positions[j].x; | 1060 advance = positions[j + 1].x - positions[j].x; |
1040 else /* last glyph */ | 1061 else /* last glyph */ |
1041 advance = run_advance - (positions[j].x - positions[0].x); | 1062 advance = run_advance - (positions[j].x - positions[0].x); |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1240 | 1261 |
1241 hb_bool_t | 1262 hb_bool_t |
1242 _hb_coretext_aat_shape (hb_shape_plan_t *shape_plan, | 1263 _hb_coretext_aat_shape (hb_shape_plan_t *shape_plan, |
1243 hb_font_t *font, | 1264 hb_font_t *font, |
1244 hb_buffer_t *buffer, | 1265 hb_buffer_t *buffer, |
1245 const hb_feature_t *features, | 1266 const hb_feature_t *features, |
1246 unsigned int num_features) | 1267 unsigned int num_features) |
1247 { | 1268 { |
1248 return _hb_coretext_shape (shape_plan, font, buffer, features, num_features); | 1269 return _hb_coretext_shape (shape_plan, font, buffer, features, num_features); |
1249 } | 1270 } |
OLD | NEW |