Path: blob/master/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc
41149 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 ^84(unsigned int) p->script ^85(intptr_t) (p->language);86}87888990/* Here is how the buffer works internally:91*92* There are two info pointers: info and out_info. They always have93* the same allocated size, but different lengths.94*95* As an optimization, both info and out_info may point to the96* same piece of memory, which is owned by info. This remains the97* case as long as out_len doesn't exceed i at any time.98* In that case, swap_buffers() is no-op and the glyph operations operate99* mostly in-place.100*101* As soon as out_info gets longer than info, out_info is moved over102* to an alternate buffer (which we reuse the pos buffer for!), and its103* current contents (out_len entries) are copied to the new place.104* This should all remain transparent to the user. swap_buffers() then105* switches info and out_info.106*/107108109110/* Internal API */111112bool113hb_buffer_t::enlarge (unsigned int size)114{115if (unlikely (!successful))116return false;117if (unlikely (size > max_len))118{119successful = false;120return false;121}122123unsigned int new_allocated = allocated;124hb_glyph_position_t *new_pos = nullptr;125hb_glyph_info_t *new_info = nullptr;126bool separate_out = out_info != info;127128if (unlikely (hb_unsigned_mul_overflows (size, sizeof (info[0]))))129goto done;130131while (size >= new_allocated)132new_allocated += (new_allocated >> 1) + 32;133134static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");135if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))136goto done;137138new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));139new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));140141done:142if (unlikely (!new_pos || !new_info))143successful = false;144145if (likely (new_pos))146pos = new_pos;147148if (likely (new_info))149info = new_info;150151out_info = separate_out ? (hb_glyph_info_t *) pos : info;152if (likely (successful))153allocated = new_allocated;154155return likely (successful);156}157158bool159hb_buffer_t::make_room_for (unsigned int num_in,160unsigned int num_out)161{162if (unlikely (!ensure (out_len + num_out))) return false;163164if (out_info == info &&165out_len + num_out > idx + num_in)166{167assert (have_output);168169out_info = (hb_glyph_info_t *) pos;170memcpy (out_info, info, out_len * sizeof (out_info[0]));171}172173return true;174}175176bool177hb_buffer_t::shift_forward (unsigned int count)178{179assert (have_output);180if (unlikely (!ensure (len + count))) return false;181182memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));183if (idx + count > len)184{185/* Under memory failure we might expose this area. At least186* clean it up. Oh well...187*188* Ideally, we should at least set Default_Ignorable bits on189* these, as well as consistent cluster values. But the former190* is layering violation... */191memset (info + len, 0, (idx + count - len) * sizeof (info[0]));192}193len += count;194idx += count;195196return true;197}198199hb_buffer_t::scratch_buffer_t *200hb_buffer_t::get_scratch_buffer (unsigned int *size)201{202have_output = false;203have_positions = false;204205out_len = 0;206out_info = info;207208assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);209*size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);210return (scratch_buffer_t *) (void *) pos;211}212213214215/* HarfBuzz-Internal API */216217void218hb_buffer_t::reset ()219{220hb_unicode_funcs_destroy (unicode);221unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());222flags = HB_BUFFER_FLAG_DEFAULT;223replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;224invisible = 0;225226clear ();227}228229void230hb_buffer_t::clear ()231{232hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;233props = default_props;234scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;235236content_type = HB_BUFFER_CONTENT_TYPE_INVALID;237successful = true;238have_output = false;239have_positions = false;240241idx = 0;242len = 0;243out_len = 0;244out_info = info;245246serial = 0;247248memset (context, 0, sizeof context);249memset (context_len, 0, sizeof context_len);250251deallocate_var_all ();252}253254void255hb_buffer_t::add (hb_codepoint_t codepoint,256unsigned int cluster)257{258hb_glyph_info_t *glyph;259260if (unlikely (!ensure (len + 1))) return;261262glyph = &info[len];263264memset (glyph, 0, sizeof (*glyph));265glyph->codepoint = codepoint;266glyph->mask = 0;267glyph->cluster = cluster;268269len++;270}271272void273hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)274{275if (unlikely (!ensure (len + 1))) return;276277info[len] = glyph_info;278279len++;280}281282283void284hb_buffer_t::remove_output ()285{286have_output = false;287have_positions = false;288289out_len = 0;290out_info = info;291}292293void294hb_buffer_t::clear_output ()295{296have_output = true;297have_positions = false;298299out_len = 0;300out_info = info;301}302303void304hb_buffer_t::clear_positions ()305{306have_output = false;307have_positions = true;308309out_len = 0;310out_info = info;311312hb_memset (pos, 0, sizeof (pos[0]) * len);313}314315void316hb_buffer_t::swap_buffers ()317{318if (unlikely (!successful)) return;319320assert (idx <= len);321if (unlikely (!next_glyphs (len - idx))) return;322323assert (have_output);324have_output = false;325326if (out_info != info)327{328hb_glyph_info_t *tmp;329tmp = info;330info = out_info;331out_info = tmp;332333pos = (hb_glyph_position_t *) out_info;334}335336unsigned int tmp;337tmp = len;338len = out_len;339out_len = tmp;340341idx = 0;342}343344bool345hb_buffer_t::move_to (unsigned int i)346{347if (!have_output)348{349assert (i <= len);350idx = i;351return true;352}353if (unlikely (!successful))354return false;355356assert (i <= out_len + (len - idx));357358if (out_len < i)359{360unsigned int count = i - out_len;361if (unlikely (!make_room_for (count, count))) return false;362363memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));364idx += count;365out_len += count;366}367else if (out_len > i)368{369/* Tricky part: rewinding... */370unsigned int count = out_len - i;371372/* This will blow in our face if memory allocation fails later373* in this same lookup...374*375* We used to shift with extra 32 items, instead of the 0 below.376* But that would leave empty slots in the buffer in case of allocation377* failures. Setting to zero for now to avoid other problems (see378* comments in shift_forward(). This can cause O(N^2) behavior more379* severely than adding 32 empty slots can... */380if (unlikely (idx < count && !shift_forward (count + 0))) return false;381382assert (idx >= count);383384idx -= count;385out_len -= count;386memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));387}388389return true;390}391392393void394hb_buffer_t::set_masks (hb_mask_t value,395hb_mask_t mask,396unsigned int cluster_start,397unsigned int cluster_end)398{399hb_mask_t not_mask = ~mask;400value &= mask;401402if (!mask)403return;404405unsigned int count = len;406for (unsigned int i = 0; i < count; i++)407if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)408info[i].mask = (info[i].mask & not_mask) | value;409}410411void412hb_buffer_t::reverse_range (unsigned int start,413unsigned int end)414{415if (end - start < 2)416return;417418hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end);419420if (have_positions) {421hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end);422}423}424425void426hb_buffer_t::reverse ()427{428if (unlikely (!len))429return;430431reverse_range (0, len);432}433434void435hb_buffer_t::reverse_clusters ()436{437unsigned int i, start, count, last_cluster;438439if (unlikely (!len))440return;441442reverse ();443444count = len;445start = 0;446last_cluster = info[0].cluster;447for (i = 1; i < count; i++) {448if (last_cluster != info[i].cluster) {449reverse_range (start, i);450start = i;451last_cluster = info[i].cluster;452}453}454reverse_range (start, i);455}456457void458hb_buffer_t::merge_clusters_impl (unsigned int start,459unsigned int end)460{461if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)462{463unsafe_to_break (start, end);464return;465}466467unsigned int cluster = info[start].cluster;468469for (unsigned int i = start + 1; i < end; i++)470cluster = hb_min (cluster, info[i].cluster);471472/* Extend end */473while (end < len && info[end - 1].cluster == info[end].cluster)474end++;475476/* Extend start */477while (idx < start && info[start - 1].cluster == info[start].cluster)478start--;479480/* If we hit the start of buffer, continue in out-buffer. */481if (idx == start)482for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)483set_cluster (out_info[i - 1], cluster);484485for (unsigned int i = start; i < end; i++)486set_cluster (info[i], cluster);487}488void489hb_buffer_t::merge_out_clusters (unsigned int start,490unsigned int end)491{492if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)493return;494495if (unlikely (end - start < 2))496return;497498unsigned int cluster = out_info[start].cluster;499500for (unsigned int i = start + 1; i < end; i++)501cluster = hb_min (cluster, out_info[i].cluster);502503/* Extend start */504while (start && out_info[start - 1].cluster == out_info[start].cluster)505start--;506507/* Extend end */508while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)509end++;510511/* If we hit the end of out-buffer, continue in buffer. */512if (end == out_len)513for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)514set_cluster (info[i], cluster);515516for (unsigned int i = start; i < end; i++)517set_cluster (out_info[i], cluster);518}519void520hb_buffer_t::delete_glyph ()521{522/* The logic here is duplicated in hb_ot_hide_default_ignorables(). */523524unsigned int cluster = info[idx].cluster;525if (idx + 1 < len && cluster == info[idx + 1].cluster)526{527/* Cluster survives; do nothing. */528goto done;529}530531if (out_len)532{533/* Merge cluster backward. */534if (cluster < out_info[out_len - 1].cluster)535{536unsigned int mask = info[idx].mask;537unsigned int old_cluster = out_info[out_len - 1].cluster;538for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)539set_cluster (out_info[i - 1], cluster, mask);540}541goto done;542}543544if (idx + 1 < len)545{546/* Merge cluster forward. */547merge_clusters (idx, idx + 2);548goto done;549}550551done:552skip_glyph ();553}554555void556hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end)557{558unsigned int cluster = UINT_MAX;559cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster);560_unsafe_to_break_set_mask (info, start, end, cluster);561}562void563hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end)564{565if (!have_output)566{567unsafe_to_break_impl (start, end);568return;569}570571assert (start <= out_len);572assert (idx <= end);573574unsigned int cluster = UINT_MAX;575cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster);576cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster);577_unsafe_to_break_set_mask (out_info, start, out_len, cluster);578_unsafe_to_break_set_mask (info, idx, end, cluster);579}580581void582hb_buffer_t::guess_segment_properties ()583{584assert_unicode ();585586/* If script is set to INVALID, guess from buffer contents */587if (props.script == HB_SCRIPT_INVALID) {588for (unsigned int i = 0; i < len; i++) {589hb_script_t script = unicode->script (info[i].codepoint);590if (likely (script != HB_SCRIPT_COMMON &&591script != HB_SCRIPT_INHERITED &&592script != HB_SCRIPT_UNKNOWN)) {593props.script = script;594break;595}596}597}598599/* If direction is set to INVALID, guess from script */600if (props.direction == HB_DIRECTION_INVALID) {601props.direction = hb_script_get_horizontal_direction (props.script);602if (props.direction == HB_DIRECTION_INVALID)603props.direction = HB_DIRECTION_LTR;604}605606/* If language is not set, use default language from locale */607if (props.language == HB_LANGUAGE_INVALID) {608/* TODO get_default_for_script? using $LANGUAGE */609props.language = hb_language_get_default ();610}611}612613614/* Public API */615616DEFINE_NULL_INSTANCE (hb_buffer_t) =617{618HB_OBJECT_HEADER_STATIC,619620const_cast<hb_unicode_funcs_t *> (&_hb_Null_hb_unicode_funcs_t),621HB_BUFFER_FLAG_DEFAULT,622HB_BUFFER_CLUSTER_LEVEL_DEFAULT,623HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,6240, /* invisible */625HB_BUFFER_SCRATCH_FLAG_DEFAULT,626HB_BUFFER_MAX_LEN_DEFAULT,627HB_BUFFER_MAX_OPS_DEFAULT,628629HB_BUFFER_CONTENT_TYPE_INVALID,630HB_SEGMENT_PROPERTIES_DEFAULT,631false, /* successful */632true, /* have_output */633true /* have_positions */634635/* Zero is good enough for everything else. */636};637638639/**640* hb_buffer_create: (Xconstructor)641*642* Creates a new #hb_buffer_t with all properties to defaults.643*644* Return value: (transfer full):645* A newly allocated #hb_buffer_t with a reference count of 1. The initial646* reference count should be released with hb_buffer_destroy() when you are done647* using the #hb_buffer_t. This function never returns %NULL. If memory cannot648* be allocated, a special #hb_buffer_t object will be returned on which649* hb_buffer_allocation_successful() returns %false.650*651* Since: 0.9.2652**/653hb_buffer_t *654hb_buffer_create ()655{656hb_buffer_t *buffer;657658if (!(buffer = hb_object_create<hb_buffer_t> ()))659return hb_buffer_get_empty ();660661buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;662buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;663664buffer->reset ();665666return buffer;667}668669/**670* hb_buffer_get_empty:671*672* Fetches an empty #hb_buffer_t.673*674* Return value: (transfer full): The empty buffer675*676* Since: 0.9.2677**/678hb_buffer_t *679hb_buffer_get_empty ()680{681return const_cast<hb_buffer_t *> (&Null (hb_buffer_t));682}683684/**685* hb_buffer_reference: (skip)686* @buffer: An #hb_buffer_t687*688* Increases the reference count on @buffer by one. This prevents @buffer from689* being destroyed until a matching call to hb_buffer_destroy() is made.690*691* Return value: (transfer full):692* The referenced #hb_buffer_t.693*694* Since: 0.9.2695**/696hb_buffer_t *697hb_buffer_reference (hb_buffer_t *buffer)698{699return hb_object_reference (buffer);700}701702/**703* hb_buffer_destroy: (skip)704* @buffer: An #hb_buffer_t705*706* Deallocate the @buffer.707* Decreases the reference count on @buffer by one. If the result is zero, then708* @buffer and all associated resources are freed. See hb_buffer_reference().709*710* Since: 0.9.2711**/712void713hb_buffer_destroy (hb_buffer_t *buffer)714{715if (!hb_object_destroy (buffer)) return;716717hb_unicode_funcs_destroy (buffer->unicode);718719free (buffer->info);720free (buffer->pos);721#ifndef HB_NO_BUFFER_MESSAGE722if (buffer->message_destroy)723buffer->message_destroy (buffer->message_data);724#endif725726free (buffer);727}728729/**730* hb_buffer_set_user_data: (skip)731* @buffer: An #hb_buffer_t732* @key: The user-data key733* @data: A pointer to the user data734* @destroy: (nullable): A callback to call when @data is not needed anymore735* @replace: Whether to replace an existing data with the same key736*737* Attaches a user-data key/data pair to the specified buffer.738*739* Return value: %true if success, %false otherwise740*741* Since: 0.9.2742**/743hb_bool_t744hb_buffer_set_user_data (hb_buffer_t *buffer,745hb_user_data_key_t *key,746void * data,747hb_destroy_func_t destroy,748hb_bool_t replace)749{750return hb_object_set_user_data (buffer, key, data, destroy, replace);751}752753/**754* hb_buffer_get_user_data: (skip)755* @buffer: An #hb_buffer_t756* @key: The user-data key to query757*758* Fetches the user data associated with the specified key,759* attached to the specified buffer.760*761* Return value: (transfer none): A pointer to the user data762*763* Since: 0.9.2764**/765void *766hb_buffer_get_user_data (hb_buffer_t *buffer,767hb_user_data_key_t *key)768{769return hb_object_get_user_data (buffer, key);770}771772773/**774* hb_buffer_set_content_type:775* @buffer: An #hb_buffer_t776* @content_type: The type of buffer contents to set777*778* Sets the type of @buffer contents. Buffers are either empty, contain779* characters (before shaping), or contain glyphs (the result of shaping).780*781* Since: 0.9.5782**/783void784hb_buffer_set_content_type (hb_buffer_t *buffer,785hb_buffer_content_type_t content_type)786{787buffer->content_type = content_type;788}789790/**791* hb_buffer_get_content_type:792* @buffer: An #hb_buffer_t793*794* Fetches the type of @buffer contents. Buffers are either empty, contain795* characters (before shaping), or contain glyphs (the result of shaping).796*797* Return value:798* The type of @buffer contents799*800* Since: 0.9.5801**/802hb_buffer_content_type_t803hb_buffer_get_content_type (hb_buffer_t *buffer)804{805return buffer->content_type;806}807808809/**810* hb_buffer_set_unicode_funcs:811* @buffer: An #hb_buffer_t812* @unicode_funcs: The Unicode-functions structure813*814* Sets the Unicode-functions structure of a buffer to815* @unicode_funcs.816*817* Since: 0.9.2818**/819void820hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,821hb_unicode_funcs_t *unicode_funcs)822{823if (unlikely (hb_object_is_immutable (buffer)))824return;825826if (!unicode_funcs)827unicode_funcs = hb_unicode_funcs_get_default ();828829hb_unicode_funcs_reference (unicode_funcs);830hb_unicode_funcs_destroy (buffer->unicode);831buffer->unicode = unicode_funcs;832}833834/**835* hb_buffer_get_unicode_funcs:836* @buffer: An #hb_buffer_t837*838* Fetches the Unicode-functions structure of a buffer.839*840* Return value: The Unicode-functions structure841*842* Since: 0.9.2843**/844hb_unicode_funcs_t *845hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)846{847return buffer->unicode;848}849850/**851* hb_buffer_set_direction:852* @buffer: An #hb_buffer_t853* @direction: the #hb_direction_t of the @buffer854*855* Set the text flow direction of the buffer. No shaping can happen without856* setting @buffer direction, and it controls the visual direction for the857* output glyphs; for RTL direction the glyphs will be reversed. Many layout858* features depend on the proper setting of the direction, for example,859* reversing RTL text before shaping, then shaping with LTR direction is not860* the same as keeping the text in logical order and shaping with RTL861* direction.862*863* Since: 0.9.2864**/865void866hb_buffer_set_direction (hb_buffer_t *buffer,867hb_direction_t direction)868869{870if (unlikely (hb_object_is_immutable (buffer)))871return;872873buffer->props.direction = direction;874}875876/**877* hb_buffer_get_direction:878* @buffer: An #hb_buffer_t879*880* See hb_buffer_set_direction()881*882* Return value:883* The direction of the @buffer.884*885* Since: 0.9.2886**/887hb_direction_t888hb_buffer_get_direction (hb_buffer_t *buffer)889{890return buffer->props.direction;891}892893/**894* hb_buffer_set_script:895* @buffer: An #hb_buffer_t896* @script: An #hb_script_t to set.897*898* Sets the script of @buffer to @script.899*900* Script is crucial for choosing the proper shaping behaviour for scripts that901* require it (e.g. Arabic) and the which OpenType features defined in the font902* to be applied.903*904* You can pass one of the predefined #hb_script_t values, or use905* hb_script_from_string() or hb_script_from_iso15924_tag() to get the906* corresponding script from an ISO 15924 script tag.907*908* Since: 0.9.2909**/910void911hb_buffer_set_script (hb_buffer_t *buffer,912hb_script_t script)913{914if (unlikely (hb_object_is_immutable (buffer)))915return;916917buffer->props.script = script;918}919920/**921* hb_buffer_get_script:922* @buffer: An #hb_buffer_t923*924* Fetches the script of @buffer.925*926* Return value:927* The #hb_script_t of the @buffer928*929* Since: 0.9.2930**/931hb_script_t932hb_buffer_get_script (hb_buffer_t *buffer)933{934return buffer->props.script;935}936937/**938* hb_buffer_set_language:939* @buffer: An #hb_buffer_t940* @language: An hb_language_t to set941*942* Sets the language of @buffer to @language.943*944* Languages are crucial for selecting which OpenType feature to apply to the945* buffer which can result in applying language-specific behaviour. Languages946* are orthogonal to the scripts, and though they are related, they are947* different concepts and should not be confused with each other.948*949* Use hb_language_from_string() to convert from BCP 47 language tags to950* #hb_language_t.951*952* Since: 0.9.2953**/954void955hb_buffer_set_language (hb_buffer_t *buffer,956hb_language_t language)957{958if (unlikely (hb_object_is_immutable (buffer)))959return;960961buffer->props.language = language;962}963964/**965* hb_buffer_get_language:966* @buffer: An #hb_buffer_t967*968* See hb_buffer_set_language().969*970* Return value: (transfer none):971* The #hb_language_t of the buffer. Must not be freed by the caller.972*973* Since: 0.9.2974**/975hb_language_t976hb_buffer_get_language (hb_buffer_t *buffer)977{978return buffer->props.language;979}980981/**982* hb_buffer_set_segment_properties:983* @buffer: An #hb_buffer_t984* @props: An #hb_segment_properties_t to use985*986* Sets the segment properties of the buffer, a shortcut for calling987* hb_buffer_set_direction(), hb_buffer_set_script() and988* hb_buffer_set_language() individually.989*990* Since: 0.9.7991**/992void993hb_buffer_set_segment_properties (hb_buffer_t *buffer,994const hb_segment_properties_t *props)995{996if (unlikely (hb_object_is_immutable (buffer)))997return;998999buffer->props = *props;1000}10011002/**1003* hb_buffer_get_segment_properties:1004* @buffer: An #hb_buffer_t1005* @props: (out): The output #hb_segment_properties_t1006*1007* Sets @props to the #hb_segment_properties_t of @buffer.1008*1009* Since: 0.9.71010**/1011void1012hb_buffer_get_segment_properties (hb_buffer_t *buffer,1013hb_segment_properties_t *props)1014{1015*props = buffer->props;1016}101710181019/**1020* hb_buffer_set_flags:1021* @buffer: An #hb_buffer_t1022* @flags: The buffer flags to set1023*1024* Sets @buffer flags to @flags. See #hb_buffer_flags_t.1025*1026* Since: 0.9.71027**/1028void1029hb_buffer_set_flags (hb_buffer_t *buffer,1030hb_buffer_flags_t flags)1031{1032if (unlikely (hb_object_is_immutable (buffer)))1033return;10341035buffer->flags = flags;1036}10371038/**1039* hb_buffer_get_flags:1040* @buffer: An #hb_buffer_t1041*1042* Fetches the #hb_buffer_flags_t of @buffer.1043*1044* Return value:1045* The @buffer flags1046*1047* Since: 0.9.71048**/1049hb_buffer_flags_t1050hb_buffer_get_flags (hb_buffer_t *buffer)1051{1052return buffer->flags;1053}10541055/**1056* hb_buffer_set_cluster_level:1057* @buffer: An #hb_buffer_t1058* @cluster_level: The cluster level to set on the buffer1059*1060* Sets the cluster level of a buffer. The #hb_buffer_cluster_level_t1061* dictates one aspect of how HarfBuzz will treat non-base characters1062* during shaping.1063*1064* Since: 0.9.421065**/1066void1067hb_buffer_set_cluster_level (hb_buffer_t *buffer,1068hb_buffer_cluster_level_t cluster_level)1069{1070if (unlikely (hb_object_is_immutable (buffer)))1071return;10721073buffer->cluster_level = cluster_level;1074}10751076/**1077* hb_buffer_get_cluster_level:1078* @buffer: An #hb_buffer_t1079*1080* Fetches the cluster level of a buffer. The #hb_buffer_cluster_level_t1081* dictates one aspect of how HarfBuzz will treat non-base characters1082* during shaping.1083*1084* Return value: The cluster level of @buffer1085*1086* Since: 0.9.421087**/1088hb_buffer_cluster_level_t1089hb_buffer_get_cluster_level (hb_buffer_t *buffer)1090{1091return buffer->cluster_level;1092}109310941095/**1096* hb_buffer_set_replacement_codepoint:1097* @buffer: An #hb_buffer_t1098* @replacement: the replacement #hb_codepoint_t1099*1100* Sets the #hb_codepoint_t that replaces invalid entries for a given encoding1101* when adding text to @buffer.1102*1103* Default is #HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.1104*1105* Since: 0.9.311106**/1107void1108hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,1109hb_codepoint_t replacement)1110{1111if (unlikely (hb_object_is_immutable (buffer)))1112return;11131114buffer->replacement = replacement;1115}11161117/**1118* hb_buffer_get_replacement_codepoint:1119* @buffer: An #hb_buffer_t1120*1121* Fetches the #hb_codepoint_t that replaces invalid entries for a given encoding1122* when adding text to @buffer.1123*1124* Return value:1125* The @buffer replacement #hb_codepoint_t1126*1127* Since: 0.9.311128**/1129hb_codepoint_t1130hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)1131{1132return buffer->replacement;1133}113411351136/**1137* hb_buffer_set_invisible_glyph:1138* @buffer: An #hb_buffer_t1139* @invisible: the invisible #hb_codepoint_t1140*1141* Sets the #hb_codepoint_t that replaces invisible characters in1142* the shaping result. If set to zero (default), the glyph for the1143* U+0020 SPACE character is used. Otherwise, this value is used1144* verbatim.1145*1146* Since: 2.0.01147**/1148void1149hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,1150hb_codepoint_t invisible)1151{1152if (unlikely (hb_object_is_immutable (buffer)))1153return;11541155buffer->invisible = invisible;1156}11571158/**1159* hb_buffer_get_invisible_glyph:1160* @buffer: An #hb_buffer_t1161*1162* See hb_buffer_set_invisible_glyph().1163*1164* Return value:1165* The @buffer invisible #hb_codepoint_t1166*1167* Since: 2.0.01168**/1169hb_codepoint_t1170hb_buffer_get_invisible_glyph (hb_buffer_t *buffer)1171{1172return buffer->invisible;1173}117411751176/**1177* hb_buffer_reset:1178* @buffer: An #hb_buffer_t1179*1180* Resets the buffer to its initial status, as if it was just newly created1181* with hb_buffer_create().1182*1183* Since: 0.9.21184**/1185void1186hb_buffer_reset (hb_buffer_t *buffer)1187{1188if (unlikely (hb_object_is_immutable (buffer)))1189return;11901191buffer->reset ();1192}11931194/**1195* hb_buffer_clear_contents:1196* @buffer: An #hb_buffer_t1197*1198* Similar to hb_buffer_reset(), but does not clear the Unicode functions and1199* the replacement code point.1200*1201* Since: 0.9.111202**/1203void1204hb_buffer_clear_contents (hb_buffer_t *buffer)1205{1206if (unlikely (hb_object_is_immutable (buffer)))1207return;12081209buffer->clear ();1210}12111212/**1213* hb_buffer_pre_allocate:1214* @buffer: An #hb_buffer_t1215* @size: Number of items to pre allocate.1216*1217* Pre allocates memory for @buffer to fit at least @size number of items.1218*1219* Return value:1220* %true if @buffer memory allocation succeeded, %false otherwise1221*1222* Since: 0.9.21223**/1224hb_bool_t1225hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)1226{1227return buffer->ensure (size);1228}12291230/**1231* hb_buffer_allocation_successful:1232* @buffer: An #hb_buffer_t1233*1234* Check if allocating memory for the buffer succeeded.1235*1236* Return value:1237* %true if @buffer memory allocation succeeded, %false otherwise.1238*1239* Since: 0.9.21240**/1241hb_bool_t1242hb_buffer_allocation_successful (hb_buffer_t *buffer)1243{1244return buffer->successful;1245}12461247/**1248* hb_buffer_add:1249* @buffer: An #hb_buffer_t1250* @codepoint: A Unicode code point.1251* @cluster: The cluster value of @codepoint.1252*1253* Appends a character with the Unicode value of @codepoint to @buffer, and1254* gives it the initial cluster value of @cluster. Clusters can be any thing1255* the client wants, they are usually used to refer to the index of the1256* character in the input text stream and are output in1257* #hb_glyph_info_t.cluster field.1258*1259* This function does not check the validity of @codepoint, it is up to the1260* caller to ensure it is a valid Unicode code point.1261*1262* Since: 0.9.71263**/1264void1265hb_buffer_add (hb_buffer_t *buffer,1266hb_codepoint_t codepoint,1267unsigned int cluster)1268{1269buffer->add (codepoint, cluster);1270buffer->clear_context (1);1271}12721273/**1274* hb_buffer_set_length:1275* @buffer: An #hb_buffer_t1276* @length: The new length of @buffer1277*1278* Similar to hb_buffer_pre_allocate(), but clears any new items added at the1279* end.1280*1281* Return value:1282* %true if @buffer memory allocation succeeded, %false otherwise.1283*1284* Since: 0.9.21285**/1286hb_bool_t1287hb_buffer_set_length (hb_buffer_t *buffer,1288unsigned int length)1289{1290if (unlikely (hb_object_is_immutable (buffer)))1291return length == 0;12921293if (unlikely (!buffer->ensure (length)))1294return false;12951296/* Wipe the new space */1297if (length > buffer->len) {1298memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));1299if (buffer->have_positions)1300memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));1301}13021303buffer->len = length;13041305if (!length)1306{1307buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;1308buffer->clear_context (0);1309}1310buffer->clear_context (1);13111312return true;1313}13141315/**1316* hb_buffer_get_length:1317* @buffer: An #hb_buffer_t1318*1319* Returns the number of items in the buffer.1320*1321* Return value:1322* The @buffer length.1323* The value valid as long as buffer has not been modified.1324*1325* Since: 0.9.21326**/1327unsigned int1328hb_buffer_get_length (hb_buffer_t *buffer)1329{1330return buffer->len;1331}13321333/**1334* hb_buffer_get_glyph_infos:1335* @buffer: An #hb_buffer_t1336* @length: (out): The output-array length.1337*1338* Returns @buffer glyph information array. Returned pointer1339* is valid as long as @buffer contents are not modified.1340*1341* Return value: (transfer none) (array length=length):1342* The @buffer glyph information array.1343* The value valid as long as buffer has not been modified.1344*1345* Since: 0.9.21346**/1347hb_glyph_info_t *1348hb_buffer_get_glyph_infos (hb_buffer_t *buffer,1349unsigned int *length)1350{1351if (length)1352*length = buffer->len;13531354return (hb_glyph_info_t *) buffer->info;1355}13561357/**1358* hb_buffer_get_glyph_positions:1359* @buffer: An #hb_buffer_t1360* @length: (out): The output length1361*1362* Returns @buffer glyph position array. Returned pointer1363* is valid as long as @buffer contents are not modified.1364*1365* Return value: (transfer none) (array length=length):1366* The @buffer glyph position array.1367* The value valid as long as buffer has not been modified.1368*1369* Since: 0.9.21370**/1371hb_glyph_position_t *1372hb_buffer_get_glyph_positions (hb_buffer_t *buffer,1373unsigned int *length)1374{1375if (!buffer->have_positions)1376buffer->clear_positions ();13771378if (length)1379*length = buffer->len;13801381return (hb_glyph_position_t *) buffer->pos;1382}13831384/**1385* hb_buffer_has_positions:1386* @buffer: an #hb_buffer_t.1387*1388* Returns whether @buffer has glyph position data.1389* A buffer gains position data when hb_buffer_get_glyph_positions() is called on it,1390* and cleared of position data when hb_buffer_clear_contents() is called.1391*1392* Return value:1393* %true if the @buffer has position array, %false otherwise.1394*1395* Since: 2.7.31396**/1397HB_EXTERN hb_bool_t1398hb_buffer_has_positions (hb_buffer_t *buffer)1399{1400return buffer->have_positions;1401}14021403/**1404* hb_glyph_info_get_glyph_flags:1405* @info: a #hb_glyph_info_t1406*1407* Returns glyph flags encoded within a #hb_glyph_info_t.1408*1409* Return value:1410* The #hb_glyph_flags_t encoded within @info1411*1412* Since: 1.5.01413**/1414hb_glyph_flags_t1415(hb_glyph_info_get_glyph_flags) (const hb_glyph_info_t *info)1416{1417return hb_glyph_info_get_glyph_flags (info);1418}14191420/**1421* hb_buffer_reverse:1422* @buffer: An #hb_buffer_t1423*1424* Reverses buffer contents.1425*1426* Since: 0.9.21427**/1428void1429hb_buffer_reverse (hb_buffer_t *buffer)1430{1431buffer->reverse ();1432}14331434/**1435* hb_buffer_reverse_range:1436* @buffer: An #hb_buffer_t1437* @start: start index1438* @end: end index1439*1440* Reverses buffer contents between @start and @end.1441*1442* Since: 0.9.411443**/1444void1445hb_buffer_reverse_range (hb_buffer_t *buffer,1446unsigned int start, unsigned int end)1447{1448buffer->reverse_range (start, end);1449}14501451/**1452* hb_buffer_reverse_clusters:1453* @buffer: An #hb_buffer_t1454*1455* Reverses buffer clusters. That is, the buffer contents are1456* reversed, then each cluster (consecutive items having the1457* same cluster number) are reversed again.1458*1459* Since: 0.9.21460**/1461void1462hb_buffer_reverse_clusters (hb_buffer_t *buffer)1463{1464buffer->reverse_clusters ();1465}14661467/**1468* hb_buffer_guess_segment_properties:1469* @buffer: An #hb_buffer_t1470*1471* Sets unset buffer segment properties based on buffer Unicode1472* contents. If buffer is not empty, it must have content type1473* #HB_BUFFER_CONTENT_TYPE_UNICODE.1474*1475* If buffer script is not set (ie. is #HB_SCRIPT_INVALID), it1476* will be set to the Unicode script of the first character in1477* the buffer that has a script other than #HB_SCRIPT_COMMON,1478* #HB_SCRIPT_INHERITED, and #HB_SCRIPT_UNKNOWN.1479*1480* Next, if buffer direction is not set (ie. is #HB_DIRECTION_INVALID),1481* it will be set to the natural horizontal direction of the1482* buffer script as returned by hb_script_get_horizontal_direction().1483* If hb_script_get_horizontal_direction() returns #HB_DIRECTION_INVALID,1484* then #HB_DIRECTION_LTR is used.1485*1486* Finally, if buffer language is not set (ie. is #HB_LANGUAGE_INVALID),1487* it will be set to the process's default language as returned by1488* hb_language_get_default(). This may change in the future by1489* taking buffer script into consideration when choosing a language.1490* Note that hb_language_get_default() is NOT threadsafe the first time1491* it is called. See documentation for that function for details.1492*1493* Since: 0.9.71494**/1495void1496hb_buffer_guess_segment_properties (hb_buffer_t *buffer)1497{1498buffer->guess_segment_properties ();1499}15001501template <typename utf_t>1502static inline void1503hb_buffer_add_utf (hb_buffer_t *buffer,1504const typename utf_t::codepoint_t *text,1505int text_length,1506unsigned int item_offset,1507int item_length)1508{1509typedef typename utf_t::codepoint_t T;1510const hb_codepoint_t replacement = buffer->replacement;15111512buffer->assert_unicode ();15131514if (unlikely (hb_object_is_immutable (buffer)))1515return;15161517if (text_length == -1)1518text_length = utf_t::strlen (text);15191520if (item_length == -1)1521item_length = text_length - item_offset;15221523if (unlikely (item_length < 0 ||1524item_length > INT_MAX / 8 ||1525!buffer->ensure (buffer->len + item_length * sizeof (T) / 4)))1526return;15271528/* If buffer is empty and pre-context provided, install it.1529* This check is written this way, to make sure people can1530* provide pre-context in one add_utf() call, then provide1531* text in a follow-up call. See:1532*1533* https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c131534*/1535if (!buffer->len && item_offset > 0)1536{1537/* Add pre-context */1538buffer->clear_context (0);1539const T *prev = text + item_offset;1540const T *start = text;1541while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)1542{1543hb_codepoint_t u;1544prev = utf_t::prev (prev, start, &u, replacement);1545buffer->context[0][buffer->context_len[0]++] = u;1546}1547}15481549const T *next = text + item_offset;1550const T *end = next + item_length;1551while (next < end)1552{1553hb_codepoint_t u;1554const T *old_next = next;1555next = utf_t::next (next, end, &u, replacement);1556buffer->add (u, old_next - (const T *) text);1557}15581559/* Add post-context */1560buffer->clear_context (1);1561end = text + text_length;1562while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)1563{1564hb_codepoint_t u;1565next = utf_t::next (next, end, &u, replacement);1566buffer->context[1][buffer->context_len[1]++] = u;1567}15681569buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;1570}15711572/**1573* hb_buffer_add_utf8:1574* @buffer: An #hb_buffer_t1575* @text: (array length=text_length) (element-type uint8_t): An array of UTF-81576* characters to append.1577* @text_length: The length of the @text, or -1 if it is %NULL terminated.1578* @item_offset: The offset of the first character to add to the @buffer.1579* @item_length: The number of characters to add to the @buffer, or -1 for the1580* end of @text (assuming it is %NULL terminated).1581*1582* See hb_buffer_add_codepoints().1583*1584* Replaces invalid UTF-8 characters with the @buffer replacement code point,1585* see hb_buffer_set_replacement_codepoint().1586*1587* Since: 0.9.21588**/1589void1590hb_buffer_add_utf8 (hb_buffer_t *buffer,1591const char *text,1592int text_length,1593unsigned int item_offset,1594int item_length)1595{1596hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);1597}15981599/**1600* hb_buffer_add_utf16:1601* @buffer: An #hb_buffer_t1602* @text: (array length=text_length): An array of UTF-16 characters to append1603* @text_length: The length of the @text, or -1 if it is %NULL terminated1604* @item_offset: The offset of the first character to add to the @buffer1605* @item_length: The number of characters to add to the @buffer, or -1 for the1606* end of @text (assuming it is %NULL terminated)1607*1608* See hb_buffer_add_codepoints().1609*1610* Replaces invalid UTF-16 characters with the @buffer replacement code point,1611* see hb_buffer_set_replacement_codepoint().1612*1613* Since: 0.9.21614**/1615void1616hb_buffer_add_utf16 (hb_buffer_t *buffer,1617const uint16_t *text,1618int text_length,1619unsigned int item_offset,1620int item_length)1621{1622hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length);1623}16241625/**1626* hb_buffer_add_utf32:1627* @buffer: An #hb_buffer_t1628* @text: (array length=text_length): An array of UTF-32 characters to append1629* @text_length: The length of the @text, or -1 if it is %NULL terminated1630* @item_offset: The offset of the first character to add to the @buffer1631* @item_length: The number of characters to add to the @buffer, or -1 for the1632* end of @text (assuming it is %NULL terminated)1633*1634* See hb_buffer_add_codepoints().1635*1636* Replaces invalid UTF-32 characters with the @buffer replacement code point,1637* see hb_buffer_set_replacement_codepoint().1638*1639* Since: 0.9.21640**/1641void1642hb_buffer_add_utf32 (hb_buffer_t *buffer,1643const uint32_t *text,1644int text_length,1645unsigned int item_offset,1646int item_length)1647{1648hb_buffer_add_utf<hb_utf32_t> (buffer, text, text_length, item_offset, item_length);1649}16501651/**1652* hb_buffer_add_latin1:1653* @buffer: An #hb_buffer_t1654* @text: (array length=text_length) (element-type uint8_t): an array of UTF-81655* characters to append1656* @text_length: the length of the @text, or -1 if it is %NULL terminated1657* @item_offset: the offset of the first character to add to the @buffer1658* @item_length: the number of characters to add to the @buffer, or -1 for the1659* end of @text (assuming it is %NULL terminated)1660*1661* Similar to hb_buffer_add_codepoints(), but allows only access to first 2561662* Unicode code points that can fit in 8-bit strings.1663*1664* <note>Has nothing to do with non-Unicode Latin-1 encoding.</note>1665*1666* Since: 0.9.391667**/1668void1669hb_buffer_add_latin1 (hb_buffer_t *buffer,1670const uint8_t *text,1671int text_length,1672unsigned int item_offset,1673int item_length)1674{1675hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length);1676}16771678/**1679* hb_buffer_add_codepoints:1680* @buffer: a #hb_buffer_t to append characters to.1681* @text: (array length=text_length): an array of Unicode code points to append.1682* @text_length: the length of the @text, or -1 if it is %NULL terminated.1683* @item_offset: the offset of the first code point to add to the @buffer.1684* @item_length: the number of code points to add to the @buffer, or -1 for the1685* end of @text (assuming it is %NULL terminated).1686*1687* Appends characters from @text array to @buffer. The @item_offset is the1688* position of the first character from @text that will be appended, and1689* @item_length is the number of character. When shaping part of a larger text1690* (e.g. a run of text from a paragraph), instead of passing just the substring1691* corresponding to the run, it is preferable to pass the whole1692* paragraph and specify the run start and length as @item_offset and1693* @item_length, respectively, to give HarfBuzz the full context to be able,1694* for example, to do cross-run Arabic shaping or properly handle combining1695* marks at stat of run.1696*1697* This function does not check the validity of @text, it is up to the caller1698* to ensure it contains a valid Unicode code points.1699*1700* Since: 0.9.311701**/1702void1703hb_buffer_add_codepoints (hb_buffer_t *buffer,1704const hb_codepoint_t *text,1705int text_length,1706unsigned int item_offset,1707int item_length)1708{1709hb_buffer_add_utf<hb_utf32_novalidate_t> (buffer, text, text_length, item_offset, item_length);1710}171117121713/**1714* hb_buffer_append:1715* @buffer: An #hb_buffer_t1716* @source: source #hb_buffer_t1717* @start: start index into source buffer to copy. Use 0 to copy from start of buffer.1718* @end: end index into source buffer to copy. Use @HB_FEATURE_GLOBAL_END to copy to end of buffer.1719*1720* Append (part of) contents of another buffer to this buffer.1721*1722* Since: 1.5.01723**/1724HB_EXTERN void1725hb_buffer_append (hb_buffer_t *buffer,1726hb_buffer_t *source,1727unsigned int start,1728unsigned int end)1729{1730assert (!buffer->have_output && !source->have_output);1731assert (buffer->have_positions == source->have_positions ||1732!buffer->len || !source->len);1733assert (buffer->content_type == source->content_type ||1734!buffer->len || !source->len);17351736if (end > source->len)1737end = source->len;1738if (start > end)1739start = end;1740if (start == end)1741return;17421743if (buffer->len + (end - start) < buffer->len) /* Overflows. */1744{1745buffer->successful = false;1746return;1747}17481749unsigned int orig_len = buffer->len;1750hb_buffer_set_length (buffer, buffer->len + (end - start));1751if (unlikely (!buffer->successful))1752return;17531754if (!orig_len)1755buffer->content_type = source->content_type;1756if (!buffer->have_positions && source->have_positions)1757buffer->clear_positions ();17581759memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));1760if (buffer->have_positions)1761memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));1762}176317641765static int1766compare_info_codepoint (const hb_glyph_info_t *pa,1767const hb_glyph_info_t *pb)1768{1769return (int) pb->codepoint - (int) pa->codepoint;1770}17711772static inline void1773normalize_glyphs_cluster (hb_buffer_t *buffer,1774unsigned int start,1775unsigned int end,1776bool backward)1777{1778hb_glyph_position_t *pos = buffer->pos;17791780/* Total cluster advance */1781hb_position_t total_x_advance = 0, total_y_advance = 0;1782for (unsigned int i = start; i < end; i++)1783{1784total_x_advance += pos[i].x_advance;1785total_y_advance += pos[i].y_advance;1786}17871788hb_position_t x_advance = 0, y_advance = 0;1789for (unsigned int i = start; i < end; i++)1790{1791pos[i].x_offset += x_advance;1792pos[i].y_offset += y_advance;17931794x_advance += pos[i].x_advance;1795y_advance += pos[i].y_advance;17961797pos[i].x_advance = 0;1798pos[i].y_advance = 0;1799}18001801if (backward)1802{1803/* Transfer all cluster advance to the last glyph. */1804pos[end - 1].x_advance = total_x_advance;1805pos[end - 1].y_advance = total_y_advance;18061807hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);1808} else {1809/* Transfer all cluster advance to the first glyph. */1810pos[start].x_advance += total_x_advance;1811pos[start].y_advance += total_y_advance;1812for (unsigned int i = start + 1; i < end; i++) {1813pos[i].x_offset -= total_x_advance;1814pos[i].y_offset -= total_y_advance;1815}1816hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);1817}1818}18191820/**1821* hb_buffer_normalize_glyphs:1822* @buffer: An #hb_buffer_t1823*1824* Reorders a glyph buffer to have canonical in-cluster glyph order / position.1825* The resulting clusters should behave identical to pre-reordering clusters.1826*1827* <note>This has nothing to do with Unicode normalization.</note>1828*1829* Since: 0.9.21830**/1831void1832hb_buffer_normalize_glyphs (hb_buffer_t *buffer)1833{1834assert (buffer->have_positions);18351836buffer->assert_glyphs ();18371838bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);18391840foreach_cluster (buffer, start, end)1841normalize_glyphs_cluster (buffer, start, end, backward);1842}18431844void1845hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *))1846{1847assert (!have_positions);1848for (unsigned int i = start + 1; i < end; i++)1849{1850unsigned int j = i;1851while (j > start && compar (&info[j - 1], &info[i]) > 0)1852j--;1853if (i == j)1854continue;1855/* Move item i to occupy place for item j, shift what's in between. */1856merge_clusters (j, i + 1);1857{1858hb_glyph_info_t t = info[i];1859memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t));1860info[j] = t;1861}1862}1863}186418651866/*1867* Comparing buffers.1868*/18691870/**1871* hb_buffer_diff:1872* @buffer: a buffer.1873* @reference: other buffer to compare to.1874* @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.1875* @position_fuzz: allowed absolute difference in position values.1876*1877* If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT1878* and #HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most1879* callers if just comparing two buffers is needed.1880*1881* Since: 1.5.01882**/1883hb_buffer_diff_flags_t1884hb_buffer_diff (hb_buffer_t *buffer,1885hb_buffer_t *reference,1886hb_codepoint_t dottedcircle_glyph,1887unsigned int position_fuzz)1888{1889if (buffer->content_type != reference->content_type && buffer->len && reference->len)1890return HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH;18911892hb_buffer_diff_flags_t result = HB_BUFFER_DIFF_FLAG_EQUAL;1893bool contains = dottedcircle_glyph != (hb_codepoint_t) -1;18941895unsigned int count = reference->len;18961897if (buffer->len != count)1898{1899/*1900* we can't compare glyph-by-glyph, but we do want to know if there1901* are .notdef or dottedcircle glyphs present in the reference buffer1902*/1903const hb_glyph_info_t *info = reference->info;1904unsigned int i;1905for (i = 0; i < count; i++)1906{1907if (contains && info[i].codepoint == dottedcircle_glyph)1908result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;1909if (contains && info[i].codepoint == 0)1910result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;1911}1912result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;1913return hb_buffer_diff_flags_t (result);1914}19151916if (!count)1917return hb_buffer_diff_flags_t (result);19181919const hb_glyph_info_t *buf_info = buffer->info;1920const hb_glyph_info_t *ref_info = reference->info;1921for (unsigned int i = 0; i < count; i++)1922{1923if (buf_info->codepoint != ref_info->codepoint)1924result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;1925if (buf_info->cluster != ref_info->cluster)1926result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;1927if ((buf_info->mask & ~ref_info->mask & HB_GLYPH_FLAG_DEFINED))1928result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;1929if (contains && ref_info->codepoint == dottedcircle_glyph)1930result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;1931if (contains && ref_info->codepoint == 0)1932result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;1933buf_info++;1934ref_info++;1935}19361937if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)1938{1939assert (buffer->have_positions);1940const hb_glyph_position_t *buf_pos = buffer->pos;1941const hb_glyph_position_t *ref_pos = reference->pos;1942for (unsigned int i = 0; i < count; i++)1943{1944if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||1945(unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||1946(unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||1947(unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)1948{1949result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;1950break;1951}1952buf_pos++;1953ref_pos++;1954}1955}19561957return result;1958}195919601961/*1962* Debugging.1963*/19641965#ifndef HB_NO_BUFFER_MESSAGE1966/**1967* hb_buffer_set_message_func:1968* @buffer: An #hb_buffer_t1969* @func: (closure user_data) (destroy destroy) (scope notified): Callback function1970* @user_data: (nullable): Data to pass to @func1971* @destroy: (nullable): The function to call when @user_data is not needed anymore1972*1973* Sets the implementation function for #hb_buffer_message_func_t.1974*1975* Since: 1.1.31976**/1977void1978hb_buffer_set_message_func (hb_buffer_t *buffer,1979hb_buffer_message_func_t func,1980void *user_data, hb_destroy_func_t destroy)1981{1982if (buffer->message_destroy)1983buffer->message_destroy (buffer->message_data);19841985if (func) {1986buffer->message_func = func;1987buffer->message_data = user_data;1988buffer->message_destroy = destroy;1989} else {1990buffer->message_func = nullptr;1991buffer->message_data = nullptr;1992buffer->message_destroy = nullptr;1993}1994}1995bool1996hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)1997{1998char buf[100];1999vsnprintf (buf, sizeof (buf), fmt, ap);2000return (bool) this->message_func (this, font, buf, this->message_data);2001}2002#endif200320042005