blob: 23da56c2f0ab7764af71e6e08f303e537233e396 [file] [log] [blame]
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +01001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 2009,2010 Red Hat, Inc.
Behdad Esfahbod07d68282012-08-10 03:28:50 -04003 * Copyright © 2010,2011,2012 Google, Inc.
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +01004 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04005 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +01006 *
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
Behdad Esfahbod476c9422010-10-07 17:47:33 -040026 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +010027 */
28
Behdad Esfahbod027857d2012-07-26 17:34:25 -040029#define HB_SHAPER ot
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -070030#define hb_ot_shape_plan_data_t hb_ot_shape_plan_t
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070031#include "hb-shaper-impl.hh"
Behdad Esfahbod027857d2012-07-26 17:34:25 -040032
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070033#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"
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +010037
Behdad Esfahbodb9291002018-08-26 01:15:47 -070038#include "hb-ot-face.hh"
Behdad Esfahbod10b6c7c2018-10-02 13:11:18 +020039
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070040#include "hb-set.hh"
Behdad Esfahbod72657e42011-05-02 20:46:32 -040041
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070042#include "hb-aat-layout.hh"
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040043
Behdad Esfahbod1d1734e2018-10-02 13:04:05 +020044
Behdad Esfahbod38a7a8a2018-10-10 17:44:46 -040045static bool
46_hb_apply_morx (hb_face_t *face)
47{
48 if (hb_options ().aat &&
49 hb_aat_layout_has_substitution (face))
50 return true;
51
52 return !hb_ot_layout_has_substitution (face) &&
53 hb_aat_layout_has_substitution (face);
54}
55
Behdad Esfahbod76324d92018-10-23 13:09:30 -070056hb_ot_shape_planner_t::hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) :
57 face (master_plan->face_unsafe),
58 props (master_plan->props),
59 map (face, &props),
Behdad Esfahbodffe34782018-10-23 14:14:03 -070060 aat_map (face, &props),
Behdad Esfahbod76324d92018-10-23 13:09:30 -070061 apply_morx (_hb_apply_morx (face)),
62 shaper (apply_morx ?
63 &_hb_ot_complex_shaper_default :
64 hb_ot_shape_complex_categorize (this)) {}
65
Behdad Esfahbod1d1734e2018-10-02 13:04:05 +020066void
67hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
68 const int *coords,
69 unsigned int num_coords)
70{
71 plan.props = props;
72 plan.shaper = shaper;
73 map.compile (plan.map, coords, num_coords);
Behdad Esfahbodffe34782018-10-23 14:14:03 -070074 aat_map.compile (plan.aat_map, coords, num_coords);
Behdad Esfahbod1d1734e2018-10-02 13:04:05 +020075
Behdad Esfahbod1d1734e2018-10-02 13:04:05 +020076 plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
77 plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r'));
78 plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m'));
Behdad Esfahbod1d1734e2018-10-02 13:04:05 +020079 plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
Behdad Esfahbodcf92d652018-10-23 03:10:56 -070080 plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
Behdad Esfahbod961ab462018-10-10 10:42:10 -040081 hb_tag_t kern_tag = HB_DIRECTION_IS_HORIZONTAL (plan.props.direction) ?
82 HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n');
83 plan.kern_mask = plan.map.get_mask (kern_tag);
Behdad Esfahbodcf92d652018-10-23 03:10:56 -070084 plan.trak_mask = plan.map.get_mask (HB_TAG ('t','r','a','k'));
Behdad Esfahbod961ab462018-10-10 10:42:10 -040085
Behdad Esfahbod60f86d32018-10-10 18:10:05 -040086 plan.requested_kerning = !!plan.kern_mask;
Behdad Esfahbodcf92d652018-10-23 03:10:56 -070087 plan.requested_tracking = !!plan.trak_mask;
Behdad Esfahboda03850a2018-10-10 10:57:28 -040088 bool has_gpos_kern = plan.map.get_feature_index (1, kern_tag) != HB_OT_LAYOUT_NO_FEATURE_INDEX;
Behdad Esfahbod961ab462018-10-10 10:42:10 -040089 bool disable_gpos = plan.shaper->gpos_tag &&
90 plan.shaper->gpos_tag != plan.map.chosen_script[1];
Behdad Esfahbod96eca872018-10-02 13:24:40 +020091
Behdad Esfahbodd1be8052018-10-10 10:49:45 -040092 /*
93 * Decide who provides glyph classes. GDEF or Unicode.
94 */
Behdad Esfahbode655fd32018-10-10 10:16:09 -040095
Behdad Esfahbodd1be8052018-10-10 10:49:45 -040096 if (!hb_ot_layout_has_glyph_classes (face))
97 plan.fallback_glyph_classes = true;
Behdad Esfahbod14ff3cb2018-10-04 11:34:21 +020098
Behdad Esfahbodd1be8052018-10-10 10:49:45 -040099 /*
100 * Decide who does substitutions. GSUB, morx, or fallback.
101 */
Behdad Esfahbode655fd32018-10-10 10:16:09 -0400102
Behdad Esfahbod76324d92018-10-23 13:09:30 -0700103 plan.apply_morx = apply_morx;
Behdad Esfahbodd1be8052018-10-10 10:49:45 -0400104
105 /*
106 * Decide who does positioning. GPOS, kerx, kern, or fallback.
107 */
108
Behdad Esfahbod38a7a8a2018-10-10 17:44:46 -0400109 if (hb_options ().aat && hb_aat_layout_has_positioning (face))
110 plan.apply_kerx = true;
111 else if (!disable_gpos && hb_ot_layout_has_positioning (face))
Behdad Esfahbodd1be8052018-10-10 10:49:45 -0400112 plan.apply_gpos = true;
113 else if (hb_aat_layout_has_positioning (face))
114 plan.apply_kerx = true;
115
Behdad Esfahbod0b9d60e2018-10-11 13:26:58 -0400116 if (plan.requested_kerning && !plan.apply_kerx && !has_gpos_kern)
Behdad Esfahbodd1be8052018-10-10 10:49:45 -0400117 {
Behdad Esfahbod0b9d60e2018-10-11 13:26:58 -0400118 /* Apparently Apple applies kerx if GPOS kern was not applied. */
119 if (hb_aat_layout_has_positioning (face))
120 plan.apply_kerx = true;
121 if (hb_ot_layout_has_kerning (face))
122 plan.apply_kern = true;
123 else
124 plan.fallback_kerning = true;
Behdad Esfahbodd1be8052018-10-10 10:49:45 -0400125 }
Behdad Esfahbode655fd32018-10-10 10:16:09 -0400126
127 plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
Behdad Esfahbod504cb682018-10-10 21:29:46 -0400128 if (!plan.apply_gpos && !plan.apply_kerx)
Behdad Esfahbodd1be8052018-10-10 10:49:45 -0400129 plan.fallback_mark_positioning = true;
Behdad Esfahbodb59a4282018-10-11 13:24:17 -0400130
131 /* Currently we always apply trak. */
Behdad Esfahbodcf92d652018-10-23 03:10:56 -0700132 plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face);
Behdad Esfahbod1d1734e2018-10-02 13:04:05 +0200133}
134
135
Behdad Esfahbod94d15522018-10-02 14:45:09 +0200136static const hb_ot_map_feature_t
137common_features[] =
Behdad Esfahbod1d1734e2018-10-02 13:04:05 +0200138{
Behdad Esfahbod94d15522018-10-02 14:45:09 +0200139 {HB_TAG('c','c','m','p'), F_GLOBAL},
140 {HB_TAG('l','o','c','l'), F_GLOBAL},
141 {HB_TAG('m','a','r','k'), F_GLOBAL_MANUAL_JOINERS},
142 {HB_TAG('m','k','m','k'), F_GLOBAL_MANUAL_JOINERS},
143 {HB_TAG('r','l','i','g'), F_GLOBAL},
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -0400144};
145
Behdad Esfahbodd1deaa22012-05-09 15:04:13 +0200146
Behdad Esfahbod94d15522018-10-02 14:45:09 +0200147static const hb_ot_map_feature_t
148horizontal_features[] =
Behdad Esfahbod1d1734e2018-10-02 13:04:05 +0200149{
Behdad Esfahbod94d15522018-10-02 14:45:09 +0200150 {HB_TAG('c','a','l','t'), F_GLOBAL},
151 {HB_TAG('c','l','i','g'), F_GLOBAL},
152 {HB_TAG('c','u','r','s'), F_GLOBAL},
153 {HB_TAG('k','e','r','n'), F_GLOBAL_HAS_FALLBACK},
154 {HB_TAG('l','i','g','a'), F_GLOBAL},
155 {HB_TAG('r','c','l','t'), F_GLOBAL},
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -0400156};
157
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100158static void
Behdad Esfahbod90645fb2011-05-27 18:13:31 -0400159hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
Behdad Esfahbod49baa1f2010-10-12 16:50:36 -0400160 const hb_segment_properties_t *props,
Behdad Esfahbod90645fb2011-05-27 18:13:31 -0400161 const hb_feature_t *user_features,
162 unsigned int num_user_features)
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100163{
Behdad Esfahbod8bb5deb2012-08-02 10:07:58 -0400164 hb_ot_map_builder_t *map = &planner->map;
Behdad Esfahbodffe34782018-10-23 14:14:03 -0700165 hb_aat_map_builder_t *aat_map = &planner->aat_map;
Behdad Esfahbod8bb5deb2012-08-02 10:07:58 -0400166
Behdad Esfahbodf048ead2018-09-24 18:01:53 -0400167 map->enable_feature (HB_TAG('r','v','r','n'));
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200168 map->add_gsub_pause (nullptr);
Behdad Esfahbod0aedfd52016-09-28 17:05:43 +0200169
Behdad Esfahbod895fb5d2010-10-12 16:00:21 -0400170 switch (props->direction) {
Behdad Esfahbod074ea782010-05-21 17:53:10 +0100171 case HB_DIRECTION_LTR:
Behdad Esfahbodf048ead2018-09-24 18:01:53 -0400172 map->enable_feature (HB_TAG ('l','t','r','a'));
173 map->enable_feature (HB_TAG ('l','t','r','m'));
Behdad Esfahbod074ea782010-05-21 17:53:10 +0100174 break;
175 case HB_DIRECTION_RTL:
Behdad Esfahbodf048ead2018-09-24 18:01:53 -0400176 map->enable_feature (HB_TAG ('r','t','l','a'));
177 map->add_feature (HB_TAG ('r','t','l','m'));
Behdad Esfahbod0e235d02010-05-28 20:21:47 -0400178 break;
179 case HB_DIRECTION_TTB:
180 case HB_DIRECTION_BTT:
Behdad Esfahbod3286fc02011-03-16 14:53:32 -0300181 case HB_DIRECTION_INVALID:
Behdad Esfahbod0e235d02010-05-28 20:21:47 -0400182 default:
183 break;
184 }
185
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200186 /* Automatic fractions. */
Behdad Esfahbodf048ead2018-09-24 18:01:53 -0400187 map->add_feature (HB_TAG ('f','r','a','c'));
188 map->add_feature (HB_TAG ('n','u','m','r'));
189 map->add_feature (HB_TAG ('d','n','o','m'));
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500190
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200191 /* Random! */
Behdad Esfahbod0a371fe2018-10-02 14:48:39 +0200192 map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE);
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200193
Behdad Esfahbodcf92d652018-10-23 03:10:56 -0700194 /* Tracking. We enable dummy feature here just to allow disabling
195 * AAT 'trak' table using features.
196 * https://github.com/harfbuzz/harfbuzz/issues/1303 */
Ebrahim Byagowi22ecefd2018-10-23 00:52:05 +0330197 map->enable_feature (HB_TAG ('t','r','a','k'), F_HAS_FALLBACK);
198
199 map->enable_feature (HB_TAG ('H','A','R','F'));
Behdad Esfahboda01194a2018-10-04 13:00:37 +0200200
Behdad Esfahbod693918e2012-07-30 21:08:51 -0400201 if (planner->shaper->collect_features)
Behdad Esfahbod16c6a272012-08-02 09:38:28 -0400202 planner->shaper->collect_features (planner);
Behdad Esfahbode04685e2010-05-28 20:37:06 -0400203
Ebrahim Byagowi22ecefd2018-10-23 00:52:05 +0330204 map->enable_feature (HB_TAG ('B','U','Z','Z'));
Behdad Esfahboda01194a2018-10-04 13:00:37 +0200205
Behdad Esfahbodee9c3a12013-02-15 06:22:26 -0500206 for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
Behdad Esfahbod94d15522018-10-02 14:45:09 +0200207 map->add_feature (common_features[i]);
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -0400208
209 if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
Behdad Esfahbodee9c3a12013-02-15 06:22:26 -0500210 for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
Behdad Esfahbod94d15522018-10-02 14:45:09 +0200211 map->add_feature (horizontal_features[i]);
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -0400212 else
Behdad Esfahbodf327aac2015-07-23 11:32:59 +0100213 {
Behdad Esfahbod0f98fe82015-07-23 11:52:11 +0100214 /* We really want to find a 'vert' feature if there's any in the font, no
215 * matter which script/langsys it is listed (or not) under.
216 * See various bugs referenced from:
ebraminio7c6937e2017-11-20 14:49:22 -0500217 * https://github.com/harfbuzz/harfbuzz/issues/63 */
Behdad Esfahbod0a371fe2018-10-02 14:48:39 +0200218 map->enable_feature (HB_TAG ('v','e','r','t'), F_GLOBAL_SEARCH);
Behdad Esfahbodf327aac2015-07-23 11:32:59 +0100219 }
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -0400220
Behdad Esfahbod693918e2012-07-30 21:08:51 -0400221 if (planner->shaper->override_features)
Behdad Esfahbod16c6a272012-08-02 09:38:28 -0400222 planner->shaper->override_features (planner);
Behdad Esfahbodd96838e2012-07-16 20:26:57 -0400223
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200224 for (unsigned int i = 0; i < num_user_features; i++)
225 {
Behdad Esfahbod895fb5d2010-10-12 16:00:21 -0400226 const hb_feature_t *feature = &user_features[i];
Behdad Esfahbodf048ead2018-09-24 18:01:53 -0400227 map->add_feature (feature->tag,
Behdad Esfahbodd9867492018-09-24 18:11:59 -0400228 (feature->start == HB_FEATURE_GLOBAL_START &&
229 feature->end == HB_FEATURE_GLOBAL_END) ? F_GLOBAL : F_NONE,
Behdad Esfahbodf048ead2018-09-24 18:01:53 -0400230 feature->value);
Behdad Esfahbodffe34782018-10-23 14:14:03 -0700231 aat_map->add_feature (feature->tag, feature->value);
Behdad Esfahbode04685e2010-05-28 20:37:06 -0400232 }
Behdad Esfahbode89b7d22010-10-08 12:29:59 -0400233}
Behdad Esfahbod0e235d02010-05-28 20:21:47 -0400234
235
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400236/*
237 * shaper face data
238 */
239
Behdad Esfahbod466b3e52017-02-03 16:43:25 -0800240HB_SHAPER_DATA_ENSURE_DEFINE(ot, face)
241
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700242hb_ot_face_data_t *
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400243_hb_ot_shaper_face_data_create (hb_face_t *face)
244{
Behdad Esfahbod1c6b3692018-08-15 20:12:25 -0700245 return _hb_ot_face_data_create (face);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400246}
247
248void
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700249_hb_ot_shaper_face_data_destroy (hb_ot_face_data_t *data)
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400250{
Behdad Esfahbod1c6b3692018-08-15 20:12:25 -0700251 _hb_ot_face_data_destroy (data);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400252}
253
254
255/*
256 * shaper font data
257 */
258
Behdad Esfahbod466b3e52017-02-03 16:43:25 -0800259HB_SHAPER_DATA_ENSURE_DEFINE(ot, font)
260
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700261struct hb_ot_font_data_t {};
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400262
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700263hb_ot_font_data_t *
Behdad Esfahbod89137e32016-02-22 16:00:59 +0900264_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400265{
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700266 return (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400267}
268
269void
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700270_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data)
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400271{
272}
273
274
275/*
276 * shaper shape_plan data
277 */
278
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700279hb_ot_shape_plan_data_t *
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400280_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
281 const hb_feature_t *user_features,
Behdad Esfahbod72ada4f2016-09-10 03:57:24 -0700282 unsigned int num_user_features,
283 const int *coords,
284 unsigned int num_coords)
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400285{
Behdad Esfahboda8c6da92012-08-02 10:46:34 -0400286 hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
287 if (unlikely (!plan))
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200288 return nullptr;
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400289
Behdad Esfahbodf9abbf82018-06-02 15:30:59 -0700290 plan->init ();
291
Behdad Esfahbod5393e3a2012-08-02 09:24:35 -0400292 hb_ot_shape_planner_t planner (shape_plan);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400293
Behdad Esfahbod72ada4f2016-09-10 03:57:24 -0700294 hb_ot_shape_collect_features (&planner, &shape_plan->props,
295 user_features, num_user_features);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400296
Behdad Esfahbod72ada4f2016-09-10 03:57:24 -0700297 planner.compile (*plan, coords, num_coords);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400298
Behdad Esfahboda8c6da92012-08-02 10:46:34 -0400299 if (plan->shaper->data_create) {
300 plan->data = plan->shaper->data_create (plan);
Behdad Esfahbod42c183f2018-07-27 14:55:29 -0700301 if (unlikely (!plan->data))
302 {
303 free (plan);
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200304 return nullptr;
prrace2e25d8f2018-07-27 13:58:27 -0700305 }
Behdad Esfahboda8c6da92012-08-02 10:46:34 -0400306 }
307
308 return plan;
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400309}
310
311void
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700312_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shape_plan_data_t *plan)
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400313{
Behdad Esfahboda8c6da92012-08-02 10:46:34 -0400314 if (plan->shaper->data_destroy)
315 plan->shaper->data_destroy (const_cast<void *> (plan->data));
Behdad Esfahbod4ba647e2012-07-30 09:53:06 -0400316
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400317 plan->fini ();
Behdad Esfahboda8c6da92012-08-02 10:46:34 -0400318
319 free (plan);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400320}
321
322
323/*
324 * shaper
325 */
326
Behdad Esfahbodb9f199c2012-04-14 20:23:58 -0400327struct hb_ot_shape_context_t
328{
Behdad Esfahbodb9f199c2012-04-14 20:23:58 -0400329 hb_ot_shape_plan_t *plan;
330 hb_font_t *font;
331 hb_face_t *face;
332 hb_buffer_t *buffer;
333 const hb_feature_t *user_features;
334 unsigned int num_user_features;
335
336 /* Transient stuff */
337 hb_direction_t target_direction;
Behdad Esfahbodb9f199c2012-04-14 20:23:58 -0400338};
339
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100340
341
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100342/* Main shaper */
343
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400344
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100345/* Prepare */
346
Behdad Esfahbodb9f199c2012-04-14 20:23:58 -0400347static void
348hb_set_unicode_props (hb_buffer_t *buffer)
Behdad Esfahbod3a852ae2010-11-03 16:37:24 -0400349{
Behdad Esfahbod3b783182018-10-03 19:44:15 +0200350 /* Implement enough of Unicode Graphemes here that shaping
351 * in reverse-direction wouldn't break graphemes. Namely,
352 * we mark all marks and ZWJ and ZWJ,Extended_Pictographic
353 * sequences as continuations. The foreach_grapheme()
354 * macro uses this bit.
355 *
356 * https://www.unicode.org/reports/tr29/#Regex_Definitions
357 */
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400358 unsigned int count = buffer->len;
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400359 hb_glyph_info_t *info = buffer->info;
Behdad Esfahbod0e336142012-04-12 10:06:52 -0400360 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod3b783182018-10-03 19:44:15 +0200361 {
Behdad Esfahbod69862082015-11-04 18:46:22 -0800362 _hb_glyph_info_set_unicode_props (&info[i], buffer);
Behdad Esfahbod3b783182018-10-03 19:44:15 +0200363
364 /* Marks are already set as continuation by the above line.
Behdad Esfahbodb710ea42018-10-03 21:17:59 +0200365 * Handle Emoji_Modifier and ZWJ-continuation. */
366 if (unlikely (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
367 hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu)))
368 {
369 _hb_glyph_info_set_continuation (&info[i]);
370 }
371 else if (unlikely (_hb_glyph_info_is_zwj (&info[i])))
Behdad Esfahbod3b783182018-10-03 19:44:15 +0200372 {
373 _hb_glyph_info_set_continuation (&info[i]);
374 if (i + 1 < count &&
375 _hb_unicode_is_emoji_Extended_Pictographic (info[i + 1].codepoint))
376 {
377 i++;
378 _hb_glyph_info_set_unicode_props (&info[i], buffer);
379 _hb_glyph_info_set_continuation (&info[i]);
380 }
381 }
382 }
Behdad Esfahbod3a852ae2010-11-03 16:37:24 -0400383}
384
385static void
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400386hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
387{
Behdad Esfahbod0c7df222012-11-13 14:42:35 -0800388 if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
Behdad Esfahbod763e5462014-08-02 16:17:44 -0400389 buffer->context_len[0] ||
Behdad Esfahbod123326e2018-10-03 19:19:51 +0200390 !_hb_glyph_info_is_unicode_mark (&buffer->info[0]))
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400391 return;
392
Behdad Esfahbod76271002014-07-11 14:54:42 -0400393 if (!font->has_glyph (0x25CCu))
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400394 return;
395
Behdad Esfahbod595d2b92014-07-26 18:44:15 -0400396 hb_glyph_info_t dottedcircle = {0};
Behdad Esfahbod76271002014-07-11 14:54:42 -0400397 dottedcircle.codepoint = 0x25CCu;
Behdad Esfahbod69862082015-11-04 18:46:22 -0800398 _hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400399
400 buffer->clear_output ();
401
402 buffer->idx = 0;
403 hb_glyph_info_t info = dottedcircle;
404 info.cluster = buffer->cur().cluster;
405 info.mask = buffer->cur().mask;
406 buffer->output_info (info);
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700407 while (buffer->idx < buffer->len && buffer->successful)
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400408 buffer->next_glyph ();
409
410 buffer->swap_buffers ();
411}
412
413static void
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400414hb_form_clusters (hb_buffer_t *buffer)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100415{
Behdad Esfahbod7cc34802017-09-04 20:04:59 -0700416 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
Behdad Esfahbod376d5872015-07-22 16:51:12 +0100417 return;
418
Behdad Esfahbod7cc34802017-09-04 20:04:59 -0700419 if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
Behdad Esfahbod03fb6dd2018-10-03 21:02:16 +0200420 foreach_grapheme (buffer, start, end)
421 buffer->merge_clusters (start, end);
Behdad Esfahbod7cc34802017-09-04 20:04:59 -0700422 else
Behdad Esfahbod03fb6dd2018-10-03 21:02:16 +0200423 foreach_grapheme (buffer, start, end)
424 buffer->unsafe_to_break (start, end);
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100425}
426
Behdad Esfahbod967240d2010-10-05 23:00:05 -0400427static void
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400428hb_ensure_native_direction (hb_buffer_t *buffer)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100429{
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400430 hb_direction_t direction = buffer->props.direction;
Behdad Esfahbodf673cfb2018-05-07 13:58:32 -0700431 hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script);
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100432
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400433 /* TODO vertical:
434 * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
435 * Ogham fonts are supposed to be implemented BTT or not. Need to research that
436 * first. */
Behdad Esfahbodf673cfb2018-05-07 13:58:32 -0700437 if ((HB_DIRECTION_IS_HORIZONTAL (direction) &&
438 direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) ||
439 (HB_DIRECTION_IS_VERTICAL (direction) &&
440 direction != HB_DIRECTION_TTB))
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100441 {
Behdad Esfahbodf883de62015-09-01 16:23:40 +0100442
Behdad Esfahbod376d5872015-07-22 16:51:12 +0100443 if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
Behdad Esfahbod03fb6dd2018-10-03 21:02:16 +0200444 foreach_grapheme (buffer, start, end)
445 {
446 buffer->merge_clusters (start, end);
447 buffer->reverse_range (start, end);
448 }
449 else
450 foreach_grapheme (buffer, start, end)
451 /* form_clusters() merged clusters already, we don't merge. */
452 buffer->reverse_range (start, end);
Behdad Esfahboda60e2cf2015-07-22 15:49:08 +0100453
454 buffer->reverse ();
455
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400456 buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100457 }
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100458}
459
460
461/* Substitute */
462
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400463static inline void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400464hb_ot_mirror_chars (const hb_ot_shape_context_t *c)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100465{
Behdad Esfahbodbbbbe802010-12-07 16:22:02 -0500466 if (HB_DIRECTION_IS_FORWARD (c->target_direction))
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100467 return;
468
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200469 hb_buffer_t *buffer = c->buffer;
470 hb_unicode_funcs_t *unicode = buffer->unicode;
Behdad Esfahbod5497a8a2013-12-22 20:48:53 -0500471 hb_mask_t rtlm_mask = c->plan->rtlm_mask;
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400472
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200473 unsigned int count = buffer->len;
474 hb_glyph_info_t *info = buffer->info;
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100475 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200476 hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
Behdad Esfahbod7b8b63a2015-07-22 15:24:26 +0100477 if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200478 info[i].mask |= rtlm_mask;
Behdad Esfahbod1094a292010-05-21 17:58:20 +0100479 else
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200480 info[i].codepoint = codepoint;
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100481 }
482}
483
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400484static inline void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400485hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c)
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500486{
Behdad Esfahbode3e4bb02015-11-04 18:58:02 -0800487 if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
488 !c->plan->has_frac)
Behdad Esfahbod5497a8a2013-12-22 20:48:53 -0500489 return;
490
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500491 hb_buffer_t *buffer = c->buffer;
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500492
Khaled Hosny24525432017-01-18 22:48:13 +0200493 hb_mask_t pre_mask, post_mask;
494 if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
495 {
496 pre_mask = c->plan->numr_mask | c->plan->frac_mask;
497 post_mask = c->plan->frac_mask | c->plan->dnom_mask;
498 }
499 else
500 {
501 pre_mask = c->plan->frac_mask | c->plan->dnom_mask;
502 post_mask = c->plan->numr_mask | c->plan->frac_mask;
503 }
504
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500505 unsigned int count = buffer->len;
506 hb_glyph_info_t *info = buffer->info;
507 for (unsigned int i = 0; i < count; i++)
508 {
Behdad Esfahbod76271002014-07-11 14:54:42 -0400509 if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500510 {
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500511 unsigned int start = i, end = i + 1;
512 while (start &&
513 _hb_glyph_info_get_general_category (&info[start - 1]) ==
514 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
515 start--;
516 while (end < count &&
517 _hb_glyph_info_get_general_category (&info[end]) ==
518 HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
519 end++;
520
Behdad Esfahbodc449d2d2017-08-30 17:28:22 -0700521 buffer->unsafe_to_break (start, end);
522
Behdad Esfahboda7e8bbb2013-12-22 19:33:35 -0500523 for (unsigned int j = start; j < i; j++)
Khaled Hosny24525432017-01-18 22:48:13 +0200524 info[j].mask |= pre_mask;
Behdad Esfahbod5497a8a2013-12-22 20:48:53 -0500525 info[i].mask |= c->plan->frac_mask;
Behdad Esfahboda7e8bbb2013-12-22 19:33:35 -0500526 for (unsigned int j = i + 1; j < end; j++)
Khaled Hosny24525432017-01-18 22:48:13 +0200527 info[j].mask |= post_mask;
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500528
529 i = end - 1;
530 }
531 }
532}
533
534static inline void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400535hb_ot_shape_initialize_masks (const hb_ot_shape_context_t *c)
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400536{
537 hb_ot_map_t *map = &c->plan->map;
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200538 hb_buffer_t *buffer = c->buffer;
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400539
540 hb_mask_t global_mask = map->get_global_mask ();
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200541 buffer->reset_masks (global_mask);
Behdad Esfahbod73932512013-12-21 00:18:18 -0500542}
543
544static inline void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400545hb_ot_shape_setup_masks (const hb_ot_shape_context_t *c)
Behdad Esfahbod73932512013-12-21 00:18:18 -0500546{
547 hb_ot_map_t *map = &c->plan->map;
548 hb_buffer_t *buffer = c->buffer;
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400549
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500550 hb_ot_shape_setup_masks_fraction (c);
551
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400552 if (c->plan->shaper->setup_masks)
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200553 c->plan->shaper->setup_masks (c->plan, buffer, c->font);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400554
555 for (unsigned int i = 0; i < c->num_user_features; i++)
556 {
557 const hb_feature_t *feature = &c->user_features[i];
558 if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
559 unsigned int shift;
560 hb_mask_t mask = map->get_mask (feature->tag, &shift);
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200561 buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400562 }
563 }
564}
565
Behdad Esfahbod8cfbc302015-07-22 18:41:10 +0100566static void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400567hb_ot_zero_width_default_ignorables (const hb_ot_shape_context_t *c)
Behdad Esfahbod8cfbc302015-07-22 18:41:10 +0100568{
569 hb_buffer_t *buffer = c->buffer;
570
Behdad Esfahbod69862082015-11-04 18:46:22 -0800571 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
Behdad Esfahbod3b1e97f2018-01-10 03:35:20 +0100572 (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) ||
573 (buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES))
Behdad Esfahbod8cfbc302015-07-22 18:41:10 +0100574 return;
575
576 unsigned int count = buffer->len;
577 hb_glyph_info_t *info = buffer->info;
578 hb_glyph_position_t *pos = buffer->pos;
579 unsigned int i = 0;
580 for (i = 0; i < count; i++)
581 if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
582 pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
583}
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100584
585static void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400586hb_ot_hide_default_ignorables (const hb_ot_shape_context_t *c)
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100587{
588 hb_buffer_t *buffer = c->buffer;
589
Behdad Esfahbod69862082015-11-04 18:46:22 -0800590 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
591 (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100592 return;
593
594 unsigned int count = buffer->len;
595 hb_glyph_info_t *info = buffer->info;
596 hb_glyph_position_t *pos = buffer->pos;
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100597
Behdad Esfahbod71b65eb2018-10-07 18:41:52 +0200598 hb_codepoint_t invisible = c->buffer->invisible;
Behdad Esfahbod3b1e97f2018-01-10 03:35:20 +0100599 if (!(buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) &&
Behdad Esfahbod71b65eb2018-10-07 18:41:52 +0200600 (invisible || c->font->get_nominal_glyph (' ', &invisible)))
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100601 {
Behdad Esfahbod71b65eb2018-10-07 18:41:52 +0200602 /* Replace default-ignorables with a zero-advance invisible glyph. */
Behdad Esfahbod94368852018-10-07 18:52:12 -0400603 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100604 {
Behdad Esfahbod4ba796b2015-07-22 17:41:31 +0100605 if (_hb_glyph_info_is_default_ignorable (&info[i]))
Behdad Esfahbod71b65eb2018-10-07 18:41:52 +0200606 info[i].codepoint = invisible;
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100607 }
608 }
609 else
610 {
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100611 /* Merge clusters and delete default-ignorables.
612 * NOTE! We can't use out-buffer as we have positioning data. */
Behdad Esfahbod94368852018-10-07 18:52:12 -0400613 unsigned int j = 0;
614 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100615 {
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100616 if (_hb_glyph_info_is_default_ignorable (&info[i]))
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100617 {
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100618 /* Merge clusters.
619 * Same logic as buffer->delete_glyph(), but for in-place removal. */
620
621 unsigned int cluster = info[i].cluster;
622 if (i + 1 < count && cluster == info[i + 1].cluster)
623 continue; /* Cluster survives; do nothing. */
624
625 if (j)
626 {
627 /* Merge cluster backward. */
628 if (cluster < info[j - 1].cluster)
629 {
Behdad Esfahbode2a2b5b2017-08-10 20:10:12 -0700630 unsigned int mask = info[i].mask;
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100631 unsigned int old_cluster = info[j - 1].cluster;
632 for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
Behdad Esfahbode2a2b5b2017-08-10 20:10:12 -0700633 buffer->set_cluster (info[k - 1], cluster, mask);
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100634 }
635 continue;
636 }
637
638 if (i + 1 < count)
639 buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
640
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100641 continue;
642 }
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100643
644 if (j != i)
645 {
646 info[j] = info[i];
647 pos[j] = pos[i];
648 }
649 j++;
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100650 }
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100651 buffer->len = j;
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100652 }
653}
654
655
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400656static inline void
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400657hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100658{
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400659 /* Normalization process sets up glyph_index(), we just copy it. */
660 unsigned int count = buffer->len;
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400661 hb_glyph_info_t *info = buffer->info;
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400662 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400663 info[i].codepoint = info[i].glyph_index();
Behdad Esfahbode47b7722015-08-18 18:42:47 +0100664
665 buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100666}
667
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400668static inline void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400669hb_synthesize_glyph_classes (const hb_ot_shape_context_t *c)
Behdad Esfahbod1a0f4aa2016-12-22 13:33:54 -0600670{
671 unsigned int count = c->buffer->len;
672 hb_glyph_info_t *info = c->buffer->info;
673 for (unsigned int i = 0; i < count; i++)
674 {
675 hb_ot_layout_glyph_props_flags_t klass;
676
677 /* Never mark default-ignorables as marks.
678 * They won't get in the way of lookups anyway,
679 * but having them as mark will cause them to be skipped
680 * over if the lookup-flag says so, but at least for the
681 * Mongolian variation selectors, looks like Uniscribe
682 * marks them as non-mark. Some Mongolian fonts without
683 * GDEF rely on this. Another notable character that
684 * this applies to is COMBINING GRAPHEME JOINER. */
685 klass = (_hb_glyph_info_get_general_category (&info[i]) !=
686 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
687 _hb_glyph_info_is_default_ignorable (&info[i])) ?
688 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
689 HB_OT_LAYOUT_GLYPH_PROPS_MARK;
690 _hb_glyph_info_set_glyph_props (&info[i], klass);
691 }
692}
693
694static inline void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400695hb_ot_substitute_default (const hb_ot_shape_context_t *c)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100696{
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200697 hb_buffer_t *buffer = c->buffer;
698
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400699 hb_ot_mirror_chars (c);
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400700
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200701 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400702
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200703 _hb_ot_shape_normalize (c->plan, buffer, c->font);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400704
705 hb_ot_shape_setup_masks (c);
706
Behdad Esfahbod3992b5e2012-09-01 19:20:41 -0400707 /* This is unfortunate to go here, but necessary... */
Behdad Esfahbod09ad2612018-10-08 23:30:24 -0400708 if (c->plan->fallback_mark_positioning)
709 _hb_ot_shape_fallback_mark_position_recategorize_marks (c->plan, c->font, buffer);
Behdad Esfahbod3992b5e2012-09-01 19:20:41 -0400710
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200711 hb_ot_map_glyphs_fast (buffer);
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400712
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200713 HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100714}
715
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400716static inline void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400717hb_ot_substitute_complex (const hb_ot_shape_context_t *c)
Behdad Esfahbodc86f9322011-07-25 00:44:50 -0400718{
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200719 hb_buffer_t *buffer = c->buffer;
720
721 hb_ot_layout_substitute_start (c->font, buffer);
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400722
Behdad Esfahbodcca757a2018-10-02 13:27:11 +0200723 if (c->plan->fallback_glyph_classes)
Behdad Esfahbod1a0f4aa2016-12-22 13:33:54 -0600724 hb_synthesize_glyph_classes (c);
725
Behdad Esfahbod14ff3cb2018-10-04 11:34:21 +0200726 if (unlikely (c->plan->apply_morx))
Behdad Esfahbod53e55942018-10-09 22:35:22 -0400727 hb_aat_layout_substitute (c->plan, c->font, c->buffer);
Behdad Esfahbod14ff3cb2018-10-04 11:34:21 +0200728 else
729 c->plan->substitute (c->font, buffer);
Behdad Esfahbodc86f9322011-07-25 00:44:50 -0400730}
731
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400732static inline void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400733hb_ot_substitute (const hb_ot_shape_context_t *c)
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400734{
735 hb_ot_substitute_default (c);
Behdad Esfahbod0f407322015-11-04 22:28:44 -0800736
737 _hb_buffer_allocate_gsubgpos_vars (c->buffer);
738
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400739 hb_ot_substitute_complex (c);
740}
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100741
742/* Position */
743
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400744static inline void
Jonathan Kew798e4182014-06-10 13:10:30 +0100745adjust_mark_offsets (hb_glyph_position_t *pos)
746{
747 pos->x_offset -= pos->x_advance;
748 pos->y_offset -= pos->y_advance;
749}
750
751static inline void
752zero_mark_width (hb_glyph_position_t *pos)
753{
754 pos->x_advance = 0;
755 pos->y_advance = 0;
756}
757
758static inline void
Jonathan Kew798e4182014-06-10 13:10:30 +0100759zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
Behdad Esfahbodd785fa02013-05-20 09:18:52 -0400760{
761 unsigned int count = buffer->len;
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400762 hb_glyph_info_t *info = buffer->info;
Behdad Esfahbodd785fa02013-05-20 09:18:52 -0400763 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400764 if (_hb_glyph_info_is_mark (&info[i]))
Behdad Esfahbodd785fa02013-05-20 09:18:52 -0400765 {
Jonathan Kew798e4182014-06-10 13:10:30 +0100766 if (adjust_offsets)
767 adjust_mark_offsets (&buffer->pos[i]);
768 zero_mark_width (&buffer->pos[i]);
Behdad Esfahbodd785fa02013-05-20 09:18:52 -0400769 }
770}
771
772static inline void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400773hb_ot_position_default (const hb_ot_shape_context_t *c)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100774{
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200775 hb_direction_t direction = c->buffer->props.direction;
Behdad Esfahbod967240d2010-10-05 23:00:05 -0400776 unsigned int count = c->buffer->len;
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200777 hb_glyph_info_t *info = c->buffer->info;
778 hb_glyph_position_t *pos = c->buffer->pos;
Behdad Esfahbod56800022013-02-12 09:44:57 -0500779
Behdad Esfahbodbee901b2015-11-04 19:28:17 -0800780 if (HB_DIRECTION_IS_HORIZONTAL (direction))
781 {
Koji Ishii95333642018-08-01 13:01:08 +0900782 c->font->get_glyph_h_advances (count, &info[0].codepoint, sizeof(info[0]),
783 &pos[0].x_advance, sizeof(pos[0]));
Behdad Esfahbod67a36a72015-11-26 18:48:42 -0500784 /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
Behdad Esfahbod5bc28b52015-11-04 21:53:16 -0800785 if (c->font->has_glyph_h_origin_func ())
786 for (unsigned int i = 0; i < count; i++)
787 c->font->subtract_glyph_h_origin (info[i].codepoint,
788 &pos[i].x_offset,
789 &pos[i].y_offset);
Behdad Esfahbodbee901b2015-11-04 19:28:17 -0800790 }
791 else
792 {
Behdad Esfahbod79e21982018-08-06 09:45:17 -0700793 c->font->get_glyph_v_advances (count, &info[0].codepoint, sizeof(info[0]),
794 &pos[0].y_advance, sizeof(pos[0]));
Behdad Esfahbodbee901b2015-11-04 19:28:17 -0800795 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod67a36a72015-11-26 18:48:42 -0500796 {
Behdad Esfahbod67a36a72015-11-26 18:48:42 -0500797 c->font->subtract_glyph_v_origin (info[i].codepoint,
798 &pos[i].x_offset,
799 &pos[i].y_offset);
800 }
Behdad Esfahbod56800022013-02-12 09:44:57 -0500801 }
Behdad Esfahbod49ef6302015-11-04 17:27:07 -0800802 if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
803 _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
Behdad Esfahbod4b011092013-09-13 20:17:42 -0400804}
805
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600806static inline void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400807hb_ot_position_complex (const hb_ot_shape_context_t *c)
Behdad Esfahbod4b011092013-09-13 20:17:42 -0400808{
Behdad Esfahbod4b011092013-09-13 20:17:42 -0400809 unsigned int count = c->buffer->len;
Behdad Esfahbod9786fcd2017-10-03 17:22:43 +0200810 hb_glyph_info_t *info = c->buffer->info;
811 hb_glyph_position_t *pos = c->buffer->pos;
Behdad Esfahbod84742312016-02-11 16:27:41 +0700812
Jonathan Kew798e4182014-06-10 13:10:30 +0100813 /* If the font has no GPOS, AND, no fallback positioning will
814 * happen, AND, direction is forward, then when zeroing mark
815 * widths, we shift the mark with it, such that the mark
816 * is positioned hanging over the previous glyph. When
817 * direction is backward we don't shift and it will end up
818 * hanging over the next glyph after the final reordering.
819 * If fallback positinoing happens or GPOS is present, we don't
820 * care.
821 */
Behdad Esfahbod09ad2612018-10-08 23:30:24 -0400822 bool adjust_offsets_when_zeroing = c->plan->fallback_mark_positioning &&
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600823 !c->plan->shaper->fallback_position &&
824 HB_DIRECTION_IS_FORWARD (c->buffer->props.direction);
Behdad Esfahbod56800022013-02-12 09:44:57 -0500825
Behdad Esfahbod9786fcd2017-10-03 17:22:43 +0200826 /* We change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
827
828 /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
829 if (c->font->has_glyph_h_origin_func ())
830 for (unsigned int i = 0; i < count; i++)
831 c->font->add_glyph_h_origin (info[i].codepoint,
832 &pos[i].x_offset,
833 &pos[i].y_offset);
834
835 hb_ot_layout_position_start (c->font, c->buffer);
836
Behdad Esfahbod504cb682018-10-10 21:29:46 -0400837 if (!c->plan->apply_kerx)
838 switch (c->plan->shaper->zero_width_marks)
839 {
840 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
841 zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
842 break;
Behdad Esfahbod56800022013-02-12 09:44:57 -0500843
Behdad Esfahbod504cb682018-10-10 21:29:46 -0400844 default:
845 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
846 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
847 break;
848 }
Behdad Esfahbodc86f9322011-07-25 00:44:50 -0400849
Behdad Esfahbod14ff3cb2018-10-04 11:34:21 +0200850 if (c->plan->apply_gpos)
Behdad Esfahbod34caadc2018-10-10 22:17:07 -0400851 c->plan->position (c->font, c->buffer);
Behdad Esfahbod7727e732018-10-10 13:24:51 -0400852 else if (c->plan->apply_kerx)
853 hb_aat_layout_position (c->plan, c->font, c->buffer);
Behdad Esfahbodc86f9322011-07-25 00:44:50 -0400854
Behdad Esfahbodb59a4282018-10-11 13:24:17 -0400855 if (c->plan->apply_trak)
856 hb_aat_layout_track (c->plan, c->font, c->buffer);
Behdad Esfahbodd6a12db2018-10-11 11:10:06 -0400857
Behdad Esfahbod504cb682018-10-10 21:29:46 -0400858 if (!c->plan->apply_kerx)
859 switch (c->plan->shaper->zero_width_marks)
860 {
861 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
862 zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
863 break;
Behdad Esfahbod127daf12013-05-20 09:11:35 -0400864
Behdad Esfahbod504cb682018-10-10 21:29:46 -0400865 default:
866 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
867 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
868 break;
869 }
Behdad Esfahbod0291a652013-02-13 05:57:24 -0500870
Behdad Esfahbod7d8d58a2016-02-11 16:34:28 +0700871 /* Finishing off GPOS has to follow a certain order. */
872 hb_ot_layout_position_finish_advances (c->font, c->buffer);
Behdad Esfahbod84742312016-02-11 16:27:41 +0700873 hb_ot_zero_width_default_ignorables (c);
Behdad Esfahbod7d8d58a2016-02-11 16:34:28 +0700874 hb_ot_layout_position_finish_offsets (c->font, c->buffer);
Behdad Esfahbod9786fcd2017-10-03 17:22:43 +0200875
876 /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
877 if (c->font->has_glyph_h_origin_func ())
878 for (unsigned int i = 0; i < count; i++)
879 c->font->subtract_glyph_h_origin (info[i].codepoint,
880 &pos[i].x_offset,
881 &pos[i].y_offset);
Behdad Esfahbodc86f9322011-07-25 00:44:50 -0400882}
883
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400884static inline void
Behdad Esfahbodc0d3bf12018-10-08 16:32:44 -0400885hb_ot_position (const hb_ot_shape_context_t *c)
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400886{
Behdad Esfahbod84742312016-02-11 16:27:41 +0700887 c->buffer->clear_positions ();
Behdad Esfahbod4b011092013-09-13 20:17:42 -0400888
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400889 hb_ot_position_default (c);
890
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600891 hb_ot_position_complex (c);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400892
Behdad Esfahbod09ad2612018-10-08 23:30:24 -0400893 if (c->plan->fallback_mark_positioning && c->plan->shaper->fallback_position)
894 _hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400895
896 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
897 hb_buffer_reverse (c->buffer);
898
Behdad Esfahbod865745b2012-11-14 13:48:26 -0800899 /* Visual fallback goes here. */
900
Behdad Esfahbodd1be8052018-10-10 10:49:45 -0400901 if (c->plan->apply_kern)
Behdad Esfahboda5195882018-10-08 23:57:45 -0400902 hb_ot_layout_kern (c->font, c->buffer, c->plan->kern_mask);
903 else if (c->plan->fallback_kerning)
Behdad Esfahbodba87b8f2013-02-21 15:23:39 -0500904 _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
Behdad Esfahbod8f3eebf2014-08-02 17:18:46 -0400905
906 _hb_buffer_deallocate_gsubgpos_vars (c->buffer);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400907}
908
Behdad Esfahbod1c17c2b2017-08-11 19:06:07 -0700909static inline void
910hb_propagate_flags (hb_buffer_t *buffer)
911{
912 /* Propagate cluster-level glyph flags to be the same on all cluster glyphs.
913 * Simplifies using them. */
914
915 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK))
916 return;
917
918 hb_glyph_info_t *info = buffer->info;
919
920 foreach_cluster (buffer, start, end)
921 {
922 unsigned int mask = 0;
923 for (unsigned int i = start; i < end; i++)
924 if (info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
925 {
926 mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
927 break;
928 }
929 if (mask)
930 for (unsigned int i = start; i < end; i++)
931 info[i].mask |= mask;
932 }
933}
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400934
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400935/* Pull it all together! */
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100936
Behdad Esfahbod967240d2010-10-05 23:00:05 -0400937static void
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400938hb_ot_shape_internal (hb_ot_shape_context_t *c)
Behdad Esfahbod967240d2010-10-05 23:00:05 -0400939{
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400940 c->buffer->deallocate_var_all ();
Behdad Esfahbod49ef6302015-11-04 17:27:07 -0800941 c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
Behdad Esfahbodbddeb2b2018-07-10 14:12:37 +0200942 if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
Behdad Esfahbod43017032015-11-05 23:44:59 -0800943 {
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800944 c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
Behdad Esfahbod43017032015-11-05 23:44:59 -0800945 (unsigned) HB_BUFFER_MAX_LEN_MIN);
946 }
Behdad Esfahbodbddeb2b2018-07-10 14:12:37 +0200947 if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800948 {
949 c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
950 (unsigned) HB_BUFFER_MAX_OPS_MIN);
951 }
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400952
Behdad Esfahbodd2ba0162010-10-12 15:35:45 -0400953 /* Save the original direction, we use it later. */
Behdad Esfahbodbbbbe802010-12-07 16:22:02 -0500954 c->target_direction = c->buffer->props.direction;
Behdad Esfahbodd2ba0162010-10-12 15:35:45 -0400955
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200956 _hb_buffer_allocate_unicode_vars (c->buffer);
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400957
Behdad Esfahbod330a2af2012-06-08 20:40:02 -0400958 c->buffer->clear_output ();
959
Behdad Esfahbod7cc34802017-09-04 20:04:59 -0700960 hb_ot_shape_initialize_masks (c);
Behdad Esfahbodd1deaa22012-05-09 15:04:13 +0200961 hb_set_unicode_props (c->buffer);
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400962 hb_insert_dotted_circle (c->buffer, c->font);
Behdad Esfahbod7cc34802017-09-04 20:04:59 -0700963
Behdad Esfahbod4ff0d2d2011-07-22 16:15:32 -0400964 hb_form_clusters (c->buffer);
965
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400966 hb_ensure_native_direction (c->buffer);
Behdad Esfahbod54d1a0d2011-07-21 01:11:09 -0400967
Behdad Esfahbod13686332015-11-05 13:24:15 -0800968 if (c->plan->shaper->preprocess_text)
969 c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
970
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400971 hb_ot_substitute (c);
972 hb_ot_position (c);
Behdad Esfahbod655586f2011-07-21 00:51:18 -0400973
Behdad Esfahbod8cfbc302015-07-22 18:41:10 +0100974 hb_ot_hide_default_ignorables (c);
975
Behdad Esfahbod13686332015-11-05 13:24:15 -0800976 if (c->plan->shaper->postprocess_glyphs)
977 c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
978
Behdad Esfahbod1c17c2b2017-08-11 19:06:07 -0700979 hb_propagate_flags (c->buffer);
980
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200981 _hb_buffer_deallocate_unicode_vars (c->buffer);
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400982
Behdad Esfahbodbbbbe802010-12-07 16:22:02 -0500983 c->buffer->props.direction = c->target_direction;
Behdad Esfahbod9f9bcce2011-07-28 17:06:46 -0400984
Behdad Esfahbod43017032015-11-05 23:44:59 -0800985 c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800986 c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
Behdad Esfahbod9f9bcce2011-07-28 17:06:46 -0400987 c->buffer->deallocate_var_all ();
Behdad Esfahbod967240d2010-10-05 23:00:05 -0400988}
989
Behdad Esfahbodfd3d32d2010-10-12 16:57:47 -0400990
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400991hb_bool_t
Behdad Esfahbodbd26b4d2012-07-26 22:05:39 -0400992_hb_ot_shape (hb_shape_plan_t *shape_plan,
993 hb_font_t *font,
Behdad Esfahbod6bd9b472012-04-12 14:53:53 -0400994 hb_buffer_t *buffer,
995 const hb_feature_t *features,
996 unsigned int num_features)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100997{
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400998 hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
999 hb_ot_shape_internal (&c);
Behdad Esfahbod02aeca92011-08-04 22:31:05 -04001000
Behdad Esfahbod0594a242012-06-05 20:35:40 -04001001 return true;
Behdad Esfahbodca663bb2010-05-21 14:34:23 +01001002}
Behdad Esfahbod1827dc22012-04-24 16:56:37 -04001003
1004
Sascha Brawer01c3a882015-06-01 13:22:01 +02001005/**
Behdad Esfahbod35d18582015-11-26 19:30:37 -05001006 * hb_ot_shape_plan_collect_lookups:
1007 *
Sascha Brawer01c3a882015-06-01 13:22:01 +02001008 * Since: 0.9.7
1009 **/
Behdad Esfahbodf3064102012-11-15 18:39:46 -08001010void
1011hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
1012 hb_tag_t table_tag,
1013 hb_set_t *lookup_indexes /* OUT */)
Behdad Esfahbodb00321e2012-08-09 22:33:32 -04001014{
Behdad Esfahbod51bb4982012-11-16 14:08:05 -08001015 /* XXX Does the first part always succeed? */
Behdad Esfahbodf3064102012-11-15 18:39:46 -08001016 HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
Behdad Esfahbodb00321e2012-08-09 22:33:32 -04001017}
1018
Behdad Esfahbodf3064102012-11-15 18:39:46 -08001019
1020/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
1021static void
1022add_char (hb_font_t *font,
1023 hb_unicode_funcs_t *unicode,
1024 hb_bool_t mirror,
1025 hb_codepoint_t u,
1026 hb_set_t *glyphs)
1027{
1028 hb_codepoint_t glyph;
Behdad Esfahbod8b5bc142016-02-24 19:05:23 +09001029 if (font->get_nominal_glyph (u, &glyph))
Behdad Esfahbodf3064102012-11-15 18:39:46 -08001030 glyphs->add (glyph);
1031 if (mirror)
1032 {
1033 hb_codepoint_t m = unicode->mirroring (u);
Behdad Esfahbod8b5bc142016-02-24 19:05:23 +09001034 if (m != u && font->get_nominal_glyph (m, &glyph))
Behdad Esfahbodf3064102012-11-15 18:39:46 -08001035 glyphs->add (glyph);
1036 }
1037}
1038
1039
Sascha Brawer01c3a882015-06-01 13:22:01 +02001040/**
Behdad Esfahbod35d18582015-11-26 19:30:37 -05001041 * hb_ot_shape_glyphs_closure:
1042 *
Sascha Brawer01c3a882015-06-01 13:22:01 +02001043 * Since: 0.9.2
1044 **/
Behdad Esfahbod1827dc22012-04-24 16:56:37 -04001045void
1046hb_ot_shape_glyphs_closure (hb_font_t *font,
1047 hb_buffer_t *buffer,
1048 const hb_feature_t *features,
1049 unsigned int num_features,
1050 hb_set_t *glyphs)
1051{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001052 const char *shapers[] = {"ot", nullptr};
Behdad Esfahbodf3064102012-11-15 18:39:46 -08001053 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
1054 features, num_features, shapers);
Behdad Esfahbod1827dc22012-04-24 16:56:37 -04001055
Behdad Esfahbodf3064102012-11-15 18:39:46 -08001056 bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
Behdad Esfahbod1827dc22012-04-24 16:56:37 -04001057
Behdad Esfahbod1827dc22012-04-24 16:56:37 -04001058 unsigned int count = buffer->len;
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -04001059 hb_glyph_info_t *info = buffer->info;
Behdad Esfahbod1827dc22012-04-24 16:56:37 -04001060 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -04001061 add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
Behdad Esfahbodf3064102012-11-15 18:39:46 -08001062
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -04001063 hb_set_t *lookups = hb_set_create ();
1064 hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, lookups);
Garret Rieger57badad2018-06-06 16:02:51 -07001065 hb_ot_layout_lookups_substitute_closure (font->face, lookups, glyphs);
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -04001066
1067 hb_set_destroy (lookups);
Behdad Esfahbode82061e2012-07-27 02:29:32 -04001068
1069 hb_shape_plan_destroy (shape_plan);
Behdad Esfahbod1827dc22012-04-24 16:56:37 -04001070}