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