Coverage Report

Created: 2026-11-06 11:29

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