Path: blob/master/thirdparty/harfbuzz/src/hb-buffer.cc
20956 views
/*1* Copyright © 1998-2004 David Turner and Werner Lemberg2* Copyright © 2004,2007,2009,2010 Red Hat, Inc.3* Copyright © 2011,2012 Google, Inc.4*5* This is part of HarfBuzz, a text shaping library.6*7* Permission is hereby granted, without written agreement and without8* license or royalty fees, to use, copy, modify, and distribute this9* software and its documentation for any purpose, provided that the10* above copyright notice and the following two paragraphs appear in11* all copies of this software.12*13* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR14* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES15* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN16* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH17* DAMAGE.18*19* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,20* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND21* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS22* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO23* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.24*25* Red Hat Author(s): Owen Taylor, Behdad Esfahbod26* Google Author(s): Behdad Esfahbod27*/2829#include "hb-buffer.hh"30#include "hb-utf.hh"313233/**34* SECTION: hb-buffer35* @title: hb-buffer36* @short_description: Input and output buffers37* @include: hb.h38*39* Buffers serve a dual role in HarfBuzz; before shaping, they hold40* the input characters that are passed to hb_shape(), and after41* shaping they hold the output glyphs.42*43* The input buffer is a sequence of Unicode codepoints, with44* associated attributes such as direction and script. The output45* buffer is a sequence of glyphs, with associated attributes such46* as position and cluster.47**/484950/**51* hb_segment_properties_equal:52* @a: first #hb_segment_properties_t to compare.53* @b: second #hb_segment_properties_t to compare.54*55* Checks the equality of two #hb_segment_properties_t's.56*57* Return value:58* `true` if all properties of @a equal those of @b, `false` otherwise.59*60* Since: 0.9.761**/62hb_bool_t63hb_segment_properties_equal (const hb_segment_properties_t *a,64const hb_segment_properties_t *b)65{66return a->direction == b->direction &&67a->script == b->script &&68a->language == b->language &&69a->reserved1 == b->reserved1 &&70a->reserved2 == b->reserved2;7172}7374/**75* hb_segment_properties_hash:76* @p: #hb_segment_properties_t to hash.77*78* Creates a hash representing @p.79*80* Return value:81* A hash of @p.82*83* Since: 0.9.784**/85unsigned int86hb_segment_properties_hash (const hb_segment_properties_t *p)87{88return ((unsigned int) p->direction * 31 +89(unsigned int) p->script) * 31 +90(intptr_t) (p->language);91}9293/**94* hb_segment_properties_overlay:95* @p: #hb_segment_properties_t to fill in.96* @src: #hb_segment_properties_t to fill in from.97*98* Fills in missing fields of @p from @src in a considered manner.99*100* First, if @p does not have direction set, direction is copied from @src.101*102* Next, if @p and @src have the same direction (which can be unset), if @p103* does not have script set, script is copied from @src.104*105* Finally, if @p and @src have the same direction and script (which either106* can be unset), if @p does not have language set, language is copied from107* @src.108*109* Since: 3.3.0110**/111void112hb_segment_properties_overlay (hb_segment_properties_t *p,113const hb_segment_properties_t *src)114{115if (unlikely (!p || !src))116return;117118if (!p->direction)119p->direction = src->direction;120121if (p->direction != src->direction)122return;123124if (!p->script)125p->script = src->script;126127if (p->script != src->script)128return;129130if (!p->language)131p->language = src->language;132}133134/* Here is how the buffer works internally:135*136* There are two info pointers: info and out_info. They always have137* the same allocated size, but different lengths.138*139* As an optimization, both info and out_info may point to the140* same piece of memory, which is owned by info. This remains the141* case as long as out_len doesn't exceed i at any time.142* In that case, sync() is mostly no-op and the glyph operations143* operate mostly in-place.144*145* As soon as out_info gets longer than info, out_info is moved over146* to an alternate buffer (which we reuse the pos buffer for), and its147* current contents (out_len entries) are copied to the new place.148*149* This should all remain transparent to the user. sync() then150* switches info over to out_info and does housekeeping.151*/152153154155/* Internal API */156157bool158hb_buffer_t::enlarge (unsigned int size)159{160if (unlikely (size > max_len))161{162successful = false;163return false;164}165166if (unlikely (!successful))167return false;168169unsigned int new_allocated = allocated;170hb_glyph_position_t *new_pos = nullptr;171hb_glyph_info_t *new_info = nullptr;172bool separate_out = out_info != info;173174if (unlikely (hb_unsigned_mul_overflows (size, sizeof (info[0]))))175goto done;176177while (size >= new_allocated)178new_allocated += (new_allocated >> 1) + 32;179180unsigned new_bytes;181if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]), &new_bytes)))182goto done;183184static_assert (sizeof (info[0]) == sizeof (pos[0]), "");185new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_bytes);186new_info = (hb_glyph_info_t *) hb_realloc (info, new_bytes);187188done:189if (unlikely (!new_pos || !new_info))190successful = false;191192if (likely (new_pos))193pos = new_pos;194195if (likely (new_info))196info = new_info;197198out_info = separate_out ? (hb_glyph_info_t *) pos : info;199if (likely (successful))200allocated = new_allocated;201202return likely (successful);203}204205bool206hb_buffer_t::make_room_for (unsigned int num_in,207unsigned int num_out)208{209if (unlikely (!ensure (out_len + num_out))) return false;210211if (out_info == info &&212out_len + num_out > idx + num_in)213{214assert (have_output);215216out_info = (hb_glyph_info_t *) pos;217hb_memcpy (out_info, info, out_len * sizeof (out_info[0]));218}219220return true;221}222223bool224hb_buffer_t::shift_forward (unsigned int count)225{226assert (have_output);227if (unlikely (!ensure (len + count))) return false;228229max_ops -= len - idx;230if (unlikely (max_ops < 0))231{232successful = false;233return false;234}235236memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));237if (idx + count > len)238{239/* Under memory failure we might expose this area. At least240* clean it up. Oh well...241*242* Ideally, we should at least set Default_Ignorable bits on243* these, as well as consistent cluster values. But the former244* is layering violation... */245hb_memset (info + len, 0, (idx + count - len) * sizeof (info[0]));246}247len += count;248idx += count;249250return true;251}252253hb_buffer_t::scratch_buffer_t *254hb_buffer_t::get_scratch_buffer (unsigned int *size)255{256have_output = false;257have_positions = false;258259out_len = 0;260out_info = info;261262assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);263*size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);264return (scratch_buffer_t *) (void *) pos;265}266267268269/* HarfBuzz-Internal API */270271void272hb_buffer_t::similar (const hb_buffer_t &src)273{274hb_unicode_funcs_destroy (unicode);275unicode = hb_unicode_funcs_reference (src.unicode);276flags = src.flags;277cluster_level = src.cluster_level;278replacement = src.replacement;279invisible = src.invisible;280not_found = src.not_found;281not_found_variation_selector = src.not_found_variation_selector;282}283284void285hb_buffer_t::reset ()286{287hb_unicode_funcs_destroy (unicode);288unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());289flags = HB_BUFFER_FLAG_DEFAULT;290cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;291replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;292invisible = 0;293not_found = 0;294not_found_variation_selector = HB_CODEPOINT_INVALID;295296clear ();297}298299void300hb_buffer_t::clear ()301{302content_type = HB_BUFFER_CONTENT_TYPE_INVALID;303hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;304props = default_props;305306successful = true;307have_output = false;308have_positions = false;309310idx = 0;311len = 0;312out_len = 0;313out_info = info;314315hb_memset (context, 0, sizeof context);316hb_memset (context_len, 0, sizeof context_len);317318deallocate_var_all ();319serial = 0;320random_state = 1;321scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;322}323324void325hb_buffer_t::enter ()326{327deallocate_var_all ();328serial = 0;329scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;330unsigned mul;331if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul)))332{333max_len = hb_max (mul, (unsigned) HB_BUFFER_MAX_LEN_MIN);334}335if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR, &mul)))336{337max_ops = hb_max (mul, (unsigned) HB_BUFFER_MAX_OPS_MIN);338}339}340void341hb_buffer_t::leave ()342{343max_len = HB_BUFFER_MAX_LEN_DEFAULT;344max_ops = HB_BUFFER_MAX_OPS_DEFAULT;345deallocate_var_all ();346serial = 0;347}348349350void351hb_buffer_t::add (hb_codepoint_t codepoint,352unsigned int cluster)353{354hb_glyph_info_t *glyph;355356if (unlikely (!ensure (len + 1))) return;357358glyph = &info[len];359360hb_memset (glyph, 0, sizeof (*glyph));361glyph->codepoint = codepoint;362glyph->mask = 0;363glyph->cluster = cluster;364365len++;366}367368void369hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)370{371if (unlikely (!ensure (len + 1))) return;372373info[len] = glyph_info;374375len++;376}377void378hb_buffer_t::add_info_and_pos (const hb_glyph_info_t &glyph_info,379const hb_glyph_position_t &glyph_pos)380{381if (unlikely (!ensure (len + 1))) return;382383info[len] = glyph_info;384assert (have_positions);385pos[len] = glyph_pos;386387len++;388}389390391void392hb_buffer_t::clear_output ()393{394have_output = true;395have_positions = false;396397idx = 0;398out_len = 0;399out_info = info;400}401402void403hb_buffer_t::clear_positions ()404{405have_output = false;406have_positions = true;407408out_len = 0;409out_info = info;410411hb_memset (pos, 0, sizeof (pos[0]) * len);412}413414bool415hb_buffer_t::sync ()416{417bool ret = false;418419assert (have_output);420421assert (idx <= len);422423if (unlikely (!successful || !next_glyphs (len - idx)))424goto reset;425426if (out_info != info)427{428pos = (hb_glyph_position_t *) info;429info = out_info;430}431len = out_len;432ret = true;433434reset:435have_output = false;436out_len = 0;437out_info = info;438idx = 0;439440return ret;441}442443int444hb_buffer_t::sync_so_far ()445{446bool had_output = have_output;447unsigned out_i = out_len;448unsigned i = idx;449unsigned old_idx = idx;450451if (sync ())452idx = out_i;453else454idx = i;455456if (had_output)457{458have_output = true;459out_len = idx;460}461462assert (idx <= len);463464return idx - old_idx;465}466467bool468hb_buffer_t::move_to (unsigned int i)469{470if (!have_output)471{472assert (i <= len);473idx = i;474return true;475}476if (unlikely (!successful))477return false;478479assert (i <= out_len + (len - idx));480481if (out_len < i)482{483unsigned int count = i - out_len;484if (unlikely (!make_room_for (count, count))) return false;485486memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));487idx += count;488out_len += count;489}490else if (out_len > i)491{492/* Tricky part: rewinding... */493unsigned int count = out_len - i;494495/* This will blow in our face if memory allocation fails later496* in this same lookup...497*498* We used to shift with extra 32 items.499* But that would leave empty slots in the buffer in case of allocation500* failures. See comments in shift_forward(). This can cause O(N^2)501* behavior more severely than adding 32 empty slots can... */502if (unlikely (idx < count && !shift_forward (count - idx))) return false;503504assert (idx >= count);505506idx -= count;507out_len -= count;508memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));509}510511return true;512}513514515void516hb_buffer_t::set_masks (hb_mask_t value,517hb_mask_t mask,518unsigned int cluster_start,519unsigned int cluster_end)520{521if (!mask)522return;523524hb_mask_t not_mask = ~mask;525value &= mask;526527max_ops -= len;528if (unlikely (max_ops < 0))529successful = false;530531unsigned int count = len;532533if (cluster_start == 0 && cluster_end == (unsigned int) -1)534{535for (unsigned int i = 0; i < count; i++)536info[i].mask = (info[i].mask & not_mask) | value;537return;538}539540for (unsigned int i = 0; i < count; i++)541if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)542info[i].mask = (info[i].mask & not_mask) | value;543}544545void546hb_buffer_t::merge_clusters_impl (unsigned int start,547unsigned int end)548{549if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))550{551unsafe_to_break (start, end);552return;553}554555max_ops -= end - start;556if (unlikely (max_ops < 0))557successful = false;558559unsigned int cluster = info[start].cluster;560561for (unsigned int i = start + 1; i < end; i++)562cluster = hb_min (cluster, info[i].cluster);563564/* Extend end */565if (cluster != info[end - 1].cluster)566while (end < len && info[end - 1].cluster == info[end].cluster)567end++;568569/* Extend start */570if (cluster != info[start].cluster)571while (idx < start && info[start - 1].cluster == info[start].cluster)572start--;573574/* If we hit the start of buffer, continue in out-buffer. */575if (idx == start && info[start].cluster != cluster)576for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)577set_cluster (out_info[i - 1], cluster);578579for (unsigned int i = start; i < end; i++)580set_cluster (info[i], cluster);581}582void583hb_buffer_t::merge_out_clusters (unsigned int start,584unsigned int end)585{586if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))587return;588589if (unlikely (end - start < 2))590return;591592max_ops -= end - start;593if (unlikely (max_ops < 0))594successful = false;595596unsigned int cluster = out_info[start].cluster;597598for (unsigned int i = start + 1; i < end; i++)599cluster = hb_min (cluster, out_info[i].cluster);600601/* Extend start */602while (start && out_info[start - 1].cluster == out_info[start].cluster)603start--;604605/* Extend end */606while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)607end++;608609/* If we hit the end of out-buffer, continue in buffer. */610if (end == out_len)611for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)612set_cluster (info[i], cluster);613614for (unsigned int i = start; i < end; i++)615set_cluster (out_info[i], cluster);616}617void618hb_buffer_t::delete_glyph ()619{620/* The logic here is duplicated in hb_ot_hide_default_ignorables(). */621622unsigned int cluster = info[idx].cluster;623if ((idx + 1 < len && cluster == info[idx + 1].cluster) ||624(out_len && cluster == out_info[out_len - 1].cluster))625{626/* Cluster survives; do nothing. */627goto done;628}629630if (out_len)631{632/* Merge cluster backward. */633if (cluster < out_info[out_len - 1].cluster)634{635unsigned int mask = info[idx].mask;636unsigned int old_cluster = out_info[out_len - 1].cluster;637for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)638set_cluster (out_info[i - 1], cluster, mask);639}640goto done;641}642643if (idx + 1 < len)644{645/* Merge cluster forward. */646merge_clusters (idx, idx + 2);647goto done;648}649650done:651skip_glyph ();652}653654void655hb_buffer_t::delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info))656{657/* Merge clusters and delete filtered glyphs.658* NOTE! We can't use out-buffer as we have positioning data. */659unsigned int j = 0;660unsigned int count = len;661for (unsigned int i = 0; i < count; i++)662{663if (filter (&info[i]))664{665/* Merge clusters.666* Same logic as delete_glyph(), but for in-place removal. */667668unsigned int cluster = info[i].cluster;669if (i + 1 < count && cluster == info[i + 1].cluster)670continue; /* Cluster survives; do nothing. */671672if (j)673{674/* Merge cluster backward. */675if (cluster < info[j - 1].cluster)676{677unsigned int mask = info[i].mask;678unsigned int old_cluster = info[j - 1].cluster;679for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)680set_cluster (info[k - 1], cluster, mask);681}682continue;683}684685if (i + 1 < count)686merge_clusters (i, i + 2); /* Merge cluster forward. */687688continue;689}690691if (j != i)692{693info[j] = info[i];694pos[j] = pos[i];695}696j++;697}698len = j;699}700701void702hb_buffer_t::guess_segment_properties ()703{704assert_unicode ();705706/* If script is set to INVALID, guess from buffer contents */707if (props.script == HB_SCRIPT_INVALID) {708for (unsigned int i = 0; i < len; i++) {709hb_script_t script = unicode->script (info[i].codepoint);710if (likely (script != HB_SCRIPT_COMMON &&711script != HB_SCRIPT_INHERITED &&712script != HB_SCRIPT_UNKNOWN)) {713props.script = script;714break;715}716}717}718719/* If direction is set to INVALID, guess from script */720if (props.direction == HB_DIRECTION_INVALID) {721props.direction = hb_script_get_horizontal_direction (props.script);722if (props.direction == HB_DIRECTION_INVALID)723props.direction = HB_DIRECTION_LTR;724}725726/* If language is not set, use default language from locale */727if (props.language == HB_LANGUAGE_INVALID) {728/* TODO get_default_for_script? using $LANGUAGE */729props.language = hb_language_get_default ();730}731}732733734/* Public API */735736DEFINE_NULL_INSTANCE (hb_buffer_t) =737{738HB_OBJECT_HEADER_STATIC,739740const_cast<hb_unicode_funcs_t *> (&_hb_Null_hb_unicode_funcs_t),741HB_BUFFER_FLAG_DEFAULT,742HB_BUFFER_CLUSTER_LEVEL_DEFAULT,743HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,7440, /* invisible */7450, /* not_found */746HB_CODEPOINT_INVALID, /* not_found_variation_selector */747748749HB_BUFFER_CONTENT_TYPE_INVALID,750HB_SEGMENT_PROPERTIES_DEFAULT,751752false, /* successful */753false, /* have_output */754true /* have_positions */755756/* Zero is good enough for everything else. */757};758759760/**761* hb_buffer_create:762*763* Creates a new #hb_buffer_t with all properties to defaults.764*765* Return value: (transfer full):766* A newly allocated #hb_buffer_t with a reference count of 1. The initial767* reference count should be released with hb_buffer_destroy() when you are done768* using the #hb_buffer_t. This function never returns `NULL`. If memory cannot769* be allocated, a special #hb_buffer_t object will be returned on which770* hb_buffer_allocation_successful() returns `false`.771*772* Since: 0.9.2773**/774hb_buffer_t *775hb_buffer_create ()776{777hb_buffer_t *buffer;778779if (!(buffer = hb_object_create<hb_buffer_t> ()))780return hb_buffer_get_empty ();781782buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;783buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;784785buffer->reset ();786787return buffer;788}789790/**791* hb_buffer_create_similar:792* @src: An #hb_buffer_t793*794* Creates a new #hb_buffer_t, similar to hb_buffer_create(). The only795* difference is that the buffer is configured similarly to @src.796*797* Return value: (transfer full):798* A newly allocated #hb_buffer_t, similar to hb_buffer_create().799*800* Since: 3.3.0801**/802hb_buffer_t *803hb_buffer_create_similar (const hb_buffer_t *src)804{805hb_buffer_t *buffer = hb_buffer_create ();806807buffer->similar (*src);808809return buffer;810}811812/**813* hb_buffer_reset:814* @buffer: An #hb_buffer_t815*816* Resets the buffer to its initial status, as if it was just newly created817* with hb_buffer_create().818*819* Since: 0.9.2820**/821void822hb_buffer_reset (hb_buffer_t *buffer)823{824if (unlikely (hb_object_is_immutable (buffer)))825return;826827buffer->reset ();828}829830/**831* hb_buffer_get_empty:832*833* Fetches an empty #hb_buffer_t.834*835* Return value: (transfer full): The empty buffer836*837* Since: 0.9.2838**/839hb_buffer_t *840hb_buffer_get_empty ()841{842return const_cast<hb_buffer_t *> (&Null (hb_buffer_t));843}844845/**846* hb_buffer_reference: (skip)847* @buffer: An #hb_buffer_t848*849* Increases the reference count on @buffer by one. This prevents @buffer from850* being destroyed until a matching call to hb_buffer_destroy() is made.851*852* Return value: (transfer full):853* The referenced #hb_buffer_t.854*855* Since: 0.9.2856**/857hb_buffer_t *858hb_buffer_reference (hb_buffer_t *buffer)859{860return hb_object_reference (buffer);861}862863/**864* hb_buffer_destroy: (skip)865* @buffer: An #hb_buffer_t866*867* Deallocate the @buffer.868* Decreases the reference count on @buffer by one. If the result is zero, then869* @buffer and all associated resources are freed. See hb_buffer_reference().870*871* Since: 0.9.2872**/873void874hb_buffer_destroy (hb_buffer_t *buffer)875{876if (!hb_object_destroy (buffer)) return;877878hb_unicode_funcs_destroy (buffer->unicode);879880hb_free (buffer->info);881hb_free (buffer->pos);882#ifndef HB_NO_BUFFER_MESSAGE883if (buffer->message_destroy)884buffer->message_destroy (buffer->message_data);885#endif886887hb_free (buffer);888}889890/**891* hb_buffer_set_user_data: (skip)892* @buffer: An #hb_buffer_t893* @key: The user-data key894* @data: A pointer to the user data895* @destroy: (nullable): A callback to call when @data is not needed anymore896* @replace: Whether to replace an existing data with the same key897*898* Attaches a user-data key/data pair to the specified buffer.899*900* Return value: `true` if success, `false` otherwise901*902* Since: 0.9.2903**/904hb_bool_t905hb_buffer_set_user_data (hb_buffer_t *buffer,906hb_user_data_key_t *key,907void * data,908hb_destroy_func_t destroy,909hb_bool_t replace)910{911return hb_object_set_user_data (buffer, key, data, destroy, replace);912}913914/**915* hb_buffer_get_user_data: (skip)916* @buffer: An #hb_buffer_t917* @key: The user-data key to query918*919* Fetches the user data associated with the specified key,920* attached to the specified buffer.921*922* Return value: (transfer none): A pointer to the user data923*924* Since: 0.9.2925**/926void *927hb_buffer_get_user_data (const hb_buffer_t *buffer,928hb_user_data_key_t *key)929{930return hb_object_get_user_data (buffer, key);931}932933934/**935* hb_buffer_set_content_type:936* @buffer: An #hb_buffer_t937* @content_type: The type of buffer contents to set938*939* Sets the type of @buffer contents. Buffers are either empty, contain940* characters (before shaping), or contain glyphs (the result of shaping).941*942* You rarely need to call this function, since a number of other943* functions transition the content type for you. Namely:944*945* - A newly created buffer starts with content type946* %HB_BUFFER_CONTENT_TYPE_INVALID. Calling hb_buffer_reset(),947* hb_buffer_clear_contents(), as well as calling hb_buffer_set_length()948* with an argument of zero all set the buffer content type to invalid949* as well.950*951* - Calling hb_buffer_add_utf8(), hb_buffer_add_utf16(),952* hb_buffer_add_utf32(), hb_buffer_add_codepoints() and953* hb_buffer_add_latin1() expect that buffer is either empty and954* have a content type of invalid, or that buffer content type is955* %HB_BUFFER_CONTENT_TYPE_UNICODE, and they also set the content956* type to Unicode if they added anything to an empty buffer.957*958* - Finally hb_shape() and hb_shape_full() expect that the buffer959* is either empty and have content type of invalid, or that buffer960* content type is %HB_BUFFER_CONTENT_TYPE_UNICODE, and upon961* success they set the buffer content type to962* %HB_BUFFER_CONTENT_TYPE_GLYPHS.963*964* The above transitions are designed such that one can use a buffer965* in a loop of "reset : add-text : shape" without needing to ever966* modify the content type manually.967*968* Since: 0.9.5969**/970void971hb_buffer_set_content_type (hb_buffer_t *buffer,972hb_buffer_content_type_t content_type)973{974buffer->content_type = content_type;975}976977/**978* hb_buffer_get_content_type:979* @buffer: An #hb_buffer_t980*981* Fetches the type of @buffer contents. Buffers are either empty, contain982* characters (before shaping), or contain glyphs (the result of shaping).983*984* Return value:985* The type of @buffer contents986*987* Since: 0.9.5988**/989hb_buffer_content_type_t990hb_buffer_get_content_type (const hb_buffer_t *buffer)991{992return buffer->content_type;993}994995996/**997* hb_buffer_set_unicode_funcs:998* @buffer: An #hb_buffer_t999* @unicode_funcs: The Unicode-functions structure1000*1001* Sets the Unicode-functions structure of a buffer to1002* @unicode_funcs.1003*1004* Since: 0.9.21005**/1006void1007hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,1008hb_unicode_funcs_t *unicode_funcs)1009{1010if (unlikely (hb_object_is_immutable (buffer)))1011return;10121013if (!unicode_funcs)1014unicode_funcs = hb_unicode_funcs_get_default ();10151016hb_unicode_funcs_reference (unicode_funcs);1017hb_unicode_funcs_destroy (buffer->unicode);1018buffer->unicode = unicode_funcs;1019}10201021/**1022* hb_buffer_get_unicode_funcs:1023* @buffer: An #hb_buffer_t1024*1025* Fetches the Unicode-functions structure of a buffer.1026*1027* Return value: The Unicode-functions structure1028*1029* Since: 0.9.21030**/1031hb_unicode_funcs_t *1032hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer)1033{1034return buffer->unicode;1035}10361037/**1038* hb_buffer_set_direction:1039* @buffer: An #hb_buffer_t1040* @direction: the #hb_direction_t of the @buffer1041*1042* Set the text flow direction of the buffer. No shaping can happen without1043* setting @buffer direction, and it controls the visual direction for the1044* output glyphs; for RTL direction the glyphs will be reversed. Many layout1045* features depend on the proper setting of the direction, for example,1046* reversing RTL text before shaping, then shaping with LTR direction is not1047* the same as keeping the text in logical order and shaping with RTL1048* direction.1049*1050* Since: 0.9.21051**/1052void1053hb_buffer_set_direction (hb_buffer_t *buffer,1054hb_direction_t direction)1055{1056if (unlikely (hb_object_is_immutable (buffer)))1057return;10581059buffer->props.direction = direction;1060}10611062/**1063* hb_buffer_get_direction:1064* @buffer: An #hb_buffer_t1065*1066* See hb_buffer_set_direction()1067*1068* Return value:1069* The direction of the @buffer.1070*1071* Since: 0.9.21072**/1073hb_direction_t1074hb_buffer_get_direction (const hb_buffer_t *buffer)1075{1076return buffer->props.direction;1077}10781079/**1080* hb_buffer_set_script:1081* @buffer: An #hb_buffer_t1082* @script: An #hb_script_t to set.1083*1084* Sets the script of @buffer to @script.1085*1086* Script is crucial for choosing the proper shaping behaviour for scripts that1087* require it (e.g. Arabic) and the which OpenType features defined in the font1088* to be applied.1089*1090* You can pass one of the predefined #hb_script_t values, or use1091* hb_script_from_string() or hb_script_from_iso15924_tag() to get the1092* corresponding script from an ISO 15924 script tag.1093*1094* Since: 0.9.21095**/1096void1097hb_buffer_set_script (hb_buffer_t *buffer,1098hb_script_t script)1099{1100if (unlikely (hb_object_is_immutable (buffer)))1101return;11021103buffer->props.script = script;1104}11051106/**1107* hb_buffer_get_script:1108* @buffer: An #hb_buffer_t1109*1110* Fetches the script of @buffer.1111*1112* Return value:1113* The #hb_script_t of the @buffer1114*1115* Since: 0.9.21116**/1117hb_script_t1118hb_buffer_get_script (const hb_buffer_t *buffer)1119{1120return buffer->props.script;1121}11221123/**1124* hb_buffer_set_language:1125* @buffer: An #hb_buffer_t1126* @language: An hb_language_t to set1127*1128* Sets the language of @buffer to @language.1129*1130* Languages are crucial for selecting which OpenType feature to apply to the1131* buffer which can result in applying language-specific behaviour. Languages1132* are orthogonal to the scripts, and though they are related, they are1133* different concepts and should not be confused with each other.1134*1135* Use hb_language_from_string() to convert from BCP 47 language tags to1136* #hb_language_t.1137*1138* Since: 0.9.21139**/1140void1141hb_buffer_set_language (hb_buffer_t *buffer,1142hb_language_t language)1143{1144if (unlikely (hb_object_is_immutable (buffer)))1145return;11461147buffer->props.language = language;1148}11491150/**1151* hb_buffer_get_language:1152* @buffer: An #hb_buffer_t1153*1154* See hb_buffer_set_language().1155*1156* Return value: (transfer none):1157* The #hb_language_t of the buffer. Must not be freed by the caller.1158*1159* Since: 0.9.21160**/1161hb_language_t1162hb_buffer_get_language (const hb_buffer_t *buffer)1163{1164return buffer->props.language;1165}11661167/**1168* hb_buffer_set_segment_properties:1169* @buffer: An #hb_buffer_t1170* @props: An #hb_segment_properties_t to use1171*1172* Sets the segment properties of the buffer, a shortcut for calling1173* hb_buffer_set_direction(), hb_buffer_set_script() and1174* hb_buffer_set_language() individually.1175*1176* Since: 0.9.71177**/1178void1179hb_buffer_set_segment_properties (hb_buffer_t *buffer,1180const hb_segment_properties_t *props)1181{1182if (unlikely (hb_object_is_immutable (buffer)))1183return;11841185buffer->props = *props;1186}11871188/**1189* hb_buffer_get_segment_properties:1190* @buffer: An #hb_buffer_t1191* @props: (out): The output #hb_segment_properties_t1192*1193* Sets @props to the #hb_segment_properties_t of @buffer.1194*1195* Since: 0.9.71196**/1197void1198hb_buffer_get_segment_properties (const hb_buffer_t *buffer,1199hb_segment_properties_t *props)1200{1201*props = buffer->props;1202}120312041205/**1206* hb_buffer_set_flags:1207* @buffer: An #hb_buffer_t1208* @flags: The buffer flags to set1209*1210* Sets @buffer flags to @flags. See #hb_buffer_flags_t.1211*1212* Since: 0.9.71213**/1214void1215hb_buffer_set_flags (hb_buffer_t *buffer,1216hb_buffer_flags_t flags)1217{1218if (unlikely (hb_object_is_immutable (buffer)))1219return;12201221buffer->flags = flags;1222}12231224/**1225* hb_buffer_get_flags:1226* @buffer: An #hb_buffer_t1227*1228* Fetches the #hb_buffer_flags_t of @buffer.1229*1230* Return value:1231* The @buffer flags1232*1233* Since: 0.9.71234**/1235hb_buffer_flags_t1236hb_buffer_get_flags (const hb_buffer_t *buffer)1237{1238return buffer->flags;1239}12401241/**1242* hb_buffer_set_cluster_level:1243* @buffer: An #hb_buffer_t1244* @cluster_level: The cluster level to set on the buffer1245*1246* Sets the cluster level of a buffer. The #hb_buffer_cluster_level_t1247* dictates one aspect of how HarfBuzz will treat non-base characters1248* during shaping.1249*1250* Since: 0.9.421251**/1252void1253hb_buffer_set_cluster_level (hb_buffer_t *buffer,1254hb_buffer_cluster_level_t cluster_level)1255{1256if (unlikely (hb_object_is_immutable (buffer)))1257return;12581259buffer->cluster_level = cluster_level;1260}12611262/**1263* hb_buffer_get_cluster_level:1264* @buffer: An #hb_buffer_t1265*1266* Fetches the cluster level of a buffer. The #hb_buffer_cluster_level_t1267* dictates one aspect of how HarfBuzz will treat non-base characters1268* during shaping.1269*1270* Return value: The cluster level of @buffer1271*1272* Since: 0.9.421273**/1274hb_buffer_cluster_level_t1275hb_buffer_get_cluster_level (const hb_buffer_t *buffer)1276{1277return buffer->cluster_level;1278}127912801281/**1282* hb_buffer_set_replacement_codepoint:1283* @buffer: An #hb_buffer_t1284* @replacement: the replacement #hb_codepoint_t1285*1286* Sets the #hb_codepoint_t that replaces invalid entries for a given encoding1287* when adding text to @buffer.1288*1289* Default is #HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.1290*1291* Since: 0.9.311292**/1293void1294hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,1295hb_codepoint_t replacement)1296{1297if (unlikely (hb_object_is_immutable (buffer)))1298return;12991300buffer->replacement = replacement;1301}13021303/**1304* hb_buffer_get_replacement_codepoint:1305* @buffer: An #hb_buffer_t1306*1307* Fetches the #hb_codepoint_t that replaces invalid entries for a given encoding1308* when adding text to @buffer.1309*1310* Return value:1311* The @buffer replacement #hb_codepoint_t1312*1313* Since: 0.9.311314**/1315hb_codepoint_t1316hb_buffer_get_replacement_codepoint (const hb_buffer_t *buffer)1317{1318return buffer->replacement;1319}132013211322/**1323* hb_buffer_set_invisible_glyph:1324* @buffer: An #hb_buffer_t1325* @invisible: the invisible #hb_codepoint_t1326*1327* Sets the #hb_codepoint_t that replaces invisible characters in1328* the shaping result. If set to zero (default), the glyph for the1329* U+0020 SPACE character is used. Otherwise, this value is used1330* verbatim.1331*1332* Since: 2.0.01333**/1334void1335hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,1336hb_codepoint_t invisible)1337{1338if (unlikely (hb_object_is_immutable (buffer)))1339return;13401341buffer->invisible = invisible;1342}13431344/**1345* hb_buffer_get_invisible_glyph:1346* @buffer: An #hb_buffer_t1347*1348* See hb_buffer_set_invisible_glyph().1349*1350* Return value:1351* The @buffer invisible #hb_codepoint_t1352*1353* Since: 2.0.01354**/1355hb_codepoint_t1356hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer)1357{1358return buffer->invisible;1359}13601361/**1362* hb_buffer_set_not_found_glyph:1363* @buffer: An #hb_buffer_t1364* @not_found: the not-found #hb_codepoint_t1365*1366* Sets the #hb_codepoint_t that replaces characters not found in1367* the font during shaping.1368*1369* The not-found glyph defaults to zero, sometimes known as the1370* ".notdef" glyph. This API allows for differentiating the two.1371*1372* Since: 3.1.01373**/1374void1375hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,1376hb_codepoint_t not_found)1377{1378if (unlikely (hb_object_is_immutable (buffer)))1379return;13801381buffer->not_found = not_found;1382}13831384/**1385* hb_buffer_get_not_found_glyph:1386* @buffer: An #hb_buffer_t1387*1388* See hb_buffer_set_not_found_glyph().1389*1390* Return value:1391* The @buffer not-found #hb_codepoint_t1392*1393* Since: 3.1.01394**/1395hb_codepoint_t1396hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)1397{1398return buffer->not_found;1399}14001401/**1402* hb_buffer_set_not_found_variation_selector_glyph:1403* @buffer: An #hb_buffer_t1404* @not_found_variation_selector: the not-found-variation-selector #hb_codepoint_t1405*1406* Sets the #hb_codepoint_t that replaces variation-selector characters not resolved1407* in the font during shaping.1408*1409* The not-found-variation-selector glyph defaults to #HB_CODEPOINT_INVALID,1410* in which case an unresolved variation-selector will be removed from the glyph1411* string during shaping. This API allows for changing that and retaining a glyph,1412* such that the situation can be detected by the client and handled accordingly1413* (e.g. by using a different font).1414*1415* Since: 10.0.01416**/1417void1418hb_buffer_set_not_found_variation_selector_glyph (hb_buffer_t *buffer,1419hb_codepoint_t not_found_variation_selector)1420{1421buffer->not_found_variation_selector = not_found_variation_selector;1422}14231424/**1425* hb_buffer_get_not_found_variation_selector_glyph:1426* @buffer: An #hb_buffer_t1427*1428* See hb_buffer_set_not_found_variation_selector_glyph().1429*1430* Return value:1431* The @buffer not-found-variation-selector #hb_codepoint_t1432*1433* Since: 10.0.01434**/1435hb_codepoint_t1436hb_buffer_get_not_found_variation_selector_glyph (const hb_buffer_t *buffer)1437{1438return buffer->not_found_variation_selector;1439}14401441/**1442* hb_buffer_set_random_state:1443* @buffer: An #hb_buffer_t1444* @state: the new random state1445*1446* Sets the random state of the buffer. The state changes1447* every time a glyph uses randomness (eg. the `rand`1448* OpenType feature). This function together with1449* hb_buffer_get_random_state() allow for transferring1450* the current random state to a subsequent buffer, to1451* get better randomness distribution.1452*1453* Defaults to 1 and when buffer contents are cleared.1454* A value of 0 disables randomness during shaping.1455*1456* Since: 8.4.01457**/1458void1459hb_buffer_set_random_state (hb_buffer_t *buffer,1460unsigned state)1461{1462if (unlikely (hb_object_is_immutable (buffer)))1463return;14641465buffer->random_state = state;1466}14671468/**1469* hb_buffer_get_random_state:1470* @buffer: An #hb_buffer_t1471*1472* See hb_buffer_set_random_state().1473*1474* Return value:1475* The @buffer random state1476*1477* Since: 8.4.01478**/1479unsigned1480hb_buffer_get_random_state (const hb_buffer_t *buffer)1481{1482return buffer->random_state;1483}14841485/**1486* hb_buffer_clear_contents:1487* @buffer: An #hb_buffer_t1488*1489* Similar to hb_buffer_reset(), but does not clear the Unicode functions and1490* the replacement code point.1491*1492* Since: 0.9.111493**/1494void1495hb_buffer_clear_contents (hb_buffer_t *buffer)1496{1497if (unlikely (hb_object_is_immutable (buffer)))1498return;14991500buffer->clear ();1501}15021503/**1504* hb_buffer_pre_allocate:1505* @buffer: An #hb_buffer_t1506* @size: Number of items to pre allocate.1507*1508* Pre allocates memory for @buffer to fit at least @size number of items.1509*1510* Return value:1511* `true` if @buffer memory allocation succeeded, `false` otherwise1512*1513* Since: 0.9.21514**/1515hb_bool_t1516hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)1517{1518return buffer->ensure (size);1519}15201521/**1522* hb_buffer_allocation_successful:1523* @buffer: An #hb_buffer_t1524*1525* Check if allocating memory for the buffer succeeded.1526*1527* Return value:1528* `true` if @buffer memory allocation succeeded, `false` otherwise.1529*1530* Since: 0.9.21531**/1532hb_bool_t1533hb_buffer_allocation_successful (hb_buffer_t *buffer)1534{1535return buffer->successful;1536}15371538/**1539* hb_buffer_add:1540* @buffer: An #hb_buffer_t1541* @codepoint: A Unicode code point.1542* @cluster: The cluster value of @codepoint.1543*1544* Appends a character with the Unicode value of @codepoint to @buffer, and1545* gives it the initial cluster value of @cluster. Clusters can be any thing1546* the client wants, they are usually used to refer to the index of the1547* character in the input text stream and are output in1548* #hb_glyph_info_t.cluster field.1549*1550* This function does not check the validity of @codepoint, it is up to the1551* caller to ensure it is a valid Unicode code point.1552*1553* Since: 0.9.71554**/1555void1556hb_buffer_add (hb_buffer_t *buffer,1557hb_codepoint_t codepoint,1558unsigned int cluster)1559{1560buffer->add (codepoint, cluster);1561buffer->clear_context (1);1562}15631564/**1565* hb_buffer_set_length:1566* @buffer: An #hb_buffer_t1567* @length: The new length of @buffer1568*1569* Similar to hb_buffer_pre_allocate(), but clears any new items added at the1570* end.1571*1572* Return value:1573* `true` if @buffer memory allocation succeeded, `false` otherwise.1574*1575* Since: 0.9.21576**/1577hb_bool_t1578hb_buffer_set_length (hb_buffer_t *buffer,1579unsigned int length)1580{1581if (unlikely (hb_object_is_immutable (buffer)))1582return length == 0;15831584if (unlikely (!buffer->ensure (length)))1585return false;15861587/* Wipe the new space */1588if (length > buffer->len) {1589hb_memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));1590if (buffer->have_positions)1591hb_memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));1592}15931594buffer->len = length;15951596if (!length)1597{1598buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;1599buffer->clear_context (0);1600}1601buffer->clear_context (1);16021603return true;1604}16051606/**1607* hb_buffer_get_length:1608* @buffer: An #hb_buffer_t1609*1610* Returns the number of items in the buffer.1611*1612* Return value:1613* The @buffer length.1614* The value valid as long as buffer has not been modified.1615*1616* Since: 0.9.21617**/1618unsigned int1619hb_buffer_get_length (const hb_buffer_t *buffer)1620{1621return buffer->len;1622}16231624/**1625* hb_buffer_get_glyph_infos:1626* @buffer: An #hb_buffer_t1627* @length: (out): The output-array length.1628*1629* Returns @buffer glyph information array. Returned pointer1630* is valid as long as @buffer contents are not modified.1631*1632* Return value: (transfer none) (array length=length):1633* The @buffer glyph information array.1634* The value valid as long as buffer has not been modified.1635*1636* Since: 0.9.21637**/1638hb_glyph_info_t *1639hb_buffer_get_glyph_infos (hb_buffer_t *buffer,1640unsigned int *length)1641{1642if (length)1643*length = buffer->len;16441645return (hb_glyph_info_t *) buffer->info;1646}16471648/**1649* hb_buffer_get_glyph_positions:1650* @buffer: An #hb_buffer_t1651* @length: (out): The output length1652*1653* Returns @buffer glyph position array. Returned pointer1654* is valid as long as @buffer contents are not modified.1655*1656* If buffer did not have positions before, the positions will be1657* initialized to zeros, unless this function is called from1658* within a buffer message callback (see hb_buffer_set_message_func()),1659* in which case `NULL` is returned.1660*1661* Return value: (transfer none) (array length=length):1662* The @buffer glyph position array.1663* The value valid as long as buffer has not been modified.1664*1665* Since: 0.9.21666**/1667hb_glyph_position_t *1668hb_buffer_get_glyph_positions (hb_buffer_t *buffer,1669unsigned int *length)1670{1671if (length)1672*length = buffer->len;16731674if (!buffer->have_positions)1675{1676if (unlikely (buffer->message_depth))1677return nullptr;16781679buffer->clear_positions ();1680}16811682return (hb_glyph_position_t *) buffer->pos;1683}16841685/**1686* hb_buffer_has_positions:1687* @buffer: an #hb_buffer_t.1688*1689* Returns whether @buffer has glyph position data.1690* A buffer gains position data when hb_buffer_get_glyph_positions() is called on it,1691* and cleared of position data when hb_buffer_clear_contents() is called.1692*1693* Return value:1694* `true` if the @buffer has position array, `false` otherwise.1695*1696* Since: 2.7.31697**/1698HB_EXTERN hb_bool_t1699hb_buffer_has_positions (hb_buffer_t *buffer)1700{1701return buffer->have_positions;1702}17031704/**1705* hb_glyph_info_get_glyph_flags:1706* @info: a #hb_glyph_info_t1707*1708* Returns glyph flags encoded within a #hb_glyph_info_t.1709*1710* Return value:1711* The #hb_glyph_flags_t encoded within @info1712*1713* Since: 1.5.01714**/1715hb_glyph_flags_t1716(hb_glyph_info_get_glyph_flags) (const hb_glyph_info_t *info)1717{1718return hb_glyph_info_get_glyph_flags (info);1719}17201721/**1722* hb_buffer_reverse:1723* @buffer: An #hb_buffer_t1724*1725* Reverses buffer contents.1726*1727* Since: 0.9.21728**/1729void1730hb_buffer_reverse (hb_buffer_t *buffer)1731{1732buffer->reverse ();1733}17341735/**1736* hb_buffer_reverse_range:1737* @buffer: An #hb_buffer_t1738* @start: start index1739* @end: end index1740*1741* Reverses buffer contents between @start and @end.1742*1743* Since: 0.9.411744**/1745void1746hb_buffer_reverse_range (hb_buffer_t *buffer,1747unsigned int start, unsigned int end)1748{1749buffer->reverse_range (start, end);1750}17511752/**1753* hb_buffer_reverse_clusters:1754* @buffer: An #hb_buffer_t1755*1756* Reverses buffer clusters. That is, the buffer contents are1757* reversed, then each cluster (consecutive items having the1758* same cluster number) are reversed again.1759*1760* Since: 0.9.21761**/1762void1763hb_buffer_reverse_clusters (hb_buffer_t *buffer)1764{1765buffer->reverse_clusters ();1766}17671768/**1769* hb_buffer_guess_segment_properties:1770* @buffer: An #hb_buffer_t1771*1772* Sets unset buffer segment properties based on buffer Unicode1773* contents. If buffer is not empty, it must have content type1774* #HB_BUFFER_CONTENT_TYPE_UNICODE.1775*1776* If buffer script is not set (ie. is #HB_SCRIPT_INVALID), it1777* will be set to the Unicode script of the first character in1778* the buffer that has a script other than #HB_SCRIPT_COMMON,1779* #HB_SCRIPT_INHERITED, and #HB_SCRIPT_UNKNOWN.1780*1781* Next, if buffer direction is not set (ie. is #HB_DIRECTION_INVALID),1782* it will be set to the natural horizontal direction of the1783* buffer script as returned by hb_script_get_horizontal_direction().1784* If hb_script_get_horizontal_direction() returns #HB_DIRECTION_INVALID,1785* then #HB_DIRECTION_LTR is used.1786*1787* Finally, if buffer language is not set (ie. is #HB_LANGUAGE_INVALID),1788* it will be set to the process's default language as returned by1789* hb_language_get_default(). This may change in the future by1790* taking buffer script into consideration when choosing a language.1791* Note that hb_language_get_default() is NOT threadsafe the first time1792* it is called. See documentation for that function for details.1793*1794* Since: 0.9.71795**/1796void1797hb_buffer_guess_segment_properties (hb_buffer_t *buffer)1798{1799buffer->guess_segment_properties ();1800}18011802template <typename utf_t>1803static inline void1804hb_buffer_add_utf (hb_buffer_t *buffer,1805const typename utf_t::codepoint_t *text,1806int text_length,1807unsigned int item_offset,1808int item_length)1809{1810typedef typename utf_t::codepoint_t T;1811const hb_codepoint_t replacement = buffer->replacement;18121813buffer->assert_unicode ();18141815if (unlikely (hb_object_is_immutable (buffer)))1816return;18171818if (text_length == -1)1819text_length = utf_t::strlen (text);18201821if (item_length == -1)1822item_length = text_length - item_offset;18231824if (unlikely (item_length < 0 ||1825item_length > INT_MAX / 8 ||1826!buffer->ensure (buffer->len + item_length * sizeof (T) / 4)))1827return;18281829/* If buffer is empty and pre-context provided, install it.1830* This check is written this way, to make sure people can1831* provide pre-context in one add_utf() call, then provide1832* text in a follow-up call. See:1833*1834* https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c131835*/1836if (!buffer->len && item_offset > 0)1837{1838/* Add pre-context */1839buffer->clear_context (0);1840const T *prev = text + item_offset;1841const T *start = text;1842while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)1843{1844hb_codepoint_t u;1845prev = utf_t::prev (prev, start, &u, replacement);1846buffer->context[0][buffer->context_len[0]++] = u;1847}1848}18491850const T *next = text + item_offset;1851const T *end = next + item_length;1852while (next < end)1853{1854hb_codepoint_t u;1855const T *old_next = next;1856next = utf_t::next (next, end, &u, replacement);1857buffer->add (u, old_next - (const T *) text);1858}18591860/* Add post-context */1861buffer->clear_context (1);1862end = text + text_length;1863while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)1864{1865hb_codepoint_t u;1866next = utf_t::next (next, end, &u, replacement);1867buffer->context[1][buffer->context_len[1]++] = u;1868}18691870buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;1871}18721873/**1874* hb_buffer_add_utf8:1875* @buffer: An #hb_buffer_t1876* @text: (array length=text_length) (element-type uint8_t): An array of UTF-81877* characters to append.1878* @text_length: The length of the @text, or -1 if it is `NULL` terminated.1879* @item_offset: The offset of the first character to add to the @buffer.1880* @item_length: The number of characters to add to the @buffer, or -1 for the1881* end of @text (assuming it is `NULL` terminated).1882*1883* See hb_buffer_add_codepoints().1884*1885* Replaces invalid UTF-8 characters with the @buffer replacement code point,1886* see hb_buffer_set_replacement_codepoint().1887*1888* Since: 0.9.21889**/1890void1891hb_buffer_add_utf8 (hb_buffer_t *buffer,1892const char *text,1893int text_length,1894unsigned int item_offset,1895int item_length)1896{1897hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);1898}18991900/**1901* hb_buffer_add_utf16:1902* @buffer: An #hb_buffer_t1903* @text: (array length=text_length): An array of UTF-16 characters to append1904* @text_length: The length of the @text, or -1 if it is `NULL` terminated1905* @item_offset: The offset of the first character to add to the @buffer1906* @item_length: The number of characters to add to the @buffer, or -1 for the1907* end of @text (assuming it is `NULL` terminated)1908*1909* See hb_buffer_add_codepoints().1910*1911* Replaces invalid UTF-16 characters with the @buffer replacement code point,1912* see hb_buffer_set_replacement_codepoint().1913*1914* Since: 0.9.21915**/1916void1917hb_buffer_add_utf16 (hb_buffer_t *buffer,1918const uint16_t *text,1919int text_length,1920unsigned int item_offset,1921int item_length)1922{1923hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length);1924}19251926/**1927* hb_buffer_add_utf32:1928* @buffer: An #hb_buffer_t1929* @text: (array length=text_length): An array of UTF-32 characters to append1930* @text_length: The length of the @text, or -1 if it is `NULL` terminated1931* @item_offset: The offset of the first character to add to the @buffer1932* @item_length: The number of characters to add to the @buffer, or -1 for the1933* end of @text (assuming it is `NULL` terminated)1934*1935* See hb_buffer_add_codepoints().1936*1937* Replaces invalid UTF-32 characters with the @buffer replacement code point,1938* see hb_buffer_set_replacement_codepoint().1939*1940* Since: 0.9.21941**/1942void1943hb_buffer_add_utf32 (hb_buffer_t *buffer,1944const uint32_t *text,1945int text_length,1946unsigned int item_offset,1947int item_length)1948{1949hb_buffer_add_utf<hb_utf32_t> (buffer, text, text_length, item_offset, item_length);1950}19511952/**1953* hb_buffer_add_latin1:1954* @buffer: An #hb_buffer_t1955* @text: (array length=text_length) (element-type uint8_t): an array of UTF-81956* characters to append1957* @text_length: the length of the @text, or -1 if it is `NULL` terminated1958* @item_offset: the offset of the first character to add to the @buffer1959* @item_length: the number of characters to add to the @buffer, or -1 for the1960* end of @text (assuming it is `NULL` terminated)1961*1962* Similar to hb_buffer_add_codepoints(), but allows only access to first 2561963* Unicode code points that can fit in 8-bit strings.1964*1965* <note>Has nothing to do with non-Unicode Latin-1 encoding.</note>1966*1967* Since: 0.9.391968**/1969void1970hb_buffer_add_latin1 (hb_buffer_t *buffer,1971const uint8_t *text,1972int text_length,1973unsigned int item_offset,1974int item_length)1975{1976hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length);1977}19781979/**1980* hb_buffer_add_codepoints:1981* @buffer: a #hb_buffer_t to append characters to.1982* @text: (array length=text_length): an array of Unicode code points to append.1983* @text_length: the length of the @text, or -1 if it is `NULL` terminated.1984* @item_offset: the offset of the first code point to add to the @buffer.1985* @item_length: the number of code points to add to the @buffer, or -1 for the1986* end of @text (assuming it is `NULL` terminated).1987*1988* Appends characters from @text array to @buffer. The @item_offset is the1989* position of the first character from @text that will be appended, and1990* @item_length is the number of character. When shaping part of a larger text1991* (e.g. a run of text from a paragraph), instead of passing just the substring1992* corresponding to the run, it is preferable to pass the whole1993* paragraph and specify the run start and length as @item_offset and1994* @item_length, respectively, to give HarfBuzz the full context to be able,1995* for example, to do cross-run Arabic shaping or properly handle combining1996* marks at stat of run.1997*1998* This function does not check the validity of @text, it is up to the caller1999* to ensure it contains a valid Unicode scalar values. In contrast,2000* hb_buffer_add_utf32() can be used that takes similar input but performs2001* sanity-check on the input.2002*2003* Since: 0.9.312004**/2005void2006hb_buffer_add_codepoints (hb_buffer_t *buffer,2007const hb_codepoint_t *text,2008int text_length,2009unsigned int item_offset,2010int item_length)2011{2012hb_buffer_add_utf<hb_utf32_novalidate_t> (buffer, text, text_length, item_offset, item_length);2013}201420152016/**2017* hb_buffer_append:2018* @buffer: An #hb_buffer_t2019* @source: source #hb_buffer_t2020* @start: start index into source buffer to copy. Use 0 to copy from start of buffer.2021* @end: end index into source buffer to copy. Use @UINT_MAX (or ((unsigned int) -1)) to copy to end of buffer.2022*2023* Append (part of) contents of another buffer to this buffer.2024*2025* Since: 1.5.02026**/2027HB_EXTERN void2028hb_buffer_append (hb_buffer_t *buffer,2029const hb_buffer_t *source,2030unsigned int start,2031unsigned int end)2032{2033assert (!buffer->have_output && !source->have_output);2034assert (buffer->have_positions == source->have_positions ||2035!buffer->len || !source->len);2036assert (buffer->content_type == source->content_type ||2037!buffer->len || !source->len);20382039if (end > source->len)2040end = source->len;2041if (start > end)2042start = end;2043if (start == end)2044return;20452046if (buffer->len + (end - start) < buffer->len) /* Overflows. */2047{2048buffer->successful = false;2049return;2050}20512052unsigned int orig_len = buffer->len;2053hb_buffer_set_length (buffer, buffer->len + (end - start));2054if (unlikely (!buffer->successful))2055return;20562057if (!orig_len)2058buffer->content_type = source->content_type;2059if (!buffer->have_positions && source->have_positions)2060buffer->clear_positions ();20612062hb_segment_properties_overlay (&buffer->props, &source->props);20632064hb_memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));2065if (buffer->have_positions)2066hb_memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));20672068if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)2069{2070/* See similar logic in add_utf. */20712072/* pre-context */2073if (!orig_len && start + source->context_len[0] > 0)2074{2075buffer->clear_context (0);2076while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH)2077buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint;2078for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++)2079buffer->context[0][buffer->context_len[0]++] = source->context[0][i];2080}20812082/* post-context */2083buffer->clear_context (1);2084while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH)2085buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint;2086for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++)2087buffer->context[1][buffer->context_len[1]++] = source->context[1][i];2088}2089}209020912092static int2093compare_info_codepoint (const hb_glyph_info_t *pa,2094const hb_glyph_info_t *pb)2095{2096return (int) pb->codepoint - (int) pa->codepoint;2097}20982099static inline void2100normalize_glyphs_cluster (hb_buffer_t *buffer,2101unsigned int start,2102unsigned int end,2103bool backward)2104{2105hb_glyph_position_t *pos = buffer->pos;21062107/* Total cluster advance */2108hb_position_t total_x_advance = 0, total_y_advance = 0;2109for (unsigned int i = start; i < end; i++)2110{2111total_x_advance += pos[i].x_advance;2112total_y_advance += pos[i].y_advance;2113}21142115hb_position_t x_advance = 0, y_advance = 0;2116for (unsigned int i = start; i < end; i++)2117{2118pos[i].x_offset += x_advance;2119pos[i].y_offset += y_advance;21202121x_advance += pos[i].x_advance;2122y_advance += pos[i].y_advance;21232124pos[i].x_advance = 0;2125pos[i].y_advance = 0;2126}21272128if (backward)2129{2130/* Transfer all cluster advance to the last glyph. */2131pos[end - 1].x_advance = total_x_advance;2132pos[end - 1].y_advance = total_y_advance;21332134hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);2135} else {2136/* Transfer all cluster advance to the first glyph. */2137pos[start].x_advance += total_x_advance;2138pos[start].y_advance += total_y_advance;2139for (unsigned int i = start + 1; i < end; i++) {2140pos[i].x_offset -= total_x_advance;2141pos[i].y_offset -= total_y_advance;2142}2143hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);2144}2145}21462147/**2148* hb_buffer_normalize_glyphs:2149* @buffer: An #hb_buffer_t2150*2151* Reorders a glyph buffer to have canonical in-cluster glyph order / position.2152* The resulting clusters should behave identical to pre-reordering clusters.2153*2154* <note>This has nothing to do with Unicode normalization.</note>2155*2156* Since: 0.9.22157**/2158void2159hb_buffer_normalize_glyphs (hb_buffer_t *buffer)2160{2161assert (buffer->have_positions);21622163buffer->assert_glyphs ();21642165bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);21662167foreach_cluster (buffer, start, end)2168normalize_glyphs_cluster (buffer, start, end, backward);2169}21702171void2172hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *))2173{2174assert (!have_positions);2175for (unsigned int i = start + 1; i < end; i++)2176{2177unsigned int j = i;2178while (j > start && compar (&info[j - 1], &info[i]) > 0)2179j--;2180if (i == j)2181continue;2182/* Move item i to occupy place for item j, shift what's in between. */2183merge_clusters (j, i + 1);2184{2185hb_glyph_info_t t = info[i];2186memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t));2187info[j] = t;2188}2189}2190}219121922193/*2194* Comparing buffers.2195*/21962197/**2198* hb_buffer_diff:2199* @buffer: a buffer.2200* @reference: other buffer to compare to.2201* @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepoint_t) -1.2202* @position_fuzz: allowed absolute difference in position values.2203*2204* If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT2205* and #HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most2206* callers if just comparing two buffers is needed.2207*2208* Since: 1.5.02209**/2210hb_buffer_diff_flags_t2211hb_buffer_diff (hb_buffer_t *buffer,2212hb_buffer_t *reference,2213hb_codepoint_t dottedcircle_glyph,2214unsigned int position_fuzz)2215{2216if (buffer->content_type != reference->content_type && buffer->len && reference->len)2217return HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH;22182219hb_buffer_diff_flags_t result = HB_BUFFER_DIFF_FLAG_EQUAL;2220bool contains = dottedcircle_glyph != (hb_codepoint_t) -1;22212222unsigned int count = reference->len;22232224if (buffer->len != count)2225{2226/*2227* we can't compare glyph-by-glyph, but we do want to know if there2228* are .notdef or dottedcircle glyphs present in the reference buffer2229*/2230const hb_glyph_info_t *info = reference->info;2231unsigned int i;2232for (i = 0; i < count; i++)2233{2234if (contains && info[i].codepoint == dottedcircle_glyph)2235result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;2236if (contains && info[i].codepoint == 0)2237result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;2238}2239result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;2240return hb_buffer_diff_flags_t (result);2241}22422243if (!count)2244return hb_buffer_diff_flags_t (result);22452246const hb_glyph_info_t *buf_info = buffer->info;2247const hb_glyph_info_t *ref_info = reference->info;2248for (unsigned int i = 0; i < count; i++)2249{2250if (buf_info->codepoint != ref_info->codepoint)2251result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;2252if (buf_info->cluster != ref_info->cluster)2253result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;2254if ((buf_info->mask ^ ref_info->mask) & HB_GLYPH_FLAG_DEFINED)2255result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;2256if (contains && ref_info->codepoint == dottedcircle_glyph)2257result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;2258if (contains && ref_info->codepoint == 0)2259result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;2260buf_info++;2261ref_info++;2262}22632264if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)2265{2266assert (buffer->have_positions);2267const hb_glyph_position_t *buf_pos = buffer->pos;2268const hb_glyph_position_t *ref_pos = reference->pos;2269for (unsigned int i = 0; i < count; i++)2270{2271if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||2272(unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||2273(unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||2274(unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)2275{2276result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;2277break;2278}2279buf_pos++;2280ref_pos++;2281}2282}22832284return result;2285}228622872288/*2289* Debugging.2290*/22912292#ifndef HB_NO_BUFFER_MESSAGE2293/**2294* hb_buffer_set_message_func:2295* @buffer: An #hb_buffer_t2296* @func: (closure user_data) (destroy destroy) (scope notified): Callback function2297* @user_data: (nullable): Data to pass to @func2298* @destroy: (nullable): The function to call when @user_data is not needed anymore2299*2300* Sets the implementation function for #hb_buffer_message_func_t.2301*2302* Since: 1.1.32303**/2304void2305hb_buffer_set_message_func (hb_buffer_t *buffer,2306hb_buffer_message_func_t func,2307void *user_data, hb_destroy_func_t destroy)2308{2309if (unlikely (hb_object_is_immutable (buffer)))2310{2311if (destroy)2312destroy (user_data);2313return;2314}23152316if (buffer->message_destroy)2317buffer->message_destroy (buffer->message_data);23182319if (func) {2320buffer->message_func = func;2321buffer->message_data = user_data;2322buffer->message_destroy = destroy;2323} else {2324buffer->message_func = nullptr;2325buffer->message_data = nullptr;2326buffer->message_destroy = nullptr;2327}2328}2329bool2330hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)2331{2332assert (!have_output || (out_info == info && out_len == idx));23332334message_depth++;23352336char buf[100];2337vsnprintf (buf, sizeof (buf), fmt, ap);2338bool ret = (bool) this->message_func (this, font, buf, this->message_data);23392340message_depth--;23412342return ret;2343}2344#endif234523462347