?? t1load.c
字號:
/***************************************************************************//* *//* t1load.c *//* *//* Type 1 font loader (body). *//* *//* Copyright 1996-2001, 2002 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. *//* *//***************************************************************************/ /*************************************************************************/ /* */ /* This is the new and improved Type 1 data loader for FreeType 2. The */ /* old loader has several problems: it is slow, complex, difficult to */ /* maintain, and contains incredible hacks to make it accept some */ /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */ /* the Type 1 fonts on my machine still aren't loaded correctly by it. */ /* */ /* This version is much simpler, much faster and also easier to read and */ /* maintain by a great order of magnitude. The idea behind it is to */ /* _not_ try to read the Type 1 token stream with a state machine (i.e. */ /* a Postscript-like interpreter) but rather to perform simple pattern */ /* matching. */ /* */ /* Indeed, nearly all data definitions follow a simple pattern like */ /* */ /* ... /Field <data> ... */ /* */ /* where <data> can be a number, a boolean, a string, or an array of */ /* numbers. There are a few exceptions, namely the encoding, font name, */ /* charstrings, and subrs; they are handled with a special pattern */ /* matching routine. */ /* */ /* All other common cases are handled very simply. The matching rules */ /* are defined in the file `t1tokens.h' through the use of several */ /* macros calls PARSE_XXX. */ /* */ /* This file is included twice here; the first time to generate parsing */ /* callback functions, the second to generate a table of keywords (with */ /* pointers to the associated callback). */ /* */ /* The function `parse_dict' simply scans *linearly* a given dictionary */ /* (either the top-level or private one) and calls the appropriate */ /* callback when it encounters an immediate keyword. */ /* */ /* This is by far the fastest way one can find to parse and read all */ /* data. */ /* */ /* This led to tremendous code size reduction. Note that later, the */ /* glyph loader will also be _greatly_ simplified, and the automatic */ /* hinter will replace the clumsy `t1hinter'. */ /* */ /*************************************************************************/#include <ft2build.h>#include FT_INTERNAL_DEBUG_H#include FT_CONFIG_CONFIG_H#include FT_MULTIPLE_MASTERS_H#include FT_INTERNAL_TYPE1_TYPES_H#include "t1load.h"#include "t1errors.h" /*************************************************************************/ /* */ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ /* messages during execution. */ /* */#undef FT_COMPONENT#define FT_COMPONENT trace_t1load#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** MULTIPLE MASTERS SUPPORT *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ static FT_Error t1_allocate_blend( T1_Face face, FT_UInt num_designs, FT_UInt num_axis ) { PS_Blend blend; FT_Memory memory = face->root.memory; FT_Error error = 0; blend = face->blend; if ( !blend ) { if ( FT_NEW( blend ) ) goto Exit; face->blend = blend; } /* allocate design data if needed */ if ( num_designs > 0 ) { if ( blend->num_designs == 0 ) { FT_UInt nn; /* allocate the blend `private' and `font_info' dictionaries */ if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || FT_NEW_ARRAY( blend->privates[1], num_designs ) || FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) goto Exit; blend->default_weight_vector = blend->weight_vector + num_designs; blend->font_infos[0] = &face->type1.font_info; blend->privates [0] = &face->type1.private_dict; for ( nn = 2; nn <= num_designs; nn++ ) { blend->privates[nn] = blend->privates [nn - 1] + 1; blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; } blend->num_designs = num_designs; } else if ( blend->num_designs != num_designs ) goto Fail; } /* allocate axis data if needed */ if ( num_axis > 0 ) { if ( blend->num_axis != 0 && blend->num_axis != num_axis ) goto Fail; blend->num_axis = num_axis; } /* allocate the blend design pos table if needed */ num_designs = blend->num_designs; num_axis = blend->num_axis; if ( num_designs && num_axis && blend->design_pos[0] == 0 ) { FT_UInt n; if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) ) goto Exit; for ( n = 1; n < num_designs; n++ ) blend->design_pos[n] = blend->design_pos[0] + num_axis * n; } Exit: return error; Fail: error = -1; goto Exit; } FT_LOCAL_DEF( FT_Error ) T1_Get_Multi_Master( T1_Face face, FT_Multi_Master* master ) { PS_Blend blend = face->blend; FT_UInt n; FT_Error error; error = T1_Err_Invalid_Argument; if ( blend ) { master->num_axis = blend->num_axis; master->num_designs = blend->num_designs; for ( n = 0; n < blend->num_axis; n++ ) { FT_MM_Axis* axis = master->axis + n; PS_DesignMap map = blend->design_map + n; axis->name = blend->axis_names[n]; axis->minimum = map->design_points[0]; axis->maximum = map->design_points[map->num_points - 1]; } error = 0; } return error; } FT_LOCAL_DEF( FT_Error ) T1_Set_MM_Blend( T1_Face face, FT_UInt num_coords, FT_Fixed* coords ) { PS_Blend blend = face->blend; FT_Error error; FT_UInt n, m; error = T1_Err_Invalid_Argument; if ( blend && blend->num_axis == num_coords ) { /* recompute the weight vector from the blend coordinates */ error = T1_Err_Ok; for ( n = 0; n < blend->num_designs; n++ ) { FT_Fixed result = 0x10000L; /* 1.0 fixed */ for ( m = 0; m < blend->num_axis; m++ ) { FT_Fixed factor; /* get current blend axis position */ factor = coords[m]; if ( factor < 0 ) factor = 0; if ( factor > 0x10000L ) factor = 0x10000L; if ( ( n & ( 1 << m ) ) == 0 ) factor = 0x10000L - factor; result = FT_MulFix( result, factor ); } blend->weight_vector[n] = result; } error = T1_Err_Ok; } return error; } FT_LOCAL_DEF( FT_Error ) T1_Set_MM_Design( T1_Face face, FT_UInt num_coords, FT_Long* coords ) { PS_Blend blend = face->blend; FT_Error error; FT_UInt n, p; error = T1_Err_Invalid_Argument; if ( blend && blend->num_axis == num_coords ) { /* compute the blend coordinates through the blend design map */ FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; for ( n = 0; n < blend->num_axis; n++ ) { FT_Long design = coords[n]; FT_Fixed the_blend; PS_DesignMap map = blend->design_map + n; FT_Fixed* designs = map->design_points; FT_Fixed* blends = map->blend_points; FT_Int before = -1, after = -1; for ( p = 0; p < (FT_UInt)map->num_points; p++ ) { FT_Fixed p_design = designs[p]; /* exact match ? */ if ( design == p_design ) { the_blend = blends[p]; goto Found; } if ( design < p_design ) { after = p; break; } before = p; } /* now, interpolate if needed */ if ( before < 0 ) the_blend = blends[0]; else if ( after < 0 ) the_blend = blends[map->num_points - 1]; else the_blend = FT_MulDiv( design - designs[before], blends [after] - blends [before], designs[after] - designs[before] ); Found: final_blends[n] = the_blend; } error = T1_Set_MM_Blend( face, num_coords, final_blends ); } return error; } FT_LOCAL_DEF( void ) T1_Done_Blend( T1_Face face ) { FT_Memory memory = face->root.memory; PS_Blend blend = face->blend; if ( blend ) { FT_UInt num_designs = blend->num_designs; FT_UInt num_axis = blend->num_axis; FT_UInt n; /* release design pos table */ FT_FREE( blend->design_pos[0] ); for ( n = 1; n < num_designs; n++ ) blend->design_pos[n] = 0; /* release blend `private' and `font info' dictionaries */ FT_FREE( blend->privates[1] ); FT_FREE( blend->font_infos[1] ); for ( n = 0; n < num_designs; n++ ) { blend->privates [n] = 0; blend->font_infos[n] = 0; } /* release weight vectors */ FT_FREE( blend->weight_vector ); blend->default_weight_vector = 0; /* release axis names */ for ( n = 0; n < num_axis; n++ ) FT_FREE( blend->axis_names[n] ); /* release design map */ for ( n = 0; n < num_axis; n++ ) { PS_DesignMap dmap = blend->design_map + n; FT_FREE( dmap->design_points ); dmap->num_points = 0; } FT_FREE( face->blend ); } } static void parse_blend_axis_types( T1_Face face, T1_Loader loader ) { T1_TokenRec axis_tokens[ T1_MAX_MM_AXIS ]; FT_Int n, num_axis; FT_Error error = 0; PS_Blend blend; FT_Memory memory; /* take an array of objects */ T1_ToTokenArray( &loader->parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis ); if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS ) { FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n", num_axis )); error = T1_Err_Invalid_File_Format; goto Exit; } /* allocate blend if necessary */ error = t1_allocate_blend( face, 0, (FT_UInt)num_axis ); if ( error ) goto Exit; blend = face->blend; memory = face->root.memory; /* each token is an immediate containing the name of the axis */ for ( n = 0; n < num_axis; n++ ) { T1_Token token = axis_tokens + n; FT_Byte* name; FT_Int len; /* skip first slash, if any */ if ( token->start[0] == '/' ) token->start++; len = (FT_Int)( token->limit - token->start ); if ( len <= 0 ) { error = T1_Err_Invalid_File_Format; goto Exit; } if ( FT_ALLOC( blend->axis_names[n], len + 1 ) ) goto Exit; name = (FT_Byte*)blend->axis_names[n]; FT_MEM_COPY( name, token->start, len ); name[len] = 0; } Exit: loader->parser.root.error = error; } static void
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -