/***************************************************************************/ | |
/* */ | |
/* ftgloadr.c */ | |
/* */ | |
/* The FreeType glyph loader (body). */ | |
/* */ | |
/* Copyright 2002-2015 by */ | |
/* David Turner, Robert Wilhelm, and Werner Lemberg */ | |
/* */ | |
/* This file is part of the FreeType project, and may only be used, */ | |
/* modified, and distributed under the terms of the FreeType project */ | |
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ | |
/* this file you indicate that you have read the license and */ | |
/* understand and accept it fully. */ | |
/* */ | |
/***************************************************************************/ | |
#include <ft2build.h> | |
#include FT_INTERNAL_DEBUG_H | |
#include FT_INTERNAL_GLYPH_LOADER_H | |
#include FT_INTERNAL_MEMORY_H | |
#include FT_INTERNAL_OBJECTS_H | |
#undef FT_COMPONENT | |
#define FT_COMPONENT trace_gloader | |
/*************************************************************************/ | |
/*************************************************************************/ | |
/*************************************************************************/ | |
/***** *****/ | |
/***** *****/ | |
/***** G L Y P H L O A D E R *****/ | |
/***** *****/ | |
/***** *****/ | |
/*************************************************************************/ | |
/*************************************************************************/ | |
/*************************************************************************/ | |
/*************************************************************************/ | |
/* */ | |
/* The glyph loader is a simple object which is used to load a set of */ | |
/* glyphs easily. It is critical for the correct loading of composites. */ | |
/* */ | |
/* Ideally, one can see it as a stack of abstract `glyph' objects. */ | |
/* */ | |
/* loader.base Is really the bottom of the stack. It describes a */ | |
/* single glyph image made of the juxtaposition of */ | |
/* several glyphs (those `in the stack'). */ | |
/* */ | |
/* loader.current Describes the top of the stack, on which a new */ | |
/* glyph can be loaded. */ | |
/* */ | |
/* Rewind Clears the stack. */ | |
/* Prepare Set up `loader.current' for addition of a new glyph */ | |
/* image. */ | |
/* Add Add the `current' glyph image to the `base' one, */ | |
/* and prepare for another one. */ | |
/* */ | |
/* The glyph loader is now a base object. Each driver used to */ | |
/* re-implement it in one way or the other, which wasted code and */ | |
/* energy. */ | |
/* */ | |
/*************************************************************************/ | |
/* create a new glyph loader */ | |
FT_BASE_DEF( FT_Error ) | |
FT_GlyphLoader_New( FT_Memory memory, | |
FT_GlyphLoader *aloader ) | |
{ | |
FT_GlyphLoader loader = NULL; | |
FT_Error error; | |
if ( !FT_NEW( loader ) ) | |
{ | |
loader->memory = memory; | |
*aloader = loader; | |
} | |
return error; | |
} | |
/* rewind the glyph loader - reset counters to 0 */ | |
FT_BASE_DEF( void ) | |
FT_GlyphLoader_Rewind( FT_GlyphLoader loader ) | |
{ | |
FT_GlyphLoad base = &loader->base; | |
FT_GlyphLoad current = &loader->current; | |
base->outline.n_points = 0; | |
base->outline.n_contours = 0; | |
base->num_subglyphs = 0; | |
*current = *base; | |
} | |
/* reset the glyph loader, frees all allocated tables */ | |
/* and starts from zero */ | |
FT_BASE_DEF( void ) | |
FT_GlyphLoader_Reset( FT_GlyphLoader loader ) | |
{ | |
FT_Memory memory = loader->memory; | |
FT_FREE( loader->base.outline.points ); | |
FT_FREE( loader->base.outline.tags ); | |
FT_FREE( loader->base.outline.contours ); | |
FT_FREE( loader->base.extra_points ); | |
FT_FREE( loader->base.subglyphs ); | |
loader->base.extra_points2 = NULL; | |
loader->max_points = 0; | |
loader->max_contours = 0; | |
loader->max_subglyphs = 0; | |
FT_GlyphLoader_Rewind( loader ); | |
} | |
/* delete a glyph loader */ | |
FT_BASE_DEF( void ) | |
FT_GlyphLoader_Done( FT_GlyphLoader loader ) | |
{ | |
if ( loader ) | |
{ | |
FT_Memory memory = loader->memory; | |
FT_GlyphLoader_Reset( loader ); | |
FT_FREE( loader ); | |
} | |
} | |
/* re-adjust the `current' outline fields */ | |
static void | |
FT_GlyphLoader_Adjust_Points( FT_GlyphLoader loader ) | |
{ | |
FT_Outline* base = &loader->base.outline; | |
FT_Outline* current = &loader->current.outline; | |
current->points = base->points + base->n_points; | |
current->tags = base->tags + base->n_points; | |
current->contours = base->contours + base->n_contours; | |
/* handle extra points table - if any */ | |
if ( loader->use_extra ) | |
{ | |
loader->current.extra_points = loader->base.extra_points + | |
base->n_points; | |
loader->current.extra_points2 = loader->base.extra_points2 + | |
base->n_points; | |
} | |
} | |
FT_BASE_DEF( FT_Error ) | |
FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader ) | |
{ | |
FT_Error error; | |
FT_Memory memory = loader->memory; | |
if ( !FT_NEW_ARRAY( loader->base.extra_points, 2 * loader->max_points ) ) | |
{ | |
loader->use_extra = 1; | |
loader->base.extra_points2 = loader->base.extra_points + | |
loader->max_points; | |
FT_GlyphLoader_Adjust_Points( loader ); | |
} | |
return error; | |
} | |
/* re-adjust the `current' subglyphs field */ | |
static void | |
FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader loader ) | |
{ | |
FT_GlyphLoad base = &loader->base; | |
FT_GlyphLoad current = &loader->current; | |
current->subglyphs = base->subglyphs + base->num_subglyphs; | |
} | |
/* Ensure that we can add `n_points' and `n_contours' to our glyph. */ | |
/* This function reallocates its outline tables if necessary. Note that */ | |
/* it DOESN'T change the number of points within the loader! */ | |
/* */ | |
FT_BASE_DEF( FT_Error ) | |
FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, | |
FT_UInt n_points, | |
FT_UInt n_contours ) | |
{ | |
FT_Memory memory = loader->memory; | |
FT_Error error = FT_Err_Ok; | |
FT_Outline* base = &loader->base.outline; | |
FT_Outline* current = &loader->current.outline; | |
FT_Bool adjust = 0; | |
FT_UInt new_max, old_max; | |
/* check points & tags */ | |
new_max = (FT_UInt)base->n_points + (FT_UInt)current->n_points + | |
n_points; | |
old_max = loader->max_points; | |
if ( new_max > old_max ) | |
{ | |
new_max = FT_PAD_CEIL( new_max, 8 ); | |
if ( new_max > FT_OUTLINE_POINTS_MAX ) | |
return FT_THROW( Array_Too_Large ); | |
if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) || | |
FT_RENEW_ARRAY( base->tags, old_max, new_max ) ) | |
goto Exit; | |
if ( loader->use_extra ) | |
{ | |
if ( FT_RENEW_ARRAY( loader->base.extra_points, | |
old_max * 2, new_max * 2 ) ) | |
goto Exit; | |
FT_ARRAY_MOVE( loader->base.extra_points + new_max, | |
loader->base.extra_points + old_max, | |
old_max ); | |
loader->base.extra_points2 = loader->base.extra_points + new_max; | |
} | |
adjust = 1; | |
loader->max_points = new_max; | |
} | |
/* check contours */ | |
old_max = loader->max_contours; | |
new_max = (FT_UInt)base->n_contours + (FT_UInt)current->n_contours + | |
n_contours; | |
if ( new_max > old_max ) | |
{ | |
new_max = FT_PAD_CEIL( new_max, 4 ); | |
if ( new_max > FT_OUTLINE_CONTOURS_MAX ) | |
return FT_THROW( Array_Too_Large ); | |
if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) ) | |
goto Exit; | |
adjust = 1; | |
loader->max_contours = new_max; | |
} | |
if ( adjust ) | |
FT_GlyphLoader_Adjust_Points( loader ); | |
Exit: | |
if ( error ) | |
FT_GlyphLoader_Reset( loader ); | |
return error; | |
} | |
/* Ensure that we can add `n_subglyphs' to our glyph. this function */ | |
/* reallocates its subglyphs table if necessary. Note that it DOES */ | |
/* NOT change the number of subglyphs within the loader! */ | |
/* */ | |
FT_BASE_DEF( FT_Error ) | |
FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, | |
FT_UInt n_subs ) | |
{ | |
FT_Memory memory = loader->memory; | |
FT_Error error = FT_Err_Ok; | |
FT_UInt new_max, old_max; | |
FT_GlyphLoad base = &loader->base; | |
FT_GlyphLoad current = &loader->current; | |
new_max = base->num_subglyphs + current->num_subglyphs + n_subs; | |
old_max = loader->max_subglyphs; | |
if ( new_max > old_max ) | |
{ | |
new_max = FT_PAD_CEIL( new_max, 2 ); | |
if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) ) | |
goto Exit; | |
loader->max_subglyphs = new_max; | |
FT_GlyphLoader_Adjust_Subglyphs( loader ); | |
} | |
Exit: | |
return error; | |
} | |
/* prepare loader for the addition of a new glyph on top of the base one */ | |
FT_BASE_DEF( void ) | |
FT_GlyphLoader_Prepare( FT_GlyphLoader loader ) | |
{ | |
FT_GlyphLoad current = &loader->current; | |
current->outline.n_points = 0; | |
current->outline.n_contours = 0; | |
current->num_subglyphs = 0; | |
FT_GlyphLoader_Adjust_Points ( loader ); | |
FT_GlyphLoader_Adjust_Subglyphs( loader ); | |
} | |
/* add current glyph to the base image -- and prepare for another */ | |
FT_BASE_DEF( void ) | |
FT_GlyphLoader_Add( FT_GlyphLoader loader ) | |
{ | |
FT_GlyphLoad base; | |
FT_GlyphLoad current; | |
FT_Int n_curr_contours; | |
FT_Int n_base_points; | |
FT_Int n; | |
if ( !loader ) | |
return; | |
base = &loader->base; | |
current = &loader->current; | |
n_curr_contours = current->outline.n_contours; | |
n_base_points = base->outline.n_points; | |
base->outline.n_points = | |
(short)( base->outline.n_points + current->outline.n_points ); | |
base->outline.n_contours = | |
(short)( base->outline.n_contours + current->outline.n_contours ); | |
base->num_subglyphs += current->num_subglyphs; | |
/* adjust contours count in newest outline */ | |
for ( n = 0; n < n_curr_contours; n++ ) | |
current->outline.contours[n] = | |
(short)( current->outline.contours[n] + n_base_points ); | |
/* prepare for another new glyph image */ | |
FT_GlyphLoader_Prepare( loader ); | |
} | |
FT_BASE_DEF( FT_Error ) | |
FT_GlyphLoader_CopyPoints( FT_GlyphLoader target, | |
FT_GlyphLoader source ) | |
{ | |
FT_Error error; | |
FT_UInt num_points = (FT_UInt)source->base.outline.n_points; | |
FT_UInt num_contours = (FT_UInt)source->base.outline.n_contours; | |
error = FT_GlyphLoader_CheckPoints( target, num_points, num_contours ); | |
if ( !error ) | |
{ | |
FT_Outline* out = &target->base.outline; | |
FT_Outline* in = &source->base.outline; | |
FT_ARRAY_COPY( out->points, in->points, | |
num_points ); | |
FT_ARRAY_COPY( out->tags, in->tags, | |
num_points ); | |
FT_ARRAY_COPY( out->contours, in->contours, | |
num_contours ); | |
/* do we need to copy the extra points? */ | |
if ( target->use_extra && source->use_extra ) | |
{ | |
FT_ARRAY_COPY( target->base.extra_points, source->base.extra_points, | |
num_points ); | |
FT_ARRAY_COPY( target->base.extra_points2, source->base.extra_points2, | |
num_points ); | |
} | |
out->n_points = (short)num_points; | |
out->n_contours = (short)num_contours; | |
FT_GlyphLoader_Adjust_Points( target ); | |
} | |
return error; | |
} | |
/* END */ |