📄 t1load.c
字号:
/***************************************************************************/
/* */
/* t1load.c */
/* */
/* Type 1 font loader (body). */
/* */
/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 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 time to */
/* generate a table of keywords (with pointers to the associated */
/* callback functions). */
/* */
/* 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 = T1_Err_Ok;
blend = face->blend;
if ( !blend )
{
if ( FT_NEW( blend ) )
goto Exit;
blend->num_default_design_vector = 0;
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->bboxes[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;
blend->bboxes [0] = &face->type1.font_bbox;
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->bboxes[nn] = blend->bboxes [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 = T1_Err_Invalid_File_Format;
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 = T1_Err_Ok;
}
return error;
}
#define FT_INT_TO_FIXED( a ) ( (a) << 16 )
#define FT_FIXED_TO_INT( a ) ( FT_RoundFix( a ) >> 16 )
/*************************************************************************/
/* */
/* Given a normalized (blend) coordinate, figure out the design */
/* coordinate appropriate for that value. */
/* */
FT_LOCAL_DEF( FT_Fixed )
mm_axis_unmap( PS_DesignMap axismap,
FT_Fixed ncv )
{
int j;
if ( ncv <= axismap->blend_points[0] )
return axismap->design_points[0];
for ( j = 1; j < axismap->num_points; ++j )
{
if ( ncv <= axismap->blend_points[j] )
{
FT_Fixed t = FT_MulDiv( ncv - axismap->blend_points[j - 1],
0x10000L,
axismap->blend_points[j] -
axismap->blend_points[j - 1] );
return axismap->design_points[j - 1] +
FT_MulDiv( t,
axismap->design_points[j] -
axismap->design_points[j - 1],
1L );
}
}
return axismap->design_points[axismap->num_points - 1];
}
/*************************************************************************/
/* */
/* Given a vector of weights, one for each design, figure out the */
/* normalized axis coordinates which gave rise to those weights. */
/* */
FT_LOCAL_DEF( void )
mm_weights_unmap( FT_Fixed* weights,
FT_Fixed* axiscoords,
FT_UInt axis_count )
{
FT_ASSERT( axis_count <= T1_MAX_MM_AXIS );
if ( axis_count == 1 )
axiscoords[0] = weights[1];
else if ( axis_count == 2 )
{
axiscoords[0] = weights[3] + weights[1];
axiscoords[1] = weights[3] + weights[2];
}
else if ( axis_count == 3 )
{
axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1];
axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2];
axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4];
}
else
{
axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] +
weights[7] + weights[5] + weights[3] + weights[1];
axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] +
weights[7] + weights[6] + weights[3] + weights[2];
axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] +
weights[7] + weights[6] + weights[5] + weights[4];
axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] +
weights[11] + weights[10] + weights[9] + weights[8];
}
}
/*************************************************************************/
/* */
/* Just a wrapper around T1_Get_Multi_Master to support the different */
/* arguments needed by the GX var distortable fonts. */
/* */
FT_LOCAL_DEF( FT_Error )
T1_Get_MM_Var( T1_Face face,
FT_MM_Var* *master )
{
FT_Memory memory = face->root.memory;
FT_MM_Var *mmvar;
FT_Multi_Master mmaster;
FT_Error error;
FT_UInt i;
FT_Fixed axiscoords[T1_MAX_MM_AXIS];
PS_Blend blend = face->blend;
error = T1_Get_Multi_Master( face, &mmaster );
if ( error )
goto Exit;
if ( FT_ALLOC( mmvar,
sizeof ( FT_MM_Var ) +
mmaster.num_axis * sizeof ( FT_Var_Axis ) ) )
goto Exit;
mmvar->num_axis = mmaster.num_axis;
mmvar->num_designs = mmaster.num_designs;
mmvar->num_namedstyles = (FT_UInt)-1; /* Does not apply */
mmvar->axis = (FT_Var_Axis*)&mmvar[1];
/* Point to axes after MM_Var struct */
mmvar->namedstyle = NULL;
for ( i = 0 ; i < mmaster.num_axis; ++i )
{
mmvar->axis[i].name = mmaster.axis[i].name;
mmvar->axis[i].minimum = FT_INT_TO_FIXED( mmaster.axis[i].minimum);
mmvar->axis[i].maximum = FT_INT_TO_FIXED( mmaster.axis[i].maximum);
mmvar->axis[i].def = ( mmvar->axis[i].minimum +
mmvar->axis[i].maximum ) / 2;
/* Does not apply. But this value is in range */
mmvar->axis[i].strid = 0xFFFFFFFFUL; /* Does not apply */
mmvar->axis[i].tag = 0xFFFFFFFFUL; /* Does not apply */
if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 )
mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' );
else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 )
mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' );
else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 )
mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' );
}
if ( blend->num_designs == 1U << blend->num_axis )
{
mm_weights_unmap( blend->default_weight_vector,
axiscoords,
blend->num_axis );
for ( i = 0; i < mmaster.num_axis; ++i )
mmvar->axis[i].def =
FT_INT_TO_FIXED( mm_axis_unmap( &blend->design_map[i],
axiscoords[i] ) );
}
*master = mmvar;
Exit:
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -