blob: 220ba4fc192085efc0b2dad7e9870b27bfe73528 [file] [log] [blame]
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +02001/*
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +02002 * Copyright © 2011 Martin Hosken
3 * Copyright © 2011 SIL International
Behdad Esfahbode4992e12012-08-06 19:25:39 -07004 * Copyright © 2011,2012 Google, Inc.
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +02005 *
6 * This is part of HarfBuzz, a text shaping library.
7 *
8 * Permission is hereby granted, without written agreement and without
9 * license or royalty fees, to use, copy, modify, and distribute this
10 * software and its documentation for any purpose, provided that the
11 * above copyright notice and the following two paragraphs appear in
12 * all copies of this software.
13 *
14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18 * DAMAGE.
19 *
20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
23 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020025 *
26 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +020027 */
28
Behdad Esfahbodaa3450c2019-06-17 22:41:49 -070029#include "hb.hh"
30
31#ifdef HAVE_GRAPHITE2
32
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070033#include "hb-shaper-impl.hh"
Behdad Esfahbodcd2b9012011-08-24 01:47:25 +020034
Behdad Esfahbode4992e12012-08-06 19:25:39 -070035#include "hb-graphite2.h"
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +020036
Behdad Esfahbod882edce2013-09-13 20:36:43 -040037#include <graphite2/Segment.h>
38
Behdad Esfahbod46072b72018-10-27 04:21:20 -070039#include "hb-ot-layout.h"
Behdad Esfahbodec8f4932018-10-11 20:15:00 -040040
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +020041
Behdad Esfahbod04981ee2018-10-27 04:40:43 -070042/**
43 * SECTION:hb-graphite2
44 * @title: hb-graphite2
45 * @short_description: Graphite2 integration
46 * @include: hb-graphite2.h
47 *
n8willisfb9d1062020-04-13 15:14:42 +010048 * Functions for using HarfBuzz with fonts that include Graphite features.
Nathan Willisd00a20b2019-05-20 17:38:38 +010049 *
n8willisa199eab2020-04-13 15:14:28 +010050 * For Graphite features to work, you must be sure that HarfBuzz was compiled
Nathan Willisd00a20b2019-05-20 17:38:38 +010051 * with the `graphite2` shaping engine enabled. Currently, the default is to
52 * not enable `graphite2` shaping.
Behdad Esfahbod04981ee2018-10-27 04:40:43 -070053 **/
54
55
Behdad Esfahbode4992e12012-08-06 19:25:39 -070056/*
57 * shaper face data
58 */
59
Behdad Esfahbod1f738092018-08-09 00:22:37 -070060typedef struct hb_graphite2_tablelist_t
61{
Behdad Esfahbode4992e12012-08-06 19:25:39 -070062 struct hb_graphite2_tablelist_t *next;
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040063 hb_blob_t *blob;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020064 unsigned int tag;
Behdad Esfahbode4992e12012-08-06 19:25:39 -070065} hb_graphite2_tablelist_t;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020066
Behdad Esfahbod1f738092018-08-09 00:22:37 -070067struct hb_graphite2_face_data_t
68{
Behdad Esfahbode4992e12012-08-06 19:25:39 -070069 hb_face_t *face;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020070 gr_face *grface;
Behdad Esfahbod1f738092018-08-09 00:22:37 -070071 hb_atomic_ptr_t<hb_graphite2_tablelist_t> tlist;
Behdad Esfahbode4992e12012-08-06 19:25:39 -070072};
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020073
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040074static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020075{
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -070076 hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -050077 hb_graphite2_tablelist_t *tlist = face_data->tlist;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020078
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +020079 hb_blob_t *blob = nullptr;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020080
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040081 for (hb_graphite2_tablelist_t *p = tlist; p; p = p->next)
82 if (p->tag == tag) {
83 blob = p->blob;
84 break;
85 }
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020086
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040087 if (unlikely (!blob))
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020088 {
Behdad Esfahbod4c8ac4f2012-08-08 17:44:19 -040089 blob = face_data->face->reference_table (tag);
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040090
91 hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
92 if (unlikely (!p)) {
Behdad Esfahbod81ec2892011-08-26 09:33:06 +020093 hb_blob_destroy (blob);
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +020094 return nullptr;
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +020095 }
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040096 p->blob = blob;
97 p->tag = tag;
98
Ebrahim Byagowid3a432a2018-03-30 04:58:47 +043099retry:
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -0500100 hb_graphite2_tablelist_t *tlist = face_data->tlist;
Ebrahim Byagowid3a432a2018-03-30 04:58:47 +0430101 p->next = tlist;
102
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700103 if (unlikely (!face_data->tlist.cmpexch (tlist, p)))
Ebrahim Byagowid3a432a2018-03-30 04:58:47 +0430104 goto retry;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200105 }
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200106
107 unsigned int tlen;
108 const char *d = hb_blob_get_data (blob, &tlen);
109 *len = tlen;
110 return d;
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200111}
112
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700113hb_graphite2_face_data_t *
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700114_hb_graphite2_shaper_face_data_create (hb_face_t *face)
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200115{
Behdad Esfahbod4c8ac4f2012-08-08 17:44:19 -0400116 hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF);
Behdad Esfahbodade74592012-08-06 19:42:47 -0700117 /* Umm, we just reference the table to check whether it exists.
118 * Maybe add better API for this? */
Behdad Esfahbod81ec2892011-08-26 09:33:06 +0200119 if (!hb_blob_get_length (silf_blob))
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200120 {
Behdad Esfahbod81ec2892011-08-26 09:33:06 +0200121 hb_blob_destroy (silf_blob);
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200122 return nullptr;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200123 }
Behdad Esfahbodade74592012-08-06 19:42:47 -0700124 hb_blob_destroy (silf_blob);
125
Behdad Esfahbodd4d1bf82018-08-02 02:04:02 -0700126 hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) calloc (1, sizeof (hb_graphite2_face_data_t));
Behdad Esfahbodade74592012-08-06 19:42:47 -0700127 if (unlikely (!data))
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200128 return nullptr;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200129
130 data->face = face;
Behdad Esfahbod4730b352019-07-12 15:38:35 -0700131 data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200132
Behdad Esfahbodade74592012-08-06 19:42:47 -0700133 if (unlikely (!data->grface)) {
134 free (data);
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200135 return nullptr;
Behdad Esfahbodade74592012-08-06 19:42:47 -0700136 }
137
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200138 return data;
139}
140
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700141void
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700142_hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200143{
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -0500144 hb_graphite2_tablelist_t *tlist = data->tlist;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200145
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700146 while (tlist)
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200147 {
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700148 hb_graphite2_tablelist_t *old = tlist;
149 hb_blob_destroy (tlist->blob);
150 tlist = tlist->next;
151 free (old);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200152 }
153
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700154 gr_face_destroy (data->grface);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200155
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700156 free (data);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200157}
158
Nathan Willisd00a20b2019-05-20 17:38:38 +0100159/**
160 * hb_graphite2_face_get_gr_face:
161 * @face: @hb_face_t to query
162 *
163 * Fetches the Graphite2 gr_face corresponding to the specified
164 * #hb_face_t face object.
165 *
166 * Return value: the gr_face found
167 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430168 * Since: 0.9.10
169 */
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500170gr_face *
171hb_graphite2_face_get_gr_face (hb_face_t *face)
172{
Behdad Esfahbodce5da0f2018-11-16 02:29:13 -0500173 const hb_graphite2_face_data_t *data = face->data.graphite2;
174 return data ? data->grface : nullptr;
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500175}
176
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200177
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700178/*
179 * shaper font data
180 */
181
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700182struct hb_graphite2_font_data_t {};
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700183
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700184hb_graphite2_font_data_t *
Khaled Hosnyb435c7c2016-11-11 02:16:39 +0200185_hb_graphite2_shaper_font_data_create (hb_font_t *font HB_UNUSED)
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700186{
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700187 return (hb_graphite2_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700188}
189
190void
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700191_hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED)
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700192{
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700193}
194
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700195#ifndef HB_DISABLE_DEPRECATED
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700196/**
197 * hb_graphite2_font_get_gr_font:
Khaled Hosny478d1692020-12-31 18:17:33 +0200198 * @font: An #hb_font_t
199 *
200 * Always returns %NULL. Use hb_graphite2_face_get_gr_face() instead.
201 *
202 * Return value: (nullable): Graphite2 font associated with @font.
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700203 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430204 * Since: 0.9.10
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700205 * Deprecated: 1.4.2
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430206 */
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500207gr_font *
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700208hb_graphite2_font_get_gr_font (hb_font_t *font HB_UNUSED)
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500209{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200210 return nullptr;
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500211}
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700212#endif
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500213
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700214
215/*
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700216 * shaper
217 */
218
219struct hb_graphite2_cluster_t {
220 unsigned int base_char;
221 unsigned int num_chars;
222 unsigned int base_glyph;
223 unsigned int num_glyphs;
Behdad Esfahbod6ae13f22014-05-30 17:38:14 -0400224 unsigned int cluster;
Martin Hosken731b13e2019-03-04 11:12:21 +0700225 unsigned int advance;
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700226};
227
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200228hb_bool_t
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700229_hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700230 hb_font_t *font,
231 hb_buffer_t *buffer,
232 const hb_feature_t *features,
233 unsigned int num_features)
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200234{
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700235 hb_face_t *face = font->face;
Behdad Esfahbodce5da0f2018-11-16 02:29:13 -0500236 gr_face *grface = face->data.graphite2->grface;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200237
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200238 const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200239 const char *lang_end = lang ? strchr (lang, '-') : nullptr;
Behdad Esfahbod290e3ee2011-08-26 09:25:04 +0200240 int lang_len = lang_end ? lang_end - lang : -1;
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700241 gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200242
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100243 for (unsigned int i = 0; i < num_features; i++)
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200244 {
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100245 const gr_feature_ref *fref = gr_face_find_fref (grface, features[i].tag);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200246 if (fref)
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100247 gr_fref_set_feature_value (fref, features[i].value, feats);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200248 }
249
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200250 gr_segment *seg = nullptr;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200251 const gr_slot *is;
252 unsigned int ci = 0, ic = 0;
Martin Hosken731b13e2019-03-04 11:12:21 +0700253 unsigned int curradvx = 0, curradvy = 0;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200254
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400255 unsigned int scratch_size;
Behdad Esfahbod68c372e2013-11-13 14:44:01 -0500256 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200257
Behdad Esfahbod16f175c2013-11-12 17:22:49 -0500258 uint32_t *chars = (uint32_t *) scratch;
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400259
260 for (unsigned int i = 0; i < buffer->len; ++i)
261 chars[i] = buffer->info[i].codepoint;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200262
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100263 /* TODO ensure_native_direction. */
264
David Corbett1e816d62018-10-11 20:37:49 -0400265 hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT];
266 unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT;
Behdad Esfahbod4f9e36e2018-10-11 14:32:59 -0400267 hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer),
268 HB_LANGUAGE_INVALID,
269 &count,
270 script_tag,
271 nullptr, nullptr);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200272
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200273 seg = gr_make_seg (nullptr, grface,
Behdad Esfahbodec8f4932018-10-11 20:15:00 -0400274 count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT,
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200275 feats,
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400276 gr_utf32, chars, buffer->len,
Behdad Esfahbod81ec2892011-08-26 09:33:06 +0200277 2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200278
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400279 if (unlikely (!seg)) {
280 if (feats) gr_featureval_destroy (feats);
281 return false;
282 }
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200283
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400284 unsigned int glyph_count = gr_seg_n_slots (seg);
285 if (unlikely (!glyph_count)) {
286 if (feats) gr_featureval_destroy (feats);
287 gr_seg_destroy (seg);
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100288 buffer->len = 0;
289 return true;
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400290 }
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200291
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100292 buffer->ensure (glyph_count);
Behdad Esfahbod16f175c2013-11-12 17:22:49 -0500293 scratch = buffer->get_scratch_buffer (&scratch_size);
294 while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
295 DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400296 {
Behdad Esfahbod15c633d2014-08-11 13:42:42 -0400297 if (unlikely (!buffer->ensure (buffer->allocated * 2)))
298 {
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400299 if (feats) gr_featureval_destroy (feats);
300 gr_seg_destroy (seg);
301 return false;
302 }
Behdad Esfahbod16f175c2013-11-12 17:22:49 -0500303 scratch = buffer->get_scratch_buffer (&scratch_size);
304 }
305
306#define ALLOCATE_ARRAY(Type, name, len) \
307 Type *name = (Type *) scratch; \
Behdad Esfahbod68e12e62019-05-13 17:28:59 -0700308 do { \
Behdad Esfahbod16f175c2013-11-12 17:22:49 -0500309 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
310 assert (_consumed <= scratch_size); \
311 scratch += _consumed; \
312 scratch_size -= _consumed; \
Behdad Esfahbod68e12e62019-05-13 17:28:59 -0700313 } while (0)
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400314
315 ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len);
316 ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count);
317
Behdad Esfahbod16f175c2013-11-12 17:22:49 -0500318#undef ALLOCATE_ARRAY
319
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400320 memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
321
322 hb_codepoint_t *pg = gids;
Behdad Esfahbod6ae13f22014-05-30 17:38:14 -0400323 clusters[0].cluster = buffer->info[0].cluster;
Martin Hosken731b13e2019-03-04 11:12:21 +0700324 unsigned int upem = hb_face_get_upem (face);
325 float xscale = (float) font->x_scale / upem;
326 float yscale = (float) font->y_scale / upem;
327 yscale *= yscale / xscale;
328 unsigned int curradv = 0;
Martin Hosken146fe252016-01-16 17:24:00 -0600329 if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
330 {
Martin Hosken731b13e2019-03-04 11:12:21 +0700331 curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
332 clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
Martin Hosken146fe252016-01-16 17:24:00 -0600333 }
Martin Hosken4de03a12017-11-10 13:47:38 +0700334 else
335 clusters[0].advance = 0;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200336 for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
337 {
338 unsigned int before = gr_slot_before (is);
339 unsigned int after = gr_slot_after (is);
340 *pg = gr_slot_gid (is);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200341 pg++;
342 while (clusters[ci].base_char > before && ci)
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200343 {
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200344 clusters[ci-1].num_chars += clusters[ci].num_chars;
345 clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
Martin Hosken146fe252016-01-16 17:24:00 -0600346 clusters[ci-1].advance += clusters[ci].advance;
Behdad Esfahboda5edb102011-08-26 09:27:13 +0200347 ci--;
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200348 }
349
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200350 if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200351 {
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700352 hb_graphite2_cluster_t *c = clusters + ci + 1;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200353 c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
Behdad Esfahbod6ae13f22014-05-30 17:38:14 -0400354 c->cluster = buffer->info[c->base_char].cluster;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200355 c->num_chars = before - c->base_char;
356 c->base_glyph = ic;
357 c->num_glyphs = 0;
Martin Hosken146fe252016-01-16 17:24:00 -0600358 if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
Martin Hosken731b13e2019-03-04 11:12:21 +0700359 {
Ebrahim Byagowia0b4ac42019-08-24 17:57:14 +0430360 c->advance = curradv - gr_slot_origin_X(is) * xscale;
361 curradv -= c->advance;
Martin Hosken731b13e2019-03-04 11:12:21 +0700362 }
mhosken74b99ef2017-04-20 19:13:22 +0100363 else
Martin Hosken4de03a12017-11-10 13:47:38 +0700364 {
Ebrahim Byagowia0b4ac42019-08-24 17:57:14 +0430365 c->advance = 0;
366 clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv;
367 curradv += clusters[ci].advance;
Martin Hosken4de03a12017-11-10 13:47:38 +0700368 }
mhosken74b99ef2017-04-20 19:13:22 +0100369 ci++;
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200370 }
Behdad Esfahboda5edb102011-08-26 09:27:13 +0200371 clusters[ci].num_glyphs++;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200372
373 if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
374 clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
375 }
Martin Hosken146fe252016-01-16 17:24:00 -0600376
mhosken74b99ef2017-04-20 19:13:22 +0100377 if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
378 clusters[ci].advance += curradv;
379 else
Martin Hosken731b13e2019-03-04 11:12:21 +0700380 clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
Behdad Esfahboda5edb102011-08-26 09:27:13 +0200381 ci++;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200382
Behdad Esfahboda5edb102011-08-26 09:27:13 +0200383 for (unsigned int i = 0; i < ci; ++i)
Behdad Esfahbod8e584592012-12-09 18:45:47 -0500384 {
385 for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
386 {
387 hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
388 info->codepoint = gids[clusters[i].base_glyph + j];
Behdad Esfahbod6ae13f22014-05-30 17:38:14 -0400389 info->cluster = clusters[i].cluster;
Martin Hosken146fe252016-01-16 17:24:00 -0600390 info->var1.i32 = clusters[i].advance; // all glyphs in the cluster get the same advance
Behdad Esfahbod8e584592012-12-09 18:45:47 -0500391 }
392 }
393 buffer->len = glyph_count;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200394
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100395 /* Positioning. */
Evgeniy Reiznerb79ceac2019-12-15 16:50:01 +0200396 unsigned int currclus = UINT_MAX;
mhosken74b99ef2017-04-20 19:13:22 +0100397 const hb_glyph_info_t *info = buffer->info;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200398 hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr);
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100399 if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200400 {
Martin Hosken146fe252016-01-16 17:24:00 -0600401 curradvx = 0;
402 for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100403 {
Khaled Hosny1b00a3b2016-10-30 20:16:41 +0200404 pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
Martin Hosken1979f6f2015-11-23 10:03:56 +0700405 pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
Martin Hosken146fe252016-01-16 17:24:00 -0600406 if (info->cluster != currclus) {
Martin Hosken731b13e2019-03-04 11:12:21 +0700407 pPos->x_advance = info->var1.i32;
Ebrahim Byagowi09d5e542018-04-11 17:41:48 +0430408 curradvx += pPos->x_advance;
409 currclus = info->cluster;
Martin Hosken146fe252016-01-16 17:24:00 -0600410 } else
Ebrahim Byagowi09d5e542018-04-11 17:41:48 +0430411 pPos->x_advance = 0.;
Martin Hosken146fe252016-01-16 17:24:00 -0600412
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200413 pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100414 curradvy += pPos->y_advance;
415 }
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100416 }
417 else
418 {
mhosken66128d32017-09-27 01:29:45 +0700419 curradvx = gr_seg_advance_X(seg) * xscale;
Martin Hosken146fe252016-01-16 17:24:00 -0600420 for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100421 {
422 if (info->cluster != currclus)
423 {
Martin Hosken731b13e2019-03-04 11:12:21 +0700424 pPos->x_advance = info->var1.i32;
Ebrahim Byagowi09d5e542018-04-11 17:41:48 +0430425 curradvx -= pPos->x_advance;
426 currclus = info->cluster;
Martin Hosken146fe252016-01-16 17:24:00 -0600427 } else
Ebrahim Byagowi09d5e542018-04-11 17:41:48 +0430428 pPos->x_advance = 0.;
Martin Hosken146fe252016-01-16 17:24:00 -0600429
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200430 pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100431 curradvy -= pPos->y_advance;
Martin Hosken731b13e2019-03-04 11:12:21 +0700432 pPos->x_offset = gr_slot_origin_X (is) * xscale - info->var1.i32 - curradvx + pPos->x_advance;
Martin Hosken1979f6f2015-11-23 10:03:56 +0700433 pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100434 }
Behdad Esfahbod2fef9932012-08-06 19:35:04 -0700435 hb_buffer_reverse_clusters (buffer);
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100436 }
Behdad Esfahbodf83f0f42011-09-19 18:51:48 -0400437
Behdad Esfahbodade74592012-08-06 19:42:47 -0700438 if (feats) gr_featureval_destroy (feats);
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400439 gr_seg_destroy (seg);
440
Behdad Esfahbode4da3802017-11-10 17:14:27 -0800441 buffer->unsafe_to_break_all ();
442
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400443 return true;
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200444}
Behdad Esfahbodaa3450c2019-06-17 22:41:49 -0700445
446
447#endif