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 }
|