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 "harfbuzz-impl.h"
29 #include "harfbuzz-buffer-private.h"
30 #include "harfbuzz-gsub-private.h"
31 #include "harfbuzz-gpos-private.h"
33 /* Here is how the buffer works internally:
35 * There are two string pointers: in_string and out_string. They
36 * always have same allocated size, but different length and positions.
38 * As an optimization, both in_string and out_string may point to the
39 * same piece of memory, which is owned by in_string. This remains the
42 * - copy_glyph() is called
43 * - replace_glyph() is called with inplace=TRUE
44 * - add_output_glyph() and add_output_glyphs() are not called
46 * In that case swap(), and copy_glyph(), and replace_glyph() are all
49 * As soon an add_output_glyph[s]() or replace_glyph() with inplace=FALSE is
50 * called, out_string is moved over to an alternate buffer (alt_string), and
51 * its current contents (out_length entries) are copied to the alt buffer.
52 * This should all remain transparent to the user. swap() then switches
53 * in_string and alt_string. alt_string is not allocated until its needed,
54 * but after that it's grown with in_string unconditionally.
56 * The buffer->separate_out boolean keeps status of whether out_string points
57 * to in_string (FALSE) or alt_string (TRUE).
63 hb_buffer_ensure( HB_Buffer buffer
,
66 HB_UInt new_allocated
= buffer
->allocated
;
68 if (size
> new_allocated
)
72 while (size
> new_allocated
)
73 new_allocated
+= (new_allocated
>> 1) + 8;
75 if ( buffer
->positions
)
77 if ( REALLOC_ARRAY( buffer
->positions
, new_allocated
, HB_PositionRec
) )
81 if ( REALLOC_ARRAY( buffer
->in_string
, new_allocated
, HB_GlyphItemRec
) )
84 if ( buffer
->separate_out
)
86 if ( REALLOC_ARRAY( buffer
->alt_string
, new_allocated
, HB_GlyphItemRec
) )
89 buffer
->out_string
= buffer
->alt_string
;
93 buffer
->out_string
= buffer
->in_string
;
95 if ( buffer
->alt_string
)
97 if ( REALLOC_ARRAY( buffer
->alt_string
, new_allocated
, HB_GlyphItemRec
) )
102 buffer
->allocated
= new_allocated
;
109 hb_buffer_duplicate_out_buffer( HB_Buffer buffer
)
111 if ( !buffer
->alt_string
)
115 if ( ALLOC_ARRAY( buffer
->alt_string
, buffer
->allocated
, HB_GlyphItemRec
) )
119 buffer
->out_string
= buffer
->alt_string
;
120 memcpy( buffer
->out_string
, buffer
->in_string
, buffer
->out_length
* sizeof (buffer
->out_string
[0]) );
121 buffer
->separate_out
= TRUE
;
129 hb_buffer_new( HB_Buffer
*pbuffer
)
134 if ( ALLOC( buffer
, sizeof( HB_BufferRec
) ) )
137 buffer
->allocated
= 0;
138 buffer
->in_string
= NULL
;
139 buffer
->alt_string
= NULL
;
140 buffer
->positions
= NULL
;
142 hb_buffer_clear( buffer
);
150 hb_buffer_free( HB_Buffer buffer
)
152 FREE( buffer
->in_string
);
153 FREE( buffer
->alt_string
);
154 buffer
->out_string
= NULL
;
155 FREE( buffer
->positions
);
160 hb_buffer_clear( HB_Buffer buffer
)
162 buffer
->in_length
= 0;
163 buffer
->out_length
= 0;
166 buffer
->out_string
= buffer
->in_string
;
167 buffer
->separate_out
= FALSE
;
168 buffer
->max_ligID
= 0;
172 hb_buffer_add_glyph( HB_Buffer buffer
,
180 error
= hb_buffer_ensure( buffer
, buffer
->in_length
+ 1 );
184 glyph
= &buffer
->in_string
[buffer
->in_length
];
185 glyph
->gindex
= glyph_index
;
186 glyph
->properties
= properties
;
187 glyph
->cluster
= cluster
;
188 glyph
->component
= 0;
190 glyph
->gproperties
= HB_GLYPH_PROPERTIES_UNKNOWN
;
197 /* HarfBuzz-Internal API */
200 _hb_buffer_clear_output( HB_Buffer buffer
)
202 buffer
->out_length
= 0;
204 buffer
->out_string
= buffer
->in_string
;
205 buffer
->separate_out
= FALSE
;
209 _hb_buffer_clear_positions( HB_Buffer buffer
)
211 if ( !buffer
->positions
)
215 if ( ALLOC_ARRAY( buffer
->positions
, buffer
->allocated
, HB_PositionRec
) )
219 memset (buffer
->positions
, 0, sizeof (buffer
->positions
[0]) * buffer
->in_length
);
225 _hb_buffer_swap( HB_Buffer buffer
)
227 HB_GlyphItem tmp_string
;
231 if ( buffer
->separate_out
)
233 tmp_string
= buffer
->in_string
;
234 buffer
->in_string
= buffer
->out_string
;
235 buffer
->out_string
= tmp_string
;
236 buffer
->alt_string
= buffer
->out_string
;
239 tmp_length
= buffer
->in_length
;
240 buffer
->in_length
= buffer
->out_length
;
241 buffer
->out_length
= tmp_length
;
243 tmp_pos
= buffer
->in_pos
;
244 buffer
->in_pos
= buffer
->out_pos
;
245 buffer
->out_pos
= tmp_pos
;
248 /* The following function copies `num_out' elements from `glyph_data'
249 to `buffer->out_string', advancing the in array pointer in the structure
250 by `num_in' elements, and the out array pointer by `num_out' elements.
251 Finally, it sets the `length' field of `out' equal to
252 `pos' of the `out' structure.
254 If `component' is 0xFFFF, the component value from buffer->in_pos
255 will copied `num_out' times, otherwise `component' itself will
256 be used to fill the `component' fields.
258 If `ligID' is 0xFFFF, the ligID value from buffer->in_pos
259 will copied `num_out' times, otherwise `ligID' itself will
260 be used to fill the `ligID' fields.
262 The properties for all replacement glyphs are taken
263 from the glyph at position `buffer->in_pos'.
265 The cluster value for the glyph at position buffer->in_pos is used
266 for all replacement glyphs */
268 _hb_buffer_add_output_glyphs( HB_Buffer buffer
,
271 HB_UShort
*glyph_data
,
280 error
= hb_buffer_ensure( buffer
, buffer
->out_pos
+ num_out
);
284 if ( !buffer
->separate_out
)
286 error
= hb_buffer_duplicate_out_buffer( buffer
);
291 properties
= buffer
->in_string
[buffer
->in_pos
].properties
;
292 cluster
= buffer
->in_string
[buffer
->in_pos
].cluster
;
293 if ( component
== 0xFFFF )
294 component
= buffer
->in_string
[buffer
->in_pos
].component
;
295 if ( ligID
== 0xFFFF )
296 ligID
= buffer
->in_string
[buffer
->in_pos
].ligID
;
298 for ( i
= 0; i
< num_out
; i
++ )
300 HB_GlyphItem item
= &buffer
->out_string
[buffer
->out_pos
+ i
];
302 item
->gindex
= glyph_data
[i
];
303 item
->properties
= properties
;
304 item
->cluster
= cluster
;
305 item
->component
= component
;
307 item
->gproperties
= HB_GLYPH_PROPERTIES_UNKNOWN
;
310 buffer
->in_pos
+= num_in
;
311 buffer
->out_pos
+= num_out
;
313 buffer
->out_length
= buffer
->out_pos
;
319 _hb_buffer_add_output_glyph( HB_Buffer buffer
,
324 HB_UShort glyph_data
= glyph_index
;
326 return _hb_buffer_add_output_glyphs ( buffer
, 1, 1,
327 &glyph_data
, component
, ligID
);
331 _hb_buffer_copy_output_glyph ( HB_Buffer buffer
)
335 error
= hb_buffer_ensure( buffer
, buffer
->out_pos
+ 1 );
339 if ( buffer
->separate_out
)
341 buffer
->out_string
[buffer
->out_pos
] = buffer
->in_string
[buffer
->in_pos
];
346 buffer
->out_length
= buffer
->out_pos
;
352 _hb_buffer_replace_output_glyph( HB_Buffer buffer
,
361 error
= _hb_buffer_copy_output_glyph ( buffer
);
365 buffer
->out_string
[buffer
->out_pos
-1].gindex
= glyph_index
;
369 return _hb_buffer_add_output_glyph( buffer
, glyph_index
, 0xFFFF, 0xFFFF );
375 HB_INTERNAL HB_UShort
376 _hb_buffer_allocate_ligid( HB_Buffer buffer
)
379 if (HB_UNLIKELY (buffer
->max_ligID
== 0))
382 return buffer
->max_ligID
;