/***************************************************************************/ | |
/* */ | |
/* afglobal.c */ | |
/* */ | |
/* Auto-fitter routines to compute global hinting values (body). */ | |
/* */ | |
/* Copyright 2003, 2004, 2005, 2006, 2007, 2008 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 "afglobal.h" | |
#include "afdummy.h" | |
#include "aflatin.h" | |
#include "afcjk.h" | |
#include "afindic.h" | |
#include "aferrors.h" | |
#ifdef FT_OPTION_AUTOFIT2 | |
#include "aflatin2.h" | |
#endif | |
/* populate this list when you add new scripts */ | |
static AF_ScriptClass const af_script_classes[] = | |
{ | |
&af_dummy_script_class, | |
#ifdef FT_OPTION_AUTOFIT2 | |
&af_latin2_script_class, | |
#endif | |
&af_latin_script_class, | |
&af_cjk_script_class, | |
&af_indic_script_class, | |
NULL /* do not remove */ | |
}; | |
/* index of default script in `af_script_classes' */ | |
#define AF_SCRIPT_LIST_DEFAULT 2 | |
/* indicates an uncovered glyph */ | |
#define AF_SCRIPT_LIST_NONE 255 | |
/* | |
* Note that glyph_scripts[] is used to map each glyph into | |
* an index into the `af_script_classes' array. | |
* | |
*/ | |
typedef struct AF_FaceGlobalsRec_ | |
{ | |
FT_Face face; | |
FT_UInt glyph_count; /* same as face->num_glyphs */ | |
FT_Byte* glyph_scripts; | |
AF_ScriptMetrics metrics[AF_SCRIPT_MAX]; | |
} AF_FaceGlobalsRec; | |
/* Compute the script index of each glyph within a given face. */ | |
static FT_Error | |
af_face_globals_compute_script_coverage( AF_FaceGlobals globals ) | |
{ | |
FT_Error error = AF_Err_Ok; | |
FT_Face face = globals->face; | |
FT_CharMap old_charmap = face->charmap; | |
FT_Byte* gscripts = globals->glyph_scripts; | |
FT_UInt ss; | |
/* the value 255 means `uncovered glyph' */ | |
FT_MEM_SET( globals->glyph_scripts, | |
AF_SCRIPT_LIST_NONE, | |
globals->glyph_count ); | |
error = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); | |
if ( error ) | |
{ | |
/* | |
* Ignore this error; we simply use the default script. | |
* XXX: Shouldn't we rather disable hinting? | |
*/ | |
error = AF_Err_Ok; | |
goto Exit; | |
} | |
/* scan each script in a Unicode charmap */ | |
for ( ss = 0; af_script_classes[ss]; ss++ ) | |
{ | |
AF_ScriptClass clazz = af_script_classes[ss]; | |
AF_Script_UniRange range; | |
if ( clazz->script_uni_ranges == NULL ) | |
continue; | |
/* | |
* Scan all unicode points in the range and set the corresponding | |
* glyph script index. | |
*/ | |
for ( range = clazz->script_uni_ranges; range->first != 0; range++ ) | |
{ | |
FT_ULong charcode = range->first; | |
FT_UInt gindex; | |
gindex = FT_Get_Char_Index( face, charcode ); | |
if ( gindex != 0 && | |
gindex < globals->glyph_count && | |
gscripts[gindex] == AF_SCRIPT_LIST_NONE ) | |
{ | |
gscripts[gindex] = (FT_Byte)ss; | |
} | |
for (;;) | |
{ | |
charcode = FT_Get_Next_Char( face, charcode, &gindex ); | |
if ( gindex == 0 || charcode > range->last ) | |
break; | |
if ( gindex < globals->glyph_count && | |
gscripts[gindex] == AF_SCRIPT_LIST_NONE ) | |
{ | |
gscripts[gindex] = (FT_Byte)ss; | |
} | |
} | |
} | |
} | |
Exit: | |
/* | |
* By default, all uncovered glyphs are set to the latin script. | |
* XXX: Shouldn't we disable hinting or do something similar? | |
*/ | |
{ | |
FT_UInt nn; | |
for ( nn = 0; nn < globals->glyph_count; nn++ ) | |
{ | |
if ( gscripts[nn] == AF_SCRIPT_LIST_NONE ) | |
gscripts[nn] = AF_SCRIPT_LIST_DEFAULT; | |
} | |
} | |
FT_Set_Charmap( face, old_charmap ); | |
return error; | |
} | |
FT_LOCAL_DEF( FT_Error ) | |
af_face_globals_new( FT_Face face, | |
AF_FaceGlobals *aglobals ) | |
{ | |
FT_Error error; | |
FT_Memory memory; | |
AF_FaceGlobals globals; | |
memory = face->memory; | |
if ( !FT_ALLOC( globals, sizeof ( *globals ) + | |
face->num_glyphs * sizeof ( FT_Byte ) ) ) | |
{ | |
globals->face = face; | |
globals->glyph_count = face->num_glyphs; | |
globals->glyph_scripts = (FT_Byte*)( globals + 1 ); | |
error = af_face_globals_compute_script_coverage( globals ); | |
if ( error ) | |
{ | |
af_face_globals_free( globals ); | |
globals = NULL; | |
} | |
} | |
*aglobals = globals; | |
return error; | |
} | |
FT_LOCAL_DEF( void ) | |
af_face_globals_free( AF_FaceGlobals globals ) | |
{ | |
if ( globals ) | |
{ | |
FT_Memory memory = globals->face->memory; | |
FT_UInt nn; | |
for ( nn = 0; nn < AF_SCRIPT_MAX; nn++ ) | |
{ | |
if ( globals->metrics[nn] ) | |
{ | |
AF_ScriptClass clazz = af_script_classes[nn]; | |
FT_ASSERT( globals->metrics[nn]->clazz == clazz ); | |
if ( clazz->script_metrics_done ) | |
clazz->script_metrics_done( globals->metrics[nn] ); | |
FT_FREE( globals->metrics[nn] ); | |
} | |
} | |
globals->glyph_count = 0; | |
globals->glyph_scripts = NULL; /* no need to free this one! */ | |
globals->face = NULL; | |
FT_FREE( globals ); | |
} | |
} | |
FT_LOCAL_DEF( FT_Error ) | |
af_face_globals_get_metrics( AF_FaceGlobals globals, | |
FT_UInt gindex, | |
FT_UInt options, | |
AF_ScriptMetrics *ametrics ) | |
{ | |
AF_ScriptMetrics metrics = NULL; | |
FT_UInt gidx; | |
AF_ScriptClass clazz; | |
FT_UInt script = options & 15; | |
const FT_UInt script_max = sizeof ( af_script_classes ) / | |
sizeof ( af_script_classes[0] ); | |
FT_Error error = AF_Err_Ok; | |
if ( gindex >= globals->glyph_count ) | |
{ | |
error = AF_Err_Invalid_Argument; | |
goto Exit; | |
} | |
gidx = script; | |
if ( gidx == 0 || gidx + 1 >= script_max ) | |
gidx = globals->glyph_scripts[gindex]; | |
clazz = af_script_classes[gidx]; | |
if ( script == 0 ) | |
script = clazz->script; | |
metrics = globals->metrics[clazz->script]; | |
if ( metrics == NULL ) | |
{ | |
/* create the global metrics object when needed */ | |
FT_Memory memory = globals->face->memory; | |
if ( FT_ALLOC( metrics, clazz->script_metrics_size ) ) | |
goto Exit; | |
metrics->clazz = clazz; | |
if ( clazz->script_metrics_init ) | |
{ | |
error = clazz->script_metrics_init( metrics, globals->face ); | |
if ( error ) | |
{ | |
if ( clazz->script_metrics_done ) | |
clazz->script_metrics_done( metrics ); | |
FT_FREE( metrics ); | |
goto Exit; | |
} | |
} | |
globals->metrics[clazz->script] = metrics; | |
} | |
Exit: | |
*ametrics = metrics; | |
return error; | |
} | |
/* END */ |