[HB] More buffer cleanup
[framework/uifw/harfbuzz.git] / src / hb-buffer.c
1 /*
2  * Copyright (C) 1998-2004  David Turner and Werner Lemberg
3  * Copyright (C) 2004,2007  Red Hat, Inc.
4  *
5  * This is part of HarfBuzz, an OpenType Layout engine library.
6  *
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.
12  *
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
17  * DAMAGE.
18  *
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.
24  *
25  * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
26  */
27
28 #include "hb-buffer-private.h"
29
30 #include <string.h>
31
32 /* Here is how the buffer works internally:
33  *
34  * There are two string pointers: in_string and out_string.  They
35  * always have same allocated size, but different length and positions.
36  *
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
39  * case as long as:
40  *
41  *   - copy_glyph() is called
42  *   - replace_glyph() is called with inplace=TRUE
43  *   - add_output_glyph() and add_output_glyphs() are not called
44  *
45  * In that case swap(), and copy_glyph(), and replace_glyph() are all
46  * mostly no-op.
47  *
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.
54  *
55  * The buffer->separate_out boolean keeps status of whether out_string points
56  * to in_string (FALSE) or alt_string (TRUE).
57  */
58
59 /* XXX err handling */
60
61 /* Internal API */
62
63 static void
64 hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
65 {
66   unsigned int new_allocated = buffer->allocated;
67
68   if (size > new_allocated)
69     {
70       while (size > new_allocated)
71         new_allocated += (new_allocated >> 1) + 8;
72
73       if (buffer->positions)
74         buffer->positions = realloc (buffer->positions, new_allocated * sizeof (buffer->positions[0]));
75
76       buffer->in_string = realloc (buffer->in_string, new_allocated * sizeof (buffer->in_string[0]));
77
78       if (buffer->separate_out)
79         {
80           buffer->alt_string = realloc (buffer->alt_string, new_allocated * sizeof (buffer->alt_string[0]));
81           buffer->out_string = buffer->alt_string;
82         }
83       else
84         {
85           buffer->out_string = buffer->in_string;
86
87           if (buffer->alt_string)
88             {
89               free (buffer->alt_string);
90               buffer->alt_string = NULL;
91             }
92         }
93
94       buffer->allocated = new_allocated;
95     }
96 }
97
98 static void
99 hb_buffer_duplicate_out_buffer (hb_buffer_t *buffer)
100 {
101   if (!buffer->alt_string)
102     buffer->alt_string = malloc (buffer->allocated * sizeof (buffer->alt_string[0]));
103
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;
107 }
108
109 static void
110 hb_buffer_ensure_separate (hb_buffer_t *buffer, unsigned int size)
111 {
112   hb_buffer_ensure (buffer, size);
113   if ( !buffer->separate_out )
114     hb_buffer_duplicate_out_buffer (buffer);
115 }
116
117 /* Public API */
118
119 hb_buffer_t *
120 hb_buffer_new (void)
121 {
122   hb_buffer_t *buffer;
123
124   buffer = malloc (sizeof (hb_buffer_t));
125   if (HB_UNLIKELY (!buffer))
126     return NULL;
127
128   buffer->allocated = 0;
129   buffer->in_string = NULL;
130   buffer->alt_string = NULL;
131   buffer->positions = NULL;
132
133   hb_buffer_clear (buffer);
134
135   return buffer;
136 }
137
138 void
139 hb_buffer_free (hb_buffer_t *buffer)
140 {
141   free (buffer->in_string);
142   free (buffer->alt_string);
143   free (buffer->positions);
144   free (buffer);
145 }
146
147 void
148 hb_buffer_clear (hb_buffer_t *buffer)
149 {
150   buffer->in_length = 0;
151   buffer->out_length = 0;
152   buffer->in_pos = 0;
153   buffer->out_pos = 0;
154   buffer->out_string = buffer->in_string;
155   buffer->separate_out = FALSE;
156   buffer->max_lig_id = 0;
157 }
158
159 void
160 hb_buffer_add_glyph (hb_buffer_t    *buffer,
161                      hb_codepoint_t  glyph_index,
162                      unsigned int    properties,
163                      unsigned int    cluster)
164 {
165   hb_glyph_info_t *glyph;
166
167   hb_buffer_ensure (buffer, buffer->in_length + 1);
168
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;
174   glyph->ligID = 0;
175   glyph->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
176
177   buffer->in_length++;
178 }
179
180 /* HarfBuzz-Internal API */
181
182 HB_INTERNAL void
183 _hb_buffer_clear_output (hb_buffer_t *buffer)
184 {
185   buffer->out_length = 0;
186   buffer->out_pos = 0;
187   buffer->out_string = buffer->in_string;
188   buffer->separate_out = FALSE;
189 }
190
191 HB_INTERNAL void
192 _hb_buffer_clear_positions (hb_buffer_t *buffer)
193 {
194   _hb_buffer_clear_output (buffer);
195
196   if (HB_UNLIKELY (!buffer->positions))
197   {
198     buffer->positions = calloc (buffer->allocated, sizeof (buffer->positions[0]));
199     return;
200   }
201
202   memset (buffer->positions, 0, sizeof (buffer->positions[0]) * buffer->in_length);
203 }
204
205 HB_INTERNAL void
206 _hb_buffer_swap (hb_buffer_t *buffer)
207 {
208   unsigned int tmp;
209
210   if (buffer->separate_out)
211     {
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;
217     }
218
219   tmp = buffer->in_length;
220   buffer->in_length = buffer->out_length;
221   buffer->out_length = tmp;
222
223   tmp = buffer->in_pos;
224   buffer->in_pos = buffer->out_pos;
225   buffer->out_pos = tmp;
226 }
227
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.
233
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.
237
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.
241
242    The properties for all replacement glyphs are taken
243    from the glyph at position `buffer->in_pos'.
244
245    The cluster value for the glyph at position buffer->in_pos is used
246    for all replacement glyphs */
247 HB_INTERNAL void
248 _hb_buffer_add_output_glyphs (hb_buffer_t *buffer,
249                               unsigned int num_in,
250                               unsigned int num_out,
251                               const uint16_t *glyph_data_be,
252                               unsigned short component,
253                               unsigned short ligID)
254 {
255   unsigned int i;
256   unsigned int properties;
257   unsigned int cluster;
258
259   hb_buffer_ensure_separate (buffer, buffer->out_pos + num_out);
260
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;
265   if (ligID == 0xFFFF)
266     ligID = buffer->in_string[buffer->in_pos].ligID;
267
268   for (i = 0; i < num_out; i++)
269   {
270     hb_glyph_info_t *info = &buffer->out_string[buffer->out_pos + i];
271
272     info->gindex = hb_be_uint16_t (glyph_data_be[i]);
273     info->properties = properties;
274     info->cluster = cluster;
275     info->component = component;
276     info->ligID = ligID;
277     info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
278   }
279
280   buffer->in_pos  += num_in;
281   buffer->out_pos += num_out;
282
283   buffer->out_length = buffer->out_pos;
284 }
285
286
287 HB_INTERNAL void
288 _hb_buffer_add_output_glyph (hb_buffer_t *buffer,
289                              hb_codepoint_t glyph_index,
290                              unsigned short component,
291                              unsigned short ligID)
292 {
293   hb_glyph_info_t *info;
294
295   hb_buffer_ensure_separate (buffer, buffer->out_pos + 1);
296
297   info = &buffer->out_string[buffer->out_pos];
298   *info = buffer->in_string[buffer->in_pos];
299
300   info->gindex = glyph_index;
301   if (component != 0xFFFF)
302     info->component = component;
303   if (ligID != 0xFFFF)
304     info->ligID = ligID;
305   info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
306
307   buffer->in_pos++;
308   buffer->out_pos++;
309
310   buffer->out_length = buffer->out_pos;
311 }
312
313 HB_INTERNAL void
314 _hb_buffer_next_glyph (hb_buffer_t *buffer)
315 {
316   if (buffer->separate_out)
317     {
318       hb_buffer_ensure (buffer, buffer->out_pos + 1);
319
320       buffer->out_string[buffer->out_pos] = buffer->in_string[buffer->in_pos];
321     }
322
323   buffer->in_pos++;
324   buffer->out_pos++;
325   buffer->out_length = buffer->out_pos;
326 }
327
328 HB_INTERNAL void
329 _hb_buffer_replace_glyph (hb_buffer_t *buffer,
330                           hb_codepoint_t glyph_index)
331 {
332   if (!buffer->separate_out)
333     {
334       buffer->out_string[buffer->out_pos].gindex = glyph_index;
335
336       buffer->in_pos++;
337       buffer->out_pos++;
338       buffer->out_length = buffer->out_pos;
339     }
340   else
341     {
342       return _hb_buffer_add_output_glyph (buffer, glyph_index, 0xFFFF, 0xFFFF);
343     }
344 }
345
346 HB_INTERNAL unsigned short
347 _hb_buffer_allocate_lig_id (hb_buffer_t *buffer)
348 {
349   return ++buffer->max_lig_id;
350 }