blob: 38eb95f86d69204ae8430d362b25b7c09eafec45 [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.
4 * Copyright © 2011 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 Esfahbod9f8da382006-03-31 12:28:09 +000031
Behdad Esfahbod88a5f5a2009-05-25 03:39:11 -040032#include <string.h>
33
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040034
Behdad Esfahbodf1322e52009-08-01 22:53:04 -040035
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -040036#ifndef HB_DEBUG_BUFFER
37#define HB_DEBUG_BUFFER (HB_DEBUG+0)
38#endif
39
Behdad Esfahbodbe4560a2012-06-05 18:14:03 -040040#define _HB_BUFFER_UNICODE_FUNCS_DEFAULT (const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_default))
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -040041#define _HB_BUFFER_PROPS_DEFAULT { HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID }
Behdad Esfahbod11fbb542009-08-01 22:19:06 -040042
Behdad Esfahboda8abb8b2007-10-11 00:07:58 +000043/* Here is how the buffer works internally:
44 *
Behdad Esfahbod910a33f2010-05-14 22:13:38 -040045 * There are two info pointers: info and out_info. They always have
46 * the same allocated size, but different lengths.
Behdad Esfahboda8abb8b2007-10-11 00:07:58 +000047 *
Behdad Esfahbod9d5e26d2010-05-14 22:03:11 -040048 * As an optimization, both info and out_info may point to the
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -040049 * same piece of memory, which is owned by info. This remains the
Behdad Esfahbodcc1a8a92011-01-06 14:58:52 -050050 * case as long as out_len doesn't exceed i at any time.
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040051 * In that case, swap_buffers() is no-op and the glyph operations operate
Behdad Esfahbod910a33f2010-05-14 22:13:38 -040052 * mostly in-place.
Behdad Esfahboda8abb8b2007-10-11 00:07:58 +000053 *
Behdad Esfahbod9d5e26d2010-05-14 22:03:11 -040054 * As soon as out_info gets longer than info, out_info is moved over
Behdad Esfahbod910a33f2010-05-14 22:13:38 -040055 * to an alternate buffer (which we reuse the pos buffer for!), and its
56 * current contents (out_len entries) are copied to the new place.
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040057 * This should all remain transparent to the user. swap_buffers() then
Behdad Esfahbod910a33f2010-05-14 22:13:38 -040058 * switches info and out_info.
Behdad Esfahboda8abb8b2007-10-11 00:07:58 +000059 */
60
Behdad Esfahbodc968fc22009-05-25 04:04:24 -040061
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040062
63/* Internal API */
64
65bool
66hb_buffer_t::enlarge (unsigned int size)
Behdad Esfahbod3567b872010-05-14 23:28:44 -040067{
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040068 if (unlikely (in_error))
Behdad Esfahbod0594a242012-06-05 20:35:40 -040069 return false;
Behdad Esfahbod3567b872010-05-14 23:28:44 -040070
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040071 unsigned int new_allocated = allocated;
Behdad Esfahbode0db4b82011-04-28 12:56:49 -040072 hb_glyph_position_t *new_pos = NULL;
73 hb_glyph_info_t *new_info = NULL;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040074 bool separate_out = out_info != info;
Behdad Esfahbod3567b872010-05-14 23:28:44 -040075
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040076 if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
Behdad Esfahbode0db4b82011-04-28 12:56:49 -040077 goto done;
Behdad Esfahbod3567b872010-05-14 23:28:44 -040078
79 while (size > new_allocated)
Behdad Esfahbod65e00632011-04-27 09:33:58 -040080 new_allocated += (new_allocated >> 1) + 32;
Behdad Esfahbod3567b872010-05-14 23:28:44 -040081
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040082 ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
83 if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
Behdad Esfahbode0db4b82011-04-28 12:56:49 -040084 goto done;
Behdad Esfahbodb5dd44e2011-02-28 10:13:52 -080085
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040086 new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
87 new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
Behdad Esfahbod3567b872010-05-14 23:28:44 -040088
Behdad Esfahbode0db4b82011-04-28 12:56:49 -040089done:
Behdad Esfahbod3567b872010-05-14 23:28:44 -040090 if (unlikely (!new_pos || !new_info))
Behdad Esfahbod0594a242012-06-05 20:35:40 -040091 in_error = true;
Behdad Esfahbod3567b872010-05-14 23:28:44 -040092
93 if (likely (new_pos))
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040094 pos = new_pos;
Behdad Esfahbod3567b872010-05-14 23:28:44 -040095
96 if (likely (new_info))
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040097 info = new_info;
Behdad Esfahbod3567b872010-05-14 23:28:44 -040098
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -040099 out_info = separate_out ? (hb_glyph_info_t *) pos : info;
100 if (likely (!in_error))
101 allocated = new_allocated;
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400102
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400103 return likely (!in_error);
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400104}
105
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400106bool
107hb_buffer_t::make_room_for (unsigned int num_in,
108 unsigned int num_out)
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400109{
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400110 if (unlikely (!ensure (out_len + num_out))) return false;
Behdad Esfahbod6b347132007-10-11 08:30:50 +0000111
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400112 if (out_info == info &&
113 out_len + num_out > idx + num_in)
Behdad Esfahbode35bbd52009-05-30 12:02:46 -0400114 {
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400115 assert (have_output);
Behdad Esfahbode35bbd52009-05-30 12:02:46 -0400116
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400117 out_info = (hb_glyph_info_t *) pos;
118 memcpy (out_info, info, out_len * sizeof (out_info[0]));
Behdad Esfahbode35bbd52009-05-30 12:02:46 -0400119 }
Behdad Esfahboda6a79df2010-05-14 23:20:16 -0400120
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400121 return true;
Behdad Esfahboda8abb8b2007-10-11 00:07:58 +0000122}
123
Behdad Esfahbode62df432011-08-03 17:38:54 -0400124void *
125hb_buffer_t::get_scratch_buffer (unsigned int *size)
126{
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400127 have_output = false;
128 have_positions = false;
Behdad Esfahbode62df432011-08-03 17:38:54 -0400129 out_len = 0;
130 *size = allocated * sizeof (pos[0]);
131 return pos;
132}
133
Behdad Esfahbod3567b872010-05-14 23:28:44 -0400134
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400135/* HarfBuzz-Internal API */
136
137void
138hb_buffer_t::reset (void)
139{
140 if (unlikely (hb_object_is_inert (this)))
141 return;
142
143 hb_unicode_funcs_destroy (unicode);
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -0400144 unicode = _HB_BUFFER_UNICODE_FUNCS_DEFAULT;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400145
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -0400146 hb_segment_properties_t default_props = _HB_BUFFER_PROPS_DEFAULT;
147 props = default_props;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400148
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400149 in_error = false;
150 have_output = false;
151 have_positions = false;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400152
153 idx = 0;
154 len = 0;
155 out_len = 0;
156
157 serial = 0;
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400158 memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
159 memset (allocated_var_owner, 0, sizeof allocated_var_owner);
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400160
161 out_info = info;
162}
163
164void
165hb_buffer_t::add (hb_codepoint_t codepoint,
166 hb_mask_t mask,
167 unsigned int cluster)
168{
169 hb_glyph_info_t *glyph;
170
171 if (unlikely (!ensure (len + 1))) return;
172
173 glyph = &info[len];
174
175 memset (glyph, 0, sizeof (*glyph));
176 glyph->codepoint = codepoint;
177 glyph->mask = mask;
178 glyph->cluster = cluster;
179
180 len++;
181}
182
183void
184hb_buffer_t::clear_output (void)
185{
186 if (unlikely (hb_object_is_inert (this)))
187 return;
188
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400189 have_output = true;
190 have_positions = false;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400191
192 out_len = 0;
193 out_info = info;
194}
195
196void
197hb_buffer_t::clear_positions (void)
198{
199 if (unlikely (hb_object_is_inert (this)))
200 return;
201
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400202 have_output = false;
203 have_positions = true;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400204
205 memset (pos, 0, sizeof (pos[0]) * len);
206}
207
208void
209hb_buffer_t::swap_buffers (void)
210{
211 if (unlikely (in_error)) return;
212
213 assert (have_output);
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400214 have_output = false;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400215
216 if (out_info != info)
217 {
218 hb_glyph_info_t *tmp_string;
219 tmp_string = info;
220 info = out_info;
221 out_info = tmp_string;
222 pos = (hb_glyph_position_t *) out_info;
223 }
224
225 unsigned int tmp;
226 tmp = len;
227 len = out_len;
228 out_len = tmp;
229
230 idx = 0;
231}
232
233void
234hb_buffer_t::replace_glyphs_be16 (unsigned int num_in,
235 unsigned int num_out,
Behdad Esfahbod2a3d9112012-06-07 17:31:46 -0400236 const char *glyph_data_be)
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400237{
238 if (!make_room_for (num_in, num_out)) return;
239
240 hb_glyph_info_t orig_info = info[idx];
241 for (unsigned int i = 1; i < num_in; i++)
242 {
243 hb_glyph_info_t *inf = &info[idx + i];
244 orig_info.cluster = MIN (orig_info.cluster, inf->cluster);
245 }
246
247 hb_glyph_info_t *pinfo = &out_info[out_len];
Behdad Esfahbod2a3d9112012-06-07 17:31:46 -0400248 const unsigned char *data = (const unsigned char *) glyph_data_be;
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400249 for (unsigned int i = 0; i < num_out; i++)
250 {
251 *pinfo = orig_info;
Behdad Esfahbod2a3d9112012-06-07 17:31:46 -0400252 pinfo->codepoint = (data[2*i] << 8) | data[2*i+1];
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400253 pinfo++;
254 }
255
256 idx += num_in;
257 out_len += num_out;
258}
259
260void
Behdad Esfahbod9ebe8c02011-08-26 09:29:42 +0200261hb_buffer_t::replace_glyphs (unsigned int num_in,
262 unsigned int num_out,
Behdad Esfahbod8e3715f2012-04-23 22:18:54 -0400263 const uint32_t *glyph_data)
Behdad Esfahbod9ebe8c02011-08-26 09:29:42 +0200264{
265 if (!make_room_for (num_in, num_out)) return;
266
267 hb_glyph_info_t orig_info = info[idx];
268 for (unsigned int i = 1; i < num_in; i++)
269 {
270 hb_glyph_info_t *inf = &info[idx + i];
271 orig_info.cluster = MIN (orig_info.cluster, inf->cluster);
272 }
273
274 hb_glyph_info_t *pinfo = &out_info[out_len];
275 for (unsigned int i = 0; i < num_out; i++)
276 {
277 *pinfo = orig_info;
278 pinfo->codepoint = glyph_data[i];
279 pinfo++;
280 }
281
282 idx += num_in;
283 out_len += num_out;
284}
285
286void
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400287hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
288{
289 if (!make_room_for (0, 1)) return;
290
291 out_info[out_len] = info[idx];
292 out_info[out_len].codepoint = glyph_index;
293
294 out_len++;
295}
296
297void
298hb_buffer_t::copy_glyph (void)
299{
300 if (!make_room_for (0, 1)) return;
301
302 out_info[out_len] = info[idx];
303
304 out_len++;
305}
306
307void
308hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
309{
Behdad Esfahbodc521e792012-01-18 21:51:05 -0500310 if (!make_room_for (1, 1)) return;
311
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400312 out_info[out_len] = info[idx];
313 out_info[out_len].codepoint = glyph_index;
314
315 idx++;
316 out_len++;
317}
318
319void
320hb_buffer_t::next_glyph (void)
321{
322 if (have_output)
323 {
324 if (out_info != info)
325 {
326 if (unlikely (!ensure (out_len + 1))) return;
327 out_info[out_len] = info[idx];
328 }
329 else if (out_len != idx)
330 out_info[out_len] = info[idx];
331
332 out_len++;
333 }
334
335 idx++;
336}
337
338void
339hb_buffer_t::set_masks (hb_mask_t value,
340 hb_mask_t mask,
341 unsigned int cluster_start,
342 unsigned int cluster_end)
343{
344 hb_mask_t not_mask = ~mask;
345 value &= mask;
346
347 if (!mask)
348 return;
349
350 if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
351 unsigned int count = len;
352 for (unsigned int i = 0; i < count; i++)
353 info[i].mask = (info[i].mask & not_mask) | value;
354 return;
355 }
356
357 unsigned int count = len;
358 for (unsigned int i = 0; i < count; i++)
359 if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
360 info[i].mask = (info[i].mask & not_mask) | value;
361}
362
363void
364hb_buffer_t::reverse_range (unsigned int start,
365 unsigned int end)
366{
367 unsigned int i, j;
368
369 if (start == end - 1)
370 return;
371
372 for (i = start, j = end - 1; i < j; i++, j--) {
373 hb_glyph_info_t t;
374
375 t = info[i];
376 info[i] = info[j];
377 info[j] = t;
378 }
379
380 if (pos) {
381 for (i = start, j = end - 1; i < j; i++, j--) {
382 hb_glyph_position_t t;
383
384 t = pos[i];
385 pos[i] = pos[j];
386 pos[j] = t;
387 }
388 }
389}
390
391void
392hb_buffer_t::reverse (void)
393{
394 if (unlikely (!len))
395 return;
396
397 reverse_range (0, len);
398}
399
400void
401hb_buffer_t::reverse_clusters (void)
402{
403 unsigned int i, start, count, last_cluster;
404
405 if (unlikely (!len))
406 return;
407
408 reverse ();
409
410 count = len;
411 start = 0;
412 last_cluster = info[0].cluster;
413 for (i = 1; i < count; i++) {
414 if (last_cluster != info[i].cluster) {
415 reverse_range (start, i);
416 start = i;
417 last_cluster = info[i].cluster;
418 }
419 }
420 reverse_range (start, i);
421}
422
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400423void
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400424hb_buffer_t::merge_clusters (unsigned int start,
425 unsigned int end)
426{
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400427 if (unlikely (start >= end))
428 return;
429
430 unsigned int cluster = info[start].cluster;
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400431
432 for (unsigned int i = start + 1; i < end; i++)
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400433 cluster = MIN (cluster, info[i].cluster);
434
435 /* Extend end */
436 while (end < len && info[end - 1].cluster == info[end].cluster)
437 end++;
438
Behdad Esfahbodcd589142012-06-08 20:27:53 -0400439 /* Extend start */
440 while (idx < start && info[start - 1].cluster == info[start].cluster)
441 start--;
442
443 /* If we hit the start of buffer, continue in out-buffer. */
444 if (idx == start)
445 for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
446 out_info[i - 1].cluster = cluster;
447
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400448 for (unsigned int i = start; i < end; i++)
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400449 info[i].cluster = cluster;
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400450}
451void
452hb_buffer_t::merge_out_clusters (unsigned int start,
453 unsigned int end)
454{
Behdad Esfahbod72c0a182012-06-08 20:30:03 -0400455 if (unlikely (start >= end))
456 return;
457
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400458 unsigned int cluster = out_info[start].cluster;
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400459
460 for (unsigned int i = start + 1; i < end; i++)
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400461 cluster = MIN (cluster, out_info[i].cluster);
Behdad Esfahbod72c0a182012-06-08 20:30:03 -0400462
463 /* Extend start */
464 while (start && out_info[start - 1].cluster == out_info[start].cluster)
465 start--;
466
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400467 for (unsigned int i = start; i < end; i++)
Behdad Esfahbodcafa6f32012-06-08 20:17:10 -0400468 out_info[i].cluster = cluster;
Behdad Esfahbodd4cc4472012-04-07 21:52:28 -0400469}
470
471void
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400472hb_buffer_t::guess_properties (void)
473{
474 /* If script is set to INVALID, guess from buffer contents */
475 if (props.script == HB_SCRIPT_INVALID) {
476 for (unsigned int i = 0; i < len; i++) {
477 hb_script_t script = hb_unicode_script (unicode, info[i].codepoint);
478 if (likely (script != HB_SCRIPT_COMMON &&
479 script != HB_SCRIPT_INHERITED &&
480 script != HB_SCRIPT_UNKNOWN)) {
481 props.script = script;
482 break;
483 }
484 }
485 }
486
487 /* If direction is set to INVALID, guess from script */
488 if (props.direction == HB_DIRECTION_INVALID) {
489 props.direction = hb_script_get_horizontal_direction (props.script);
490 }
491
492 /* If language is not set, use default language from locale */
493 if (props.language == HB_LANGUAGE_INVALID) {
494 /* TODO get_default_for_script? using $LANGUAGE */
495 props.language = hb_language_get_default ();
496 }
497}
498
499
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -0400500static inline void
501dump_var_allocation (const hb_buffer_t *buffer)
502{
503 char buf[80];
504 for (unsigned int i = 0; i < 8; i++)
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400505 buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -0400506 buf[8] = '\0';
507 DEBUG_MSG (BUFFER, buffer,
508 "Current var allocation: %s",
509 buf);
510}
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400511
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400512void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
513{
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400514 assert (byte_i < 8 && byte_i + count <= 8);
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -0400515
516 if (DEBUG (BUFFER))
517 dump_var_allocation (this);
518 DEBUG_MSG (BUFFER, this,
519 "Allocating var bytes %d..%d for %s",
520 byte_i, byte_i + count - 1, owner);
521
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400522 for (unsigned int i = byte_i; i < byte_i + count; i++) {
523 assert (!allocated_var_bytes[i]);
524 allocated_var_bytes[i]++;
525 allocated_var_owner[i] = owner;
526 }
527}
528
529void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
530{
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400531 if (DEBUG (BUFFER))
532 dump_var_allocation (this);
533
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -0400534 DEBUG_MSG (BUFFER, this,
535 "Deallocating var bytes %d..%d for %s",
536 byte_i, byte_i + count - 1, owner);
537
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400538 assert (byte_i < 8 && byte_i + count <= 8);
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400539 for (unsigned int i = byte_i; i < byte_i + count; i++) {
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400540 assert (allocated_var_bytes[i]);
541 assert (0 == strcmp (allocated_var_owner[i], owner));
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400542 allocated_var_bytes[i]--;
543 }
544}
545
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -0400546void hb_buffer_t::deallocate_var_all (void)
547{
548 memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
549 memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
550}
Behdad Esfahbodf4a579b2011-07-25 16:20:16 -0400551
Behdad Esfahbod6b347132007-10-11 08:30:50 +0000552/* Public API */
553
Behdad Esfahbodb857b492009-05-20 05:35:14 -0400554hb_buffer_t *
Behdad Esfahbode6c09cd2011-08-17 19:07:59 +0200555hb_buffer_create ()
Behdad Esfahbod9f8da382006-03-31 12:28:09 +0000556{
Behdad Esfahbodb857b492009-05-20 05:35:14 -0400557 hb_buffer_t *buffer;
558
Behdad Esfahbod47e71d92011-04-27 16:38:03 -0400559 if (!(buffer = hb_object_create<hb_buffer_t> ()))
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -0400560 return hb_buffer_get_empty ();
Behdad Esfahbod9f8da382006-03-31 12:28:09 +0000561
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400562 buffer->reset ();
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500563
Behdad Esfahbodb857b492009-05-20 05:35:14 -0400564 return buffer;
Behdad Esfahbod9f8da382006-03-31 12:28:09 +0000565}
566
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400567hb_buffer_t *
Behdad Esfahbod80a68332011-05-11 18:14:44 -0400568hb_buffer_get_empty (void)
569{
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -0400570 static const hb_buffer_t _hb_buffer_nil = {
571 HB_OBJECT_HEADER_STATIC,
572
573 _HB_BUFFER_UNICODE_FUNCS_DEFAULT,
574 _HB_BUFFER_PROPS_DEFAULT,
575
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400576 true, /* in_error */
577 true, /* have_output */
578 true /* have_positions */
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -0400579 };
580
581 return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
Behdad Esfahbod80a68332011-05-11 18:14:44 -0400582}
583
584hb_buffer_t *
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400585hb_buffer_reference (hb_buffer_t *buffer)
Behdad Esfahbod7a268642007-10-11 07:21:31 +0000586{
Behdad Esfahbod47e71d92011-04-27 16:38:03 -0400587 return hb_object_reference (buffer);
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400588}
589
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400590void
591hb_buffer_destroy (hb_buffer_t *buffer)
592{
Behdad Esfahbod47e71d92011-04-27 16:38:03 -0400593 if (!hb_object_destroy (buffer)) return;
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400594
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500595 hb_unicode_funcs_destroy (buffer->unicode);
596
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -0400597 free (buffer->info);
Behdad Esfahbod1b621822010-05-14 22:05:53 -0400598 free (buffer->pos);
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400599
Behdad Esfahbodb857b492009-05-20 05:35:14 -0400600 free (buffer);
Behdad Esfahbod7a268642007-10-11 07:21:31 +0000601}
602
Behdad Esfahbod5fa849b2011-04-27 21:46:01 -0400603hb_bool_t
604hb_buffer_set_user_data (hb_buffer_t *buffer,
605 hb_user_data_key_t *key,
606 void * data,
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200607 hb_destroy_func_t destroy,
608 hb_bool_t replace)
Behdad Esfahbod5fa849b2011-04-27 21:46:01 -0400609{
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200610 return hb_object_set_user_data (buffer, key, data, destroy, replace);
Behdad Esfahbod5fa849b2011-04-27 21:46:01 -0400611}
612
613void *
614hb_buffer_get_user_data (hb_buffer_t *buffer,
615 hb_user_data_key_t *key)
616{
617 return hb_object_get_user_data (buffer, key);
618}
619
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500620
621void
622hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
623 hb_unicode_funcs_t *unicode)
624{
Behdad Esfahbode0db4b82011-04-28 12:56:49 -0400625 if (unlikely (hb_object_is_inert (buffer)))
626 return;
627
Behdad Esfahbod0465e692009-12-20 16:25:18 +0100628 if (!unicode)
Behdad Esfahbodf06ab8a2012-06-05 12:31:51 -0400629 unicode = _HB_BUFFER_UNICODE_FUNCS_DEFAULT;
Behdad Esfahbod0465e692009-12-20 16:25:18 +0100630
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500631 hb_unicode_funcs_reference (unicode);
632 hb_unicode_funcs_destroy (buffer->unicode);
633 buffer->unicode = unicode;
634}
635
636hb_unicode_funcs_t *
637hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
638{
639 return buffer->unicode;
640}
641
642void
643hb_buffer_set_direction (hb_buffer_t *buffer,
644 hb_direction_t direction)
645
646{
Behdad Esfahbode0db4b82011-04-28 12:56:49 -0400647 if (unlikely (hb_object_is_inert (buffer)))
648 return;
649
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400650 buffer->props.direction = direction;
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500651}
652
653hb_direction_t
654hb_buffer_get_direction (hb_buffer_t *buffer)
655{
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400656 return buffer->props.direction;
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500657}
658
Behdad Esfahbodae070b72009-11-04 20:29:54 -0500659void
660hb_buffer_set_script (hb_buffer_t *buffer,
661 hb_script_t script)
662{
Behdad Esfahbode0db4b82011-04-28 12:56:49 -0400663 if (unlikely (hb_object_is_inert (buffer)))
664 return;
665
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400666 buffer->props.script = script;
Behdad Esfahbodae070b72009-11-04 20:29:54 -0500667}
668
669hb_script_t
670hb_buffer_get_script (hb_buffer_t *buffer)
671{
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400672 return buffer->props.script;
Behdad Esfahbodae070b72009-11-04 20:29:54 -0500673}
674
675void
676hb_buffer_set_language (hb_buffer_t *buffer,
677 hb_language_t language)
678{
Behdad Esfahbode0db4b82011-04-28 12:56:49 -0400679 if (unlikely (hb_object_is_inert (buffer)))
680 return;
681
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400682 buffer->props.language = language;
Behdad Esfahbodae070b72009-11-04 20:29:54 -0500683}
684
685hb_language_t
686hb_buffer_get_language (hb_buffer_t *buffer)
687{
Behdad Esfahbod4e4ef242010-07-23 17:22:11 -0400688 return buffer->props.language;
Behdad Esfahbodae070b72009-11-04 20:29:54 -0500689}
690
Behdad Esfahbod5ebabec2009-11-03 15:15:07 -0500691
Behdad Esfahbod7a268642007-10-11 07:21:31 +0000692void
Behdad Esfahbodc910bec2011-04-13 15:49:06 -0400693hb_buffer_reset (hb_buffer_t *buffer)
694{
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400695 buffer->reset ();
Behdad Esfahbod7a268642007-10-11 07:21:31 +0000696}
697
Behdad Esfahboda6a79df2010-05-14 23:20:16 -0400698hb_bool_t
Ryan Lortie02a534b2011-04-15 18:34:45 -0400699hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
Behdad Esfahbodf9cd1012009-07-28 15:43:34 -0400700{
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400701 return buffer->ensure (size);
Behdad Esfahbodf9cd1012009-07-28 15:43:34 -0400702}
703
Behdad Esfahbodaab0de52011-04-19 00:32:19 -0400704hb_bool_t
705hb_buffer_allocation_successful (hb_buffer_t *buffer)
706{
707 return !buffer->in_error;
708}
709
Behdad Esfahbodf9cd1012009-07-28 15:43:34 -0400710void
Behdad Esfahbodf85faee2011-04-19 00:38:01 -0400711hb_buffer_add (hb_buffer_t *buffer,
712 hb_codepoint_t codepoint,
713 hb_mask_t mask,
714 unsigned int cluster)
Behdad Esfahbod6b347132007-10-11 08:30:50 +0000715{
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400716 buffer->add (codepoint, mask, cluster);
Behdad Esfahbod6b347132007-10-11 08:30:50 +0000717}
718
Behdad Esfahbodc910bec2011-04-13 15:49:06 -0400719hb_bool_t
720hb_buffer_set_length (hb_buffer_t *buffer,
721 unsigned int length)
722{
Behdad Esfahbode1ac38f2012-06-05 20:31:49 -0400723 if (unlikely (hb_object_is_inert (buffer)))
724 return length == 0;
725
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400726 if (!buffer->ensure (length))
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400727 return false;
Behdad Esfahbodc910bec2011-04-13 15:49:06 -0400728
729 /* Wipe the new space */
730 if (length > buffer->len) {
731 memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
732 if (buffer->have_positions)
733 memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
734 }
735
736 buffer->len = length;
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400737 return true;
Behdad Esfahbodc910bec2011-04-13 15:49:06 -0400738}
739
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400740unsigned int
Behdad Esfahbod3d145282009-11-06 15:13:17 -0500741hb_buffer_get_length (hb_buffer_t *buffer)
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400742{
Behdad Esfahbod69603502010-05-14 22:07:46 -0400743 return buffer->len;
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400744}
745
746/* Return value valid as long as buffer not modified */
747hb_glyph_info_t *
Ryan Lortie70566be2011-04-15 18:32:36 -0400748hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
749 unsigned int *length)
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400750{
Ryan Lortie70566be2011-04-15 18:32:36 -0400751 if (length)
752 *length = buffer->len;
753
Behdad Esfahbod7e7007a2010-05-14 22:02:37 -0400754 return (hb_glyph_info_t *) buffer->info;
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400755}
756
757/* Return value valid as long as buffer not modified */
758hb_glyph_position_t *
Ryan Lortie70566be2011-04-15 18:32:36 -0400759hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
760 unsigned int *length)
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400761{
Behdad Esfahbod314905d2009-12-20 14:50:42 +0100762 if (!buffer->have_positions)
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400763 buffer->clear_positions ();
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400764
Ryan Lortie70566be2011-04-15 18:32:36 -0400765 if (length)
766 *length = buffer->len;
767
Behdad Esfahbod1b621822010-05-14 22:05:53 -0400768 return (hb_glyph_position_t *) buffer->pos;
Behdad Esfahbod11fbb542009-08-01 22:19:06 -0400769}
Behdad Esfahbodfbaf8ff2009-08-10 20:59:25 -0400770
Behdad Esfahbodff44f882009-11-06 19:48:16 -0500771void
772hb_buffer_reverse (hb_buffer_t *buffer)
773{
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400774 buffer->reverse ();
Behdad Esfahbodff44f882009-11-06 19:48:16 -0500775}
776
777void
778hb_buffer_reverse_clusters (hb_buffer_t *buffer)
779{
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -0400780 buffer->reverse_clusters ();
Behdad Esfahbodff44f882009-11-06 19:48:16 -0500781}
782
Behdad Esfahbod02aeca92011-08-04 22:31:05 -0400783void
784hb_buffer_guess_properties (hb_buffer_t *buffer)
785{
786 buffer->guess_properties ();
787}
788
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400789#define ADD_UTF(T) \
790 HB_STMT_START { \
Behdad Esfahbod144cd492011-08-07 00:51:50 -0400791 if (text_length == -1) { \
792 text_length = 0; \
793 const T *p = (const T *) text; \
794 while (*p) { \
795 text_length++; \
796 p++; \
797 } \
798 } \
799 if (item_length == -1) \
800 item_length = text_length - item_offset; \
Behdad Esfahbod4e9ff1d2011-08-15 16:21:22 +0200801 buffer->ensure (buffer->len + item_length * sizeof (T) / 4); \
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400802 const T *next = (const T *) text + item_offset; \
803 const T *end = next + item_length; \
804 while (next < end) { \
805 hb_codepoint_t u; \
806 const T *old_next = next; \
807 next = UTF_NEXT (next, end, u); \
Behdad Esfahbodf85faee2011-04-19 00:38:01 -0400808 hb_buffer_add (buffer, u, 1, old_next - (const T *) text); \
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400809 } \
810 } HB_STMT_END
811
812
813#define UTF8_COMPUTE(Char, Mask, Len) \
814 if (Char < 128) { Len = 1; Mask = 0x7f; } \
815 else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
816 else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
817 else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
818 else Len = 0;
819
820static inline const uint8_t *
821hb_utf8_next (const uint8_t *text,
822 const uint8_t *end,
823 hb_codepoint_t *unicode)
824{
825 uint8_t c = *text;
826 unsigned int mask, len;
827
Behdad Esfahbod243673d2011-04-28 19:37:51 -0400828 /* TODO check for overlong sequences? */
Behdad Esfahbod2163afb2010-05-27 14:04:15 -0400829
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400830 UTF8_COMPUTE (c, mask, len);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400831 if (unlikely (!len || (unsigned int) (end - text) < len)) {
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400832 *unicode = -1;
833 return text + 1;
834 } else {
835 hb_codepoint_t result;
836 unsigned int i;
837 result = c & mask;
838 for (i = 1; i < len; i++)
839 {
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400840 if (unlikely ((text[i] & 0xc0) != 0x80))
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400841 {
842 *unicode = -1;
843 return text + 1;
844 }
845 result <<= 6;
846 result |= (text[i] & 0x3f);
847 }
848 *unicode = result;
849 return text + len;
850 }
851}
852
853void
854hb_buffer_add_utf8 (hb_buffer_t *buffer,
855 const char *text,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +0200856 int text_length,
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400857 unsigned int item_offset,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +0200858 int item_length)
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400859{
860#define UTF_NEXT(S, E, U) hb_utf8_next (S, E, &(U))
861 ADD_UTF (uint8_t);
862#undef UTF_NEXT
863}
864
865static inline const uint16_t *
866hb_utf16_next (const uint16_t *text,
867 const uint16_t *end,
868 hb_codepoint_t *unicode)
869{
870 uint16_t c = *text++;
871
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400872 if (unlikely (c >= 0xd800 && c < 0xdc00)) {
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400873 /* high surrogate */
874 uint16_t l;
Behdad Esfahbod69ea23c2011-04-13 15:02:40 -0400875 if (text < end && ((l = *text), likely (l >= 0xdc00 && l < 0xe000))) {
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400876 /* low surrogate */
877 *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000);
878 text++;
879 } else
880 *unicode = -1;
881 } else
882 *unicode = c;
883
884 return text;
885}
886
887void
888hb_buffer_add_utf16 (hb_buffer_t *buffer,
889 const uint16_t *text,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +0200890 int text_length,
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400891 unsigned int item_offset,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +0200892 int item_length)
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400893{
894#define UTF_NEXT(S, E, U) hb_utf16_next (S, E, &(U))
895 ADD_UTF (uint16_t);
896#undef UTF_NEXT
897}
898
899void
900hb_buffer_add_utf32 (hb_buffer_t *buffer,
901 const uint32_t *text,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +0200902 int text_length,
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400903 unsigned int item_offset,
Behdad Esfahbod944b2ba2011-08-09 00:23:58 +0200904 int item_length)
Behdad Esfahbod299f0892009-08-10 22:47:57 -0400905{
906#define UTF_NEXT(S, E, U) ((U) = *(S), (S)+1)
907 ADD_UTF (uint32_t);
908#undef UTF_NEXT
909}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400910
911