1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright © 2011 Martin Hosken 3cb93a386Sopenharmony_ci * Copyright © 2011 SIL International 4cb93a386Sopenharmony_ci * Copyright © 2011,2012 Google, Inc. 5cb93a386Sopenharmony_ci * 6cb93a386Sopenharmony_ci * This is part of HarfBuzz, a text shaping library. 7cb93a386Sopenharmony_ci * 8cb93a386Sopenharmony_ci * Permission is hereby granted, without written agreement and without 9cb93a386Sopenharmony_ci * license or royalty fees, to use, copy, modify, and distribute this 10cb93a386Sopenharmony_ci * software and its documentation for any purpose, provided that the 11cb93a386Sopenharmony_ci * above copyright notice and the following two paragraphs appear in 12cb93a386Sopenharmony_ci * all copies of this software. 13cb93a386Sopenharmony_ci * 14cb93a386Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 15cb93a386Sopenharmony_ci * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 16cb93a386Sopenharmony_ci * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 17cb93a386Sopenharmony_ci * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 18cb93a386Sopenharmony_ci * DAMAGE. 19cb93a386Sopenharmony_ci * 20cb93a386Sopenharmony_ci * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 21cb93a386Sopenharmony_ci * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22cb93a386Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 23cb93a386Sopenharmony_ci * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 24cb93a386Sopenharmony_ci * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25cb93a386Sopenharmony_ci * 26cb93a386Sopenharmony_ci * Google Author(s): Behdad Esfahbod 27cb93a386Sopenharmony_ci */ 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci#include "hb.hh" 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci#ifdef HAVE_GRAPHITE2 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci#include "hb-shaper-impl.hh" 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci#include "hb-graphite2.h" 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci#include <graphite2/Segment.h> 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci#include "hb-ot-layout.h" 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci/** 43cb93a386Sopenharmony_ci * SECTION:hb-graphite2 44cb93a386Sopenharmony_ci * @title: hb-graphite2 45cb93a386Sopenharmony_ci * @short_description: Graphite2 integration 46cb93a386Sopenharmony_ci * @include: hb-graphite2.h 47cb93a386Sopenharmony_ci * 48cb93a386Sopenharmony_ci * Functions for using HarfBuzz with fonts that include Graphite features. 49cb93a386Sopenharmony_ci * 50cb93a386Sopenharmony_ci * For Graphite features to work, you must be sure that HarfBuzz was compiled 51cb93a386Sopenharmony_ci * with the `graphite2` shaping engine enabled. Currently, the default is to 52cb93a386Sopenharmony_ci * not enable `graphite2` shaping. 53cb93a386Sopenharmony_ci **/ 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci/* 57cb93a386Sopenharmony_ci * shaper face data 58cb93a386Sopenharmony_ci */ 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_citypedef struct hb_graphite2_tablelist_t 61cb93a386Sopenharmony_ci{ 62cb93a386Sopenharmony_ci struct hb_graphite2_tablelist_t *next; 63cb93a386Sopenharmony_ci hb_blob_t *blob; 64cb93a386Sopenharmony_ci unsigned int tag; 65cb93a386Sopenharmony_ci} hb_graphite2_tablelist_t; 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_cistruct hb_graphite2_face_data_t 68cb93a386Sopenharmony_ci{ 69cb93a386Sopenharmony_ci hb_face_t *face; 70cb93a386Sopenharmony_ci gr_face *grface; 71cb93a386Sopenharmony_ci hb_atomic_ptr_t<hb_graphite2_tablelist_t> tlist; 72cb93a386Sopenharmony_ci}; 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_cistatic const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len) 75cb93a386Sopenharmony_ci{ 76cb93a386Sopenharmony_ci hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data; 77cb93a386Sopenharmony_ci hb_graphite2_tablelist_t *tlist = face_data->tlist; 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci hb_blob_t *blob = nullptr; 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci for (hb_graphite2_tablelist_t *p = tlist; p; p = p->next) 82cb93a386Sopenharmony_ci if (p->tag == tag) { 83cb93a386Sopenharmony_ci blob = p->blob; 84cb93a386Sopenharmony_ci break; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci if (unlikely (!blob)) 88cb93a386Sopenharmony_ci { 89cb93a386Sopenharmony_ci blob = face_data->face->reference_table (tag); 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) hb_calloc (1, sizeof (hb_graphite2_tablelist_t)); 92cb93a386Sopenharmony_ci if (unlikely (!p)) { 93cb93a386Sopenharmony_ci hb_blob_destroy (blob); 94cb93a386Sopenharmony_ci return nullptr; 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci p->blob = blob; 97cb93a386Sopenharmony_ci p->tag = tag; 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ciretry: 100cb93a386Sopenharmony_ci hb_graphite2_tablelist_t *tlist = face_data->tlist; 101cb93a386Sopenharmony_ci p->next = tlist; 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci if (unlikely (!face_data->tlist.cmpexch (tlist, p))) 104cb93a386Sopenharmony_ci goto retry; 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci unsigned int tlen; 108cb93a386Sopenharmony_ci const char *d = hb_blob_get_data (blob, &tlen); 109cb93a386Sopenharmony_ci *len = tlen; 110cb93a386Sopenharmony_ci return d; 111cb93a386Sopenharmony_ci} 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_cihb_graphite2_face_data_t * 114cb93a386Sopenharmony_ci_hb_graphite2_shaper_face_data_create (hb_face_t *face) 115cb93a386Sopenharmony_ci{ 116cb93a386Sopenharmony_ci hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF); 117cb93a386Sopenharmony_ci /* Umm, we just reference the table to check whether it exists. 118cb93a386Sopenharmony_ci * Maybe add better API for this? */ 119cb93a386Sopenharmony_ci if (!hb_blob_get_length (silf_blob)) 120cb93a386Sopenharmony_ci { 121cb93a386Sopenharmony_ci hb_blob_destroy (silf_blob); 122cb93a386Sopenharmony_ci return nullptr; 123cb93a386Sopenharmony_ci } 124cb93a386Sopenharmony_ci hb_blob_destroy (silf_blob); 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) hb_calloc (1, sizeof (hb_graphite2_face_data_t)); 127cb93a386Sopenharmony_ci if (unlikely (!data)) 128cb93a386Sopenharmony_ci return nullptr; 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci data->face = face; 131cb93a386Sopenharmony_ci const gr_face_ops ops = {sizeof(gr_face_ops), &hb_graphite2_get_table, NULL}; 132cb93a386Sopenharmony_ci data->grface = gr_make_face_with_ops (data, &ops, gr_face_preloadAll); 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci if (unlikely (!data->grface)) { 135cb93a386Sopenharmony_ci hb_free (data); 136cb93a386Sopenharmony_ci return nullptr; 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci return data; 140cb93a386Sopenharmony_ci} 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_civoid 143cb93a386Sopenharmony_ci_hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data) 144cb93a386Sopenharmony_ci{ 145cb93a386Sopenharmony_ci hb_graphite2_tablelist_t *tlist = data->tlist; 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci while (tlist) 148cb93a386Sopenharmony_ci { 149cb93a386Sopenharmony_ci hb_graphite2_tablelist_t *old = tlist; 150cb93a386Sopenharmony_ci hb_blob_destroy (tlist->blob); 151cb93a386Sopenharmony_ci tlist = tlist->next; 152cb93a386Sopenharmony_ci hb_free (old); 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci gr_face_destroy (data->grface); 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci hb_free (data); 158cb93a386Sopenharmony_ci} 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci/** 161cb93a386Sopenharmony_ci * hb_graphite2_face_get_gr_face: 162cb93a386Sopenharmony_ci * @face: @hb_face_t to query 163cb93a386Sopenharmony_ci * 164cb93a386Sopenharmony_ci * Fetches the Graphite2 gr_face corresponding to the specified 165cb93a386Sopenharmony_ci * #hb_face_t face object. 166cb93a386Sopenharmony_ci * 167cb93a386Sopenharmony_ci * Return value: the gr_face found 168cb93a386Sopenharmony_ci * 169cb93a386Sopenharmony_ci * Since: 0.9.10 170cb93a386Sopenharmony_ci */ 171cb93a386Sopenharmony_cigr_face * 172cb93a386Sopenharmony_cihb_graphite2_face_get_gr_face (hb_face_t *face) 173cb93a386Sopenharmony_ci{ 174cb93a386Sopenharmony_ci const hb_graphite2_face_data_t *data = face->data.graphite2; 175cb93a386Sopenharmony_ci return data ? data->grface : nullptr; 176cb93a386Sopenharmony_ci} 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_ci/* 180cb93a386Sopenharmony_ci * shaper font data 181cb93a386Sopenharmony_ci */ 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_cistruct hb_graphite2_font_data_t {}; 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_cihb_graphite2_font_data_t * 186cb93a386Sopenharmony_ci_hb_graphite2_shaper_font_data_create (hb_font_t *font HB_UNUSED) 187cb93a386Sopenharmony_ci{ 188cb93a386Sopenharmony_ci return (hb_graphite2_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; 189cb93a386Sopenharmony_ci} 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_civoid 192cb93a386Sopenharmony_ci_hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED) 193cb93a386Sopenharmony_ci{ 194cb93a386Sopenharmony_ci} 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci#ifndef HB_DISABLE_DEPRECATED 197cb93a386Sopenharmony_ci/** 198cb93a386Sopenharmony_ci * hb_graphite2_font_get_gr_font: 199cb93a386Sopenharmony_ci * @font: An #hb_font_t 200cb93a386Sopenharmony_ci * 201cb93a386Sopenharmony_ci * Always returns %NULL. Use hb_graphite2_face_get_gr_face() instead. 202cb93a386Sopenharmony_ci * 203cb93a386Sopenharmony_ci * Return value: (nullable): Graphite2 font associated with @font. 204cb93a386Sopenharmony_ci * 205cb93a386Sopenharmony_ci * Since: 0.9.10 206cb93a386Sopenharmony_ci * Deprecated: 1.4.2 207cb93a386Sopenharmony_ci */ 208cb93a386Sopenharmony_cigr_font * 209cb93a386Sopenharmony_cihb_graphite2_font_get_gr_font (hb_font_t *font HB_UNUSED) 210cb93a386Sopenharmony_ci{ 211cb93a386Sopenharmony_ci return nullptr; 212cb93a386Sopenharmony_ci} 213cb93a386Sopenharmony_ci#endif 214cb93a386Sopenharmony_ci 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci/* 217cb93a386Sopenharmony_ci * shaper 218cb93a386Sopenharmony_ci */ 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_cistruct hb_graphite2_cluster_t { 221cb93a386Sopenharmony_ci unsigned int base_char; 222cb93a386Sopenharmony_ci unsigned int num_chars; 223cb93a386Sopenharmony_ci unsigned int base_glyph; 224cb93a386Sopenharmony_ci unsigned int num_glyphs; 225cb93a386Sopenharmony_ci unsigned int cluster; 226cb93a386Sopenharmony_ci unsigned int advance; 227cb93a386Sopenharmony_ci}; 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_cihb_bool_t 230cb93a386Sopenharmony_ci_hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, 231cb93a386Sopenharmony_ci hb_font_t *font, 232cb93a386Sopenharmony_ci hb_buffer_t *buffer, 233cb93a386Sopenharmony_ci const hb_feature_t *features, 234cb93a386Sopenharmony_ci unsigned int num_features) 235cb93a386Sopenharmony_ci{ 236cb93a386Sopenharmony_ci hb_face_t *face = font->face; 237cb93a386Sopenharmony_ci gr_face *grface = face->data.graphite2->grface; 238cb93a386Sopenharmony_ci 239cb93a386Sopenharmony_ci const char *lang = hb_language_to_string (hb_buffer_get_language (buffer)); 240cb93a386Sopenharmony_ci const char *lang_end = lang ? strchr (lang, '-') : nullptr; 241cb93a386Sopenharmony_ci int lang_len = lang_end ? lang_end - lang : -1; 242cb93a386Sopenharmony_ci gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0); 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci for (unsigned int i = 0; i < num_features; i++) 245cb93a386Sopenharmony_ci { 246cb93a386Sopenharmony_ci const gr_feature_ref *fref = gr_face_find_fref (grface, features[i].tag); 247cb93a386Sopenharmony_ci if (fref) 248cb93a386Sopenharmony_ci gr_fref_set_feature_value (fref, features[i].value, feats); 249cb93a386Sopenharmony_ci } 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci gr_segment *seg = nullptr; 252cb93a386Sopenharmony_ci const gr_slot *is; 253cb93a386Sopenharmony_ci unsigned int ci = 0, ic = 0; 254cb93a386Sopenharmony_ci unsigned int curradvx = 0, curradvy = 0; 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci unsigned int scratch_size; 257cb93a386Sopenharmony_ci hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_ci uint32_t *chars = (uint32_t *) scratch; 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ci for (unsigned int i = 0; i < buffer->len; ++i) 262cb93a386Sopenharmony_ci chars[i] = buffer->info[i].codepoint; 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ci /* TODO ensure_native_direction. */ 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ci hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT]; 267cb93a386Sopenharmony_ci unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT; 268cb93a386Sopenharmony_ci hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer), 269cb93a386Sopenharmony_ci HB_LANGUAGE_INVALID, 270cb93a386Sopenharmony_ci &count, 271cb93a386Sopenharmony_ci script_tag, 272cb93a386Sopenharmony_ci nullptr, nullptr); 273cb93a386Sopenharmony_ci 274cb93a386Sopenharmony_ci seg = gr_make_seg (nullptr, grface, 275cb93a386Sopenharmony_ci count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT, 276cb93a386Sopenharmony_ci feats, 277cb93a386Sopenharmony_ci gr_utf32, chars, buffer->len, 278cb93a386Sopenharmony_ci 2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0)); 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_ci if (unlikely (!seg)) { 281cb93a386Sopenharmony_ci if (feats) gr_featureval_destroy (feats); 282cb93a386Sopenharmony_ci return false; 283cb93a386Sopenharmony_ci } 284cb93a386Sopenharmony_ci 285cb93a386Sopenharmony_ci unsigned int glyph_count = gr_seg_n_slots (seg); 286cb93a386Sopenharmony_ci if (unlikely (!glyph_count)) { 287cb93a386Sopenharmony_ci if (feats) gr_featureval_destroy (feats); 288cb93a386Sopenharmony_ci gr_seg_destroy (seg); 289cb93a386Sopenharmony_ci buffer->len = 0; 290cb93a386Sopenharmony_ci return true; 291cb93a386Sopenharmony_ci } 292cb93a386Sopenharmony_ci 293cb93a386Sopenharmony_ci (void) buffer->ensure (glyph_count); 294cb93a386Sopenharmony_ci scratch = buffer->get_scratch_buffer (&scratch_size); 295cb93a386Sopenharmony_ci while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) + 296cb93a386Sopenharmony_ci DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size) 297cb93a386Sopenharmony_ci { 298cb93a386Sopenharmony_ci if (unlikely (!buffer->ensure (buffer->allocated * 2))) 299cb93a386Sopenharmony_ci { 300cb93a386Sopenharmony_ci if (feats) gr_featureval_destroy (feats); 301cb93a386Sopenharmony_ci gr_seg_destroy (seg); 302cb93a386Sopenharmony_ci return false; 303cb93a386Sopenharmony_ci } 304cb93a386Sopenharmony_ci scratch = buffer->get_scratch_buffer (&scratch_size); 305cb93a386Sopenharmony_ci } 306cb93a386Sopenharmony_ci 307cb93a386Sopenharmony_ci#define ALLOCATE_ARRAY(Type, name, len) \ 308cb93a386Sopenharmony_ci Type *name = (Type *) scratch; \ 309cb93a386Sopenharmony_ci do { \ 310cb93a386Sopenharmony_ci unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ 311cb93a386Sopenharmony_ci assert (_consumed <= scratch_size); \ 312cb93a386Sopenharmony_ci scratch += _consumed; \ 313cb93a386Sopenharmony_ci scratch_size -= _consumed; \ 314cb93a386Sopenharmony_ci } while (0) 315cb93a386Sopenharmony_ci 316cb93a386Sopenharmony_ci ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len); 317cb93a386Sopenharmony_ci ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count); 318cb93a386Sopenharmony_ci 319cb93a386Sopenharmony_ci#undef ALLOCATE_ARRAY 320cb93a386Sopenharmony_ci 321cb93a386Sopenharmony_ci memset (clusters, 0, sizeof (clusters[0]) * buffer->len); 322cb93a386Sopenharmony_ci 323cb93a386Sopenharmony_ci hb_codepoint_t *pg = gids; 324cb93a386Sopenharmony_ci clusters[0].cluster = buffer->info[0].cluster; 325cb93a386Sopenharmony_ci unsigned int upem = hb_face_get_upem (face); 326cb93a386Sopenharmony_ci float xscale = (float) font->x_scale / upem; 327cb93a386Sopenharmony_ci float yscale = (float) font->y_scale / upem; 328cb93a386Sopenharmony_ci yscale *= yscale / xscale; 329cb93a386Sopenharmony_ci unsigned int curradv = 0; 330cb93a386Sopenharmony_ci if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) 331cb93a386Sopenharmony_ci { 332cb93a386Sopenharmony_ci curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale; 333cb93a386Sopenharmony_ci clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv; 334cb93a386Sopenharmony_ci } 335cb93a386Sopenharmony_ci else 336cb93a386Sopenharmony_ci clusters[0].advance = 0; 337cb93a386Sopenharmony_ci for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++) 338cb93a386Sopenharmony_ci { 339cb93a386Sopenharmony_ci unsigned int before = gr_slot_before (is); 340cb93a386Sopenharmony_ci unsigned int after = gr_slot_after (is); 341cb93a386Sopenharmony_ci *pg = gr_slot_gid (is); 342cb93a386Sopenharmony_ci pg++; 343cb93a386Sopenharmony_ci while (clusters[ci].base_char > before && ci) 344cb93a386Sopenharmony_ci { 345cb93a386Sopenharmony_ci clusters[ci-1].num_chars += clusters[ci].num_chars; 346cb93a386Sopenharmony_ci clusters[ci-1].num_glyphs += clusters[ci].num_glyphs; 347cb93a386Sopenharmony_ci clusters[ci-1].advance += clusters[ci].advance; 348cb93a386Sopenharmony_ci ci--; 349cb93a386Sopenharmony_ci } 350cb93a386Sopenharmony_ci 351cb93a386Sopenharmony_ci if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars) 352cb93a386Sopenharmony_ci { 353cb93a386Sopenharmony_ci hb_graphite2_cluster_t *c = clusters + ci + 1; 354cb93a386Sopenharmony_ci c->base_char = clusters[ci].base_char + clusters[ci].num_chars; 355cb93a386Sopenharmony_ci c->cluster = buffer->info[c->base_char].cluster; 356cb93a386Sopenharmony_ci c->num_chars = before - c->base_char; 357cb93a386Sopenharmony_ci c->base_glyph = ic; 358cb93a386Sopenharmony_ci c->num_glyphs = 0; 359cb93a386Sopenharmony_ci if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) 360cb93a386Sopenharmony_ci { 361cb93a386Sopenharmony_ci c->advance = curradv - gr_slot_origin_X(is) * xscale; 362cb93a386Sopenharmony_ci curradv -= c->advance; 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci else 365cb93a386Sopenharmony_ci { 366cb93a386Sopenharmony_ci c->advance = 0; 367cb93a386Sopenharmony_ci clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv; 368cb93a386Sopenharmony_ci curradv += clusters[ci].advance; 369cb93a386Sopenharmony_ci } 370cb93a386Sopenharmony_ci ci++; 371cb93a386Sopenharmony_ci } 372cb93a386Sopenharmony_ci clusters[ci].num_glyphs++; 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_ci if (clusters[ci].base_char + clusters[ci].num_chars < after + 1) 375cb93a386Sopenharmony_ci clusters[ci].num_chars = after + 1 - clusters[ci].base_char; 376cb93a386Sopenharmony_ci } 377cb93a386Sopenharmony_ci 378cb93a386Sopenharmony_ci if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) 379cb93a386Sopenharmony_ci clusters[ci].advance += curradv; 380cb93a386Sopenharmony_ci else 381cb93a386Sopenharmony_ci clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv; 382cb93a386Sopenharmony_ci ci++; 383cb93a386Sopenharmony_ci 384cb93a386Sopenharmony_ci for (unsigned int i = 0; i < ci; ++i) 385cb93a386Sopenharmony_ci { 386cb93a386Sopenharmony_ci for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j) 387cb93a386Sopenharmony_ci { 388cb93a386Sopenharmony_ci hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j]; 389cb93a386Sopenharmony_ci info->codepoint = gids[clusters[i].base_glyph + j]; 390cb93a386Sopenharmony_ci info->cluster = clusters[i].cluster; 391cb93a386Sopenharmony_ci info->var1.i32 = clusters[i].advance; // all glyphs in the cluster get the same advance 392cb93a386Sopenharmony_ci } 393cb93a386Sopenharmony_ci } 394cb93a386Sopenharmony_ci buffer->len = glyph_count; 395cb93a386Sopenharmony_ci 396cb93a386Sopenharmony_ci /* Positioning. */ 397cb93a386Sopenharmony_ci unsigned int currclus = UINT_MAX; 398cb93a386Sopenharmony_ci const hb_glyph_info_t *info = buffer->info; 399cb93a386Sopenharmony_ci hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr); 400cb93a386Sopenharmony_ci if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) 401cb93a386Sopenharmony_ci { 402cb93a386Sopenharmony_ci curradvx = 0; 403cb93a386Sopenharmony_ci for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is)) 404cb93a386Sopenharmony_ci { 405cb93a386Sopenharmony_ci pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx; 406cb93a386Sopenharmony_ci pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy; 407cb93a386Sopenharmony_ci if (info->cluster != currclus) { 408cb93a386Sopenharmony_ci pPos->x_advance = info->var1.i32; 409cb93a386Sopenharmony_ci curradvx += pPos->x_advance; 410cb93a386Sopenharmony_ci currclus = info->cluster; 411cb93a386Sopenharmony_ci } else 412cb93a386Sopenharmony_ci pPos->x_advance = 0.; 413cb93a386Sopenharmony_ci 414cb93a386Sopenharmony_ci pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale; 415cb93a386Sopenharmony_ci curradvy += pPos->y_advance; 416cb93a386Sopenharmony_ci } 417cb93a386Sopenharmony_ci } 418cb93a386Sopenharmony_ci else 419cb93a386Sopenharmony_ci { 420cb93a386Sopenharmony_ci curradvx = gr_seg_advance_X(seg) * xscale; 421cb93a386Sopenharmony_ci for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is)) 422cb93a386Sopenharmony_ci { 423cb93a386Sopenharmony_ci if (info->cluster != currclus) 424cb93a386Sopenharmony_ci { 425cb93a386Sopenharmony_ci pPos->x_advance = info->var1.i32; 426cb93a386Sopenharmony_ci curradvx -= pPos->x_advance; 427cb93a386Sopenharmony_ci currclus = info->cluster; 428cb93a386Sopenharmony_ci } else 429cb93a386Sopenharmony_ci pPos->x_advance = 0.; 430cb93a386Sopenharmony_ci 431cb93a386Sopenharmony_ci pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale; 432cb93a386Sopenharmony_ci curradvy -= pPos->y_advance; 433cb93a386Sopenharmony_ci pPos->x_offset = gr_slot_origin_X (is) * xscale - info->var1.i32 - curradvx + pPos->x_advance; 434cb93a386Sopenharmony_ci pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy; 435cb93a386Sopenharmony_ci } 436cb93a386Sopenharmony_ci hb_buffer_reverse_clusters (buffer); 437cb93a386Sopenharmony_ci } 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci if (feats) gr_featureval_destroy (feats); 440cb93a386Sopenharmony_ci gr_seg_destroy (seg); 441cb93a386Sopenharmony_ci 442cb93a386Sopenharmony_ci buffer->unsafe_to_break_all (); 443cb93a386Sopenharmony_ci 444cb93a386Sopenharmony_ci return true; 445cb93a386Sopenharmony_ci} 446cb93a386Sopenharmony_ci 447cb93a386Sopenharmony_ci 448cb93a386Sopenharmony_ci#endif 449