blob: 495e70278532f8bb767987ac90cd220b1e3ecf8f [file] [log] [blame]
Behdad Esfahboda2a9a022008-01-15 22:46:32 +00001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 1998-2004 David Turner and Werner Lemberg
3 * Copyright © 2004,2007,2009,2010 Red Hat, Inc.
Behdad Esfahbod05207a72012-09-25 17:44:53 -04004 * Copyright © 2011,2012 Google, Inc.
Behdad Esfahbod9f8da382006-03-31 12:28:09 +00005 *
Behdad Esfahbod8f0d7e02011-04-15 18:59:56 -04006 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod9f8da382006-03-31 12:28:09 +00007 *
Behdad Esfahboda2a9a022008-01-15 22:46:32 +00008 * 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
Behdad Esfahbodc910bec2011-04-13 15:49:06 -040027 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod9f8da382006-03-31 12:28:09 +000028 */
29
Behdad Esfahbod22da7fd2010-05-12 18:23:21 -040030#include "hb-buffer-private.hh"
Behdad Esfahbod7f19ae72012-09-25 11:22:28 -040031#include "hb-utf-private.hh"
Behdad Esfahbod9f8da382006-03-31 12:28:09 +000032
Behdad Esfahbodf1322e52009-08-01 22:53:04 -040033
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -040034#ifndef HB_DEBUG_BUFFER
35#define HB_DEBUG_BUFFER (HB_DEBUG+0)
36#endif
37
Behdad Esfahbodf3064102012-11-15 18:39:46 -080038
39hb_bool_t
40hb_segment_properties_equal (const hb_segment_properties_t *a,
41 const hb_segment_properties_t *b)
42{
43 return a->direction == b->direction &&
44 a->script == b->script &&
45 a->language == b->language &&
46 a->reserved1 == b->reserved1 &&
47 a->reserved2 == b->reserved2;
48
49}
50
51unsigned int
52hb_segment_properties_hash (const hb_segment_properties_t *p)
53{
54 return (unsigned int) p->direction ^
55 (unsigned int) p->script ^
56 (intptr_t) (p->language);
57}
58
59
60
Behdad Esfahboda8abb8b2007-10-11 00:07:58 +000061/* Here is how the buffer works internally:
62 *
Behdad Esfahbod910a33f2010-05-14 22:13:38 -040063 * There are two info pointers: info and out_info. They always have
64 * the same allocated size, but different lengths.
Behdad Esfahboda8abb8b2007-10-11 00:07:58 +000065 *
Behdad Esfahbod9d5e26d2010-05-14 22:03:11 -040066 * As an optimization, both info and out_info may point to the
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -040067 * same piece of memory, which is owned by info. This remains the
Behdad Esfahbodcc1a8a92011-01-06 14:58:52 -050068 * case as long as out_len doesn't exceed i at any time.
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040069 * In that case, swap_buffers() is no-op and the glyph operations operate
Behdad Esfahbod910a33f2010-05-14 22:13:38 -040070 * mostly in-place.
Behdad Esfahboda8abb8b2007-10-11 00:07:58 +000071 *
Behdad Esfahbod9d5e26d2010-05-14 22:03:11 -040072 * As soon as out_info gets longer than info, out_info is moved over
Behdad Esfahbod910a33f2010-05-14 22:13:38 -040073 * to an alternate buffer (which we reuse the pos buffer for!), and its
74 * current contents (out_len entries) are copied to the new place.
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040075 * This should all remain transparent to the user. swap_buffers() then
Behdad Esfahbod910a33f2010-05-14 22:13:38 -040076 * switches info and out_info.
Behdad Esfahboda8abb8b2007-10-11 00:07:58 +000077 */
78
Behdad Esfahbodc968fc22009-05-25 04:04:24 -040079
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040080
81/* Internal API */
82
83bool
84hb_buffer_t::enlarge (unsigned int size)
Behdad Esfahbod3567b872010-05-14 23:28:44 -040085{
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040086 if (unlikely (in_error))
Behdad Esfahbod0594a242012-06-05 20:35:40 -040087 return false;
Behdad Esfahbod3567b872010-05-14 23:28:44 -040088
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040089 unsigned int new_allocated = allocated;
Behdad Esfahbode0db4b82011-04-28 12:56:49 -040090 hb_glyph_position_t *new_pos = NULL;
91 hb_glyph_info_t *new_info = NULL;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040092 bool separate_out = out_info != info;
Behdad Esfahbod3567b872010-05-14 23:28:44 -040093
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040094 if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
Behdad Esfahbode0db4b82011-04-28 12:56:49 -040095 goto done;
Behdad Esfahbod3567b872010-05-14 23:28:44 -040096
Behdad Esfahbod38b015e2012-10-28 20:11:47 -070097 while (size >= new_allocated)
Behdad Esfahbod65e00632011-04-27 09:33:58 -040098 new_allocated += (new_allocated >> 1) + 32;
Behdad Esfahbod3567b872010-05-14 23:28:44 -040099
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400100 ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
101 if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
Behdad Esfahbode0db4b82011-04-28 12:56:49 -0400102 goto done;
Behdad Esfahbodb5dd44e2011-02-28 10:13:52 -0800103
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400104 new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
105 new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400106
Behdad Esfahbode0db4b82011-04-28 12:56:49 -0400107done:
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400108 if (unlikely (!new_pos || !new_info))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400109 in_error = true;
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400110
111 if (likely (new_pos))
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400112 pos = new_pos;
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400113
114 if (likely (new_info))
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400115 info = new_info;
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400116
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400117 out_info = separate_out ? (hb_glyph_info_t *) pos : info;
118 if (likely (!in_error))
119 allocated = new_allocated;
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400120
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400121 return likely (!in_error);
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400122}
123
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400124bool
125hb_buffer_t::make_room_for (unsigned int num_in,
126 unsigned int num_out)
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400127{
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400128 if (unlikely (!ensure (out_len + num_out))) return false;
Behdad Esfahbod6b347132007-10-11 08:30:50 +0000129
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400130 if (out_info == info &&
131 out_len + num_out > idx + num_in)
Behdad Esfahbode35bbd52009-05-30 12:02:46 -0400132 {
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400133 assert (have_output);
Behdad Esfahbode35bbd52009-05-30 12:02:46 -0400134
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400135 out_info = (hb_glyph_info_t *) pos;
136 memcpy (out_info, info, out_len * sizeof (out_info[0]));
Behdad Esfahbode35bbd52009-05-30 12:02:46 -0400137 }
Behdad Esfahboda6a79df2010-05-14 23:20:16 -0400138
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400139 return true;
Behdad Esfahboda8abb8b2007-10-11 00:07:58 +0000140}
141
Behdad Esfahbode62df432011-08-03 17:38:54 -0400142void *
143hb_buffer_t::get_scratch_buffer (unsigned int *size)
144{
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400145 have_output = false;
146 have_positions = false;
Behdad Esfahbod47ef9312012-07-19 20:52:44 -0400147
Behdad Esfahbode62df432011-08-03 17:38:54 -0400148 out_len = 0;
Behdad Esfahbod47ef9312012-07-19 20:52:44 -0400149 out_info = info;
150
Behdad Esfahbode62df432011-08-03 17:38:54 -0400151 *size = allocated * sizeof (pos[0]);
152 return pos;
153}
154
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400155
Behdad Esfahbod69cc4922012-07-31 14:51:36 -0400156
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400157/* HarfBuzz-Internal API */
158
159void
160hb_buffer_t::reset (void)
161{
162 if (unlikely (hb_object_is_inert (this)))
163 return;
164
165 hb_unicode_funcs_destroy (unicode);
Behdad Esfahbodd5045a52012-08-11 21:26:25 -0400166 unicode = hb_unicode_funcs_get_default ();
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400167
Behdad Esfahbod82ecaff2012-11-13 13:57:52 -0800168 clear ();
169}
170
171void
172hb_buffer_t::clear (void)
173{
174 if (unlikely (hb_object_is_inert (this)))
175 return;
176
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800177 hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -0400178 props = default_props;
Behdad Esfahbod4dc798d2013-08-26 20:39:00 -0400179 flags = HB_BUFFER_FLAG_DEFAULT;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400180
Behdad Esfahbod96fdc042012-09-06 22:26:16 -0400181 content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400182 in_error = false;
183 have_output = false;
184 have_positions = false;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400185
186 idx = 0;
187 len = 0;
188 out_len = 0;
Behdad Esfahbod47ef9312012-07-19 20:52:44 -0400189 out_info = info;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400190
191 serial = 0;
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400192 memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
193 memset (allocated_var_owner, 0, sizeof allocated_var_owner);
Behdad Esfahbod05207a72012-09-25 17:44:53 -0400194
195 memset (context, 0, sizeof context);
196 memset (context_len, 0, sizeof context_len);
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400197}
198
199void
200hb_buffer_t::add (hb_codepoint_t codepoint,
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400201 unsigned int cluster)
202{
203 hb_glyph_info_t *glyph;
204
205 if (unlikely (!ensure (len + 1))) return;
206
207 glyph = &info[len];
208
209 memset (glyph, 0, sizeof (*glyph));
210 glyph->codepoint = codepoint;
Behdad Esfahbod66ac2ff2012-11-13 16:26:32 -0800211 glyph->mask = 1;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400212 glyph->cluster = cluster;
213
214 len++;
215}
216
217void
Behdad Esfahbod847794e2013-02-27 17:59:28 -0500218hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
219{
220 if (unlikely (!ensure (len + 1))) return;
221
222 info[len] = glyph_info;
223
224 len++;
225}
226
227
228void
Behdad Esfahbod0bc7a382012-10-29 22:02:45 -0700229hb_buffer_t::remove_output (void)
230{
231 if (unlikely (hb_object_is_inert (this)))
232 return;
233
234 have_output = false;
235 have_positions = false;
236
237 out_len = 0;
238 out_info = info;
239}
240
241void
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400242hb_buffer_t::clear_output (void)
243{
244 if (unlikely (hb_object_is_inert (this)))
245 return;
246
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400247 have_output = true;
248 have_positions = false;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400249
250 out_len = 0;
251 out_info = info;
252}
253
254void
255hb_buffer_t::clear_positions (void)
256{
257 if (unlikely (hb_object_is_inert (this)))
258 return;
259
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400260 have_output = false;
261 have_positions = true;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400262
Behdad Esfahbod47ef9312012-07-19 20:52:44 -0400263 out_len = 0;
264 out_info = info;
265
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400266 memset (pos, 0, sizeof (pos[0]) * len);
267}
268
269void
270hb_buffer_t::swap_buffers (void)
271{
272 if (unlikely (in_error)) return;
273
274 assert (have_output);
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400275 have_output = false;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400276
277 if (out_info != info)
278 {
279 hb_glyph_info_t *tmp_string;
280 tmp_string = info;
281 info = out_info;
282 out_info = tmp_string;
283 pos = (hb_glyph_position_t *) out_info;
284 }
285
286 unsigned int tmp;
287 tmp = len;
288 len = out_len;
289 out_len = tmp;
290
291 idx = 0;
292}
293
Behdad Esfahbod69cc4922012-07-31 14:51:36 -0400294
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400295void
Behdad Esfahbod9ebe8c02011-08-26 09:29:42 +0200296hb_buffer_t::replace_glyphs (unsigned int num_in,
297 unsigned int num_out,
Behdad Esfahbod8e3715f2012-04-23 22:18:54 -0400298 const uint32_t *glyph_data)
Behdad Esfahbod9ebe8c02011-08-26 09:29:42 +0200299{
Behdad Esfahbod69cc4922012-07-31 14:51:36 -0400300 if (unlikely (!make_room_for (num_in, num_out))) return;
Behdad Esfahbod9ebe8c02011-08-26 09:29:42 +0200301
Behdad Esfahbode88e1442012-06-08 20:55:21 -0400302 merge_clusters (idx, idx + num_in);
Behdad Esfahbod9ebe8c02011-08-26 09:29:42 +0200303
Behdad Esfahbode88e1442012-06-08 20:55:21 -0400304 hb_glyph_info_t orig_info = info[idx];
Behdad Esfahbod9ebe8c02011-08-26 09:29:42 +0200305 hb_glyph_info_t *pinfo = &out_info[out_len];
306 for (unsigned int i = 0; i < num_out; i++)
307 {
308 *pinfo = orig_info;
309 pinfo->codepoint = glyph_data[i];
310 pinfo++;
311 }
312
313 idx += num_in;
314 out_len += num_out;
315}
316
317void
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400318hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
319{
Behdad Esfahbod69cc4922012-07-31 14:51:36 -0400320 if (unlikely (!make_room_for (0, 1))) return;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400321
322 out_info[out_len] = info[idx];
323 out_info[out_len].codepoint = glyph_index;
324
325 out_len++;
326}
327
328void
Behdad Esfahbod847794e2013-02-27 17:59:28 -0500329hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
Behdad Esfahbodb85800f2012-08-31 18:12:01 -0400330{
331 if (unlikely (!make_room_for (0, 1))) return;
332
333 out_info[out_len] = glyph_info;
334
335 out_len++;
336}
337
338void
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400339hb_buffer_t::copy_glyph (void)
340{
Behdad Esfahbod69cc4922012-07-31 14:51:36 -0400341 if (unlikely (!make_room_for (0, 1))) return;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400342
343 out_info[out_len] = info[idx];
344
345 out_len++;
346}
347
348void
349hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
350{
Behdad Esfahbod69cc4922012-07-31 14:51:36 -0400351 if (unlikely (out_info != info || out_len != idx)) {
352 if (unlikely (!make_room_for (1, 1))) return;
353 out_info[out_len] = info[idx];
354 }
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400355 out_info[out_len].codepoint = glyph_index;
356
357 idx++;
358 out_len++;
359}
360
Behdad Esfahbod69cc4922012-07-31 14:51:36 -0400361
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400362void
363hb_buffer_t::set_masks (hb_mask_t value,
364 hb_mask_t mask,
365 unsigned int cluster_start,
366 unsigned int cluster_end)
367{
368 hb_mask_t not_mask = ~mask;
369 value &= mask;
370
371 if (!mask)
372 return;
373
374 if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
375 unsigned int count = len;
376 for (unsigned int i = 0; i < count; i++)
377 info[i].mask = (info[i].mask & not_mask) | value;
378 return;
379 }
380
381 unsigned int count = len;
382 for (unsigned int i = 0; i < count; i++)
383 if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
384 info[i].mask = (info[i].mask & not_mask) | value;
385}
386
387void
388hb_buffer_t::reverse_range (unsigned int start,
389 unsigned int end)
390{
391 unsigned int i, j;
392
393 if (start == end - 1)
394 return;
395
396 for (i = start, j = end - 1; i < j; i++, j--) {
397 hb_glyph_info_t t;
398
399 t = info[i];
400 info[i] = info[j];
401 info[j] = t;
402 }
403
404 if (pos) {
405 for (i = start, j = end - 1; i < j; i++, j--) {
406 hb_glyph_position_t t;
407
408 t = pos[i];
409 pos[i] = pos[j];
410 pos[j] = t;
411 }
412 }
413}
414
415void
416hb_buffer_t::reverse (void)
417{
418 if (unlikely (!len))
419 return;
420
421 reverse_range (0, len);
422}
423
424void
425hb_buffer_t::reverse_clusters (void)
426{
427 unsigned int i, start, count, last_cluster;
428
429 if (unlikely (!len))
430 return;
431
432 reverse ();
433
434 count = len;
435 start = 0;
436 last_cluster = info[0].cluster;
437 for (i = 1; i < count; i++) {
438 if (last_cluster != info[i].cluster) {
439 reverse_range (start, i);
440 start = i;
441 last_cluster = info[i].cluster;
442 }
443 }
444 reverse_range (start, i);
445}
446
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400447void
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400448hb_buffer_t::merge_clusters (unsigned int start,
449 unsigned int end)
450{
Behdad Esfahbodfe3dabc2012-06-08 20:56:05 -0400451 if (unlikely (end - start < 2))
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400452 return;
453
454 unsigned int cluster = info[start].cluster;
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400455
456 for (unsigned int i = start + 1; i < end; i++)
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400457 cluster = MIN (cluster, info[i].cluster);
458
459 /* Extend end */
460 while (end < len && info[end - 1].cluster == info[end].cluster)
461 end++;
462
Behdad Esfahbodcd589142012-06-08 20:27:53 -0400463 /* Extend start */
464 while (idx < start && info[start - 1].cluster == info[start].cluster)
465 start--;
466
467 /* If we hit the start of buffer, continue in out-buffer. */
468 if (idx == start)
469 for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
470 out_info[i - 1].cluster = cluster;
471
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400472 for (unsigned int i = start; i < end; i++)
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400473 info[i].cluster = cluster;
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400474}
475void
476hb_buffer_t::merge_out_clusters (unsigned int start,
477 unsigned int end)
478{
Behdad Esfahbodfe3dabc2012-06-08 20:56:05 -0400479 if (unlikely (end - start < 2))
Behdad Esfahbod72c0a182012-06-08 20:30:03 -0400480 return;
481
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400482 unsigned int cluster = out_info[start].cluster;
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400483
484 for (unsigned int i = start + 1; i < end; i++)
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400485 cluster = MIN (cluster, out_info[i].cluster);
Behdad Esfahbod72c0a182012-06-08 20:30:03 -0400486
487 /* Extend start */
488 while (start && out_info[start - 1].cluster == out_info[start].cluster)
489 start--;
490
Behdad Esfahbod5ced0122012-06-08 20:31:32 -0400491 /* Extend end */
492 while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
493 end++;
494
Behdad Esfahbode51d2b62012-06-08 20:33:27 -0400495 /* If we hit the end of out-buffer, continue in buffer. */
496 if (end == out_len)
497 for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
498 info[i].cluster = cluster;
499
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400500 for (unsigned int i = start; i < end; i++)
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400501 out_info[i].cluster = cluster;
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400502}
503
504void
Behdad Esfahbod3f82f8f2012-11-15 18:45:31 -0800505hb_buffer_t::guess_segment_properties (void)
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400506{
Behdad Esfahbod8465a052012-11-30 08:46:43 +0200507 assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
508 (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
Behdad Esfahbod96fdc042012-09-06 22:26:16 -0400509
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400510 /* If script is set to INVALID, guess from buffer contents */
511 if (props.script == HB_SCRIPT_INVALID) {
512 for (unsigned int i = 0; i < len; i++) {
Behdad Esfahbod208f70f2012-08-01 17:13:10 -0400513 hb_script_t script = unicode->script (info[i].codepoint);
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400514 if (likely (script != HB_SCRIPT_COMMON &&
515 script != HB_SCRIPT_INHERITED &&
516 script != HB_SCRIPT_UNKNOWN)) {
517 props.script = script;
518 break;
519 }
520 }
521 }
522
523 /* If direction is set to INVALID, guess from script */
524 if (props.direction == HB_DIRECTION_INVALID) {
525 props.direction = hb_script_get_horizontal_direction (props.script);
526 }
527
528 /* If language is not set, use default language from locale */
529 if (props.language == HB_LANGUAGE_INVALID) {
530 /* TODO get_default_for_script? using $LANGUAGE */
531 props.language = hb_language_get_default ();
532 }
533}
534
535
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -0400536static inline void
537dump_var_allocation (const hb_buffer_t *buffer)
538{
539 char buf[80];
540 for (unsigned int i = 0; i < 8; i++)
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400541 buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -0400542 buf[8] = '\0';
543 DEBUG_MSG (BUFFER, buffer,
544 "Current var allocation: %s",
545 buf);
546}
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400547
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400548void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
549{
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400550 assert (byte_i < 8 && byte_i + count <= 8);
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -0400551
Behdad Esfahbod6c15ddf2013-04-30 11:34:00 -0400552 if (DEBUG_ENABLED (BUFFER))
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -0400553 dump_var_allocation (this);
554 DEBUG_MSG (BUFFER, this,
555 "Allocating var bytes %d..%d for %s",
556 byte_i, byte_i + count - 1, owner);
557
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400558 for (unsigned int i = byte_i; i < byte_i + count; i++) {
559 assert (!allocated_var_bytes[i]);
560 allocated_var_bytes[i]++;
561 allocated_var_owner[i] = owner;
562 }
563}
564
565void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
566{
Behdad Esfahbod6c15ddf2013-04-30 11:34:00 -0400567 if (DEBUG_ENABLED (BUFFER))
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400568 dump_var_allocation (this);
569
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -0400570 DEBUG_MSG (BUFFER, this,
571 "Deallocating var bytes %d..%d for %s",
572 byte_i, byte_i + count - 1, owner);
573
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400574 assert (byte_i < 8 && byte_i + count <= 8);
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400575 for (unsigned int i = byte_i; i < byte_i + count; i++) {
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400576 assert (allocated_var_bytes[i]);
577 assert (0 == strcmp (allocated_var_owner[i], owner));
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400578 allocated_var_bytes[i]--;
579 }
580}
581
Behdad Esfahbod965c2802012-08-29 13:59:16 -0400582void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
583{
Behdad Esfahbod6c15ddf2013-04-30 11:34:00 -0400584 if (DEBUG_ENABLED (BUFFER))
Behdad Esfahbod965c2802012-08-29 13:59:16 -0400585 dump_var_allocation (this);
586
587 DEBUG_MSG (BUFFER, this,
588 "Asserting var bytes %d..%d for %s",
589 byte_i, byte_i + count - 1, owner);
590
591 assert (byte_i < 8 && byte_i + count <= 8);
592 for (unsigned int i = byte_i; i < byte_i + count; i++) {
593 assert (allocated_var_bytes[i]);
594 assert (0 == strcmp (allocated_var_owner[i], owner));
595 }
596}
597
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -0400598void hb_buffer_t::deallocate_var_all (void)
599{
600 memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
601 memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
602}
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400603
Behdad Esfahbod6b347132007-10-11 08:30:50 +0000604/* Public API */
605
Behdad Esfahbodb857b492009-05-20 05:35:14 -0400606hb_buffer_t *
Behdad Esfahbodc54599a2012-11-15 16:14:23 -0800607hb_buffer_create (void)
Behdad Esfahbod9f8da382006-03-31 12:28:09 +0000608{
Behdad Esfahbodb857b492009-05-20 05:35:14 -0400609 hb_buffer_t *buffer;
610
Behdad Esfahbod47e71d92011-04-27 16:38:03 -0400611 if (!(buffer = hb_object_create<hb_buffer_t> ()))
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -0400612 return hb_buffer_get_empty ();
Behdad Esfahbod9f8da382006-03-31 12:28:09 +0000613
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400614 buffer->reset ();
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500615
Behdad Esfahbodb857b492009-05-20 05:35:14 -0400616 return buffer;
Behdad Esfahbod9f8da382006-03-31 12:28:09 +0000617}
618
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400619hb_buffer_t *
Behdad Esfahbod80a68332011-05-11 18:14:44 -0400620hb_buffer_get_empty (void)
621{
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -0400622 static const hb_buffer_t _hb_buffer_nil = {
623 HB_OBJECT_HEADER_STATIC,
624
Behdad Esfahbodd5045a52012-08-11 21:26:25 -0400625 const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800626 HB_SEGMENT_PROPERTIES_DEFAULT,
Behdad Esfahbod4dc798d2013-08-26 20:39:00 -0400627 HB_BUFFER_FLAG_DEFAULT,
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -0400628
Behdad Esfahbod96fdc042012-09-06 22:26:16 -0400629 HB_BUFFER_CONTENT_TYPE_INVALID,
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400630 true, /* in_error */
631 true, /* have_output */
632 true /* have_positions */
Behdad Esfahbod05207a72012-09-25 17:44:53 -0400633
634 /* Zero is good enough for everything else. */
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -0400635 };
636
637 return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
Behdad Esfahbod80a68332011-05-11 18:14:44 -0400638}
639
640hb_buffer_t *
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400641hb_buffer_reference (hb_buffer_t *buffer)
Behdad Esfahbod7a268642007-10-11 07:21:31 +0000642{
Behdad Esfahbod47e71d92011-04-27 16:38:03 -0400643 return hb_object_reference (buffer);
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400644}
645
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400646void
647hb_buffer_destroy (hb_buffer_t *buffer)
648{
Behdad Esfahbod47e71d92011-04-27 16:38:03 -0400649 if (!hb_object_destroy (buffer)) return;
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400650
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500651 hb_unicode_funcs_destroy (buffer->unicode);
652
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -0400653 free (buffer->info);
Behdad Esfahbod1b621822010-05-14 22:05:53 -0400654 free (buffer->pos);
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400655
Behdad Esfahbodb857b492009-05-20 05:35:14 -0400656 free (buffer);
Behdad Esfahbod7a268642007-10-11 07:21:31 +0000657}
658
Behdad Esfahbod5fa849b2011-04-27 21:46:01 -0400659hb_bool_t
660hb_buffer_set_user_data (hb_buffer_t *buffer,
661 hb_user_data_key_t *key,
662 void * data,
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200663 hb_destroy_func_t destroy,
664 hb_bool_t replace)
Behdad Esfahbod5fa849b2011-04-27 21:46:01 -0400665{
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200666 return hb_object_set_user_data (buffer, key, data, destroy, replace);
Behdad Esfahbod5fa849b2011-04-27 21:46:01 -0400667}
668
669void *
670hb_buffer_get_user_data (hb_buffer_t *buffer,
671 hb_user_data_key_t *key)
672{
673 return hb_object_get_user_data (buffer, key);
674}
675
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500676
677void
Behdad Esfahbod96fdc042012-09-06 22:26:16 -0400678hb_buffer_set_content_type (hb_buffer_t *buffer,
679 hb_buffer_content_type_t content_type)
680{
681 buffer->content_type = content_type;
682}
683
684hb_buffer_content_type_t
685hb_buffer_get_content_type (hb_buffer_t *buffer)
686{
687 return buffer->content_type;
688}
689
690
691void
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500692hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
693 hb_unicode_funcs_t *unicode)
694{
Behdad Esfahbode0db4b82011-04-28 12:56:49 -0400695 if (unlikely (hb_object_is_inert (buffer)))
696 return;
697
Behdad Esfahbod0465e692009-12-20 16:25:18 +0100698 if (!unicode)
Behdad Esfahbodd5045a52012-08-11 21:26:25 -0400699 unicode = hb_unicode_funcs_get_default ();
700
Behdad Esfahbod0465e692009-12-20 16:25:18 +0100701
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500702 hb_unicode_funcs_reference (unicode);
703 hb_unicode_funcs_destroy (buffer->unicode);
704 buffer->unicode = unicode;
705}
706
707hb_unicode_funcs_t *
708hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
709{
710 return buffer->unicode;
711}
712
713void
714hb_buffer_set_direction (hb_buffer_t *buffer,
715 hb_direction_t direction)
716
717{
Behdad Esfahbode0db4b82011-04-28 12:56:49 -0400718 if (unlikely (hb_object_is_inert (buffer)))
719 return;
720
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400721 buffer->props.direction = direction;
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500722}
723
724hb_direction_t
725hb_buffer_get_direction (hb_buffer_t *buffer)
726{
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400727 return buffer->props.direction;
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500728}
729
Behdad Esfahbodae070b72009-11-04 20:29:54 -0500730void
731hb_buffer_set_script (hb_buffer_t *buffer,
732 hb_script_t script)
733{
Behdad Esfahbode0db4b82011-04-28 12:56:49 -0400734 if (unlikely (hb_object_is_inert (buffer)))
735 return;
736
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400737 buffer->props.script = script;
Behdad Esfahbodae070b72009-11-04 20:29:54 -0500738}
739
740hb_script_t
741hb_buffer_get_script (hb_buffer_t *buffer)
742{
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400743 return buffer->props.script;
Behdad Esfahbodae070b72009-11-04 20:29:54 -0500744}
745
746void
747hb_buffer_set_language (hb_buffer_t *buffer,
748 hb_language_t language)
749{
Behdad Esfahbode0db4b82011-04-28 12:56:49 -0400750 if (unlikely (hb_object_is_inert (buffer)))
751 return;
752
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400753 buffer->props.language = language;
Behdad Esfahbodae070b72009-11-04 20:29:54 -0500754}
755
756hb_language_t
757hb_buffer_get_language (hb_buffer_t *buffer)
758{
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400759 return buffer->props.language;
Behdad Esfahbodae070b72009-11-04 20:29:54 -0500760}
761
Behdad Esfahbod0c7df222012-11-13 14:42:35 -0800762void
Behdad Esfahbodf3064102012-11-15 18:39:46 -0800763hb_buffer_set_segment_properties (hb_buffer_t *buffer,
764 const hb_segment_properties_t *props)
765{
766 if (unlikely (hb_object_is_inert (buffer)))
767 return;
768
769 buffer->props = *props;
770}
771
772void
773hb_buffer_get_segment_properties (hb_buffer_t *buffer,
774 hb_segment_properties_t *props)
775{
776 *props = buffer->props;
777}
778
779
780void
Behdad Esfahbod0c7df222012-11-13 14:42:35 -0800781hb_buffer_set_flags (hb_buffer_t *buffer,
782 hb_buffer_flags_t flags)
783{
784 if (unlikely (hb_object_is_inert (buffer)))
785 return;
786
787 buffer->flags = flags;
788}
789
790hb_buffer_flags_t
791hb_buffer_get_flags (hb_buffer_t *buffer)
792{
793 return buffer->flags;
794}
795
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500796
Behdad Esfahbod7a268642007-10-11 07:21:31 +0000797void
Behdad Esfahbodc910bec2011-04-13 15:49:06 -0400798hb_buffer_reset (hb_buffer_t *buffer)
799{
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400800 buffer->reset ();
Behdad Esfahbod7a268642007-10-11 07:21:31 +0000801}
802
Behdad Esfahbod82ecaff2012-11-13 13:57:52 -0800803void
Behdad Esfahbod1172dc72013-01-07 16:46:37 -0600804hb_buffer_clear_contents (hb_buffer_t *buffer)
Behdad Esfahbod82ecaff2012-11-13 13:57:52 -0800805{
806 buffer->clear ();
807}
808
Behdad Esfahboda6a79df2010-05-14 23:20:16 -0400809hb_bool_t
Ryan Lortie02a534b2011-04-15 18:34:45 -0400810hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
Behdad Esfahbodf9cd1012009-07-28 15:43:34 -0400811{
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400812 return buffer->ensure (size);
Behdad Esfahbodf9cd1012009-07-28 15:43:34 -0400813}
814
Behdad Esfahbodaab0de52011-04-19 00:32:19 -0400815hb_bool_t
816hb_buffer_allocation_successful (hb_buffer_t *buffer)
817{
818 return !buffer->in_error;
819}
820
Behdad Esfahbodf9cd1012009-07-28 15:43:34 -0400821void
Behdad Esfahbodf85faee2011-04-19 00:38:01 -0400822hb_buffer_add (hb_buffer_t *buffer,
823 hb_codepoint_t codepoint,
Behdad Esfahbodf85faee2011-04-19 00:38:01 -0400824 unsigned int cluster)
Behdad Esfahbod6b347132007-10-11 08:30:50 +0000825{
Behdad Esfahbod66ac2ff2012-11-13 16:26:32 -0800826 buffer->add (codepoint, cluster);
Behdad Esfahbod05207a72012-09-25 17:44:53 -0400827 buffer->clear_context (1);
Behdad Esfahbod6b347132007-10-11 08:30:50 +0000828}
829
Behdad Esfahbodc910bec2011-04-13 15:49:06 -0400830hb_bool_t
831hb_buffer_set_length (hb_buffer_t *buffer,
832 unsigned int length)
833{
Behdad Esfahbode1ac38f2012-06-05 20:31:49 -0400834 if (unlikely (hb_object_is_inert (buffer)))
835 return length == 0;
836
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400837 if (!buffer->ensure (length))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400838 return false;
Behdad Esfahbodc910bec2011-04-13 15:49:06 -0400839
840 /* Wipe the new space */
841 if (length > buffer->len) {
842 memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
843 if (buffer->have_positions)
844 memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
845 }
846
847 buffer->len = length;
Behdad Esfahbod05207a72012-09-25 17:44:53 -0400848
849 if (!length)
850 buffer->clear_context (0);
851 buffer->clear_context (1);
852
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400853 return true;
Behdad Esfahbodc910bec2011-04-13 15:49:06 -0400854}
855
Behdad Esfahbod5f512012013-09-04 18:28:39 -0400856/**
857 * hb_buffer_get_length:
858 * @buffer: a buffer.
859 *
860 * Returns the number of items in the buffer.
861 *
862 * Return value: buffer length.
863 *
864 * Since: 1.0
865 */
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400866unsigned int
Behdad Esfahbod3d145282009-11-06 15:13:17 -0500867hb_buffer_get_length (hb_buffer_t *buffer)
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400868{
Behdad Esfahbod69603502010-05-14 22:07:46 -0400869 return buffer->len;
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400870}
871
Behdad Esfahbod5f512012013-09-04 18:28:39 -0400872/**
873 * hb_buffer_get_glyph_infos:
874 * @buffer: a buffer.
875 * @length: (out): output array length.
876 *
877 * Returns buffer glyph information array. Returned pointer
878 * is valid as long as buffer contents are not modified.
879 *
880 * Return value: (transfer none) (array length=length): buffer glyph information array.
881 *
882 * Since: 1.0
883 */
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400884hb_glyph_info_t *
Ryan Lortie70566be2011-04-15 18:32:36 -0400885hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
886 unsigned int *length)
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400887{
Ryan Lortie70566be2011-04-15 18:32:36 -0400888 if (length)
889 *length = buffer->len;
890
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -0400891 return (hb_glyph_info_t *) buffer->info;
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400892}
893
Behdad Esfahbod5f512012013-09-04 18:28:39 -0400894/**
895 * hb_buffer_get_glyph_positions:
896 * @buffer: a buffer.
897 * @length: (out): output length.
898 *
899 * Returns buffer glyph position array. Returned pointer
900 * is valid as long as buffer contents are not modified.
901 *
902 * Return value: (transfer none) (array length=length): buffer glyph position array.
903 *
904 * Since: 1.0
905 */
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400906hb_glyph_position_t *
Ryan Lortie70566be2011-04-15 18:32:36 -0400907hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
908 unsigned int *length)
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400909{
Behdad Esfahbod314905d2009-12-20 14:50:42 +0100910 if (!buffer->have_positions)
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400911 buffer->clear_positions ();
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400912
Ryan Lortie70566be2011-04-15 18:32:36 -0400913 if (length)
914 *length = buffer->len;
915
Behdad Esfahbod1b621822010-05-14 22:05:53 -0400916 return (hb_glyph_position_t *) buffer->pos;
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400917}
Behdad Esfahbodfbaf8ff2009-08-10 20:59:25 -0400918
Behdad Esfahbod5f512012013-09-04 18:28:39 -0400919/**
920 * hb_buffer_reverse:
921 * @buffer: a buffer.
922 *
923 * Reverses buffer contents.
924 *
925 * Since: 1.0
926 */
Behdad Esfahbodff44f882009-11-06 19:48:16 -0500927void
928hb_buffer_reverse (hb_buffer_t *buffer)
929{
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400930 buffer->reverse ();
Behdad Esfahbodff44f882009-11-06 19:48:16 -0500931}
932
Behdad Esfahbod5f512012013-09-04 18:28:39 -0400933/**
934 * hb_buffer_reverse_clusters:
935 * @buffer: a buffer.
936 *
937 * Reverses buffer clusters. That is, the buffer contents are
938 * reversed, then each cluster (consecutive items having the
939 * same cluster number) are reversed again.
940 *
941 * Since: 1.0
942 */
Behdad Esfahbodff44f882009-11-06 19:48:16 -0500943void
944hb_buffer_reverse_clusters (hb_buffer_t *buffer)
945{
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400946 buffer->reverse_clusters ();
Behdad Esfahbodff44f882009-11-06 19:48:16 -0500947}
948
Behdad Esfahbod5f512012013-09-04 18:28:39 -0400949/**
950 * hb_buffer_guess_segment_properties:
951 * @buffer: a buffer.
952 *
953 * Sets unset buffer segment properties based on buffer Unicode
954 * contents. If buffer is not empty, it must have content type
955 * %HB_BUFFER_CONTENT_TYPE_UNICODE.
956 *
957 * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
958 * will be set to the Unicode script of the first character in
959 * the buffer that has a script other than %HB_SCRIPT_COMMON,
960 * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
961 *
962 * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
963 * it will be set to the natural horizontal direction of the
964 * buffer script as returned by hb_script_get_horizontal_direction().
965 *
966 * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
967 * it will be set to the process's default language as returned by
968 * hb_language_get_default(). This may change in the future by
969 * taking buffer script into consideration when choosing a language.
970 *
971 * Since: 1.0
972 */
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400973void
Behdad Esfahbod3f82f8f2012-11-15 18:45:31 -0800974hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400975{
Behdad Esfahbod3f82f8f2012-11-15 18:45:31 -0800976 buffer->guess_segment_properties ();
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400977}
978
Behdad Esfahbod7f19ae72012-09-25 11:22:28 -0400979template <typename T>
980static inline void
981hb_buffer_add_utf (hb_buffer_t *buffer,
982 const T *text,
983 int text_length,
984 unsigned int item_offset,
985 int item_length)
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400986{
Behdad Esfahbod7f19ae72012-09-25 11:22:28 -0400987 assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
988 (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400989
Behdad Esfahbod7f19ae72012-09-25 11:22:28 -0400990 if (unlikely (hb_object_is_inert (buffer)))
991 return;
Behdad Esfahbod2163afb2010-05-27 14:04:15 -0400992
Behdad Esfahbod1f66c3c2012-09-25 11:42:16 -0400993 if (text_length == -1)
994 text_length = hb_utf_strlen (text);
Behdad Esfahbod7f19ae72012-09-25 11:22:28 -0400995
996 if (item_length == -1)
997 item_length = text_length - item_offset;
998
999 buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
1000
Behdad Esfahbodda701112012-10-31 13:45:30 -07001001 /* If buffer is empty and pre-context provided, install it.
1002 * This check is written this way, to make sure people can
1003 * provide pre-context in one add_utf() call, then provide
1004 * text in a follow-up call. See:
1005 *
1006 * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
1007 */
1008 if (!buffer->len && item_offset > 0)
Behdad Esfahbod05207a72012-09-25 17:44:53 -04001009 {
1010 /* Add pre-context */
1011 buffer->clear_context (0);
1012 const T *prev = text + item_offset;
1013 const T *start = text;
1014 while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
1015 {
1016 hb_codepoint_t u;
1017 prev = hb_utf_prev (prev, start, &u);
1018 buffer->context[0][buffer->context_len[0]++] = u;
1019 }
1020 }
1021
1022 const T *next = text + item_offset;
Behdad Esfahbod7f19ae72012-09-25 11:22:28 -04001023 const T *end = next + item_length;
Behdad Esfahbod05207a72012-09-25 17:44:53 -04001024 while (next < end)
1025 {
Behdad Esfahbod7f19ae72012-09-25 11:22:28 -04001026 hb_codepoint_t u;
1027 const T *old_next = next;
1028 next = hb_utf_next (next, end, &u);
Behdad Esfahbod66ac2ff2012-11-13 16:26:32 -08001029 buffer->add (u, old_next - (const T *) text);
Behdad Esfahbod05207a72012-09-25 17:44:53 -04001030 }
1031
1032 /* Add post-context */
1033 buffer->clear_context (1);
1034 end = text + text_length;
1035 while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
1036 {
1037 hb_codepoint_t u;
1038 next = hb_utf_next (next, end, &u);
1039 buffer->context[1][buffer->context_len[1]++] = u;
Behdad Esfahbod7f19ae72012-09-25 11:22:28 -04001040 }
1041
1042 buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
Behdad Esfahbod299f0892009-08-10 22:47:57 -04001043}
1044
1045void
1046hb_buffer_add_utf8 (hb_buffer_t *buffer,
1047 const char *text,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +02001048 int text_length,
Behdad Esfahbod299f0892009-08-10 22:47:57 -04001049 unsigned int item_offset,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +02001050 int item_length)
Behdad Esfahbod299f0892009-08-10 22:47:57 -04001051{
Behdad Esfahbod7f19ae72012-09-25 11:22:28 -04001052 hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
Behdad Esfahbod299f0892009-08-10 22:47:57 -04001053}
1054
1055void
1056hb_buffer_add_utf16 (hb_buffer_t *buffer,
1057 const uint16_t *text,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +02001058 int text_length,
Behdad Esfahbod299f0892009-08-10 22:47:57 -04001059 unsigned int item_offset,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +02001060 int item_length)
Behdad Esfahbod299f0892009-08-10 22:47:57 -04001061{
Behdad Esfahbod7f19ae72012-09-25 11:22:28 -04001062 hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
Behdad Esfahbod0e0a4da2012-09-25 11:09:04 -04001063}
1064
Behdad Esfahbod299f0892009-08-10 22:47:57 -04001065void
1066hb_buffer_add_utf32 (hb_buffer_t *buffer,
1067 const uint32_t *text,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +02001068 int text_length,
Behdad Esfahbod299f0892009-08-10 22:47:57 -04001069 unsigned int item_offset,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +02001070 int item_length)
Behdad Esfahbod299f0892009-08-10 22:47:57 -04001071{
Behdad Esfahbod7f19ae72012-09-25 11:22:28 -04001072 hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
Behdad Esfahbod299f0892009-08-10 22:47:57 -04001073}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001074
1075
Behdad Esfahbod39b17832012-07-17 17:09:29 -04001076static int
1077compare_info_codepoint (const hb_glyph_info_t *pa,
1078 const hb_glyph_info_t *pb)
1079{
1080 return (int) pb->codepoint - (int) pa->codepoint;
1081}
1082
1083static inline void
1084normalize_glyphs_cluster (hb_buffer_t *buffer,
1085 unsigned int start,
1086 unsigned int end,
1087 bool backward)
1088{
1089 hb_glyph_position_t *pos = buffer->pos;
1090
1091 /* Total cluster advance */
1092 hb_position_t total_x_advance = 0, total_y_advance = 0;
1093 for (unsigned int i = start; i < end; i++)
1094 {
1095 total_x_advance += pos[i].x_advance;
1096 total_y_advance += pos[i].y_advance;
1097 }
1098
1099 hb_position_t x_advance = 0, y_advance = 0;
1100 for (unsigned int i = start; i < end; i++)
1101 {
1102 pos[i].x_offset += x_advance;
1103 pos[i].y_offset += y_advance;
1104
1105 x_advance += pos[i].x_advance;
1106 y_advance += pos[i].y_advance;
1107
1108 pos[i].x_advance = 0;
1109 pos[i].y_advance = 0;
1110 }
1111
1112 if (backward)
1113 {
1114 /* Transfer all cluster advance to the last glyph. */
1115 pos[end - 1].x_advance = total_x_advance;
1116 pos[end - 1].y_advance = total_y_advance;
1117
1118 hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
1119 } else {
1120 /* Transfer all cluster advance to the first glyph. */
1121 pos[start].x_advance += total_x_advance;
1122 pos[start].y_advance += total_y_advance;
1123 for (unsigned int i = start + 1; i < end; i++) {
1124 pos[i].x_offset -= total_x_advance;
1125 pos[i].y_offset -= total_y_advance;
1126 }
1127 hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
1128 }
1129}
1130
1131void
1132hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
1133{
1134 assert (buffer->have_positions);
Behdad Esfahbod7d372802012-09-25 11:04:41 -04001135 assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
Behdad Esfahbod39b17832012-07-17 17:09:29 -04001136
1137 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
1138
1139 unsigned int count = buffer->len;
1140 if (unlikely (!count)) return;
1141 hb_glyph_info_t *info = buffer->info;
1142
1143 unsigned int start = 0;
1144 unsigned int end;
1145 for (end = start + 1; end < count; end++)
1146 if (info[start].cluster != info[end].cluster) {
1147 normalize_glyphs_cluster (buffer, start, end, backward);
1148 start = end;
1149 }
1150 normalize_glyphs_cluster (buffer, start, end, backward);
1151}