2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg
3 * Copyright (C) 2004,2007 Red Hat, Inc.
5 * This is part of HarfBuzz, an OpenType Layout engine library.
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
28 #include "hb-buffer-private.h"
32 /* Here is how the buffer works internally:
34 * There are two string pointers: in_string and out_string. They
35 * always have same allocated size, but different length and positions.
37 * As an optimization, both in_string and out_string may point to the
38 * same piece of memory, which is owned by in_string. This remains the
41 * - copy_glyph() is called
42 * - replace_glyph() is called with inplace=TRUE
43 * - add_output_glyph() and add_output_glyphs() are not called
45 * In that case swap(), and copy_glyph(), and replace_glyph() are all
48 * As soon an add_output_glyph[s]() or replace_glyph() with inplace=FALSE is
49 * called, out_string is moved over to an alternate buffer (alt_string), and
50 * its current contents (out_length entries) are copied to the alt buffer.
51 * This should all remain transparent to the user. swap() then switches
52 * in_string and alt_string. alt_string is not allocated until its needed,
53 * but after that it's grown with in_string unconditionally.
55 * The buffer->separate_out boolean keeps status of whether out_string points
56 * to in_string (FALSE) or alt_string (TRUE).
59 /* XXX err handling */
64 hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
66 unsigned int new_allocated = buffer->allocated;
68 if (size > new_allocated)
70 while (size > new_allocated)
71 new_allocated += (new_allocated >> 1) + 8;
73 if (buffer->positions)
74 buffer->positions = realloc (buffer->positions, new_allocated * sizeof (buffer->positions[0]));
76 buffer->in_string = realloc (buffer->in_string, new_allocated * sizeof (buffer->in_string[0]));
78 if (buffer->separate_out)
80 buffer->alt_string = realloc (buffer->alt_string, new_allocated * sizeof (buffer->alt_string[0]));
81 buffer->out_string = buffer->alt_string;
85 buffer->out_string = buffer->in_string;
87 if (buffer->alt_string)
89 free (buffer->alt_string);
90 buffer->alt_string = NULL;
94 buffer->allocated = new_allocated;
99 hb_buffer_duplicate_out_buffer (hb_buffer_t *buffer)
101 if (!buffer->alt_string)
102 buffer->alt_string = malloc (buffer->allocated * sizeof (buffer->alt_string[0]));
104 buffer->out_string = buffer->alt_string;
105 memcpy (buffer->out_string, buffer->in_string, buffer->out_length * sizeof (buffer->out_string[0]));
106 buffer->separate_out = TRUE;
110 hb_buffer_ensure_separate (hb_buffer_t *buffer, unsigned int size)
112 hb_buffer_ensure (buffer, size);
113 if ( !buffer->separate_out )
114 hb_buffer_duplicate_out_buffer (buffer);
124 buffer = malloc (sizeof (hb_buffer_t));
125 if (HB_UNLIKELY (!buffer))
128 buffer->allocated = 0;
129 buffer->in_string = NULL;
130 buffer->alt_string = NULL;
131 buffer->positions = NULL;
133 hb_buffer_clear (buffer);
139 hb_buffer_free (hb_buffer_t *buffer)
141 free (buffer->in_string);
142 free (buffer->alt_string);
143 free (buffer->positions);
148 hb_buffer_clear (hb_buffer_t *buffer)
150 buffer->in_length = 0;
151 buffer->out_length = 0;
154 buffer->out_string = buffer->in_string;
155 buffer->separate_out = FALSE;
156 buffer->max_lig_id = 0;
160 hb_buffer_add_glyph (hb_buffer_t *buffer,
161 hb_codepoint_t glyph_index,
162 unsigned int properties,
163 unsigned int cluster)
165 hb_glyph_info_t *glyph;
167 hb_buffer_ensure (buffer, buffer->in_length + 1);
169 glyph = &buffer->in_string[buffer->in_length];
170 glyph->gindex = glyph_index;
171 glyph->properties = properties;
172 glyph->cluster = cluster;
173 glyph->component = 0;
175 glyph->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
180 /* HarfBuzz-Internal API */
183 _hb_buffer_clear_output (hb_buffer_t *buffer)
185 buffer->out_length = 0;
187 buffer->out_string = buffer->in_string;
188 buffer->separate_out = FALSE;
192 _hb_buffer_clear_positions (hb_buffer_t *buffer)
194 _hb_buffer_clear_output (buffer);
196 if (HB_UNLIKELY (!buffer->positions))
198 buffer->positions = calloc (buffer->allocated, sizeof (buffer->positions[0]));
202 memset (buffer->positions, 0, sizeof (buffer->positions[0]) * buffer->in_length);
206 _hb_buffer_swap (hb_buffer_t *buffer)
210 if (buffer->separate_out)
212 hb_glyph_info_t *tmp_string;
213 tmp_string = buffer->in_string;
214 buffer->in_string = buffer->out_string;
215 buffer->out_string = tmp_string;
216 buffer->alt_string = buffer->out_string;
219 tmp = buffer->in_length;
220 buffer->in_length = buffer->out_length;
221 buffer->out_length = tmp;
223 tmp = buffer->in_pos;
224 buffer->in_pos = buffer->out_pos;
225 buffer->out_pos = tmp;
228 /* The following function copies `num_out' elements from `glyph_data'
229 to `buffer->out_string', advancing the in array pointer in the structure
230 by `num_in' elements, and the out array pointer by `num_out' elements.
231 Finally, it sets the `length' field of `out' equal to
232 `pos' of the `out' structure.
234 If `component' is 0xFFFF, the component value from buffer->in_pos
235 will copied `num_out' times, otherwise `component' itself will
236 be used to fill the `component' fields.
238 If `ligID' is 0xFFFF, the ligID value from buffer->in_pos
239 will copied `num_out' times, otherwise `ligID' itself will
240 be used to fill the `ligID' fields.
242 The properties for all replacement glyphs are taken
243 from the glyph at position `buffer->in_pos'.
245 The cluster value for the glyph at position buffer->in_pos is used
246 for all replacement glyphs */
248 _hb_buffer_add_output_glyphs (hb_buffer_t *buffer,
250 unsigned int num_out,
251 const uint16_t *glyph_data_be,
252 unsigned short component,
253 unsigned short ligID)
256 unsigned int properties;
257 unsigned int cluster;
259 hb_buffer_ensure_separate (buffer, buffer->out_pos + num_out);
261 properties = buffer->in_string[buffer->in_pos].properties;
262 cluster = buffer->in_string[buffer->in_pos].cluster;
263 if (component == 0xFFFF)
264 component = buffer->in_string[buffer->in_pos].component;
266 ligID = buffer->in_string[buffer->in_pos].ligID;
268 for (i = 0; i < num_out; i++)
270 hb_glyph_info_t *info = &buffer->out_string[buffer->out_pos + i];
272 info->gindex = hb_be_uint16_t (glyph_data_be[i]);
273 info->properties = properties;
274 info->cluster = cluster;
275 info->component = component;
277 info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
280 buffer->in_pos += num_in;
281 buffer->out_pos += num_out;
283 buffer->out_length = buffer->out_pos;
288 _hb_buffer_add_output_glyph (hb_buffer_t *buffer,
289 hb_codepoint_t glyph_index,
290 unsigned short component,
291 unsigned short ligID)
293 hb_glyph_info_t *info;
295 hb_buffer_ensure_separate (buffer, buffer->out_pos + 1);
297 info = &buffer->out_string[buffer->out_pos];
298 *info = buffer->in_string[buffer->in_pos];
300 info->gindex = glyph_index;
301 if (component != 0xFFFF)
302 info->component = component;
305 info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
310 buffer->out_length = buffer->out_pos;
314 _hb_buffer_next_glyph (hb_buffer_t *buffer)
316 if (buffer->separate_out)
318 hb_buffer_ensure (buffer, buffer->out_pos + 1);
320 buffer->out_string[buffer->out_pos] = buffer->in_string[buffer->in_pos];
325 buffer->out_length = buffer->out_pos;
329 _hb_buffer_replace_glyph (hb_buffer_t *buffer,
330 hb_codepoint_t glyph_index)
332 if (!buffer->separate_out)
334 buffer->out_string[buffer->out_pos].gindex = glyph_index;
338 buffer->out_length = buffer->out_pos;
342 return _hb_buffer_add_output_glyph (buffer, glyph_index, 0xFFFF, 0xFFFF);
346 HB_INTERNAL unsigned short
347 _hb_buffer_allocate_lig_id (hb_buffer_t *buffer)
349 return ++buffer->max_lig_id;