📄 ttgxvar.c
字号:
/***************************************************************************/
/* */
/* ttgxvar.c */
/* */
/* TrueType GX Font Variation loader */
/* */
/* Copyright 2004, 2005, 2006, 2007 by */
/* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */
/* */
/* 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. */
/* */
/***************************************************************************/
/***************************************************************************/
/* */
/* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at */
/* */
/* http://developer.apple.com/fonts/TTRefMan/RM06/Chap6[fgca]var.html */
/* */
/* The documentation for `fvar' is inconsistent. At one point it says */
/* that `countSizePairs' should be 3, at another point 2. It should be 2. */
/* */
/* The documentation for `gvar' is not intelligible; `cvar' refers you to */
/* `gvar' and is thus also incomprehensible. */
/* */
/* The documentation for `avar' appears correct, but Apple has no fonts */
/* with an `avar' table, so it is hard to test. */
/* */
/* Many thanks to John Jenkins (at Apple) in figuring this out. */
/* */
/* */
/* Apple's `kern' table has some references to tuple indices, but as there */
/* is no indication where these indices are defined, nor how to */
/* interpolate the kerning values (different tuples have different */
/* classes) this issue is ignored. */
/* */
/***************************************************************************/
#include <ft2build.h>
#include FT_INTERNAL_DEBUG_H
#include FT_CONFIG_CONFIG_H
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_SFNT_H
#include FT_TRUETYPE_IDS_H
#include FT_TRUETYPE_TAGS_H
#include FT_MULTIPLE_MASTERS_H
#include "ttdriver.h"
#include "ttpload.h"
#include "ttgxvar.h"
#include "tterrors.h"
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
#define FT_Stream_FTell( stream ) \
( (stream)->cursor - (stream)->base )
#define FT_Stream_SeekSet( stream, off ) \
( (stream)->cursor = (stream)->base+(off) )
/*************************************************************************/
/* */
/* 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_ttgxvar
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** Internal Routines *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/* */
/* The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It */
/* indicates that there is a delta for every point without needing to */
/* enumerate all of them. */
/* */
#define ALL_POINTS (FT_UShort*)( -1 )
enum
{
GX_PT_POINTS_ARE_WORDS = 0x80,
GX_PT_POINT_RUN_COUNT_MASK = 0x7F
};
/*************************************************************************/
/* */
/* <Function> */
/* ft_var_readpackedpoints */
/* */
/* <Description> */
/* Read a set of points to which the following deltas will apply. */
/* Points are packed with a run length encoding. */
/* */
/* <Input> */
/* stream :: The data stream. */
/* */
/* <Output> */
/* point_cnt :: The number of points read. A zero value means that */
/* all points in the glyph will be affected, without */
/* enumerating them individually. */
/* */
/* <Return> */
/* An array of FT_UShort containing the affected points or the */
/* special value ALL_POINTS. */
/* */
static FT_UShort*
ft_var_readpackedpoints( FT_Stream stream,
FT_UInt *point_cnt )
{
FT_UShort *points;
FT_Int n;
FT_Int runcnt;
FT_Int i;
FT_Int j;
FT_Int first;
FT_Memory memory = stream->memory;
FT_Error error = TT_Err_Ok;
FT_UNUSED( error );
*point_cnt = n = FT_GET_BYTE();
if ( n == 0 )
return ALL_POINTS;
if ( n & GX_PT_POINTS_ARE_WORDS )
n = FT_GET_BYTE() | ( ( n & GX_PT_POINT_RUN_COUNT_MASK ) << 8 );
if ( FT_NEW_ARRAY( points, n ) )
return NULL;
i = 0;
while ( i < n )
{
runcnt = FT_GET_BYTE();
if ( runcnt & GX_PT_POINTS_ARE_WORDS )
{
runcnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK;
first = points[i++] = FT_GET_USHORT();
/* first point not included in runcount */
for ( j = 0; j < runcnt; ++j )
points[i++] = (FT_UShort)( first += FT_GET_USHORT() );
}
else
{
first = points[i++] = FT_GET_BYTE();
for ( j = 0; j < runcnt; ++j )
points[i++] = (FT_UShort)( first += FT_GET_BYTE() );
}
}
return points;
}
enum
{
GX_DT_DELTAS_ARE_ZERO = 0x80,
GX_DT_DELTAS_ARE_WORDS = 0x40,
GX_DT_DELTA_RUN_COUNT_MASK = 0x3F
};
/*************************************************************************/
/* */
/* <Function> */
/* ft_var_readpackeddeltas */
/* */
/* <Description> */
/* Read a set of deltas. These are packed slightly differently than */
/* points. In particular there is no overall count. */
/* */
/* <Input> */
/* stream :: The data stream. */
/* */
/* delta_cnt :: The number of to be read. */
/* */
/* <Return> */
/* An array of FT_Short containing the deltas for the affected */
/* points. (This only gets the deltas for one dimension. It will */
/* generally be called twice, once for x, once for y. When used in */
/* cvt table, it will only be called once.) */
/* */
static FT_Short*
ft_var_readpackeddeltas( FT_Stream stream,
FT_Int delta_cnt )
{
FT_Short *deltas;
FT_Int runcnt;
FT_Int i;
FT_Int j;
FT_Memory memory = stream->memory;
FT_Error error = TT_Err_Ok;
FT_UNUSED( error );
if ( FT_NEW_ARRAY( deltas, delta_cnt ) )
return NULL;
i = 0;
while ( i < delta_cnt )
{
runcnt = FT_GET_BYTE();
if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
{
/* runcnt zeroes get added */
for ( j = 0;
j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
++j )
deltas[i++] = 0;
}
else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
{
/* runcnt shorts from the stack */
for ( j = 0;
j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
++j )
deltas[i++] = FT_GET_SHORT();
}
else
{
/* runcnt signed bytes from the stack */
for ( j = 0;
j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
++j )
deltas[i++] = FT_GET_CHAR();
}
if ( j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) )
{
/* Bad format */
FT_FREE( deltas );
return NULL;
}
}
return deltas;
}
/*************************************************************************/
/* */
/* <Function> */
/* ft_var_load_avar */
/* */
/* <Description> */
/* Parse the `avar' table if present. It need not be, so we return */
/* nothing. */
/* */
/* <InOut> */
/* face :: The font face. */
/* */
static void
ft_var_load_avar( TT_Face face )
{
FT_Stream stream = FT_FACE_STREAM(face);
FT_Memory memory = stream->memory;
GX_Blend blend = face->blend;
GX_AVarSegment segment;
FT_Error error = TT_Err_Ok;
FT_ULong version;
FT_Long axisCount;
FT_Int i, j;
FT_ULong table_len;
FT_UNUSED( error );
blend->avar_checked = TRUE;
if ( (error = face->goto_table( face, TTAG_avar, stream, &table_len )) != 0 )
return;
if ( FT_FRAME_ENTER( table_len ) )
return;
version = FT_GET_LONG();
axisCount = FT_GET_LONG();
if ( version != 0x00010000L ||
axisCount != (FT_Long)blend->mmvar->num_axis )
goto Exit;
if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) )
goto Exit;
segment = &blend->avar_segment[0];
for ( i = 0; i < axisCount; ++i, ++segment )
{
segment->pairCount = FT_GET_USHORT();
if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) )
{
/* Failure. Free everything we have done so far. We must do */
/* it right now since loading the `avar' table is optional. */
for ( j = i - 1; j >= 0; --j )
FT_FREE( blend->avar_segment[j].correspondence );
FT_FREE( blend->avar_segment );
blend->avar_segment = NULL;
goto Exit;
}
for ( j = 0; j < segment->pairCount; ++j )
{
segment->correspondence[j].fromCoord =
FT_GET_SHORT() << 2; /* convert to Fixed */
segment->correspondence[j].toCoord =
FT_GET_SHORT()<<2; /* convert to Fixed */
}
}
Exit:
FT_FRAME_EXIT();
}
typedef struct GX_GVar_Head_ {
FT_Long version;
FT_UShort axisCount;
FT_UShort globalCoordCount;
FT_ULong offsetToCoord;
FT_UShort glyphCount;
FT_UShort flags;
FT_ULong offsetToData;
} GX_GVar_Head;
/*************************************************************************/
/* */
/* <Function> */
/* ft_var_load_gvar */
/* */
/* <Description> */
/* Parses the `gvar' table if present. If `fvar' is there, `gvar' */
/* had better be there too. */
/* */
/* <InOut> */
/* face :: The font face. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
static FT_Error
ft_var_load_gvar( TT_Face face )
{
FT_Stream stream = FT_FACE_STREAM(face);
FT_Memory memory = stream->memory;
GX_Blend blend = face->blend;
FT_Error error;
FT_UInt i, j;
FT_ULong table_len;
FT_ULong gvar_start;
FT_ULong offsetToData;
GX_GVar_Head gvar_head;
static const FT_Frame_Field gvar_fields[] =
{
#undef FT_STRUCTURE
#define FT_STRUCTURE GX_GVar_Head
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -