| 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 |