blob: e40a0e94a3daab9b5a793866ef77a32ab45d5ea5 [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
30#define hb_ot_shaper_face_data_t hb_ot_layout_t
Behdad Esfahbode82061e2012-07-27 02:29:32 -040031#define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t
Behdad Esfahbod027857d2012-07-26 17:34:25 -040032#include "hb-shaper-impl-private.hh"
33
Behdad Esfahbod4924aff2010-10-08 19:18:16 -040034#include "hb-ot-shape-private.hh"
Behdad Esfahbod16c6a272012-08-02 09:38:28 -040035#include "hb-ot-shape-complex-private.hh"
Behdad Esfahbod9c929ab2012-08-08 14:33:37 -040036#include "hb-ot-shape-fallback-private.hh"
Behdad Esfahbodaffaf8a2012-08-07 22:41:38 -040037#include "hb-ot-shape-normalize-private.hh"
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +010038
Behdad Esfahbodb70021f2012-07-23 20:18:17 -040039#include "hb-ot-layout-private.hh"
Behdad Esfahbod878a2532014-07-16 13:21:26 -040040#include "hb-unicode-private.hh"
Behdad Esfahbod1827dc22012-04-24 16:56:37 -040041#include "hb-set-private.hh"
Behdad Esfahbod72657e42011-05-02 20:46:32 -040042
Behdad Esfahbod748b9892018-01-09 17:55:17 +010043#include "hb-ot-layout-gsubgpos-private.hh"
Behdad Esfahboddb5d4302018-07-17 18:14:45 +020044#include "hb-aat-layout-private.hh"
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040045
Behdad Esfahboda02d8642012-08-08 18:04:29 -040046static hb_tag_t common_features[] = {
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +010047 HB_TAG('c','c','m','p'),
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -040048 HB_TAG('l','o','c','l'),
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -040049 HB_TAG('m','a','r','k'),
50 HB_TAG('m','k','m','k'),
51 HB_TAG('r','l','i','g'),
52};
53
Behdad Esfahbodd1deaa22012-05-09 15:04:13 +020054
Behdad Esfahboda02d8642012-08-08 18:04:29 -040055static hb_tag_t horizontal_features[] = {
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -040056 HB_TAG('c','a','l','t'),
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +010057 HB_TAG('c','l','i','g'),
Behdad Esfahbodbd098732010-05-21 18:06:35 +010058 HB_TAG('c','u','r','s'),
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +010059 HB_TAG('k','e','r','n'),
Behdad Esfahbod2053f362014-08-02 16:31:16 -040060 HB_TAG('l','i','g','a'),
Behdad Esfahbodf4e48ad2012-08-07 21:12:49 -040061 HB_TAG('r','c','l','t'),
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -040062};
63
Behdad Esfahbodb9f199c2012-04-14 20:23:58 -040064
65
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +010066static void
Behdad Esfahbod90645fb2011-05-27 18:13:31 -040067hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
Behdad Esfahbod49baa1f2010-10-12 16:50:36 -040068 const hb_segment_properties_t *props,
Behdad Esfahbod90645fb2011-05-27 18:13:31 -040069 const hb_feature_t *user_features,
70 unsigned int num_user_features)
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +010071{
Behdad Esfahbod8bb5deb2012-08-02 10:07:58 -040072 hb_ot_map_builder_t *map = &planner->map;
73
Behdad Esfahbod0aedfd52016-09-28 17:05:43 +020074 map->add_global_bool_feature (HB_TAG('r','v','r','n'));
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +020075 map->add_gsub_pause (nullptr);
Behdad Esfahbod0aedfd52016-09-28 17:05:43 +020076
Behdad Esfahbod895fb5d2010-10-12 16:00:21 -040077 switch (props->direction) {
Behdad Esfahbod074ea782010-05-21 17:53:10 +010078 case HB_DIRECTION_LTR:
Behdad Esfahbode7ffcfa2013-02-14 11:05:56 -050079 map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
80 map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
Behdad Esfahbod074ea782010-05-21 17:53:10 +010081 break;
82 case HB_DIRECTION_RTL:
Behdad Esfahbode7ffcfa2013-02-14 11:05:56 -050083 map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
Behdad Esfahbodec544862013-02-14 11:25:10 -050084 map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE);
Behdad Esfahbod0e235d02010-05-28 20:21:47 -040085 break;
86 case HB_DIRECTION_TTB:
87 case HB_DIRECTION_BTT:
Behdad Esfahbod3286fc02011-03-16 14:53:32 -030088 case HB_DIRECTION_INVALID:
Behdad Esfahbod0e235d02010-05-28 20:21:47 -040089 default:
90 break;
91 }
92
Behdad Esfahbod3aeee512013-12-22 16:17:54 -050093 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
Behdad Esfahbod693918e2012-07-30 21:08:51 -040097 if (planner->shaper->collect_features)
Behdad Esfahbod16c6a272012-08-02 09:38:28 -040098 planner->shaper->collect_features (planner);
Behdad Esfahbode04685e2010-05-28 20:37:06 -040099
Behdad Esfahbodee9c3a12013-02-15 06:22:26 -0500100 for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
101 map->add_global_bool_feature (common_features[i]);
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -0400102
103 if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
Behdad Esfahbodee9c3a12013-02-15 06:22:26 -0500104 for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
Behdad Esfahbod038c98f2013-02-15 07:41:07 -0500105 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));
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -0400108 else
Behdad Esfahbodf327aac2015-07-23 11:32:59 +0100109 {
Behdad Esfahbod0f98fe82015-07-23 11:52:11 +0100110 /* 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:
ebraminio7c6937e2017-11-20 14:49:22 -0500113 * https://github.com/harfbuzz/harfbuzz/issues/63 */
Behdad Esfahbod0f98fe82015-07-23 11:52:11 +0100114 map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH);
Behdad Esfahbodf327aac2015-07-23 11:32:59 +0100115 }
Behdad Esfahbod89a2bc92011-05-31 15:18:13 -0400116
Behdad Esfahbod693918e2012-07-30 21:08:51 -0400117 if (planner->shaper->override_features)
Behdad Esfahbod16c6a272012-08-02 09:38:28 -0400118 planner->shaper->override_features (planner);
Behdad Esfahbodd96838e2012-07-16 20:26:57 -0400119
Behdad Esfahbod895fb5d2010-10-12 16:00:21 -0400120 for (unsigned int i = 0; i < num_user_features; i++) {
121 const hb_feature_t *feature = &user_features[i];
Behdad Esfahbodec544862013-02-14 11:25:10 -0500122 map->add_feature (feature->tag, feature->value,
123 (feature->start == 0 && feature->end == (unsigned int) -1) ?
124 F_GLOBAL : F_NONE);
Behdad Esfahbode04685e2010-05-28 20:37:06 -0400125 }
Behdad Esfahbode89b7d22010-10-08 12:29:59 -0400126}
Behdad Esfahbod0e235d02010-05-28 20:21:47 -0400127
128
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400129/*
130 * shaper face data
131 */
132
Behdad Esfahbod466b3e52017-02-03 16:43:25 -0800133HB_SHAPER_DATA_ENSURE_DEFINE(ot, face)
134
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400135hb_ot_shaper_face_data_t *
136_hb_ot_shaper_face_data_create (hb_face_t *face)
137{
138 return _hb_ot_layout_create (face);
139}
140
141void
142_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
143{
144 _hb_ot_layout_destroy (data);
145}
146
147
148/*
149 * shaper font data
150 */
151
Behdad Esfahbod466b3e52017-02-03 16:43:25 -0800152HB_SHAPER_DATA_ENSURE_DEFINE(ot, font)
153
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400154struct hb_ot_shaper_font_data_t {};
155
156hb_ot_shaper_font_data_t *
Behdad Esfahbod89137e32016-02-22 16:00:59 +0900157_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400158{
159 return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
160}
161
162void
163_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
164{
165}
166
167
168/*
169 * shaper shape_plan data
170 */
171
172hb_ot_shaper_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,
Behdad Esfahbod72ada4f2016-09-10 03:57:24 -0700175 unsigned int num_user_features,
176 const int *coords,
177 unsigned int num_coords)
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400178{
Behdad Esfahboda8c6da92012-08-02 10:46:34 -0400179 hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
180 if (unlikely (!plan))
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200181 return nullptr;
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400182
Behdad Esfahbodf9abbf82018-06-02 15:30:59 -0700183 plan->init ();
184
Behdad Esfahbod5393e3a2012-08-02 09:24:35 -0400185 hb_ot_shape_planner_t planner (shape_plan);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400186
Behdad Esfahbod9b37b4c2012-11-12 18:23:38 -0800187 planner.shaper = hb_ot_shape_complex_categorize (&planner);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400188
Behdad Esfahbod72ada4f2016-09-10 03:57:24 -0700189 hb_ot_shape_collect_features (&planner, &shape_plan->props,
190 user_features, num_user_features);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400191
Behdad Esfahbod72ada4f2016-09-10 03:57:24 -0700192 planner.compile (*plan, coords, num_coords);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400193
Behdad Esfahboda8c6da92012-08-02 10:46:34 -0400194 if (plan->shaper->data_create) {
195 plan->data = plan->shaper->data_create (plan);
Behdad Esfahbod42c183f2018-07-27 14:55:29 -0700196 if (unlikely (!plan->data))
197 {
198 free (plan);
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200199 return nullptr;
prrace2e25d8f2018-07-27 13:58:27 -0700200 }
Behdad Esfahboda8c6da92012-08-02 10:46:34 -0400201 }
202
203 return plan;
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400204}
205
206void
Behdad Esfahboda8c6da92012-08-02 10:46:34 -0400207_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan)
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400208{
Behdad Esfahboda8c6da92012-08-02 10:46:34 -0400209 if (plan->shaper->data_destroy)
210 plan->shaper->data_destroy (const_cast<void *> (plan->data));
Behdad Esfahbod4ba647e2012-07-30 09:53:06 -0400211
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400212 plan->fini ();
Behdad Esfahboda8c6da92012-08-02 10:46:34 -0400213
214 free (plan);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400215}
216
217
218/*
219 * shaper
220 */
221
Behdad Esfahbodb9f199c2012-04-14 20:23:58 -0400222struct hb_ot_shape_context_t
223{
Behdad Esfahbodb9f199c2012-04-14 20:23:58 -0400224 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 */
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600232 bool fallback_positioning;
233 bool fallback_glyph_classes;
Behdad Esfahbodb9f199c2012-04-14 20:23:58 -0400234 hb_direction_t target_direction;
Behdad Esfahbodb9f199c2012-04-14 20:23:58 -0400235};
236
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100237
238
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100239/* Main shaper */
240
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400241
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100242/* Prepare */
243
Behdad Esfahbodb9f199c2012-04-14 20:23:58 -0400244static void
245hb_set_unicode_props (hb_buffer_t *buffer)
Behdad Esfahbod3a852ae2010-11-03 16:37:24 -0400246{
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400247 unsigned int count = buffer->len;
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400248 hb_glyph_info_t *info = buffer->info;
Behdad Esfahbod0e336142012-04-12 10:06:52 -0400249 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod69862082015-11-04 18:46:22 -0800250 _hb_glyph_info_set_unicode_props (&info[i], buffer);
Behdad Esfahbod3a852ae2010-11-03 16:37:24 -0400251}
252
253static void
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400254hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
255{
Behdad Esfahbod0c7df222012-11-13 14:42:35 -0800256 if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
Behdad Esfahbod763e5462014-08-02 16:17:44 -0400257 buffer->context_len[0] ||
Behdad Esfahbodf2eb3fa2012-09-25 21:35:35 -0400258 _hb_glyph_info_get_general_category (&buffer->info[0]) !=
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400259 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
260 return;
261
Behdad Esfahbod76271002014-07-11 14:54:42 -0400262 if (!font->has_glyph (0x25CCu))
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400263 return;
264
Behdad Esfahbod595d2b92014-07-26 18:44:15 -0400265 hb_glyph_info_t dottedcircle = {0};
Behdad Esfahbod76271002014-07-11 14:54:42 -0400266 dottedcircle.codepoint = 0x25CCu;
Behdad Esfahbod69862082015-11-04 18:46:22 -0800267 _hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400268
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);
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700276 while (buffer->idx < buffer->len && buffer->successful)
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400277 buffer->next_glyph ();
278
279 buffer->swap_buffers ();
280}
281
282static void
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400283hb_form_clusters (hb_buffer_t *buffer)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100284{
Behdad Esfahbod7cc34802017-09-04 20:04:59 -0700285 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
Behdad Esfahbod376d5872015-07-22 16:51:12 +0100286 return;
287
Behdad Esfahbod62c27112016-02-22 15:07:20 +0900288 /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
Behdad Esfahbod701112d2015-07-22 15:42:20 +0100289 unsigned int base = 0;
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400290 unsigned int count = buffer->len;
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400291 hb_glyph_info_t *info = buffer->info;
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100292 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod701112d2015-07-22 15:42:20 +0100293 {
Behdad Esfahbod815bdd72016-02-22 18:22:44 +0900294 if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) &&
295 !_hb_glyph_info_is_joiner (&info[i])))
Behdad Esfahbod701112d2015-07-22 15:42:20 +0100296 {
Behdad Esfahbod7cc34802017-09-04 20:04:59 -0700297 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);
Behdad Esfahbod701112d2015-07-22 15:42:20 +0100301 base = i;
302 }
303 }
Behdad Esfahbod7cc34802017-09-04 20:04:59 -0700304 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);
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100308}
309
Behdad Esfahbod967240d2010-10-05 23:00:05 -0400310static void
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400311hb_ensure_native_direction (hb_buffer_t *buffer)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100312{
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400313 hb_direction_t direction = buffer->props.direction;
Behdad Esfahbodf673cfb2018-05-07 13:58:32 -0700314 hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script);
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100315
Behdad Esfahbod7403e052011-05-24 21:04:15 -0400316 /* 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. */
Behdad Esfahbodf673cfb2018-05-07 13:58:32 -0700320 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))
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100324 {
Behdad Esfahboda60e2cf2015-07-22 15:49:08 +0100325 /* 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 {
Behdad Esfahbod376d5872015-07-22 16:51:12 +0100334 if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
335 buffer->merge_clusters (base, i);
Behdad Esfahbodf883de62015-09-01 16:23:40 +0100336 buffer->reverse_range (base, i);
337
Behdad Esfahboda60e2cf2015-07-22 15:49:08 +0100338 base = i;
339 }
340 }
Behdad Esfahbod376d5872015-07-22 16:51:12 +0100341 if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
342 buffer->merge_clusters (base, count);
Behdad Esfahbodf883de62015-09-01 16:23:40 +0100343 buffer->reverse_range (base, count);
Behdad Esfahboda60e2cf2015-07-22 15:49:08 +0100344
345 buffer->reverse ();
346
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400347 buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100348 }
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100349}
350
351
352/* Substitute */
353
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400354static inline void
355hb_ot_mirror_chars (hb_ot_shape_context_t *c)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100356{
Behdad Esfahbodbbbbe802010-12-07 16:22:02 -0500357 if (HB_DIRECTION_IS_FORWARD (c->target_direction))
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100358 return;
359
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200360 hb_buffer_t *buffer = c->buffer;
361 hb_unicode_funcs_t *unicode = buffer->unicode;
Behdad Esfahbod5497a8a2013-12-22 20:48:53 -0500362 hb_mask_t rtlm_mask = c->plan->rtlm_mask;
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400363
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200364 unsigned int count = buffer->len;
365 hb_glyph_info_t *info = buffer->info;
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100366 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200367 hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
Behdad Esfahbod7b8b63a2015-07-22 15:24:26 +0100368 if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200369 info[i].mask |= rtlm_mask;
Behdad Esfahbod1094a292010-05-21 17:58:20 +0100370 else
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200371 info[i].codepoint = codepoint;
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100372 }
373}
374
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400375static inline void
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500376hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
377{
Behdad Esfahbode3e4bb02015-11-04 18:58:02 -0800378 if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
379 !c->plan->has_frac)
Behdad Esfahbod5497a8a2013-12-22 20:48:53 -0500380 return;
381
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500382 hb_buffer_t *buffer = c->buffer;
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500383
Khaled Hosny24525432017-01-18 22:48:13 +0200384 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
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500396 unsigned int count = buffer->len;
397 hb_glyph_info_t *info = buffer->info;
398 for (unsigned int i = 0; i < count; i++)
399 {
Behdad Esfahbod76271002014-07-11 14:54:42 -0400400 if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500401 {
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500402 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
Behdad Esfahbodc449d2d2017-08-30 17:28:22 -0700412 buffer->unsafe_to_break (start, end);
413
Behdad Esfahboda7e8bbb2013-12-22 19:33:35 -0500414 for (unsigned int j = start; j < i; j++)
Khaled Hosny24525432017-01-18 22:48:13 +0200415 info[j].mask |= pre_mask;
Behdad Esfahbod5497a8a2013-12-22 20:48:53 -0500416 info[i].mask |= c->plan->frac_mask;
Behdad Esfahboda7e8bbb2013-12-22 19:33:35 -0500417 for (unsigned int j = i + 1; j < end; j++)
Khaled Hosny24525432017-01-18 22:48:13 +0200418 info[j].mask |= post_mask;
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500419
420 i = end - 1;
421 }
422 }
423}
424
425static inline void
Behdad Esfahbod73932512013-12-21 00:18:18 -0500426hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400427{
428 hb_ot_map_t *map = &c->plan->map;
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200429 hb_buffer_t *buffer = c->buffer;
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400430
431 hb_mask_t global_mask = map->get_global_mask ();
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200432 buffer->reset_masks (global_mask);
Behdad Esfahbod73932512013-12-21 00:18:18 -0500433}
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;
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400440
Behdad Esfahbod3aeee512013-12-22 16:17:54 -0500441 hb_ot_shape_setup_masks_fraction (c);
442
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400443 if (c->plan->shaper->setup_masks)
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200444 c->plan->shaper->setup_masks (c->plan, buffer, c->font);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400445
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);
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200452 buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400453 }
454 }
455}
456
Behdad Esfahbod8cfbc302015-07-22 18:41:10 +0100457static void
458hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
459{
460 hb_buffer_t *buffer = c->buffer;
461
Behdad Esfahbod69862082015-11-04 18:46:22 -0800462 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
Behdad Esfahbod3b1e97f2018-01-10 03:35:20 +0100463 (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) ||
464 (buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES))
Behdad Esfahbod8cfbc302015-07-22 18:41:10 +0100465 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}
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100475
476static void
477hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
478{
479 hb_buffer_t *buffer = c->buffer;
480
Behdad Esfahbod69862082015-11-04 18:46:22 -0800481 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
482 (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100483 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 {
Behdad Esfahbod4ba796b2015-07-22 17:41:31 +0100491 if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100492 break;
493 }
494
495 /* No default-ignorables found; return. */
496 if (i == count)
497 return;
498
499 hb_codepoint_t space;
Behdad Esfahbod3b1e97f2018-01-10 03:35:20 +0100500 if (!(buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) &&
501 c->font->get_nominal_glyph (' ', &space))
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100502 {
503 /* Replace default-ignorables with a zero-advance space glyph. */
504 for (/*continue*/; i < count; i++)
505 {
Behdad Esfahbod4ba796b2015-07-22 17:41:31 +0100506 if (_hb_glyph_info_is_default_ignorable (&info[i]))
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100507 info[i].codepoint = space;
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100508 }
509 }
510 else
511 {
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100512 /* 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++)
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100516 {
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100517 if (_hb_glyph_info_is_default_ignorable (&info[i]))
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100518 {
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100519 /* 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 {
Behdad Esfahbode2a2b5b2017-08-10 20:10:12 -0700531 unsigned int mask = info[i].mask;
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100532 unsigned int old_cluster = info[j - 1].cluster;
533 for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
Behdad Esfahbode2a2b5b2017-08-10 20:10:12 -0700534 buffer->set_cluster (info[k - 1], cluster, mask);
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100535 }
536 continue;
537 }
538
539 if (i + 1 < count)
540 buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
541
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100542 continue;
543 }
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100544
545 if (j != i)
546 {
547 info[j] = info[i];
548 pos[j] = pos[i];
549 }
550 j++;
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100551 }
Behdad Esfahbod2dbd3d22015-07-22 18:28:39 +0100552 buffer->len = j;
Behdad Esfahbodf0010df2015-07-22 17:36:23 +0100553 }
554}
555
556
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400557static inline void
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400558hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100559{
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400560 /* Normalization process sets up glyph_index(), we just copy it. */
561 unsigned int count = buffer->len;
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400562 hb_glyph_info_t *info = buffer->info;
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400563 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400564 info[i].codepoint = info[i].glyph_index();
Behdad Esfahbode47b7722015-08-18 18:42:47 +0100565
566 buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100567}
568
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400569static inline void
Behdad Esfahbod1a0f4aa2016-12-22 13:33:54 -0600570hb_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
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400596hb_ot_substitute_default (hb_ot_shape_context_t *c)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100597{
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200598 hb_buffer_t *buffer = c->buffer;
599
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400600 hb_ot_mirror_chars (c);
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400601
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200602 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400603
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200604 _hb_ot_shape_normalize (c->plan, buffer, c->font);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400605
606 hb_ot_shape_setup_masks (c);
607
Behdad Esfahbod3992b5e2012-09-01 19:20:41 -0400608 /* This is unfortunate to go here, but necessary... */
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600609 if (c->fallback_positioning)
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200610 _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
Behdad Esfahbod3992b5e2012-09-01 19:20:41 -0400611
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200612 hb_ot_map_glyphs_fast (buffer);
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400613
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200614 HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100615}
616
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400617static inline void
Behdad Esfahbodc86f9322011-07-25 00:44:50 -0400618hb_ot_substitute_complex (hb_ot_shape_context_t *c)
619{
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200620 hb_buffer_t *buffer = c->buffer;
621
622 hb_ot_layout_substitute_start (c->font, buffer);
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400623
Behdad Esfahbod1a0f4aa2016-12-22 13:33:54 -0600624 if (!hb_ot_layout_has_glyph_classes (c->face))
625 hb_synthesize_glyph_classes (c);
626
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200627 c->plan->substitute (c->font, buffer);
Behdad Esfahbod748b9892018-01-09 17:55:17 +0100628
Behdad Esfahboddb5d4302018-07-17 18:14:45 +0200629 if (0) /* XXX Call morx instead. */
630 hb_aat_layout_substitute (c->font, c->buffer);
Behdad Esfahbodc86f9322011-07-25 00:44:50 -0400631}
632
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400633static inline void
634hb_ot_substitute (hb_ot_shape_context_t *c)
635{
636 hb_ot_substitute_default (c);
Behdad Esfahbod0f407322015-11-04 22:28:44 -0800637
638 _hb_buffer_allocate_gsubgpos_vars (c->buffer);
639
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400640 hb_ot_substitute_complex (c);
641}
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100642
643/* Position */
644
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400645static inline void
Jonathan Kew798e4182014-06-10 13:10:30 +0100646adjust_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
Jonathan Kew798e4182014-06-10 13:10:30 +0100660zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
Behdad Esfahbodd785fa02013-05-20 09:18:52 -0400661{
662 unsigned int count = buffer->len;
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400663 hb_glyph_info_t *info = buffer->info;
Behdad Esfahbodd785fa02013-05-20 09:18:52 -0400664 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400665 if (_hb_glyph_info_is_mark (&info[i]))
Behdad Esfahbodd785fa02013-05-20 09:18:52 -0400666 {
Jonathan Kew798e4182014-06-10 13:10:30 +0100667 if (adjust_offsets)
668 adjust_mark_offsets (&buffer->pos[i]);
669 zero_mark_width (&buffer->pos[i]);
Behdad Esfahbodd785fa02013-05-20 09:18:52 -0400670 }
671}
672
673static inline void
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400674hb_ot_position_default (hb_ot_shape_context_t *c)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100675{
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200676 hb_direction_t direction = c->buffer->props.direction;
Behdad Esfahbod967240d2010-10-05 23:00:05 -0400677 unsigned int count = c->buffer->len;
Behdad Esfahbodac8cd512013-10-18 19:33:09 +0200678 hb_glyph_info_t *info = c->buffer->info;
679 hb_glyph_position_t *pos = c->buffer->pos;
Behdad Esfahbod56800022013-02-12 09:44:57 -0500680
Behdad Esfahbodbee901b2015-11-04 19:28:17 -0800681 if (HB_DIRECTION_IS_HORIZONTAL (direction))
682 {
683 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodbee901b2015-11-04 19:28:17 -0800684 pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint);
Behdad Esfahbod67a36a72015-11-26 18:48:42 -0500685 /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
Behdad Esfahbod5bc28b52015-11-04 21:53:16 -0800686 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);
Behdad Esfahbodbee901b2015-11-04 19:28:17 -0800691 }
692 else
693 {
694 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod67a36a72015-11-26 18:48:42 -0500695 {
Behdad Esfahbodbee901b2015-11-04 19:28:17 -0800696 pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint);
Behdad Esfahbod67a36a72015-11-26 18:48:42 -0500697 c->font->subtract_glyph_v_origin (info[i].codepoint,
698 &pos[i].x_offset,
699 &pos[i].y_offset);
700 }
Behdad Esfahbod56800022013-02-12 09:44:57 -0500701 }
Behdad Esfahbod49ef6302015-11-04 17:27:07 -0800702 if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
703 _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
Behdad Esfahbod4b011092013-09-13 20:17:42 -0400704}
705
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600706static inline void
Behdad Esfahbod4b011092013-09-13 20:17:42 -0400707hb_ot_position_complex (hb_ot_shape_context_t *c)
708{
Behdad Esfahbod4b011092013-09-13 20:17:42 -0400709 unsigned int count = c->buffer->len;
Behdad Esfahbod9786fcd2017-10-03 17:22:43 +0200710 hb_glyph_info_t *info = c->buffer->info;
711 hb_glyph_position_t *pos = c->buffer->pos;
Behdad Esfahbod84742312016-02-11 16:27:41 +0700712
Jonathan Kew798e4182014-06-10 13:10:30 +0100713 /* If the font has no GPOS, AND, no fallback positioning will
714 * happen, AND, direction is forward, then when zeroing mark
715 * widths, we shift the mark with it, such that the mark
716 * is positioned hanging over the previous glyph. When
717 * direction is backward we don't shift and it will end up
718 * hanging over the next glyph after the final reordering.
719 * If fallback positinoing happens or GPOS is present, we don't
720 * care.
721 */
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600722 bool adjust_offsets_when_zeroing = c->fallback_positioning &&
723 !c->plan->shaper->fallback_position &&
724 HB_DIRECTION_IS_FORWARD (c->buffer->props.direction);
Behdad Esfahbod56800022013-02-12 09:44:57 -0500725
Behdad Esfahbod9786fcd2017-10-03 17:22:43 +0200726 /* We change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
727
728 /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
729 if (c->font->has_glyph_h_origin_func ())
730 for (unsigned int i = 0; i < count; i++)
731 c->font->add_glyph_h_origin (info[i].codepoint,
732 &pos[i].x_offset,
733 &pos[i].y_offset);
734
735 hb_ot_layout_position_start (c->font, c->buffer);
736
Behdad Esfahbod71b4c992013-10-28 00:20:59 +0100737 switch (c->plan->shaper->zero_width_marks)
Behdad Esfahbod56800022013-02-12 09:44:57 -0500738 {
Behdad Esfahbod127daf12013-05-20 09:11:35 -0400739 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
Jonathan Kew798e4182014-06-10 13:10:30 +0100740 zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
Behdad Esfahbod56800022013-02-12 09:44:57 -0500741 break;
742
743 default:
744 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
Behdad Esfahbod127daf12013-05-20 09:11:35 -0400745 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
Behdad Esfahbod56800022013-02-12 09:44:57 -0500746 break;
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100747 }
Behdad Esfahbodc86f9322011-07-25 00:44:50 -0400748
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600749 if (likely (!c->fallback_positioning))
Behdad Esfahbod8bb5deb2012-08-02 10:07:58 -0400750 c->plan->position (c->font, c->buffer);
Behdad Esfahbodc86f9322011-07-25 00:44:50 -0400751
Behdad Esfahbod71b4c992013-10-28 00:20:59 +0100752 switch (c->plan->shaper->zero_width_marks)
Behdad Esfahbod0291a652013-02-13 05:57:24 -0500753 {
Behdad Esfahbod127daf12013-05-20 09:11:35 -0400754 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
Jonathan Kew798e4182014-06-10 13:10:30 +0100755 zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
Behdad Esfahbod127daf12013-05-20 09:11:35 -0400756 break;
757
Behdad Esfahbod0291a652013-02-13 05:57:24 -0500758 default:
759 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
Behdad Esfahbod127daf12013-05-20 09:11:35 -0400760 case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
Behdad Esfahbod0291a652013-02-13 05:57:24 -0500761 break;
762 }
763
Behdad Esfahbod7d8d58a2016-02-11 16:34:28 +0700764 /* Finishing off GPOS has to follow a certain order. */
765 hb_ot_layout_position_finish_advances (c->font, c->buffer);
Behdad Esfahbod84742312016-02-11 16:27:41 +0700766 hb_ot_zero_width_default_ignorables (c);
Behdad Esfahbod7d8d58a2016-02-11 16:34:28 +0700767 hb_ot_layout_position_finish_offsets (c->font, c->buffer);
Behdad Esfahbod9786fcd2017-10-03 17:22:43 +0200768
769 /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
770 if (c->font->has_glyph_h_origin_func ())
771 for (unsigned int i = 0; i < count; i++)
772 c->font->subtract_glyph_h_origin (info[i].codepoint,
773 &pos[i].x_offset,
774 &pos[i].y_offset);
Behdad Esfahbodc86f9322011-07-25 00:44:50 -0400775}
776
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400777static inline void
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400778hb_ot_position (hb_ot_shape_context_t *c)
779{
Behdad Esfahbod84742312016-02-11 16:27:41 +0700780 c->buffer->clear_positions ();
Behdad Esfahbod4b011092013-09-13 20:17:42 -0400781
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400782 hb_ot_position_default (c);
783
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600784 hb_ot_position_complex (c);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400785
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600786 if (c->fallback_positioning && c->plan->shaper->fallback_position)
Behdad Esfahbod865745b2012-11-14 13:48:26 -0800787 _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400788
789 if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
790 hb_buffer_reverse (c->buffer);
791
Behdad Esfahbod865745b2012-11-14 13:48:26 -0800792 /* Visual fallback goes here. */
793
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600794 if (c->fallback_positioning)
Behdad Esfahbodba87b8f2013-02-21 15:23:39 -0500795 _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
Behdad Esfahbod8f3eebf2014-08-02 17:18:46 -0400796
797 _hb_buffer_deallocate_gsubgpos_vars (c->buffer);
Ebrahim Byagowi1ab16f42018-02-24 12:49:42 +0330798
799 //hb_aat_layout_position (c->font, c->buffer);
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400800}
801
Behdad Esfahbod1c17c2b2017-08-11 19:06:07 -0700802static inline void
803hb_propagate_flags (hb_buffer_t *buffer)
804{
805 /* Propagate cluster-level glyph flags to be the same on all cluster glyphs.
806 * Simplifies using them. */
807
808 if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK))
809 return;
810
811 hb_glyph_info_t *info = buffer->info;
812
813 foreach_cluster (buffer, start, end)
814 {
815 unsigned int mask = 0;
816 for (unsigned int i = start; i < end; i++)
817 if (info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
818 {
819 mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
820 break;
821 }
822 if (mask)
823 for (unsigned int i = start; i < end; i++)
824 info[i].mask |= mask;
825 }
826}
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400827
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400828/* Pull it all together! */
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100829
Behdad Esfahbod967240d2010-10-05 23:00:05 -0400830static void
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400831hb_ot_shape_internal (hb_ot_shape_context_t *c)
Behdad Esfahbod967240d2010-10-05 23:00:05 -0400832{
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400833 c->buffer->deallocate_var_all ();
Behdad Esfahbod49ef6302015-11-04 17:27:07 -0800834 c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
Behdad Esfahbodbddeb2b2018-07-10 14:12:37 +0200835 if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
Behdad Esfahbod43017032015-11-05 23:44:59 -0800836 {
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800837 c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
Behdad Esfahbod43017032015-11-05 23:44:59 -0800838 (unsigned) HB_BUFFER_MAX_LEN_MIN);
839 }
Behdad Esfahbodbddeb2b2018-07-10 14:12:37 +0200840 if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800841 {
842 c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
843 (unsigned) HB_BUFFER_MAX_OPS_MIN);
844 }
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400845
Behdad Esfahbode2b87802016-12-22 14:40:19 -0600846 bool disable_otl = c->plan->shaper->disable_otl && c->plan->shaper->disable_otl (c->plan);
847 //c->fallback_substitute = disable_otl || !hb_ot_layout_has_substitution (c->face);
848 c->fallback_positioning = disable_otl || !hb_ot_layout_has_positioning (c->face);
849 c->fallback_glyph_classes = disable_otl || !hb_ot_layout_has_glyph_classes (c->face);
850
Behdad Esfahbodd2ba0162010-10-12 15:35:45 -0400851 /* Save the original direction, we use it later. */
Behdad Esfahbodbbbbe802010-12-07 16:22:02 -0500852 c->target_direction = c->buffer->props.direction;
Behdad Esfahbodd2ba0162010-10-12 15:35:45 -0400853
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200854 _hb_buffer_allocate_unicode_vars (c->buffer);
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400855
Behdad Esfahbod330a2af2012-06-08 20:40:02 -0400856 c->buffer->clear_output ();
857
Behdad Esfahbod7cc34802017-09-04 20:04:59 -0700858 hb_ot_shape_initialize_masks (c);
Behdad Esfahbodd1deaa22012-05-09 15:04:13 +0200859 hb_set_unicode_props (c->buffer);
Behdad Esfahbod6912e472012-09-01 20:38:45 -0400860 hb_insert_dotted_circle (c->buffer, c->font);
Behdad Esfahbod7cc34802017-09-04 20:04:59 -0700861
Behdad Esfahbod4ff0d2d2011-07-22 16:15:32 -0400862 hb_form_clusters (c->buffer);
863
Behdad Esfahbodaa726412011-07-21 11:34:59 -0400864 hb_ensure_native_direction (c->buffer);
Behdad Esfahbod54d1a0d2011-07-21 01:11:09 -0400865
Behdad Esfahbod13686332015-11-05 13:24:15 -0800866 if (c->plan->shaper->preprocess_text)
867 c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
868
Behdad Esfahbod5c60b702012-08-09 21:58:07 -0400869 hb_ot_substitute (c);
870 hb_ot_position (c);
Behdad Esfahbod655586f2011-07-21 00:51:18 -0400871
Behdad Esfahbod8cfbc302015-07-22 18:41:10 +0100872 hb_ot_hide_default_ignorables (c);
873
Behdad Esfahbod13686332015-11-05 13:24:15 -0800874 if (c->plan->shaper->postprocess_glyphs)
875 c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
876
Behdad Esfahbod1c17c2b2017-08-11 19:06:07 -0700877 hb_propagate_flags (c->buffer);
878
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200879 _hb_buffer_deallocate_unicode_vars (c->buffer);
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400880
Behdad Esfahbodbbbbe802010-12-07 16:22:02 -0500881 c->buffer->props.direction = c->target_direction;
Behdad Esfahbod9f9bcce2011-07-28 17:06:46 -0400882
Behdad Esfahbod43017032015-11-05 23:44:59 -0800883 c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800884 c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
Behdad Esfahbod9f9bcce2011-07-28 17:06:46 -0400885 c->buffer->deallocate_var_all ();
Behdad Esfahbod967240d2010-10-05 23:00:05 -0400886}
887
Behdad Esfahbodfd3d32d2010-10-12 16:57:47 -0400888
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400889hb_bool_t
Behdad Esfahbodbd26b4d2012-07-26 22:05:39 -0400890_hb_ot_shape (hb_shape_plan_t *shape_plan,
891 hb_font_t *font,
Behdad Esfahbod6bd9b472012-04-12 14:53:53 -0400892 hb_buffer_t *buffer,
893 const hb_feature_t *features,
894 unsigned int num_features)
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100895{
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400896 hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
897 hb_ot_shape_internal (&c);
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400898
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400899 return true;
Behdad Esfahbodca663bb2010-05-21 14:34:23 +0100900}
Behdad Esfahbod1827dc22012-04-24 16:56:37 -0400901
902
Sascha Brawer01c3a882015-06-01 13:22:01 +0200903/**
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500904 * hb_ot_shape_plan_collect_lookups:
905 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200906 * Since: 0.9.7
907 **/
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800908void
909hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
910 hb_tag_t table_tag,
911 hb_set_t *lookup_indexes /* OUT */)
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400912{
Behdad Esfahbod51bb4982012-11-16 14:08:05 -0800913 /* XXX Does the first part always succeed? */
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800914 HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
Behdad Esfahbodb00321e2012-08-09 22:33:32 -0400915}
916
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800917
918/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
919static void
920add_char (hb_font_t *font,
921 hb_unicode_funcs_t *unicode,
922 hb_bool_t mirror,
923 hb_codepoint_t u,
924 hb_set_t *glyphs)
925{
926 hb_codepoint_t glyph;
Behdad Esfahbod8b5bc142016-02-24 19:05:23 +0900927 if (font->get_nominal_glyph (u, &glyph))
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800928 glyphs->add (glyph);
929 if (mirror)
930 {
931 hb_codepoint_t m = unicode->mirroring (u);
Behdad Esfahbod8b5bc142016-02-24 19:05:23 +0900932 if (m != u && font->get_nominal_glyph (m, &glyph))
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800933 glyphs->add (glyph);
934 }
935}
936
937
Sascha Brawer01c3a882015-06-01 13:22:01 +0200938/**
Behdad Esfahbod35d18582015-11-26 19:30:37 -0500939 * hb_ot_shape_glyphs_closure:
940 *
Sascha Brawer01c3a882015-06-01 13:22:01 +0200941 * Since: 0.9.2
942 **/
Behdad Esfahbod1827dc22012-04-24 16:56:37 -0400943void
944hb_ot_shape_glyphs_closure (hb_font_t *font,
945 hb_buffer_t *buffer,
946 const hb_feature_t *features,
947 unsigned int num_features,
948 hb_set_t *glyphs)
949{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200950 const char *shapers[] = {"ot", nullptr};
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800951 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
952 features, num_features, shapers);
Behdad Esfahbod1827dc22012-04-24 16:56:37 -0400953
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800954 bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
Behdad Esfahbod1827dc22012-04-24 16:56:37 -0400955
Behdad Esfahbod1827dc22012-04-24 16:56:37 -0400956 unsigned int count = buffer->len;
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400957 hb_glyph_info_t *info = buffer->info;
Behdad Esfahbod1827dc22012-04-24 16:56:37 -0400958 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod7cd33f22014-07-17 14:22:11 -0400959 add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800960
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400961 hb_set_t *lookups = hb_set_create ();
962 hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, lookups);
Garret Rieger57badad2018-06-06 16:02:51 -0700963 hb_ot_layout_lookups_substitute_closure (font->face, lookups, glyphs);
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400964
965 hb_set_destroy (lookups);
Behdad Esfahbode82061e2012-07-27 02:29:32 -0400966
967 hb_shape_plan_destroy (shape_plan);
Behdad Esfahbod1827dc22012-04-24 16:56:37 -0400968}