OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg | 2 * Copyright © 1998-2004 David Turner and Werner Lemberg |
3 * Copyright (C) 2004,2007,2009,2010 Red Hat, Inc. | 3 * Copyright © 2004,2007,2009,2010 Red Hat, Inc. |
| 4 * Copyright © 2011 Google, Inc. |
4 * | 5 * |
5 * This is part of HarfBuzz, a text shaping library. | 6 * This is part of HarfBuzz, a text shaping library. |
6 * | 7 * |
7 * Permission is hereby granted, without written agreement and without | 8 * Permission is hereby granted, without written agreement and without |
8 * license or royalty fees, to use, copy, modify, and distribute this | 9 * license or royalty fees, to use, copy, modify, and distribute this |
9 * software and its documentation for any purpose, provided that the | 10 * software and its documentation for any purpose, provided that the |
10 * above copyright notice and the following two paragraphs appear in | 11 * above copyright notice and the following two paragraphs appear in |
11 * all copies of this software. | 12 * all copies of this software. |
12 * | 13 * |
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | 14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | 15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | 16 * 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 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
17 * DAMAGE. | 18 * DAMAGE. |
18 * | 19 * |
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | 20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | 21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | 22 * 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 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
24 * | 25 * |
25 * Red Hat Author(s): Owen Taylor, Behdad Esfahbod | 26 * Red Hat Author(s): Owen Taylor, Behdad Esfahbod |
| 27 * Google Author(s): Behdad Esfahbod |
26 */ | 28 */ |
27 | 29 |
28 #include "hb-buffer-private.hh" | 30 #include "hb-buffer-private.hh" |
29 | 31 |
30 #include <string.h> | 32 #include <string.h> |
31 | 33 |
32 HB_BEGIN_DECLS | 34 |
| 35 |
| 36 #ifndef HB_DEBUG_BUFFER |
| 37 #define HB_DEBUG_BUFFER (HB_DEBUG+0) |
| 38 #endif |
33 | 39 |
34 | 40 |
35 static hb_buffer_t _hb_buffer_nil = { | 41 static hb_buffer_t _hb_buffer_nil = { |
36 HB_REFERENCE_COUNT_INVALID, /* ref_count */ | 42 HB_OBJECT_HEADER_STATIC, |
37 | 43 |
38 &_hb_unicode_funcs_nil /* unicode */ | 44 &_hb_unicode_funcs_default, |
| 45 { |
| 46 HB_DIRECTION_INVALID, |
| 47 HB_SCRIPT_INVALID, |
| 48 NULL, |
| 49 }, |
| 50 |
| 51 TRUE, /* in_error */ |
| 52 TRUE, /* have_output */ |
| 53 TRUE /* have_positions */ |
39 }; | 54 }; |
40 | 55 |
41 /* Here is how the buffer works internally: | 56 /* Here is how the buffer works internally: |
42 * | 57 * |
43 * There are two info pointers: info and out_info. They always have | 58 * There are two info pointers: info and out_info. They always have |
44 * the same allocated size, but different lengths. | 59 * the same allocated size, but different lengths. |
45 * | 60 * |
46 * As an optimization, both info and out_info may point to the | 61 * As an optimization, both info and out_info may point to the |
47 * same piece of memory, which is owned by info. This remains the | 62 * same piece of memory, which is owned by info. This remains the |
48 * case as long as out_len doesn't exceed len at any time. | 63 * case as long as out_len doesn't exceed i at any time. |
49 * In that case, swap() is no-op and the glyph operations operate | 64 * In that case, swap_buffers() is no-op and the glyph operations operate |
50 * mostly in-place. | 65 * mostly in-place. |
51 * | 66 * |
52 * As soon as out_info gets longer than info, out_info is moved over | 67 * As soon as out_info gets longer than info, out_info is moved over |
53 * to an alternate buffer (which we reuse the pos buffer for!), and its | 68 * to an alternate buffer (which we reuse the pos buffer for!), and its |
54 * current contents (out_len entries) are copied to the new place. | 69 * current contents (out_len entries) are copied to the new place. |
55 * This should all remain transparent to the user. swap() then | 70 * This should all remain transparent to the user. swap_buffers() then |
56 * switches info and out_info. | 71 * switches info and out_info. |
57 */ | 72 */ |
58 | 73 |
59 | 74 |
60 static hb_bool_t | 75 |
61 _hb_buffer_enlarge (hb_buffer_t *buffer, unsigned int size) | 76 /* Internal API */ |
62 { | 77 |
63 if (unlikely (buffer->in_error)) | 78 bool |
| 79 hb_buffer_t::enlarge (unsigned int size) |
| 80 { |
| 81 if (unlikely (in_error)) |
64 return FALSE; | 82 return FALSE; |
65 | 83 |
66 unsigned int new_allocated = buffer->allocated; | 84 unsigned int new_allocated = allocated; |
67 hb_glyph_position_t *new_pos; | 85 hb_glyph_position_t *new_pos = NULL; |
68 hb_glyph_info_t *new_info; | 86 hb_glyph_info_t *new_info = NULL; |
69 bool separate_out; | 87 bool separate_out = out_info != info; |
70 | 88 |
71 separate_out = buffer->out_info != buffer->info; | 89 if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0])))) |
| 90 goto done; |
72 | 91 |
73 while (size > new_allocated) | 92 while (size > new_allocated) |
74 new_allocated += (new_allocated >> 1) + 8; | 93 new_allocated += (new_allocated >> 1) + 32; |
75 | 94 |
76 new_pos = (hb_glyph_position_t *) realloc (buffer->pos, new_allocated * sizeof
(buffer->pos[0])); | 95 ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0])); |
77 new_info = (hb_glyph_info_t *) realloc (buffer->info, new_allocated * sizeof (
buffer->info[0])); | 96 if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))
)) |
78 | 97 goto done; |
| 98 |
| 99 new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]
)); |
| 100 new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0])
); |
| 101 |
| 102 done: |
79 if (unlikely (!new_pos || !new_info)) | 103 if (unlikely (!new_pos || !new_info)) |
80 buffer->in_error = TRUE; | 104 in_error = TRUE; |
81 | 105 |
82 if (likely (new_pos)) | 106 if (likely (new_pos)) |
83 buffer->pos = new_pos; | 107 pos = new_pos; |
84 | 108 |
85 if (likely (new_info)) | 109 if (likely (new_info)) |
86 buffer->info = new_info; | 110 info = new_info; |
87 | 111 |
88 buffer->out_info = separate_out ? (hb_glyph_info_t *) buffer->pos : buffer->in
fo; | 112 out_info = separate_out ? (hb_glyph_info_t *) pos : info; |
89 if (likely (!buffer->in_error)) | 113 if (likely (!in_error)) |
90 buffer->allocated = new_allocated; | 114 allocated = new_allocated; |
91 | 115 |
92 return likely (!buffer->in_error); | 116 return likely (!in_error); |
93 } | 117 } |
94 | 118 |
95 static inline hb_bool_t | 119 bool |
96 _hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size) | 120 hb_buffer_t::make_room_for (unsigned int num_in, |
97 { | 121 » » » unsigned int num_out) |
98 return likely (size <= buffer->allocated) ? TRUE : _hb_buffer_enlarge (buffer,
size); | 122 { |
99 } | 123 if (unlikely (!ensure (out_len + num_out))) return FALSE; |
100 | 124 |
101 static inline hb_bool_t | 125 if (out_info == info && |
102 _hb_buffer_ensure_separate (hb_buffer_t *buffer, unsigned int size) | 126 out_len + num_out > idx + num_in) |
103 { | |
104 if (unlikely (!_hb_buffer_ensure (buffer, size))) return FALSE; | |
105 | |
106 if (buffer->out_info == buffer->info) | |
107 { | 127 { |
108 assert (buffer->have_output); | 128 assert (have_output); |
109 | 129 |
110 buffer->out_info = (hb_glyph_info_t *) buffer->pos; | 130 out_info = (hb_glyph_info_t *) pos; |
111 memcpy (buffer->out_info, buffer->info, buffer->out_len * sizeof (buffer->ou
t_info[0])); | 131 memcpy (out_info, info, out_len * sizeof (out_info[0])); |
112 } | 132 } |
113 | 133 |
114 return TRUE; | 134 return TRUE; |
115 } | 135 } |
116 | 136 |
117 | 137 void * |
118 /* Public API */ | 138 hb_buffer_t::get_scratch_buffer (unsigned int *size) |
119 | 139 { |
120 hb_buffer_t * | 140 have_output = FALSE; |
121 hb_buffer_create (unsigned int pre_alloc_size) | 141 have_positions = FALSE; |
122 { | 142 out_len = 0; |
123 hb_buffer_t *buffer; | 143 *size = allocated * sizeof (pos[0]); |
124 | 144 return pos; |
125 if (!HB_OBJECT_DO_CREATE (hb_buffer_t, buffer)) | 145 } |
126 return &_hb_buffer_nil; | 146 |
127 | 147 |
128 if (pre_alloc_size) | 148 /* HarfBuzz-Internal API */ |
129 _hb_buffer_ensure (buffer, pre_alloc_size); | 149 |
130 | 150 void |
131 buffer->unicode = &_hb_unicode_funcs_nil; | 151 hb_buffer_t::reset (void) |
132 | 152 { |
133 return buffer; | 153 if (unlikely (hb_object_is_inert (this))) |
134 } | 154 return; |
135 | 155 |
136 hb_buffer_t * | 156 hb_unicode_funcs_destroy (unicode); |
137 hb_buffer_reference (hb_buffer_t *buffer) | 157 unicode = _hb_buffer_nil.unicode; |
138 { | 158 |
139 HB_OBJECT_DO_REFERENCE (buffer); | 159 props = _hb_buffer_nil.props; |
140 } | 160 |
141 | 161 in_error = FALSE; |
142 unsigned int | 162 have_output = FALSE; |
143 hb_buffer_get_reference_count (hb_buffer_t *buffer) | 163 have_positions = FALSE; |
144 { | 164 |
145 HB_OBJECT_DO_GET_REFERENCE_COUNT (buffer); | 165 idx = 0; |
146 } | 166 len = 0; |
147 | 167 out_len = 0; |
148 void | 168 |
149 hb_buffer_destroy (hb_buffer_t *buffer) | 169 serial = 0; |
150 { | 170 memset (allocated_var_bytes, 0, sizeof allocated_var_bytes); |
151 HB_OBJECT_DO_DESTROY (buffer); | 171 memset (allocated_var_owner, 0, sizeof allocated_var_owner); |
152 | 172 |
153 hb_unicode_funcs_destroy (buffer->unicode); | 173 out_info = info; |
154 | 174 } |
155 free (buffer->info); | 175 |
156 free (buffer->pos); | 176 void |
157 | 177 hb_buffer_t::add (hb_codepoint_t codepoint, |
158 free (buffer); | 178 » » hb_mask_t mask, |
159 } | 179 » » unsigned int cluster) |
160 | |
161 | |
162 void | |
163 hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, | |
164 » » » hb_unicode_funcs_t *unicode) | |
165 { | |
166 if (!unicode) | |
167 unicode = &_hb_unicode_funcs_nil; | |
168 | |
169 hb_unicode_funcs_reference (unicode); | |
170 hb_unicode_funcs_destroy (buffer->unicode); | |
171 buffer->unicode = unicode; | |
172 } | |
173 | |
174 hb_unicode_funcs_t * | |
175 hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) | |
176 { | |
177 return buffer->unicode; | |
178 } | |
179 | |
180 void | |
181 hb_buffer_set_direction (hb_buffer_t *buffer, | |
182 » » » hb_direction_t direction) | |
183 | |
184 { | |
185 buffer->props.direction = direction; | |
186 } | |
187 | |
188 hb_direction_t | |
189 hb_buffer_get_direction (hb_buffer_t *buffer) | |
190 { | |
191 return buffer->props.direction; | |
192 } | |
193 | |
194 void | |
195 hb_buffer_set_script (hb_buffer_t *buffer, | |
196 » » hb_script_t script) | |
197 { | |
198 buffer->props.script = script; | |
199 } | |
200 | |
201 hb_script_t | |
202 hb_buffer_get_script (hb_buffer_t *buffer) | |
203 { | |
204 return buffer->props.script; | |
205 } | |
206 | |
207 void | |
208 hb_buffer_set_language (hb_buffer_t *buffer, | |
209 » » » hb_language_t language) | |
210 { | |
211 buffer->props.language = language; | |
212 } | |
213 | |
214 hb_language_t | |
215 hb_buffer_get_language (hb_buffer_t *buffer) | |
216 { | |
217 return buffer->props.language; | |
218 } | |
219 | |
220 | |
221 void | |
222 hb_buffer_clear (hb_buffer_t *buffer) | |
223 { | |
224 buffer->have_output = FALSE; | |
225 buffer->have_positions = FALSE; | |
226 buffer->in_error = FALSE; | |
227 buffer->len = 0; | |
228 buffer->out_len = 0; | |
229 buffer->i = 0; | |
230 buffer->out_info = buffer->info; | |
231 buffer->serial = 0; | |
232 } | |
233 | |
234 hb_bool_t | |
235 hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size) | |
236 { | |
237 return _hb_buffer_ensure (buffer, size); | |
238 } | |
239 | |
240 void | |
241 hb_buffer_add_glyph (hb_buffer_t *buffer, | |
242 » » hb_codepoint_t codepoint, | |
243 » » hb_mask_t mask, | |
244 » » unsigned int cluster) | |
245 { | 180 { |
246 hb_glyph_info_t *glyph; | 181 hb_glyph_info_t *glyph; |
247 | 182 |
248 if (unlikely (!_hb_buffer_ensure (buffer, buffer->len + 1))) return; | 183 if (unlikely (!ensure (len + 1))) return; |
249 | 184 |
250 glyph = &buffer->info[buffer->len]; | 185 glyph = &info[len]; |
251 | 186 |
252 memset (glyph, 0, sizeof (*glyph)); | 187 memset (glyph, 0, sizeof (*glyph)); |
253 glyph->codepoint = codepoint; | 188 glyph->codepoint = codepoint; |
254 glyph->mask = mask; | 189 glyph->mask = mask; |
255 glyph->cluster = cluster; | 190 glyph->cluster = cluster; |
256 | 191 |
257 buffer->len++; | 192 len++; |
258 } | 193 } |
259 | 194 |
260 void | 195 void |
261 hb_buffer_clear_positions (hb_buffer_t *buffer) | 196 hb_buffer_t::clear_output (void) |
262 { | 197 { |
263 _hb_buffer_clear_output (buffer); | 198 if (unlikely (hb_object_is_inert (this))) |
264 buffer->have_output = FALSE; | 199 return; |
265 buffer->have_positions = TRUE; | 200 |
266 | 201 have_output = TRUE; |
267 if (unlikely (!buffer->pos)) | 202 have_positions = FALSE; |
268 { | 203 |
269 buffer->pos = (hb_glyph_position_t *) calloc (buffer->allocated, sizeof (buf
fer->pos[0])); | 204 out_len = 0; |
270 return; | 205 out_info = info; |
271 } | 206 } |
272 | 207 |
273 memset (buffer->pos, 0, sizeof (buffer->pos[0]) * buffer->len); | 208 void |
274 } | 209 hb_buffer_t::clear_positions (void) |
275 | 210 { |
276 /* HarfBuzz-Internal API */ | 211 if (unlikely (hb_object_is_inert (this))) |
277 | 212 return; |
278 void | 213 |
279 _hb_buffer_clear_output (hb_buffer_t *buffer) | 214 have_output = FALSE; |
280 { | 215 have_positions = TRUE; |
281 buffer->have_output = TRUE; | 216 |
282 buffer->have_positions = FALSE; | 217 memset (pos, 0, sizeof (pos[0]) * len); |
283 buffer->out_len = 0; | 218 } |
284 buffer->out_info = buffer->info; | 219 |
285 } | 220 void |
286 | 221 hb_buffer_t::swap_buffers (void) |
287 void | 222 { |
288 _hb_buffer_swap (hb_buffer_t *buffer) | 223 if (unlikely (in_error)) return; |
289 { | 224 |
290 unsigned int tmp; | 225 assert (have_output); |
291 | 226 |
292 assert (buffer->have_output); | 227 if (out_info != info) |
293 | |
294 if (unlikely (buffer->in_error)) return; | |
295 | |
296 if (buffer->out_info != buffer->info) | |
297 { | 228 { |
298 hb_glyph_info_t *tmp_string; | 229 hb_glyph_info_t *tmp_string; |
299 tmp_string = buffer->info; | 230 tmp_string = info; |
300 buffer->info = buffer->out_info; | 231 info = out_info; |
301 buffer->out_info = tmp_string; | 232 out_info = tmp_string; |
302 buffer->pos = (hb_glyph_position_t *) buffer->out_info; | 233 pos = (hb_glyph_position_t *) out_info; |
303 } | 234 } |
304 | 235 |
305 tmp = buffer->len; | 236 unsigned int tmp; |
306 buffer->len = buffer->out_len; | 237 tmp = len; |
307 buffer->out_len = tmp; | 238 len = out_len; |
308 | 239 out_len = tmp; |
309 buffer->i = 0; | 240 |
310 } | 241 idx = 0; |
311 | 242 } |
312 void | 243 |
313 _hb_buffer_replace_glyphs_be16 (hb_buffer_t *buffer, | 244 void |
314 » » » » unsigned int num_in, | 245 hb_buffer_t::replace_glyphs_be16 (unsigned int num_in, |
315 » » » » unsigned int num_out, | 246 » » » » unsigned int num_out, |
316 » » » » const uint16_t *glyph_data_be) | 247 » » » » const uint16_t *glyph_data_be) |
317 { | 248 { |
318 if (buffer->out_info != buffer->info || | 249 if (!make_room_for (num_in, num_out)) return; |
319 buffer->out_len + num_out > buffer->i + num_in) | 250 |
| 251 hb_glyph_info_t orig_info = info[idx]; |
| 252 for (unsigned int i = 1; i < num_in; i++) |
320 { | 253 { |
321 if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out
))) | 254 hb_glyph_info_t *inf = &info[idx + i]; |
322 return; | 255 orig_info.cluster = MIN (orig_info.cluster, inf->cluster); |
323 } | 256 } |
324 | 257 |
325 hb_glyph_info_t orig_info = buffer->info[buffer->i]; | 258 hb_glyph_info_t *pinfo = &out_info[out_len]; |
326 | |
327 for (unsigned int i = 0; i < num_out; i++) | 259 for (unsigned int i = 0; i < num_out; i++) |
328 { | 260 { |
329 hb_glyph_info_t *info = &buffer->out_info[buffer->out_len + i]; | 261 *pinfo = orig_info; |
330 *info = orig_info; | 262 pinfo->codepoint = hb_be_uint16 (glyph_data_be[i]); |
331 info->codepoint = hb_be_uint16 (glyph_data_be[i]); | 263 pinfo++; |
332 } | 264 } |
333 | 265 |
334 buffer->i += num_in; | 266 idx += num_in; |
335 buffer->out_len += num_out; | 267 out_len += num_out; |
336 } | 268 } |
337 | 269 |
338 void | 270 void |
339 _hb_buffer_replace_glyph (hb_buffer_t *buffer, | 271 hb_buffer_t::replace_glyphs (unsigned int num_in, |
340 » » » hb_codepoint_t glyph_index) | 272 » » » unsigned int num_out, |
341 { | 273 » » » const uint16_t *glyph_data) |
342 hb_glyph_info_t *info; | 274 { |
343 | 275 if (!make_room_for (num_in, num_out)) return; |
344 if (buffer->out_info != buffer->info) | 276 |
| 277 hb_glyph_info_t orig_info = info[idx]; |
| 278 for (unsigned int i = 1; i < num_in; i++) |
345 { | 279 { |
346 if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return; | 280 hb_glyph_info_t *inf = &info[idx + i]; |
347 buffer->out_info[buffer->out_len] = buffer->info[buffer->i]; | 281 orig_info.cluster = MIN (orig_info.cluster, inf->cluster); |
348 } | 282 } |
349 else if (buffer->out_len != buffer->i) | 283 |
350 buffer->out_info[buffer->out_len] = buffer->info[buffer->i]; | 284 hb_glyph_info_t *pinfo = &out_info[out_len]; |
351 | 285 for (unsigned int i = 0; i < num_out; i++) |
352 info = &buffer->out_info[buffer->out_len]; | |
353 info->codepoint = glyph_index; | |
354 | |
355 buffer->i++; | |
356 buffer->out_len++; | |
357 } | |
358 | |
359 void | |
360 _hb_buffer_next_glyph (hb_buffer_t *buffer) | |
361 { | |
362 if (buffer->have_output) | |
363 { | 286 { |
364 if (buffer->out_info != buffer->info) | 287 *pinfo = orig_info; |
| 288 pinfo->codepoint = glyph_data[i]; |
| 289 pinfo++; |
| 290 } |
| 291 |
| 292 idx += num_in; |
| 293 out_len += num_out; |
| 294 } |
| 295 |
| 296 void |
| 297 hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) |
| 298 { |
| 299 if (!make_room_for (0, 1)) return; |
| 300 |
| 301 out_info[out_len] = info[idx]; |
| 302 out_info[out_len].codepoint = glyph_index; |
| 303 |
| 304 out_len++; |
| 305 } |
| 306 |
| 307 void |
| 308 hb_buffer_t::copy_glyph (void) |
| 309 { |
| 310 if (!make_room_for (0, 1)) return; |
| 311 |
| 312 out_info[out_len] = info[idx]; |
| 313 |
| 314 out_len++; |
| 315 } |
| 316 |
| 317 void |
| 318 hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) |
| 319 { |
| 320 if (!make_room_for (1, 1)) return; |
| 321 |
| 322 out_info[out_len] = info[idx]; |
| 323 out_info[out_len].codepoint = glyph_index; |
| 324 |
| 325 idx++; |
| 326 out_len++; |
| 327 } |
| 328 |
| 329 void |
| 330 hb_buffer_t::next_glyph (void) |
| 331 { |
| 332 if (have_output) |
| 333 { |
| 334 if (out_info != info) |
365 { | 335 { |
366 if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return; | 336 if (unlikely (!ensure (out_len + 1))) return; |
367 buffer->out_info[buffer->out_len] = buffer->info[buffer->i]; | 337 out_info[out_len] = info[idx]; |
368 } | 338 } |
369 else if (buffer->out_len != buffer->i) | 339 else if (out_len != idx) |
370 buffer->out_info[buffer->out_len] = buffer->info[buffer->i]; | 340 out_info[out_len] = info[idx]; |
371 | 341 |
372 buffer->out_len++; | 342 out_len++; |
373 } | 343 } |
374 | 344 |
375 buffer->i++; | 345 idx++; |
376 } | 346 } |
377 | 347 |
378 void | 348 void |
379 _hb_buffer_reset_masks (hb_buffer_t *buffer, | 349 hb_buffer_t::set_masks (hb_mask_t value, |
380 » » » hb_mask_t mask) | 350 » » » hb_mask_t mask, |
381 { | 351 » » » unsigned int cluster_start, |
382 unsigned int count = buffer->len; | 352 » » » unsigned int cluster_end) |
383 for (unsigned int i = 0; i < count; i++) | |
384 buffer->info[i].mask = mask; | |
385 } | |
386 | |
387 void | |
388 _hb_buffer_add_masks (hb_buffer_t *buffer, | |
389 » » hb_mask_t mask) | |
390 { | |
391 unsigned int count = buffer->len; | |
392 for (unsigned int i = 0; i < count; i++) | |
393 buffer->info[i].mask |= mask; | |
394 } | |
395 | |
396 void | |
397 _hb_buffer_set_masks (hb_buffer_t *buffer, | |
398 » » hb_mask_t value, | |
399 » » hb_mask_t mask, | |
400 » » unsigned int cluster_start, | |
401 » » unsigned int cluster_end) | |
402 { | 353 { |
403 hb_mask_t not_mask = ~mask; | 354 hb_mask_t not_mask = ~mask; |
404 value &= mask; | 355 value &= mask; |
405 | 356 |
406 if (!mask) | 357 if (!mask) |
407 return; | 358 return; |
408 | 359 |
409 if (cluster_start == 0 && cluster_end == (unsigned int)-1) { | 360 if (cluster_start == 0 && cluster_end == (unsigned int)-1) { |
410 unsigned int count = buffer->len; | 361 unsigned int count = len; |
411 for (unsigned int i = 0; i < count; i++) | 362 for (unsigned int i = 0; i < count; i++) |
412 buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value; | 363 info[i].mask = (info[i].mask & not_mask) | value; |
413 return; | 364 return; |
414 } | 365 } |
415 | 366 |
416 /* XXX can't bsearch since .cluster may not be sorted. */ | 367 unsigned int count = len; |
417 /* Binary search to find the start position and go from there. */ | 368 for (unsigned int i = 0; i < count; i++) |
418 unsigned int min = 0, max = buffer->len; | 369 if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) |
419 while (min < max) | 370 info[i].mask = (info[i].mask & not_mask) | value; |
420 { | 371 } |
421 unsigned int mid = min + ((max - min) / 2); | 372 |
422 if (buffer->info[mid].cluster < cluster_start) | 373 void |
423 min = mid + 1; | 374 hb_buffer_t::reverse_range (unsigned int start, |
424 else | 375 » » » unsigned int end) |
425 max = mid; | 376 { |
426 } | 377 unsigned int i, j; |
427 unsigned int count = buffer->len; | 378 |
428 for (unsigned int i = min; i < count && buffer->info[i].cluster < cluster_end;
i++) | 379 if (start == end - 1) |
429 buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value; | 380 return; |
430 } | 381 |
431 | 382 for (i = start, j = end - 1; i < j; i++, j--) { |
432 | 383 hb_glyph_info_t t; |
433 /* Public API again */ | 384 |
| 385 t = info[i]; |
| 386 info[i] = info[j]; |
| 387 info[j] = t; |
| 388 } |
| 389 |
| 390 if (pos) { |
| 391 for (i = start, j = end - 1; i < j; i++, j--) { |
| 392 hb_glyph_position_t t; |
| 393 |
| 394 t = pos[i]; |
| 395 pos[i] = pos[j]; |
| 396 pos[j] = t; |
| 397 } |
| 398 } |
| 399 } |
| 400 |
| 401 void |
| 402 hb_buffer_t::reverse (void) |
| 403 { |
| 404 if (unlikely (!len)) |
| 405 return; |
| 406 |
| 407 reverse_range (0, len); |
| 408 } |
| 409 |
| 410 void |
| 411 hb_buffer_t::reverse_clusters (void) |
| 412 { |
| 413 unsigned int i, start, count, last_cluster; |
| 414 |
| 415 if (unlikely (!len)) |
| 416 return; |
| 417 |
| 418 reverse (); |
| 419 |
| 420 count = len; |
| 421 start = 0; |
| 422 last_cluster = info[0].cluster; |
| 423 for (i = 1; i < count; i++) { |
| 424 if (last_cluster != info[i].cluster) { |
| 425 reverse_range (start, i); |
| 426 start = i; |
| 427 last_cluster = info[i].cluster; |
| 428 } |
| 429 } |
| 430 reverse_range (start, i); |
| 431 } |
| 432 |
| 433 void |
| 434 hb_buffer_t::guess_properties (void) |
| 435 { |
| 436 /* If script is set to INVALID, guess from buffer contents */ |
| 437 if (props.script == HB_SCRIPT_INVALID) { |
| 438 for (unsigned int i = 0; i < len; i++) { |
| 439 hb_script_t script = hb_unicode_script (unicode, info[i].codepoint); |
| 440 if (likely (script != HB_SCRIPT_COMMON && |
| 441 » » script != HB_SCRIPT_INHERITED && |
| 442 » » script != HB_SCRIPT_UNKNOWN)) { |
| 443 props.script = script; |
| 444 break; |
| 445 } |
| 446 } |
| 447 } |
| 448 |
| 449 /* If direction is set to INVALID, guess from script */ |
| 450 if (props.direction == HB_DIRECTION_INVALID) { |
| 451 props.direction = hb_script_get_horizontal_direction (props.script); |
| 452 } |
| 453 |
| 454 /* If language is not set, use default language from locale */ |
| 455 if (props.language == HB_LANGUAGE_INVALID) { |
| 456 /* TODO get_default_for_script? using $LANGUAGE */ |
| 457 props.language = hb_language_get_default (); |
| 458 } |
| 459 } |
| 460 |
| 461 |
| 462 static inline void |
| 463 dump_var_allocation (const hb_buffer_t *buffer) |
| 464 { |
| 465 char buf[80]; |
| 466 for (unsigned int i = 0; i < 8; i++) |
| 467 buf[i] = '0' + buffer->allocated_var_bytes[7 - i]; |
| 468 buf[8] = '\0'; |
| 469 DEBUG_MSG (BUFFER, buffer, |
| 470 » "Current var allocation: %s", |
| 471 » buf); |
| 472 } |
| 473 |
| 474 void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const c
har *owner) |
| 475 { |
| 476 assert (byte_i < 8 && byte_i + count <= 8); |
| 477 |
| 478 if (DEBUG (BUFFER)) |
| 479 dump_var_allocation (this); |
| 480 DEBUG_MSG (BUFFER, this, |
| 481 » "Allocating var bytes %d..%d for %s", |
| 482 » byte_i, byte_i + count - 1, owner); |
| 483 |
| 484 for (unsigned int i = byte_i; i < byte_i + count; i++) { |
| 485 assert (!allocated_var_bytes[i]); |
| 486 allocated_var_bytes[i]++; |
| 487 allocated_var_owner[i] = owner; |
| 488 } |
| 489 } |
| 490 |
| 491 void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const
char *owner) |
| 492 { |
| 493 if (DEBUG (BUFFER)) |
| 494 dump_var_allocation (this); |
| 495 |
| 496 DEBUG_MSG (BUFFER, this, |
| 497 » "Deallocating var bytes %d..%d for %s", |
| 498 » byte_i, byte_i + count - 1, owner); |
| 499 |
| 500 assert (byte_i < 8 && byte_i + count <= 8); |
| 501 for (unsigned int i = byte_i; i < byte_i + count; i++) { |
| 502 assert (allocated_var_bytes[i]); |
| 503 assert (0 == strcmp (allocated_var_owner[i], owner)); |
| 504 allocated_var_bytes[i]--; |
| 505 } |
| 506 } |
| 507 |
| 508 void hb_buffer_t::deallocate_var_all (void) |
| 509 { |
| 510 memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes)); |
| 511 memset (allocated_var_owner, 0, sizeof (allocated_var_owner)); |
| 512 } |
| 513 |
| 514 /* Public API */ |
| 515 |
| 516 hb_buffer_t * |
| 517 hb_buffer_create () |
| 518 { |
| 519 hb_buffer_t *buffer; |
| 520 |
| 521 if (!(buffer = hb_object_create<hb_buffer_t> ())) |
| 522 return &_hb_buffer_nil; |
| 523 |
| 524 buffer->reset (); |
| 525 |
| 526 return buffer; |
| 527 } |
| 528 |
| 529 hb_buffer_t * |
| 530 hb_buffer_get_empty (void) |
| 531 { |
| 532 return &_hb_buffer_nil; |
| 533 } |
| 534 |
| 535 hb_buffer_t * |
| 536 hb_buffer_reference (hb_buffer_t *buffer) |
| 537 { |
| 538 return hb_object_reference (buffer); |
| 539 } |
| 540 |
| 541 void |
| 542 hb_buffer_destroy (hb_buffer_t *buffer) |
| 543 { |
| 544 if (!hb_object_destroy (buffer)) return; |
| 545 |
| 546 hb_unicode_funcs_destroy (buffer->unicode); |
| 547 |
| 548 free (buffer->info); |
| 549 free (buffer->pos); |
| 550 |
| 551 free (buffer); |
| 552 } |
| 553 |
| 554 hb_bool_t |
| 555 hb_buffer_set_user_data (hb_buffer_t *buffer, |
| 556 » » » hb_user_data_key_t *key, |
| 557 » » » void * data, |
| 558 » » » hb_destroy_func_t destroy, |
| 559 » » » hb_bool_t replace) |
| 560 { |
| 561 return hb_object_set_user_data (buffer, key, data, destroy, replace); |
| 562 } |
| 563 |
| 564 void * |
| 565 hb_buffer_get_user_data (hb_buffer_t *buffer, |
| 566 » » » hb_user_data_key_t *key) |
| 567 { |
| 568 return hb_object_get_user_data (buffer, key); |
| 569 } |
| 570 |
| 571 |
| 572 void |
| 573 hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, |
| 574 » » » hb_unicode_funcs_t *unicode) |
| 575 { |
| 576 if (unlikely (hb_object_is_inert (buffer))) |
| 577 return; |
| 578 |
| 579 if (!unicode) |
| 580 unicode = _hb_buffer_nil.unicode; |
| 581 |
| 582 hb_unicode_funcs_reference (unicode); |
| 583 hb_unicode_funcs_destroy (buffer->unicode); |
| 584 buffer->unicode = unicode; |
| 585 } |
| 586 |
| 587 hb_unicode_funcs_t * |
| 588 hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) |
| 589 { |
| 590 return buffer->unicode; |
| 591 } |
| 592 |
| 593 void |
| 594 hb_buffer_set_direction (hb_buffer_t *buffer, |
| 595 » » » hb_direction_t direction) |
| 596 |
| 597 { |
| 598 if (unlikely (hb_object_is_inert (buffer))) |
| 599 return; |
| 600 |
| 601 buffer->props.direction = direction; |
| 602 } |
| 603 |
| 604 hb_direction_t |
| 605 hb_buffer_get_direction (hb_buffer_t *buffer) |
| 606 { |
| 607 return buffer->props.direction; |
| 608 } |
| 609 |
| 610 void |
| 611 hb_buffer_set_script (hb_buffer_t *buffer, |
| 612 » » hb_script_t script) |
| 613 { |
| 614 if (unlikely (hb_object_is_inert (buffer))) |
| 615 return; |
| 616 |
| 617 buffer->props.script = script; |
| 618 } |
| 619 |
| 620 hb_script_t |
| 621 hb_buffer_get_script (hb_buffer_t *buffer) |
| 622 { |
| 623 return buffer->props.script; |
| 624 } |
| 625 |
| 626 void |
| 627 hb_buffer_set_language (hb_buffer_t *buffer, |
| 628 » » » hb_language_t language) |
| 629 { |
| 630 if (unlikely (hb_object_is_inert (buffer))) |
| 631 return; |
| 632 |
| 633 buffer->props.language = language; |
| 634 } |
| 635 |
| 636 hb_language_t |
| 637 hb_buffer_get_language (hb_buffer_t *buffer) |
| 638 { |
| 639 return buffer->props.language; |
| 640 } |
| 641 |
| 642 |
| 643 void |
| 644 hb_buffer_reset (hb_buffer_t *buffer) |
| 645 { |
| 646 buffer->reset (); |
| 647 } |
| 648 |
| 649 hb_bool_t |
| 650 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) |
| 651 { |
| 652 return buffer->ensure (size); |
| 653 } |
| 654 |
| 655 hb_bool_t |
| 656 hb_buffer_allocation_successful (hb_buffer_t *buffer) |
| 657 { |
| 658 return !buffer->in_error; |
| 659 } |
| 660 |
| 661 void |
| 662 hb_buffer_add (hb_buffer_t *buffer, |
| 663 » hb_codepoint_t codepoint, |
| 664 » hb_mask_t mask, |
| 665 » unsigned int cluster) |
| 666 { |
| 667 buffer->add (codepoint, mask, cluster); |
| 668 } |
| 669 |
| 670 hb_bool_t |
| 671 hb_buffer_set_length (hb_buffer_t *buffer, |
| 672 » » unsigned int length) |
| 673 { |
| 674 if (!buffer->ensure (length)) |
| 675 return FALSE; |
| 676 |
| 677 /* Wipe the new space */ |
| 678 if (length > buffer->len) { |
| 679 memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length -
buffer->len)); |
| 680 if (buffer->have_positions) |
| 681 memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length -
buffer->len)); |
| 682 } |
| 683 |
| 684 buffer->len = length; |
| 685 return TRUE; |
| 686 } |
434 | 687 |
435 unsigned int | 688 unsigned int |
436 hb_buffer_get_length (hb_buffer_t *buffer) | 689 hb_buffer_get_length (hb_buffer_t *buffer) |
437 { | 690 { |
438 return buffer->len; | 691 return buffer->len; |
439 } | 692 } |
440 | 693 |
441 /* Return value valid as long as buffer not modified */ | 694 /* Return value valid as long as buffer not modified */ |
442 hb_glyph_info_t * | 695 hb_glyph_info_t * |
443 hb_buffer_get_glyph_infos (hb_buffer_t *buffer) | 696 hb_buffer_get_glyph_infos (hb_buffer_t *buffer, |
| 697 unsigned int *length) |
444 { | 698 { |
| 699 if (length) |
| 700 *length = buffer->len; |
| 701 |
445 return (hb_glyph_info_t *) buffer->info; | 702 return (hb_glyph_info_t *) buffer->info; |
446 } | 703 } |
447 | 704 |
448 /* Return value valid as long as buffer not modified */ | 705 /* Return value valid as long as buffer not modified */ |
449 hb_glyph_position_t * | 706 hb_glyph_position_t * |
450 hb_buffer_get_glyph_positions (hb_buffer_t *buffer) | 707 hb_buffer_get_glyph_positions (hb_buffer_t *buffer, |
| 708 unsigned int *length) |
451 { | 709 { |
452 if (!buffer->have_positions) | 710 if (!buffer->have_positions) |
453 hb_buffer_clear_positions (buffer); | 711 buffer->clear_positions (); |
| 712 |
| 713 if (length) |
| 714 *length = buffer->len; |
454 | 715 |
455 return (hb_glyph_position_t *) buffer->pos; | 716 return (hb_glyph_position_t *) buffer->pos; |
456 } | 717 } |
457 | 718 |
458 | |
459 static void | |
460 reverse_range (hb_buffer_t *buffer, | |
461 unsigned int start, | |
462 unsigned int end) | |
463 { | |
464 unsigned int i, j; | |
465 | |
466 for (i = start, j = end - 1; i < j; i++, j--) { | |
467 hb_glyph_info_t t; | |
468 | |
469 t = buffer->info[i]; | |
470 buffer->info[i] = buffer->info[j]; | |
471 buffer->info[j] = t; | |
472 } | |
473 | |
474 if (buffer->pos) { | |
475 for (i = 0, j = end - 1; i < j; i++, j--) { | |
476 hb_glyph_position_t t; | |
477 | |
478 t = buffer->pos[i]; | |
479 buffer->pos[i] = buffer->pos[j]; | |
480 buffer->pos[j] = t; | |
481 } | |
482 } | |
483 } | |
484 | |
485 void | 719 void |
486 hb_buffer_reverse (hb_buffer_t *buffer) | 720 hb_buffer_reverse (hb_buffer_t *buffer) |
487 { | 721 { |
488 if (unlikely (!buffer->len)) | 722 buffer->reverse (); |
489 return; | |
490 | |
491 reverse_range (buffer, 0, buffer->len); | |
492 } | 723 } |
493 | 724 |
494 void | 725 void |
495 hb_buffer_reverse_clusters (hb_buffer_t *buffer) | 726 hb_buffer_reverse_clusters (hb_buffer_t *buffer) |
496 { | 727 { |
497 unsigned int i, start, count, last_cluster; | 728 buffer->reverse_clusters (); |
498 | |
499 if (unlikely (!buffer->len)) | |
500 return; | |
501 | |
502 hb_buffer_reverse (buffer); | |
503 | |
504 count = buffer->len; | |
505 start = 0; | |
506 last_cluster = buffer->info[0].cluster; | |
507 for (i = 1; i < count; i++) { | |
508 if (last_cluster != buffer->info[i].cluster) { | |
509 reverse_range (buffer, start, i); | |
510 start = i; | |
511 last_cluster = buffer->info[i].cluster; | |
512 } | |
513 } | |
514 reverse_range (buffer, start, i); | |
515 } | 729 } |
516 | 730 |
| 731 void |
| 732 hb_buffer_guess_properties (hb_buffer_t *buffer) |
| 733 { |
| 734 buffer->guess_properties (); |
| 735 } |
517 | 736 |
518 #define ADD_UTF(T) \ | 737 #define ADD_UTF(T) \ |
519 HB_STMT_START { \ | 738 HB_STMT_START { \ |
| 739 if (text_length == -1) { \ |
| 740 text_length = 0; \ |
| 741 const T *p = (const T *) text; \ |
| 742 while (*p) { \ |
| 743 text_length++; \ |
| 744 p++; \ |
| 745 } \ |
| 746 } \ |
| 747 if (item_length == -1) \ |
| 748 item_length = text_length - item_offset; \ |
| 749 buffer->ensure (buffer->len + item_length * sizeof (T) / 4); \ |
520 const T *next = (const T *) text + item_offset; \ | 750 const T *next = (const T *) text + item_offset; \ |
521 const T *end = next + item_length; \ | 751 const T *end = next + item_length; \ |
522 while (next < end) { \ | 752 while (next < end) { \ |
523 hb_codepoint_t u; \ | 753 hb_codepoint_t u; \ |
524 const T *old_next = next; \ | 754 const T *old_next = next; \ |
525 next = UTF_NEXT (next, end, u); \ | 755 next = UTF_NEXT (next, end, u); \ |
526 » hb_buffer_add_glyph (buffer, u, 1, old_next - (const T *) text); \ | 756 » hb_buffer_add (buffer, u, 1, old_next - (const T *) text); \ |
527 } \ | 757 } \ |
528 } HB_STMT_END | 758 } HB_STMT_END |
529 | 759 |
530 | 760 |
531 #define UTF8_COMPUTE(Char, Mask, Len) \ | 761 #define UTF8_COMPUTE(Char, Mask, Len) \ |
532 if (Char < 128) { Len = 1; Mask = 0x7f; } \ | 762 if (Char < 128) { Len = 1; Mask = 0x7f; } \ |
533 else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \ | 763 else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \ |
534 else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \ | 764 else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \ |
535 else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \ | 765 else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \ |
536 else Len = 0; | 766 else Len = 0; |
537 | 767 |
538 static inline const uint8_t * | 768 static inline const uint8_t * |
539 hb_utf8_next (const uint8_t *text, | 769 hb_utf8_next (const uint8_t *text, |
540 const uint8_t *end, | 770 const uint8_t *end, |
541 hb_codepoint_t *unicode) | 771 hb_codepoint_t *unicode) |
542 { | 772 { |
543 uint8_t c = *text; | 773 uint8_t c = *text; |
544 unsigned int mask, len; | 774 unsigned int mask, len; |
545 | 775 |
546 /* TODO check for overlong sequences? also: optimize? */ | 776 /* TODO check for overlong sequences? */ |
547 | 777 |
548 UTF8_COMPUTE (c, mask, len); | 778 UTF8_COMPUTE (c, mask, len); |
549 if (unlikely (!len || (unsigned int) (end - text) < len)) { | 779 if (unlikely (!len || (unsigned int) (end - text) < len)) { |
550 *unicode = -1; | 780 *unicode = -1; |
551 return text + 1; | 781 return text + 1; |
552 } else { | 782 } else { |
553 hb_codepoint_t result; | 783 hb_codepoint_t result; |
554 unsigned int i; | 784 unsigned int i; |
555 result = c & mask; | 785 result = c & mask; |
556 for (i = 1; i < len; i++) | 786 for (i = 1; i < len; i++) |
557 { | 787 { |
558 if (unlikely ((text[i] & 0xc0) != 0x80)) | 788 if (unlikely ((text[i] & 0xc0) != 0x80)) |
559 { | 789 { |
560 *unicode = -1; | 790 *unicode = -1; |
561 return text + 1; | 791 return text + 1; |
562 } | 792 } |
563 result <<= 6; | 793 result <<= 6; |
564 result |= (text[i] & 0x3f); | 794 result |= (text[i] & 0x3f); |
565 } | 795 } |
566 *unicode = result; | 796 *unicode = result; |
567 return text + len; | 797 return text + len; |
568 } | 798 } |
569 } | 799 } |
570 | 800 |
571 void | 801 void |
572 hb_buffer_add_utf8 (hb_buffer_t *buffer, | 802 hb_buffer_add_utf8 (hb_buffer_t *buffer, |
573 const char *text, | 803 const char *text, |
574 » » unsigned int text_length HB_UNUSED, | 804 » » int text_length, |
575 unsigned int item_offset, | 805 unsigned int item_offset, |
576 » » unsigned int item_length) | 806 » » int item_length) |
577 { | 807 { |
578 #define UTF_NEXT(S, E, U) hb_utf8_next (S, E, &(U)) | 808 #define UTF_NEXT(S, E, U) hb_utf8_next (S, E, &(U)) |
579 ADD_UTF (uint8_t); | 809 ADD_UTF (uint8_t); |
580 #undef UTF_NEXT | 810 #undef UTF_NEXT |
581 } | 811 } |
582 | 812 |
583 static inline const uint16_t * | 813 static inline const uint16_t * |
584 hb_utf16_next (const uint16_t *text, | 814 hb_utf16_next (const uint16_t *text, |
585 const uint16_t *end, | 815 const uint16_t *end, |
586 hb_codepoint_t *unicode) | 816 hb_codepoint_t *unicode) |
587 { | 817 { |
588 uint16_t c = *text++; | 818 uint16_t c = *text++; |
589 | 819 |
590 if (unlikely (c >= 0xd800 && c < 0xdc00)) { | 820 if (unlikely (c >= 0xd800 && c < 0xdc00)) { |
591 /* high surrogate */ | 821 /* high surrogate */ |
592 uint16_t l; | 822 uint16_t l; |
593 if (text < end && ((l = *text), unlikely (l >= 0xdc00 && l < 0xe000))) { | 823 if (text < end && ((l = *text), likely (l >= 0xdc00 && l < 0xe000))) { |
594 /* low surrogate */ | 824 /* low surrogate */ |
595 *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x100
00); | 825 *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x100
00); |
596 text++; | 826 text++; |
597 } else | 827 } else |
598 *unicode = -1; | 828 *unicode = -1; |
599 } else | 829 } else |
600 *unicode = c; | 830 *unicode = c; |
601 | 831 |
602 return text; | 832 return text; |
603 } | 833 } |
604 | 834 |
605 void | 835 void |
606 hb_buffer_add_utf16 (hb_buffer_t *buffer, | 836 hb_buffer_add_utf16 (hb_buffer_t *buffer, |
607 const uint16_t *text, | 837 const uint16_t *text, |
608 » » unsigned int text_length HB_UNUSED, | 838 » » int text_length, |
609 unsigned int item_offset, | 839 unsigned int item_offset, |
610 » » unsigned int item_length) | 840 » » int item_length) |
611 { | 841 { |
612 #define UTF_NEXT(S, E, U) hb_utf16_next (S, E, &(U)) | 842 #define UTF_NEXT(S, E, U) hb_utf16_next (S, E, &(U)) |
613 ADD_UTF (uint16_t); | 843 ADD_UTF (uint16_t); |
614 #undef UTF_NEXT | 844 #undef UTF_NEXT |
615 } | 845 } |
616 | 846 |
617 void | 847 void |
618 hb_buffer_add_utf32 (hb_buffer_t *buffer, | 848 hb_buffer_add_utf32 (hb_buffer_t *buffer, |
619 const uint32_t *text, | 849 const uint32_t *text, |
620 » » unsigned int text_length HB_UNUSED, | 850 » » int text_length, |
621 unsigned int item_offset, | 851 unsigned int item_offset, |
622 » » unsigned int item_length) | 852 » » int item_length) |
623 { | 853 { |
624 #define UTF_NEXT(S, E, U) ((U) = *(S), (S)+1) | 854 #define UTF_NEXT(S, E, U) ((U) = *(S), (S)+1) |
625 ADD_UTF (uint32_t); | 855 ADD_UTF (uint32_t); |
626 #undef UTF_NEXT | 856 #undef UTF_NEXT |
627 } | 857 } |
628 | 858 |
629 | 859 |
630 HB_END_DECLS | |
OLD | NEW |