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