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
46static 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
55static 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
66static void
67hb_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
133HB_SHAPER_DATA_ENSURE_DEFINE(ot, face)
134
135hb_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
141void
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
152HB_SHAPER_DATA_ENSURE_DEFINE(ot, font)
153
154struct hb_ot_font_data_t {};
155
156hb_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
162void
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
172hb_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
206void
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
222struct 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
244static void
245hb_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
253static void
254hb_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
282static void
283hb_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
310static void
311hb_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
354static inline void
355hb_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
375static inline void
376hb_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
425static inline void
426hb_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
435static inline void
436hb_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
457static void
458hb_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
476static void
477hb_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
557static inline void
558hb_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
569static inline void
570hb_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
595static inline void
596hb_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
617static inline void
618hb_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
633static inline void
634hb_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
645static inline void
646adjust_mark_offsets (hb_glyph_position_t *pos)
647{
648 pos->x_offset -= pos->x_advance;
649 pos->y_offset -= pos->y_advance;
650}
651
652static inline void
653zero_mark_width (hb_glyph_position_t *pos)
654{
655 pos->x_advance = 0;
656 pos->y_advance = 0;
657}
658
659static inline void
660zero_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
673static inline void
674hb_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
707static inline void
708hb_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
778static inline void
779hb_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
803static inline void
804hb_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
831static void
832hb_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
890hb_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 **/
909void
910hb_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. */
920static void
921add_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 **/
944void
945hb_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