Coverage Report

Created: 2025-08-26 06:29

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