Path: blob/master/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc
66644 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**/434445/**46* hb_segment_properties_equal:47* @a: first #hb_segment_properties_t to compare.48* @b: second #hb_segment_properties_t to compare.49*50* Checks the equality of two #hb_segment_properties_t's.51*52* Return value:53* %true if all properties of @a equal those of @b, %false otherwise.54*55* Since: 0.9.756**/57hb_bool_t58hb_segment_properties_equal (const hb_segment_properties_t *a,59const hb_segment_properties_t *b)60{61return a->direction == b->direction &&62a->script == b->script &&63a->language == b->language &&64a->reserved1 == b->reserved1 &&65a->reserved2 == b->reserved2;6667}6869/**70* hb_segment_properties_hash:71* @p: #hb_segment_properties_t to hash.72*73* Creates a hash representing @p.74*75* Return value:76* A hash of @p.77*78* Since: 0.9.779**/80unsigned int81hb_segment_properties_hash (const hb_segment_properties_t *p)82{83return ((unsigned int) p->direction * 31 +84(unsigned int) p->script) * 31 +85(intptr_t) (p->language);86}8788/**89* hb_segment_properties_overlay:90* @p: #hb_segment_properties_t to fill in.91* @src: #hb_segment_properties_t to fill in from.92*93* Fills in missing fields of @p from @src in a considered manner.94*95* First, if @p does not have direction set, direction is copied from @src.96*97* Next, if @p and @src have the same direction (which can be unset), if @p98* does not have script set, script is copied from @src.99*100* Finally, if @p and @src have the same direction and script (which either101* can be unset), if @p does not have language set, language is copied from102* @src.103*104* Since: 3.3.0105**/106void107hb_segment_properties_overlay (hb_segment_properties_t *p,108const hb_segment_properties_t *src)109{110if (unlikely (!p || !src))111return;112113if (!p->direction)114p->direction = src->direction;115116if (p->direction != src->direction)117return;118119if (!p->script)120p->script = src->script;121122if (p->script != src->script)123return;124125if (!p->language)126p->language = src->language;127}128129/* Here is how the buffer works internally:130*131* There are two info pointers: info and out_info. They always have132* the same allocated size, but different lengths.133*134* As an optimization, both info and out_info may point to the135* same piece of memory, which is owned by info. This remains the136* case as long as out_len doesn't exceed i at any time.137* In that case, sync() is mostly no-op and the glyph operations138* operate mostly in-place.139*140* As soon as out_info gets longer than info, out_info is moved over141* to an alternate buffer (which we reuse the pos buffer for), and its142* current contents (out_len entries) are copied to the new place.143*144* This should all remain transparent to the user. sync() then145* switches info over to out_info and does housekeeping.146*/147148149150/* Internal API */151152bool153hb_buffer_t::enlarge (unsigned int size)154{155if (unlikely (!successful))156return false;157if (unlikely (size > max_len))158{159successful = false;160return false;161}162163unsigned int new_allocated = allocated;164hb_glyph_position_t *new_pos = nullptr;165hb_glyph_info_t *new_info = nullptr;166bool separate_out = out_info != info;167168if (unlikely (hb_unsigned_mul_overflows (size, sizeof (info[0]))))169goto done;170171while (size >= new_allocated)172new_allocated += (new_allocated >> 1) + 32;173174static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");175if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))176goto done;177178new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_allocated * sizeof (pos[0]));179new_info = (hb_glyph_info_t *) hb_realloc (info, new_allocated * sizeof (info[0]));180181done:182if (unlikely (!new_pos || !new_info))183successful = false;184185if (likely (new_pos))186pos = new_pos;187188if (likely (new_info))189info = new_info;190191out_info = separate_out ? (hb_glyph_info_t *) pos : info;192if (likely (successful))193allocated = new_allocated;194195return likely (successful);196}197198bool199hb_buffer_t::make_room_for (unsigned int num_in,200unsigned int num_out)201{202if (unlikely (!ensure (out_len + num_out))) return false;203204if (out_info == info &&205out_len + num_out > idx + num_in)206{207assert (have_output);208209out_info = (hb_glyph_info_t *) pos;210memcpy (out_info, info, out_len * sizeof (out_info[0]));211}212213return true;214}215216bool217hb_buffer_t::shift_forward (unsigned int count)218{219assert (have_output);220if (unlikely (!ensure (len + count))) return false;221222memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));223if (idx + count > len)224{225/* Under memory failure we might expose this area. At least226* clean it up. Oh well...227*228* Ideally, we should at least set Default_Ignorable bits on229* these, as well as consistent cluster values. But the former230* is layering violation... */231memset (info + len, 0, (idx + count - len) * sizeof (info[0]));232}233len += count;234idx += count;235236return true;237}238239hb_buffer_t::scratch_buffer_t *240hb_buffer_t::get_scratch_buffer (unsigned int *size)241{242have_output = false;243have_positions = false;244245out_len = 0;246out_info = info;247248assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);249*size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);250return (scratch_buffer_t *) (void *) pos;251}252253254255/* HarfBuzz-Internal API */256257void258hb_buffer_t::similar (const hb_buffer_t &src)259{260hb_unicode_funcs_destroy (unicode);261unicode = hb_unicode_funcs_reference (src.unicode);262flags = src.flags;263cluster_level = src.cluster_level;264replacement = src.invisible;265invisible = src.invisible;266not_found = src.not_found;267}268269void270hb_buffer_t::reset ()271{272hb_unicode_funcs_destroy (unicode);273unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());274flags = HB_BUFFER_FLAG_DEFAULT;275cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;276replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;277invisible = 0;278not_found = 0;279280clear ();281}282283void284hb_buffer_t::clear ()285{286content_type = HB_BUFFER_CONTENT_TYPE_INVALID;287hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;288props = default_props;289290successful = true;291shaping_failed = false;292have_output = false;293have_positions = false;294295idx = 0;296len = 0;297out_len = 0;298out_info = info;299300memset (context, 0, sizeof context);301memset (context_len, 0, sizeof context_len);302303deallocate_var_all ();304serial = 0;305scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;306}307308void309hb_buffer_t::enter ()310{311deallocate_var_all ();312serial = 0;313shaping_failed = false;314scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;315if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR)))316{317max_len = hb_max (len * HB_BUFFER_MAX_LEN_FACTOR,318(unsigned) HB_BUFFER_MAX_LEN_MIN);319}320if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR)))321{322max_ops = hb_max (len * HB_BUFFER_MAX_OPS_FACTOR,323(unsigned) HB_BUFFER_MAX_OPS_MIN);324}325}326void327hb_buffer_t::leave ()328{329max_len = HB_BUFFER_MAX_LEN_DEFAULT;330max_ops = HB_BUFFER_MAX_OPS_DEFAULT;331deallocate_var_all ();332serial = 0;333// Intentionally not reseting shaping_failed, such that it can be inspected.334}335336337void338hb_buffer_t::add (hb_codepoint_t codepoint,339unsigned int cluster)340{341hb_glyph_info_t *glyph;342343if (unlikely (!ensure (len + 1))) return;344345glyph = &info[len];346347memset (glyph, 0, sizeof (*glyph));348glyph->codepoint = codepoint;349glyph->mask = 0;350glyph->cluster = cluster;351352len++;353}354355void356hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)357{358if (unlikely (!ensure (len + 1))) return;359360info[len] = glyph_info;361362len++;363}364365366void367hb_buffer_t::clear_output ()368{369have_output = true;370have_positions = false;371372idx = 0;373out_len = 0;374out_info = info;375}376377void378hb_buffer_t::clear_positions ()379{380have_output = false;381have_positions = true;382383out_len = 0;384out_info = info;385386hb_memset (pos, 0, sizeof (pos[0]) * len);387}388389void390hb_buffer_t::sync ()391{392assert (have_output);393394assert (idx <= len);395396if (unlikely (!successful || !next_glyphs (len - idx)))397goto reset;398399if (out_info != info)400{401pos = (hb_glyph_position_t *) info;402info = out_info;403}404len = out_len;405406reset:407have_output = false;408out_len = 0;409out_info = info;410idx = 0;411}412413bool414hb_buffer_t::move_to (unsigned int i)415{416if (!have_output)417{418assert (i <= len);419idx = i;420return true;421}422if (unlikely (!successful))423return false;424425assert (i <= out_len + (len - idx));426427if (out_len < i)428{429unsigned int count = i - out_len;430if (unlikely (!make_room_for (count, count))) return false;431432memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));433idx += count;434out_len += count;435}436else if (out_len > i)437{438/* Tricky part: rewinding... */439unsigned int count = out_len - i;440441/* This will blow in our face if memory allocation fails later442* in this same lookup...443*444* We used to shift with extra 32 items.445* But that would leave empty slots in the buffer in case of allocation446* failures. See comments in shift_forward(). This can cause O(N^2)447* behavior more severely than adding 32 empty slots can... */448if (unlikely (idx < count && !shift_forward (count - idx))) return false;449450assert (idx >= count);451452idx -= count;453out_len -= count;454memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));455}456457return true;458}459460461void462hb_buffer_t::set_masks (hb_mask_t value,463hb_mask_t mask,464unsigned int cluster_start,465unsigned int cluster_end)466{467hb_mask_t not_mask = ~mask;468value &= mask;469470if (!mask)471return;472473unsigned int count = len;474for (unsigned int i = 0; i < count; i++)475if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)476info[i].mask = (info[i].mask & not_mask) | value;477}478479void480hb_buffer_t::merge_clusters_impl (unsigned int start,481unsigned int end)482{483if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)484{485unsafe_to_break (start, end);486return;487}488489unsigned int cluster = info[start].cluster;490491for (unsigned int i = start + 1; i < end; i++)492cluster = hb_min (cluster, info[i].cluster);493494/* Extend end */495while (end < len && info[end - 1].cluster == info[end].cluster)496end++;497498/* Extend start */499while (idx < start && info[start - 1].cluster == info[start].cluster)500start--;501502/* If we hit the start of buffer, continue in out-buffer. */503if (idx == start)504for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)505set_cluster (out_info[i - 1], cluster);506507for (unsigned int i = start; i < end; i++)508set_cluster (info[i], cluster);509}510void511hb_buffer_t::merge_out_clusters (unsigned int start,512unsigned int end)513{514if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)515return;516517if (unlikely (end - start < 2))518return;519520unsigned int cluster = out_info[start].cluster;521522for (unsigned int i = start + 1; i < end; i++)523cluster = hb_min (cluster, out_info[i].cluster);524525/* Extend start */526while (start && out_info[start - 1].cluster == out_info[start].cluster)527start--;528529/* Extend end */530while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)531end++;532533/* If we hit the end of out-buffer, continue in buffer. */534if (end == out_len)535for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)536set_cluster (info[i], cluster);537538for (unsigned int i = start; i < end; i++)539set_cluster (out_info[i], cluster);540}541void542hb_buffer_t::delete_glyph ()543{544/* The logic here is duplicated in hb_ot_hide_default_ignorables(). */545546unsigned int cluster = info[idx].cluster;547if ((idx + 1 < len && cluster == info[idx + 1].cluster) ||548(out_len && cluster == out_info[out_len - 1].cluster))549{550/* Cluster survives; do nothing. */551goto done;552}553554if (out_len)555{556/* Merge cluster backward. */557if (cluster < out_info[out_len - 1].cluster)558{559unsigned int mask = info[idx].mask;560unsigned int old_cluster = out_info[out_len - 1].cluster;561for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)562set_cluster (out_info[i - 1], cluster, mask);563}564goto done;565}566567if (idx + 1 < len)568{569/* Merge cluster forward. */570merge_clusters (idx, idx + 2);571goto done;572}573574done:575skip_glyph ();576}577578void579hb_buffer_t::guess_segment_properties ()580{581assert_unicode ();582583/* If script is set to INVALID, guess from buffer contents */584if (props.script == HB_SCRIPT_INVALID) {585for (unsigned int i = 0; i < len; i++) {586hb_script_t script = unicode->script (info[i].codepoint);587if (likely (script != HB_SCRIPT_COMMON &&588script != HB_SCRIPT_INHERITED &&589script != HB_SCRIPT_UNKNOWN)) {590props.script = script;591break;592}593}594}595596/* If direction is set to INVALID, guess from script */597if (props.direction == HB_DIRECTION_INVALID) {598props.direction = hb_script_get_horizontal_direction (props.script);599if (props.direction == HB_DIRECTION_INVALID)600props.direction = HB_DIRECTION_LTR;601}602603/* If language is not set, use default language from locale */604if (props.language == HB_LANGUAGE_INVALID) {605/* TODO get_default_for_script? using $LANGUAGE */606props.language = hb_language_get_default ();607}608}609610611/* Public API */612613DEFINE_NULL_INSTANCE (hb_buffer_t) =614{615HB_OBJECT_HEADER_STATIC,616617const_cast<hb_unicode_funcs_t *> (&_hb_Null_hb_unicode_funcs_t),618HB_BUFFER_FLAG_DEFAULT,619HB_BUFFER_CLUSTER_LEVEL_DEFAULT,620HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,6210, /* invisible */6220, /* not_found */623624625HB_BUFFER_CONTENT_TYPE_INVALID,626HB_SEGMENT_PROPERTIES_DEFAULT,627628false, /* successful */629true, /* shaping_failed */630false, /* have_output */631true /* have_positions */632633/* Zero is good enough for everything else. */634};635636637/**638* hb_buffer_create:639*640* Creates a new #hb_buffer_t with all properties to defaults.641*642* Return value: (transfer full):643* A newly allocated #hb_buffer_t with a reference count of 1. The initial644* reference count should be released with hb_buffer_destroy() when you are done645* using the #hb_buffer_t. This function never returns %NULL. If memory cannot646* be allocated, a special #hb_buffer_t object will be returned on which647* hb_buffer_allocation_successful() returns %false.648*649* Since: 0.9.2650**/651hb_buffer_t *652hb_buffer_create ()653{654hb_buffer_t *buffer;655656if (!(buffer = hb_object_create<hb_buffer_t> ()))657return hb_buffer_get_empty ();658659buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;660buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;661662buffer->reset ();663664return buffer;665}666667/**668* hb_buffer_create_similar:669* @src: An #hb_buffer_t670*671* Creates a new #hb_buffer_t, similar to hb_buffer_create(). The only672* difference is that the buffer is configured similarly to @src.673*674* Return value: (transfer full):675* A newly allocated #hb_buffer_t, similar to hb_buffer_create().676*677* Since: 3.3.0678**/679hb_buffer_t *680hb_buffer_create_similar (const hb_buffer_t *src)681{682hb_buffer_t *buffer = hb_buffer_create ();683684buffer->similar (*src);685686return buffer;687}688689/**690* hb_buffer_reset:691* @buffer: An #hb_buffer_t692*693* Resets the buffer to its initial status, as if it was just newly created694* with hb_buffer_create().695*696* Since: 0.9.2697**/698void699hb_buffer_reset (hb_buffer_t *buffer)700{701if (unlikely (hb_object_is_immutable (buffer)))702return;703704buffer->reset ();705}706707/**708* hb_buffer_get_empty:709*710* Fetches an empty #hb_buffer_t.711*712* Return value: (transfer full): The empty buffer713*714* Since: 0.9.2715**/716hb_buffer_t *717hb_buffer_get_empty ()718{719return const_cast<hb_buffer_t *> (&Null (hb_buffer_t));720}721722/**723* hb_buffer_reference: (skip)724* @buffer: An #hb_buffer_t725*726* Increases the reference count on @buffer by one. This prevents @buffer from727* being destroyed until a matching call to hb_buffer_destroy() is made.728*729* Return value: (transfer full):730* The referenced #hb_buffer_t.731*732* Since: 0.9.2733**/734hb_buffer_t *735hb_buffer_reference (hb_buffer_t *buffer)736{737return hb_object_reference (buffer);738}739740/**741* hb_buffer_destroy: (skip)742* @buffer: An #hb_buffer_t743*744* Deallocate the @buffer.745* Decreases the reference count on @buffer by one. If the result is zero, then746* @buffer and all associated resources are freed. See hb_buffer_reference().747*748* Since: 0.9.2749**/750void751hb_buffer_destroy (hb_buffer_t *buffer)752{753if (!hb_object_destroy (buffer)) return;754755hb_unicode_funcs_destroy (buffer->unicode);756757hb_free (buffer->info);758hb_free (buffer->pos);759#ifndef HB_NO_BUFFER_MESSAGE760if (buffer->message_destroy)761buffer->message_destroy (buffer->message_data);762#endif763764hb_free (buffer);765}766767/**768* hb_buffer_set_user_data: (skip)769* @buffer: An #hb_buffer_t770* @key: The user-data key771* @data: A pointer to the user data772* @destroy: (nullable): A callback to call when @data is not needed anymore773* @replace: Whether to replace an existing data with the same key774*775* Attaches a user-data key/data pair to the specified buffer.776*777* Return value: %true if success, %false otherwise778*779* Since: 0.9.2780**/781hb_bool_t782hb_buffer_set_user_data (hb_buffer_t *buffer,783hb_user_data_key_t *key,784void * data,785hb_destroy_func_t destroy,786hb_bool_t replace)787{788return hb_object_set_user_data (buffer, key, data, destroy, replace);789}790791/**792* hb_buffer_get_user_data: (skip)793* @buffer: An #hb_buffer_t794* @key: The user-data key to query795*796* Fetches the user data associated with the specified key,797* attached to the specified buffer.798*799* Return value: (transfer none): A pointer to the user data800*801* Since: 0.9.2802**/803void *804hb_buffer_get_user_data (hb_buffer_t *buffer,805hb_user_data_key_t *key)806{807return hb_object_get_user_data (buffer, key);808}809810811/**812* hb_buffer_set_content_type:813* @buffer: An #hb_buffer_t814* @content_type: The type of buffer contents to set815*816* Sets the type of @buffer contents. Buffers are either empty, contain817* characters (before shaping), or contain glyphs (the result of shaping).818*819* Since: 0.9.5820**/821void822hb_buffer_set_content_type (hb_buffer_t *buffer,823hb_buffer_content_type_t content_type)824{825buffer->content_type = content_type;826}827828/**829* hb_buffer_get_content_type:830* @buffer: An #hb_buffer_t831*832* Fetches the type of @buffer contents. Buffers are either empty, contain833* characters (before shaping), or contain glyphs (the result of shaping).834*835* Return value:836* The type of @buffer contents837*838* Since: 0.9.5839**/840hb_buffer_content_type_t841hb_buffer_get_content_type (const hb_buffer_t *buffer)842{843return buffer->content_type;844}845846847/**848* hb_buffer_set_unicode_funcs:849* @buffer: An #hb_buffer_t850* @unicode_funcs: The Unicode-functions structure851*852* Sets the Unicode-functions structure of a buffer to853* @unicode_funcs.854*855* Since: 0.9.2856**/857void858hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,859hb_unicode_funcs_t *unicode_funcs)860{861if (unlikely (hb_object_is_immutable (buffer)))862return;863864if (!unicode_funcs)865unicode_funcs = hb_unicode_funcs_get_default ();866867hb_unicode_funcs_reference (unicode_funcs);868hb_unicode_funcs_destroy (buffer->unicode);869buffer->unicode = unicode_funcs;870}871872/**873* hb_buffer_get_unicode_funcs:874* @buffer: An #hb_buffer_t875*876* Fetches the Unicode-functions structure of a buffer.877*878* Return value: The Unicode-functions structure879*880* Since: 0.9.2881**/882hb_unicode_funcs_t *883hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer)884{885return buffer->unicode;886}887888/**889* hb_buffer_set_direction:890* @buffer: An #hb_buffer_t891* @direction: the #hb_direction_t of the @buffer892*893* Set the text flow direction of the buffer. No shaping can happen without894* setting @buffer direction, and it controls the visual direction for the895* output glyphs; for RTL direction the glyphs will be reversed. Many layout896* features depend on the proper setting of the direction, for example,897* reversing RTL text before shaping, then shaping with LTR direction is not898* the same as keeping the text in logical order and shaping with RTL899* direction.900*901* Since: 0.9.2902**/903void904hb_buffer_set_direction (hb_buffer_t *buffer,905hb_direction_t direction)906907{908if (unlikely (hb_object_is_immutable (buffer)))909return;910911buffer->props.direction = direction;912}913914/**915* hb_buffer_get_direction:916* @buffer: An #hb_buffer_t917*918* See hb_buffer_set_direction()919*920* Return value:921* The direction of the @buffer.922*923* Since: 0.9.2924**/925hb_direction_t926hb_buffer_get_direction (const hb_buffer_t *buffer)927{928return buffer->props.direction;929}930931/**932* hb_buffer_set_script:933* @buffer: An #hb_buffer_t934* @script: An #hb_script_t to set.935*936* Sets the script of @buffer to @script.937*938* Script is crucial for choosing the proper shaping behaviour for scripts that939* require it (e.g. Arabic) and the which OpenType features defined in the font940* to be applied.941*942* You can pass one of the predefined #hb_script_t values, or use943* hb_script_from_string() or hb_script_from_iso15924_tag() to get the944* corresponding script from an ISO 15924 script tag.945*946* Since: 0.9.2947**/948void949hb_buffer_set_script (hb_buffer_t *buffer,950hb_script_t script)951{952if (unlikely (hb_object_is_immutable (buffer)))953return;954955buffer->props.script = script;956}957958/**959* hb_buffer_get_script:960* @buffer: An #hb_buffer_t961*962* Fetches the script of @buffer.963*964* Return value:965* The #hb_script_t of the @buffer966*967* Since: 0.9.2968**/969hb_script_t970hb_buffer_get_script (const hb_buffer_t *buffer)971{972return buffer->props.script;973}974975/**976* hb_buffer_set_language:977* @buffer: An #hb_buffer_t978* @language: An hb_language_t to set979*980* Sets the language of @buffer to @language.981*982* Languages are crucial for selecting which OpenType feature to apply to the983* buffer which can result in applying language-specific behaviour. Languages984* are orthogonal to the scripts, and though they are related, they are985* different concepts and should not be confused with each other.986*987* Use hb_language_from_string() to convert from BCP 47 language tags to988* #hb_language_t.989*990* Since: 0.9.2991**/992void993hb_buffer_set_language (hb_buffer_t *buffer,994hb_language_t language)995{996if (unlikely (hb_object_is_immutable (buffer)))997return;998999buffer->props.language = language;1000}10011002/**1003* hb_buffer_get_language:1004* @buffer: An #hb_buffer_t1005*1006* See hb_buffer_set_language().1007*1008* Return value: (transfer none):1009* The #hb_language_t of the buffer. Must not be freed by the caller.1010*1011* Since: 0.9.21012**/1013hb_language_t1014hb_buffer_get_language (const hb_buffer_t *buffer)1015{1016return buffer->props.language;1017}10181019/**1020* hb_buffer_set_segment_properties:1021* @buffer: An #hb_buffer_t1022* @props: An #hb_segment_properties_t to use1023*1024* Sets the segment properties of the buffer, a shortcut for calling1025* hb_buffer_set_direction(), hb_buffer_set_script() and1026* hb_buffer_set_language() individually.1027*1028* Since: 0.9.71029**/1030void1031hb_buffer_set_segment_properties (hb_buffer_t *buffer,1032const hb_segment_properties_t *props)1033{1034if (unlikely (hb_object_is_immutable (buffer)))1035return;10361037buffer->props = *props;1038}10391040/**1041* hb_buffer_get_segment_properties:1042* @buffer: An #hb_buffer_t1043* @props: (out): The output #hb_segment_properties_t1044*1045* Sets @props to the #hb_segment_properties_t of @buffer.1046*1047* Since: 0.9.71048**/1049void1050hb_buffer_get_segment_properties (const hb_buffer_t *buffer,1051hb_segment_properties_t *props)1052{1053*props = buffer->props;1054}105510561057/**1058* hb_buffer_set_flags:1059* @buffer: An #hb_buffer_t1060* @flags: The buffer flags to set1061*1062* Sets @buffer flags to @flags. See #hb_buffer_flags_t.1063*1064* Since: 0.9.71065**/1066void1067hb_buffer_set_flags (hb_buffer_t *buffer,1068hb_buffer_flags_t flags)1069{1070if (unlikely (hb_object_is_immutable (buffer)))1071return;10721073buffer->flags = flags;1074}10751076/**1077* hb_buffer_get_flags:1078* @buffer: An #hb_buffer_t1079*1080* Fetches the #hb_buffer_flags_t of @buffer.1081*1082* Return value:1083* The @buffer flags1084*1085* Since: 0.9.71086**/1087hb_buffer_flags_t1088hb_buffer_get_flags (const hb_buffer_t *buffer)1089{1090return buffer->flags;1091}10921093/**1094* hb_buffer_set_cluster_level:1095* @buffer: An #hb_buffer_t1096* @cluster_level: The cluster level to set on the buffer1097*1098* Sets the cluster level of a buffer. The #hb_buffer_cluster_level_t1099* dictates one aspect of how HarfBuzz will treat non-base characters1100* during shaping.1101*1102* Since: 0.9.421103**/1104void1105hb_buffer_set_cluster_level (hb_buffer_t *buffer,1106hb_buffer_cluster_level_t cluster_level)1107{1108if (unlikely (hb_object_is_immutable (buffer)))1109return;11101111buffer->cluster_level = cluster_level;1112}11131114/**1115* hb_buffer_get_cluster_level:1116* @buffer: An #hb_buffer_t1117*1118* Fetches the cluster level of a buffer. The #hb_buffer_cluster_level_t1119* dictates one aspect of how HarfBuzz will treat non-base characters1120* during shaping.1121*1122* Return value: The cluster level of @buffer1123*1124* Since: 0.9.421125**/1126hb_buffer_cluster_level_t1127hb_buffer_get_cluster_level (const hb_buffer_t *buffer)1128{1129return buffer->cluster_level;1130}113111321133/**1134* hb_buffer_set_replacement_codepoint:1135* @buffer: An #hb_buffer_t1136* @replacement: the replacement #hb_codepoint_t1137*1138* Sets the #hb_codepoint_t that replaces invalid entries for a given encoding1139* when adding text to @buffer.1140*1141* Default is #HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.1142*1143* Since: 0.9.311144**/1145void1146hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,1147hb_codepoint_t replacement)1148{1149if (unlikely (hb_object_is_immutable (buffer)))1150return;11511152buffer->replacement = replacement;1153}11541155/**1156* hb_buffer_get_replacement_codepoint:1157* @buffer: An #hb_buffer_t1158*1159* Fetches the #hb_codepoint_t that replaces invalid entries for a given encoding1160* when adding text to @buffer.1161*1162* Return value:1163* The @buffer replacement #hb_codepoint_t1164*1165* Since: 0.9.311166**/1167hb_codepoint_t1168hb_buffer_get_replacement_codepoint (const hb_buffer_t *buffer)1169{1170return buffer->replacement;1171}117211731174/**1175* hb_buffer_set_invisible_glyph:1176* @buffer: An #hb_buffer_t1177* @invisible: the invisible #hb_codepoint_t1178*1179* Sets the #hb_codepoint_t that replaces invisible characters in1180* the shaping result. If set to zero (default), the glyph for the1181* U+0020 SPACE character is used. Otherwise, this value is used1182* verbatim.1183*1184* Since: 2.0.01185**/1186void1187hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,1188hb_codepoint_t invisible)1189{1190if (unlikely (hb_object_is_immutable (buffer)))1191return;11921193buffer->invisible = invisible;1194}11951196/**1197* hb_buffer_get_invisible_glyph:1198* @buffer: An #hb_buffer_t1199*1200* See hb_buffer_set_invisible_glyph().1201*1202* Return value:1203* The @buffer invisible #hb_codepoint_t1204*1205* Since: 2.0.01206**/1207hb_codepoint_t1208hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer)1209{1210return buffer->invisible;1211}12121213/**1214* hb_buffer_set_not_found_glyph:1215* @buffer: An #hb_buffer_t1216* @not_found: the not-found #hb_codepoint_t1217*1218* Sets the #hb_codepoint_t that replaces characters not found in1219* the font during shaping.1220*1221* The not-found glyph defaults to zero, sometimes knows as the1222* ".notdef" glyph. This API allows for differentiating the two.1223*1224* Since: 3.1.01225**/1226void1227hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,1228hb_codepoint_t not_found)1229{1230if (unlikely (hb_object_is_immutable (buffer)))1231return;12321233buffer->not_found = not_found;1234}12351236/**1237* hb_buffer_get_not_found_glyph:1238* @buffer: An #hb_buffer_t1239*1240* See hb_buffer_set_not_found_glyph().1241*1242* Return value:1243* The @buffer not-found #hb_codepoint_t1244*1245* Since: 3.1.01246**/1247hb_codepoint_t1248hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)1249{1250return buffer->not_found;1251}125212531254/**1255* hb_buffer_clear_contents:1256* @buffer: An #hb_buffer_t1257*1258* Similar to hb_buffer_reset(), but does not clear the Unicode functions and1259* the replacement code point.1260*1261* Since: 0.9.111262**/1263void1264hb_buffer_clear_contents (hb_buffer_t *buffer)1265{1266if (unlikely (hb_object_is_immutable (buffer)))1267return;12681269buffer->clear ();1270}12711272/**1273* hb_buffer_pre_allocate:1274* @buffer: An #hb_buffer_t1275* @size: Number of items to pre allocate.1276*1277* Pre allocates memory for @buffer to fit at least @size number of items.1278*1279* Return value:1280* %true if @buffer memory allocation succeeded, %false otherwise1281*1282* Since: 0.9.21283**/1284hb_bool_t1285hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)1286{1287return buffer->ensure (size);1288}12891290/**1291* hb_buffer_allocation_successful:1292* @buffer: An #hb_buffer_t1293*1294* Check if allocating memory for the buffer succeeded.1295*1296* Return value:1297* %true if @buffer memory allocation succeeded, %false otherwise.1298*1299* Since: 0.9.21300**/1301hb_bool_t1302hb_buffer_allocation_successful (hb_buffer_t *buffer)1303{1304return buffer->successful;1305}13061307/**1308* hb_buffer_add:1309* @buffer: An #hb_buffer_t1310* @codepoint: A Unicode code point.1311* @cluster: The cluster value of @codepoint.1312*1313* Appends a character with the Unicode value of @codepoint to @buffer, and1314* gives it the initial cluster value of @cluster. Clusters can be any thing1315* the client wants, they are usually used to refer to the index of the1316* character in the input text stream and are output in1317* #hb_glyph_info_t.cluster field.1318*1319* This function does not check the validity of @codepoint, it is up to the1320* caller to ensure it is a valid Unicode code point.1321*1322* Since: 0.9.71323**/1324void1325hb_buffer_add (hb_buffer_t *buffer,1326hb_codepoint_t codepoint,1327unsigned int cluster)1328{1329buffer->add (codepoint, cluster);1330buffer->clear_context (1);1331}13321333/**1334* hb_buffer_set_length:1335* @buffer: An #hb_buffer_t1336* @length: The new length of @buffer1337*1338* Similar to hb_buffer_pre_allocate(), but clears any new items added at the1339* end.1340*1341* Return value:1342* %true if @buffer memory allocation succeeded, %false otherwise.1343*1344* Since: 0.9.21345**/1346hb_bool_t1347hb_buffer_set_length (hb_buffer_t *buffer,1348unsigned int length)1349{1350if (unlikely (hb_object_is_immutable (buffer)))1351return length == 0;13521353if (unlikely (!buffer->ensure (length)))1354return false;13551356/* Wipe the new space */1357if (length > buffer->len) {1358memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));1359if (buffer->have_positions)1360memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));1361}13621363buffer->len = length;13641365if (!length)1366{1367buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;1368buffer->clear_context (0);1369}1370buffer->clear_context (1);13711372return true;1373}13741375/**1376* hb_buffer_get_length:1377* @buffer: An #hb_buffer_t1378*1379* Returns the number of items in the buffer.1380*1381* Return value:1382* The @buffer length.1383* The value valid as long as buffer has not been modified.1384*1385* Since: 0.9.21386**/1387unsigned int1388hb_buffer_get_length (const hb_buffer_t *buffer)1389{1390return buffer->len;1391}13921393/**1394* hb_buffer_get_glyph_infos:1395* @buffer: An #hb_buffer_t1396* @length: (out): The output-array length.1397*1398* Returns @buffer glyph information array. Returned pointer1399* is valid as long as @buffer contents are not modified.1400*1401* Return value: (transfer none) (array length=length):1402* The @buffer glyph information array.1403* The value valid as long as buffer has not been modified.1404*1405* Since: 0.9.21406**/1407hb_glyph_info_t *1408hb_buffer_get_glyph_infos (hb_buffer_t *buffer,1409unsigned int *length)1410{1411if (length)1412*length = buffer->len;14131414return (hb_glyph_info_t *) buffer->info;1415}14161417/**1418* hb_buffer_get_glyph_positions:1419* @buffer: An #hb_buffer_t1420* @length: (out): The output length1421*1422* Returns @buffer glyph position array. Returned pointer1423* is valid as long as @buffer contents are not modified.1424*1425* If buffer did not have positions before, the positions will be1426* initialized to zeros, unless this function is called from1427* within a buffer message callback (see hb_buffer_set_message_func()),1428* in which case %NULL is returned.1429*1430* Return value: (transfer none) (array length=length):1431* The @buffer glyph position array.1432* The value valid as long as buffer has not been modified.1433*1434* Since: 0.9.21435**/1436hb_glyph_position_t *1437hb_buffer_get_glyph_positions (hb_buffer_t *buffer,1438unsigned int *length)1439{1440if (length)1441*length = buffer->len;14421443if (!buffer->have_positions)1444{1445if (unlikely (buffer->message_depth))1446return nullptr;14471448buffer->clear_positions ();1449}14501451return (hb_glyph_position_t *) buffer->pos;1452}14531454/**1455* hb_buffer_has_positions:1456* @buffer: an #hb_buffer_t.1457*1458* Returns whether @buffer has glyph position data.1459* A buffer gains position data when hb_buffer_get_glyph_positions() is called on it,1460* and cleared of position data when hb_buffer_clear_contents() is called.1461*1462* Return value:1463* %true if the @buffer has position array, %false otherwise.1464*1465* Since: 2.7.31466**/1467HB_EXTERN hb_bool_t1468hb_buffer_has_positions (hb_buffer_t *buffer)1469{1470return buffer->have_positions;1471}14721473/**1474* hb_glyph_info_get_glyph_flags:1475* @info: a #hb_glyph_info_t1476*1477* Returns glyph flags encoded within a #hb_glyph_info_t.1478*1479* Return value:1480* The #hb_glyph_flags_t encoded within @info1481*1482* Since: 1.5.01483**/1484hb_glyph_flags_t1485(hb_glyph_info_get_glyph_flags) (const hb_glyph_info_t *info)1486{1487return hb_glyph_info_get_glyph_flags (info);1488}14891490/**1491* hb_buffer_reverse:1492* @buffer: An #hb_buffer_t1493*1494* Reverses buffer contents.1495*1496* Since: 0.9.21497**/1498void1499hb_buffer_reverse (hb_buffer_t *buffer)1500{1501buffer->reverse ();1502}15031504/**1505* hb_buffer_reverse_range:1506* @buffer: An #hb_buffer_t1507* @start: start index1508* @end: end index1509*1510* Reverses buffer contents between @start and @end.1511*1512* Since: 0.9.411513**/1514void1515hb_buffer_reverse_range (hb_buffer_t *buffer,1516unsigned int start, unsigned int end)1517{1518buffer->reverse_range (start, end);1519}15201521/**1522* hb_buffer_reverse_clusters:1523* @buffer: An #hb_buffer_t1524*1525* Reverses buffer clusters. That is, the buffer contents are1526* reversed, then each cluster (consecutive items having the1527* same cluster number) are reversed again.1528*1529* Since: 0.9.21530**/1531void1532hb_buffer_reverse_clusters (hb_buffer_t *buffer)1533{1534buffer->reverse_clusters ();1535}15361537/**1538* hb_buffer_guess_segment_properties:1539* @buffer: An #hb_buffer_t1540*1541* Sets unset buffer segment properties based on buffer Unicode1542* contents. If buffer is not empty, it must have content type1543* #HB_BUFFER_CONTENT_TYPE_UNICODE.1544*1545* If buffer script is not set (ie. is #HB_SCRIPT_INVALID), it1546* will be set to the Unicode script of the first character in1547* the buffer that has a script other than #HB_SCRIPT_COMMON,1548* #HB_SCRIPT_INHERITED, and #HB_SCRIPT_UNKNOWN.1549*1550* Next, if buffer direction is not set (ie. is #HB_DIRECTION_INVALID),1551* it will be set to the natural horizontal direction of the1552* buffer script as returned by hb_script_get_horizontal_direction().1553* If hb_script_get_horizontal_direction() returns #HB_DIRECTION_INVALID,1554* then #HB_DIRECTION_LTR is used.1555*1556* Finally, if buffer language is not set (ie. is #HB_LANGUAGE_INVALID),1557* it will be set to the process's default language as returned by1558* hb_language_get_default(). This may change in the future by1559* taking buffer script into consideration when choosing a language.1560* Note that hb_language_get_default() is NOT threadsafe the first time1561* it is called. See documentation for that function for details.1562*1563* Since: 0.9.71564**/1565void1566hb_buffer_guess_segment_properties (hb_buffer_t *buffer)1567{1568buffer->guess_segment_properties ();1569}15701571template <typename utf_t>1572static inline void1573hb_buffer_add_utf (hb_buffer_t *buffer,1574const typename utf_t::codepoint_t *text,1575int text_length,1576unsigned int item_offset,1577int item_length)1578{1579typedef typename utf_t::codepoint_t T;1580const hb_codepoint_t replacement = buffer->replacement;15811582buffer->assert_unicode ();15831584if (unlikely (hb_object_is_immutable (buffer)))1585return;15861587if (text_length == -1)1588text_length = utf_t::strlen (text);15891590if (item_length == -1)1591item_length = text_length - item_offset;15921593if (unlikely (item_length < 0 ||1594item_length > INT_MAX / 8 ||1595!buffer->ensure (buffer->len + item_length * sizeof (T) / 4)))1596return;15971598/* If buffer is empty and pre-context provided, install it.1599* This check is written this way, to make sure people can1600* provide pre-context in one add_utf() call, then provide1601* text in a follow-up call. See:1602*1603* https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c131604*/1605if (!buffer->len && item_offset > 0)1606{1607/* Add pre-context */1608buffer->clear_context (0);1609const T *prev = text + item_offset;1610const T *start = text;1611while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)1612{1613hb_codepoint_t u;1614prev = utf_t::prev (prev, start, &u, replacement);1615buffer->context[0][buffer->context_len[0]++] = u;1616}1617}16181619const T *next = text + item_offset;1620const T *end = next + item_length;1621while (next < end)1622{1623hb_codepoint_t u;1624const T *old_next = next;1625next = utf_t::next (next, end, &u, replacement);1626buffer->add (u, old_next - (const T *) text);1627}16281629/* Add post-context */1630buffer->clear_context (1);1631end = text + text_length;1632while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)1633{1634hb_codepoint_t u;1635next = utf_t::next (next, end, &u, replacement);1636buffer->context[1][buffer->context_len[1]++] = u;1637}16381639buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;1640}16411642/**1643* hb_buffer_add_utf8:1644* @buffer: An #hb_buffer_t1645* @text: (array length=text_length) (element-type uint8_t): An array of UTF-81646* characters to append.1647* @text_length: The length of the @text, or -1 if it is %NULL terminated.1648* @item_offset: The offset of the first character to add to the @buffer.1649* @item_length: The number of characters to add to the @buffer, or -1 for the1650* end of @text (assuming it is %NULL terminated).1651*1652* See hb_buffer_add_codepoints().1653*1654* Replaces invalid UTF-8 characters with the @buffer replacement code point,1655* see hb_buffer_set_replacement_codepoint().1656*1657* Since: 0.9.21658**/1659void1660hb_buffer_add_utf8 (hb_buffer_t *buffer,1661const char *text,1662int text_length,1663unsigned int item_offset,1664int item_length)1665{1666hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);1667}16681669/**1670* hb_buffer_add_utf16:1671* @buffer: An #hb_buffer_t1672* @text: (array length=text_length): An array of UTF-16 characters to append1673* @text_length: The length of the @text, or -1 if it is %NULL terminated1674* @item_offset: The offset of the first character to add to the @buffer1675* @item_length: The number of characters to add to the @buffer, or -1 for the1676* end of @text (assuming it is %NULL terminated)1677*1678* See hb_buffer_add_codepoints().1679*1680* Replaces invalid UTF-16 characters with the @buffer replacement code point,1681* see hb_buffer_set_replacement_codepoint().1682*1683* Since: 0.9.21684**/1685void1686hb_buffer_add_utf16 (hb_buffer_t *buffer,1687const uint16_t *text,1688int text_length,1689unsigned int item_offset,1690int item_length)1691{1692hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length);1693}16941695/**1696* hb_buffer_add_utf32:1697* @buffer: An #hb_buffer_t1698* @text: (array length=text_length): An array of UTF-32 characters to append1699* @text_length: The length of the @text, or -1 if it is %NULL terminated1700* @item_offset: The offset of the first character to add to the @buffer1701* @item_length: The number of characters to add to the @buffer, or -1 for the1702* end of @text (assuming it is %NULL terminated)1703*1704* See hb_buffer_add_codepoints().1705*1706* Replaces invalid UTF-32 characters with the @buffer replacement code point,1707* see hb_buffer_set_replacement_codepoint().1708*1709* Since: 0.9.21710**/1711void1712hb_buffer_add_utf32 (hb_buffer_t *buffer,1713const uint32_t *text,1714int text_length,1715unsigned int item_offset,1716int item_length)1717{1718hb_buffer_add_utf<hb_utf32_t> (buffer, text, text_length, item_offset, item_length);1719}17201721/**1722* hb_buffer_add_latin1:1723* @buffer: An #hb_buffer_t1724* @text: (array length=text_length) (element-type uint8_t): an array of UTF-81725* characters to append1726* @text_length: the length of the @text, or -1 if it is %NULL terminated1727* @item_offset: the offset of the first character to add to the @buffer1728* @item_length: the number of characters to add to the @buffer, or -1 for the1729* end of @text (assuming it is %NULL terminated)1730*1731* Similar to hb_buffer_add_codepoints(), but allows only access to first 2561732* Unicode code points that can fit in 8-bit strings.1733*1734* <note>Has nothing to do with non-Unicode Latin-1 encoding.</note>1735*1736* Since: 0.9.391737**/1738void1739hb_buffer_add_latin1 (hb_buffer_t *buffer,1740const uint8_t *text,1741int text_length,1742unsigned int item_offset,1743int item_length)1744{1745hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length);1746}17471748/**1749* hb_buffer_add_codepoints:1750* @buffer: a #hb_buffer_t to append characters to.1751* @text: (array length=text_length): an array of Unicode code points to append.1752* @text_length: the length of the @text, or -1 if it is %NULL terminated.1753* @item_offset: the offset of the first code point to add to the @buffer.1754* @item_length: the number of code points to add to the @buffer, or -1 for the1755* end of @text (assuming it is %NULL terminated).1756*1757* Appends characters from @text array to @buffer. The @item_offset is the1758* position of the first character from @text that will be appended, and1759* @item_length is the number of character. When shaping part of a larger text1760* (e.g. a run of text from a paragraph), instead of passing just the substring1761* corresponding to the run, it is preferable to pass the whole1762* paragraph and specify the run start and length as @item_offset and1763* @item_length, respectively, to give HarfBuzz the full context to be able,1764* for example, to do cross-run Arabic shaping or properly handle combining1765* marks at stat of run.1766*1767* This function does not check the validity of @text, it is up to the caller1768* to ensure it contains a valid Unicode code points.1769*1770* Since: 0.9.311771**/1772void1773hb_buffer_add_codepoints (hb_buffer_t *buffer,1774const hb_codepoint_t *text,1775int text_length,1776unsigned int item_offset,1777int item_length)1778{1779hb_buffer_add_utf<hb_utf32_novalidate_t> (buffer, text, text_length, item_offset, item_length);1780}178117821783/**1784* hb_buffer_append:1785* @buffer: An #hb_buffer_t1786* @source: source #hb_buffer_t1787* @start: start index into source buffer to copy. Use 0 to copy from start of buffer.1788* @end: end index into source buffer to copy. Use @HB_FEATURE_GLOBAL_END to copy to end of buffer.1789*1790* Append (part of) contents of another buffer to this buffer.1791*1792* Since: 1.5.01793**/1794HB_EXTERN void1795hb_buffer_append (hb_buffer_t *buffer,1796const hb_buffer_t *source,1797unsigned int start,1798unsigned int end)1799{1800assert (!buffer->have_output && !source->have_output);1801assert (buffer->have_positions == source->have_positions ||1802!buffer->len || !source->len);1803assert (buffer->content_type == source->content_type ||1804!buffer->len || !source->len);18051806if (end > source->len)1807end = source->len;1808if (start > end)1809start = end;1810if (start == end)1811return;18121813if (buffer->len + (end - start) < buffer->len) /* Overflows. */1814{1815buffer->successful = false;1816return;1817}18181819unsigned int orig_len = buffer->len;1820hb_buffer_set_length (buffer, buffer->len + (end - start));1821if (unlikely (!buffer->successful))1822return;18231824if (!orig_len)1825buffer->content_type = source->content_type;1826if (!buffer->have_positions && source->have_positions)1827buffer->clear_positions ();18281829hb_segment_properties_overlay (&buffer->props, &source->props);18301831memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));1832if (buffer->have_positions)1833memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));18341835if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)1836{1837/* See similar logic in add_utf. */18381839/* pre-context */1840if (!orig_len && start + source->context_len[0] > 0)1841{1842buffer->clear_context (0);1843while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH)1844buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint;1845for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++)1846buffer->context[0][buffer->context_len[0]++] = source->context[0][i];1847}18481849/* post-context */1850buffer->clear_context (1);1851while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH)1852buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint;1853for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++)1854buffer->context[1][buffer->context_len[1]++] = source->context[1][i];1855}1856}185718581859static int1860compare_info_codepoint (const hb_glyph_info_t *pa,1861const hb_glyph_info_t *pb)1862{1863return (int) pb->codepoint - (int) pa->codepoint;1864}18651866static inline void1867normalize_glyphs_cluster (hb_buffer_t *buffer,1868unsigned int start,1869unsigned int end,1870bool backward)1871{1872hb_glyph_position_t *pos = buffer->pos;18731874/* Total cluster advance */1875hb_position_t total_x_advance = 0, total_y_advance = 0;1876for (unsigned int i = start; i < end; i++)1877{1878total_x_advance += pos[i].x_advance;1879total_y_advance += pos[i].y_advance;1880}18811882hb_position_t x_advance = 0, y_advance = 0;1883for (unsigned int i = start; i < end; i++)1884{1885pos[i].x_offset += x_advance;1886pos[i].y_offset += y_advance;18871888x_advance += pos[i].x_advance;1889y_advance += pos[i].y_advance;18901891pos[i].x_advance = 0;1892pos[i].y_advance = 0;1893}18941895if (backward)1896{1897/* Transfer all cluster advance to the last glyph. */1898pos[end - 1].x_advance = total_x_advance;1899pos[end - 1].y_advance = total_y_advance;19001901hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);1902} else {1903/* Transfer all cluster advance to the first glyph. */1904pos[start].x_advance += total_x_advance;1905pos[start].y_advance += total_y_advance;1906for (unsigned int i = start + 1; i < end; i++) {1907pos[i].x_offset -= total_x_advance;1908pos[i].y_offset -= total_y_advance;1909}1910hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);1911}1912}19131914/**1915* hb_buffer_normalize_glyphs:1916* @buffer: An #hb_buffer_t1917*1918* Reorders a glyph buffer to have canonical in-cluster glyph order / position.1919* The resulting clusters should behave identical to pre-reordering clusters.1920*1921* <note>This has nothing to do with Unicode normalization.</note>1922*1923* Since: 0.9.21924**/1925void1926hb_buffer_normalize_glyphs (hb_buffer_t *buffer)1927{1928assert (buffer->have_positions);19291930buffer->assert_glyphs ();19311932bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);19331934foreach_cluster (buffer, start, end)1935normalize_glyphs_cluster (buffer, start, end, backward);1936}19371938void1939hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *))1940{1941assert (!have_positions);1942for (unsigned int i = start + 1; i < end; i++)1943{1944unsigned int j = i;1945while (j > start && compar (&info[j - 1], &info[i]) > 0)1946j--;1947if (i == j)1948continue;1949/* Move item i to occupy place for item j, shift what's in between. */1950merge_clusters (j, i + 1);1951{1952hb_glyph_info_t t = info[i];1953memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t));1954info[j] = t;1955}1956}1957}195819591960/*1961* Comparing buffers.1962*/19631964/**1965* hb_buffer_diff:1966* @buffer: a buffer.1967* @reference: other buffer to compare to.1968* @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.1969* @position_fuzz: allowed absolute difference in position values.1970*1971* If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT1972* and #HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most1973* callers if just comparing two buffers is needed.1974*1975* Since: 1.5.01976**/1977hb_buffer_diff_flags_t1978hb_buffer_diff (hb_buffer_t *buffer,1979hb_buffer_t *reference,1980hb_codepoint_t dottedcircle_glyph,1981unsigned int position_fuzz)1982{1983if (buffer->content_type != reference->content_type && buffer->len && reference->len)1984return HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH;19851986hb_buffer_diff_flags_t result = HB_BUFFER_DIFF_FLAG_EQUAL;1987bool contains = dottedcircle_glyph != (hb_codepoint_t) -1;19881989unsigned int count = reference->len;19901991if (buffer->len != count)1992{1993/*1994* we can't compare glyph-by-glyph, but we do want to know if there1995* are .notdef or dottedcircle glyphs present in the reference buffer1996*/1997const hb_glyph_info_t *info = reference->info;1998unsigned int i;1999for (i = 0; i < count; i++)2000{2001if (contains && info[i].codepoint == dottedcircle_glyph)2002result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;2003if (contains && info[i].codepoint == 0)2004result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;2005}2006result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;2007return hb_buffer_diff_flags_t (result);2008}20092010if (!count)2011return hb_buffer_diff_flags_t (result);20122013const hb_glyph_info_t *buf_info = buffer->info;2014const hb_glyph_info_t *ref_info = reference->info;2015for (unsigned int i = 0; i < count; i++)2016{2017if (buf_info->codepoint != ref_info->codepoint)2018result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;2019if (buf_info->cluster != ref_info->cluster)2020result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;2021if ((buf_info->mask & ~ref_info->mask & HB_GLYPH_FLAG_DEFINED))2022result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;2023if (contains && ref_info->codepoint == dottedcircle_glyph)2024result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;2025if (contains && ref_info->codepoint == 0)2026result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;2027buf_info++;2028ref_info++;2029}20302031if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)2032{2033assert (buffer->have_positions);2034const hb_glyph_position_t *buf_pos = buffer->pos;2035const hb_glyph_position_t *ref_pos = reference->pos;2036for (unsigned int i = 0; i < count; i++)2037{2038if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||2039(unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||2040(unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||2041(unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)2042{2043result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;2044break;2045}2046buf_pos++;2047ref_pos++;2048}2049}20502051return result;2052}205320542055/*2056* Debugging.2057*/20582059#ifndef HB_NO_BUFFER_MESSAGE2060/**2061* hb_buffer_set_message_func:2062* @buffer: An #hb_buffer_t2063* @func: (closure user_data) (destroy destroy) (scope notified): Callback function2064* @user_data: (nullable): Data to pass to @func2065* @destroy: (nullable): The function to call when @user_data is not needed anymore2066*2067* Sets the implementation function for #hb_buffer_message_func_t.2068*2069* Since: 1.1.32070**/2071void2072hb_buffer_set_message_func (hb_buffer_t *buffer,2073hb_buffer_message_func_t func,2074void *user_data, hb_destroy_func_t destroy)2075{2076if (buffer->message_destroy)2077buffer->message_destroy (buffer->message_data);20782079if (func) {2080buffer->message_func = func;2081buffer->message_data = user_data;2082buffer->message_destroy = destroy;2083} else {2084buffer->message_func = nullptr;2085buffer->message_data = nullptr;2086buffer->message_destroy = nullptr;2087}2088}2089bool2090hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)2091{2092char buf[100];2093vsnprintf (buf, sizeof (buf), fmt, ap);2094return (bool) this->message_func (this, font, buf, this->message_data);2095}2096#endif209720982099