Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/harfbuzz/src/hb-buffer.cc
20956 views
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
*/
29
30
#include "hb-buffer.hh"
31
#include "hb-utf.hh"
32
33
34
/**
35
* SECTION: hb-buffer
36
* @title: hb-buffer
37
* @short_description: Input and output buffers
38
* @include: hb.h
39
*
40
* Buffers serve a dual role in HarfBuzz; before shaping, they hold
41
* the input characters that are passed to hb_shape(), and after
42
* shaping they hold the output glyphs.
43
*
44
* The input buffer is a sequence of Unicode codepoints, with
45
* associated attributes such as direction and script. The output
46
* buffer is a sequence of glyphs, with associated attributes such
47
* as position and cluster.
48
**/
49
50
51
/**
52
* hb_segment_properties_equal:
53
* @a: first #hb_segment_properties_t to compare.
54
* @b: second #hb_segment_properties_t to compare.
55
*
56
* Checks the equality of two #hb_segment_properties_t's.
57
*
58
* Return value:
59
* `true` if all properties of @a equal those of @b, `false` otherwise.
60
*
61
* Since: 0.9.7
62
**/
63
hb_bool_t
64
hb_segment_properties_equal (const hb_segment_properties_t *a,
65
const hb_segment_properties_t *b)
66
{
67
return a->direction == b->direction &&
68
a->script == b->script &&
69
a->language == b->language &&
70
a->reserved1 == b->reserved1 &&
71
a->reserved2 == b->reserved2;
72
73
}
74
75
/**
76
* hb_segment_properties_hash:
77
* @p: #hb_segment_properties_t to hash.
78
*
79
* Creates a hash representing @p.
80
*
81
* Return value:
82
* A hash of @p.
83
*
84
* Since: 0.9.7
85
**/
86
unsigned int
87
hb_segment_properties_hash (const hb_segment_properties_t *p)
88
{
89
return ((unsigned int) p->direction * 31 +
90
(unsigned int) p->script) * 31 +
91
(intptr_t) (p->language);
92
}
93
94
/**
95
* hb_segment_properties_overlay:
96
* @p: #hb_segment_properties_t to fill in.
97
* @src: #hb_segment_properties_t to fill in from.
98
*
99
* Fills in missing fields of @p from @src in a considered manner.
100
*
101
* First, if @p does not have direction set, direction is copied from @src.
102
*
103
* Next, if @p and @src have the same direction (which can be unset), if @p
104
* does not have script set, script is copied from @src.
105
*
106
* Finally, if @p and @src have the same direction and script (which either
107
* can be unset), if @p does not have language set, language is copied from
108
* @src.
109
*
110
* Since: 3.3.0
111
**/
112
void
113
hb_segment_properties_overlay (hb_segment_properties_t *p,
114
const hb_segment_properties_t *src)
115
{
116
if (unlikely (!p || !src))
117
return;
118
119
if (!p->direction)
120
p->direction = src->direction;
121
122
if (p->direction != src->direction)
123
return;
124
125
if (!p->script)
126
p->script = src->script;
127
128
if (p->script != src->script)
129
return;
130
131
if (!p->language)
132
p->language = src->language;
133
}
134
135
/* Here is how the buffer works internally:
136
*
137
* There are two info pointers: info and out_info. They always have
138
* the same allocated size, but different lengths.
139
*
140
* As an optimization, both info and out_info may point to the
141
* same piece of memory, which is owned by info. This remains the
142
* case as long as out_len doesn't exceed i at any time.
143
* In that case, sync() is mostly no-op and the glyph operations
144
* operate mostly in-place.
145
*
146
* As soon as out_info gets longer than info, out_info is moved over
147
* to an alternate buffer (which we reuse the pos buffer for), and its
148
* current contents (out_len entries) are copied to the new place.
149
*
150
* This should all remain transparent to the user. sync() then
151
* switches info over to out_info and does housekeeping.
152
*/
153
154
155
156
/* Internal API */
157
158
bool
159
hb_buffer_t::enlarge (unsigned int size)
160
{
161
if (unlikely (size > max_len))
162
{
163
successful = false;
164
return false;
165
}
166
167
if (unlikely (!successful))
168
return false;
169
170
unsigned int new_allocated = allocated;
171
hb_glyph_position_t *new_pos = nullptr;
172
hb_glyph_info_t *new_info = nullptr;
173
bool separate_out = out_info != info;
174
175
if (unlikely (hb_unsigned_mul_overflows (size, sizeof (info[0]))))
176
goto done;
177
178
while (size >= new_allocated)
179
new_allocated += (new_allocated >> 1) + 32;
180
181
unsigned new_bytes;
182
if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]), &new_bytes)))
183
goto done;
184
185
static_assert (sizeof (info[0]) == sizeof (pos[0]), "");
186
new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_bytes);
187
new_info = (hb_glyph_info_t *) hb_realloc (info, new_bytes);
188
189
done:
190
if (unlikely (!new_pos || !new_info))
191
successful = false;
192
193
if (likely (new_pos))
194
pos = new_pos;
195
196
if (likely (new_info))
197
info = new_info;
198
199
out_info = separate_out ? (hb_glyph_info_t *) pos : info;
200
if (likely (successful))
201
allocated = new_allocated;
202
203
return likely (successful);
204
}
205
206
bool
207
hb_buffer_t::make_room_for (unsigned int num_in,
208
unsigned int num_out)
209
{
210
if (unlikely (!ensure (out_len + num_out))) return false;
211
212
if (out_info == info &&
213
out_len + num_out > idx + num_in)
214
{
215
assert (have_output);
216
217
out_info = (hb_glyph_info_t *) pos;
218
hb_memcpy (out_info, info, out_len * sizeof (out_info[0]));
219
}
220
221
return true;
222
}
223
224
bool
225
hb_buffer_t::shift_forward (unsigned int count)
226
{
227
assert (have_output);
228
if (unlikely (!ensure (len + count))) return false;
229
230
max_ops -= len - idx;
231
if (unlikely (max_ops < 0))
232
{
233
successful = false;
234
return false;
235
}
236
237
memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
238
if (idx + count > len)
239
{
240
/* Under memory failure we might expose this area. At least
241
* clean it up. Oh well...
242
*
243
* Ideally, we should at least set Default_Ignorable bits on
244
* these, as well as consistent cluster values. But the former
245
* is layering violation... */
246
hb_memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
247
}
248
len += count;
249
idx += count;
250
251
return true;
252
}
253
254
hb_buffer_t::scratch_buffer_t *
255
hb_buffer_t::get_scratch_buffer (unsigned int *size)
256
{
257
have_output = false;
258
have_positions = false;
259
260
out_len = 0;
261
out_info = info;
262
263
assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);
264
*size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);
265
return (scratch_buffer_t *) (void *) pos;
266
}
267
268
269
270
/* HarfBuzz-Internal API */
271
272
void
273
hb_buffer_t::similar (const hb_buffer_t &src)
274
{
275
hb_unicode_funcs_destroy (unicode);
276
unicode = hb_unicode_funcs_reference (src.unicode);
277
flags = src.flags;
278
cluster_level = src.cluster_level;
279
replacement = src.replacement;
280
invisible = src.invisible;
281
not_found = src.not_found;
282
not_found_variation_selector = src.not_found_variation_selector;
283
}
284
285
void
286
hb_buffer_t::reset ()
287
{
288
hb_unicode_funcs_destroy (unicode);
289
unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
290
flags = HB_BUFFER_FLAG_DEFAULT;
291
cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
292
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
293
invisible = 0;
294
not_found = 0;
295
not_found_variation_selector = HB_CODEPOINT_INVALID;
296
297
clear ();
298
}
299
300
void
301
hb_buffer_t::clear ()
302
{
303
content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
304
hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
305
props = default_props;
306
307
successful = true;
308
have_output = false;
309
have_positions = false;
310
311
idx = 0;
312
len = 0;
313
out_len = 0;
314
out_info = info;
315
316
hb_memset (context, 0, sizeof context);
317
hb_memset (context_len, 0, sizeof context_len);
318
319
deallocate_var_all ();
320
serial = 0;
321
random_state = 1;
322
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
323
}
324
325
void
326
hb_buffer_t::enter ()
327
{
328
deallocate_var_all ();
329
serial = 0;
330
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
331
unsigned mul;
332
if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul)))
333
{
334
max_len = hb_max (mul, (unsigned) HB_BUFFER_MAX_LEN_MIN);
335
}
336
if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR, &mul)))
337
{
338
max_ops = hb_max (mul, (unsigned) HB_BUFFER_MAX_OPS_MIN);
339
}
340
}
341
void
342
hb_buffer_t::leave ()
343
{
344
max_len = HB_BUFFER_MAX_LEN_DEFAULT;
345
max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
346
deallocate_var_all ();
347
serial = 0;
348
}
349
350
351
void
352
hb_buffer_t::add (hb_codepoint_t codepoint,
353
unsigned int cluster)
354
{
355
hb_glyph_info_t *glyph;
356
357
if (unlikely (!ensure (len + 1))) return;
358
359
glyph = &info[len];
360
361
hb_memset (glyph, 0, sizeof (*glyph));
362
glyph->codepoint = codepoint;
363
glyph->mask = 0;
364
glyph->cluster = cluster;
365
366
len++;
367
}
368
369
void
370
hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
371
{
372
if (unlikely (!ensure (len + 1))) return;
373
374
info[len] = glyph_info;
375
376
len++;
377
}
378
void
379
hb_buffer_t::add_info_and_pos (const hb_glyph_info_t &glyph_info,
380
const hb_glyph_position_t &glyph_pos)
381
{
382
if (unlikely (!ensure (len + 1))) return;
383
384
info[len] = glyph_info;
385
assert (have_positions);
386
pos[len] = glyph_pos;
387
388
len++;
389
}
390
391
392
void
393
hb_buffer_t::clear_output ()
394
{
395
have_output = true;
396
have_positions = false;
397
398
idx = 0;
399
out_len = 0;
400
out_info = info;
401
}
402
403
void
404
hb_buffer_t::clear_positions ()
405
{
406
have_output = false;
407
have_positions = true;
408
409
out_len = 0;
410
out_info = info;
411
412
hb_memset (pos, 0, sizeof (pos[0]) * len);
413
}
414
415
bool
416
hb_buffer_t::sync ()
417
{
418
bool ret = false;
419
420
assert (have_output);
421
422
assert (idx <= len);
423
424
if (unlikely (!successful || !next_glyphs (len - idx)))
425
goto reset;
426
427
if (out_info != info)
428
{
429
pos = (hb_glyph_position_t *) info;
430
info = out_info;
431
}
432
len = out_len;
433
ret = true;
434
435
reset:
436
have_output = false;
437
out_len = 0;
438
out_info = info;
439
idx = 0;
440
441
return ret;
442
}
443
444
int
445
hb_buffer_t::sync_so_far ()
446
{
447
bool had_output = have_output;
448
unsigned out_i = out_len;
449
unsigned i = idx;
450
unsigned old_idx = idx;
451
452
if (sync ())
453
idx = out_i;
454
else
455
idx = i;
456
457
if (had_output)
458
{
459
have_output = true;
460
out_len = idx;
461
}
462
463
assert (idx <= len);
464
465
return idx - old_idx;
466
}
467
468
bool
469
hb_buffer_t::move_to (unsigned int i)
470
{
471
if (!have_output)
472
{
473
assert (i <= len);
474
idx = i;
475
return true;
476
}
477
if (unlikely (!successful))
478
return false;
479
480
assert (i <= out_len + (len - idx));
481
482
if (out_len < i)
483
{
484
unsigned int count = i - out_len;
485
if (unlikely (!make_room_for (count, count))) return false;
486
487
memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
488
idx += count;
489
out_len += count;
490
}
491
else if (out_len > i)
492
{
493
/* Tricky part: rewinding... */
494
unsigned int count = out_len - i;
495
496
/* This will blow in our face if memory allocation fails later
497
* in this same lookup...
498
*
499
* We used to shift with extra 32 items.
500
* But that would leave empty slots in the buffer in case of allocation
501
* failures. See comments in shift_forward(). This can cause O(N^2)
502
* behavior more severely than adding 32 empty slots can... */
503
if (unlikely (idx < count && !shift_forward (count - idx))) return false;
504
505
assert (idx >= count);
506
507
idx -= count;
508
out_len -= count;
509
memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));
510
}
511
512
return true;
513
}
514
515
516
void
517
hb_buffer_t::set_masks (hb_mask_t value,
518
hb_mask_t mask,
519
unsigned int cluster_start,
520
unsigned int cluster_end)
521
{
522
if (!mask)
523
return;
524
525
hb_mask_t not_mask = ~mask;
526
value &= mask;
527
528
max_ops -= len;
529
if (unlikely (max_ops < 0))
530
successful = false;
531
532
unsigned int count = len;
533
534
if (cluster_start == 0 && cluster_end == (unsigned int) -1)
535
{
536
for (unsigned int i = 0; i < count; i++)
537
info[i].mask = (info[i].mask & not_mask) | value;
538
return;
539
}
540
541
for (unsigned int i = 0; i < count; i++)
542
if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
543
info[i].mask = (info[i].mask & not_mask) | value;
544
}
545
546
void
547
hb_buffer_t::merge_clusters_impl (unsigned int start,
548
unsigned int end)
549
{
550
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
551
{
552
unsafe_to_break (start, end);
553
return;
554
}
555
556
max_ops -= end - start;
557
if (unlikely (max_ops < 0))
558
successful = false;
559
560
unsigned int cluster = info[start].cluster;
561
562
for (unsigned int i = start + 1; i < end; i++)
563
cluster = hb_min (cluster, info[i].cluster);
564
565
/* Extend end */
566
if (cluster != info[end - 1].cluster)
567
while (end < len && info[end - 1].cluster == info[end].cluster)
568
end++;
569
570
/* Extend start */
571
if (cluster != info[start].cluster)
572
while (idx < start && info[start - 1].cluster == info[start].cluster)
573
start--;
574
575
/* If we hit the start of buffer, continue in out-buffer. */
576
if (idx == start && info[start].cluster != cluster)
577
for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
578
set_cluster (out_info[i - 1], cluster);
579
580
for (unsigned int i = start; i < end; i++)
581
set_cluster (info[i], cluster);
582
}
583
void
584
hb_buffer_t::merge_out_clusters (unsigned int start,
585
unsigned int end)
586
{
587
if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level))
588
return;
589
590
if (unlikely (end - start < 2))
591
return;
592
593
max_ops -= end - start;
594
if (unlikely (max_ops < 0))
595
successful = false;
596
597
unsigned int cluster = out_info[start].cluster;
598
599
for (unsigned int i = start + 1; i < end; i++)
600
cluster = hb_min (cluster, out_info[i].cluster);
601
602
/* Extend start */
603
while (start && out_info[start - 1].cluster == out_info[start].cluster)
604
start--;
605
606
/* Extend end */
607
while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
608
end++;
609
610
/* If we hit the end of out-buffer, continue in buffer. */
611
if (end == out_len)
612
for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
613
set_cluster (info[i], cluster);
614
615
for (unsigned int i = start; i < end; i++)
616
set_cluster (out_info[i], cluster);
617
}
618
void
619
hb_buffer_t::delete_glyph ()
620
{
621
/* The logic here is duplicated in hb_ot_hide_default_ignorables(). */
622
623
unsigned int cluster = info[idx].cluster;
624
if ((idx + 1 < len && cluster == info[idx + 1].cluster) ||
625
(out_len && cluster == out_info[out_len - 1].cluster))
626
{
627
/* Cluster survives; do nothing. */
628
goto done;
629
}
630
631
if (out_len)
632
{
633
/* Merge cluster backward. */
634
if (cluster < out_info[out_len - 1].cluster)
635
{
636
unsigned int mask = info[idx].mask;
637
unsigned int old_cluster = out_info[out_len - 1].cluster;
638
for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)
639
set_cluster (out_info[i - 1], cluster, mask);
640
}
641
goto done;
642
}
643
644
if (idx + 1 < len)
645
{
646
/* Merge cluster forward. */
647
merge_clusters (idx, idx + 2);
648
goto done;
649
}
650
651
done:
652
skip_glyph ();
653
}
654
655
void
656
hb_buffer_t::delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info))
657
{
658
/* Merge clusters and delete filtered glyphs.
659
* NOTE! We can't use out-buffer as we have positioning data. */
660
unsigned int j = 0;
661
unsigned int count = len;
662
for (unsigned int i = 0; i < count; i++)
663
{
664
if (filter (&info[i]))
665
{
666
/* Merge clusters.
667
* Same logic as delete_glyph(), but for in-place removal. */
668
669
unsigned int cluster = info[i].cluster;
670
if (i + 1 < count && cluster == info[i + 1].cluster)
671
continue; /* Cluster survives; do nothing. */
672
673
if (j)
674
{
675
/* Merge cluster backward. */
676
if (cluster < info[j - 1].cluster)
677
{
678
unsigned int mask = info[i].mask;
679
unsigned int old_cluster = info[j - 1].cluster;
680
for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
681
set_cluster (info[k - 1], cluster, mask);
682
}
683
continue;
684
}
685
686
if (i + 1 < count)
687
merge_clusters (i, i + 2); /* Merge cluster forward. */
688
689
continue;
690
}
691
692
if (j != i)
693
{
694
info[j] = info[i];
695
pos[j] = pos[i];
696
}
697
j++;
698
}
699
len = j;
700
}
701
702
void
703
hb_buffer_t::guess_segment_properties ()
704
{
705
assert_unicode ();
706
707
/* If script is set to INVALID, guess from buffer contents */
708
if (props.script == HB_SCRIPT_INVALID) {
709
for (unsigned int i = 0; i < len; i++) {
710
hb_script_t script = unicode->script (info[i].codepoint);
711
if (likely (script != HB_SCRIPT_COMMON &&
712
script != HB_SCRIPT_INHERITED &&
713
script != HB_SCRIPT_UNKNOWN)) {
714
props.script = script;
715
break;
716
}
717
}
718
}
719
720
/* If direction is set to INVALID, guess from script */
721
if (props.direction == HB_DIRECTION_INVALID) {
722
props.direction = hb_script_get_horizontal_direction (props.script);
723
if (props.direction == HB_DIRECTION_INVALID)
724
props.direction = HB_DIRECTION_LTR;
725
}
726
727
/* If language is not set, use default language from locale */
728
if (props.language == HB_LANGUAGE_INVALID) {
729
/* TODO get_default_for_script? using $LANGUAGE */
730
props.language = hb_language_get_default ();
731
}
732
}
733
734
735
/* Public API */
736
737
DEFINE_NULL_INSTANCE (hb_buffer_t) =
738
{
739
HB_OBJECT_HEADER_STATIC,
740
741
const_cast<hb_unicode_funcs_t *> (&_hb_Null_hb_unicode_funcs_t),
742
HB_BUFFER_FLAG_DEFAULT,
743
HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
744
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
745
0, /* invisible */
746
0, /* not_found */
747
HB_CODEPOINT_INVALID, /* not_found_variation_selector */
748
749
750
HB_BUFFER_CONTENT_TYPE_INVALID,
751
HB_SEGMENT_PROPERTIES_DEFAULT,
752
753
false, /* successful */
754
false, /* have_output */
755
true /* have_positions */
756
757
/* Zero is good enough for everything else. */
758
};
759
760
761
/**
762
* hb_buffer_create:
763
*
764
* Creates a new #hb_buffer_t with all properties to defaults.
765
*
766
* Return value: (transfer full):
767
* A newly allocated #hb_buffer_t with a reference count of 1. The initial
768
* reference count should be released with hb_buffer_destroy() when you are done
769
* using the #hb_buffer_t. This function never returns `NULL`. If memory cannot
770
* be allocated, a special #hb_buffer_t object will be returned on which
771
* hb_buffer_allocation_successful() returns `false`.
772
*
773
* Since: 0.9.2
774
**/
775
hb_buffer_t *
776
hb_buffer_create ()
777
{
778
hb_buffer_t *buffer;
779
780
if (!(buffer = hb_object_create<hb_buffer_t> ()))
781
return hb_buffer_get_empty ();
782
783
buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
784
buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
785
786
buffer->reset ();
787
788
return buffer;
789
}
790
791
/**
792
* hb_buffer_create_similar:
793
* @src: An #hb_buffer_t
794
*
795
* Creates a new #hb_buffer_t, similar to hb_buffer_create(). The only
796
* difference is that the buffer is configured similarly to @src.
797
*
798
* Return value: (transfer full):
799
* A newly allocated #hb_buffer_t, similar to hb_buffer_create().
800
*
801
* Since: 3.3.0
802
**/
803
hb_buffer_t *
804
hb_buffer_create_similar (const hb_buffer_t *src)
805
{
806
hb_buffer_t *buffer = hb_buffer_create ();
807
808
buffer->similar (*src);
809
810
return buffer;
811
}
812
813
/**
814
* hb_buffer_reset:
815
* @buffer: An #hb_buffer_t
816
*
817
* Resets the buffer to its initial status, as if it was just newly created
818
* with hb_buffer_create().
819
*
820
* Since: 0.9.2
821
**/
822
void
823
hb_buffer_reset (hb_buffer_t *buffer)
824
{
825
if (unlikely (hb_object_is_immutable (buffer)))
826
return;
827
828
buffer->reset ();
829
}
830
831
/**
832
* hb_buffer_get_empty:
833
*
834
* Fetches an empty #hb_buffer_t.
835
*
836
* Return value: (transfer full): The empty buffer
837
*
838
* Since: 0.9.2
839
**/
840
hb_buffer_t *
841
hb_buffer_get_empty ()
842
{
843
return const_cast<hb_buffer_t *> (&Null (hb_buffer_t));
844
}
845
846
/**
847
* hb_buffer_reference: (skip)
848
* @buffer: An #hb_buffer_t
849
*
850
* Increases the reference count on @buffer by one. This prevents @buffer from
851
* being destroyed until a matching call to hb_buffer_destroy() is made.
852
*
853
* Return value: (transfer full):
854
* The referenced #hb_buffer_t.
855
*
856
* Since: 0.9.2
857
**/
858
hb_buffer_t *
859
hb_buffer_reference (hb_buffer_t *buffer)
860
{
861
return hb_object_reference (buffer);
862
}
863
864
/**
865
* hb_buffer_destroy: (skip)
866
* @buffer: An #hb_buffer_t
867
*
868
* Deallocate the @buffer.
869
* Decreases the reference count on @buffer by one. If the result is zero, then
870
* @buffer and all associated resources are freed. See hb_buffer_reference().
871
*
872
* Since: 0.9.2
873
**/
874
void
875
hb_buffer_destroy (hb_buffer_t *buffer)
876
{
877
if (!hb_object_destroy (buffer)) return;
878
879
hb_unicode_funcs_destroy (buffer->unicode);
880
881
hb_free (buffer->info);
882
hb_free (buffer->pos);
883
#ifndef HB_NO_BUFFER_MESSAGE
884
if (buffer->message_destroy)
885
buffer->message_destroy (buffer->message_data);
886
#endif
887
888
hb_free (buffer);
889
}
890
891
/**
892
* hb_buffer_set_user_data: (skip)
893
* @buffer: An #hb_buffer_t
894
* @key: The user-data key
895
* @data: A pointer to the user data
896
* @destroy: (nullable): A callback to call when @data is not needed anymore
897
* @replace: Whether to replace an existing data with the same key
898
*
899
* Attaches a user-data key/data pair to the specified buffer.
900
*
901
* Return value: `true` if success, `false` otherwise
902
*
903
* Since: 0.9.2
904
**/
905
hb_bool_t
906
hb_buffer_set_user_data (hb_buffer_t *buffer,
907
hb_user_data_key_t *key,
908
void * data,
909
hb_destroy_func_t destroy,
910
hb_bool_t replace)
911
{
912
return hb_object_set_user_data (buffer, key, data, destroy, replace);
913
}
914
915
/**
916
* hb_buffer_get_user_data: (skip)
917
* @buffer: An #hb_buffer_t
918
* @key: The user-data key to query
919
*
920
* Fetches the user data associated with the specified key,
921
* attached to the specified buffer.
922
*
923
* Return value: (transfer none): A pointer to the user data
924
*
925
* Since: 0.9.2
926
**/
927
void *
928
hb_buffer_get_user_data (const hb_buffer_t *buffer,
929
hb_user_data_key_t *key)
930
{
931
return hb_object_get_user_data (buffer, key);
932
}
933
934
935
/**
936
* hb_buffer_set_content_type:
937
* @buffer: An #hb_buffer_t
938
* @content_type: The type of buffer contents to set
939
*
940
* Sets the type of @buffer contents. Buffers are either empty, contain
941
* characters (before shaping), or contain glyphs (the result of shaping).
942
*
943
* You rarely need to call this function, since a number of other
944
* functions transition the content type for you. Namely:
945
*
946
* - A newly created buffer starts with content type
947
* %HB_BUFFER_CONTENT_TYPE_INVALID. Calling hb_buffer_reset(),
948
* hb_buffer_clear_contents(), as well as calling hb_buffer_set_length()
949
* with an argument of zero all set the buffer content type to invalid
950
* as well.
951
*
952
* - Calling hb_buffer_add_utf8(), hb_buffer_add_utf16(),
953
* hb_buffer_add_utf32(), hb_buffer_add_codepoints() and
954
* hb_buffer_add_latin1() expect that buffer is either empty and
955
* have a content type of invalid, or that buffer content type is
956
* %HB_BUFFER_CONTENT_TYPE_UNICODE, and they also set the content
957
* type to Unicode if they added anything to an empty buffer.
958
*
959
* - Finally hb_shape() and hb_shape_full() expect that the buffer
960
* is either empty and have content type of invalid, or that buffer
961
* content type is %HB_BUFFER_CONTENT_TYPE_UNICODE, and upon
962
* success they set the buffer content type to
963
* %HB_BUFFER_CONTENT_TYPE_GLYPHS.
964
*
965
* The above transitions are designed such that one can use a buffer
966
* in a loop of "reset : add-text : shape" without needing to ever
967
* modify the content type manually.
968
*
969
* Since: 0.9.5
970
**/
971
void
972
hb_buffer_set_content_type (hb_buffer_t *buffer,
973
hb_buffer_content_type_t content_type)
974
{
975
buffer->content_type = content_type;
976
}
977
978
/**
979
* hb_buffer_get_content_type:
980
* @buffer: An #hb_buffer_t
981
*
982
* Fetches the type of @buffer contents. Buffers are either empty, contain
983
* characters (before shaping), or contain glyphs (the result of shaping).
984
*
985
* Return value:
986
* The type of @buffer contents
987
*
988
* Since: 0.9.5
989
**/
990
hb_buffer_content_type_t
991
hb_buffer_get_content_type (const hb_buffer_t *buffer)
992
{
993
return buffer->content_type;
994
}
995
996
997
/**
998
* hb_buffer_set_unicode_funcs:
999
* @buffer: An #hb_buffer_t
1000
* @unicode_funcs: The Unicode-functions structure
1001
*
1002
* Sets the Unicode-functions structure of a buffer to
1003
* @unicode_funcs.
1004
*
1005
* Since: 0.9.2
1006
**/
1007
void
1008
hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
1009
hb_unicode_funcs_t *unicode_funcs)
1010
{
1011
if (unlikely (hb_object_is_immutable (buffer)))
1012
return;
1013
1014
if (!unicode_funcs)
1015
unicode_funcs = hb_unicode_funcs_get_default ();
1016
1017
hb_unicode_funcs_reference (unicode_funcs);
1018
hb_unicode_funcs_destroy (buffer->unicode);
1019
buffer->unicode = unicode_funcs;
1020
}
1021
1022
/**
1023
* hb_buffer_get_unicode_funcs:
1024
* @buffer: An #hb_buffer_t
1025
*
1026
* Fetches the Unicode-functions structure of a buffer.
1027
*
1028
* Return value: The Unicode-functions structure
1029
*
1030
* Since: 0.9.2
1031
**/
1032
hb_unicode_funcs_t *
1033
hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer)
1034
{
1035
return buffer->unicode;
1036
}
1037
1038
/**
1039
* hb_buffer_set_direction:
1040
* @buffer: An #hb_buffer_t
1041
* @direction: the #hb_direction_t of the @buffer
1042
*
1043
* Set the text flow direction of the buffer. No shaping can happen without
1044
* setting @buffer direction, and it controls the visual direction for the
1045
* output glyphs; for RTL direction the glyphs will be reversed. Many layout
1046
* features depend on the proper setting of the direction, for example,
1047
* reversing RTL text before shaping, then shaping with LTR direction is not
1048
* the same as keeping the text in logical order and shaping with RTL
1049
* direction.
1050
*
1051
* Since: 0.9.2
1052
**/
1053
void
1054
hb_buffer_set_direction (hb_buffer_t *buffer,
1055
hb_direction_t direction)
1056
{
1057
if (unlikely (hb_object_is_immutable (buffer)))
1058
return;
1059
1060
buffer->props.direction = direction;
1061
}
1062
1063
/**
1064
* hb_buffer_get_direction:
1065
* @buffer: An #hb_buffer_t
1066
*
1067
* See hb_buffer_set_direction()
1068
*
1069
* Return value:
1070
* The direction of the @buffer.
1071
*
1072
* Since: 0.9.2
1073
**/
1074
hb_direction_t
1075
hb_buffer_get_direction (const hb_buffer_t *buffer)
1076
{
1077
return buffer->props.direction;
1078
}
1079
1080
/**
1081
* hb_buffer_set_script:
1082
* @buffer: An #hb_buffer_t
1083
* @script: An #hb_script_t to set.
1084
*
1085
* Sets the script of @buffer to @script.
1086
*
1087
* Script is crucial for choosing the proper shaping behaviour for scripts that
1088
* require it (e.g. Arabic) and the which OpenType features defined in the font
1089
* to be applied.
1090
*
1091
* You can pass one of the predefined #hb_script_t values, or use
1092
* hb_script_from_string() or hb_script_from_iso15924_tag() to get the
1093
* corresponding script from an ISO 15924 script tag.
1094
*
1095
* Since: 0.9.2
1096
**/
1097
void
1098
hb_buffer_set_script (hb_buffer_t *buffer,
1099
hb_script_t script)
1100
{
1101
if (unlikely (hb_object_is_immutable (buffer)))
1102
return;
1103
1104
buffer->props.script = script;
1105
}
1106
1107
/**
1108
* hb_buffer_get_script:
1109
* @buffer: An #hb_buffer_t
1110
*
1111
* Fetches the script of @buffer.
1112
*
1113
* Return value:
1114
* The #hb_script_t of the @buffer
1115
*
1116
* Since: 0.9.2
1117
**/
1118
hb_script_t
1119
hb_buffer_get_script (const hb_buffer_t *buffer)
1120
{
1121
return buffer->props.script;
1122
}
1123
1124
/**
1125
* hb_buffer_set_language:
1126
* @buffer: An #hb_buffer_t
1127
* @language: An hb_language_t to set
1128
*
1129
* Sets the language of @buffer to @language.
1130
*
1131
* Languages are crucial for selecting which OpenType feature to apply to the
1132
* buffer which can result in applying language-specific behaviour. Languages
1133
* are orthogonal to the scripts, and though they are related, they are
1134
* different concepts and should not be confused with each other.
1135
*
1136
* Use hb_language_from_string() to convert from BCP 47 language tags to
1137
* #hb_language_t.
1138
*
1139
* Since: 0.9.2
1140
**/
1141
void
1142
hb_buffer_set_language (hb_buffer_t *buffer,
1143
hb_language_t language)
1144
{
1145
if (unlikely (hb_object_is_immutable (buffer)))
1146
return;
1147
1148
buffer->props.language = language;
1149
}
1150
1151
/**
1152
* hb_buffer_get_language:
1153
* @buffer: An #hb_buffer_t
1154
*
1155
* See hb_buffer_set_language().
1156
*
1157
* Return value: (transfer none):
1158
* The #hb_language_t of the buffer. Must not be freed by the caller.
1159
*
1160
* Since: 0.9.2
1161
**/
1162
hb_language_t
1163
hb_buffer_get_language (const hb_buffer_t *buffer)
1164
{
1165
return buffer->props.language;
1166
}
1167
1168
/**
1169
* hb_buffer_set_segment_properties:
1170
* @buffer: An #hb_buffer_t
1171
* @props: An #hb_segment_properties_t to use
1172
*
1173
* Sets the segment properties of the buffer, a shortcut for calling
1174
* hb_buffer_set_direction(), hb_buffer_set_script() and
1175
* hb_buffer_set_language() individually.
1176
*
1177
* Since: 0.9.7
1178
**/
1179
void
1180
hb_buffer_set_segment_properties (hb_buffer_t *buffer,
1181
const hb_segment_properties_t *props)
1182
{
1183
if (unlikely (hb_object_is_immutable (buffer)))
1184
return;
1185
1186
buffer->props = *props;
1187
}
1188
1189
/**
1190
* hb_buffer_get_segment_properties:
1191
* @buffer: An #hb_buffer_t
1192
* @props: (out): The output #hb_segment_properties_t
1193
*
1194
* Sets @props to the #hb_segment_properties_t of @buffer.
1195
*
1196
* Since: 0.9.7
1197
**/
1198
void
1199
hb_buffer_get_segment_properties (const hb_buffer_t *buffer,
1200
hb_segment_properties_t *props)
1201
{
1202
*props = buffer->props;
1203
}
1204
1205
1206
/**
1207
* hb_buffer_set_flags:
1208
* @buffer: An #hb_buffer_t
1209
* @flags: The buffer flags to set
1210
*
1211
* Sets @buffer flags to @flags. See #hb_buffer_flags_t.
1212
*
1213
* Since: 0.9.7
1214
**/
1215
void
1216
hb_buffer_set_flags (hb_buffer_t *buffer,
1217
hb_buffer_flags_t flags)
1218
{
1219
if (unlikely (hb_object_is_immutable (buffer)))
1220
return;
1221
1222
buffer->flags = flags;
1223
}
1224
1225
/**
1226
* hb_buffer_get_flags:
1227
* @buffer: An #hb_buffer_t
1228
*
1229
* Fetches the #hb_buffer_flags_t of @buffer.
1230
*
1231
* Return value:
1232
* The @buffer flags
1233
*
1234
* Since: 0.9.7
1235
**/
1236
hb_buffer_flags_t
1237
hb_buffer_get_flags (const hb_buffer_t *buffer)
1238
{
1239
return buffer->flags;
1240
}
1241
1242
/**
1243
* hb_buffer_set_cluster_level:
1244
* @buffer: An #hb_buffer_t
1245
* @cluster_level: The cluster level to set on the buffer
1246
*
1247
* Sets the cluster level of a buffer. The #hb_buffer_cluster_level_t
1248
* dictates one aspect of how HarfBuzz will treat non-base characters
1249
* during shaping.
1250
*
1251
* Since: 0.9.42
1252
**/
1253
void
1254
hb_buffer_set_cluster_level (hb_buffer_t *buffer,
1255
hb_buffer_cluster_level_t cluster_level)
1256
{
1257
if (unlikely (hb_object_is_immutable (buffer)))
1258
return;
1259
1260
buffer->cluster_level = cluster_level;
1261
}
1262
1263
/**
1264
* hb_buffer_get_cluster_level:
1265
* @buffer: An #hb_buffer_t
1266
*
1267
* Fetches the cluster level of a buffer. The #hb_buffer_cluster_level_t
1268
* dictates one aspect of how HarfBuzz will treat non-base characters
1269
* during shaping.
1270
*
1271
* Return value: The cluster level of @buffer
1272
*
1273
* Since: 0.9.42
1274
**/
1275
hb_buffer_cluster_level_t
1276
hb_buffer_get_cluster_level (const hb_buffer_t *buffer)
1277
{
1278
return buffer->cluster_level;
1279
}
1280
1281
1282
/**
1283
* hb_buffer_set_replacement_codepoint:
1284
* @buffer: An #hb_buffer_t
1285
* @replacement: the replacement #hb_codepoint_t
1286
*
1287
* Sets the #hb_codepoint_t that replaces invalid entries for a given encoding
1288
* when adding text to @buffer.
1289
*
1290
* Default is #HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
1291
*
1292
* Since: 0.9.31
1293
**/
1294
void
1295
hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
1296
hb_codepoint_t replacement)
1297
{
1298
if (unlikely (hb_object_is_immutable (buffer)))
1299
return;
1300
1301
buffer->replacement = replacement;
1302
}
1303
1304
/**
1305
* hb_buffer_get_replacement_codepoint:
1306
* @buffer: An #hb_buffer_t
1307
*
1308
* Fetches the #hb_codepoint_t that replaces invalid entries for a given encoding
1309
* when adding text to @buffer.
1310
*
1311
* Return value:
1312
* The @buffer replacement #hb_codepoint_t
1313
*
1314
* Since: 0.9.31
1315
**/
1316
hb_codepoint_t
1317
hb_buffer_get_replacement_codepoint (const hb_buffer_t *buffer)
1318
{
1319
return buffer->replacement;
1320
}
1321
1322
1323
/**
1324
* hb_buffer_set_invisible_glyph:
1325
* @buffer: An #hb_buffer_t
1326
* @invisible: the invisible #hb_codepoint_t
1327
*
1328
* Sets the #hb_codepoint_t that replaces invisible characters in
1329
* the shaping result. If set to zero (default), the glyph for the
1330
* U+0020 SPACE character is used. Otherwise, this value is used
1331
* verbatim.
1332
*
1333
* Since: 2.0.0
1334
**/
1335
void
1336
hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,
1337
hb_codepoint_t invisible)
1338
{
1339
if (unlikely (hb_object_is_immutable (buffer)))
1340
return;
1341
1342
buffer->invisible = invisible;
1343
}
1344
1345
/**
1346
* hb_buffer_get_invisible_glyph:
1347
* @buffer: An #hb_buffer_t
1348
*
1349
* See hb_buffer_set_invisible_glyph().
1350
*
1351
* Return value:
1352
* The @buffer invisible #hb_codepoint_t
1353
*
1354
* Since: 2.0.0
1355
**/
1356
hb_codepoint_t
1357
hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer)
1358
{
1359
return buffer->invisible;
1360
}
1361
1362
/**
1363
* hb_buffer_set_not_found_glyph:
1364
* @buffer: An #hb_buffer_t
1365
* @not_found: the not-found #hb_codepoint_t
1366
*
1367
* Sets the #hb_codepoint_t that replaces characters not found in
1368
* the font during shaping.
1369
*
1370
* The not-found glyph defaults to zero, sometimes known as the
1371
* ".notdef" glyph. This API allows for differentiating the two.
1372
*
1373
* Since: 3.1.0
1374
**/
1375
void
1376
hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
1377
hb_codepoint_t not_found)
1378
{
1379
if (unlikely (hb_object_is_immutable (buffer)))
1380
return;
1381
1382
buffer->not_found = not_found;
1383
}
1384
1385
/**
1386
* hb_buffer_get_not_found_glyph:
1387
* @buffer: An #hb_buffer_t
1388
*
1389
* See hb_buffer_set_not_found_glyph().
1390
*
1391
* Return value:
1392
* The @buffer not-found #hb_codepoint_t
1393
*
1394
* Since: 3.1.0
1395
**/
1396
hb_codepoint_t
1397
hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)
1398
{
1399
return buffer->not_found;
1400
}
1401
1402
/**
1403
* hb_buffer_set_not_found_variation_selector_glyph:
1404
* @buffer: An #hb_buffer_t
1405
* @not_found_variation_selector: the not-found-variation-selector #hb_codepoint_t
1406
*
1407
* Sets the #hb_codepoint_t that replaces variation-selector characters not resolved
1408
* in the font during shaping.
1409
*
1410
* The not-found-variation-selector glyph defaults to #HB_CODEPOINT_INVALID,
1411
* in which case an unresolved variation-selector will be removed from the glyph
1412
* string during shaping. This API allows for changing that and retaining a glyph,
1413
* such that the situation can be detected by the client and handled accordingly
1414
* (e.g. by using a different font).
1415
*
1416
* Since: 10.0.0
1417
**/
1418
void
1419
hb_buffer_set_not_found_variation_selector_glyph (hb_buffer_t *buffer,
1420
hb_codepoint_t not_found_variation_selector)
1421
{
1422
buffer->not_found_variation_selector = not_found_variation_selector;
1423
}
1424
1425
/**
1426
* hb_buffer_get_not_found_variation_selector_glyph:
1427
* @buffer: An #hb_buffer_t
1428
*
1429
* See hb_buffer_set_not_found_variation_selector_glyph().
1430
*
1431
* Return value:
1432
* The @buffer not-found-variation-selector #hb_codepoint_t
1433
*
1434
* Since: 10.0.0
1435
**/
1436
hb_codepoint_t
1437
hb_buffer_get_not_found_variation_selector_glyph (const hb_buffer_t *buffer)
1438
{
1439
return buffer->not_found_variation_selector;
1440
}
1441
1442
/**
1443
* hb_buffer_set_random_state:
1444
* @buffer: An #hb_buffer_t
1445
* @state: the new random state
1446
*
1447
* Sets the random state of the buffer. The state changes
1448
* every time a glyph uses randomness (eg. the `rand`
1449
* OpenType feature). This function together with
1450
* hb_buffer_get_random_state() allow for transferring
1451
* the current random state to a subsequent buffer, to
1452
* get better randomness distribution.
1453
*
1454
* Defaults to 1 and when buffer contents are cleared.
1455
* A value of 0 disables randomness during shaping.
1456
*
1457
* Since: 8.4.0
1458
**/
1459
void
1460
hb_buffer_set_random_state (hb_buffer_t *buffer,
1461
unsigned state)
1462
{
1463
if (unlikely (hb_object_is_immutable (buffer)))
1464
return;
1465
1466
buffer->random_state = state;
1467
}
1468
1469
/**
1470
* hb_buffer_get_random_state:
1471
* @buffer: An #hb_buffer_t
1472
*
1473
* See hb_buffer_set_random_state().
1474
*
1475
* Return value:
1476
* The @buffer random state
1477
*
1478
* Since: 8.4.0
1479
**/
1480
unsigned
1481
hb_buffer_get_random_state (const hb_buffer_t *buffer)
1482
{
1483
return buffer->random_state;
1484
}
1485
1486
/**
1487
* hb_buffer_clear_contents:
1488
* @buffer: An #hb_buffer_t
1489
*
1490
* Similar to hb_buffer_reset(), but does not clear the Unicode functions and
1491
* the replacement code point.
1492
*
1493
* Since: 0.9.11
1494
**/
1495
void
1496
hb_buffer_clear_contents (hb_buffer_t *buffer)
1497
{
1498
if (unlikely (hb_object_is_immutable (buffer)))
1499
return;
1500
1501
buffer->clear ();
1502
}
1503
1504
/**
1505
* hb_buffer_pre_allocate:
1506
* @buffer: An #hb_buffer_t
1507
* @size: Number of items to pre allocate.
1508
*
1509
* Pre allocates memory for @buffer to fit at least @size number of items.
1510
*
1511
* Return value:
1512
* `true` if @buffer memory allocation succeeded, `false` otherwise
1513
*
1514
* Since: 0.9.2
1515
**/
1516
hb_bool_t
1517
hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
1518
{
1519
return buffer->ensure (size);
1520
}
1521
1522
/**
1523
* hb_buffer_allocation_successful:
1524
* @buffer: An #hb_buffer_t
1525
*
1526
* Check if allocating memory for the buffer succeeded.
1527
*
1528
* Return value:
1529
* `true` if @buffer memory allocation succeeded, `false` otherwise.
1530
*
1531
* Since: 0.9.2
1532
**/
1533
hb_bool_t
1534
hb_buffer_allocation_successful (hb_buffer_t *buffer)
1535
{
1536
return buffer->successful;
1537
}
1538
1539
/**
1540
* hb_buffer_add:
1541
* @buffer: An #hb_buffer_t
1542
* @codepoint: A Unicode code point.
1543
* @cluster: The cluster value of @codepoint.
1544
*
1545
* Appends a character with the Unicode value of @codepoint to @buffer, and
1546
* gives it the initial cluster value of @cluster. Clusters can be any thing
1547
* the client wants, they are usually used to refer to the index of the
1548
* character in the input text stream and are output in
1549
* #hb_glyph_info_t.cluster field.
1550
*
1551
* This function does not check the validity of @codepoint, it is up to the
1552
* caller to ensure it is a valid Unicode code point.
1553
*
1554
* Since: 0.9.7
1555
**/
1556
void
1557
hb_buffer_add (hb_buffer_t *buffer,
1558
hb_codepoint_t codepoint,
1559
unsigned int cluster)
1560
{
1561
buffer->add (codepoint, cluster);
1562
buffer->clear_context (1);
1563
}
1564
1565
/**
1566
* hb_buffer_set_length:
1567
* @buffer: An #hb_buffer_t
1568
* @length: The new length of @buffer
1569
*
1570
* Similar to hb_buffer_pre_allocate(), but clears any new items added at the
1571
* end.
1572
*
1573
* Return value:
1574
* `true` if @buffer memory allocation succeeded, `false` otherwise.
1575
*
1576
* Since: 0.9.2
1577
**/
1578
hb_bool_t
1579
hb_buffer_set_length (hb_buffer_t *buffer,
1580
unsigned int length)
1581
{
1582
if (unlikely (hb_object_is_immutable (buffer)))
1583
return length == 0;
1584
1585
if (unlikely (!buffer->ensure (length)))
1586
return false;
1587
1588
/* Wipe the new space */
1589
if (length > buffer->len) {
1590
hb_memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
1591
if (buffer->have_positions)
1592
hb_memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
1593
}
1594
1595
buffer->len = length;
1596
1597
if (!length)
1598
{
1599
buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
1600
buffer->clear_context (0);
1601
}
1602
buffer->clear_context (1);
1603
1604
return true;
1605
}
1606
1607
/**
1608
* hb_buffer_get_length:
1609
* @buffer: An #hb_buffer_t
1610
*
1611
* Returns the number of items in the buffer.
1612
*
1613
* Return value:
1614
* The @buffer length.
1615
* The value valid as long as buffer has not been modified.
1616
*
1617
* Since: 0.9.2
1618
**/
1619
unsigned int
1620
hb_buffer_get_length (const hb_buffer_t *buffer)
1621
{
1622
return buffer->len;
1623
}
1624
1625
/**
1626
* hb_buffer_get_glyph_infos:
1627
* @buffer: An #hb_buffer_t
1628
* @length: (out): The output-array length.
1629
*
1630
* Returns @buffer glyph information array. Returned pointer
1631
* is valid as long as @buffer contents are not modified.
1632
*
1633
* Return value: (transfer none) (array length=length):
1634
* The @buffer glyph information array.
1635
* The value valid as long as buffer has not been modified.
1636
*
1637
* Since: 0.9.2
1638
**/
1639
hb_glyph_info_t *
1640
hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
1641
unsigned int *length)
1642
{
1643
if (length)
1644
*length = buffer->len;
1645
1646
return (hb_glyph_info_t *) buffer->info;
1647
}
1648
1649
/**
1650
* hb_buffer_get_glyph_positions:
1651
* @buffer: An #hb_buffer_t
1652
* @length: (out): The output length
1653
*
1654
* Returns @buffer glyph position array. Returned pointer
1655
* is valid as long as @buffer contents are not modified.
1656
*
1657
* If buffer did not have positions before, the positions will be
1658
* initialized to zeros, unless this function is called from
1659
* within a buffer message callback (see hb_buffer_set_message_func()),
1660
* in which case `NULL` is returned.
1661
*
1662
* Return value: (transfer none) (array length=length):
1663
* The @buffer glyph position array.
1664
* The value valid as long as buffer has not been modified.
1665
*
1666
* Since: 0.9.2
1667
**/
1668
hb_glyph_position_t *
1669
hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
1670
unsigned int *length)
1671
{
1672
if (length)
1673
*length = buffer->len;
1674
1675
if (!buffer->have_positions)
1676
{
1677
if (unlikely (buffer->message_depth))
1678
return nullptr;
1679
1680
buffer->clear_positions ();
1681
}
1682
1683
return (hb_glyph_position_t *) buffer->pos;
1684
}
1685
1686
/**
1687
* hb_buffer_has_positions:
1688
* @buffer: an #hb_buffer_t.
1689
*
1690
* Returns whether @buffer has glyph position data.
1691
* A buffer gains position data when hb_buffer_get_glyph_positions() is called on it,
1692
* and cleared of position data when hb_buffer_clear_contents() is called.
1693
*
1694
* Return value:
1695
* `true` if the @buffer has position array, `false` otherwise.
1696
*
1697
* Since: 2.7.3
1698
**/
1699
HB_EXTERN hb_bool_t
1700
hb_buffer_has_positions (hb_buffer_t *buffer)
1701
{
1702
return buffer->have_positions;
1703
}
1704
1705
/**
1706
* hb_glyph_info_get_glyph_flags:
1707
* @info: a #hb_glyph_info_t
1708
*
1709
* Returns glyph flags encoded within a #hb_glyph_info_t.
1710
*
1711
* Return value:
1712
* The #hb_glyph_flags_t encoded within @info
1713
*
1714
* Since: 1.5.0
1715
**/
1716
hb_glyph_flags_t
1717
(hb_glyph_info_get_glyph_flags) (const hb_glyph_info_t *info)
1718
{
1719
return hb_glyph_info_get_glyph_flags (info);
1720
}
1721
1722
/**
1723
* hb_buffer_reverse:
1724
* @buffer: An #hb_buffer_t
1725
*
1726
* Reverses buffer contents.
1727
*
1728
* Since: 0.9.2
1729
**/
1730
void
1731
hb_buffer_reverse (hb_buffer_t *buffer)
1732
{
1733
buffer->reverse ();
1734
}
1735
1736
/**
1737
* hb_buffer_reverse_range:
1738
* @buffer: An #hb_buffer_t
1739
* @start: start index
1740
* @end: end index
1741
*
1742
* Reverses buffer contents between @start and @end.
1743
*
1744
* Since: 0.9.41
1745
**/
1746
void
1747
hb_buffer_reverse_range (hb_buffer_t *buffer,
1748
unsigned int start, unsigned int end)
1749
{
1750
buffer->reverse_range (start, end);
1751
}
1752
1753
/**
1754
* hb_buffer_reverse_clusters:
1755
* @buffer: An #hb_buffer_t
1756
*
1757
* Reverses buffer clusters. That is, the buffer contents are
1758
* reversed, then each cluster (consecutive items having the
1759
* same cluster number) are reversed again.
1760
*
1761
* Since: 0.9.2
1762
**/
1763
void
1764
hb_buffer_reverse_clusters (hb_buffer_t *buffer)
1765
{
1766
buffer->reverse_clusters ();
1767
}
1768
1769
/**
1770
* hb_buffer_guess_segment_properties:
1771
* @buffer: An #hb_buffer_t
1772
*
1773
* Sets unset buffer segment properties based on buffer Unicode
1774
* contents. If buffer is not empty, it must have content type
1775
* #HB_BUFFER_CONTENT_TYPE_UNICODE.
1776
*
1777
* If buffer script is not set (ie. is #HB_SCRIPT_INVALID), it
1778
* will be set to the Unicode script of the first character in
1779
* the buffer that has a script other than #HB_SCRIPT_COMMON,
1780
* #HB_SCRIPT_INHERITED, and #HB_SCRIPT_UNKNOWN.
1781
*
1782
* Next, if buffer direction is not set (ie. is #HB_DIRECTION_INVALID),
1783
* it will be set to the natural horizontal direction of the
1784
* buffer script as returned by hb_script_get_horizontal_direction().
1785
* If hb_script_get_horizontal_direction() returns #HB_DIRECTION_INVALID,
1786
* then #HB_DIRECTION_LTR is used.
1787
*
1788
* Finally, if buffer language is not set (ie. is #HB_LANGUAGE_INVALID),
1789
* it will be set to the process's default language as returned by
1790
* hb_language_get_default(). This may change in the future by
1791
* taking buffer script into consideration when choosing a language.
1792
* Note that hb_language_get_default() is NOT threadsafe the first time
1793
* it is called. See documentation for that function for details.
1794
*
1795
* Since: 0.9.7
1796
**/
1797
void
1798
hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
1799
{
1800
buffer->guess_segment_properties ();
1801
}
1802
1803
template <typename utf_t>
1804
static inline void
1805
hb_buffer_add_utf (hb_buffer_t *buffer,
1806
const typename utf_t::codepoint_t *text,
1807
int text_length,
1808
unsigned int item_offset,
1809
int item_length)
1810
{
1811
typedef typename utf_t::codepoint_t T;
1812
const hb_codepoint_t replacement = buffer->replacement;
1813
1814
buffer->assert_unicode ();
1815
1816
if (unlikely (hb_object_is_immutable (buffer)))
1817
return;
1818
1819
if (text_length == -1)
1820
text_length = utf_t::strlen (text);
1821
1822
if (item_length == -1)
1823
item_length = text_length - item_offset;
1824
1825
if (unlikely (item_length < 0 ||
1826
item_length > INT_MAX / 8 ||
1827
!buffer->ensure (buffer->len + item_length * sizeof (T) / 4)))
1828
return;
1829
1830
/* If buffer is empty and pre-context provided, install it.
1831
* This check is written this way, to make sure people can
1832
* provide pre-context in one add_utf() call, then provide
1833
* text in a follow-up call. See:
1834
*
1835
* https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
1836
*/
1837
if (!buffer->len && item_offset > 0)
1838
{
1839
/* Add pre-context */
1840
buffer->clear_context (0);
1841
const T *prev = text + item_offset;
1842
const T *start = text;
1843
while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
1844
{
1845
hb_codepoint_t u;
1846
prev = utf_t::prev (prev, start, &u, replacement);
1847
buffer->context[0][buffer->context_len[0]++] = u;
1848
}
1849
}
1850
1851
const T *next = text + item_offset;
1852
const T *end = next + item_length;
1853
while (next < end)
1854
{
1855
hb_codepoint_t u;
1856
const T *old_next = next;
1857
next = utf_t::next (next, end, &u, replacement);
1858
buffer->add (u, old_next - (const T *) text);
1859
}
1860
1861
/* Add post-context */
1862
buffer->clear_context (1);
1863
end = text + text_length;
1864
while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
1865
{
1866
hb_codepoint_t u;
1867
next = utf_t::next (next, end, &u, replacement);
1868
buffer->context[1][buffer->context_len[1]++] = u;
1869
}
1870
1871
buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
1872
}
1873
1874
/**
1875
* hb_buffer_add_utf8:
1876
* @buffer: An #hb_buffer_t
1877
* @text: (array length=text_length) (element-type uint8_t): An array of UTF-8
1878
* characters to append.
1879
* @text_length: The length of the @text, or -1 if it is `NULL` terminated.
1880
* @item_offset: The offset of the first character to add to the @buffer.
1881
* @item_length: The number of characters to add to the @buffer, or -1 for the
1882
* end of @text (assuming it is `NULL` terminated).
1883
*
1884
* See hb_buffer_add_codepoints().
1885
*
1886
* Replaces invalid UTF-8 characters with the @buffer replacement code point,
1887
* see hb_buffer_set_replacement_codepoint().
1888
*
1889
* Since: 0.9.2
1890
**/
1891
void
1892
hb_buffer_add_utf8 (hb_buffer_t *buffer,
1893
const char *text,
1894
int text_length,
1895
unsigned int item_offset,
1896
int item_length)
1897
{
1898
hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
1899
}
1900
1901
/**
1902
* hb_buffer_add_utf16:
1903
* @buffer: An #hb_buffer_t
1904
* @text: (array length=text_length): An array of UTF-16 characters to append
1905
* @text_length: The length of the @text, or -1 if it is `NULL` terminated
1906
* @item_offset: The offset of the first character to add to the @buffer
1907
* @item_length: The number of characters to add to the @buffer, or -1 for the
1908
* end of @text (assuming it is `NULL` terminated)
1909
*
1910
* See hb_buffer_add_codepoints().
1911
*
1912
* Replaces invalid UTF-16 characters with the @buffer replacement code point,
1913
* see hb_buffer_set_replacement_codepoint().
1914
*
1915
* Since: 0.9.2
1916
**/
1917
void
1918
hb_buffer_add_utf16 (hb_buffer_t *buffer,
1919
const uint16_t *text,
1920
int text_length,
1921
unsigned int item_offset,
1922
int item_length)
1923
{
1924
hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length);
1925
}
1926
1927
/**
1928
* hb_buffer_add_utf32:
1929
* @buffer: An #hb_buffer_t
1930
* @text: (array length=text_length): An array of UTF-32 characters to append
1931
* @text_length: The length of the @text, or -1 if it is `NULL` terminated
1932
* @item_offset: The offset of the first character to add to the @buffer
1933
* @item_length: The number of characters to add to the @buffer, or -1 for the
1934
* end of @text (assuming it is `NULL` terminated)
1935
*
1936
* See hb_buffer_add_codepoints().
1937
*
1938
* Replaces invalid UTF-32 characters with the @buffer replacement code point,
1939
* see hb_buffer_set_replacement_codepoint().
1940
*
1941
* Since: 0.9.2
1942
**/
1943
void
1944
hb_buffer_add_utf32 (hb_buffer_t *buffer,
1945
const uint32_t *text,
1946
int text_length,
1947
unsigned int item_offset,
1948
int item_length)
1949
{
1950
hb_buffer_add_utf<hb_utf32_t> (buffer, text, text_length, item_offset, item_length);
1951
}
1952
1953
/**
1954
* hb_buffer_add_latin1:
1955
* @buffer: An #hb_buffer_t
1956
* @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
1957
* characters to append
1958
* @text_length: the length of the @text, or -1 if it is `NULL` terminated
1959
* @item_offset: the offset of the first character to add to the @buffer
1960
* @item_length: the number of characters to add to the @buffer, or -1 for the
1961
* end of @text (assuming it is `NULL` terminated)
1962
*
1963
* Similar to hb_buffer_add_codepoints(), but allows only access to first 256
1964
* Unicode code points that can fit in 8-bit strings.
1965
*
1966
* <note>Has nothing to do with non-Unicode Latin-1 encoding.</note>
1967
*
1968
* Since: 0.9.39
1969
**/
1970
void
1971
hb_buffer_add_latin1 (hb_buffer_t *buffer,
1972
const uint8_t *text,
1973
int text_length,
1974
unsigned int item_offset,
1975
int item_length)
1976
{
1977
hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length);
1978
}
1979
1980
/**
1981
* hb_buffer_add_codepoints:
1982
* @buffer: a #hb_buffer_t to append characters to.
1983
* @text: (array length=text_length): an array of Unicode code points to append.
1984
* @text_length: the length of the @text, or -1 if it is `NULL` terminated.
1985
* @item_offset: the offset of the first code point to add to the @buffer.
1986
* @item_length: the number of code points to add to the @buffer, or -1 for the
1987
* end of @text (assuming it is `NULL` terminated).
1988
*
1989
* Appends characters from @text array to @buffer. The @item_offset is the
1990
* position of the first character from @text that will be appended, and
1991
* @item_length is the number of character. When shaping part of a larger text
1992
* (e.g. a run of text from a paragraph), instead of passing just the substring
1993
* corresponding to the run, it is preferable to pass the whole
1994
* paragraph and specify the run start and length as @item_offset and
1995
* @item_length, respectively, to give HarfBuzz the full context to be able,
1996
* for example, to do cross-run Arabic shaping or properly handle combining
1997
* marks at stat of run.
1998
*
1999
* This function does not check the validity of @text, it is up to the caller
2000
* to ensure it contains a valid Unicode scalar values. In contrast,
2001
* hb_buffer_add_utf32() can be used that takes similar input but performs
2002
* sanity-check on the input.
2003
*
2004
* Since: 0.9.31
2005
**/
2006
void
2007
hb_buffer_add_codepoints (hb_buffer_t *buffer,
2008
const hb_codepoint_t *text,
2009
int text_length,
2010
unsigned int item_offset,
2011
int item_length)
2012
{
2013
hb_buffer_add_utf<hb_utf32_novalidate_t> (buffer, text, text_length, item_offset, item_length);
2014
}
2015
2016
2017
/**
2018
* hb_buffer_append:
2019
* @buffer: An #hb_buffer_t
2020
* @source: source #hb_buffer_t
2021
* @start: start index into source buffer to copy. Use 0 to copy from start of buffer.
2022
* @end: end index into source buffer to copy. Use @UINT_MAX (or ((unsigned int) -1)) to copy to end of buffer.
2023
*
2024
* Append (part of) contents of another buffer to this buffer.
2025
*
2026
* Since: 1.5.0
2027
**/
2028
HB_EXTERN void
2029
hb_buffer_append (hb_buffer_t *buffer,
2030
const hb_buffer_t *source,
2031
unsigned int start,
2032
unsigned int end)
2033
{
2034
assert (!buffer->have_output && !source->have_output);
2035
assert (buffer->have_positions == source->have_positions ||
2036
!buffer->len || !source->len);
2037
assert (buffer->content_type == source->content_type ||
2038
!buffer->len || !source->len);
2039
2040
if (end > source->len)
2041
end = source->len;
2042
if (start > end)
2043
start = end;
2044
if (start == end)
2045
return;
2046
2047
if (buffer->len + (end - start) < buffer->len) /* Overflows. */
2048
{
2049
buffer->successful = false;
2050
return;
2051
}
2052
2053
unsigned int orig_len = buffer->len;
2054
hb_buffer_set_length (buffer, buffer->len + (end - start));
2055
if (unlikely (!buffer->successful))
2056
return;
2057
2058
if (!orig_len)
2059
buffer->content_type = source->content_type;
2060
if (!buffer->have_positions && source->have_positions)
2061
buffer->clear_positions ();
2062
2063
hb_segment_properties_overlay (&buffer->props, &source->props);
2064
2065
hb_memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
2066
if (buffer->have_positions)
2067
hb_memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
2068
2069
if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
2070
{
2071
/* See similar logic in add_utf. */
2072
2073
/* pre-context */
2074
if (!orig_len && start + source->context_len[0] > 0)
2075
{
2076
buffer->clear_context (0);
2077
while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
2078
buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint;
2079
for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++)
2080
buffer->context[0][buffer->context_len[0]++] = source->context[0][i];
2081
}
2082
2083
/* post-context */
2084
buffer->clear_context (1);
2085
while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
2086
buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint;
2087
for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++)
2088
buffer->context[1][buffer->context_len[1]++] = source->context[1][i];
2089
}
2090
}
2091
2092
2093
static int
2094
compare_info_codepoint (const hb_glyph_info_t *pa,
2095
const hb_glyph_info_t *pb)
2096
{
2097
return (int) pb->codepoint - (int) pa->codepoint;
2098
}
2099
2100
static inline void
2101
normalize_glyphs_cluster (hb_buffer_t *buffer,
2102
unsigned int start,
2103
unsigned int end,
2104
bool backward)
2105
{
2106
hb_glyph_position_t *pos = buffer->pos;
2107
2108
/* Total cluster advance */
2109
hb_position_t total_x_advance = 0, total_y_advance = 0;
2110
for (unsigned int i = start; i < end; i++)
2111
{
2112
total_x_advance += pos[i].x_advance;
2113
total_y_advance += pos[i].y_advance;
2114
}
2115
2116
hb_position_t x_advance = 0, y_advance = 0;
2117
for (unsigned int i = start; i < end; i++)
2118
{
2119
pos[i].x_offset += x_advance;
2120
pos[i].y_offset += y_advance;
2121
2122
x_advance += pos[i].x_advance;
2123
y_advance += pos[i].y_advance;
2124
2125
pos[i].x_advance = 0;
2126
pos[i].y_advance = 0;
2127
}
2128
2129
if (backward)
2130
{
2131
/* Transfer all cluster advance to the last glyph. */
2132
pos[end - 1].x_advance = total_x_advance;
2133
pos[end - 1].y_advance = total_y_advance;
2134
2135
hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
2136
} else {
2137
/* Transfer all cluster advance to the first glyph. */
2138
pos[start].x_advance += total_x_advance;
2139
pos[start].y_advance += total_y_advance;
2140
for (unsigned int i = start + 1; i < end; i++) {
2141
pos[i].x_offset -= total_x_advance;
2142
pos[i].y_offset -= total_y_advance;
2143
}
2144
hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
2145
}
2146
}
2147
2148
/**
2149
* hb_buffer_normalize_glyphs:
2150
* @buffer: An #hb_buffer_t
2151
*
2152
* Reorders a glyph buffer to have canonical in-cluster glyph order / position.
2153
* The resulting clusters should behave identical to pre-reordering clusters.
2154
*
2155
* <note>This has nothing to do with Unicode normalization.</note>
2156
*
2157
* Since: 0.9.2
2158
**/
2159
void
2160
hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
2161
{
2162
assert (buffer->have_positions);
2163
2164
buffer->assert_glyphs ();
2165
2166
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
2167
2168
foreach_cluster (buffer, start, end)
2169
normalize_glyphs_cluster (buffer, start, end, backward);
2170
}
2171
2172
void
2173
hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *))
2174
{
2175
assert (!have_positions);
2176
for (unsigned int i = start + 1; i < end; i++)
2177
{
2178
unsigned int j = i;
2179
while (j > start && compar (&info[j - 1], &info[i]) > 0)
2180
j--;
2181
if (i == j)
2182
continue;
2183
/* Move item i to occupy place for item j, shift what's in between. */
2184
merge_clusters (j, i + 1);
2185
{
2186
hb_glyph_info_t t = info[i];
2187
memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t));
2188
info[j] = t;
2189
}
2190
}
2191
}
2192
2193
2194
/*
2195
* Comparing buffers.
2196
*/
2197
2198
/**
2199
* hb_buffer_diff:
2200
* @buffer: a buffer.
2201
* @reference: other buffer to compare to.
2202
* @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepoint_t) -1.
2203
* @position_fuzz: allowed absolute difference in position values.
2204
*
2205
* If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
2206
* and #HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most
2207
* callers if just comparing two buffers is needed.
2208
*
2209
* Since: 1.5.0
2210
**/
2211
hb_buffer_diff_flags_t
2212
hb_buffer_diff (hb_buffer_t *buffer,
2213
hb_buffer_t *reference,
2214
hb_codepoint_t dottedcircle_glyph,
2215
unsigned int position_fuzz)
2216
{
2217
if (buffer->content_type != reference->content_type && buffer->len && reference->len)
2218
return HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH;
2219
2220
hb_buffer_diff_flags_t result = HB_BUFFER_DIFF_FLAG_EQUAL;
2221
bool contains = dottedcircle_glyph != (hb_codepoint_t) -1;
2222
2223
unsigned int count = reference->len;
2224
2225
if (buffer->len != count)
2226
{
2227
/*
2228
* we can't compare glyph-by-glyph, but we do want to know if there
2229
* are .notdef or dottedcircle glyphs present in the reference buffer
2230
*/
2231
const hb_glyph_info_t *info = reference->info;
2232
unsigned int i;
2233
for (i = 0; i < count; i++)
2234
{
2235
if (contains && info[i].codepoint == dottedcircle_glyph)
2236
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
2237
if (contains && info[i].codepoint == 0)
2238
result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
2239
}
2240
result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;
2241
return hb_buffer_diff_flags_t (result);
2242
}
2243
2244
if (!count)
2245
return hb_buffer_diff_flags_t (result);
2246
2247
const hb_glyph_info_t *buf_info = buffer->info;
2248
const hb_glyph_info_t *ref_info = reference->info;
2249
for (unsigned int i = 0; i < count; i++)
2250
{
2251
if (buf_info->codepoint != ref_info->codepoint)
2252
result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;
2253
if (buf_info->cluster != ref_info->cluster)
2254
result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;
2255
if ((buf_info->mask ^ ref_info->mask) & HB_GLYPH_FLAG_DEFINED)
2256
result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;
2257
if (contains && ref_info->codepoint == dottedcircle_glyph)
2258
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
2259
if (contains && ref_info->codepoint == 0)
2260
result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
2261
buf_info++;
2262
ref_info++;
2263
}
2264
2265
if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)
2266
{
2267
assert (buffer->have_positions);
2268
const hb_glyph_position_t *buf_pos = buffer->pos;
2269
const hb_glyph_position_t *ref_pos = reference->pos;
2270
for (unsigned int i = 0; i < count; i++)
2271
{
2272
if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||
2273
(unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
2274
(unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
2275
(unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
2276
{
2277
result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
2278
break;
2279
}
2280
buf_pos++;
2281
ref_pos++;
2282
}
2283
}
2284
2285
return result;
2286
}
2287
2288
2289
/*
2290
* Debugging.
2291
*/
2292
2293
#ifndef HB_NO_BUFFER_MESSAGE
2294
/**
2295
* hb_buffer_set_message_func:
2296
* @buffer: An #hb_buffer_t
2297
* @func: (closure user_data) (destroy destroy) (scope notified): Callback function
2298
* @user_data: (nullable): Data to pass to @func
2299
* @destroy: (nullable): The function to call when @user_data is not needed anymore
2300
*
2301
* Sets the implementation function for #hb_buffer_message_func_t.
2302
*
2303
* Since: 1.1.3
2304
**/
2305
void
2306
hb_buffer_set_message_func (hb_buffer_t *buffer,
2307
hb_buffer_message_func_t func,
2308
void *user_data, hb_destroy_func_t destroy)
2309
{
2310
if (unlikely (hb_object_is_immutable (buffer)))
2311
{
2312
if (destroy)
2313
destroy (user_data);
2314
return;
2315
}
2316
2317
if (buffer->message_destroy)
2318
buffer->message_destroy (buffer->message_data);
2319
2320
if (func) {
2321
buffer->message_func = func;
2322
buffer->message_data = user_data;
2323
buffer->message_destroy = destroy;
2324
} else {
2325
buffer->message_func = nullptr;
2326
buffer->message_data = nullptr;
2327
buffer->message_destroy = nullptr;
2328
}
2329
}
2330
bool
2331
hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
2332
{
2333
assert (!have_output || (out_info == info && out_len == idx));
2334
2335
message_depth++;
2336
2337
char buf[100];
2338
vsnprintf (buf, sizeof (buf), fmt, ap);
2339
bool ret = (bool) this->message_func (this, font, buf, this->message_data);
2340
2341
message_depth--;
2342
2343
return ret;
2344
}
2345
#endif
2346
2347