1 /***************************************************************************/ 2 /* */ 3 /* ftgloadr.c */ 4 /* */ 5 /* The FreeType glyph loader (body). */ 6 /* */ 7 /* Copyright 2002, 2003, 2004, 2005, 2006 by */ 8 /* David Turner, Robert Wilhelm, and Werner Lemberg */ 9 /* */ 10 /* This file is part of the FreeType project, and may only be used, */ 11 /* modified, and distributed under the terms of the FreeType project */ 12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13 /* this file you indicate that you have read the license and */ 14 /* understand and accept it fully. */ 15 /* */ 16 /***************************************************************************/ 17 18 19 #include <ft2build.h> 20 #include FT_INTERNAL_GLYPH_LOADER_H 21 #include FT_INTERNAL_MEMORY_H 22 #include FT_INTERNAL_OBJECTS_H 23 24 #undef FT_COMPONENT 25 #define FT_COMPONENT trace_gloader 26 27 28 /*************************************************************************/ 29 /*************************************************************************/ 30 /*************************************************************************/ 31 /***** *****/ 32 /***** *****/ 33 /***** G L Y P H L O A D E R *****/ 34 /***** *****/ 35 /***** *****/ 36 /*************************************************************************/ 37 /*************************************************************************/ 38 /*************************************************************************/ 39 40 /*************************************************************************/ 41 /* */ 42 /* The glyph loader is a simple object which is used to load a set of */ 43 /* glyphs easily. It is critical for the correct loading of composites. */ 44 /* */ 45 /* Ideally, one can see it as a stack of abstract `glyph' objects. */ 46 /* */ 47 /* loader.base Is really the bottom of the stack. It describes a */ 48 /* single glyph image made of the juxtaposition of */ 49 /* several glyphs (those `in the stack'). */ 50 /* */ 51 /* loader.current Describes the top of the stack, on which a new */ 52 /* glyph can be loaded. */ 53 /* */ 54 /* Rewind Clears the stack. */ 55 /* Prepare Set up `loader.current' for addition of a new glyph */ 56 /* image. */ 57 /* Add Add the `current' glyph image to the `base' one, */ 58 /* and prepare for another one. */ 59 /* */ 60 /* The glyph loader is now a base object. Each driver used to */ 61 /* re-implement it in one way or the other, which wasted code and */ 62 /* energy. */ 63 /* */ 64 /*************************************************************************/ 65 66 67 /* create a new glyph loader */ 68 FT_BASE_DEF( FT_Error ) FT_GlyphLoader_New(FT_Memory memory,FT_GlyphLoader * aloader)69 FT_GlyphLoader_New( FT_Memory memory, 70 FT_GlyphLoader *aloader ) 71 { 72 FT_GlyphLoader loader; 73 FT_Error error; 74 75 76 if ( !FT_NEW( loader ) ) 77 { 78 loader->memory = memory; 79 *aloader = loader; 80 } 81 return error; 82 } 83 84 85 /* rewind the glyph loader - reset counters to 0 */ 86 FT_BASE_DEF( void ) FT_GlyphLoader_Rewind(FT_GlyphLoader loader)87 FT_GlyphLoader_Rewind( FT_GlyphLoader loader ) 88 { 89 FT_GlyphLoad base = &loader->base; 90 FT_GlyphLoad current = &loader->current; 91 92 93 base->outline.n_points = 0; 94 base->outline.n_contours = 0; 95 base->num_subglyphs = 0; 96 97 *current = *base; 98 } 99 100 101 /* reset the glyph loader, frees all allocated tables */ 102 /* and starts from zero */ 103 FT_BASE_DEF( void ) FT_GlyphLoader_Reset(FT_GlyphLoader loader)104 FT_GlyphLoader_Reset( FT_GlyphLoader loader ) 105 { 106 FT_Memory memory = loader->memory; 107 108 109 FT_FREE( loader->base.outline.points ); 110 FT_FREE( loader->base.outline.tags ); 111 FT_FREE( loader->base.outline.contours ); 112 FT_FREE( loader->base.extra_points ); 113 FT_FREE( loader->base.subglyphs ); 114 115 loader->base.extra_points2 = NULL; 116 117 loader->max_points = 0; 118 loader->max_contours = 0; 119 loader->max_subglyphs = 0; 120 121 FT_GlyphLoader_Rewind( loader ); 122 } 123 124 125 /* delete a glyph loader */ 126 FT_BASE_DEF( void ) FT_GlyphLoader_Done(FT_GlyphLoader loader)127 FT_GlyphLoader_Done( FT_GlyphLoader loader ) 128 { 129 if ( loader ) 130 { 131 FT_Memory memory = loader->memory; 132 133 134 FT_GlyphLoader_Reset( loader ); 135 FT_FREE( loader ); 136 } 137 } 138 139 140 /* re-adjust the `current' outline fields */ 141 static void FT_GlyphLoader_Adjust_Points(FT_GlyphLoader loader)142 FT_GlyphLoader_Adjust_Points( FT_GlyphLoader loader ) 143 { 144 FT_Outline* base = &loader->base.outline; 145 FT_Outline* current = &loader->current.outline; 146 147 148 current->points = base->points + base->n_points; 149 current->tags = base->tags + base->n_points; 150 current->contours = base->contours + base->n_contours; 151 152 /* handle extra points table - if any */ 153 if ( loader->use_extra ) 154 { 155 loader->current.extra_points = loader->base.extra_points + 156 base->n_points; 157 158 loader->current.extra_points2 = loader->base.extra_points2 + 159 base->n_points; 160 } 161 } 162 163 164 FT_BASE_DEF( FT_Error ) FT_GlyphLoader_CreateExtra(FT_GlyphLoader loader)165 FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader ) 166 { 167 FT_Error error; 168 FT_Memory memory = loader->memory; 169 170 171 if ( !FT_NEW_ARRAY( loader->base.extra_points, 2 * loader->max_points ) ) 172 { 173 loader->use_extra = 1; 174 loader->base.extra_points2 = loader->base.extra_points + 175 loader->max_points; 176 177 FT_GlyphLoader_Adjust_Points( loader ); 178 } 179 return error; 180 } 181 182 183 /* re-adjust the `current' subglyphs field */ 184 static void FT_GlyphLoader_Adjust_Subglyphs(FT_GlyphLoader loader)185 FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader loader ) 186 { 187 FT_GlyphLoad base = &loader->base; 188 FT_GlyphLoad current = &loader->current; 189 190 191 current->subglyphs = base->subglyphs + base->num_subglyphs; 192 } 193 194 195 /* Ensure that we can add `n_points' and `n_contours' to our glyph. */ 196 /* This function reallocates its outline tables if necessary. Note that */ 197 /* it DOESN'T change the number of points within the loader! */ 198 /* */ 199 FT_BASE_DEF( FT_Error ) FT_GlyphLoader_CheckPoints(FT_GlyphLoader loader,FT_UInt n_points,FT_UInt n_contours)200 FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, 201 FT_UInt n_points, 202 FT_UInt n_contours ) 203 { 204 FT_Memory memory = loader->memory; 205 FT_Error error = FT_Err_Ok; 206 FT_Outline* base = &loader->base.outline; 207 FT_Outline* current = &loader->current.outline; 208 FT_Bool adjust = 0; 209 210 FT_UInt new_max, old_max; 211 212 213 /* check points & tags */ 214 new_max = base->n_points + current->n_points + n_points; 215 old_max = loader->max_points; 216 217 if ( new_max > old_max ) 218 { 219 new_max = FT_PAD_CEIL( new_max, 8 ); 220 221 if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) || 222 FT_RENEW_ARRAY( base->tags, old_max, new_max ) ) 223 goto Exit; 224 225 if ( loader->use_extra ) 226 { 227 if ( FT_RENEW_ARRAY( loader->base.extra_points, 228 old_max * 2, new_max * 2 ) ) 229 goto Exit; 230 231 FT_ARRAY_MOVE( loader->base.extra_points + new_max, 232 loader->base.extra_points + old_max, 233 old_max ); 234 235 loader->base.extra_points2 = loader->base.extra_points + new_max; 236 } 237 238 adjust = 1; 239 loader->max_points = new_max; 240 } 241 242 /* check contours */ 243 old_max = loader->max_contours; 244 new_max = base->n_contours + current->n_contours + 245 n_contours; 246 if ( new_max > old_max ) 247 { 248 new_max = FT_PAD_CEIL( new_max, 4 ); 249 if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) ) 250 goto Exit; 251 252 adjust = 1; 253 loader->max_contours = new_max; 254 } 255 256 if ( adjust ) 257 FT_GlyphLoader_Adjust_Points( loader ); 258 259 Exit: 260 return error; 261 } 262 263 264 /* Ensure that we can add `n_subglyphs' to our glyph. this function */ 265 /* reallocates its subglyphs table if necessary. Note that it DOES */ 266 /* NOT change the number of subglyphs within the loader! */ 267 /* */ 268 FT_BASE_DEF( FT_Error ) FT_GlyphLoader_CheckSubGlyphs(FT_GlyphLoader loader,FT_UInt n_subs)269 FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, 270 FT_UInt n_subs ) 271 { 272 FT_Memory memory = loader->memory; 273 FT_Error error = FT_Err_Ok; 274 FT_UInt new_max, old_max; 275 276 FT_GlyphLoad base = &loader->base; 277 FT_GlyphLoad current = &loader->current; 278 279 280 new_max = base->num_subglyphs + current->num_subglyphs + n_subs; 281 old_max = loader->max_subglyphs; 282 if ( new_max > old_max ) 283 { 284 new_max = FT_PAD_CEIL( new_max, 2 ); 285 if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) ) 286 goto Exit; 287 288 loader->max_subglyphs = new_max; 289 290 FT_GlyphLoader_Adjust_Subglyphs( loader ); 291 } 292 293 Exit: 294 return error; 295 } 296 297 298 /* prepare loader for the addition of a new glyph on top of the base one */ 299 FT_BASE_DEF( void ) FT_GlyphLoader_Prepare(FT_GlyphLoader loader)300 FT_GlyphLoader_Prepare( FT_GlyphLoader loader ) 301 { 302 FT_GlyphLoad current = &loader->current; 303 304 305 current->outline.n_points = 0; 306 current->outline.n_contours = 0; 307 current->num_subglyphs = 0; 308 309 FT_GlyphLoader_Adjust_Points ( loader ); 310 FT_GlyphLoader_Adjust_Subglyphs( loader ); 311 } 312 313 314 /* add current glyph to the base image - and prepare for another */ 315 FT_BASE_DEF( void ) FT_GlyphLoader_Add(FT_GlyphLoader loader)316 FT_GlyphLoader_Add( FT_GlyphLoader loader ) 317 { 318 FT_GlyphLoad base; 319 FT_GlyphLoad current; 320 321 FT_UInt n_curr_contours; 322 FT_UInt n_base_points; 323 FT_UInt n; 324 325 326 if ( !loader ) 327 return; 328 329 base = &loader->base; 330 current = &loader->current; 331 332 n_curr_contours = current->outline.n_contours; 333 n_base_points = base->outline.n_points; 334 335 base->outline.n_points = 336 (short)( base->outline.n_points + current->outline.n_points ); 337 base->outline.n_contours = 338 (short)( base->outline.n_contours + current->outline.n_contours ); 339 340 base->num_subglyphs += current->num_subglyphs; 341 342 /* adjust contours count in newest outline */ 343 for ( n = 0; n < n_curr_contours; n++ ) 344 current->outline.contours[n] = 345 (short)( current->outline.contours[n] + n_base_points ); 346 347 /* prepare for another new glyph image */ 348 FT_GlyphLoader_Prepare( loader ); 349 } 350 351 352 FT_BASE_DEF( FT_Error ) FT_GlyphLoader_CopyPoints(FT_GlyphLoader target,FT_GlyphLoader source)353 FT_GlyphLoader_CopyPoints( FT_GlyphLoader target, 354 FT_GlyphLoader source ) 355 { 356 FT_Error error; 357 FT_UInt num_points = source->base.outline.n_points; 358 FT_UInt num_contours = source->base.outline.n_contours; 359 360 361 error = FT_GlyphLoader_CheckPoints( target, num_points, num_contours ); 362 if ( !error ) 363 { 364 FT_Outline* out = &target->base.outline; 365 FT_Outline* in = &source->base.outline; 366 367 368 FT_ARRAY_COPY( out->points, in->points, 369 num_points ); 370 FT_ARRAY_COPY( out->tags, in->tags, 371 num_points ); 372 FT_ARRAY_COPY( out->contours, in->contours, 373 num_contours ); 374 375 /* do we need to copy the extra points? */ 376 if ( target->use_extra && source->use_extra ) 377 { 378 FT_ARRAY_COPY( target->base.extra_points, source->base.extra_points, 379 num_points ); 380 FT_ARRAY_COPY( target->base.extra_points2, source->base.extra_points2, 381 num_points ); 382 } 383 384 out->n_points = (short)num_points; 385 out->n_contours = (short)num_contours; 386 387 FT_GlyphLoader_Adjust_Points( target ); 388 } 389 390 return error; 391 } 392 393 394 /* END */ 395