OLD | NEW |
1 /* | 1 /* |
2 * Copyright © 2009,2010 Red Hat, Inc. | 2 * Copyright © 2009,2010 Red Hat, Inc. |
3 * Copyright © 2010,2011 Google, Inc. | 3 * Copyright © 2010,2011,2012 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 * Red Hat Author(s): Behdad Esfahbod | 25 * Red Hat Author(s): Behdad Esfahbod |
26 * Google Author(s): Behdad Esfahbod | 26 * Google Author(s): Behdad Esfahbod |
27 */ | 27 */ |
28 | 28 |
| 29 #define HB_SHAPER ot |
| 30 #define hb_ot_shaper_face_data_t hb_ot_layout_t |
| 31 #define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t |
| 32 #include "hb-shaper-impl-private.hh" |
| 33 |
29 #include "hb-ot-shape-private.hh" | 34 #include "hb-ot-shape-private.hh" |
| 35 #include "hb-ot-shape-complex-private.hh" |
| 36 #include "hb-ot-shape-fallback-private.hh" |
30 #include "hb-ot-shape-normalize-private.hh" | 37 #include "hb-ot-shape-normalize-private.hh" |
31 | 38 |
32 #include "hb-font-private.hh" | 39 #include "hb-ot-layout-private.hh" |
33 #include "hb-set-private.hh" | 40 #include "hb-set-private.hh" |
34 | 41 |
35 | 42 |
36 | 43 static hb_tag_t common_features[] = { |
37 hb_tag_t common_features[] = { | |
38 HB_TAG('c','c','m','p'), | 44 HB_TAG('c','c','m','p'), |
39 HB_TAG('l','i','g','a'), | 45 HB_TAG('l','i','g','a'), |
40 HB_TAG('l','o','c','l'), | 46 HB_TAG('l','o','c','l'), |
41 HB_TAG('m','a','r','k'), | 47 HB_TAG('m','a','r','k'), |
42 HB_TAG('m','k','m','k'), | 48 HB_TAG('m','k','m','k'), |
43 HB_TAG('r','l','i','g'), | 49 HB_TAG('r','l','i','g'), |
44 }; | 50 }; |
45 | 51 |
46 | 52 |
47 hb_tag_t horizontal_features[] = { | 53 static hb_tag_t horizontal_features[] = { |
48 HB_TAG('c','a','l','t'), | 54 HB_TAG('c','a','l','t'), |
49 HB_TAG('c','l','i','g'), | 55 HB_TAG('c','l','i','g'), |
50 HB_TAG('c','u','r','s'), | 56 HB_TAG('c','u','r','s'), |
51 HB_TAG('k','e','r','n'), | 57 HB_TAG('k','e','r','n'), |
| 58 HB_TAG('r','c','l','t'), |
52 }; | 59 }; |
53 | 60 |
54 /* Note: | 61 /* Note: |
55 * Technically speaking, vrt2 and vert are mutually exclusive. | 62 * Technically speaking, vrt2 and vert are mutually exclusive. |
56 * According to the spec, valt and vpal are also mutually exclusive. | 63 * According to the spec, valt and vpal are also mutually exclusive. |
57 * But we apply them all for now. | 64 * But we apply them all for now. |
58 */ | 65 */ |
59 hb_tag_t vertical_features[] = { | 66 static hb_tag_t vertical_features[] = { |
60 HB_TAG('v','a','l','t'), | 67 HB_TAG('v','a','l','t'), |
61 HB_TAG('v','e','r','t'), | 68 HB_TAG('v','e','r','t'), |
62 HB_TAG('v','k','r','n'), | 69 HB_TAG('v','k','r','n'), |
63 HB_TAG('v','p','a','l'), | 70 HB_TAG('v','p','a','l'), |
64 HB_TAG('v','r','t','2'), | 71 HB_TAG('v','r','t','2'), |
65 }; | 72 }; |
66 | 73 |
67 | 74 |
68 | 75 |
69 struct hb_ot_shape_planner_t | |
70 { | |
71 hb_ot_map_builder_t map; | |
72 hb_ot_complex_shaper_t shaper; | |
73 | |
74 hb_ot_shape_planner_t (void) : map () {} | |
75 ~hb_ot_shape_planner_t (void) { map.finish (); } | |
76 | |
77 inline void compile (hb_face_t *face, | |
78 const hb_segment_properties_t *props, | |
79 struct hb_ot_shape_plan_t &plan) | |
80 { | |
81 plan.shaper = shaper; | |
82 map.compile (face, props, plan.map); | |
83 } | |
84 | |
85 private: | |
86 NO_COPY (hb_ot_shape_planner_t); | |
87 }; | |
88 | |
89 static void | 76 static void |
90 hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, | 77 hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, |
91 const hb_segment_properties_t *props, | 78 const hb_segment_properties_t *props, |
92 const hb_feature_t *user_features, | 79 const hb_feature_t *user_features, |
93 unsigned int num_user_features) | 80 unsigned int num_user_features) |
94 { | 81 { |
| 82 hb_ot_map_builder_t *map = &planner->map; |
| 83 |
95 switch (props->direction) { | 84 switch (props->direction) { |
96 case HB_DIRECTION_LTR: | 85 case HB_DIRECTION_LTR: |
97 planner->map.add_bool_feature (HB_TAG ('l','t','r','a')); | 86 map->add_bool_feature (HB_TAG ('l','t','r','a')); |
98 planner->map.add_bool_feature (HB_TAG ('l','t','r','m')); | 87 map->add_bool_feature (HB_TAG ('l','t','r','m')); |
99 break; | 88 break; |
100 case HB_DIRECTION_RTL: | 89 case HB_DIRECTION_RTL: |
101 planner->map.add_bool_feature (HB_TAG ('r','t','l','a')); | 90 map->add_bool_feature (HB_TAG ('r','t','l','a')); |
102 planner->map.add_bool_feature (HB_TAG ('r','t','l','m'), false); | 91 map->add_bool_feature (HB_TAG ('r','t','l','m'), false); |
103 break; | 92 break; |
104 case HB_DIRECTION_TTB: | 93 case HB_DIRECTION_TTB: |
105 case HB_DIRECTION_BTT: | 94 case HB_DIRECTION_BTT: |
106 case HB_DIRECTION_INVALID: | 95 case HB_DIRECTION_INVALID: |
107 default: | 96 default: |
108 break; | 97 break; |
109 } | 98 } |
110 | 99 |
111 #define ADD_FEATURES(array) \ | 100 #define ADD_FEATURES(array) \ |
112 HB_STMT_START { \ | 101 HB_STMT_START { \ |
113 for (unsigned int i = 0; i < ARRAY_LENGTH (array); i++) \ | 102 for (unsigned int i = 0; i < ARRAY_LENGTH (array); i++) \ |
114 planner->map.add_bool_feature (array[i]); \ | 103 map->add_bool_feature (array[i]); \ |
115 } HB_STMT_END | 104 } HB_STMT_END |
116 | 105 |
117 hb_ot_shape_complex_collect_features (planner->shaper, &planner->map, props); | 106 if (planner->shaper->collect_features) |
| 107 planner->shaper->collect_features (planner); |
118 | 108 |
119 ADD_FEATURES (common_features); | 109 ADD_FEATURES (common_features); |
120 | 110 |
121 if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) | 111 if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) |
122 ADD_FEATURES (horizontal_features); | 112 ADD_FEATURES (horizontal_features); |
123 else | 113 else |
124 ADD_FEATURES (vertical_features); | 114 ADD_FEATURES (vertical_features); |
125 | 115 |
| 116 if (planner->shaper->override_features) |
| 117 planner->shaper->override_features (planner); |
| 118 |
126 #undef ADD_FEATURES | 119 #undef ADD_FEATURES |
127 | 120 |
128 for (unsigned int i = 0; i < num_user_features; i++) { | 121 for (unsigned int i = 0; i < num_user_features; i++) { |
129 const hb_feature_t *feature = &user_features[i]; | 122 const hb_feature_t *feature = &user_features[i]; |
130 planner->map.add_feature (feature->tag, feature->value, (feature->start == 0
&& feature->end == (unsigned int) -1)); | 123 map->add_feature (feature->tag, feature->value, (feature->start == 0 && feat
ure->end == (unsigned int) -1)); |
131 } | 124 } |
132 } | 125 } |
133 | 126 |
134 | 127 |
| 128 /* |
| 129 * shaper face data |
| 130 */ |
| 131 |
| 132 hb_ot_shaper_face_data_t * |
| 133 _hb_ot_shaper_face_data_create (hb_face_t *face) |
| 134 { |
| 135 return _hb_ot_layout_create (face); |
| 136 } |
| 137 |
| 138 void |
| 139 _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data) |
| 140 { |
| 141 _hb_ot_layout_destroy (data); |
| 142 } |
| 143 |
| 144 |
| 145 /* |
| 146 * shaper font data |
| 147 */ |
| 148 |
| 149 struct hb_ot_shaper_font_data_t {}; |
| 150 |
| 151 hb_ot_shaper_font_data_t * |
| 152 _hb_ot_shaper_font_data_create (hb_font_t *font) |
| 153 { |
| 154 return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; |
| 155 } |
| 156 |
| 157 void |
| 158 _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data) |
| 159 { |
| 160 } |
| 161 |
| 162 |
| 163 /* |
| 164 * shaper shape_plan data |
| 165 */ |
| 166 |
| 167 hb_ot_shaper_shape_plan_data_t * |
| 168 _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, |
| 169 const hb_feature_t *user_features, |
| 170 unsigned int num_user_features) |
| 171 { |
| 172 hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_sha
pe_plan_t)); |
| 173 if (unlikely (!plan)) |
| 174 return NULL; |
| 175 |
| 176 hb_ot_shape_planner_t planner (shape_plan); |
| 177 |
| 178 planner.shaper = hb_ot_shape_complex_categorize (&shape_plan->props); |
| 179 |
| 180 hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num
_user_features); |
| 181 |
| 182 planner.compile (*plan); |
| 183 |
| 184 if (plan->shaper->data_create) { |
| 185 plan->data = plan->shaper->data_create (plan); |
| 186 if (unlikely (!plan->data)) |
| 187 return NULL; |
| 188 } |
| 189 |
| 190 return plan; |
| 191 } |
| 192 |
| 193 void |
| 194 _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan) |
| 195 { |
| 196 if (plan->shaper->data_destroy) |
| 197 plan->shaper->data_destroy (const_cast<void *> (plan->data)); |
| 198 |
| 199 plan->finish (); |
| 200 |
| 201 free (plan); |
| 202 } |
| 203 |
| 204 |
| 205 /* |
| 206 * shaper |
| 207 */ |
| 208 |
135 struct hb_ot_shape_context_t | 209 struct hb_ot_shape_context_t |
136 { | 210 { |
137 /* Input to hb_ot_shape_execute() */ | |
138 hb_ot_shape_plan_t *plan; | 211 hb_ot_shape_plan_t *plan; |
139 hb_font_t *font; | 212 hb_font_t *font; |
140 hb_face_t *face; | 213 hb_face_t *face; |
141 hb_buffer_t *buffer; | 214 hb_buffer_t *buffer; |
142 const hb_feature_t *user_features; | 215 const hb_feature_t *user_features; |
143 unsigned int num_user_features; | 216 unsigned int num_user_features; |
144 | 217 |
145 /* Transient stuff */ | 218 /* Transient stuff */ |
146 hb_direction_t target_direction; | 219 hb_direction_t target_direction; |
147 hb_bool_t applied_position_complex; | |
148 }; | 220 }; |
149 | 221 |
150 static void | |
151 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) | |
152 { | |
153 hb_mask_t global_mask = c->plan->map.get_global_mask (); | |
154 c->buffer->reset_masks (global_mask); | |
155 | |
156 hb_ot_shape_complex_setup_masks (c->plan->shaper, &c->plan->map, c->buffer, c-
>font); | |
157 | |
158 for (unsigned int i = 0; i < c->num_user_features; i++) | |
159 { | |
160 const hb_feature_t *feature = &c->user_features[i]; | |
161 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { | |
162 unsigned int shift; | |
163 hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift); | |
164 c->buffer->set_masks (feature->value << shift, mask, feature->start, featu
re->end); | |
165 } | |
166 } | |
167 } | |
168 | 222 |
169 | 223 |
170 /* Main shaper */ | 224 /* Main shaper */ |
171 | 225 |
| 226 |
172 /* Prepare */ | 227 /* Prepare */ |
173 | 228 |
174 static void | 229 static void |
175 hb_set_unicode_props (hb_buffer_t *buffer) | 230 hb_set_unicode_props (hb_buffer_t *buffer) |
176 { | 231 { |
177 unsigned int count = buffer->len; | 232 unsigned int count = buffer->len; |
178 for (unsigned int i = 0; i < count; i++) | 233 for (unsigned int i = 0; i < count; i++) |
179 _hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode); | 234 _hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode); |
180 } | 235 } |
181 | 236 |
182 static void | 237 static void |
| 238 hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) |
| 239 { |
| 240 /* TODO One day, when we keep _before_ text for the buffer, take |
| 241 * that into consideration. For now, insert dotted-circle if the |
| 242 * very first character is a non-spacing mark. */ |
| 243 if (_hb_glyph_info_get_general_category (&buffer->info[0]) != |
| 244 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
| 245 return; |
| 246 |
| 247 hb_codepoint_t dottedcircle_glyph; |
| 248 if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) |
| 249 return; |
| 250 |
| 251 hb_glyph_info_t dottedcircle; |
| 252 dottedcircle.codepoint = 0x25CC; |
| 253 _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode); |
| 254 |
| 255 buffer->clear_output (); |
| 256 |
| 257 buffer->idx = 0; |
| 258 hb_glyph_info_t info = dottedcircle; |
| 259 info.cluster = buffer->cur().cluster; |
| 260 info.mask = buffer->cur().mask; |
| 261 buffer->output_info (info); |
| 262 while (buffer->idx < buffer->len) |
| 263 buffer->next_glyph (); |
| 264 |
| 265 buffer->swap_buffers (); |
| 266 } |
| 267 |
| 268 static void |
183 hb_form_clusters (hb_buffer_t *buffer) | 269 hb_form_clusters (hb_buffer_t *buffer) |
184 { | 270 { |
185 unsigned int count = buffer->len; | 271 unsigned int count = buffer->len; |
186 for (unsigned int i = 1; i < count; i++) | 272 for (unsigned int i = 1; i < count; i++) |
187 if (FLAG (_hb_glyph_info_get_general_category (&buffer->info[i])) & | 273 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category
(&buffer->info[i]))) |
188 » (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | | 274 buffer->merge_clusters (i - 1, i + 1); |
189 » FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | | |
190 » FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))) | |
191 buffer->info[i].cluster = buffer->info[i - 1].cluster; /* XXX do the min()
here */ | |
192 } | 275 } |
193 | 276 |
194 static void | 277 static void |
195 hb_ensure_native_direction (hb_buffer_t *buffer) | 278 hb_ensure_native_direction (hb_buffer_t *buffer) |
196 { | 279 { |
197 hb_direction_t direction = buffer->props.direction; | 280 hb_direction_t direction = buffer->props.direction; |
198 | 281 |
199 /* TODO vertical: | 282 /* TODO vertical: |
200 * The only BTT vertical script is Ogham, but it's not clear to me whether Ope
nType | 283 * The only BTT vertical script is Ogham, but it's not clear to me whether Ope
nType |
201 * Ogham fonts are supposed to be implemented BTT or not. Need to research th
at | 284 * Ogham fonts are supposed to be implemented BTT or not. Need to research th
at |
202 * first. */ | 285 * first. */ |
203 if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_hori
zontal_direction (buffer->props.script)) || | 286 if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_hori
zontal_direction (buffer->props.script)) || |
204 (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) | 287 (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) |
205 { | 288 { |
206 hb_buffer_reverse_clusters (buffer); | 289 hb_buffer_reverse_clusters (buffer); |
207 buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction); | 290 buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction); |
208 } | 291 } |
209 } | 292 } |
210 | 293 |
211 | 294 |
212 /* Substitute */ | 295 /* Substitute */ |
213 | 296 |
214 static void | 297 static inline void |
215 hb_mirror_chars (hb_ot_shape_context_t *c) | 298 hb_ot_mirror_chars (hb_ot_shape_context_t *c) |
216 { | 299 { |
217 hb_unicode_funcs_t *unicode = c->buffer->unicode; | |
218 | |
219 if (HB_DIRECTION_IS_FORWARD (c->target_direction)) | 300 if (HB_DIRECTION_IS_FORWARD (c->target_direction)) |
220 return; | 301 return; |
221 | 302 |
| 303 hb_unicode_funcs_t *unicode = c->buffer->unicode; |
222 hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m')); | 304 hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m')); |
223 | 305 |
224 unsigned int count = c->buffer->len; | 306 unsigned int count = c->buffer->len; |
225 for (unsigned int i = 0; i < count; i++) { | 307 for (unsigned int i = 0; i < count; i++) { |
226 hb_codepoint_t codepoint = hb_unicode_mirroring (unicode, c->buffer->info[i]
.codepoint); | 308 hb_codepoint_t codepoint = unicode->mirroring (c->buffer->info[i].codepoint)
; |
227 if (likely (codepoint == c->buffer->info[i].codepoint)) | 309 if (likely (codepoint == c->buffer->info[i].codepoint)) |
228 c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to befor
e setting user-feature masks */ | 310 c->buffer->info[i].mask |= rtlm_mask; |
229 else | 311 else |
230 c->buffer->info[i].codepoint = codepoint; | 312 c->buffer->info[i].codepoint = codepoint; |
231 } | 313 } |
232 } | 314 } |
233 | 315 |
234 static void | 316 static inline void |
235 hb_map_glyphs (hb_font_t *font, | 317 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) |
236 » hb_buffer_t *buffer) | |
237 { | 318 { |
238 hb_codepoint_t glyph; | 319 hb_ot_map_t *map = &c->plan->map; |
239 | 320 |
240 if (unlikely (!buffer->len)) | 321 hb_mask_t global_mask = map->get_global_mask (); |
241 return; | 322 c->buffer->reset_masks (global_mask); |
242 | 323 |
243 buffer->clear_output (); | 324 if (c->plan->shaper->setup_masks) |
| 325 c->plan->shaper->setup_masks (c->plan, c->buffer, c->font); |
244 | 326 |
245 unsigned int count = buffer->len - 1; | 327 for (unsigned int i = 0; i < c->num_user_features; i++) |
246 for (buffer->idx = 0; buffer->idx < count;) { | 328 { |
247 if (unlikely (_hb_unicode_is_variation_selector (buffer->cur(+1).codepoint))
) { | 329 const hb_feature_t *feature = &c->user_features[i]; |
248 hb_font_get_glyph (font, buffer->cur().codepoint, buffer->cur(+1).codepoin
t, &glyph); | 330 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { |
249 buffer->replace_glyphs (2, 1, &glyph); | 331 unsigned int shift; |
250 } else { | 332 hb_mask_t mask = map->get_mask (feature->tag, &shift); |
251 hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph); | 333 c->buffer->set_masks (feature->value << shift, mask, feature->start, featu
re->end); |
252 buffer->replace_glyph (glyph); | |
253 } | 334 } |
254 } | 335 } |
255 if (likely (buffer->idx < buffer->len)) { | |
256 hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph); | |
257 buffer->replace_glyph (glyph); | |
258 } | |
259 buffer->swap_buffers (); | |
260 } | 336 } |
261 | 337 |
262 static void | 338 static inline void |
263 hb_substitute_default (hb_ot_shape_context_t *c) | 339 hb_ot_map_glyphs_fast (hb_buffer_t *buffer) |
264 { | 340 { |
265 hb_ot_layout_substitute_start (c->buffer); | 341 /* Normalization process sets up glyph_index(), we just copy it. */ |
266 | 342 unsigned int count = buffer->len; |
267 hb_mirror_chars (c); | 343 for (unsigned int i = 0; i < count; i++) |
268 | 344 buffer->info[i].codepoint = buffer->info[i].glyph_index(); |
269 hb_map_glyphs (c->font, c->buffer); | |
270 } | 345 } |
271 | 346 |
272 static void | 347 static inline void |
| 348 hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) |
| 349 { |
| 350 unsigned int count = c->buffer->len; |
| 351 for (unsigned int i = 0; i < count; i++) |
| 352 c->buffer->info[i].glyph_props() = _hb_glyph_info_get_general_category (&c->
buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ? |
| 353 » » » » HB_OT_LAYOUT_GLYPH_CLASS_MARK : |
| 354 » » » » HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH; |
| 355 } |
| 356 |
| 357 static inline void |
| 358 hb_ot_substitute_default (hb_ot_shape_context_t *c) |
| 359 { |
| 360 if (c->plan->shaper->preprocess_text) |
| 361 c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font); |
| 362 |
| 363 hb_ot_mirror_chars (c); |
| 364 |
| 365 HB_BUFFER_ALLOCATE_VAR (c->buffer, glyph_index); |
| 366 |
| 367 _hb_ot_shape_normalize (c->font, c->buffer, |
| 368 » » » c->plan->shaper->normalization_preference ? |
| 369 » » » c->plan->shaper->normalization_preference (c->plan) : |
| 370 » » » HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT); |
| 371 |
| 372 hb_ot_shape_setup_masks (c); |
| 373 |
| 374 /* This is unfortunate to go here, but necessary... */ |
| 375 if (!hb_ot_layout_has_positioning (c->face)) |
| 376 _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, c->buff
er); |
| 377 |
| 378 hb_ot_map_glyphs_fast (c->buffer); |
| 379 |
| 380 HB_BUFFER_DEALLOCATE_VAR (c->buffer, glyph_index); |
| 381 } |
| 382 |
| 383 static inline void |
273 hb_ot_substitute_complex (hb_ot_shape_context_t *c) | 384 hb_ot_substitute_complex (hb_ot_shape_context_t *c) |
274 { | 385 { |
275 if (hb_ot_layout_has_substitution (c->face)) { | 386 hb_ot_layout_substitute_start (c->font, c->buffer); |
276 c->plan->map.substitute (c->face, c->buffer); | |
277 } | |
278 | 387 |
279 hb_ot_layout_substitute_finish (c->buffer); | 388 if (!hb_ot_layout_has_glyph_classes (c->face)) |
| 389 hb_synthesize_glyph_classes (c); |
| 390 |
| 391 c->plan->substitute (c->font, c->buffer); |
| 392 |
| 393 hb_ot_layout_substitute_finish (c->font, c->buffer); |
280 | 394 |
281 return; | 395 return; |
282 } | 396 } |
283 | 397 |
| 398 static inline void |
| 399 hb_ot_substitute (hb_ot_shape_context_t *c) |
| 400 { |
| 401 hb_ot_substitute_default (c); |
| 402 hb_ot_substitute_complex (c); |
| 403 } |
284 | 404 |
285 /* Position */ | 405 /* Position */ |
286 | 406 |
287 static void | 407 static inline void |
288 hb_position_default (hb_ot_shape_context_t *c) | 408 hb_ot_position_default (hb_ot_shape_context_t *c) |
289 { | 409 { |
290 hb_ot_layout_position_start (c->buffer); | 410 hb_ot_layout_position_start (c->font, c->buffer); |
291 | 411 |
292 unsigned int count = c->buffer->len; | 412 unsigned int count = c->buffer->len; |
293 for (unsigned int i = 0; i < count; i++) { | 413 for (unsigned int i = 0; i < count; i++) { |
294 hb_font_get_glyph_advance_for_direction (c->font, c->buffer->info[i].codepoi
nt, | 414 c->font->get_glyph_advance_for_direction (c->buffer->info[i].codepoint, |
295 » » » » » c->buffer->props.direction, | 415 » » » » » c->buffer->props.direction, |
296 » » » » » &c->buffer->pos[i].x_advance, | 416 » » » » » &c->buffer->pos[i].x_advance, |
297 » » » » » &c->buffer->pos[i].y_advance); | 417 » » » » » &c->buffer->pos[i].y_advance); |
298 hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].cod
epoint, | 418 c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint, |
299 » » » » » » c->buffer->props.direction, | 419 » » » » » » c->buffer->props.direction, |
300 » » » » » » &c->buffer->pos[i].x_offset, | 420 » » » » » » &c->buffer->pos[i].x_offset, |
301 » » » » » » &c->buffer->pos[i].y_offset); | 421 » » » » » » &c->buffer->pos[i].y_offset); |
302 } | 422 } |
303 } | 423 } |
304 | 424 |
305 static void | 425 static inline bool |
306 hb_ot_position_complex (hb_ot_shape_context_t *c) | 426 hb_ot_position_complex (hb_ot_shape_context_t *c) |
307 { | 427 { |
| 428 bool ret = false; |
308 | 429 |
309 if (hb_ot_layout_has_positioning (c->face)) | 430 if (hb_ot_layout_has_positioning (c->face)) |
310 { | 431 { |
311 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ | 432 /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ |
312 | 433 |
313 unsigned int count = c->buffer->len; | 434 unsigned int count = c->buffer->len; |
314 for (unsigned int i = 0; i < count; i++) { | 435 for (unsigned int i = 0; i < count; i++) { |
315 hb_font_add_glyph_origin_for_direction (c->font, c->buffer->info[i].codepo
int, | 436 c->font->add_glyph_origin_for_direction (c->buffer->info[i].codepoint, |
316 » » » » » HB_DIRECTION_LTR, | 437 » » » » » HB_DIRECTION_LTR, |
317 » » » » » &c->buffer->pos[i].x_offset, | 438 » » » » » &c->buffer->pos[i].x_offset, |
318 » » » » » &c->buffer->pos[i].y_offset); | 439 » » » » » &c->buffer->pos[i].y_offset); |
319 } | 440 } |
320 | 441 |
321 c->plan->map.position (c->font, c->buffer); | 442 c->plan->position (c->font, c->buffer); |
322 | 443 |
323 for (unsigned int i = 0; i < count; i++) { | 444 for (unsigned int i = 0; i < count; i++) { |
324 hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].c
odepoint, | 445 c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint
, |
325 » » » » » » HB_DIRECTION_LTR, | 446 » » » » » » HB_DIRECTION_LTR, |
326 » » » » » » &c->buffer->pos[i].x_offset, | 447 » » » » » » &c->buffer->pos[i].x_offset, |
327 » » » » » » &c->buffer->pos[i].y_offset); | 448 » » » » » » &c->buffer->pos[i].y_offset)
; |
328 } | 449 } |
329 | 450 |
330 c->applied_position_complex = true; | 451 ret = true; |
331 } | 452 } |
332 | 453 |
333 hb_ot_layout_position_finish (c->buffer); | 454 hb_ot_layout_position_finish (c->font, c->buffer, c->plan->shaper->zero_width_
attached_marks); |
334 | 455 |
335 return; | 456 return ret; |
336 } | 457 } |
337 | 458 |
338 static void | 459 static inline void |
339 hb_position_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED) | 460 hb_ot_position_complex_fallback (hb_ot_shape_context_t *c) |
340 { | 461 { |
341 /* TODO Mark pos */ | 462 _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); |
342 } | 463 } |
343 | 464 |
344 static void | 465 static inline void |
345 hb_truetype_kern (hb_ot_shape_context_t *c) | 466 hb_ot_truetype_kern (hb_ot_shape_context_t *c) |
346 { | 467 { |
347 /* TODO Check for kern=0 */ | 468 /* TODO Check for kern=0 */ |
348 unsigned int count = c->buffer->len; | 469 unsigned int count = c->buffer->len; |
349 for (unsigned int i = 1; i < count; i++) { | 470 for (unsigned int i = 1; i < count; i++) { |
350 hb_position_t x_kern, y_kern, kern1, kern2; | 471 hb_position_t x_kern, y_kern, kern1, kern2; |
351 hb_font_get_glyph_kerning_for_direction (c->font, | 472 c->font->get_glyph_kerning_for_direction (c->buffer->info[i - 1].codepoint,
c->buffer->info[i].codepoint, |
352 » » » » » c->buffer->info[i - 1].codepoint, c
->buffer->info[i].codepoint, | 473 » » » » » c->buffer->props.direction, |
353 » » » » » c->buffer->props.direction, | 474 » » » » » &x_kern, &y_kern); |
354 » » » » » &x_kern, &y_kern); | |
355 | 475 |
356 kern1 = x_kern >> 1; | 476 kern1 = x_kern >> 1; |
357 kern2 = x_kern - kern1; | 477 kern2 = x_kern - kern1; |
358 c->buffer->pos[i - 1].x_advance += kern1; | 478 c->buffer->pos[i - 1].x_advance += kern1; |
359 c->buffer->pos[i].x_advance += kern2; | 479 c->buffer->pos[i].x_advance += kern2; |
360 c->buffer->pos[i].x_offset += kern2; | 480 c->buffer->pos[i].x_offset += kern2; |
361 | 481 |
362 kern1 = y_kern >> 1; | 482 kern1 = y_kern >> 1; |
363 kern2 = y_kern - kern1; | 483 kern2 = y_kern - kern1; |
364 c->buffer->pos[i - 1].y_advance += kern1; | 484 c->buffer->pos[i - 1].y_advance += kern1; |
365 c->buffer->pos[i].y_advance += kern2; | 485 c->buffer->pos[i].y_advance += kern2; |
366 c->buffer->pos[i].y_offset += kern2; | 486 c->buffer->pos[i].y_offset += kern2; |
367 } | 487 } |
368 } | 488 } |
369 | 489 |
370 static void | 490 static inline void |
371 hb_position_complex_fallback_visual (hb_ot_shape_context_t *c) | 491 hb_position_complex_fallback_visual (hb_ot_shape_context_t *c) |
372 { | 492 { |
373 hb_truetype_kern (c); | 493 hb_ot_truetype_kern (c); |
374 } | 494 } |
375 | 495 |
| 496 static inline void |
| 497 hb_ot_position (hb_ot_shape_context_t *c) |
| 498 { |
| 499 hb_ot_position_default (c); |
| 500 |
| 501 hb_bool_t fallback = !hb_ot_position_complex (c); |
| 502 |
| 503 if (fallback) |
| 504 hb_ot_position_complex_fallback (c); |
| 505 |
| 506 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) |
| 507 hb_buffer_reverse (c->buffer); |
| 508 |
| 509 if (fallback) |
| 510 hb_position_complex_fallback_visual (c); |
| 511 } |
| 512 |
| 513 |
| 514 /* Post-process */ |
| 515 |
376 static void | 516 static void |
377 hb_hide_zerowidth (hb_ot_shape_context_t *c) | 517 hb_ot_hide_zerowidth (hb_ot_shape_context_t *c) |
378 { | 518 { |
379 /* TODO Save the space character in the font? */ | 519 hb_codepoint_t space = 0; |
380 hb_codepoint_t space; | |
381 if (!hb_font_get_glyph (c->font, ' ', 0, &space)) | |
382 return; /* No point! */ | |
383 | 520 |
384 unsigned int count = c->buffer->len; | 521 unsigned int count = c->buffer->len; |
385 for (unsigned int i = 0; i < count; i++) | 522 for (unsigned int i = 0; i < count; i++) |
386 if (unlikely (_hb_glyph_info_is_zero_width (&c->buffer->info[i]))) { | 523 if (unlikely (!is_a_ligature (c->buffer->info[i]) && |
| 524 » » _hb_glyph_info_is_zero_width (&c->buffer->info[i]))) |
| 525 { |
| 526 if (!space) { |
| 527 /* We assume that the space glyph is not gid0. */ |
| 528 if (unlikely (!c->font->get_glyph (' ', 0, &space)) || !space) |
| 529 » return; /* No point! */ |
| 530 } |
387 c->buffer->info[i].codepoint = space; | 531 c->buffer->info[i].codepoint = space; |
388 c->buffer->pos[i].x_advance = 0; | 532 c->buffer->pos[i].x_advance = 0; |
389 c->buffer->pos[i].y_advance = 0; | 533 c->buffer->pos[i].y_advance = 0; |
390 } | 534 } |
391 } | 535 } |
392 | 536 |
393 | 537 |
394 /* Do it! */ | 538 /* Pull it all together! */ |
395 | 539 |
396 static void | 540 static void |
397 hb_ot_shape_execute_internal (hb_ot_shape_context_t *c) | 541 hb_ot_shape_internal (hb_ot_shape_context_t *c) |
398 { | 542 { |
399 c->buffer->deallocate_var_all (); | 543 c->buffer->deallocate_var_all (); |
400 | 544 |
401 /* Save the original direction, we use it later. */ | 545 /* Save the original direction, we use it later. */ |
402 c->target_direction = c->buffer->props.direction; | 546 c->target_direction = c->buffer->props.direction; |
403 | 547 |
404 HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props0); | 548 HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props0); |
405 HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props1); | 549 HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props1); |
406 | 550 |
| 551 c->buffer->clear_output (); |
| 552 |
407 hb_set_unicode_props (c->buffer); | 553 hb_set_unicode_props (c->buffer); |
408 | 554 hb_insert_dotted_circle (c->buffer, c->font); |
409 hb_form_clusters (c->buffer); | 555 hb_form_clusters (c->buffer); |
410 | 556 |
411 hb_ensure_native_direction (c->buffer); | 557 hb_ensure_native_direction (c->buffer); |
412 | 558 |
413 _hb_ot_shape_normalize (c->font, c->buffer, hb_ot_shape_complex_normalization_
preference (c->plan->shaper)); | 559 hb_ot_substitute (c); |
| 560 hb_ot_position (c); |
414 | 561 |
415 hb_ot_shape_setup_masks (c); | 562 hb_ot_hide_zerowidth (c); |
416 | |
417 /* SUBSTITUTE */ | |
418 { | |
419 hb_substitute_default (c); | |
420 | |
421 hb_ot_substitute_complex (c); | |
422 } | |
423 | |
424 /* POSITION */ | |
425 { | |
426 hb_position_default (c); | |
427 | |
428 hb_ot_position_complex (c); | |
429 | |
430 hb_bool_t position_fallback = !c->applied_position_complex; | |
431 if (position_fallback) | |
432 hb_position_complex_fallback (c); | |
433 | |
434 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) | |
435 hb_buffer_reverse (c->buffer); | |
436 | |
437 if (position_fallback) | |
438 hb_position_complex_fallback_visual (c); | |
439 } | |
440 | |
441 hb_hide_zerowidth (c); | |
442 | 563 |
443 HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props1); | 564 HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props1); |
444 HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props0); | 565 HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props0); |
445 | 566 |
446 c->buffer->props.direction = c->target_direction; | 567 c->buffer->props.direction = c->target_direction; |
447 | 568 |
448 c->buffer->deallocate_var_all (); | 569 c->buffer->deallocate_var_all (); |
449 } | 570 } |
450 | 571 |
451 static void | |
452 hb_ot_shape_plan_internal (hb_ot_shape_plan_t *plan, | |
453 hb_face_t *face, | |
454 const hb_segment_properties_t *props, | |
455 const hb_feature_t *user_features, | |
456 unsigned int num_user_features) | |
457 { | |
458 hb_ot_shape_planner_t planner; | |
459 | |
460 assert (HB_DIRECTION_IS_VALID (props->direction)); | |
461 | |
462 planner.shaper = hb_ot_shape_complex_categorize (props); | |
463 | |
464 hb_ot_shape_collect_features (&planner, props, user_features, num_user_feature
s); | |
465 | |
466 planner.compile (face, props, *plan); | |
467 } | |
468 | |
469 static void | |
470 hb_ot_shape_execute (hb_ot_shape_plan_t *plan, | |
471 hb_font_t *font, | |
472 hb_buffer_t *buffer, | |
473 const hb_feature_t *user_features, | |
474 unsigned int num_user_features) | |
475 { | |
476 hb_ot_shape_context_t c = {plan, font, font->face, buffer, user_features, num_
user_features}; | |
477 hb_ot_shape_execute_internal (&c); | |
478 } | |
479 | 572 |
480 hb_bool_t | 573 hb_bool_t |
481 _hb_ot_shape (hb_font_t *font, | 574 _hb_ot_shape (hb_shape_plan_t *shape_plan, |
| 575 » hb_font_t *font, |
482 hb_buffer_t *buffer, | 576 hb_buffer_t *buffer, |
483 const hb_feature_t *features, | 577 const hb_feature_t *features, |
484 unsigned int num_features) | 578 unsigned int num_features) |
485 { | 579 { |
486 hb_ot_shape_plan_t plan; | 580 hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face,
buffer, features, num_features}; |
487 | 581 hb_ot_shape_internal (&c); |
488 buffer->guess_properties (); | |
489 | |
490 hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_fe
atures); | |
491 hb_ot_shape_execute (&plan, font, buffer, features, num_features); | |
492 | 582 |
493 return true; | 583 return true; |
494 } | 584 } |
495 | 585 |
496 | 586 |
| 587 |
| 588 static inline void |
| 589 hb_ot_map_glyphs_dumb (hb_font_t *font, |
| 590 hb_buffer_t *buffer) |
| 591 { |
| 592 unsigned int count = buffer->len; |
| 593 for (unsigned int i = 0; i < count; i++) |
| 594 font->get_glyph (buffer->cur().codepoint, 0, &buffer->cur().codepoint); |
| 595 } |
| 596 |
497 void | 597 void |
498 hb_ot_shape_glyphs_closure (hb_font_t *font, | 598 hb_ot_shape_glyphs_closure (hb_font_t *font, |
499 hb_buffer_t *buffer, | 599 hb_buffer_t *buffer, |
500 const hb_feature_t *features, | 600 const hb_feature_t *features, |
501 unsigned int num_features, | 601 unsigned int num_features, |
502 hb_set_t *glyphs) | 602 hb_set_t *glyphs) |
503 { | 603 { |
504 hb_ot_shape_plan_t plan; | 604 hb_ot_shape_plan_t plan; |
505 | 605 |
506 buffer->guess_properties (); | 606 buffer->guess_properties (); |
507 | 607 |
508 hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_fe
atures); | 608 /* TODO cache / ensure correct backend, etc. */ |
| 609 hb_shape_plan_t *shape_plan = hb_shape_plan_create (font->face, &buffer->props
, features, num_features, NULL); |
509 | 610 |
510 /* TODO: normalization? have shapers do closure()? */ | 611 /* TODO: normalization? have shapers do closure()? */ |
511 /* TODO: Deal with mirrored chars? */ | 612 /* TODO: Deal with mirrored chars? */ |
512 hb_map_glyphs (font, buffer); | 613 hb_ot_map_glyphs_dumb (font, buffer); |
513 | 614 |
514 /* Seed it. It's user's responsibility to have cleard glyphs | 615 /* Seed it. It's user's responsibility to have cleard glyphs |
515 * if that's what they desire. */ | 616 * if that's what they desire. */ |
516 unsigned int count = buffer->len; | 617 unsigned int count = buffer->len; |
517 for (unsigned int i = 0; i < count; i++) | 618 for (unsigned int i = 0; i < count; i++) |
518 hb_set_add (glyphs, buffer->info[i].codepoint); | 619 glyphs->add (buffer->info[i].codepoint); |
519 | 620 |
520 /* And find transitive closure. */ | 621 /* And find transitive closure. */ |
521 hb_set_t copy; | 622 hb_set_t copy; |
522 copy.init (); | 623 copy.init (); |
523 | 624 |
524 do { | 625 do { |
525 copy.set (glyphs); | 626 copy.set (glyphs); |
526 plan.map.substitute_closure (font->face, glyphs); | 627 HB_SHAPER_DATA_GET (shape_plan)->substitute_closure (font->face, glyphs); |
527 } while (!copy.equal (glyphs)); | 628 } while (!copy.equal (glyphs)); |
| 629 |
| 630 hb_shape_plan_destroy (shape_plan); |
528 } | 631 } |
OLD | NEW |