Coverage Report

Created: 2025-07-07 10:01

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