adding new postscript hinter

This commit is contained in:
David Turner 2001-10-18 11:38:43 +00:00
parent 02701db9ce
commit e888167e1f
15 changed files with 5400 additions and 0 deletions

View File

@ -0,0 +1,141 @@
#ifndef __PSGLOBALS_H__
#define __PSGLOBALS_H__
/**********************************************************************/
/**********************************************************************/
/***** *****/
/***** PUBLIC STRUCTURES & API *****/
/***** *****/
/**********************************************************************/
/**********************************************************************/
#if 0
/****************************************************************
*
* @constant: PS_GLOBALS_MAX_BLUE_ZONES
*
* @description:
* the maximum number of blue zones in a font global hints
* structure. See @PS_Globals_BluesRec
*/
#define PS_GLOBALS_MAX_BLUE_ZONES 16
/****************************************************************
*
* @constant: PS_GLOBALS_MAX_STD_WIDTHS
*
* @description:
* the maximum number of standard and snap widths in either the
* horizontal or vertical direction. See @PS_Globals_WidthsRec
*/
#define PS_GLOBALS_MAX_STD_WIDTHS 16
/****************************************************************
*
* @type: PS_Globals
*
* @description:
* a handle to a @PS_GlobalsRec structure used to
* describe the global hints of a given font
*/
typedef struct PS_GlobalsRec_* PS_Globals;
/****************************************************************
*
* @struct: PS_Globals_BluesRec
*
* @description:
* a structure used to model the global blue zones of a given
* font
*
* @fields:
* count :: number of blue zones
* zones :: an array of (count*2) coordinates describing the zones
*
* count_family :: number of family blue zones
* zones_family :: an array of (count_family*2) coordinates describing
* the family blue zones
*
* scale :: the blue scale to be used (fixed float)
* shift :: the blue shift to be used
* fuzz :: the blue fuzz to be used
*
* @note:
* each blue zone is modeled by a (reference,overshoot) coordinate pair
* in the table. zones can be placed in any order..
*/
typedef struct PS_Globals_BluesRec
{
FT_UInt count;
FT_Int16 zones[ 2*PS_GLOBALS_MAX_BLUE_ZONES ];
FT_UInt count_family;
FT_Int16 zones_family[ 2*PS_GLOBALS_MAX_BLUE_ZONES ];
FT_Fixed scale;
FT_Int16 shift;
FT_Int16 fuzz;
} PS_Globals_BluesRec, *PS_Globals_Blues;
/****************************************************************
*
* @type: PS_Global_Widths;
*
* @description:
* a handle to a @PS_Globals_WidthsRec structure used to model
* the global standard and snap widths in a given direction
*/
typedef struct PS_Globals_WidthsRec_* PS_Globals_Widths;
/****************************************************************
*
* @struct: PS_Globals_WidthsRec
*
* @description:
* a structure used to model the global standard and snap widths
* in a given font
*
* @fields:
* count :: number of widths
* widths :: an array of 'count' widths in font units.
*
* @note:
* 'widths[0]' must be the standard width or height, while
* remaining elements of the array are snap widths or heights
*/
typedef struct PS_Globals_WidthsRec_
{
FT_UInt count;
FT_Int16 widths[ PS_GLOBALS_MAX_STD_WIDTHS ];
} PS_Globals_WidthsRec;
/****************************************************************
*
* @struct: PS_Globals_GlobalsRec
*
* @description:
* a structure used to model the global hints for a given font
*
* @fields:
* horizontal :: horizontal widths
* vertical :: vertical heights
* blues :: blue zones
*/
typedef struct PS_GlobalsRec_
{
PS_Globals_WidthsRec horizontal;
PS_Globals_WidthsRec vertical;
PS_Globals_BluesRec blues;
} PS_GlobalsRec;
#endif
/* */
#endif /* __PS_GLOBALS_H__ */

View File

@ -0,0 +1,529 @@
/***************************************************************************/
/* */
/* pshints.h */
/* */
/* Interface to Postscript-specific (Type 1 and Type 2) hints */
/* recorders. These are used to support native T1/T2 hints */
/* in the "type1", "cid" and "cff" font drivers */
/* */
/* Copyright 2001 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. */
/* */
/***************************************************************************/
#ifndef __PSHINTS_H__
#define __PSHINTS_H__
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_TYPE1_TABLES_H
#include FT_INTERNAL_POSTSCRIPT_GLOBALS_H
FT_BEGIN_HEADER
/**********************************************************************/
/**********************************************************************/
/***** *****/
/***** INTERNAL REPRESENTATION OF GLOBALS *****/
/***** *****/
/**********************************************************************/
/**********************************************************************/
typedef struct PSH_GlobalsRec_* PSH_Globals;
typedef FT_Error (*PSH_Globals_NewFunc)( FT_Memory memory,
T1_Private* private_dict,
PSH_Globals* aglobals );
typedef FT_Error (*PSH_Globals_SetScaleFunc)( PSH_Globals globals,
FT_Fixed x_scale,
FT_Fixed y_scale,
FT_Fixed x_delta,
FT_Fixed y_delta );
typedef void (*PSH_Globals_DestroyFunc)( PSH_Globals globals );
typedef struct
{
PSH_Globals_NewFunc create;
PSH_Globals_SetScaleFunc set_scale;
PSH_Globals_DestroyFunc destroy;
} PSH_Globals_FuncsRec, *PSH_Globals_Funcs;
/**********************************************************************/
/**********************************************************************/
/***** *****/
/***** PUBLIC TYPE 1 HINTS RECORDER *****/
/***** *****/
/**********************************************************************/
/**********************************************************************/
/************************************************************************
*
* @type: T1_Hints
*
* @description:
* this is a handle to an opaque structure used to record glyph
* hints from a Type 1 character glyph character string.
*
* the methods used to operate on this object are defined by the
* @T1_Hints_FuncsRec structure. Recording glyph hints is normally
* achieved through the following scheme:
*
* - open a new hint recording session by calling the "open"
* method. This will rewind the recorder and prepare it for
* new input
*
* - for each hint found in the glyph charstring, call the
* corresponding method ("stem", "stem3" or "reset").
* note that these functions do not return an error code
*
* - close the recording session by calling the "close" method
* it will return an error code if the hints were invalid or
* something strange happened (e.g. memory shortage)
*
* the hints accumulated in the object can later be used by the
* Postscript hinter
*/
typedef struct T1_HintsRec_* T1_Hints;
/************************************************************************
*
* @type: T1_Hints_Funcs
*
* @description:
* a pointer to the @T1_Hints_FuncsRec structure that defines the
* API of a given @T1_Hints object
*/
typedef const struct T1_Hints_FuncsRec_* T1_Hints_Funcs;
/************************************************************************
*
* @functype: T1_Hints_OpenFunc
*
* @description:
* a method of the @T1_Hints class used to prepare it for a new
* Type 1 hints recording session
*
* @input:
* hints :: handle to Type 1 hints recorder
*
* @note:
* You should always call the @T1_Hints_CloseFunc method in order
* to close an opened recording session
*/
typedef void (*T1_Hints_OpenFunc) ( T1_Hints hints );
/************************************************************************
*
* @functype: T1_Hints_SetStemFunc
*
* @description:
* a method of the @T1_Hints class used to record a new horizontal or
* vertical stem. This corresponds to the Type 1 "hstem" and "vstem"
* operators
*
* @input:
* hints :: handle to Type 1 hints recorder
* dimension :: 0 for horizontal stems (hstem), 1 for vertical ones (vstem)
* coords :: array of 2 integers, used as (position,length) stem descriptor
*
* @note:
* use vertical coordinates (y) for horizontal stems (dim=0)
* use horizontal coordinates (x) for vertical stems (dim=1)
*
* "coords[0]" is the absolute stem position (lowest coordinate)
* "coords[1]" is the length.
*
* the length can be negative, in which case it must be either
* -20 or -21 in order and will be interpreted as a "ghost" stem,
* according to the Type 1 specification.
*
* if the length is -21 (corresponding to a bottom ghost stem), then
* the real stem position is "coords[0]+coords[1]"
*/
typedef void (*T1_Hints_SetStemFunc) ( T1_Hints hints,
FT_UInt dimension,
FT_Long* coords );
/************************************************************************
*
* @functype: T1_Hints_SetStem3Func
*
* @description:
* a method of the @T1_Hints class used to record three counter-controlled
* horizontal or vertical stems at once
*
* @input:
* hints :: handle to Type 1 hints recorder
* dimension :: 0 for horizontal stems, 1 for vertical ones
* coords :: array of 6 integers, i.e. 3 (position,length) pairs
* for the counter-controlled stems
*
* @note:
* use vertical coordinates (y) for horizontal stems (dim=0)
* use horizontal coordinates (x) for vertical stems (dim=1)
*
* the lengths cannot be negative (ghost stems are never counter-controlled)
*/
typedef void (*T1_Hints_SetStem3Func) ( T1_Hints hints,
FT_UInt dimension,
FT_Long* coords );
/************************************************************************
*
* @functype: T1_Hints_ResetFunc
*
* @description:
* a method of the @T1_Hints class used to reset the stems hints
* in a recording session. This is equivalent to the Type 1 ...
*
* @input:
* hints :: handle to Type 1 hints recorder
* end_point :: index of last point in the input glyph in which
* the previously defined hints apply
*/
typedef void (*T1_Hints_ResetFunc)( T1_Hints hints,
FT_UInt end_point );
/************************************************************************
*
* @functype: T1_Hints_CloseFunc
*
* @description:
* a method of the @T1_Hints class used to close a hint recording
* session.
*
* @input:
* hints :: handle to Type 1 hints recorder
* end_point :: index of last point in the input glyph
*
* @return:
* error code. 0 means success
*
* @note:
* the error code will be set to indicate that an error occured
* during the recording session
*/
typedef FT_Error (*T1_Hints_CloseFunc)( T1_Hints hints,
FT_UInt end_point );
/************************************************************************
*
* @functype: T1_Hints_ApplyFunc
*
* @description:
* a method of the @T1_Hints class used to apply hints to the
* corresponding glyph outline. Must be called once all hints
* have been recorded.
*
* @input:
* hints :: handle to Type 1 hints recorder
* outline :: pointer to target outline descriptor
* globals :: the hinter globals for this font
*
* @return:
* error code. 0 means success
*
* @note:
* on input, all points within the outline are in font coordinates.
* on output, they're in 1/64th of pixels.
*
* the scaling transform is taken from the "globals" object, which
* must correspond to the same font than the glyph
*/
typedef FT_Error (*T1_Hints_ApplyFunc)( T1_Hints hints,
FT_Outline* outline,
PSH_Globals globals );
/************************************************************************
*
* @struct: T1_Hints_FuncsRec
*
* @description:
* the structure used to provide the API to @T1_Hints objects
*
* @fields:
* hints :: handle to T1 Hints recorder
* open :: open recording session
* close :: close recording session
* stem :: set simple stem
* stem3 :: set counter-controlled stems
* reset :: reset stem hints
* apply :: apply the hints to the corresponding glyph outline
*/
typedef struct T1_Hints_FuncsRec_
{
T1_Hints hints;
T1_Hints_OpenFunc open;
T1_Hints_CloseFunc close;
T1_Hints_SetStemFunc stem;
T1_Hints_SetStem3Func stem3;
T1_Hints_ResetFunc reset;
T1_Hints_ApplyFunc apply;
} T1_Hints_FuncsRec;
/**********************************************************************/
/**********************************************************************/
/***** *****/
/***** PUBLIC TYPE 2 HINTS RECORDER *****/
/***** *****/
/**********************************************************************/
/**********************************************************************/
/************************************************************************
*
* @type: T2_Hints
*
* @description:
* this is a handle to an opaque structure used to record glyph
* hints from a Type 2 character glyph character string.
*
* the methods used to operate on this object are defined by the
* @T2_Hints_FuncsRec structure. Recording glyph hints is normally
* achieved through the following scheme:
*
* - open a new hint recording session by calling the "open"
* method. This will rewind the recorder and prepare it for
* new input
*
* - for each hint found in the glyph charstring, call the
* corresponding method ("stems", "hintmask", "counters").
* note that these functions do not return an error code
*
* - close the recording session by calling the "close" method
* it will return an error code if the hints were invalid or
* something strange happened (e.g. memory shortage)
*
* the hints accumulated in the object can later be used by the
* Postscript hinter
*/
typedef struct T2_HintsRec_* T2_Hints;
/************************************************************************
*
* @type: T2_Hints_Funcs
*
* @description:
* a pointer to the @T1_Hints_FuncsRec structure that defines the
* API of a given @T2_Hints object
*/
typedef const struct T2_Hints_FuncsRec_* T2_Hints_Funcs;
/************************************************************************
*
* @functype: T2_Hints_OpenFunc
*
* @description:
* a method of the @T2_Hints class used to prepare it for a new
* Type 2 hints recording session
*
* @input:
* hints :: handle to Type 2 hints recorder
*
* @note:
* You should always call the @T2_Hints_CloseFunc method in order
* to close an opened recording session
*/
typedef void (*T2_Hints_OpenFunc) ( T2_Hints hints );
/************************************************************************
*
* @functype: T2_Hints_StemsFunc
*
* @description:
* a method of the @T2_Hints class used to set the table of stems
* in either the vertical or horizontal dimension. Equivalent to the
* "hstem", "vstem", "hstemhm" and "vstemhm" Type 2 operators
*
* @input:
* hints :: handle to Type 2 hints recorder
* dimension :: 0 for horizontal stems (hstem), 1 for vertical ones (vstem)
* count :: number of stems
* coordinates :: an array of "count" (position,length) pairs
*
* @note:
* use vertical coordinates (y) for horizontal stems (dim=0)
* use horizontal coordinates (x) for vertical stems (dim=1)
*
* there are "2*count" elements in the "coordinates" array. Each
* even element is an absolute position in font units, each odd
* element is a length in font units
*
* a length can be negative, in which case it must be either
* -20 or -21 in order and will be interpreted as a "ghost" stem,
* according to the Type 1 specification.
*/
typedef void (*T2_Hints_StemsFunc) ( T2_Hints hints,
FT_UInt dimension,
FT_UInt count,
FT_Fixed* coordinates );
/************************************************************************
*
* @functype: T2_Hints_MaskFunc
*
* @description:
* a method of the @T2_Hints class used to set a given hintmask
* (correspond to the "hintmask" Type 2 operator)
*
* @input:
* hints :: handle to Type 2 hints recorder
* end_point :: glyph index of the last point to which the previously
* defined/active hints apply.
* bit_count :: number of bits in the hint mask.
* bytes :: an array of bytes modelling the hint mask
*
* @note:
* if the hintmask starts the charstring (before any glyph point
* definition), the value of "end_point" should be 0
*
* "bit_count" is the number of meaningful bits in the "bytes" array,
* and must be equal to the total number of hints defined so far
* (i.e. horizontal+verticals)
*
* the "bytes" array can come directly from the Type 2 charstring
* and respect the same format.
*/
typedef void (*T2_Hints_MaskFunc) ( T2_Hints hints,
FT_UInt end_point,
FT_UInt bit_count,
const FT_Byte* bytes );
/************************************************************************
*
* @functype: T2_Hints_CounterFunc
*
* @description:
* a method of the @T2_Hints class used to set a given counter
* mask (correspond to the "hintmask" Type 2 operator)
*
* @input:
* hints :: handle to Type 2 hints recorder
* end_point :: glyph index of the last point to which the previously
* defined/active hints apply.
* bit_count :: number of bits in the hint mask.
* bytes :: an array of bytes modelling the hint mask
*
* @note:
* if the hintmask starts the charstring (before any glyph point
* definition), the value of "end_point" should be 0
*
* "bit_count" is the number of meaningful bits in the "bytes" array,
* and must be equal to the total number of hints defined so far
* (i.e. horizontal+verticals)
*
* the "bytes" array can come directly from the Type 2 charstring
* and respect the same format.
*/
typedef void (*T2_Hints_CounterFunc)( T2_Hints hints,
FT_UInt bit_count,
const FT_Byte* bytes );
/************************************************************************
*
* @functype: T2_Hints_CloseFunc
*
* @description:
* a method of the @T2_Hints class used to close a hint recording
* session.
*
* @input:
* hints :: handle to Type 2 hints recorder
* end_point :: index of last point in the input glyph
*
* @return:
* error code. 0 means success
*
* @note:
* the error code will be set to indicate that an error occured
* during the recording session
*/
typedef FT_Error (*T2_Hints_CloseFunc) ( T2_Hints hints,
FT_UInt end_point );
/************************************************************************
*
* @functype: T2_Hints_ApplyFunc
*
* @description:
* a method of the @T2_Hints class used to apply hints to the
* corresponding glyph outline. Must be called after the "close" method
*
* @input:
* hints :: handle to Type 2 hints recorder
* outline :: pointer to target outline descriptor
* globals :: the hinter globals for this font
*
* @return:
* error code. 0 means success
*
* @note:
* on input, all points within the outline are in font coordinates.
* on output, they're in 1/64th of pixels.
*
* the scaling transform is taken from the "globals" object, which
* must correspond to the same font than the glyph
*/
typedef FT_Error (*T2_Hints_ApplyFunc)( T2_Hints hints,
FT_Outline* outline,
PSH_Globals globals );
/************************************************************************
*
* @struct: T2_Hints_FuncsRec
*
* @description:
* the structure used to provide the API to @T2_Hints objects
*
* @fields:
* hints :: handle to T2 hints recorder object
* open :: open recording session
* close :: close recording session
* stems :: set dimension's stems table
* hintmask :: set hint masks
* counter :: set counter masks
* apply :: apply the hints on the corresponding glyph outline
*/
typedef struct T2_Hints_FuncsRec_
{
T2_Hints hints;
T2_Hints_OpenFunc open;
T2_Hints_CloseFunc close;
T2_Hints_StemsFunc stems;
T2_Hints_MaskFunc hintmask;
T2_Hints_CounterFunc counter;
T2_Hints_ApplyFunc apply;
} T2_Hints_FuncsRec;
/* */
typedef struct PSHinter_Interface_
{
PSH_Globals_Funcs (*get_globals_funcs)( FT_Module module );
T1_Hints_Funcs (*get_t1_funcs) ( FT_Module module );
T2_Hints_Funcs (*get_t2_funcs) ( FT_Module module );
} PSHinter_Interface, *PSHinter_InterfacePtr;
FT_END_HEADER
#endif /* __PSHINTS_H__ */

23
src/pshinter/Jamfile Normal file
View File

@ -0,0 +1,23 @@
# FreeType 2 src/pshinter Jamfile (c) 2001 David Turner
#
SubDir FT2_TOP src pshinter ;
SubDirHdrs [ FT2_SubDir src pshinter ] ;
{
local _sources ;
if $(FT2_MULTI)
{
_sources = pshrec pshglob pshalgo1 pshalgo2 pshmod ;
}
else
{
_sources = pshinter ;
}
Library $(FT2_LIB) : $(_sources).c ;
}
# end of src/psaux Jamfile

19
src/pshinter/pshalgo.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef __PS_HINTER_ALGO_H__
#define __PS_HINTER_ALGO_H__
FT_BEGIN_HEADER
/* define to choose hinting algorithm */
#define PSH_ALGORITHM_2
#ifdef PSH_ALGORITHM_1
# include "pshalgo1.h"
# define PS_HINTS_APPLY_FUNC ps1_hints_apply
#else
# include "pshalgo2.h"
# define PS_HINTS_APPLY_FUNC ps2_hints_apply
#endif
FT_END_HEADER
#endif /* __PS_HINTER_ALGO_H__ */

736
src/pshinter/pshalgo1.c Normal file
View File

@ -0,0 +1,736 @@
#include <ft2build.h>
#include FT_INTERNAL_OBJECTS_H
#include FT_INTERNAL_DEBUG_H
#include "pshalgo1.h"
#ifdef DEBUG_HINTER
extern PSH1_Hint_Table ps1_debug_hint_table = 0;
extern PSH1_HintFunc ps1_debug_hint_func = 0;
#endif
/************************************************************************/
/************************************************************************/
/***** *****/
/***** BASIC HINTS RECORDINGS *****/
/***** *****/
/************************************************************************/
/************************************************************************/
/* return true iff two stem hints overlap */
static FT_Int
psh1_hint_overlap( PSH1_Hint hint1,
PSH1_Hint hint2 )
{
return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
hint2->org_pos + hint2->org_len >= hint1->org_pos );
}
/* destroy hints table */
static void
psh1_hint_table_done( PSH1_Hint_Table table,
FT_Memory memory )
{
FREE( table->zones );
table->num_zones = 0;
table->zone = 0;
FREE( table->sort );
FREE( table->hints );
table->num_hints = 0;
table->max_hints = 0;
table->sort_global = 0;
}
/* deactivate all hints in a table */
static void
psh1_hint_table_deactivate( PSH1_Hint_Table table )
{
FT_UInt count = table->max_hints;
PSH1_Hint hint = table->hints;
for ( ; count > 0; count--, hint++ )
{
psh1_hint_deactivate(hint);
hint->order = -1;
}
}
/* internal function used to record a new hint */
static void
psh1_hint_table_record( PSH1_Hint_Table table,
FT_UInt index )
{
PSH1_Hint hint = table->hints + index;
if ( index >= table->max_hints )
{
FT_ERROR(( "%s.activate: invalid hint index %d\n", index ));
return;
}
/* ignore active hints */
if ( psh1_hint_is_active(hint) )
return;
psh1_hint_activate(hint);
/* now scan the current active hint set in order to determine */
/* if we're overlapping with another segment.. */
{
PSH1_Hint* sorted = table->sort_global;
FT_UInt count = table->num_hints;
PSH1_Hint hint2;
hint->parent = 0;
for ( ; count > 0; count--, sorted++ )
{
hint2 = sorted[0];
if ( psh1_hint_overlap( hint, hint2 ) )
{
hint->parent = hint2;
break;
}
}
}
if ( table->num_hints < table->max_hints )
table->sort_global[ table->num_hints++ ] = hint;
else
{
FT_ERROR(( "%s.activate: too many sorted hints !! BUG !!\n",
"ps.fitter" ));
}
}
static void
psh1_hint_table_record_mask( PSH1_Hint_Table table,
PS_Mask hint_mask )
{
FT_Int mask = 0, val = 0;
FT_Byte* cursor = hint_mask->bytes;
FT_UInt index, limit;
limit = hint_mask->num_bits;
if ( limit != table->max_hints )
{
FT_ERROR(( "%s.activate_mask: invalid bit count (%d instead of %d)\n",
"ps.fitter", hint_mask->num_bits, table->max_hints ));
}
for ( index = 0; index < limit; index++ )
{
if ( mask == 0 )
{
val = *cursor++;
mask = 0x80;
}
if ( val & mask )
psh1_hint_table_record( table, index );
mask >>= 1;
}
}
/* create hints table */
static FT_Error
psh1_hint_table_init( PSH1_Hint_Table table,
PS_Hint_Table hints,
PS_Mask_Table hint_masks,
PS_Mask_Table counter_masks,
FT_Memory memory )
{
FT_UInt count = hints->num_hints;
FT_Error error;
FT_UNUSED(counter_masks);
/* allocate our tables */
if ( ALLOC_ARRAY( table->sort, 2*count, PSH1_Hint ) ||
ALLOC_ARRAY( table->hints, count, PSH1_HintRec ) ||
ALLOC_ARRAY( table->zones, 2*count+1, PSH1_ZoneRec ) )
goto Exit;
table->max_hints = count;
table->sort_global = table->sort + count;
table->num_hints = 0;
table->num_zones = 0;
table->zone = 0;
/* now, initialise the "hints" array */
{
PSH1_Hint write = table->hints;
PS_Hint read = hints->hints;
for ( ; count > 0; count--, write++, read++ )
{
write->org_pos = read->pos;
write->org_len = read->len;
write->flags = read->flags;
}
}
/* we now need to determine the initial "parent" stems, first */
/* activate the hints that are given by the initial hint masks */
if ( hint_masks )
{
FT_UInt count = hint_masks->num_masks;
PS_Mask mask = hint_masks->masks;
table->hint_masks = hint_masks;
for ( ; count > 0; count--, mask++ )
psh1_hint_table_record_mask( table, mask );
}
/* now, do a linear parse in case some hints were left alone */
if ( table->num_hints != table->max_hints )
{
FT_UInt index, count;
FT_ERROR(( "%s.init: missing/incorrect hint masks !!\n" ));
count = table->max_hints;
for ( index = 0; index < count; index++ )
psh1_hint_table_record( table, index );
}
Exit:
return error;
}
static void
psh1_hint_table_activate_mask( PSH1_Hint_Table table,
PS_Mask hint_mask )
{
FT_Int mask = 0, val = 0;
FT_Byte* cursor = hint_mask->bytes;
FT_UInt index, limit, count;
limit = hint_mask->num_bits;
count = 0;
psh1_hint_table_deactivate( table );
for ( index = 0; index < limit; index++ )
{
if ( mask == 0 )
{
val = *cursor++;
mask = 0x80;
}
if ( val & mask )
{
PSH1_Hint hint = &table->hints[index];
if ( !psh1_hint_is_active(hint) )
{
PSH1_Hint* sort = table->sort;
FT_UInt count2;
PSH1_Hint hint2;
for ( count2 = count; count2 > 0; count2--, sort++ )
{
hint2 = sort[0];
if ( psh1_hint_overlap( hint, hint2 ) )
{
FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
"psf.hint" ));
break;
}
}
if ( count2 == 0 )
{
psh1_hint_activate( hint );
if ( count < table->max_hints )
table->sort[count++] = hint;
else
{
FT_ERROR(( "%s.activate_mask: too many active hints\n",
"psf.hint" ));
}
}
}
}
mask >>= 1;
}
table->num_hints = count;
/* now, sort the hints, they're guaranteed to not overlap */
/* so we can compare their "org_pos" field directly.. */
{
FT_Int i1, i2;
PSH1_Hint hint1, hint2;
PSH1_Hint* sort = table->sort;
/* a simple bubble sort will do, since in 99% of cases, the hints */
/* will be already sorted.. and the sort will be linear */
for ( i1 = 1; i1 < (FT_Int)count; i1++ )
{
hint1 = sort[i1];
for ( i2 = i1-1; i2 >= 0; i2-- )
{
hint2 = sort[i2];
if ( hint2->org_pos < hint1->org_pos )
break;
sort[i1] = hint2;
sort[i2] = hint1;
}
}
}
}
/************************************************************************/
/************************************************************************/
/***** *****/
/***** HINTS GRID-FITTING AND OPTIMISATION *****/
/***** *****/
/************************************************************************/
/************************************************************************/
#ifdef DEBUG_HINTER
void
ps_simple_scale( PSH1_Hint_Table table,
FT_Fixed scale,
FT_Fixed delta,
FT_Bool vertical )
{
PSH1_Hint hint;
FT_UInt count;
for ( count = 0; count < table->num_hints; count++ )
{
hint = table->sort[count];
if ( psh1_hint_is_active(hint) )
{
hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
hint->cur_len = FT_MulFix( hint->org_len, scale );
if (ps1_debug_hint_func)
ps1_debug_hint_func( hint, vertical );
}
}
}
#endif
FT_LOCAL_DEF FT_Error
psh1_hint_table_optimize( PSH1_Hint_Table table,
PSH_Globals globals,
FT_Outline* outline,
FT_Bool vertical )
{
PSH_Dimension dim = &globals->dimension[vertical];
FT_Fixed scale = dim->scale_mult;
FT_Fixed delta = dim->scale_delta;
#ifdef DEBUG_HINTER
if ( ps_debug_no_vert_hints && vertical )
{
ps_simple_scale( table, scale, delta, vertical );
return 0;
}
if ( ps_debug_no_horz_hints && !vertical )
{
ps_simple_scale( table, scale, delta, vertical );
return 0;
}
#endif
/* XXXX: for now, we only scale the hints to test all other aspects */
/* of the Postscript Hinter.. */
{
PSH1_Hint hint;
FT_UInt count;
for ( count = 0; count < table->num_hints; count++ )
{
hint = table->sort[count];
if ( psh1_hint_is_active(hint) )
{
# if 1
FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
FT_Pos len = FT_MulFix( hint->org_len, scale );
FT_Pos fit_center;
FT_Pos fit_len;
PSH_AlignmentRec align;
/* compute fitted width/height */
fit_len = psh_dimension_snap_width( dim, hint->org_len );
if ( fit_len < 64 )
fit_len = 64;
else
fit_len = (fit_len + 32 ) & -64;
hint->cur_len = fit_len;
/* check blue zones for horizontal stems */
align.align = 0;
if (!vertical)
{
psh_blues_snap_stem( &globals->blues,
hint->org_pos + hint->org_len,
hint->org_pos,
&align );
}
switch (align.align)
{
case PSH_BLUE_ALIGN_TOP:
{
/* the top of the stem is aligned against a blue zone */
hint->cur_pos = align.align_top - fit_len;
break;
}
case PSH_BLUE_ALIGN_BOT:
{
/* the bottom of the stem is aligned against a blue zone */
hint->cur_pos = align.align_bot;
break;
}
case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
{
/* both edges of the stem are aligned against blue zones */
hint->cur_pos = align.align_bot;
hint->cur_len = align.align_top - align.align_bot;
}
break;
default:
/* normal processing */
if ( (fit_len/64) & 1 )
{
/* odd number of pixels */
fit_center = ((pos + (len >> 1)) & -64) + 32;
}
else
{
/* even number of pixels */
fit_center = (pos + (len >> 1) + 32) & -64;
}
hint->cur_pos = fit_center - (fit_len >> 1);
}
# else
hint->cur_pos = (FT_MulFix( hint->org_pos, scale ) + delta + 32) & -64;
hint->cur_len = FT_MulFix( hint->org_len, scale );
# endif
#ifdef DEBUG_HINTER
if (ps1_debug_hint_func)
ps1_debug_hint_func( hint, vertical );
#endif
}
}
}
return 0;
}
/************************************************************************/
/************************************************************************/
/***** *****/
/***** POINTS INTERPOLATION ROUTINES *****/
/***** *****/
/************************************************************************/
/************************************************************************/
#define PSH1_ZONE_MIN -3200000
#define PSH1_ZONE_MAX +3200000
#define xxDEBUG_ZONES
#ifdef DEBUG_ZONES
#include <stdio.h>
static void
print_zone( PSH1_Zone zone )
{
printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
zone->scale/65536.0,
zone->delta/64.0,
zone->min,
zone->max );
}
#else
# define print_zone(x) do { } while (0)
#endif
/* setup interpolation zones once the hints have been grid-fitted */
/* by the optimizer.. */
static void
psh1_hint_table_setup_zones( PSH1_Hint_Table table,
FT_Fixed scale,
FT_Fixed delta )
{
FT_UInt count;
PSH1_Zone zone;
PSH1_Hint *sort, hint, hint2;
zone = table->zones;
/* special case, no hints defined */
if ( table->num_hints == 0 )
{
zone->scale = scale;
zone->delta = delta;
zone->min = PSH1_ZONE_MIN;
zone->max = PSH1_ZONE_MAX;
table->num_zones = 1;
table->zone = zone;
return;
}
/* the first zone is before the first hint */
/* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
sort = table->sort;
hint = sort[0];
zone->scale = scale;
zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
zone->min = PSH1_ZONE_MIN;
zone->max = hint->org_pos;
print_zone( zone );
zone++;
for ( count = table->num_hints; count > 0; count-- )
{
FT_Fixed scale2;
if ( hint->org_len > 0 )
{
/* setup a zone for inner-stem interpolation */
/* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0) */
/* x' = x*s2 + x0' - x0*s2 */
scale2 = FT_DivFix( hint->cur_len, hint->org_len );
zone->scale = scale2;
zone->min = hint->org_pos;
zone->max = hint->org_pos + hint->org_len;
zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
print_zone( zone );
zone++;
}
if ( count == 1 )
break;
sort++;
hint2 = sort[0];
/* setup zone for inter-stem interpolation */
/* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1) */
/* x' = x*s3 + x1' - x1*s3 */
scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
hint2->org_pos - (hint->org_pos + hint->org_len) );
zone->scale = scale2;
zone->min = hint->org_pos + hint->org_len;
zone->max = hint2->org_pos;
zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale2 );
print_zone( zone );
zone++;
hint = hint2;
}
/* the last zone */
zone->scale = scale;
zone->min = hint->org_pos + hint->org_len;
zone->max = PSH1_ZONE_MAX;
zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale );
print_zone( zone );
zone++;
table->num_zones = zone - table->zones;
table->zone = table->zones;
}
/* tune a single coordinate with the current interpolation zones */
static FT_Pos
psh1_hint_table_tune_coord( PSH1_Hint_Table table,
FT_Int coord )
{
PSH1_Zone zone;
zone = table->zone;
if ( coord < zone->min )
{
do
{
if ( zone == table->zones )
break;
zone--;
}
while ( coord < zone->min );
table->zone = zone;
}
else if ( coord > zone->max )
{
do
{
if ( zone == table->zones + table->num_zones - 1 )
break;
zone++;
}
while ( coord > zone->max );
table->zone = zone;
}
return FT_MulFix( coord, zone->scale ) + zone->delta;
}
/* tune a given outline with current interpolation zones */
/* the function only works in a single dimension.. */
static void
psh1_hint_table_tune_outline( PSH1_Hint_Table table,
FT_Outline* outline,
PSH_Globals globals,
FT_Bool vertical )
{
FT_UInt count, first, last;
PS_Mask_Table hint_masks = table->hint_masks;
PS_Mask mask;
PSH_Dimension dim = &globals->dimension[vertical];
FT_Fixed scale = dim->scale_mult;
FT_Fixed delta = dim->scale_delta;
if ( hint_masks && hint_masks->num_masks > 0 )
{
first = 0;
mask = hint_masks->masks;
count = hint_masks->num_masks;
for ( ; count > 0; count--, mask++ )
{
last = mask->end_point;
if ( last > first )
{
FT_Vector* vec;
FT_Int count2;
psh1_hint_table_activate_mask( table, mask );
psh1_hint_table_optimize( table, globals, outline, vertical );
psh1_hint_table_setup_zones( table, scale, delta );
last = mask->end_point;
vec = outline->points + first;
count2 = last - first;
for ( ; count2 > 0; count2--, vec++ )
{
FT_Pos x, *px;
px = vertical ? &vec->x : &vec->y;
x = *px;
*px = psh1_hint_table_tune_coord( table, (FT_Int)x );
}
}
first = last;
}
}
else /* no hints in this glyph, simply scale the outline */
{
FT_Vector* vec;
vec = outline->points;
count = outline->n_points;
if ( vertical )
{
for ( ; count > 0; count--, vec++ )
vec->x = FT_MulFix( vec->x, scale ) + delta;
}
else
{
for ( ; count > 0; count--, vec++ )
vec->y = FT_MulFix( vec->y, scale ) + delta;
}
}
}
/************************************************************************/
/************************************************************************/
/***** *****/
/***** HIGH-LEVEL INTERFACE *****/
/***** *****/
/************************************************************************/
/************************************************************************/
FT_Error
ps1_hints_apply( PS_Hints ps_hints,
FT_Outline* outline,
PSH_Globals globals )
{
PSH1_Hint_TableRec hints;
FT_Error error;
FT_Int dimension;
for ( dimension = 1; dimension >= 0; dimension-- )
{
PS_Dimension dim = &ps_hints->dimension[dimension];
/* initialise hints table */
memset( &hints, 0, sizeof(hints) );
error = psh1_hint_table_init( &hints,
&dim->hints,
&dim->masks,
&dim->counters,
ps_hints->memory );
if (error) goto Exit;
psh1_hint_table_tune_outline( &hints,
outline,
globals,
dimension );
psh1_hint_table_done( &hints, ps_hints->memory );
}
Exit:
return error;
}

100
src/pshinter/pshalgo1.h Normal file
View File

@ -0,0 +1,100 @@
/***************************************************************************/
/* */
/* pshalgo1.h */
/* */
/* First (basic) Postscript hinting routines */
/* */
/* Copyright 2001 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. */
/* */
/***************************************************************************/
#ifndef __PS_HINTER_ALGO1_H__
#define __PS_HINTER_ALGO1_H__
#include "pshrec.h"
FT_BEGIN_HEADER
typedef struct PSH1_HintRec_* PSH1_Hint;
typedef enum
{
PSH1_HINT_FLAG_GHOST = PS_HINT_FLAG_GHOST,
PSH1_HINT_FLAG_BOTTOM = PS_HINT_FLAG_BOTTOM,
PSH1_HINT_FLAG_ACTIVE = 4
} PSH1_Hint_Flags;
#define psh1_hint_is_active(x) (((x)->flags & PSH1_HINT_FLAG_ACTIVE) != 0)
#define psh1_hint_is_ghost(x) (((x)->flags & PSH1_HINT_FLAG_GHOST ) != 0)
#define psh1_hint_activate(x) (x)->flags |= PSH1_HINT_FLAG_ACTIVE
#define psh1_hint_deactivate(x) (x)->flags &= ~PSH1_HINT_FLAG_ACTIVE
typedef struct PSH1_HintRec_
{
FT_Int org_pos;
FT_Int org_len;
FT_Pos cur_pos;
FT_Pos cur_len;
FT_UInt flags;
PSH1_Hint parent;
FT_Int order;
} PSH1_HintRec;
/* this is an interpolation zone used for strong points */
/* weak points are interpolated according to their strong */
/* neighbours.. */
typedef struct PSH1_ZoneRec_
{
FT_Fixed scale;
FT_Fixed delta;
FT_Pos min;
FT_Pos max;
} PSH1_ZoneRec, *PSH1_Zone;
typedef struct PSH1_Hint_TableRec_
{
FT_UInt max_hints;
FT_UInt num_hints;
PSH1_Hint hints;
PSH1_Hint* sort;
PSH1_Hint* sort_global;
FT_UInt num_zones;
PSH1_Zone zones;
PSH1_Zone zone;
PS_Mask_Table hint_masks;
PS_Mask_Table counter_masks;
} PSH1_Hint_TableRec, *PSH1_Hint_Table;
extern FT_Error
ps1_hints_apply( PS_Hints ps_hints,
FT_Outline* outline,
PSH_Globals globals );
#ifdef DEBUG_HINTER
extern PSH1_Hint_Table ps1_debug_hint_table;
typedef void (*PSH1_HintFunc)( PSH1_Hint hint, FT_Bool vertical );
extern PSH1_HintFunc ps1_debug_hint_func;
#endif
FT_END_HEADER
#endif /* __PS_HINTER_FITTER_H__ */

1484
src/pshinter/pshalgo2.c Normal file

File diff suppressed because it is too large Load Diff

185
src/pshinter/pshalgo2.h Normal file
View File

@ -0,0 +1,185 @@
/***************************************************************************/
/* */
/* pshalgo2.h */
/* */
/* First (basic) Postscript hinting routines */
/* */
/* Copyright 2001 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. */
/* */
/***************************************************************************/
#ifndef __PS_HINTER_ALGO2_H__
#define __PS_HINTER_ALGO2_H__
#include "pshrec.h"
#include "pshglob.h"
#include FT_TRIGONOMETRY_H
FT_BEGIN_HEADER
typedef struct PSH2_HintRec_* PSH2_Hint;
typedef enum
{
PSH2_HINT_GHOST = PS_HINT_FLAG_GHOST,
PSH2_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM,
PSH2_HINT_ACTIVE = 4,
PSH2_HINT_FITTED = 8
} PSH2_Hint_Flags;
#define psh2_hint_is_active(x) (((x)->flags & PSH2_HINT_ACTIVE) != 0)
#define psh2_hint_is_ghost(x) (((x)->flags & PSH2_HINT_GHOST) != 0)
#define psh2_hint_is_fitted(x) (((x)->flags & PSH2_HINT_FITTED) != 0)
#define psh2_hint_activate(x) (x)->flags |= PSH2_HINT_ACTIVE
#define psh2_hint_deactivate(x) (x)->flags &= ~PSH2_HINT_ACTIVE
#define psh2_hint_set_fitted(x) (x)->flags |= PSH2_HINT_FITTED
typedef struct PSH2_HintRec_
{
FT_Int org_pos;
FT_Int org_len;
FT_Pos cur_pos;
FT_Pos cur_len;
FT_UInt flags;
PSH2_Hint parent;
FT_Int order;
} PSH2_HintRec;
/* this is an interpolation zone used for strong points */
/* weak points are interpolated according to their strong */
/* neighbours.. */
typedef struct PSH2_ZoneRec_
{
FT_Fixed scale;
FT_Fixed delta;
FT_Pos min;
FT_Pos max;
} PSH2_ZoneRec, *PSH2_Zone;
typedef struct PSH2_Hint_TableRec_
{
FT_UInt max_hints;
FT_UInt num_hints;
PSH2_Hint hints;
PSH2_Hint* sort;
PSH2_Hint* sort_global;
FT_UInt num_zones;
PSH2_Zone zones;
PSH2_Zone zone;
PS_Mask_Table hint_masks;
PS_Mask_Table counter_masks;
} PSH2_Hint_TableRec, *PSH2_Hint_Table;
typedef struct PSH2_PointRec_* PSH2_Point;
typedef struct PSH2_ContourRec_* PSH2_Contour;
enum
{
PSH2_DIR_NONE = 4,
PSH2_DIR_UP = 1,
PSH2_DIR_DOWN = -1,
PSH2_DIR_LEFT = -2,
PSH2_DIR_RIGHT = 2
};
enum
{
PSH2_POINT_OFF = 1, /* point is off the curve */
PSH2_POINT_STRONG = 2, /* point is strong */
PSH2_POINT_SMOOTH = 4, /* point is smooth */
PSH2_POINT_FITTED = 8 /* point is already fitted */
};
typedef struct PSH2_PointRec_
{
PSH2_Point prev;
PSH2_Point next;
PSH2_Contour contour;
FT_UInt flags;
FT_Char dir_in;
FT_Char dir_out;
FT_Angle angle_in;
FT_Angle angle_out;
PSH2_Hint hint;
FT_Pos org_u;
FT_Pos cur_u;
#ifdef DEBUG_HINTER
FT_Pos org_x;
FT_Pos cur_x;
FT_Pos org_y;
FT_Pos cur_y;
FT_UInt flags_x;
FT_UInt flags_y;
#endif
} PSH2_PointRec;
#define psh2_point_is_strong(p) ((p)->flags & PSH2_POINT_STRONG)
#define psh2_point_is_fitted(p) ((p)->flags & PSH2_POINT_FITTED)
#define psh2_point_is_smooth(p) ((p)->flags & PSH2_POINT_SMOOTH)
#define psh2_point_set_strong(p) (p)->flags |= PSH2_POINT_STRONG
#define psh2_point_set_fitted(p) (p)->flags |= PSH2_POINT_FITTED
#define psh2_point_set_smooth(p) (p)->flags |= PSH2_POINT_SMOOTH
typedef struct PSH2_ContourRec_
{
PSH2_Point start;
FT_UInt count;
} PSH2_ContourRec;
typedef struct PSH2_GlyphRec_
{
FT_UInt num_points;
FT_UInt num_contours;
PSH2_Point points;
PSH2_Contour contours;
FT_Memory memory;
FT_Outline* outline;
PSH_Globals globals;
PSH2_Hint_TableRec hint_tables[2];
FT_Bool vertical;
FT_Int major_dir;
FT_Int minor_dir;
} PSH2_GlyphRec, *PSH2_Glyph;
#ifdef DEBUG_HINTER
extern PSH2_Hint_Table ps2_debug_hint_table;
typedef void (*PSH2_HintFunc)( PSH2_Hint hint, FT_Bool vertical );
extern PSH2_HintFunc ps2_debug_hint_func;
extern PSH2_Glyph ps2_debug_glyph;
#endif
extern FT_Error
ps2_hints_apply( PS_Hints ps_hints,
FT_Outline* outline,
PSH_Globals globals );
FT_END_HEADER
#endif /* __PS_HINTS_ALGO_2_H__ */

553
src/pshinter/pshglob.c Normal file
View File

@ -0,0 +1,553 @@
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_INTERNAL_OBJECTS_H
#include "pshglob.h"
#ifdef DEBUG_HINTER
extern PSH_Globals ps_debug_globals = 0;
#endif
/* "simple" ps hinter globals management, inspired from the new auto-hinter */
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** STANDARD WIDTHS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* scale the widths/heights table */
static void
psh_globals_scale_widths( PSH_Globals globals,
FT_UInt direction )
{
PSH_Dimension dim = &globals->dimension[direction];
PSH_Widths std = &dim->std;
FT_UInt count = std->count;
PSH_Width width = std->widths;
FT_Fixed scale = dim->scale_mult;
for ( ; count > 0; count--, width++ )
{
width->cur = FT_MulFix( width->org, scale );
width->fit = FT_RoundFix( width->cur );
}
}
/* org_width is is font units, result in device pixels, 26.6 format */
FT_LOCAL_DEF FT_Pos
psh_dimension_snap_width( PSH_Dimension dimension,
FT_Int org_width )
{
FT_UInt n;
FT_Pos width = FT_MulFix( org_width, dimension->scale_mult );
FT_Pos best = 64 + 32 + 2;
FT_Pos reference = width;
for ( n = 0; n < dimension->std.count; n++ )
{
FT_Pos w;
FT_Pos dist;
w = dimension->std.widths[n].cur;
dist = width - w;
if ( dist < 0 )
dist = -dist;
if ( dist < best )
{
best = dist;
reference = w;
}
}
if ( width >= reference )
{
width -= 0x21;
if ( width < reference )
width = reference;
}
else
{
width += 0x21;
if ( width > reference )
width = reference;
}
return width;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** BLUE ZONES *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
static void
psh_blues_set_zones_0( PSH_Blues target,
FT_Bool is_others,
FT_UInt read_count,
FT_Short* read,
PSH_Blue_Table top_table,
PSH_Blue_Table bot_table )
{
FT_UInt count_top = top_table->count;
FT_UInt count_bot = bot_table->count;
FT_Bool first = 1;
for ( ; read_count > 0; read_count -= 2 )
{
FT_Int reference, delta;
FT_UInt count;
PSH_Blue_Zone zones, zone;
FT_Bool top;
/* read blue zone entry, and select target top/bottom zone */
top = 0;
if ( first || is_others )
{
reference = read[1];
delta = read[0] - reference;
zones = bot_table->zones;
count = count_bot;
first = 0;
}
else
{
reference = read[0];
delta = read[1] - reference;
zones = top_table->zones;
count = count_top;
top = 1;
}
/* insert into sorted table */
zone = zones;
for ( ; count > 0; count--, zone++ )
{
if ( reference < zone->org_ref )
break;
if ( reference == zone->org_ref )
{
FT_Int delta0 = zone->org_delta;
/* we have two zones on the same reference position */
/* only keep the largest one.. */
if ( delta < 0 )
{
if ( delta < delta0 )
zone->org_delta = delta;
}
else
{
if ( delta > delta0 )
zone->org_delta = delta;
}
goto Skip;
}
}
for ( ; count > 0; count-- )
zone[count] = zone[count-1];
zone->org_ref = reference;
zone->org_delta = delta;
if ( top )
count_top ++;
else
count_bot ++;
Skip:
read += 2;
}
top_table->count = count_top;
bot_table->count = count_bot;
}
/* re-read blue zones from the original fonts, and store them into out */
/* private structure. This function re-orders, sanitizes and fuzz-expands */
/* the zones as well.. */
static void
psh_blues_set_zones( PSH_Blues target,
FT_UInt count,
FT_Short* blues,
FT_UInt count_others,
FT_Short* other_blues,
FT_Int fuzz,
FT_Int family )
{
PSH_Blue_Table top_table, bot_table;
FT_Int count_top, count_bot;
if ( family )
{
top_table = &target->family_top;
bot_table = &target->family_bottom;
}
else
{
top_table = &target->normal_top;
bot_table = &target->normal_bottom;
}
/* read the input blue zones, and build two sorted tables */
/* (one for the top zones, the other for the bottom zones */
top_table->count = 0;
bot_table->count = 0;
/* first, the blues */
psh_blues_set_zones_0( target, 0, count, blues, top_table, bot_table );
psh_blues_set_zones_0( target, 1, count_others, other_blues, top_table, bot_table );
count_top = top_table->count;
count_bot = bot_table->count;
/* sanitize top table */
if ( count_top > 0 )
{
PSH_Blue_Zone zone = top_table->zones;
for ( count = count_top; count > 0; count--, zone++ )
{
FT_Int delta;
if ( count > 1 )
{
delta = zone[1].org_ref - zone[0].org_ref;
if ( zone->org_delta > delta )
zone->org_delta = delta;
}
zone->org_bottom = zone->org_ref;
zone->org_top = zone->org_delta + zone->org_ref;
}
}
/* sanitize bottom table */
if ( count_bot > 0 )
{
PSH_Blue_Zone zone = bot_table->zones;
for ( count = count_bot; count > 0; count--, zone++ )
{
FT_Int delta;
if ( count > 1 )
{
delta = zone[0].org_ref - zone[1].org_ref;
if ( zone->org_delta < delta )
zone->org_delta = delta;
}
zone->org_top = zone->org_ref;
zone->org_bottom = zone->org_delta + zone->org_ref;
}
}
/* expand top and bottom tables with blue fuzz */
{
FT_Int dim, top, bot, delta;
PSH_Blue_Zone zone;
zone = top_table->zones;
count = count_top;
for ( dim = 1; dim >= 0; dim-- )
{
if ( count > 0 )
{
/* expand the bottom of the lowest zone normally */
zone->org_bottom -= fuzz;
/* expand the top and bottom of intermediate zones */
/* checking that the interval is smaller than the fuzz */
top = zone->org_top;
for ( count--; count > 0; count-- )
{
bot = zone[1].org_bottom;
delta = bot - top;
if ( delta < 2*fuzz )
{
zone[0].org_top = zone[1].org_bottom = top + delta/2;
}
else
{
zone[0].org_top = top + fuzz;
zone[1].org_bottom = bot - fuzz;
}
zone++;
top = zone->org_top;
}
/* expand the top of the highest zone normally */
zone->org_top = top + fuzz;
}
zone = bot_table->zones;
count = count_bot;
}
}
}
/* reset the blues table when the device transform changes */
static void
psh_blues_scale_zones( PSH_Blues blues,
FT_Fixed scale,
FT_Pos delta )
{
FT_UInt count;
FT_UInt num;
PSH_Blue_Table table = 0;
for ( num = 0; num < 4; num++ )
{
PSH_Blue_Zone zone;
switch (num)
{
case 0: table = &blues->normal_top; break;
case 1: table = &blues->normal_bottom; break;
case 2: table = &blues->family_top; break;
default: table = &blues->family_bottom;
}
zone = table->zones;
count = table->count;
for ( ; count > 0; count--, zone++ )
{
zone->cur_top = FT_MulFix( zone->org_top, scale ) + delta;
zone->cur_bottom = FT_MulFix( zone->org_bottom, scale ) + delta;
zone->cur_ref = FT_MulFix( zone->org_ref, scale ) + delta;
zone->cur_delta = FT_MulFix( zone->org_delta, scale );
/* round scaled reference position */
zone->cur_ref = ( zone->cur_ref + 32 ) & -64;
#if 0
if ( zone->cur_ref > zone->cur_top )
zone->cur_ref -= 64;
else if ( zone->cur_ref < zone->cur_bottom )
zone->cur_ref += 64;
#endif
}
}
/* XXX: we should process the family / normal tables here !! */
}
FT_LOCAL_DEF void
psh_blues_snap_stem( PSH_Blues blues,
FT_Int stem_top,
FT_Int stem_bot,
PSH_Alignment alignment )
{
PSH_Blue_Table table;
FT_UInt count;
PSH_Blue_Zone zone;
alignment->align = 0;
/* lookup stem top in top zones table */
table = &blues->normal_top;
count = table->count;
zone = table->zones;
for ( ; count > 0; count--, zone++ )
{
if ( stem_top < zone->org_bottom )
break;
if ( stem_top <= zone->org_top )
{
alignment->align |= PSH_BLUE_ALIGN_TOP;
alignment->align_top = zone->cur_ref;
break;
}
}
/* lookup stem bottom in bottom zones table */
table = &blues->normal_bottom;
count = table->count;
zone = table->zones;
for ( ; count > 0; count--, zone++ )
{
if ( stem_bot < zone->org_bottom )
break;
if ( stem_bot <= zone->org_top )
{
alignment->align |= PSH_BLUE_ALIGN_BOT;
alignment->align_bot = zone->cur_ref;
break;
}
}
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** GLOBAL HINTS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
static void
psh_globals_destroy( PSH_Globals globals )
{
if (globals)
{
FT_Memory memory;
memory = globals->memory;
globals->dimension[0].std.count = 0;
globals->dimension[1].std.count = 0;
globals->blues.normal_top.count = 0;
globals->blues.normal_bottom.count = 0;
globals->blues.family_top.count = 0;
globals->blues.family_bottom.count = 0;
FREE( globals );
#ifdef DEBUG_HINTER
ps_debug_globals = 0;
#endif
}
}
static FT_Error
psh_globals_new( FT_Memory memory,
T1_Private* priv,
PSH_Globals *aglobals )
{
PSH_Globals globals;
FT_Error error;
if ( !ALLOC( globals, sizeof(*globals) ) )
{
FT_UInt count;
FT_Short* read;
globals->memory = memory;
/* copy standard widths */
{
PSH_Dimension dim = &globals->dimension[1];
PSH_Width write = dim->std.widths;
write->org = priv->standard_width[1];
write++;
read = priv->snap_widths;
for ( count = priv->num_snap_widths; count > 0; count-- )
{
write->org = *read;
write++;
read++;
}
dim->std.count = write - dim->std.widths;
}
/* copy standard heights */
{
PSH_Dimension dim = &globals->dimension[0];
PSH_Width write = dim->std.widths;
write->org = priv->standard_height[1];
write++;
read = priv->snap_heights;
for ( count = priv->num_snap_heights; count > 0; count-- )
{
write->org = *read;
write++;
read++;
}
dim->std.count = write - dim->std.widths;
}
/* copy blue zones */
psh_blues_set_zones( &globals->blues, priv->num_blue_values,
priv->blue_values, priv->num_other_blues,
priv->other_blues, priv->blue_fuzz, 0 );
psh_blues_set_zones( &globals->blues, priv->num_family_blues,
priv->family_blues, priv->num_family_other_blues,
priv->family_other_blues, priv->blue_fuzz, 1 );
globals->dimension[0].scale_mult = 0;
globals->dimension[0].scale_delta = 0;
globals->dimension[1].scale_mult = 0;
globals->dimension[1].scale_delta = 0;
#ifdef DEBUG_HINTER
ps_debug_globals = globals;
#endif
}
*aglobals = globals;
return error;
}
static FT_Error
psh_globals_set_scale( PSH_Globals globals,
FT_Fixed x_scale,
FT_Fixed y_scale,
FT_Fixed x_delta,
FT_Fixed y_delta )
{
PSH_Dimension dim = &globals->dimension[0];
dim = &globals->dimension[0];
if ( x_scale != dim->scale_mult ||
x_delta != dim->scale_delta )
{
dim->scale_mult = x_scale;
dim->scale_delta = x_delta;
psh_globals_scale_widths( globals, 0 );
}
dim = &globals->dimension[1];
if ( y_scale != dim->scale_mult ||
y_delta != dim->scale_delta )
{
dim->scale_mult = y_scale;
dim->scale_delta = y_delta;
psh_globals_scale_widths( globals, 1 );
psh_blues_scale_zones( &globals->blues, y_scale, y_delta );
}
return 0;
}
FT_LOCAL_DEF void
psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs )
{
funcs->create = psh_globals_new;
funcs->set_scale = psh_globals_set_scale;
funcs->destroy = psh_globals_destroy;
}

171
src/pshinter/pshglob.h Normal file
View File

@ -0,0 +1,171 @@
/***************************************************************************/
/* */
/* pshglob.h */
/* */
/* Postscript hinter globals hints management. */
/* */
/* Copyright 2001 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. */
/* */
/***************************************************************************/
#ifndef __PS_HINTER_GLOBALS_H__
#define __PS_HINTER_GLOBALS_H__
#include FT_FREETYPE_H
#include FT_INTERNAL_POSTSCRIPT_GLOBALS_H
#include FT_INTERNAL_POSTSCRIPT_HINTS_H
FT_BEGIN_HEADER
/**********************************************************************/
/**********************************************************************/
/***** *****/
/***** GLOBAL HINTS INTERNALS *****/
/***** *****/
/**********************************************************************/
/**********************************************************************/
/****************************************************************
*
* @constant: PS_GLOBALS_MAX_BLUE_ZONES
*
* @description:
* the maximum number of blue zones in a font global hints
* structure. See @PS_Globals_BluesRec
*/
#define PS_GLOBALS_MAX_BLUE_ZONES 16
/****************************************************************
*
* @constant: PS_GLOBALS_MAX_STD_WIDTHS
*
* @description:
* the maximum number of standard and snap widths in either the
* horizontal or vertical direction. See @PS_Globals_WidthsRec
*/
#define PS_GLOBALS_MAX_STD_WIDTHS 16
/* standard and snap width */
typedef struct PSH_WidthRec_
{
FT_Int org;
FT_Pos cur;
FT_Pos fit;
} PSH_WidthRec, *PSH_Width;
/* standard and snap widths table */
typedef struct PSH_WidthsRec_
{
FT_UInt count;
PSH_WidthRec widths[ PS_GLOBALS_MAX_STD_WIDTHS ];
} PSH_WidthsRec, *PSH_Widths;
typedef struct PSH_DimensionRec_
{
PSH_WidthsRec std;
FT_Fixed scale_mult;
FT_Fixed scale_delta;
} PSH_DimensionRec, *PSH_Dimension;
/* blue zone descriptor */
typedef struct PSH_Blue_ZoneRec_
{
FT_Int org_ref;
FT_Int org_delta;
FT_Int org_top;
FT_Int org_bottom;
FT_Pos cur_ref;
FT_Pos cur_delta;
FT_Pos cur_bottom;
FT_Pos cur_top;
} PSH_Blue_ZoneRec, *PSH_Blue_Zone;
typedef struct PSH_Blue_TableRec_
{
FT_UInt count;
PSH_Blue_ZoneRec zones[ PS_GLOBALS_MAX_BLUE_ZONES ];
} PSH_Blue_TableRec, *PSH_Blue_Table;
/* blue zones table */
typedef struct PSH_BluesRec_
{
PSH_Blue_TableRec normal_top;
PSH_Blue_TableRec normal_bottom;
PSH_Blue_TableRec family_top;
PSH_Blue_TableRec family_bottom;
FT_Fixed blue_scale;
} PSH_BluesRec, *PSH_Blues;
/* font globals */
typedef struct PSH_GlobalsRec_
{
FT_Memory memory;
PSH_DimensionRec dimension[2];
PSH_BluesRec blues;
} PSH_GlobalsRec;
typedef enum
{
PSH_BLUE_ALIGN_TOP = 1,
PSH_BLUE_ALIGN_BOT = 2
} PSH_Blue_Align;
typedef struct
{
PSH_Blue_Align align;
FT_Pos align_top;
FT_Pos align_bot;
} PSH_AlignmentRec, *PSH_Alignment;
FT_LOCAL void
psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs );
/* snap a stem width to fitter coordinates. org_width is in font units */
/* result is in device pixels (26.6 format).. */
FT_LOCAL FT_Pos
psh_dimension_snap_width( PSH_Dimension dimension,
FT_Int org_width );
/* snap a stem to one or two blue zones */
FT_LOCAL void
psh_blues_snap_stem( PSH_Blues blues,
FT_Int stem_top,
FT_Int stem_bot,
PSH_Alignment alignment );
/* */
#ifdef DEBUG_HINTER
extern PSH_Globals ps_debug_globals;
#endif
FT_END_HEADER
#endif __T1_FITTER_GLOBALS_H__

29
src/pshinter/pshinter.c Normal file
View File

@ -0,0 +1,29 @@
/***************************************************************************/
/* */
/* pshinter.c */
/* */
/* FreeType Postscript Hinting module */
/* */
/* Copyright 1996-2000 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. */
/* */
/***************************************************************************/
#define FT_MAKE_OPTION_SINGLE_OBJECT
#include <ft2build.h>
#include "pshrec.c"
#include "pshglob.c"
#include "pshalgo1.c"
#include "pshalgo2.c"
#include "pshmod.c"
/* END */

116
src/pshinter/pshmod.c Normal file
View File

@ -0,0 +1,116 @@
/***************************************************************************/
/* */
/* pshmod.c */
/* */
/* FreeType Postscript hinter module implementation (body). */
/* */
/* Copyright 2000 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_OBJECTS_H
#include "pshrec.h"
#include "pshalgo.h"
/* the Postscript Hinter module structure */
typedef struct
{
FT_ModuleRec root;
PS_HintsRec ps_hints;
PSH_Globals_FuncsRec globals_funcs;
T1_Hints_FuncsRec t1_funcs;
T2_Hints_FuncsRec t2_funcs;
} PS_Hinter_ModuleRec, *PS_Hinter_Module;
/* finalize module */
FT_CALLBACK_DEF void
ps_hinter_done( PS_Hinter_Module module )
{
module->t1_funcs.hints = NULL;
module->t2_funcs.hints = NULL;
ps_hints_done( &module->ps_hints );
}
/* initialise module, create hints recorder and the interface */
FT_CALLBACK_DEF FT_Error
ps_hinter_init( PS_Hinter_Module module )
{
FT_Memory memory = module->root.memory;
ps_hints_init( &module->ps_hints, memory );
psh_globals_funcs_init( &module->globals_funcs );
t1_hints_funcs_init( &module->t1_funcs );
module->t1_funcs.hints = (T1_Hints) & module->ps_hints;
t2_hints_funcs_init( &module->t2_funcs );
module->t2_funcs.hints = (T2_Hints) & module->ps_hints;
return 0;
}
/* returns global hints interface */
FT_CALLBACK_DEF PSH_Globals_Funcs
pshinter_get_globals_funcs( FT_Module module )
{
return &((PS_Hinter_Module)module)->globals_funcs;
}
/* return Type 1 hints interface */
FT_CALLBACK_DEF T1_Hints_Funcs
pshinter_get_t1_funcs( FT_Module module )
{
return &((PS_Hinter_Module)module)->t1_funcs;
}
/* return Type 2 hints interface */
FT_CALLBACK_DEF T2_Hints_Funcs
pshinter_get_t2_funcs( FT_Module module )
{
return &((PS_Hinter_Module)module)->t2_funcs;
}
FT_CALLBACK_DEF
PSHinter_Interface pshinter_interface =
{
pshinter_get_globals_funcs,
pshinter_get_t1_funcs,
pshinter_get_t2_funcs
};
FT_CALLBACK_TABLE_DEF
const FT_Module_Class pshinter_module_class =
{
0,
sizeof( PS_Hinter_ModuleRec ),
"pshinter",
0x10000L,
0x20000L,
&pshinter_interface, /* module-specific interface */
(FT_Module_Constructor) ps_hinter_init,
(FT_Module_Destructor) ps_hinter_done,
(FT_Module_Requester) 0 /* no additional interface for now */
};

37
src/pshinter/pshmod.h Normal file
View File

@ -0,0 +1,37 @@
/***************************************************************************/
/* */
/* pshmod.h */
/* */
/* Postscript hinter module interface */
/* */
/* Copyright 1996-2000 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. */
/* */
/***************************************************************************/
#ifndef __PS_HINTER_MODULE_H__
#define __PS_HINTER_MODULE_H__
#include <ft2build.h>
#include FT_MODULE_H
FT_BEGIN_HEADER
FT_EXPORT_VAR( const FT_Module_Class ) pshinter_module_class;
FT_END_HEADER
#endif /* __PS_HINTER_MODULE_H__ */
/* END */

1112
src/pshinter/pshrec.c Normal file

File diff suppressed because it is too large Load Diff

165
src/pshinter/pshrec.h Normal file
View File

@ -0,0 +1,165 @@
/***************************************************************************/
/* */
/* pshrec.h */
/* */
/* Postscript (Type1/Type2) hints recorder. */
/* */
/* Copyright 2001 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. */
/* */
/* */
/* The functions defined here are called from the Type 1, CID and CFF */
/* font drivers to record the hints of a given character/glyph. */
/* */
/* The hints are recorded in a unified format, and are later processed */
/* by the "optimiser" and "fitter" to adjust the outlines to the pixel */
/* grid. */
/* */
/***************************************************************************/
#ifndef __PS_HINTER_RECORD_H__
#define __PS_HINTER_RECORD_H__
#include <ft2build.h>
#include FT_INTERNAL_POSTSCRIPT_HINTS_H
#include "pshglob.h"
FT_BEGIN_HEADER
/**********************************************************************/
/**********************************************************************/
/***** *****/
/***** GLYPH HINTS RECORDER INTERNALS *****/
/***** *****/
/**********************************************************************/
/**********************************************************************/
/* handle to hint record */
typedef struct PS_HintRec_* PS_Hint;
/* hint types */
typedef enum
{
PS_HINT_TYPE_1 = 1,
PS_HINT_TYPE_2 = 2
} PS_Hint_Type;
/* hint flags */
typedef enum
{
PS_HINT_FLAG_GHOST = 1,
PS_HINT_FLAG_BOTTOM = 2
} PS_Hint_Flags;
/* hint descriptor */
typedef struct PS_HintRec_
{
FT_Int pos;
FT_Int len;
FT_UInt flags;
} PS_HintRec;
#define ps_hint_is_active(x) ((x)->flags & PS_HINT_FLAG_ACTIVE)
#define ps_hint_is_ghost(x) ((x)->flags & PS_HINT_FLAG_GHOST)
#define ps_hint_is_bottom(x) ((x)->flags & PS_HINT_FLAG_BOTTOM)
/* hints table descriptor */
typedef struct PS_Hint_TableRec_
{
FT_UInt num_hints;
FT_UInt max_hints;
PS_Hint hints;
} PS_Hint_TableRec, *PS_Hint_Table;
/* hint and counter mask descriptor */
typedef struct PS_MaskRec_
{
FT_UInt num_bits;
FT_UInt max_bits;
FT_Byte* bytes;
FT_UInt end_point;
} PS_MaskRec, *PS_Mask;
/* masks and counters table descriptor */
typedef struct PS_Mask_TableRec_
{
FT_UInt num_masks;
FT_UInt max_masks;
PS_Mask masks;
} PS_Mask_TableRec, *PS_Mask_Table;
/* dimension-specific hints descriptor */
typedef struct PS_DimensionRec_
{
PS_Hint_TableRec hints;
PS_Mask_TableRec masks;
PS_Mask_TableRec counters;
} PS_DimensionRec, *PS_Dimension;
/* magic value used within PS_HintsRec */
#define PS_HINTS_MAGIC 0x68696e74 /* "hint" */
/* glyph hints descriptor */
typedef struct PS_HintsRec_
{
FT_Memory memory;
FT_Error error;
FT_UInt32 magic;
PS_Hint_Type hint_type;
PS_DimensionRec dimension[2];
} PS_HintsRec, *PS_Hints;
/* */
/* initialise hints recorder */
FT_LOCAL FT_Error
ps_hints_init( PS_Hints hints,
FT_Memory memory );
/* finalize hints recorder */
FT_LOCAL void
ps_hints_done( PS_Hints hints );
/* initialise Type1 hints recorder interface */
FT_LOCAL void
t1_hints_funcs_init( T1_Hints_FuncsRec* funcs );
/* initialise Type2 hints recorder interface */
FT_LOCAL void
t2_hints_funcs_init( T2_Hints_FuncsRec* funcs );
#ifdef DEBUG_HINTER
extern PS_Hints ps_debug_hints;
extern int ps_debug_no_horz_hints;
extern int ps_debug_no_vert_hints;
#endif
/* */
FT_END_HEADER
#endif /* __PS_HINTER_RECORD_H__ */