blob: 5b1ba4515434e28ce62c68aba1d73a7fdf715904 [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 Esfahbodc77ae402018-08-25 22:36:36 -070029#include "hb-shaper-impl.hh"
Behdad Esfahbodcd2b9012011-08-24 01:47:25 +020030
Behdad Esfahbode4992e12012-08-06 19:25:39 -070031#include "hb-graphite2.h"
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +020032
Behdad Esfahbod882edce2013-09-13 20:36:43 -040033#include <graphite2/Segment.h>
34
Behdad Esfahbod46072b72018-10-27 04:21:20 -070035#include "hb-ot-layout.h"
Behdad Esfahbodec8f4932018-10-11 20:15:00 -040036
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +020037
Behdad Esfahbod04981ee2018-10-27 04:40:43 -070038/**
39 * SECTION:hb-graphite2
40 * @title: hb-graphite2
41 * @short_description: Graphite2 integration
42 * @include: hb-graphite2.h
43 *
44 * Functions for using HarfBuzz with the Graphite2 fonts.
45 **/
46
47
Behdad Esfahbode4992e12012-08-06 19:25:39 -070048/*
49 * shaper face data
50 */
51
Behdad Esfahbod1f738092018-08-09 00:22:37 -070052typedef struct hb_graphite2_tablelist_t
53{
Behdad Esfahbode4992e12012-08-06 19:25:39 -070054 struct hb_graphite2_tablelist_t *next;
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040055 hb_blob_t *blob;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020056 unsigned int tag;
Behdad Esfahbode4992e12012-08-06 19:25:39 -070057} hb_graphite2_tablelist_t;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020058
Behdad Esfahbod1f738092018-08-09 00:22:37 -070059struct hb_graphite2_face_data_t
60{
Behdad Esfahbode4992e12012-08-06 19:25:39 -070061 hb_face_t *face;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020062 gr_face *grface;
Behdad Esfahbod1f738092018-08-09 00:22:37 -070063 hb_atomic_ptr_t<hb_graphite2_tablelist_t> tlist;
Behdad Esfahbode4992e12012-08-06 19:25:39 -070064};
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020065
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040066static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020067{
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -070068 hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -050069 hb_graphite2_tablelist_t *tlist = face_data->tlist;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020070
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +020071 hb_blob_t *blob = nullptr;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020072
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040073 for (hb_graphite2_tablelist_t *p = tlist; p; p = p->next)
74 if (p->tag == tag) {
75 blob = p->blob;
76 break;
77 }
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020078
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040079 if (unlikely (!blob))
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020080 {
Behdad Esfahbod4c8ac4f2012-08-08 17:44:19 -040081 blob = face_data->face->reference_table (tag);
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040082
83 hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
84 if (unlikely (!p)) {
Behdad Esfahbod81ec2892011-08-26 09:33:06 +020085 hb_blob_destroy (blob);
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +020086 return nullptr;
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +020087 }
Behdad Esfahbod32d71dc2012-08-07 14:11:16 -040088 p->blob = blob;
89 p->tag = tag;
90
Ebrahim Byagowid3a432a2018-03-30 04:58:47 +043091retry:
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -050092 hb_graphite2_tablelist_t *tlist = face_data->tlist;
Ebrahim Byagowid3a432a2018-03-30 04:58:47 +043093 p->next = tlist;
94
Behdad Esfahbod1f738092018-08-09 00:22:37 -070095 if (unlikely (!face_data->tlist.cmpexch (tlist, p)))
Ebrahim Byagowid3a432a2018-03-30 04:58:47 +043096 goto retry;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020097 }
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +020098
99 unsigned int tlen;
100 const char *d = hb_blob_get_data (blob, &tlen);
101 *len = tlen;
102 return d;
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200103}
104
mhoskene4e74c22018-10-04 02:33:26 +0700105static void hb_graphite2_release_table(const void *data, const void *table_buffer)
106{
107 hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -0500108 hb_graphite2_tablelist_t *tlist = face_data->tlist;
mhoskene4e74c22018-10-04 02:33:26 +0700109
110 hb_graphite2_tablelist_t *prev = nullptr;
111 hb_graphite2_tablelist_t *curr = tlist;
112 while (curr)
113 {
114 if (hb_blob_get_data(curr->blob, nullptr) == table_buffer)
115 {
116 if (prev == nullptr)
117 face_data->tlist.cmpexch(tlist, curr->next);
118 else
119 prev->next = curr->next;
120 hb_blob_destroy(curr->blob);
121 free(curr);
122 break;
123 }
124 prev = curr;
125 curr = curr->next;
126 }
127}
128
129static gr_face_ops hb_graphite2_face_ops = { sizeof(gr_face_ops), hb_graphite2_get_table, hb_graphite2_release_table };
130
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700131hb_graphite2_face_data_t *
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700132_hb_graphite2_shaper_face_data_create (hb_face_t *face)
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200133{
Behdad Esfahbod4c8ac4f2012-08-08 17:44:19 -0400134 hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF);
Behdad Esfahbodade74592012-08-06 19:42:47 -0700135 /* Umm, we just reference the table to check whether it exists.
136 * Maybe add better API for this? */
Behdad Esfahbod81ec2892011-08-26 09:33:06 +0200137 if (!hb_blob_get_length (silf_blob))
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200138 {
Behdad Esfahbod81ec2892011-08-26 09:33:06 +0200139 hb_blob_destroy (silf_blob);
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200140 return nullptr;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200141 }
Behdad Esfahbodade74592012-08-06 19:42:47 -0700142 hb_blob_destroy (silf_blob);
143
Behdad Esfahbodd4d1bf82018-08-02 02:04:02 -0700144 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 -0700145 if (unlikely (!data))
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200146 return nullptr;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200147
148 data->face = face;
mhoskene4e74c22018-10-04 02:33:26 +0700149 data->grface = gr_make_face_with_ops (data, &hb_graphite2_face_ops, gr_face_preloadAll);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200150
Behdad Esfahbodade74592012-08-06 19:42:47 -0700151 if (unlikely (!data->grface)) {
152 free (data);
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200153 return nullptr;
Behdad Esfahbodade74592012-08-06 19:42:47 -0700154 }
155
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200156 return data;
157}
158
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700159void
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700160_hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200161{
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -0500162 hb_graphite2_tablelist_t *tlist = data->tlist;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200163
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700164 while (tlist)
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200165 {
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700166 hb_graphite2_tablelist_t *old = tlist;
167 hb_blob_destroy (tlist->blob);
168 tlist = tlist->next;
169 free (old);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200170 }
171
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700172 gr_face_destroy (data->grface);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200173
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700174 free (data);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200175}
176
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430177/*
178 * Since: 0.9.10
179 */
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500180gr_face *
181hb_graphite2_face_get_gr_face (hb_face_t *face)
182{
Behdad Esfahbodce5da0f2018-11-16 02:29:13 -0500183 const hb_graphite2_face_data_t *data = face->data.graphite2;
184 return data ? data->grface : nullptr;
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500185}
186
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200187
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700188/*
189 * shaper font data
190 */
191
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700192struct hb_graphite2_font_data_t {};
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700193
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700194hb_graphite2_font_data_t *
Khaled Hosnyb435c7c2016-11-11 02:16:39 +0200195_hb_graphite2_shaper_font_data_create (hb_font_t *font HB_UNUSED)
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700196{
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700197 return (hb_graphite2_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700198}
199
200void
Behdad Esfahbod3d22aef2018-08-01 18:03:32 -0700201_hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED)
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700202{
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700203}
204
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700205#ifndef HB_DISABLE_DEPRECATED
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700206/**
207 * hb_graphite2_font_get_gr_font:
208 *
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430209 * Since: 0.9.10
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700210 * Deprecated: 1.4.2
Behdad Esfahbodb8811422015-09-03 15:53:22 +0430211 */
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500212gr_font *
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700213hb_graphite2_font_get_gr_font (hb_font_t *font HB_UNUSED)
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500214{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200215 return nullptr;
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500216}
Behdad Esfahbodfca27862019-05-11 00:37:01 -0700217#endif
Behdad Esfahboda5a4ab32012-12-09 18:44:41 -0500218
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700219
220/*
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700221 * shaper
222 */
223
224struct hb_graphite2_cluster_t {
225 unsigned int base_char;
226 unsigned int num_chars;
227 unsigned int base_glyph;
228 unsigned int num_glyphs;
Behdad Esfahbod6ae13f22014-05-30 17:38:14 -0400229 unsigned int cluster;
Martin Hosken731b13e2019-03-04 11:12:21 +0700230 unsigned int advance;
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700231};
232
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200233hb_bool_t
Behdad Esfahbod39bd07a2018-10-26 21:01:11 -0700234_hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700235 hb_font_t *font,
236 hb_buffer_t *buffer,
237 const hb_feature_t *features,
238 unsigned int num_features)
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200239{
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700240 hb_face_t *face = font->face;
Behdad Esfahbodce5da0f2018-11-16 02:29:13 -0500241 gr_face *grface = face->data.graphite2->grface;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200242
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200243 const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200244 const char *lang_end = lang ? strchr (lang, '-') : nullptr;
Behdad Esfahbod290e3ee2011-08-26 09:25:04 +0200245 int lang_len = lang_end ? lang_end - lang : -1;
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700246 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 +0200247
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100248 for (unsigned int i = 0; i < num_features; i++)
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200249 {
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100250 const gr_feature_ref *fref = gr_face_find_fref (grface, features[i].tag);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200251 if (fref)
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100252 gr_fref_set_feature_value (fref, features[i].value, feats);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200253 }
254
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200255 gr_segment *seg = nullptr;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200256 const gr_slot *is;
257 unsigned int ci = 0, ic = 0;
Martin Hosken731b13e2019-03-04 11:12:21 +0700258 unsigned int curradvx = 0, curradvy = 0;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200259
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400260 unsigned int scratch_size;
Behdad Esfahbod68c372e2013-11-13 14:44:01 -0500261 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200262
Behdad Esfahbod16f175c2013-11-12 17:22:49 -0500263 uint32_t *chars = (uint32_t *) scratch;
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400264
265 for (unsigned int i = 0; i < buffer->len; ++i)
266 chars[i] = buffer->info[i].codepoint;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200267
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100268 /* TODO ensure_native_direction. */
269
David Corbett1e816d62018-10-11 20:37:49 -0400270 hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT];
271 unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT;
Behdad Esfahbod4f9e36e2018-10-11 14:32:59 -0400272 hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer),
273 HB_LANGUAGE_INVALID,
274 &count,
275 script_tag,
276 nullptr, nullptr);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200277
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200278 seg = gr_make_seg (nullptr, grface,
Behdad Esfahbodec8f4932018-10-11 20:15:00 -0400279 count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT,
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200280 feats,
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400281 gr_utf32, chars, buffer->len,
Behdad Esfahbod81ec2892011-08-26 09:33:06 +0200282 2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200283
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400284 if (unlikely (!seg)) {
285 if (feats) gr_featureval_destroy (feats);
286 return false;
287 }
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200288
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400289 unsigned int glyph_count = gr_seg_n_slots (seg);
290 if (unlikely (!glyph_count)) {
291 if (feats) gr_featureval_destroy (feats);
292 gr_seg_destroy (seg);
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100293 buffer->len = 0;
294 return true;
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400295 }
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200296
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100297 buffer->ensure (glyph_count);
Behdad Esfahbod16f175c2013-11-12 17:22:49 -0500298 scratch = buffer->get_scratch_buffer (&scratch_size);
299 while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
300 DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400301 {
Behdad Esfahbod15c633d2014-08-11 13:42:42 -0400302 if (unlikely (!buffer->ensure (buffer->allocated * 2)))
303 {
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400304 if (feats) gr_featureval_destroy (feats);
305 gr_seg_destroy (seg);
306 return false;
307 }
Behdad Esfahbod16f175c2013-11-12 17:22:49 -0500308 scratch = buffer->get_scratch_buffer (&scratch_size);
309 }
310
311#define ALLOCATE_ARRAY(Type, name, len) \
312 Type *name = (Type *) scratch; \
313 { \
314 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
315 assert (_consumed <= scratch_size); \
316 scratch += _consumed; \
317 scratch_size -= _consumed; \
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400318 }
319
320 ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len);
321 ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count);
322
Behdad Esfahbod16f175c2013-11-12 17:22:49 -0500323#undef ALLOCATE_ARRAY
324
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400325 memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
326
327 hb_codepoint_t *pg = gids;
Behdad Esfahbod6ae13f22014-05-30 17:38:14 -0400328 clusters[0].cluster = buffer->info[0].cluster;
Martin Hosken731b13e2019-03-04 11:12:21 +0700329 unsigned int upem = hb_face_get_upem (face);
330 float xscale = (float) font->x_scale / upem;
331 float yscale = (float) font->y_scale / upem;
332 yscale *= yscale / xscale;
333 unsigned int curradv = 0;
Martin Hosken146fe252016-01-16 17:24:00 -0600334 if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
335 {
Martin Hosken731b13e2019-03-04 11:12:21 +0700336 curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
337 clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
Martin Hosken146fe252016-01-16 17:24:00 -0600338 }
Martin Hosken4de03a12017-11-10 13:47:38 +0700339 else
340 clusters[0].advance = 0;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200341 for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
342 {
343 unsigned int before = gr_slot_before (is);
344 unsigned int after = gr_slot_after (is);
345 *pg = gr_slot_gid (is);
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200346 pg++;
347 while (clusters[ci].base_char > before && ci)
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200348 {
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200349 clusters[ci-1].num_chars += clusters[ci].num_chars;
350 clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
Martin Hosken146fe252016-01-16 17:24:00 -0600351 clusters[ci-1].advance += clusters[ci].advance;
Behdad Esfahboda5edb102011-08-26 09:27:13 +0200352 ci--;
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200353 }
354
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200355 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 +0200356 {
Behdad Esfahbode4992e12012-08-06 19:25:39 -0700357 hb_graphite2_cluster_t *c = clusters + ci + 1;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200358 c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
Behdad Esfahbod6ae13f22014-05-30 17:38:14 -0400359 c->cluster = buffer->info[c->base_char].cluster;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200360 c->num_chars = before - c->base_char;
361 c->base_glyph = ic;
362 c->num_glyphs = 0;
Martin Hosken146fe252016-01-16 17:24:00 -0600363 if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
Martin Hosken731b13e2019-03-04 11:12:21 +0700364 {
365 c->advance = curradv - gr_slot_origin_X(is) * xscale;
366 curradv -= c->advance;
367 }
mhosken74b99ef2017-04-20 19:13:22 +0100368 else
Martin Hosken4de03a12017-11-10 13:47:38 +0700369 {
370 c->advance = 0;
Martin Hosken731b13e2019-03-04 11:12:21 +0700371 clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv;
372 curradv += clusters[ci].advance;
Martin Hosken4de03a12017-11-10 13:47:38 +0700373 }
mhosken74b99ef2017-04-20 19:13:22 +0100374 ci++;
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200375 }
Behdad Esfahboda5edb102011-08-26 09:27:13 +0200376 clusters[ci].num_glyphs++;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200377
378 if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
379 clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
380 }
Martin Hosken146fe252016-01-16 17:24:00 -0600381
mhosken74b99ef2017-04-20 19:13:22 +0100382 if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
383 clusters[ci].advance += curradv;
384 else
Martin Hosken731b13e2019-03-04 11:12:21 +0700385 clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
Behdad Esfahboda5edb102011-08-26 09:27:13 +0200386 ci++;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200387
Behdad Esfahboda5edb102011-08-26 09:27:13 +0200388 for (unsigned int i = 0; i < ci; ++i)
Behdad Esfahbod8e584592012-12-09 18:45:47 -0500389 {
390 for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
391 {
392 hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
393 info->codepoint = gids[clusters[i].base_glyph + j];
Behdad Esfahbod6ae13f22014-05-30 17:38:14 -0400394 info->cluster = clusters[i].cluster;
Martin Hosken146fe252016-01-16 17:24:00 -0600395 info->var1.i32 = clusters[i].advance; // all glyphs in the cluster get the same advance
Behdad Esfahbod8e584592012-12-09 18:45:47 -0500396 }
397 }
398 buffer->len = glyph_count;
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200399
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100400 /* Positioning. */
Behdad Esfahbod219af502017-08-13 15:10:26 -0700401 unsigned int currclus = (unsigned int) -1;
mhosken74b99ef2017-04-20 19:13:22 +0100402 const hb_glyph_info_t *info = buffer->info;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200403 hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr);
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100404 if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
Behdad Esfahboda3bd8a02011-08-24 03:22:49 +0200405 {
Martin Hosken146fe252016-01-16 17:24:00 -0600406 curradvx = 0;
407 for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100408 {
Khaled Hosny1b00a3b2016-10-30 20:16:41 +0200409 pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
Martin Hosken1979f6f2015-11-23 10:03:56 +0700410 pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
Martin Hosken146fe252016-01-16 17:24:00 -0600411 if (info->cluster != currclus) {
Martin Hosken731b13e2019-03-04 11:12:21 +0700412 pPos->x_advance = info->var1.i32;
Ebrahim Byagowi09d5e542018-04-11 17:41:48 +0430413 curradvx += pPos->x_advance;
414 currclus = info->cluster;
Martin Hosken146fe252016-01-16 17:24:00 -0600415 } else
Ebrahim Byagowi09d5e542018-04-11 17:41:48 +0430416 pPos->x_advance = 0.;
Martin Hosken146fe252016-01-16 17:24:00 -0600417
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200418 pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100419 curradvy += pPos->y_advance;
420 }
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100421 }
422 else
423 {
mhosken66128d32017-09-27 01:29:45 +0700424 curradvx = gr_seg_advance_X(seg) * xscale;
Martin Hosken146fe252016-01-16 17:24:00 -0600425 for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100426 {
427 if (info->cluster != currclus)
428 {
Martin Hosken731b13e2019-03-04 11:12:21 +0700429 pPos->x_advance = info->var1.i32;
Ebrahim Byagowi09d5e542018-04-11 17:41:48 +0430430 curradvx -= pPos->x_advance;
431 currclus = info->cluster;
Martin Hosken146fe252016-01-16 17:24:00 -0600432 } else
Ebrahim Byagowi09d5e542018-04-11 17:41:48 +0430433 pPos->x_advance = 0.;
Martin Hosken146fe252016-01-16 17:24:00 -0600434
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200435 pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100436 curradvy -= pPos->y_advance;
Martin Hosken731b13e2019-03-04 11:12:21 +0700437 pPos->x_offset = gr_slot_origin_X (is) * xscale - info->var1.i32 - curradvx + pPos->x_advance;
Martin Hosken1979f6f2015-11-23 10:03:56 +0700438 pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100439 }
Behdad Esfahbod2fef9932012-08-06 19:35:04 -0700440 hb_buffer_reverse_clusters (buffer);
Behdad Esfahbod97d7c3a2015-07-22 14:28:25 +0100441 }
Behdad Esfahbodf83f0f42011-09-19 18:51:48 -0400442
Behdad Esfahbodade74592012-08-06 19:42:47 -0700443 if (feats) gr_featureval_destroy (feats);
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400444 gr_seg_destroy (seg);
445
Behdad Esfahbode4da3802017-11-10 17:14:27 -0800446 buffer->unsafe_to_break_all ();
447
Behdad Esfahbod56e878a2012-08-24 00:41:51 -0400448 return true;
Behdad Esfahbod1f49cf32011-08-24 01:29:25 +0200449}