| 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 |