1 | /* |
2 | * Copyright © 2009,2010 Red Hat, Inc. |
3 | * Copyright © 2010,2011,2012 Google, Inc. |
4 | * |
5 | * This is part of HarfBuzz, a text shaping library. |
6 | * |
7 | * Permission is hereby granted, without written agreement and without |
8 | * license or royalty fees, to use, copy, modify, and distribute this |
9 | * software and its documentation for any purpose, provided that the |
10 | * above copyright notice and the following two paragraphs appear in |
11 | * all copies of this software. |
12 | * |
13 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
14 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
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 |
17 | * DAMAGE. |
18 | * |
19 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
20 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
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 |
23 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
24 | * |
25 | * Red Hat Author(s): Behdad Esfahbod |
26 | * Google Author(s): Behdad Esfahbod |
27 | */ |
28 | |
29 | #define HB_SHAPER ot |
30 | #define hb_ot_shape_plan_data_t hb_ot_shape_plan_t |
31 | #include "hb-shaper-impl.hh" |
32 | |
33 | #include "hb-ot-shape.hh" |
34 | #include "hb-ot-shape-complex.hh" |
35 | #include "hb-ot-shape-fallback.hh" |
36 | #include "hb-ot-shape-normalize.hh" |
37 | |
38 | #include "hb-ot-face.hh" |
39 | #include "hb-ot-layout.hh" |
40 | #include "hb-unicode.hh" |
41 | #include "hb-set.hh" |
42 | |
43 | #include "hb-ot-layout-gsubgpos.hh" |
44 | #include "hb-aat-layout.hh" |
45 | |
46 | static hb_tag_t common_features[] = { |
47 | HB_TAG('c','c','m','p'), |
48 | HB_TAG('l','o','c','l'), |
49 | HB_TAG('m','a','r','k'), |
50 | HB_TAG('m','k','m','k'), |
51 | HB_TAG('r','l','i','g'), |
52 | }; |
53 | |
54 | |
55 | static hb_tag_t horizontal_features[] = { |
56 | HB_TAG('c','a','l','t'), |
57 | HB_TAG('c','l','i','g'), |
58 | HB_TAG('c','u','r','s'), |
59 | HB_TAG('k','e','r','n'), |
60 | HB_TAG('l','i','g','a'), |
61 | HB_TAG('r','c','l','t'), |
62 | }; |
63 | |
64 | |
65 | |
66 | static void |
67 | hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, |
68 | const hb_segment_properties_t *props, |
69 | const hb_feature_t *user_features, |
70 | unsigned int num_user_features) |
71 | { |
72 | hb_ot_map_builder_t *map = &planner->map; |
73 | |
74 | map->add_global_bool_feature (HB_TAG('r','v','r','n')); |
75 | map->add_gsub_pause (nullptr); |
76 | |
77 | switch (props->direction) { |
78 | case HB_DIRECTION_LTR: |
79 | map->add_global_bool_feature (HB_TAG ('l','t','r','a')); |
80 | map->add_global_bool_feature (HB_TAG ('l','t','r','m')); |
81 | break; |
82 | case HB_DIRECTION_RTL: |
83 | map->add_global_bool_feature (HB_TAG ('r','t','l','a')); |
84 | map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE); |
85 | break; |
86 | case HB_DIRECTION_TTB: |
87 | case HB_DIRECTION_BTT: |
88 | case HB_DIRECTION_INVALID: |
89 | default: |
90 | break; |
91 | } |
92 | |
93 | map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE); |
94 | map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE); |
95 | map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE); |
96 | |
97 | if (planner->shaper->collect_features) |
98 | planner->shaper->collect_features (planner); |
99 | |
100 | for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) |
101 | map->add_global_bool_feature (common_features[i]); |
102 | |
103 | if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) |
104 | for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) |
105 | map->add_feature (horizontal_features[i], 1, F_GLOBAL | |
106 | (horizontal_features[i] == HB_TAG('k','e','r','n') ? |
107 | F_HAS_FALLBACK : F_NONE)); |
108 | else |
109 | { |
110 | /* We really want to find a 'vert' feature if there's any in the font, no |
111 | * matter which script/langsys it is listed (or not) under. |
112 | * See various bugs referenced from: |
113 | * https://github.com/harfbuzz/harfbuzz/issues/63 */ |
114 | map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH); |
115 | } |
116 | |
117 | if (planner->shaper->override_features) |
118 | planner->shaper->override_features (planner); |
119 | |
120 | for (unsigned int i = 0; i < num_user_features; i++) { |
121 | const hb_feature_t *feature = &user_features[i]; |
122 | map->add_feature (feature->tag, feature->value, |
123 | (feature->start == 0 && feature->end == (unsigned int) -1) ? |
124 | F_GLOBAL : F_NONE); |
125 | } |
126 | } |
127 | |
128 | |
129 | /* |
130 | * shaper face data |
131 | */ |
132 | |
133 | HB_SHAPER_DATA_ENSURE_DEFINE(ot, face) |
134 | |
135 | hb_ot_face_data_t * |
136 | _hb_ot_shaper_face_data_create (hb_face_t *face) |
137 | { |
138 | return _hb_ot_face_data_create (face); |
139 | } |
140 | |
141 | void |
142 | _hb_ot_shaper_face_data_destroy (hb_ot_face_data_t *data) |
143 | { |
144 | _hb_ot_face_data_destroy (data); |
145 | } |
146 | |
147 | |
148 | /* |
149 | * shaper font data |
150 | */ |
151 | |
152 | HB_SHAPER_DATA_ENSURE_DEFINE(ot, font) |
153 | |
154 | struct hb_ot_font_data_t {}; |
155 | |
156 | hb_ot_font_data_t * |
157 | _hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED) |
158 | { |
159 | return (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; |
160 | } |
161 | |
162 | void |
163 | _hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data) |
164 | { |
165 | } |
166 | |
167 | |
168 | /* |
169 | * shaper shape_plan data |
170 | */ |
171 | |
172 | hb_ot_shape_plan_data_t * |
173 | _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, |
174 | const hb_feature_t *user_features, |
175 | unsigned int num_user_features, |
176 | const int *coords, |
177 | unsigned int num_coords) |
178 | { |
179 | hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t)); |
180 | if (unlikely (!plan)) |
181 | return nullptr; |
182 | |
183 | plan->init (); |
184 | |
185 | hb_ot_shape_planner_t planner (shape_plan); |
186 | |
187 | planner.shaper = hb_ot_shape_complex_categorize (&planner); |
188 | |
189 | hb_ot_shape_collect_features (&planner, &shape_plan->props, |
190 | user_features, num_user_features); |
191 | |
192 | planner.compile (*plan, coords, num_coords); |
193 | |
194 | if (plan->shaper->data_create) { |
195 | plan->data = plan->shaper->data_create (plan); |
196 | if (unlikely (!plan->data)) |
197 | { |
198 | free (plan); |
199 | return nullptr; |
200 | } |
201 | } |
202 | |
203 | return plan; |
204 | } |
205 | |
206 | void |
207 | _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shape_plan_data_t *plan) |
208 | { |
209 | if (plan->shaper->data_destroy) |
210 | plan->shaper->data_destroy (const_cast<void *> (plan->data)); |
211 | |
212 | plan->fini (); |
213 | |
214 | free (plan); |
215 | } |
216 | |
217 | |
218 | /* |
219 | * shaper |
220 | */ |
221 | |
222 | struct hb_ot_shape_context_t |
223 | { |
224 | hb_ot_shape_plan_t *plan; |
225 | hb_font_t *font; |
226 | hb_face_t *face; |
227 | hb_buffer_t *buffer; |
228 | const hb_feature_t *user_features; |
229 | unsigned int num_user_features; |
230 | |
231 | /* Transient stuff */ |
232 | bool fallback_positioning; |
233 | bool fallback_glyph_classes; |
234 | hb_direction_t target_direction; |
235 | }; |
236 | |
237 | |
238 | |
239 | /* Main shaper */ |
240 | |
241 | |
242 | /* Prepare */ |
243 | |
244 | static void |
245 | hb_set_unicode_props (hb_buffer_t *buffer) |
246 | { |
247 | unsigned int count = buffer->len; |
248 | hb_glyph_info_t *info = buffer->info; |
249 | for (unsigned int i = 0; i < count; i++) |
250 | _hb_glyph_info_set_unicode_props (&info[i], buffer); |
251 | } |
252 | |
253 | static void |
254 | hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) |
255 | { |
256 | if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || |
257 | buffer->context_len[0] || |
258 | _hb_glyph_info_get_general_category (&buffer->info[0]) != |
259 | HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
260 | return; |
261 | |
262 | if (!font->has_glyph (0x25CCu)) |
263 | return; |
264 | |
265 | hb_glyph_info_t dottedcircle = {0}; |
266 | dottedcircle.codepoint = 0x25CCu; |
267 | _hb_glyph_info_set_unicode_props (&dottedcircle, buffer); |
268 | |
269 | buffer->clear_output (); |
270 | |
271 | buffer->idx = 0; |
272 | hb_glyph_info_t info = dottedcircle; |
273 | info.cluster = buffer->cur().cluster; |
274 | info.mask = buffer->cur().mask; |
275 | buffer->output_info (info); |
276 | while (buffer->idx < buffer->len && buffer->successful) |
277 | buffer->next_glyph (); |
278 | |
279 | buffer->swap_buffers (); |
280 | } |
281 | |
282 | static void |
283 | hb_form_clusters (hb_buffer_t *buffer) |
284 | { |
285 | if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII)) |
286 | return; |
287 | |
288 | /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */ |
289 | unsigned int base = 0; |
290 | unsigned int count = buffer->len; |
291 | hb_glyph_info_t *info = buffer->info; |
292 | for (unsigned int i = 1; i < count; i++) |
293 | { |
294 | if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) && |
295 | !_hb_glyph_info_is_joiner (&info[i]))) |
296 | { |
297 | if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) |
298 | buffer->merge_clusters (base, i); |
299 | else |
300 | buffer->unsafe_to_break (base, i); |
301 | base = i; |
302 | } |
303 | } |
304 | if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES) |
305 | buffer->merge_clusters (base, count); |
306 | else |
307 | buffer->unsafe_to_break (base, count); |
308 | } |
309 | |
310 | static void |
311 | hb_ensure_native_direction (hb_buffer_t *buffer) |
312 | { |
313 | hb_direction_t direction = buffer->props.direction; |
314 | hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script); |
315 | |
316 | /* TODO vertical: |
317 | * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType |
318 | * Ogham fonts are supposed to be implemented BTT or not. Need to research that |
319 | * first. */ |
320 | if ((HB_DIRECTION_IS_HORIZONTAL (direction) && |
321 | direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) || |
322 | (HB_DIRECTION_IS_VERTICAL (direction) && |
323 | direction != HB_DIRECTION_TTB)) |
324 | { |
325 | /* Same loop as hb_form_clusters(). |
326 | * Since form_clusters() merged clusters already, we don't merge. */ |
327 | unsigned int base = 0; |
328 | unsigned int count = buffer->len; |
329 | hb_glyph_info_t *info = buffer->info; |
330 | for (unsigned int i = 1; i < count; i++) |
331 | { |
332 | if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) |
333 | { |
334 | if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) |
335 | buffer->merge_clusters (base, i); |
336 | buffer->reverse_range (base, i); |
337 | |
338 | base = i; |
339 | } |
340 | } |
341 | if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) |
342 | buffer->merge_clusters (base, count); |
343 | buffer->reverse_range (base, count); |
344 | |
345 | buffer->reverse (); |
346 | |
347 | buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction); |
348 | } |
349 | } |
350 | |
351 | |
352 | /* Substitute */ |
353 | |
354 | static inline void |
355 | hb_ot_mirror_chars (hb_ot_shape_context_t *c) |
356 | { |
357 | if (HB_DIRECTION_IS_FORWARD (c->target_direction)) |
358 | return; |
359 | |
360 | hb_buffer_t *buffer = c->buffer; |
361 | hb_unicode_funcs_t *unicode = buffer->unicode; |
362 | hb_mask_t rtlm_mask = c->plan->rtlm_mask; |
363 | |
364 | unsigned int count = buffer->len; |
365 | hb_glyph_info_t *info = buffer->info; |
366 | for (unsigned int i = 0; i < count; i++) { |
367 | hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint); |
368 | if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint))) |
369 | info[i].mask |= rtlm_mask; |
370 | else |
371 | info[i].codepoint = codepoint; |
372 | } |
373 | } |
374 | |
375 | static inline void |
376 | hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c) |
377 | { |
378 | if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) || |
379 | !c->plan->has_frac) |
380 | return; |
381 | |
382 | hb_buffer_t *buffer = c->buffer; |
383 | |
384 | hb_mask_t pre_mask, post_mask; |
385 | if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) |
386 | { |
387 | pre_mask = c->plan->numr_mask | c->plan->frac_mask; |
388 | post_mask = c->plan->frac_mask | c->plan->dnom_mask; |
389 | } |
390 | else |
391 | { |
392 | pre_mask = c->plan->frac_mask | c->plan->dnom_mask; |
393 | post_mask = c->plan->numr_mask | c->plan->frac_mask; |
394 | } |
395 | |
396 | unsigned int count = buffer->len; |
397 | hb_glyph_info_t *info = buffer->info; |
398 | for (unsigned int i = 0; i < count; i++) |
399 | { |
400 | if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */ |
401 | { |
402 | unsigned int start = i, end = i + 1; |
403 | while (start && |
404 | _hb_glyph_info_get_general_category (&info[start - 1]) == |
405 | HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) |
406 | start--; |
407 | while (end < count && |
408 | _hb_glyph_info_get_general_category (&info[end]) == |
409 | HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) |
410 | end++; |
411 | |
412 | buffer->unsafe_to_break (start, end); |
413 | |
414 | for (unsigned int j = start; j < i; j++) |
415 | info[j].mask |= pre_mask; |
416 | info[i].mask |= c->plan->frac_mask; |
417 | for (unsigned int j = i + 1; j < end; j++) |
418 | info[j].mask |= post_mask; |
419 | |
420 | i = end - 1; |
421 | } |
422 | } |
423 | } |
424 | |
425 | static inline void |
426 | hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c) |
427 | { |
428 | hb_ot_map_t *map = &c->plan->map; |
429 | hb_buffer_t *buffer = c->buffer; |
430 | |
431 | hb_mask_t global_mask = map->get_global_mask (); |
432 | buffer->reset_masks (global_mask); |
433 | } |
434 | |
435 | static inline void |
436 | hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) |
437 | { |
438 | hb_ot_map_t *map = &c->plan->map; |
439 | hb_buffer_t *buffer = c->buffer; |
440 | |
441 | hb_ot_shape_setup_masks_fraction (c); |
442 | |
443 | if (c->plan->shaper->setup_masks) |
444 | c->plan->shaper->setup_masks (c->plan, buffer, c->font); |
445 | |
446 | for (unsigned int i = 0; i < c->num_user_features; i++) |
447 | { |
448 | const hb_feature_t *feature = &c->user_features[i]; |
449 | if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { |
450 | unsigned int shift; |
451 | hb_mask_t mask = map->get_mask (feature->tag, &shift); |
452 | buffer->set_masks (feature->value << shift, mask, feature->start, feature->end); |
453 | } |
454 | } |
455 | } |
456 | |
457 | static void |
458 | hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c) |
459 | { |
460 | hb_buffer_t *buffer = c->buffer; |
461 | |
462 | if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) || |
463 | (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) || |
464 | (buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES)) |
465 | return; |
466 | |
467 | unsigned int count = buffer->len; |
468 | hb_glyph_info_t *info = buffer->info; |
469 | hb_glyph_position_t *pos = buffer->pos; |
470 | unsigned int i = 0; |
471 | for (i = 0; i < count; i++) |
472 | if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i]))) |
473 | pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0; |
474 | } |
475 | |
476 | static void |
477 | hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) |
478 | { |
479 | hb_buffer_t *buffer = c->buffer; |
480 | |
481 | if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) || |
482 | (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)) |
483 | return; |
484 | |
485 | unsigned int count = buffer->len; |
486 | hb_glyph_info_t *info = buffer->info; |
487 | hb_glyph_position_t *pos = buffer->pos; |
488 | unsigned int i = 0; |
489 | for (i = 0; i < count; i++) |
490 | { |
491 | if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i]))) |
492 | break; |
493 | } |
494 | |
495 | /* No default-ignorables found; return. */ |
496 | if (i == count) |
497 | return; |
498 | |
499 | hb_codepoint_t space; |
500 | if (!(buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) && |
501 | c->font->get_nominal_glyph (' ', &space)) |
502 | { |
503 | /* Replace default-ignorables with a zero-advance space glyph. */ |
504 | for (/*continue*/; i < count; i++) |
505 | { |
506 | if (_hb_glyph_info_is_default_ignorable (&info[i])) |
507 | info[i].codepoint = space; |
508 | } |
509 | } |
510 | else |
511 | { |
512 | /* Merge clusters and delete default-ignorables. |
513 | * NOTE! We can't use out-buffer as we have positioning data. */ |
514 | unsigned int j = i; |
515 | for (; i < count; i++) |
516 | { |
517 | if (_hb_glyph_info_is_default_ignorable (&info[i])) |
518 | { |
519 | /* Merge clusters. |
520 | * Same logic as buffer->delete_glyph(), but for in-place removal. */ |
521 | |
522 | unsigned int cluster = info[i].cluster; |
523 | if (i + 1 < count && cluster == info[i + 1].cluster) |
524 | continue; /* Cluster survives; do nothing. */ |
525 | |
526 | if (j) |
527 | { |
528 | /* Merge cluster backward. */ |
529 | if (cluster < info[j - 1].cluster) |
530 | { |
531 | unsigned int mask = info[i].mask; |
532 | unsigned int old_cluster = info[j - 1].cluster; |
533 | for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--) |
534 | buffer->set_cluster (info[k - 1], cluster, mask); |
535 | } |
536 | continue; |
537 | } |
538 | |
539 | if (i + 1 < count) |
540 | buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */ |
541 | |
542 | continue; |
543 | } |
544 | |
545 | if (j != i) |
546 | { |
547 | info[j] = info[i]; |
548 | pos[j] = pos[i]; |
549 | } |
550 | j++; |
551 | } |
552 | buffer->len = j; |
553 | } |
554 | } |
555 | |
556 | |
557 | static inline void |
558 | hb_ot_map_glyphs_fast (hb_buffer_t *buffer) |
559 | { |
560 | /* Normalization process sets up glyph_index(), we just copy it. */ |
561 | unsigned int count = buffer->len; |
562 | hb_glyph_info_t *info = buffer->info; |
563 | for (unsigned int i = 0; i < count; i++) |
564 | info[i].codepoint = info[i].glyph_index(); |
565 | |
566 | buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS; |
567 | } |
568 | |
569 | static inline void |
570 | hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) |
571 | { |
572 | unsigned int count = c->buffer->len; |
573 | hb_glyph_info_t *info = c->buffer->info; |
574 | for (unsigned int i = 0; i < count; i++) |
575 | { |
576 | hb_ot_layout_glyph_props_flags_t klass; |
577 | |
578 | /* Never mark default-ignorables as marks. |
579 | * They won't get in the way of lookups anyway, |
580 | * but having them as mark will cause them to be skipped |
581 | * over if the lookup-flag says so, but at least for the |
582 | * Mongolian variation selectors, looks like Uniscribe |
583 | * marks them as non-mark. Some Mongolian fonts without |
584 | * GDEF rely on this. Another notable character that |
585 | * this applies to is COMBINING GRAPHEME JOINER. */ |
586 | klass = (_hb_glyph_info_get_general_category (&info[i]) != |
587 | HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK || |
588 | _hb_glyph_info_is_default_ignorable (&info[i])) ? |
589 | HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : |
590 | HB_OT_LAYOUT_GLYPH_PROPS_MARK; |
591 | _hb_glyph_info_set_glyph_props (&info[i], klass); |
592 | } |
593 | } |
594 | |
595 | static inline void |
596 | hb_ot_substitute_default (hb_ot_shape_context_t *c) |
597 | { |
598 | hb_buffer_t *buffer = c->buffer; |
599 | |
600 | hb_ot_mirror_chars (c); |
601 | |
602 | HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index); |
603 | |
604 | _hb_ot_shape_normalize (c->plan, buffer, c->font); |
605 | |
606 | hb_ot_shape_setup_masks (c); |
607 | |
608 | /* This is unfortunate to go here, but necessary... */ |
609 | if (c->fallback_positioning) |
610 | _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer); |
611 | |
612 | hb_ot_map_glyphs_fast (buffer); |
613 | |
614 | HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index); |
615 | } |
616 | |
617 | static inline void |
618 | hb_ot_substitute_complex (hb_ot_shape_context_t *c) |
619 | { |
620 | hb_buffer_t *buffer = c->buffer; |
621 | |
622 | hb_ot_layout_substitute_start (c->font, buffer); |
623 | |
624 | if (!hb_ot_layout_has_glyph_classes (c->face)) |
625 | hb_synthesize_glyph_classes (c); |
626 | |
627 | c->plan->substitute (c->font, buffer); |
628 | |
629 | if (0) /* XXX Call morx instead. */ |
630 | hb_aat_layout_substitute (c->font, c->buffer); |
631 | } |
632 | |
633 | static inline void |
634 | hb_ot_substitute (hb_ot_shape_context_t *c) |
635 | { |
636 | hb_ot_substitute_default (c); |
637 | |
638 | _hb_buffer_allocate_gsubgpos_vars (c->buffer); |
639 | |
640 | hb_ot_substitute_complex (c); |
641 | } |
642 | |
643 | /* Position */ |
644 | |
645 | static inline void |
646 | adjust_mark_offsets (hb_glyph_position_t *pos) |
647 | { |
648 | pos->x_offset -= pos->x_advance; |
649 | pos->y_offset -= pos->y_advance; |
650 | } |
651 | |
652 | static inline void |
653 | zero_mark_width (hb_glyph_position_t *pos) |
654 | { |
655 | pos->x_advance = 0; |
656 | pos->y_advance = 0; |
657 | } |
658 | |
659 | static inline void |
660 | zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets) |
661 | { |
662 | unsigned int count = buffer->len; |
663 | hb_glyph_info_t *info = buffer->info; |
664 | for (unsigned int i = 0; i < count; i++) |
665 | if (_hb_glyph_info_is_mark (&info[i])) |
666 | { |
667 | if (adjust_offsets) |
668 | adjust_mark_offsets (&buffer->pos[i]); |
669 | zero_mark_width (&buffer->pos[i]); |
670 | } |
671 | } |
672 | |
673 | static inline void |
674 | hb_ot_position_default (hb_ot_shape_context_t *c) |
675 | { |
676 | hb_direction_t direction = c->buffer->props.direction; |
677 | unsigned int count = c->buffer->len; |
678 | hb_glyph_info_t *info = c->buffer->info; |
679 | hb_glyph_position_t *pos = c->buffer->pos; |
680 | |
681 | if (HB_DIRECTION_IS_HORIZONTAL (direction)) |
682 | { |
683 | c->font->get_glyph_h_advances (count, &info[0].codepoint, sizeof(info[0]), |
684 | &pos[0].x_advance, sizeof(pos[0])); |
685 | /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ |
686 | if (c->font->has_glyph_h_origin_func ()) |
687 | for (unsigned int i = 0; i < count; i++) |
688 | c->font->subtract_glyph_h_origin (info[i].codepoint, |
689 | &pos[i].x_offset, |
690 | &pos[i].y_offset); |
691 | } |
692 | else |
693 | { |
694 | c->font->get_glyph_v_advances (count, &info[0].codepoint, sizeof(info[0]), |
695 | &pos[0].y_advance, sizeof(pos[0])); |
696 | for (unsigned int i = 0; i < count; i++) |
697 | { |
698 | c->font->subtract_glyph_v_origin (info[i].codepoint, |
699 | &pos[i].x_offset, |
700 | &pos[i].y_offset); |
701 | } |
702 | } |
703 | if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK) |
704 | _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer); |
705 | } |
706 | |
707 | static inline void |
708 | hb_ot_position_complex (hb_ot_shape_context_t *c) |
709 | { |
710 | unsigned int count = c->buffer->len; |
711 | hb_glyph_info_t *info = c->buffer->info; |
712 | hb_glyph_position_t *pos = c->buffer->pos; |
713 | |
714 | /* If the font has no GPOS, AND, no fallback positioning will |
715 | * happen, AND, direction is forward, then when zeroing mark |
716 | * widths, we shift the mark with it, such that the mark |
717 | * is positioned hanging over the previous glyph. When |
718 | * direction is backward we don't shift and it will end up |
719 | * hanging over the next glyph after the final reordering. |
720 | * If fallback positinoing happens or GPOS is present, we don't |
721 | * care. |
722 | */ |
723 | bool adjust_offsets_when_zeroing = c->fallback_positioning && |
724 | !c->plan->shaper->fallback_position && |
725 | HB_DIRECTION_IS_FORWARD (c->buffer->props.direction); |
726 | |
727 | /* We change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */ |
728 | |
729 | /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ |
730 | if (c->font->has_glyph_h_origin_func ()) |
731 | for (unsigned int i = 0; i < count; i++) |
732 | c->font->add_glyph_h_origin (info[i].codepoint, |
733 | &pos[i].x_offset, |
734 | &pos[i].y_offset); |
735 | |
736 | hb_ot_layout_position_start (c->font, c->buffer); |
737 | |
738 | switch (c->plan->shaper->zero_width_marks) |
739 | { |
740 | case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: |
741 | zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); |
742 | break; |
743 | |
744 | default: |
745 | case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: |
746 | case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: |
747 | break; |
748 | } |
749 | |
750 | if (likely (!c->fallback_positioning)) |
751 | c->plan->position (c->font, c->buffer); |
752 | |
753 | switch (c->plan->shaper->zero_width_marks) |
754 | { |
755 | case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE: |
756 | zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing); |
757 | break; |
758 | |
759 | default: |
760 | case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE: |
761 | case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY: |
762 | break; |
763 | } |
764 | |
765 | /* Finishing off GPOS has to follow a certain order. */ |
766 | hb_ot_layout_position_finish_advances (c->font, c->buffer); |
767 | hb_ot_zero_width_default_ignorables (c); |
768 | hb_ot_layout_position_finish_offsets (c->font, c->buffer); |
769 | |
770 | /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ |
771 | if (c->font->has_glyph_h_origin_func ()) |
772 | for (unsigned int i = 0; i < count; i++) |
773 | c->font->subtract_glyph_h_origin (info[i].codepoint, |
774 | &pos[i].x_offset, |
775 | &pos[i].y_offset); |
776 | } |
777 | |
778 | static inline void |
779 | hb_ot_position (hb_ot_shape_context_t *c) |
780 | { |
781 | c->buffer->clear_positions (); |
782 | |
783 | hb_ot_position_default (c); |
784 | |
785 | hb_ot_position_complex (c); |
786 | |
787 | if (c->fallback_positioning && c->plan->shaper->fallback_position) |
788 | _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); |
789 | |
790 | if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) |
791 | hb_buffer_reverse (c->buffer); |
792 | |
793 | /* Visual fallback goes here. */ |
794 | |
795 | if (c->fallback_positioning) |
796 | _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); |
797 | |
798 | _hb_buffer_deallocate_gsubgpos_vars (c->buffer); |
799 | |
800 | //hb_aat_layout_position (c->font, c->buffer); |
801 | } |
802 | |
803 | static inline void |
804 | hb_propagate_flags (hb_buffer_t *buffer) |
805 | { |
806 | /* Propagate cluster-level glyph flags to be the same on all cluster glyphs. |
807 | * Simplifies using them. */ |
808 | |
809 | if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK)) |
810 | return; |
811 | |
812 | hb_glyph_info_t *info = buffer->info; |
813 | |
814 | foreach_cluster (buffer, start, end) |
815 | { |
816 | unsigned int mask = 0; |
817 | for (unsigned int i = start; i < end; i++) |
818 | if (info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) |
819 | { |
820 | mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK; |
821 | break; |
822 | } |
823 | if (mask) |
824 | for (unsigned int i = start; i < end; i++) |
825 | info[i].mask |= mask; |
826 | } |
827 | } |
828 | |
829 | /* Pull it all together! */ |
830 | |
831 | static void |
832 | hb_ot_shape_internal (hb_ot_shape_context_t *c) |
833 | { |
834 | c->buffer->deallocate_var_all (); |
835 | c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; |
836 | if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR))) |
837 | { |
838 | c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR, |
839 | (unsigned) HB_BUFFER_MAX_LEN_MIN); |
840 | } |
841 | if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR))) |
842 | { |
843 | c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR, |
844 | (unsigned) HB_BUFFER_MAX_OPS_MIN); |
845 | } |
846 | |
847 | bool disable_otl = c->plan->shaper->disable_otl && c->plan->shaper->disable_otl (c->plan); |
848 | //c->fallback_substitute = disable_otl || !hb_ot_layout_has_substitution (c->face); |
849 | c->fallback_positioning = disable_otl || !hb_ot_layout_has_positioning (c->face); |
850 | c->fallback_glyph_classes = disable_otl || !hb_ot_layout_has_glyph_classes (c->face); |
851 | |
852 | /* Save the original direction, we use it later. */ |
853 | c->target_direction = c->buffer->props.direction; |
854 | |
855 | _hb_buffer_allocate_unicode_vars (c->buffer); |
856 | |
857 | c->buffer->clear_output (); |
858 | |
859 | hb_ot_shape_initialize_masks (c); |
860 | hb_set_unicode_props (c->buffer); |
861 | hb_insert_dotted_circle (c->buffer, c->font); |
862 | |
863 | hb_form_clusters (c->buffer); |
864 | |
865 | hb_ensure_native_direction (c->buffer); |
866 | |
867 | if (c->plan->shaper->preprocess_text) |
868 | c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font); |
869 | |
870 | hb_ot_substitute (c); |
871 | hb_ot_position (c); |
872 | |
873 | hb_ot_hide_default_ignorables (c); |
874 | |
875 | if (c->plan->shaper->postprocess_glyphs) |
876 | c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font); |
877 | |
878 | hb_propagate_flags (c->buffer); |
879 | |
880 | _hb_buffer_deallocate_unicode_vars (c->buffer); |
881 | |
882 | c->buffer->props.direction = c->target_direction; |
883 | |
884 | c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT; |
885 | c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT; |
886 | c->buffer->deallocate_var_all (); |
887 | } |
888 | |
889 | |
890 | hb_bool_t |
891 | _hb_ot_shape (hb_shape_plan_t *shape_plan, |
892 | hb_font_t *font, |
893 | hb_buffer_t *buffer, |
894 | const hb_feature_t *features, |
895 | unsigned int num_features) |
896 | { |
897 | hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features}; |
898 | hb_ot_shape_internal (&c); |
899 | |
900 | return true; |
901 | } |
902 | |
903 | |
904 | /** |
905 | * hb_ot_shape_plan_collect_lookups: |
906 | * |
907 | * Since: 0.9.7 |
908 | **/ |
909 | void |
910 | hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, |
911 | hb_tag_t table_tag, |
912 | hb_set_t *lookup_indexes /* OUT */) |
913 | { |
914 | /* XXX Does the first part always succeed? */ |
915 | HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes); |
916 | } |
917 | |
918 | |
919 | /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */ |
920 | static void |
921 | add_char (hb_font_t *font, |
922 | hb_unicode_funcs_t *unicode, |
923 | hb_bool_t mirror, |
924 | hb_codepoint_t u, |
925 | hb_set_t *glyphs) |
926 | { |
927 | hb_codepoint_t glyph; |
928 | if (font->get_nominal_glyph (u, &glyph)) |
929 | glyphs->add (glyph); |
930 | if (mirror) |
931 | { |
932 | hb_codepoint_t m = unicode->mirroring (u); |
933 | if (m != u && font->get_nominal_glyph (m, &glyph)) |
934 | glyphs->add (glyph); |
935 | } |
936 | } |
937 | |
938 | |
939 | /** |
940 | * hb_ot_shape_glyphs_closure: |
941 | * |
942 | * Since: 0.9.2 |
943 | **/ |
944 | void |
945 | hb_ot_shape_glyphs_closure (hb_font_t *font, |
946 | hb_buffer_t *buffer, |
947 | const hb_feature_t *features, |
948 | unsigned int num_features, |
949 | hb_set_t *glyphs) |
950 | { |
951 | const char *shapers[] = {"ot" , nullptr}; |
952 | hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, |
953 | features, num_features, shapers); |
954 | |
955 | bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL; |
956 | |
957 | unsigned int count = buffer->len; |
958 | hb_glyph_info_t *info = buffer->info; |
959 | for (unsigned int i = 0; i < count; i++) |
960 | add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs); |
961 | |
962 | hb_set_t *lookups = hb_set_create (); |
963 | hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, lookups); |
964 | hb_ot_layout_lookups_substitute_closure (font->face, lookups, glyphs); |
965 | |
966 | hb_set_destroy (lookups); |
967 | |
968 | hb_shape_plan_destroy (shape_plan); |
969 | } |
970 | |