gfx/harfbuzz/src/hb-buffer.cc

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 /*
     2  * Copyright © 1998-2004  David Turner and Werner Lemberg
     3  * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
     4  * Copyright © 2011,2012  Google, Inc.
     5  *
     6  *  This is part of HarfBuzz, a text shaping library.
     7  *
     8  * Permission is hereby granted, without written agreement and without
     9  * license or royalty fees, to use, copy, modify, and distribute this
    10  * software and its documentation for any purpose, provided that the
    11  * above copyright notice and the following two paragraphs appear in
    12  * all copies of this software.
    13  *
    14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    18  * DAMAGE.
    19  *
    20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    25  *
    26  * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
    27  * Google Author(s): Behdad Esfahbod
    28  */
    30 #include "hb-buffer-private.hh"
    31 #include "hb-utf-private.hh"
    34 #ifndef HB_DEBUG_BUFFER
    35 #define HB_DEBUG_BUFFER (HB_DEBUG+0)
    36 #endif
    39 hb_bool_t
    40 hb_segment_properties_equal (const hb_segment_properties_t *a,
    41 			     const hb_segment_properties_t *b)
    42 {
    43   return a->direction == b->direction &&
    44 	 a->script    == b->script    &&
    45 	 a->language  == b->language  &&
    46 	 a->reserved1 == b->reserved1 &&
    47 	 a->reserved2 == b->reserved2;
    49 }
    51 unsigned int
    52 hb_segment_properties_hash (const hb_segment_properties_t *p)
    53 {
    54   return (unsigned int) p->direction ^
    55 	 (unsigned int) p->script ^
    56 	 (intptr_t) (p->language);
    57 }
    61 /* Here is how the buffer works internally:
    62  *
    63  * There are two info pointers: info and out_info.  They always have
    64  * the same allocated size, but different lengths.
    65  *
    66  * As an optimization, both info and out_info may point to the
    67  * same piece of memory, which is owned by info.  This remains the
    68  * case as long as out_len doesn't exceed i at any time.
    69  * In that case, swap_buffers() is no-op and the glyph operations operate
    70  * mostly in-place.
    71  *
    72  * As soon as out_info gets longer than info, out_info is moved over
    73  * to an alternate buffer (which we reuse the pos buffer for!), and its
    74  * current contents (out_len entries) are copied to the new place.
    75  * This should all remain transparent to the user.  swap_buffers() then
    76  * switches info and out_info.
    77  */
    81 /* Internal API */
    83 bool
    84 hb_buffer_t::enlarge (unsigned int size)
    85 {
    86   if (unlikely (in_error))
    87     return false;
    89   unsigned int new_allocated = allocated;
    90   hb_glyph_position_t *new_pos = NULL;
    91   hb_glyph_info_t *new_info = NULL;
    92   bool separate_out = out_info != info;
    94   if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
    95     goto done;
    97   while (size >= new_allocated)
    98     new_allocated += (new_allocated >> 1) + 32;
   100   ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
   101   if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
   102     goto done;
   104   new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
   105   new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
   107 done:
   108   if (unlikely (!new_pos || !new_info))
   109     in_error = true;
   111   if (likely (new_pos))
   112     pos = new_pos;
   114   if (likely (new_info))
   115     info = new_info;
   117   out_info = separate_out ? (hb_glyph_info_t *) pos : info;
   118   if (likely (!in_error))
   119     allocated = new_allocated;
   121   return likely (!in_error);
   122 }
   124 bool
   125 hb_buffer_t::make_room_for (unsigned int num_in,
   126 			    unsigned int num_out)
   127 {
   128   if (unlikely (!ensure (out_len + num_out))) return false;
   130   if (out_info == info &&
   131       out_len + num_out > idx + num_in)
   132   {
   133     assert (have_output);
   135     out_info = (hb_glyph_info_t *) pos;
   136     memcpy (out_info, info, out_len * sizeof (out_info[0]));
   137   }
   139   return true;
   140 }
   142 bool
   143 hb_buffer_t::shift_forward (unsigned int count)
   144 {
   145   assert (have_output);
   146   if (unlikely (!ensure (len + count))) return false;
   148   memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
   149   len += count;
   150   idx += count;
   152   return true;
   153 }
   155 hb_buffer_t::scratch_buffer_t *
   156 hb_buffer_t::get_scratch_buffer (unsigned int *size)
   157 {
   158   have_output = false;
   159   have_positions = false;
   161   out_len = 0;
   162   out_info = info;
   164   assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);
   165   *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);
   166   return (scratch_buffer_t *) (void *) pos;
   167 }
   171 /* HarfBuzz-Internal API */
   173 void
   174 hb_buffer_t::reset (void)
   175 {
   176   if (unlikely (hb_object_is_inert (this)))
   177     return;
   179   hb_unicode_funcs_destroy (unicode);
   180   unicode = hb_unicode_funcs_get_default ();
   182   clear ();
   183 }
   185 void
   186 hb_buffer_t::clear (void)
   187 {
   188   if (unlikely (hb_object_is_inert (this)))
   189     return;
   191   hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
   192   props = default_props;
   193   flags = HB_BUFFER_FLAG_DEFAULT;
   195   content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
   196   in_error = false;
   197   have_output = false;
   198   have_positions = false;
   200   idx = 0;
   201   len = 0;
   202   out_len = 0;
   203   out_info = info;
   205   serial = 0;
   206   memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
   207   memset (allocated_var_owner, 0, sizeof allocated_var_owner);
   209   memset (context, 0, sizeof context);
   210   memset (context_len, 0, sizeof context_len);
   211 }
   213 void
   214 hb_buffer_t::add (hb_codepoint_t  codepoint,
   215 		  unsigned int    cluster)
   216 {
   217   hb_glyph_info_t *glyph;
   219   if (unlikely (!ensure (len + 1))) return;
   221   glyph = &info[len];
   223   memset (glyph, 0, sizeof (*glyph));
   224   glyph->codepoint = codepoint;
   225   glyph->mask = 1;
   226   glyph->cluster = cluster;
   228   len++;
   229 }
   231 void
   232 hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
   233 {
   234   if (unlikely (!ensure (len + 1))) return;
   236   info[len] = glyph_info;
   238   len++;
   239 }
   242 void
   243 hb_buffer_t::remove_output (void)
   244 {
   245   if (unlikely (hb_object_is_inert (this)))
   246     return;
   248   have_output = false;
   249   have_positions = false;
   251   out_len = 0;
   252   out_info = info;
   253 }
   255 void
   256 hb_buffer_t::clear_output (void)
   257 {
   258   if (unlikely (hb_object_is_inert (this)))
   259     return;
   261   have_output = true;
   262   have_positions = false;
   264   out_len = 0;
   265   out_info = info;
   266 }
   268 void
   269 hb_buffer_t::clear_positions (void)
   270 {
   271   if (unlikely (hb_object_is_inert (this)))
   272     return;
   274   have_output = false;
   275   have_positions = true;
   277   out_len = 0;
   278   out_info = info;
   280   memset (pos, 0, sizeof (pos[0]) * len);
   281 }
   283 void
   284 hb_buffer_t::swap_buffers (void)
   285 {
   286   if (unlikely (in_error)) return;
   288   assert (have_output);
   289   have_output = false;
   291   if (out_info != info)
   292   {
   293     hb_glyph_info_t *tmp_string;
   294     tmp_string = info;
   295     info = out_info;
   296     out_info = tmp_string;
   297     pos = (hb_glyph_position_t *) out_info;
   298   }
   300   unsigned int tmp;
   301   tmp = len;
   302   len = out_len;
   303   out_len = tmp;
   305   idx = 0;
   306 }
   309 void
   310 hb_buffer_t::replace_glyphs (unsigned int num_in,
   311 			     unsigned int num_out,
   312 			     const uint32_t *glyph_data)
   313 {
   314   if (unlikely (!make_room_for (num_in, num_out))) return;
   316   merge_clusters (idx, idx + num_in);
   318   hb_glyph_info_t orig_info = info[idx];
   319   hb_glyph_info_t *pinfo = &out_info[out_len];
   320   for (unsigned int i = 0; i < num_out; i++)
   321   {
   322     *pinfo = orig_info;
   323     pinfo->codepoint = glyph_data[i];
   324     pinfo++;
   325   }
   327   idx  += num_in;
   328   out_len += num_out;
   329 }
   331 void
   332 hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
   333 {
   334   if (unlikely (!make_room_for (0, 1))) return;
   336   out_info[out_len] = info[idx];
   337   out_info[out_len].codepoint = glyph_index;
   339   out_len++;
   340 }
   342 void
   343 hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
   344 {
   345   if (unlikely (!make_room_for (0, 1))) return;
   347   out_info[out_len] = glyph_info;
   349   out_len++;
   350 }
   352 void
   353 hb_buffer_t::copy_glyph (void)
   354 {
   355   if (unlikely (!make_room_for (0, 1))) return;
   357   out_info[out_len] = info[idx];
   359   out_len++;
   360 }
   362 bool
   363 hb_buffer_t::move_to (unsigned int i)
   364 {
   365   if (!have_output)
   366   {
   367     assert (i <= len);
   368     idx = i;
   369     return true;
   370   }
   372   assert (i <= out_len + (len - idx));
   374   if (out_len < i)
   375   {
   376     unsigned int count = i - out_len;
   377     if (unlikely (!make_room_for (count, count))) return false;
   379     memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
   380     idx += count;
   381     out_len += count;
   382   }
   383   else if (out_len > i)
   384   {
   385     /* Tricky part: rewinding... */
   386     unsigned int count = out_len - i;
   388     if (unlikely (idx < count && !shift_forward (count + 32))) return false;
   390     assert (idx >= count);
   392     idx -= count;
   393     out_len -= count;
   394     memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));
   395   }
   397   return true;
   398 }
   400 void
   401 hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
   402 {
   403   if (unlikely (out_info != info || out_len != idx)) {
   404     if (unlikely (!make_room_for (1, 1))) return;
   405     out_info[out_len] = info[idx];
   406   }
   407   out_info[out_len].codepoint = glyph_index;
   409   idx++;
   410   out_len++;
   411 }
   414 void
   415 hb_buffer_t::set_masks (hb_mask_t    value,
   416 			hb_mask_t    mask,
   417 			unsigned int cluster_start,
   418 			unsigned int cluster_end)
   419 {
   420   hb_mask_t not_mask = ~mask;
   421   value &= mask;
   423   if (!mask)
   424     return;
   426   if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
   427     unsigned int count = len;
   428     for (unsigned int i = 0; i < count; i++)
   429       info[i].mask = (info[i].mask & not_mask) | value;
   430     return;
   431   }
   433   unsigned int count = len;
   434   for (unsigned int i = 0; i < count; i++)
   435     if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
   436       info[i].mask = (info[i].mask & not_mask) | value;
   437 }
   439 void
   440 hb_buffer_t::reverse_range (unsigned int start,
   441 			    unsigned int end)
   442 {
   443   unsigned int i, j;
   445   if (start == end - 1)
   446     return;
   448   for (i = start, j = end - 1; i < j; i++, j--) {
   449     hb_glyph_info_t t;
   451     t = info[i];
   452     info[i] = info[j];
   453     info[j] = t;
   454   }
   456   if (pos) {
   457     for (i = start, j = end - 1; i < j; i++, j--) {
   458       hb_glyph_position_t t;
   460       t = pos[i];
   461       pos[i] = pos[j];
   462       pos[j] = t;
   463     }
   464   }
   465 }
   467 void
   468 hb_buffer_t::reverse (void)
   469 {
   470   if (unlikely (!len))
   471     return;
   473   reverse_range (0, len);
   474 }
   476 void
   477 hb_buffer_t::reverse_clusters (void)
   478 {
   479   unsigned int i, start, count, last_cluster;
   481   if (unlikely (!len))
   482     return;
   484   reverse ();
   486   count = len;
   487   start = 0;
   488   last_cluster = info[0].cluster;
   489   for (i = 1; i < count; i++) {
   490     if (last_cluster != info[i].cluster) {
   491       reverse_range (start, i);
   492       start = i;
   493       last_cluster = info[i].cluster;
   494     }
   495   }
   496   reverse_range (start, i);
   497 }
   499 void
   500 hb_buffer_t::merge_clusters (unsigned int start,
   501 			     unsigned int end)
   502 {
   503   if (unlikely (end - start < 2))
   504     return;
   506   unsigned int cluster = info[start].cluster;
   508   for (unsigned int i = start + 1; i < end; i++)
   509     cluster = MIN (cluster, info[i].cluster);
   511   /* Extend end */
   512   while (end < len && info[end - 1].cluster == info[end].cluster)
   513     end++;
   515   /* Extend start */
   516   while (idx < start && info[start - 1].cluster == info[start].cluster)
   517     start--;
   519   /* If we hit the start of buffer, continue in out-buffer. */
   520   if (idx == start)
   521     for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
   522       out_info[i - 1].cluster = cluster;
   524   for (unsigned int i = start; i < end; i++)
   525     info[i].cluster = cluster;
   526 }
   527 void
   528 hb_buffer_t::merge_out_clusters (unsigned int start,
   529 				 unsigned int end)
   530 {
   531   if (unlikely (end - start < 2))
   532     return;
   534   unsigned int cluster = out_info[start].cluster;
   536   for (unsigned int i = start + 1; i < end; i++)
   537     cluster = MIN (cluster, out_info[i].cluster);
   539   /* Extend start */
   540   while (start && out_info[start - 1].cluster == out_info[start].cluster)
   541     start--;
   543   /* Extend end */
   544   while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
   545     end++;
   547   /* If we hit the end of out-buffer, continue in buffer. */
   548   if (end == out_len)
   549     for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
   550       info[i].cluster = cluster;
   552   for (unsigned int i = start; i < end; i++)
   553     out_info[i].cluster = cluster;
   554 }
   556 void
   557 hb_buffer_t::guess_segment_properties (void)
   558 {
   559   assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
   560 	  (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
   562   /* If script is set to INVALID, guess from buffer contents */
   563   if (props.script == HB_SCRIPT_INVALID) {
   564     for (unsigned int i = 0; i < len; i++) {
   565       hb_script_t script = unicode->script (info[i].codepoint);
   566       if (likely (script != HB_SCRIPT_COMMON &&
   567 		  script != HB_SCRIPT_INHERITED &&
   568 		  script != HB_SCRIPT_UNKNOWN)) {
   569         props.script = script;
   570         break;
   571       }
   572     }
   573   }
   575   /* If direction is set to INVALID, guess from script */
   576   if (props.direction == HB_DIRECTION_INVALID) {
   577     props.direction = hb_script_get_horizontal_direction (props.script);
   578   }
   580   /* If language is not set, use default language from locale */
   581   if (props.language == HB_LANGUAGE_INVALID) {
   582     /* TODO get_default_for_script? using $LANGUAGE */
   583     props.language = hb_language_get_default ();
   584   }
   585 }
   588 static inline void
   589 dump_var_allocation (const hb_buffer_t *buffer)
   590 {
   591   char buf[80];
   592   for (unsigned int i = 0; i < 8; i++)
   593     buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
   594   buf[8] = '\0';
   595   DEBUG_MSG (BUFFER, buffer,
   596 	     "Current var allocation: %s",
   597 	     buf);
   598 }
   600 void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
   601 {
   602   assert (byte_i < 8 && byte_i + count <= 8);
   604   if (DEBUG_ENABLED (BUFFER))
   605     dump_var_allocation (this);
   606   DEBUG_MSG (BUFFER, this,
   607 	     "Allocating var bytes %d..%d for %s",
   608 	     byte_i, byte_i + count - 1, owner);
   610   for (unsigned int i = byte_i; i < byte_i + count; i++) {
   611     assert (!allocated_var_bytes[i]);
   612     allocated_var_bytes[i]++;
   613     allocated_var_owner[i] = owner;
   614   }
   615 }
   617 void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
   618 {
   619   if (DEBUG_ENABLED (BUFFER))
   620     dump_var_allocation (this);
   622   DEBUG_MSG (BUFFER, this,
   623 	     "Deallocating var bytes %d..%d for %s",
   624 	     byte_i, byte_i + count - 1, owner);
   626   assert (byte_i < 8 && byte_i + count <= 8);
   627   for (unsigned int i = byte_i; i < byte_i + count; i++) {
   628     assert (allocated_var_bytes[i]);
   629     assert (0 == strcmp (allocated_var_owner[i], owner));
   630     allocated_var_bytes[i]--;
   631   }
   632 }
   634 void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
   635 {
   636   if (DEBUG_ENABLED (BUFFER))
   637     dump_var_allocation (this);
   639   DEBUG_MSG (BUFFER, this,
   640 	     "Asserting var bytes %d..%d for %s",
   641 	     byte_i, byte_i + count - 1, owner);
   643   assert (byte_i < 8 && byte_i + count <= 8);
   644   for (unsigned int i = byte_i; i < byte_i + count; i++) {
   645     assert (allocated_var_bytes[i]);
   646     assert (0 == strcmp (allocated_var_owner[i], owner));
   647   }
   648 }
   650 void hb_buffer_t::deallocate_var_all (void)
   651 {
   652   memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
   653   memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
   654 }
   656 /* Public API */
   658 /**
   659  * hb_buffer_create: (Xconstructor)
   660  *
   661  * 
   662  *
   663  * Return value: (transfer full)
   664  *
   665  * Since: 1.0
   666  **/
   667 hb_buffer_t *
   668 hb_buffer_create (void)
   669 {
   670   hb_buffer_t *buffer;
   672   if (!(buffer = hb_object_create<hb_buffer_t> ()))
   673     return hb_buffer_get_empty ();
   675   buffer->reset ();
   677   return buffer;
   678 }
   680 /**
   681  * hb_buffer_get_empty:
   682  *
   683  * 
   684  *
   685  * Return value: (transfer full):
   686  *
   687  * Since: 1.0
   688  **/
   689 hb_buffer_t *
   690 hb_buffer_get_empty (void)
   691 {
   692   static const hb_buffer_t _hb_buffer_nil = {
   693     HB_OBJECT_HEADER_STATIC,
   695     const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
   696     HB_SEGMENT_PROPERTIES_DEFAULT,
   697     HB_BUFFER_FLAG_DEFAULT,
   699     HB_BUFFER_CONTENT_TYPE_INVALID,
   700     true, /* in_error */
   701     true, /* have_output */
   702     true  /* have_positions */
   704     /* Zero is good enough for everything else. */
   705   };
   707   return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
   708 }
   710 /**
   711  * hb_buffer_reference: (skip)
   712  * @buffer: a buffer.
   713  *
   714  * 
   715  *
   716  * Return value: (transfer full):
   717  *
   718  * Since: 1.0
   719  **/
   720 hb_buffer_t *
   721 hb_buffer_reference (hb_buffer_t *buffer)
   722 {
   723   return hb_object_reference (buffer);
   724 }
   726 /**
   727  * hb_buffer_destroy: (skip)
   728  * @buffer: a buffer.
   729  *
   730  * 
   731  *
   732  * Since: 1.0
   733  **/
   734 void
   735 hb_buffer_destroy (hb_buffer_t *buffer)
   736 {
   737   if (!hb_object_destroy (buffer)) return;
   739   hb_unicode_funcs_destroy (buffer->unicode);
   741   free (buffer->info);
   742   free (buffer->pos);
   744   free (buffer);
   745 }
   747 /**
   748  * hb_buffer_set_user_data: (skip)
   749  * @buffer: a buffer.
   750  * @key: 
   751  * @data: 
   752  * @destroy: 
   753  * @replace: 
   754  *
   755  * 
   756  *
   757  * Return value: 
   758  *
   759  * Since: 1.0
   760  **/
   761 hb_bool_t
   762 hb_buffer_set_user_data (hb_buffer_t        *buffer,
   763 			 hb_user_data_key_t *key,
   764 			 void *              data,
   765 			 hb_destroy_func_t   destroy,
   766 			 hb_bool_t           replace)
   767 {
   768   return hb_object_set_user_data (buffer, key, data, destroy, replace);
   769 }
   771 /**
   772  * hb_buffer_get_user_data: (skip)
   773  * @buffer: a buffer.
   774  * @key: 
   775  *
   776  * 
   777  *
   778  * Return value: 
   779  *
   780  * Since: 1.0
   781  **/
   782 void *
   783 hb_buffer_get_user_data (hb_buffer_t        *buffer,
   784 			 hb_user_data_key_t *key)
   785 {
   786   return hb_object_get_user_data (buffer, key);
   787 }
   790 /**
   791  * hb_buffer_set_content_type:
   792  * @buffer: a buffer.
   793  * @content_type: 
   794  *
   795  * 
   796  *
   797  * Since: 1.0
   798  **/
   799 void
   800 hb_buffer_set_content_type (hb_buffer_t              *buffer,
   801 			    hb_buffer_content_type_t  content_type)
   802 {
   803   buffer->content_type = content_type;
   804 }
   806 /**
   807  * hb_buffer_get_content_type:
   808  * @buffer: a buffer.
   809  *
   810  * 
   811  *
   812  * Return value: 
   813  *
   814  * Since: 1.0
   815  **/
   816 hb_buffer_content_type_t
   817 hb_buffer_get_content_type (hb_buffer_t *buffer)
   818 {
   819   return buffer->content_type;
   820 }
   823 /**
   824  * hb_buffer_set_unicode_funcs:
   825  * @buffer: a buffer.
   826  * @unicode_funcs: 
   827  *
   828  * 
   829  *
   830  * Since: 1.0
   831  **/
   832 void
   833 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
   834 			     hb_unicode_funcs_t *unicode_funcs)
   835 {
   836   if (unlikely (hb_object_is_inert (buffer)))
   837     return;
   839   if (!unicode_funcs)
   840     unicode_funcs = hb_unicode_funcs_get_default ();
   843   hb_unicode_funcs_reference (unicode_funcs);
   844   hb_unicode_funcs_destroy (buffer->unicode);
   845   buffer->unicode = unicode_funcs;
   846 }
   848 /**
   849  * hb_buffer_get_unicode_funcs:
   850  * @buffer: a buffer.
   851  *
   852  * 
   853  *
   854  * Return value: 
   855  *
   856  * Since: 1.0
   857  **/
   858 hb_unicode_funcs_t *
   859 hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
   860 {
   861   return buffer->unicode;
   862 }
   864 /**
   865  * hb_buffer_set_direction:
   866  * @buffer: a buffer.
   867  * @direction: 
   868  *
   869  * 
   870  *
   871  * Since: 1.0
   872  **/
   873 void
   874 hb_buffer_set_direction (hb_buffer_t    *buffer,
   875 			 hb_direction_t  direction)
   877 {
   878   if (unlikely (hb_object_is_inert (buffer)))
   879     return;
   881   buffer->props.direction = direction;
   882 }
   884 /**
   885  * hb_buffer_get_direction:
   886  * @buffer: a buffer.
   887  *
   888  * 
   889  *
   890  * Return value: 
   891  *
   892  * Since: 1.0
   893  **/
   894 hb_direction_t
   895 hb_buffer_get_direction (hb_buffer_t    *buffer)
   896 {
   897   return buffer->props.direction;
   898 }
   900 /**
   901  * hb_buffer_set_script:
   902  * @buffer: a buffer.
   903  * @script: 
   904  *
   905  * 
   906  *
   907  * Since: 1.0
   908  **/
   909 void
   910 hb_buffer_set_script (hb_buffer_t *buffer,
   911 		      hb_script_t  script)
   912 {
   913   if (unlikely (hb_object_is_inert (buffer)))
   914     return;
   916   buffer->props.script = script;
   917 }
   919 /**
   920  * hb_buffer_get_script:
   921  * @buffer: a buffer.
   922  *
   923  * 
   924  *
   925  * Return value: 
   926  *
   927  * Since: 1.0
   928  **/
   929 hb_script_t
   930 hb_buffer_get_script (hb_buffer_t *buffer)
   931 {
   932   return buffer->props.script;
   933 }
   935 /**
   936  * hb_buffer_set_language:
   937  * @buffer: a buffer.
   938  * @language: 
   939  *
   940  * 
   941  *
   942  * Since: 1.0
   943  **/
   944 void
   945 hb_buffer_set_language (hb_buffer_t   *buffer,
   946 			hb_language_t  language)
   947 {
   948   if (unlikely (hb_object_is_inert (buffer)))
   949     return;
   951   buffer->props.language = language;
   952 }
   954 /**
   955  * hb_buffer_get_language:
   956  * @buffer: a buffer.
   957  *
   958  * 
   959  *
   960  * Return value: 
   961  *
   962  * Since: 1.0
   963  **/
   964 hb_language_t
   965 hb_buffer_get_language (hb_buffer_t *buffer)
   966 {
   967   return buffer->props.language;
   968 }
   970 /**
   971  * hb_buffer_set_segment_properties:
   972  * @buffer: a buffer.
   973  * @props: 
   974  *
   975  * 
   976  *
   977  * Since: 1.0
   978  **/
   979 void
   980 hb_buffer_set_segment_properties (hb_buffer_t *buffer,
   981 				  const hb_segment_properties_t *props)
   982 {
   983   if (unlikely (hb_object_is_inert (buffer)))
   984     return;
   986   buffer->props = *props;
   987 }
   989 /**
   990  * hb_buffer_get_segment_properties:
   991  * @buffer: a buffer.
   992  * @props: 
   993  *
   994  * 
   995  *
   996  * Since: 1.0
   997  **/
   998 void
   999 hb_buffer_get_segment_properties (hb_buffer_t *buffer,
  1000 				  hb_segment_properties_t *props)
  1002   *props = buffer->props;
  1006 /**
  1007  * hb_buffer_set_flags:
  1008  * @buffer: a buffer.
  1009  * @flags: 
  1013  * Since: 1.0
  1014  **/
  1015 void
  1016 hb_buffer_set_flags (hb_buffer_t       *buffer,
  1017 		     hb_buffer_flags_t  flags)
  1019   if (unlikely (hb_object_is_inert (buffer)))
  1020     return;
  1022   buffer->flags = flags;
  1025 /**
  1026  * hb_buffer_get_flags:
  1027  * @buffer: a buffer.
  1031  * Return value: 
  1033  * Since: 1.0
  1034  **/
  1035 hb_buffer_flags_t
  1036 hb_buffer_get_flags (hb_buffer_t *buffer)
  1038   return buffer->flags;
  1042 /**
  1043  * hb_buffer_reset:
  1044  * @buffer: a buffer.
  1048  * Since: 1.0
  1049  **/
  1050 void
  1051 hb_buffer_reset (hb_buffer_t *buffer)
  1053   buffer->reset ();
  1056 /**
  1057  * hb_buffer_clear_contents:
  1058  * @buffer: a buffer.
  1062  * Since: 1.0
  1063  **/
  1064 void
  1065 hb_buffer_clear_contents (hb_buffer_t *buffer)
  1067   buffer->clear ();
  1070 /**
  1071  * hb_buffer_pre_allocate:
  1072  * @buffer: a buffer.
  1073  * @size: 
  1077  * Return value: 
  1079  * Since: 1.0
  1080  **/
  1081 hb_bool_t
  1082 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
  1084   return buffer->ensure (size);
  1087 /**
  1088  * hb_buffer_allocation_successful:
  1089  * @buffer: a buffer.
  1093  * Return value: 
  1095  * Since: 1.0
  1096  **/
  1097 hb_bool_t
  1098 hb_buffer_allocation_successful (hb_buffer_t  *buffer)
  1100   return !buffer->in_error;
  1103 /**
  1104  * hb_buffer_add:
  1105  * @buffer: a buffer.
  1106  * @codepoint: 
  1107  * @cluster: 
  1111  * Since: 1.0
  1112  **/
  1113 void
  1114 hb_buffer_add (hb_buffer_t    *buffer,
  1115 	       hb_codepoint_t  codepoint,
  1116 	       unsigned int    cluster)
  1118   buffer->add (codepoint, cluster);
  1119   buffer->clear_context (1);
  1122 /**
  1123  * hb_buffer_set_length:
  1124  * @buffer: a buffer.
  1125  * @length: 
  1129  * Return value: 
  1131  * Since: 1.0
  1132  **/
  1133 hb_bool_t
  1134 hb_buffer_set_length (hb_buffer_t  *buffer,
  1135 		      unsigned int  length)
  1137   if (unlikely (hb_object_is_inert (buffer)))
  1138     return length == 0;
  1140   if (!buffer->ensure (length))
  1141     return false;
  1143   /* Wipe the new space */
  1144   if (length > buffer->len) {
  1145     memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
  1146     if (buffer->have_positions)
  1147       memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
  1150   buffer->len = length;
  1152   if (!length)
  1154     buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
  1155     buffer->clear_context (0);
  1157   buffer->clear_context (1);
  1159   return true;
  1162 /**
  1163  * hb_buffer_get_length:
  1164  * @buffer: a buffer.
  1166  * Returns the number of items in the buffer.
  1168  * Return value: buffer length.
  1170  * Since: 1.0
  1171  **/
  1172 unsigned int
  1173 hb_buffer_get_length (hb_buffer_t *buffer)
  1175   return buffer->len;
  1178 /**
  1179  * hb_buffer_get_glyph_infos:
  1180  * @buffer: a buffer.
  1181  * @length: (out): output array length.
  1183  * Returns buffer glyph information array.  Returned pointer
  1184  * is valid as long as buffer contents are not modified.
  1186  * Return value: (transfer none) (array length=length): buffer glyph information array.
  1188  * Since: 1.0
  1189  **/
  1190 hb_glyph_info_t *
  1191 hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
  1192                            unsigned int *length)
  1194   if (length)
  1195     *length = buffer->len;
  1197   return (hb_glyph_info_t *) buffer->info;
  1200 /**
  1201  * hb_buffer_get_glyph_positions:
  1202  * @buffer: a buffer.
  1203  * @length: (out): output length.
  1205  * Returns buffer glyph position array.  Returned pointer
  1206  * is valid as long as buffer contents are not modified.
  1208  * Return value: (transfer none) (array length=length): buffer glyph position array.
  1210  * Since: 1.0
  1211  **/
  1212 hb_glyph_position_t *
  1213 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
  1214                                unsigned int *length)
  1216   if (!buffer->have_positions)
  1217     buffer->clear_positions ();
  1219   if (length)
  1220     *length = buffer->len;
  1222   return (hb_glyph_position_t *) buffer->pos;
  1225 /**
  1226  * hb_buffer_reverse:
  1227  * @buffer: a buffer.
  1229  * Reverses buffer contents.
  1231  * Since: 1.0
  1232  **/
  1233 void
  1234 hb_buffer_reverse (hb_buffer_t *buffer)
  1236   buffer->reverse ();
  1239 /**
  1240  * hb_buffer_reverse_clusters:
  1241  * @buffer: a buffer.
  1243  * Reverses buffer clusters.  That is, the buffer contents are
  1244  * reversed, then each cluster (consecutive items having the
  1245  * same cluster number) are reversed again.
  1247  * Since: 1.0
  1248  **/
  1249 void
  1250 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
  1252   buffer->reverse_clusters ();
  1255 /**
  1256  * hb_buffer_guess_segment_properties:
  1257  * @buffer: a buffer.
  1259  * Sets unset buffer segment properties based on buffer Unicode
  1260  * contents.  If buffer is not empty, it must have content type
  1261  * %HB_BUFFER_CONTENT_TYPE_UNICODE.
  1263  * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
  1264  * will be set to the Unicode script of the first character in
  1265  * the buffer that has a script other than %HB_SCRIPT_COMMON,
  1266  * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
  1268  * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
  1269  * it will be set to the natural horizontal direction of the
  1270  * buffer script as returned by hb_script_get_horizontal_direction().
  1272  * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
  1273  * it will be set to the process's default language as returned by
  1274  * hb_language_get_default().  This may change in the future by
  1275  * taking buffer script into consideration when choosing a language.
  1277  * Since: 1.0
  1278  **/
  1279 void
  1280 hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
  1282   buffer->guess_segment_properties ();
  1285 template <typename T>
  1286 static inline void
  1287 hb_buffer_add_utf (hb_buffer_t  *buffer,
  1288 		   const T      *text,
  1289 		   int           text_length,
  1290 		   unsigned int  item_offset,
  1291 		   int           item_length)
  1293   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
  1294 	  (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
  1296   if (unlikely (hb_object_is_inert (buffer)))
  1297     return;
  1299   if (text_length == -1)
  1300     text_length = hb_utf_strlen (text);
  1302   if (item_length == -1)
  1303     item_length = text_length - item_offset;
  1305   buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
  1307   /* If buffer is empty and pre-context provided, install it.
  1308    * This check is written this way, to make sure people can
  1309    * provide pre-context in one add_utf() call, then provide
  1310    * text in a follow-up call.  See:
  1312    * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
  1313    */
  1314   if (!buffer->len && item_offset > 0)
  1316     /* Add pre-context */
  1317     buffer->clear_context (0);
  1318     const T *prev = text + item_offset;
  1319     const T *start = text;
  1320     while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
  1322       hb_codepoint_t u;
  1323       prev = hb_utf_prev (prev, start, &u);
  1324       buffer->context[0][buffer->context_len[0]++] = u;
  1328   const T *next = text + item_offset;
  1329   const T *end = next + item_length;
  1330   while (next < end)
  1332     hb_codepoint_t u;
  1333     const T *old_next = next;
  1334     next = hb_utf_next (next, end, &u);
  1335     buffer->add (u, old_next - (const T *) text);
  1338   /* Add post-context */
  1339   buffer->clear_context (1);
  1340   end = text + text_length;
  1341   while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
  1343     hb_codepoint_t u;
  1344     next = hb_utf_next (next, end, &u);
  1345     buffer->context[1][buffer->context_len[1]++] = u;
  1348   buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
  1351 /**
  1352  * hb_buffer_add_utf8:
  1353  * @buffer: a buffer.
  1354  * @text: (array length=text_length):
  1355  * @text_length: 
  1356  * @item_offset: 
  1357  * @item_length: 
  1361  * Since: 1.0
  1362  **/
  1363 void
  1364 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
  1365 		    const char   *text,
  1366 		    int           text_length,
  1367 		    unsigned int  item_offset,
  1368 		    int           item_length)
  1370   hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
  1373 /**
  1374  * hb_buffer_add_utf16:
  1375  * @buffer: a buffer.
  1376  * @text: (array length=text_length):
  1377  * @text_length: 
  1378  * @item_offset: 
  1379  * @item_length: 
  1383  * Since: 1.0
  1384  **/
  1385 void
  1386 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
  1387 		     const uint16_t *text,
  1388 		     int             text_length,
  1389 		     unsigned int    item_offset,
  1390 		     int             item_length)
  1392   hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
  1395 /**
  1396  * hb_buffer_add_utf32:
  1397  * @buffer: a buffer.
  1398  * @text: (array length=text_length):
  1399  * @text_length: 
  1400  * @item_offset: 
  1401  * @item_length: 
  1405  * Since: 1.0
  1406  **/
  1407 void
  1408 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
  1409 		     const uint32_t *text,
  1410 		     int             text_length,
  1411 		     unsigned int    item_offset,
  1412 		     int             item_length)
  1414   hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
  1418 static int
  1419 compare_info_codepoint (const hb_glyph_info_t *pa,
  1420 			const hb_glyph_info_t *pb)
  1422   return (int) pb->codepoint - (int) pa->codepoint;
  1425 static inline void
  1426 normalize_glyphs_cluster (hb_buffer_t *buffer,
  1427 			  unsigned int start,
  1428 			  unsigned int end,
  1429 			  bool backward)
  1431   hb_glyph_position_t *pos = buffer->pos;
  1433   /* Total cluster advance */
  1434   hb_position_t total_x_advance = 0, total_y_advance = 0;
  1435   for (unsigned int i = start; i < end; i++)
  1437     total_x_advance += pos[i].x_advance;
  1438     total_y_advance += pos[i].y_advance;
  1441   hb_position_t x_advance = 0, y_advance = 0;
  1442   for (unsigned int i = start; i < end; i++)
  1444     pos[i].x_offset += x_advance;
  1445     pos[i].y_offset += y_advance;
  1447     x_advance += pos[i].x_advance;
  1448     y_advance += pos[i].y_advance;
  1450     pos[i].x_advance = 0;
  1451     pos[i].y_advance = 0;
  1454   if (backward)
  1456     /* Transfer all cluster advance to the last glyph. */
  1457     pos[end - 1].x_advance = total_x_advance;
  1458     pos[end - 1].y_advance = total_y_advance;
  1460     hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
  1461   } else {
  1462     /* Transfer all cluster advance to the first glyph. */
  1463     pos[start].x_advance += total_x_advance;
  1464     pos[start].y_advance += total_y_advance;
  1465     for (unsigned int i = start + 1; i < end; i++) {
  1466       pos[i].x_offset -= total_x_advance;
  1467       pos[i].y_offset -= total_y_advance;
  1469     hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
  1473 /**
  1474  * hb_buffer_normalize_glyphs:
  1475  * @buffer: a buffer.
  1479  * Since: 1.0
  1480  **/
  1481 void
  1482 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
  1484   assert (buffer->have_positions);
  1485   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
  1487   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
  1489   unsigned int count = buffer->len;
  1490   if (unlikely (!count)) return;
  1491   hb_glyph_info_t *info = buffer->info;
  1493   unsigned int start = 0;
  1494   unsigned int end;
  1495   for (end = start + 1; end < count; end++)
  1496     if (info[start].cluster != info[end].cluster) {
  1497       normalize_glyphs_cluster (buffer, start, end, backward);
  1498       start = end;
  1500   normalize_glyphs_cluster (buffer, start, end, backward);

mercurial