< prev index next >

src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.cc

Print this page




  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  */
  29 
  30 #include "hb-buffer-private.hh"
  31 #include "hb-utf-private.hh"
  32 
  33 
  34 #ifndef HB_DEBUG_BUFFER
  35 #define HB_DEBUG_BUFFER (HB_DEBUG+0)
  36 #endif
  37 
  38 /**
  39  * SECTION: hb-buffer
  40  * @title: Buffers
  41  * @short_description: Input and output buffers
  42  * @include: hb.h
  43  *
  44  * Buffers serve dual role in HarfBuzz; they hold the input characters that are
  45  * passed hb_shape(), and after shaping they hold the output glyphs.
  46  **/
  47 
  48 /**
  49  * hb_segment_properties_equal:
  50  * @a: first #hb_segment_properties_t to compare.
  51  * @b: second #hb_segment_properties_t to compare.
  52  *
  53  * Checks the equality of two #hb_segment_properties_t's.
  54  *
  55  * Return value:
  56  * %true if all properties of @a equal those of @b, false otherwise.
  57  *


 107  * This should all remain transparent to the user.  swap_buffers() then
 108  * switches info and out_info.
 109  */
 110 
 111 
 112 
 113 /* Internal API */
 114 
 115 bool
 116 hb_buffer_t::enlarge (unsigned int size)
 117 {
 118   if (unlikely (in_error))
 119     return false;
 120   if (unlikely (size > max_len))
 121   {
 122     in_error = true;
 123     return false;
 124   }
 125 
 126   unsigned int new_allocated = allocated;
 127   hb_glyph_position_t *new_pos = NULL;
 128   hb_glyph_info_t *new_info = NULL;
 129   bool separate_out = out_info != info;
 130 
 131   if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
 132     goto done;
 133 
 134   while (size >= new_allocated)
 135     new_allocated += (new_allocated >> 1) + 32;
 136 
 137   ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
 138   if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
 139     goto done;
 140 
 141   new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
 142   new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
 143 
 144 done:
 145   if (unlikely (!new_pos || !new_info))
 146     in_error = true;
 147 
 148   if (likely (new_pos))
 149     pos = new_pos;
 150 
 151   if (likely (new_info))
 152     info = new_info;
 153 
 154   out_info = separate_out ? (hb_glyph_info_t *) pos : info;
 155   if (likely (!in_error))
 156     allocated = new_allocated;
 157 


 250   serial = 0;
 251 
 252   memset (context, 0, sizeof context);
 253   memset (context_len, 0, sizeof context_len);
 254 
 255   deallocate_var_all ();
 256 }
 257 
 258 void
 259 hb_buffer_t::add (hb_codepoint_t  codepoint,
 260                   unsigned int    cluster)
 261 {
 262   hb_glyph_info_t *glyph;
 263 
 264   if (unlikely (!ensure (len + 1))) return;
 265 
 266   glyph = &info[len];
 267 
 268   memset (glyph, 0, sizeof (*glyph));
 269   glyph->codepoint = codepoint;
 270   glyph->mask = 1;
 271   glyph->cluster = cluster;
 272 
 273   len++;
 274 }
 275 
 276 void
 277 hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
 278 {
 279   if (unlikely (!ensure (len + 1))) return;
 280 
 281   info[len] = glyph_info;
 282 
 283   len++;
 284 }
 285 
 286 
 287 void
 288 hb_buffer_t::remove_output (void)
 289 {
 290   if (unlikely (hb_object_is_inert (this)))


 533   reverse ();
 534 
 535   count = len;
 536   start = 0;
 537   last_cluster = info[0].cluster;
 538   for (i = 1; i < count; i++) {
 539     if (last_cluster != info[i].cluster) {
 540       reverse_range (start, i);
 541       start = i;
 542       last_cluster = info[i].cluster;
 543     }
 544   }
 545   reverse_range (start, i);
 546 }
 547 
 548 void
 549 hb_buffer_t::merge_clusters_impl (unsigned int start,
 550                                   unsigned int end)
 551 {
 552   if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)


 553     return;

 554 
 555   unsigned int cluster = info[start].cluster;
 556 
 557   for (unsigned int i = start + 1; i < end; i++)
 558     cluster = MIN (cluster, info[i].cluster);
 559 
 560   /* Extend end */
 561   while (end < len && info[end - 1].cluster == info[end].cluster)
 562     end++;
 563 
 564   /* Extend start */
 565   while (idx < start && info[start - 1].cluster == info[start].cluster)
 566     start--;
 567 
 568   /* If we hit the start of buffer, continue in out-buffer. */
 569   if (idx == start)
 570     for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
 571       out_info[i - 1].cluster = cluster;
 572 
 573   for (unsigned int i = start; i < end; i++)
 574     info[i].cluster = cluster;
 575 }
 576 void
 577 hb_buffer_t::merge_out_clusters (unsigned int start,
 578                                  unsigned int end)
 579 {
 580   if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
 581     return;
 582 
 583   if (unlikely (end - start < 2))
 584     return;
 585 
 586   unsigned int cluster = out_info[start].cluster;
 587 
 588   for (unsigned int i = start + 1; i < end; i++)
 589     cluster = MIN (cluster, out_info[i].cluster);
 590 
 591   /* Extend start */
 592   while (start && out_info[start - 1].cluster == out_info[start].cluster)
 593     start--;
 594 
 595   /* Extend end */
 596   while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
 597     end++;
 598 
 599   /* If we hit the end of out-buffer, continue in buffer. */
 600   if (end == out_len)
 601     for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
 602       info[i].cluster = cluster;
 603 
 604   for (unsigned int i = start; i < end; i++)
 605     out_info[i].cluster = cluster;
 606 }
 607 void
 608 hb_buffer_t::delete_glyph ()
 609 {


 610   unsigned int cluster = info[idx].cluster;
 611   if (idx + 1 < len && cluster == info[idx + 1].cluster)
 612   {
 613     /* Cluster survives; do nothing. */
 614     goto done;
 615   }
 616 
 617   if (out_len)
 618   {
 619     /* Merge cluster backward. */
 620     if (cluster < out_info[out_len - 1].cluster)
 621     {

 622       unsigned int old_cluster = out_info[out_len - 1].cluster;
 623       for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)
 624         out_info[i - 1].cluster = cluster;
 625     }
 626     goto done;
 627   }
 628 
 629   if (idx + 1 < len)
 630   {
 631     /* Merge cluster forward. */
 632     merge_clusters (idx, idx + 2);
 633     goto done;
 634   }
 635 
 636 done:
 637   skip_glyph ();
 638 }
 639 
 640 void


























 641 hb_buffer_t::guess_segment_properties (void)
 642 {
 643   assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
 644           (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
 645 
 646   /* If script is set to INVALID, guess from buffer contents */
 647   if (props.script == HB_SCRIPT_INVALID) {
 648     for (unsigned int i = 0; i < len; i++) {
 649       hb_script_t script = unicode->script (info[i].codepoint);
 650       if (likely (script != HB_SCRIPT_COMMON &&
 651                   script != HB_SCRIPT_INHERITED &&
 652                   script != HB_SCRIPT_UNKNOWN)) {
 653         props.script = script;
 654         break;
 655       }
 656     }
 657   }
 658 
 659   /* If direction is set to INVALID, guess from script */
 660   if (props.direction == HB_DIRECTION_INVALID) {


1363  * Return value: (transfer none) (array length=length):
1364  * The @buffer glyph position array.
1365  * The value valid as long as buffer has not been modified.
1366  *
1367  * Since: 0.9.2
1368  **/
1369 hb_glyph_position_t *
1370 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
1371                                unsigned int *length)
1372 {
1373   if (!buffer->have_positions)
1374     buffer->clear_positions ();
1375 
1376   if (length)
1377     *length = buffer->len;
1378 
1379   return (hb_glyph_position_t *) buffer->pos;
1380 }
1381 
1382 /**

















1383  * hb_buffer_reverse:
1384  * @buffer: an #hb_buffer_t.
1385  *
1386  * Reverses buffer contents.
1387  *
1388  * Since: 0.9.2
1389  **/
1390 void
1391 hb_buffer_reverse (hb_buffer_t *buffer)
1392 {
1393   buffer->reverse ();
1394 }
1395 
1396 /**
1397  * hb_buffer_reverse_range:
1398  * @buffer: an #hb_buffer_t.
1399  * @start: start index.
1400  * @end: end index.
1401  *
1402  * Reverses buffer contents between start to end.


1649  * @item_length, respectively, to give HarfBuzz the full context to be able,
1650  * for example, to do cross-run Arabic shaping or properly handle combining
1651  * marks at stat of run.
1652  *
1653  * This function does not check the validity of @text, it is up to the caller
1654  * to ensure it contains a valid Unicode code points.
1655  *
1656  * Since: 0.9.31
1657  **/
1658 void
1659 hb_buffer_add_codepoints (hb_buffer_t          *buffer,
1660                           const hb_codepoint_t *text,
1661                           int                   text_length,
1662                           unsigned int          item_offset,
1663                           int                   item_length)
1664 {
1665   hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
1666 }
1667 
1668 




















































1669 static int
1670 compare_info_codepoint (const hb_glyph_info_t *pa,
1671                         const hb_glyph_info_t *pb)
1672 {
1673   return (int) pb->codepoint - (int) pa->codepoint;
1674 }
1675 
1676 static inline void
1677 normalize_glyphs_cluster (hb_buffer_t *buffer,
1678                           unsigned int start,
1679                           unsigned int end,
1680                           bool backward)
1681 {
1682   hb_glyph_position_t *pos = buffer->pos;
1683 
1684   /* Total cluster advance */
1685   hb_position_t total_x_advance = 0, total_y_advance = 0;
1686   for (unsigned int i = start; i < end; i++)
1687   {
1688     total_x_advance += pos[i].x_advance;


1719     }
1720     hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
1721   }
1722 }
1723 
1724 /**
1725  * hb_buffer_normalize_glyphs:
1726  * @buffer: an #hb_buffer_t.
1727  *
1728  * Reorders a glyph buffer to have canonical in-cluster glyph order / position.
1729  * The resulting clusters should behave identical to pre-reordering clusters.
1730  *
1731  * <note>This has nothing to do with Unicode normalization.</note>
1732  *
1733  * Since: 0.9.2
1734  **/
1735 void
1736 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
1737 {
1738   assert (buffer->have_positions);
1739   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);

1740 
1741   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
1742 
1743   unsigned int count = buffer->len;
1744   if (unlikely (!count)) return;
1745   hb_glyph_info_t *info = buffer->info;
1746 
1747   unsigned int start = 0;
1748   unsigned int end;
1749   for (end = start + 1; end < count; end++)
1750     if (info[start].cluster != info[end].cluster) {
1751       normalize_glyphs_cluster (buffer, start, end, backward);
1752       start = end;
1753     }
1754   normalize_glyphs_cluster (buffer, start, end, backward);
1755 }
1756 
1757 void
1758 hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *))
1759 {
1760   assert (!have_positions);
1761   for (unsigned int i = start + 1; i < end; i++)
1762   {
1763     unsigned int j = i;
1764     while (j > start && compar (&info[j - 1], &info[i]) > 0)
1765       j--;
1766     if (i == j)
1767       continue;
1768     /* Move item i to occupy place for item j, shift what's in between. */
1769     merge_clusters (j, i + 1);
1770     {
1771       hb_glyph_info_t t = info[i];
1772       memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t));
1773       info[j] = t;
1774     }
1775   }
1776 }
1777 




























































































1778 /*
1779  * Debugging.
1780  */
1781 
1782 /**
1783  * hb_buffer_set_message_func:
1784  * @buffer: an #hb_buffer_t.
1785  * @func: (closure user_data) (destroy destroy) (scope notified):
1786  * @user_data:
1787  * @destroy:
1788  *
1789  * 
1790  *
1791  * Since: 1.1.3
1792  **/
1793 void
1794 hb_buffer_set_message_func (hb_buffer_t *buffer,
1795                             hb_buffer_message_func_t func,
1796                             void *user_data, hb_destroy_func_t destroy)
1797 {
1798   if (buffer->message_destroy)
1799     buffer->message_destroy (buffer->message_data);
1800 
1801   if (func) {
1802     buffer->message_func = func;
1803     buffer->message_data = user_data;
1804     buffer->message_destroy = destroy;
1805   } else {
1806     buffer->message_func = NULL;
1807     buffer->message_data = NULL;
1808     buffer->message_destroy = NULL;
1809   }
1810 }
1811 
1812 bool
1813 hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
1814 {
1815   char buf[100];
1816   vsnprintf (buf, sizeof (buf),  fmt, ap);
1817   return (bool) this->message_func (this, font, buf, this->message_data);
1818 }


  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  */
  29 
  30 #include "hb-buffer-private.hh"
  31 #include "hb-utf-private.hh"
  32 
  33 




  34 /**
  35  * SECTION: hb-buffer
  36  * @title: Buffers
  37  * @short_description: Input and output buffers
  38  * @include: hb.h
  39  *
  40  * Buffers serve dual role in HarfBuzz; they hold the input characters that are
  41  * passed hb_shape(), and after shaping they hold the output glyphs.
  42  **/
  43 
  44 /**
  45  * hb_segment_properties_equal:
  46  * @a: first #hb_segment_properties_t to compare.
  47  * @b: second #hb_segment_properties_t to compare.
  48  *
  49  * Checks the equality of two #hb_segment_properties_t's.
  50  *
  51  * Return value:
  52  * %true if all properties of @a equal those of @b, false otherwise.
  53  *


 103  * This should all remain transparent to the user.  swap_buffers() then
 104  * switches info and out_info.
 105  */
 106 
 107 
 108 
 109 /* Internal API */
 110 
 111 bool
 112 hb_buffer_t::enlarge (unsigned int size)
 113 {
 114   if (unlikely (in_error))
 115     return false;
 116   if (unlikely (size > max_len))
 117   {
 118     in_error = true;
 119     return false;
 120   }
 121 
 122   unsigned int new_allocated = allocated;
 123   hb_glyph_position_t *new_pos = nullptr;
 124   hb_glyph_info_t *new_info = nullptr;
 125   bool separate_out = out_info != info;
 126 
 127   if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
 128     goto done;
 129 
 130   while (size >= new_allocated)
 131     new_allocated += (new_allocated >> 1) + 32;
 132 
 133   static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");
 134   if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
 135     goto done;
 136 
 137   new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
 138   new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
 139 
 140 done:
 141   if (unlikely (!new_pos || !new_info))
 142     in_error = true;
 143 
 144   if (likely (new_pos))
 145     pos = new_pos;
 146 
 147   if (likely (new_info))
 148     info = new_info;
 149 
 150   out_info = separate_out ? (hb_glyph_info_t *) pos : info;
 151   if (likely (!in_error))
 152     allocated = new_allocated;
 153 


 246   serial = 0;
 247 
 248   memset (context, 0, sizeof context);
 249   memset (context_len, 0, sizeof context_len);
 250 
 251   deallocate_var_all ();
 252 }
 253 
 254 void
 255 hb_buffer_t::add (hb_codepoint_t  codepoint,
 256                   unsigned int    cluster)
 257 {
 258   hb_glyph_info_t *glyph;
 259 
 260   if (unlikely (!ensure (len + 1))) return;
 261 
 262   glyph = &info[len];
 263 
 264   memset (glyph, 0, sizeof (*glyph));
 265   glyph->codepoint = codepoint;
 266   glyph->mask = 0;
 267   glyph->cluster = cluster;
 268 
 269   len++;
 270 }
 271 
 272 void
 273 hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
 274 {
 275   if (unlikely (!ensure (len + 1))) return;
 276 
 277   info[len] = glyph_info;
 278 
 279   len++;
 280 }
 281 
 282 
 283 void
 284 hb_buffer_t::remove_output (void)
 285 {
 286   if (unlikely (hb_object_is_inert (this)))


 529   reverse ();
 530 
 531   count = len;
 532   start = 0;
 533   last_cluster = info[0].cluster;
 534   for (i = 1; i < count; i++) {
 535     if (last_cluster != info[i].cluster) {
 536       reverse_range (start, i);
 537       start = i;
 538       last_cluster = info[i].cluster;
 539     }
 540   }
 541   reverse_range (start, i);
 542 }
 543 
 544 void
 545 hb_buffer_t::merge_clusters_impl (unsigned int start,
 546                                   unsigned int end)
 547 {
 548   if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
 549   {
 550     unsafe_to_break (start, end);
 551     return;
 552   }
 553 
 554   unsigned int cluster = info[start].cluster;
 555 
 556   for (unsigned int i = start + 1; i < end; i++)
 557     cluster = MIN<unsigned int> (cluster, info[i].cluster);
 558 
 559   /* Extend end */
 560   while (end < len && info[end - 1].cluster == info[end].cluster)
 561     end++;
 562 
 563   /* Extend start */
 564   while (idx < start && info[start - 1].cluster == info[start].cluster)
 565     start--;
 566 
 567   /* If we hit the start of buffer, continue in out-buffer. */
 568   if (idx == start)
 569     for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
 570       set_cluster (out_info[i - 1], cluster);
 571 
 572   for (unsigned int i = start; i < end; i++)
 573     set_cluster (info[i], cluster);
 574 }
 575 void
 576 hb_buffer_t::merge_out_clusters (unsigned int start,
 577                                  unsigned int end)
 578 {
 579   if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
 580     return;
 581 
 582   if (unlikely (end - start < 2))
 583     return;
 584 
 585   unsigned int cluster = out_info[start].cluster;
 586 
 587   for (unsigned int i = start + 1; i < end; i++)
 588     cluster = MIN<unsigned int> (cluster, out_info[i].cluster);
 589 
 590   /* Extend start */
 591   while (start && out_info[start - 1].cluster == out_info[start].cluster)
 592     start--;
 593 
 594   /* Extend end */
 595   while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
 596     end++;
 597 
 598   /* If we hit the end of out-buffer, continue in buffer. */
 599   if (end == out_len)
 600     for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
 601       set_cluster (info[i], cluster);
 602 
 603   for (unsigned int i = start; i < end; i++)
 604     set_cluster (out_info[i], cluster);
 605 }
 606 void
 607 hb_buffer_t::delete_glyph ()
 608 {
 609   /* The logic here is duplicated in hb_ot_hide_default_ignorables(). */
 610 
 611   unsigned int cluster = info[idx].cluster;
 612   if (idx + 1 < len && cluster == info[idx + 1].cluster)
 613   {
 614     /* Cluster survives; do nothing. */
 615     goto done;
 616   }
 617 
 618   if (out_len)
 619   {
 620     /* Merge cluster backward. */
 621     if (cluster < out_info[out_len - 1].cluster)
 622     {
 623       unsigned int mask = info[idx].mask;
 624       unsigned int old_cluster = out_info[out_len - 1].cluster;
 625       for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)
 626         set_cluster (out_info[i - 1], cluster, mask);
 627     }
 628     goto done;
 629   }
 630 
 631   if (idx + 1 < len)
 632   {
 633     /* Merge cluster forward. */
 634     merge_clusters (idx, idx + 2);
 635     goto done;
 636   }
 637 
 638 done:
 639   skip_glyph ();
 640 }
 641 
 642 void
 643 hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end)
 644 {
 645   unsigned int cluster = (unsigned int) -1;
 646   cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster);
 647   _unsafe_to_break_set_mask (info, start, end, cluster);
 648 }
 649 void
 650 hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end)
 651 {
 652   if (!have_output)
 653   {
 654     unsafe_to_break_impl (start, end);
 655     return;
 656   }
 657 
 658   assert (start <= out_len);
 659   assert (idx <= end);
 660 
 661   unsigned int cluster = (unsigned int) -1;
 662   cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster);
 663   cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster);
 664   _unsafe_to_break_set_mask (out_info, start, out_len, cluster);
 665   _unsafe_to_break_set_mask (info, idx, end, cluster);
 666 }
 667 
 668 void
 669 hb_buffer_t::guess_segment_properties (void)
 670 {
 671   assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
 672           (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
 673 
 674   /* If script is set to INVALID, guess from buffer contents */
 675   if (props.script == HB_SCRIPT_INVALID) {
 676     for (unsigned int i = 0; i < len; i++) {
 677       hb_script_t script = unicode->script (info[i].codepoint);
 678       if (likely (script != HB_SCRIPT_COMMON &&
 679                   script != HB_SCRIPT_INHERITED &&
 680                   script != HB_SCRIPT_UNKNOWN)) {
 681         props.script = script;
 682         break;
 683       }
 684     }
 685   }
 686 
 687   /* If direction is set to INVALID, guess from script */
 688   if (props.direction == HB_DIRECTION_INVALID) {


1391  * Return value: (transfer none) (array length=length):
1392  * The @buffer glyph position array.
1393  * The value valid as long as buffer has not been modified.
1394  *
1395  * Since: 0.9.2
1396  **/
1397 hb_glyph_position_t *
1398 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
1399                                unsigned int *length)
1400 {
1401   if (!buffer->have_positions)
1402     buffer->clear_positions ();
1403 
1404   if (length)
1405     *length = buffer->len;
1406 
1407   return (hb_glyph_position_t *) buffer->pos;
1408 }
1409 
1410 /**
1411  * hb_glyph_info_get_glyph_flags:
1412  * @info: a #hb_glyph_info_t.
1413  *
1414  * Returns glyph flags encoded within a #hb_glyph_info_t.
1415  *
1416  * Return value:
1417  * The #hb_glyph_flags_t encoded within @info.
1418  *
1419  * Since: 1.5.0
1420  **/
1421 hb_glyph_flags_t
1422 (hb_glyph_info_get_glyph_flags) (const hb_glyph_info_t *info)
1423 {
1424   return hb_glyph_info_get_glyph_flags (info);
1425 }
1426 
1427 /**
1428  * hb_buffer_reverse:
1429  * @buffer: an #hb_buffer_t.
1430  *
1431  * Reverses buffer contents.
1432  *
1433  * Since: 0.9.2
1434  **/
1435 void
1436 hb_buffer_reverse (hb_buffer_t *buffer)
1437 {
1438   buffer->reverse ();
1439 }
1440 
1441 /**
1442  * hb_buffer_reverse_range:
1443  * @buffer: an #hb_buffer_t.
1444  * @start: start index.
1445  * @end: end index.
1446  *
1447  * Reverses buffer contents between start to end.


1694  * @item_length, respectively, to give HarfBuzz the full context to be able,
1695  * for example, to do cross-run Arabic shaping or properly handle combining
1696  * marks at stat of run.
1697  *
1698  * This function does not check the validity of @text, it is up to the caller
1699  * to ensure it contains a valid Unicode code points.
1700  *
1701  * Since: 0.9.31
1702  **/
1703 void
1704 hb_buffer_add_codepoints (hb_buffer_t          *buffer,
1705                           const hb_codepoint_t *text,
1706                           int                   text_length,
1707                           unsigned int          item_offset,
1708                           int                   item_length)
1709 {
1710   hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
1711 }
1712 
1713 
1714 /**
1715  * hb_buffer_append:
1716  * @buffer: an #hb_buffer_t.
1717  * @source: source #hb_buffer_t.
1718  * @start: start index into source buffer to copy.  Use 0 to copy from start of buffer.
1719  * @end: end index into source buffer to copy.  Use (unsigned int) -1 to copy to end of buffer.
1720  *
1721  * Append (part of) contents of another buffer to this buffer.
1722  *
1723  * Since: 1.5.0
1724  **/
1725 HB_EXTERN void
1726 hb_buffer_append (hb_buffer_t *buffer,
1727                   hb_buffer_t *source,
1728                   unsigned int start,
1729                   unsigned int end)
1730 {
1731   assert (!buffer->have_output && !source->have_output);
1732   assert (buffer->have_positions == source->have_positions ||
1733           !buffer->len || !source->len);
1734   assert (buffer->content_type == source->content_type ||
1735           !buffer->len || !source->len);
1736 
1737   if (end > source->len)
1738     end = source->len;
1739   if (start > end)
1740     start = end;
1741   if (start == end)
1742     return;
1743 
1744   if (!buffer->len)
1745     buffer->content_type = source->content_type;
1746   if (!buffer->have_positions && source->have_positions)
1747     buffer->clear_positions ();
1748 
1749   if (buffer->len + (end - start) < buffer->len) /* Overflows. */
1750   {
1751     buffer->in_error = true;
1752     return;
1753   }
1754 
1755   unsigned int orig_len = buffer->len;
1756   hb_buffer_set_length (buffer, buffer->len + (end - start));
1757   if (buffer->in_error)
1758     return;
1759 
1760   memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
1761   if (buffer->have_positions)
1762     memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
1763 }
1764 
1765 
1766 static int
1767 compare_info_codepoint (const hb_glyph_info_t *pa,
1768                         const hb_glyph_info_t *pb)
1769 {
1770   return (int) pb->codepoint - (int) pa->codepoint;
1771 }
1772 
1773 static inline void
1774 normalize_glyphs_cluster (hb_buffer_t *buffer,
1775                           unsigned int start,
1776                           unsigned int end,
1777                           bool backward)
1778 {
1779   hb_glyph_position_t *pos = buffer->pos;
1780 
1781   /* Total cluster advance */
1782   hb_position_t total_x_advance = 0, total_y_advance = 0;
1783   for (unsigned int i = start; i < end; i++)
1784   {
1785     total_x_advance += pos[i].x_advance;


1816     }
1817     hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
1818   }
1819 }
1820 
1821 /**
1822  * hb_buffer_normalize_glyphs:
1823  * @buffer: an #hb_buffer_t.
1824  *
1825  * Reorders a glyph buffer to have canonical in-cluster glyph order / position.
1826  * The resulting clusters should behave identical to pre-reordering clusters.
1827  *
1828  * <note>This has nothing to do with Unicode normalization.</note>
1829  *
1830  * Since: 0.9.2
1831  **/
1832 void
1833 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
1834 {
1835   assert (buffer->have_positions);
1836   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS ||
1837           (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
1838 
1839   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
1840 
1841   unsigned int count = buffer->len;
1842   if (unlikely (!count)) return;
1843   hb_glyph_info_t *info = buffer->info;
1844 
1845   unsigned int start = 0;
1846   unsigned int end;
1847   for (end = start + 1; end < count; end++)
1848     if (info[start].cluster != info[end].cluster) {
1849       normalize_glyphs_cluster (buffer, start, end, backward);
1850       start = end;
1851     }
1852   normalize_glyphs_cluster (buffer, start, end, backward);
1853 }
1854 
1855 void
1856 hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *))
1857 {
1858   assert (!have_positions);
1859   for (unsigned int i = start + 1; i < end; i++)
1860   {
1861     unsigned int j = i;
1862     while (j > start && compar (&info[j - 1], &info[i]) > 0)
1863       j--;
1864     if (i == j)
1865       continue;
1866     /* Move item i to occupy place for item j, shift what's in between. */
1867     merge_clusters (j, i + 1);
1868     {
1869       hb_glyph_info_t t = info[i];
1870       memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t));
1871       info[j] = t;
1872     }
1873   }
1874 }
1875 
1876 
1877 /*
1878  * Comparing buffers.
1879  */
1880 
1881 /**
1882  * hb_buffer_diff:
1883  *
1884  * If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
1885  * and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned.  This should be used by most
1886  * callers if just comparing two buffers is needed.
1887  *
1888  * Since: 1.5.0
1889  **/
1890 hb_buffer_diff_flags_t
1891 hb_buffer_diff (hb_buffer_t *buffer,
1892                 hb_buffer_t *reference,
1893                 hb_codepoint_t dottedcircle_glyph,
1894                 unsigned int position_fuzz)
1895 {
1896   if (buffer->content_type != reference->content_type && buffer->len && reference->len)
1897     return HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH;
1898 
1899   hb_buffer_diff_flags_t result = HB_BUFFER_DIFF_FLAG_EQUAL;
1900   bool contains = dottedcircle_glyph != (hb_codepoint_t) -1;
1901 
1902   unsigned int count = reference->len;
1903 
1904   if (buffer->len != count)
1905   {
1906     /*
1907      * we can't compare glyph-by-glyph, but we do want to know if there
1908      * are .notdef or dottedcircle glyphs present in the reference buffer
1909      */
1910     const hb_glyph_info_t *info = reference->info;
1911     unsigned int i;
1912     for (i = 0; i < count; i++)
1913     {
1914       if (contains && info[i].codepoint == dottedcircle_glyph)
1915         result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
1916       if (contains && info[i].codepoint == 0)
1917         result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
1918     }
1919     result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;
1920     return hb_buffer_diff_flags_t (result);
1921   }
1922 
1923   if (!count)
1924     return hb_buffer_diff_flags_t (result);
1925 
1926   const hb_glyph_info_t *buf_info = buffer->info;
1927   const hb_glyph_info_t *ref_info = reference->info;
1928   for (unsigned int i = 0; i < count; i++)
1929   {
1930     if (buf_info->codepoint != ref_info->codepoint)
1931       result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;
1932     if (buf_info->cluster != ref_info->cluster)
1933       result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;
1934     if ((buf_info->mask & HB_GLYPH_FLAG_DEFINED) != (ref_info->mask & HB_GLYPH_FLAG_DEFINED))
1935       result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;
1936     if (contains && ref_info->codepoint == dottedcircle_glyph)
1937       result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
1938     if (contains && ref_info->codepoint == 0)
1939       result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
1940     buf_info++;
1941     ref_info++;
1942   }
1943 
1944   if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)
1945   {
1946     assert (buffer->have_positions);
1947     const hb_glyph_position_t *buf_pos = buffer->pos;
1948     const hb_glyph_position_t *ref_pos = reference->pos;
1949     for (unsigned int i = 0; i < count; i++)
1950     {
1951       if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||
1952           (unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
1953           (unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
1954           (unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
1955       {
1956         result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
1957         break;
1958       }
1959       buf_pos++;
1960       ref_pos++;
1961     }
1962   }
1963 
1964   return result;
1965 }
1966 
1967 
1968 /*
1969  * Debugging.
1970  */
1971 
1972 /**
1973  * hb_buffer_set_message_func:
1974  * @buffer: an #hb_buffer_t.
1975  * @func: (closure user_data) (destroy destroy) (scope notified):
1976  * @user_data:
1977  * @destroy:
1978  *
1979  *
1980  *
1981  * Since: 1.1.3
1982  **/
1983 void
1984 hb_buffer_set_message_func (hb_buffer_t *buffer,
1985                             hb_buffer_message_func_t func,
1986                             void *user_data, hb_destroy_func_t destroy)
1987 {
1988   if (buffer->message_destroy)
1989     buffer->message_destroy (buffer->message_data);
1990 
1991   if (func) {
1992     buffer->message_func = func;
1993     buffer->message_data = user_data;
1994     buffer->message_destroy = destroy;
1995   } else {
1996     buffer->message_func = nullptr;
1997     buffer->message_data = nullptr;
1998     buffer->message_destroy = nullptr;
1999   }
2000 }
2001 
2002 bool
2003 hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
2004 {
2005   char buf[100];
2006   vsnprintf (buf, sizeof (buf),  fmt, ap);
2007   return (bool) this->message_func (this, font, buf, this->message_data);
2008 }
< prev index next >