1 /***************************************************************************/ 2 /* */ 3 /* ftgloadr.c */ 4 /* */ 5 /* The FreeType glyph loader (body). */ 6 /* */ 7 /* Copyright 2002, 2003, 2004, 2005, 2006, 2010 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 = NULL; 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 ( new_max > FT_OUTLINE_POINTS_MAX ) 222 return FT_Err_Array_Too_Large; 223 224 if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) || 225 FT_RENEW_ARRAY( base->tags, old_max, new_max ) ) 226 goto Exit; 227 228 if ( loader->use_extra ) 229 { 230 if ( FT_RENEW_ARRAY( loader->base.extra_points, 231 old_max * 2, new_max * 2 ) ) 232 goto Exit; 233 234 FT_ARRAY_MOVE( loader->base.extra_points + new_max, 235 loader->base.extra_points + old_max, 236 old_max ); 237 238 loader->base.extra_points2 = loader->base.extra_points + new_max; 239 } 240 241 adjust = 1; 242 loader->max_points = new_max; 243 } 244 245 /* check contours */ 246 old_max = loader->max_contours; 247 new_max = base->n_contours + current->n_contours + 248 n_contours; 249 if ( new_max > old_max ) 250 { 251 new_max = FT_PAD_CEIL( new_max, 4 ); 252 253 if ( new_max > FT_OUTLINE_CONTOURS_MAX ) 254 return FT_Err_Array_Too_Large; 255 256 if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) ) 257 goto Exit; 258 259 adjust = 1; 260 loader->max_contours = new_max; 261 } 262 263 if ( adjust ) 264 FT_GlyphLoader_Adjust_Points( loader ); 265 266 Exit: 267 return error; 268 } 269 270 271 /* Ensure that we can add `n_subglyphs' to our glyph. this function */ 272 /* reallocates its subglyphs table if necessary. Note that it DOES */ 273 /* NOT change the number of subglyphs within the loader! */ 274 /* */ 275 FT_BASE_DEF( FT_Error ) FT_GlyphLoader_CheckSubGlyphs(FT_GlyphLoader loader,FT_UInt n_subs)276 FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, 277 FT_UInt n_subs ) 278 { 279 FT_Memory memory = loader->memory; 280 FT_Error error = FT_Err_Ok; 281 FT_UInt new_max, old_max; 282 283 FT_GlyphLoad base = &loader->base; 284 FT_GlyphLoad current = &loader->current; 285 286 287 new_max = base->num_subglyphs + current->num_subglyphs + n_subs; 288 old_max = loader->max_subglyphs; 289 if ( new_max > old_max ) 290 { 291 new_max = FT_PAD_CEIL( new_max, 2 ); 292 if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) ) 293 goto Exit; 294 295 loader->max_subglyphs = new_max; 296 297 FT_GlyphLoader_Adjust_Subglyphs( loader ); 298 } 299 300 Exit: 301 return error; 302 } 303 304 305 /* prepare loader for the addition of a new glyph on top of the base one */ 306 FT_BASE_DEF( void ) FT_GlyphLoader_Prepare(FT_GlyphLoader loader)307 FT_GlyphLoader_Prepare( FT_GlyphLoader loader ) 308 { 309 FT_GlyphLoad current = &loader->current; 310 311 312 current->outline.n_points = 0; 313 current->outline.n_contours = 0; 314 current->num_subglyphs = 0; 315 316 FT_GlyphLoader_Adjust_Points ( loader ); 317 FT_GlyphLoader_Adjust_Subglyphs( loader ); 318 } 319 320 321 /* add current glyph to the base image - and prepare for another */ 322 FT_BASE_DEF( void ) FT_GlyphLoader_Add(FT_GlyphLoader loader)323 FT_GlyphLoader_Add( FT_GlyphLoader loader ) 324 { 325 FT_GlyphLoad base; 326 FT_GlyphLoad current; 327 328 FT_UInt n_curr_contours; 329 FT_UInt n_base_points; 330 FT_UInt n; 331 332 333 if ( !loader ) 334 return; 335 336 base = &loader->base; 337 current = &loader->current; 338 339 n_curr_contours = current->outline.n_contours; 340 n_base_points = base->outline.n_points; 341 342 base->outline.n_points = 343 (short)( base->outline.n_points + current->outline.n_points ); 344 base->outline.n_contours = 345 (short)( base->outline.n_contours + current->outline.n_contours ); 346 347 base->num_subglyphs += current->num_subglyphs; 348 349 /* adjust contours count in newest outline */ 350 for ( n = 0; n < n_curr_contours; n++ ) 351 current->outline.contours[n] = 352 (short)( current->outline.contours[n] + n_base_points ); 353 354 /* prepare for another new glyph image */ 355 FT_GlyphLoader_Prepare( loader ); 356 } 357 358 359 FT_BASE_DEF( FT_Error ) FT_GlyphLoader_CopyPoints(FT_GlyphLoader target,FT_GlyphLoader source)360 FT_GlyphLoader_CopyPoints( FT_GlyphLoader target, 361 FT_GlyphLoader source ) 362 { 363 FT_Error error; 364 FT_UInt num_points = source->base.outline.n_points; 365 FT_UInt num_contours = source->base.outline.n_contours; 366 367 368 error = FT_GlyphLoader_CheckPoints( target, num_points, num_contours ); 369 if ( !error ) 370 { 371 FT_Outline* out = &target->base.outline; 372 FT_Outline* in = &source->base.outline; 373 374 375 FT_ARRAY_COPY( out->points, in->points, 376 num_points ); 377 FT_ARRAY_COPY( out->tags, in->tags, 378 num_points ); 379 FT_ARRAY_COPY( out->contours, in->contours, 380 num_contours ); 381 382 /* do we need to copy the extra points? */ 383 if ( target->use_extra && source->use_extra ) 384 { 385 FT_ARRAY_COPY( target->base.extra_points, source->base.extra_points, 386 num_points ); 387 FT_ARRAY_COPY( target->base.extra_points2, source->base.extra_points2, 388 num_points ); 389 } 390 391 out->n_points = (short)num_points; 392 out->n_contours = (short)num_contours; 393 394 FT_GlyphLoader_Adjust_Points( target ); 395 } 396 397 return error; 398 } 399 400 401 /* END */ 402