OLD | NEW |
| (Empty) |
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 "harfbuzz-impl.h" | |
29 #include "harfbuzz-buffer-private.h" | |
30 #include "harfbuzz-gsub-private.h" | |
31 #include "harfbuzz-gpos-private.h" | |
32 | |
33 /* Here is how the buffer works internally: | |
34 * | |
35 * There are two string pointers: in_string and out_string. They | |
36 * always have same allocated size, but different length and positions. | |
37 * | |
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 | |
40 * case as long as: | |
41 * | |
42 * - copy_glyph() is called | |
43 * - replace_glyph() is called with inplace=TRUE | |
44 * - add_output_glyph() and add_output_glyphs() are not called | |
45 * | |
46 * In that case swap(), and copy_glyph(), and replace_glyph() are all | |
47 * mostly no-op. | |
48 * | |
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. | |
55 * | |
56 * The buffer->separate_out boolean keeps status of whether out_string points | |
57 * to in_string (FALSE) or alt_string (TRUE). | |
58 */ | |
59 | |
60 /* Internal API */ | |
61 | |
62 static HB_Error | |
63 hb_buffer_ensure( HB_Buffer buffer, | |
64 HB_UInt size ) | |
65 { | |
66 HB_UInt new_allocated = buffer->allocated; | |
67 | |
68 if (size > new_allocated) | |
69 { | |
70 HB_Error error; | |
71 | |
72 while (size > new_allocated) | |
73 new_allocated += (new_allocated >> 1) + 8; | |
74 | |
75 if ( buffer->positions ) | |
76 { | |
77 if ( REALLOC_ARRAY( buffer->positions, new_allocated, HB_PositionRec )
) | |
78 return error; | |
79 } | |
80 | |
81 if ( REALLOC_ARRAY( buffer->in_string, new_allocated, HB_GlyphItemRec ) ) | |
82 return error; | |
83 | |
84 if ( buffer->separate_out ) | |
85 { | |
86 if ( REALLOC_ARRAY( buffer->alt_string, new_allocated, HB_GlyphItemRec
) ) | |
87 return error; | |
88 | |
89 buffer->out_string = buffer->alt_string; | |
90 } | |
91 else | |
92 { | |
93 buffer->out_string = buffer->in_string; | |
94 | |
95 if ( buffer->alt_string ) | |
96 { | |
97 if ( REALLOC_ARRAY( buffer->alt_string, new_allocated, HB_GlyphIte
mRec ) ) | |
98 return error; | |
99 } | |
100 } | |
101 | |
102 buffer->allocated = new_allocated; | |
103 } | |
104 | |
105 return HB_Err_Ok; | |
106 } | |
107 | |
108 static HB_Error | |
109 hb_buffer_duplicate_out_buffer( HB_Buffer buffer ) | |
110 { | |
111 if ( !buffer->alt_string ) | |
112 { | |
113 HB_Error error; | |
114 | |
115 if ( ALLOC_ARRAY( buffer->alt_string, buffer->allocated, HB_GlyphItemRec )
) | |
116 return error; | |
117 } | |
118 | |
119 buffer->out_string = buffer->alt_string; | |
120 memcpy( buffer->out_string, buffer->in_string, buffer->out_length * sizeof (bu
ffer->out_string[0]) ); | |
121 buffer->separate_out = TRUE; | |
122 | |
123 return HB_Err_Ok; | |
124 } | |
125 | |
126 /* Public API */ | |
127 | |
128 HB_Error | |
129 hb_buffer_new( HB_Buffer *pbuffer ) | |
130 { | |
131 HB_Buffer buffer; | |
132 HB_Error error; | |
133 | |
134 if ( ALLOC( buffer, sizeof( HB_BufferRec ) ) ) | |
135 return error; | |
136 | |
137 buffer->allocated = 0; | |
138 buffer->in_string = NULL; | |
139 buffer->alt_string = NULL; | |
140 buffer->positions = NULL; | |
141 | |
142 hb_buffer_clear( buffer ); | |
143 | |
144 *pbuffer = buffer; | |
145 | |
146 return HB_Err_Ok; | |
147 } | |
148 | |
149 void | |
150 hb_buffer_free( HB_Buffer buffer ) | |
151 { | |
152 FREE( buffer->in_string ); | |
153 FREE( buffer->alt_string ); | |
154 buffer->out_string = NULL; | |
155 FREE( buffer->positions ); | |
156 FREE( buffer ); | |
157 } | |
158 | |
159 void | |
160 hb_buffer_clear( HB_Buffer buffer ) | |
161 { | |
162 buffer->in_length = 0; | |
163 buffer->out_length = 0; | |
164 buffer->in_pos = 0; | |
165 buffer->out_pos = 0; | |
166 buffer->out_string = buffer->in_string; | |
167 buffer->separate_out = FALSE; | |
168 buffer->max_ligID = 0; | |
169 } | |
170 | |
171 HB_Error | |
172 hb_buffer_add_glyph( HB_Buffer buffer, | |
173 HB_UInt glyph_index, | |
174 HB_UInt properties, | |
175 HB_UInt cluster ) | |
176 { | |
177 HB_Error error; | |
178 HB_GlyphItem glyph; | |
179 | |
180 error = hb_buffer_ensure( buffer, buffer->in_length + 1 ); | |
181 if ( error ) | |
182 return error; | |
183 | |
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; | |
189 glyph->ligID = 0; | |
190 glyph->gproperties = HB_GLYPH_PROPERTIES_UNKNOWN; | |
191 | |
192 buffer->in_length++; | |
193 | |
194 return HB_Err_Ok; | |
195 } | |
196 | |
197 /* HarfBuzz-Internal API */ | |
198 | |
199 HB_INTERNAL void | |
200 _hb_buffer_clear_output( HB_Buffer buffer ) | |
201 { | |
202 buffer->out_length = 0; | |
203 buffer->out_pos = 0; | |
204 buffer->out_string = buffer->in_string; | |
205 buffer->separate_out = FALSE; | |
206 } | |
207 | |
208 HB_INTERNAL HB_Error | |
209 _hb_buffer_clear_positions( HB_Buffer buffer ) | |
210 { | |
211 if ( !buffer->positions ) | |
212 { | |
213 HB_Error error; | |
214 | |
215 if ( ALLOC_ARRAY( buffer->positions, buffer->allocated, HB_PositionRec ) ) | |
216 return error; | |
217 } | |
218 | |
219 memset (buffer->positions, 0, sizeof (buffer->positions[0]) * buffer->in_lengt
h); | |
220 | |
221 return HB_Err_Ok; | |
222 } | |
223 | |
224 HB_INTERNAL void | |
225 _hb_buffer_swap( HB_Buffer buffer ) | |
226 { | |
227 HB_GlyphItem tmp_string; | |
228 int tmp_length; | |
229 int tmp_pos; | |
230 | |
231 if ( buffer->separate_out ) | |
232 { | |
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; | |
237 } | |
238 | |
239 tmp_length = buffer->in_length; | |
240 buffer->in_length = buffer->out_length; | |
241 buffer->out_length = tmp_length; | |
242 | |
243 tmp_pos = buffer->in_pos; | |
244 buffer->in_pos = buffer->out_pos; | |
245 buffer->out_pos = tmp_pos; | |
246 } | |
247 | |
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. | |
253 | |
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. | |
257 | |
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. | |
261 | |
262 The properties for all replacement glyphs are taken | |
263 from the glyph at position `buffer->in_pos'. | |
264 | |
265 The cluster value for the glyph at position buffer->in_pos is used | |
266 for all replacement glyphs */ | |
267 HB_INTERNAL HB_Error | |
268 _hb_buffer_add_output_glyphs( HB_Buffer buffer, | |
269 HB_UShort num_in, | |
270 HB_UShort num_out, | |
271 HB_UShort *glyph_data, | |
272 HB_UShort component, | |
273 HB_UShort ligID ) | |
274 { | |
275 HB_Error error; | |
276 HB_UShort i; | |
277 HB_UInt properties; | |
278 HB_UInt cluster; | |
279 | |
280 error = hb_buffer_ensure( buffer, buffer->out_pos + num_out ); | |
281 if ( error ) | |
282 return error; | |
283 | |
284 if ( !buffer->separate_out ) | |
285 { | |
286 error = hb_buffer_duplicate_out_buffer( buffer ); | |
287 if ( error ) | |
288 return error; | |
289 } | |
290 | |
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; | |
297 | |
298 for ( i = 0; i < num_out; i++ ) | |
299 { | |
300 HB_GlyphItem item = &buffer->out_string[buffer->out_pos + i]; | |
301 | |
302 item->gindex = glyph_data[i]; | |
303 item->properties = properties; | |
304 item->cluster = cluster; | |
305 item->component = component; | |
306 item->ligID = ligID; | |
307 item->gproperties = HB_GLYPH_PROPERTIES_UNKNOWN; | |
308 } | |
309 | |
310 buffer->in_pos += num_in; | |
311 buffer->out_pos += num_out; | |
312 | |
313 buffer->out_length = buffer->out_pos; | |
314 | |
315 return HB_Err_Ok; | |
316 } | |
317 | |
318 HB_INTERNAL HB_Error | |
319 _hb_buffer_add_output_glyph( HB_Buffer buffer, | |
320 HB_UInt glyph_index, | |
321 HB_UShort component, | |
322 HB_UShort ligID ) | |
323 { | |
324 HB_UShort glyph_data = glyph_index; | |
325 | |
326 return _hb_buffer_add_output_glyphs ( buffer, 1, 1, | |
327 &glyph_data, component, ligID ); | |
328 } | |
329 | |
330 HB_INTERNAL HB_Error | |
331 _hb_buffer_copy_output_glyph ( HB_Buffer buffer ) | |
332 { | |
333 HB_Error error; | |
334 | |
335 error = hb_buffer_ensure( buffer, buffer->out_pos + 1 ); | |
336 if ( error ) | |
337 return error; | |
338 | |
339 if ( buffer->separate_out ) | |
340 { | |
341 buffer->out_string[buffer->out_pos] = buffer->in_string[buffer->in_pos]; | |
342 } | |
343 | |
344 buffer->in_pos++; | |
345 buffer->out_pos++; | |
346 buffer->out_length = buffer->out_pos; | |
347 | |
348 return HB_Err_Ok; | |
349 } | |
350 | |
351 HB_INTERNAL HB_Error | |
352 _hb_buffer_replace_output_glyph( HB_Buffer buffer, | |
353 HB_UInt glyph_index, | |
354 HB_Bool inplace ) | |
355 { | |
356 | |
357 HB_Error error; | |
358 | |
359 if ( inplace ) | |
360 { | |
361 error = _hb_buffer_copy_output_glyph ( buffer ); | |
362 if ( error ) | |
363 return error; | |
364 | |
365 buffer->out_string[buffer->out_pos-1].gindex = glyph_index; | |
366 } | |
367 else | |
368 { | |
369 return _hb_buffer_add_output_glyph( buffer, glyph_index, 0xFFFF, 0xFFFF ); | |
370 } | |
371 | |
372 return HB_Err_Ok; | |
373 } | |
374 | |
375 HB_INTERNAL HB_UShort | |
376 _hb_buffer_allocate_ligid( HB_Buffer buffer ) | |
377 { | |
378 buffer->max_ligID++; | |
379 if (HB_UNLIKELY (buffer->max_ligID == 0)) | |
380 buffer->max_ligID++; | |
381 | |
382 return buffer->max_ligID; | |
383 } | |
OLD | NEW |