mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
987 lines
29 KiB
987 lines
29 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: vertical.c *
|
|
* *
|
|
* vertical writing (@face) support functions *
|
|
* whole file should be #ifdef-ed with DBCS_VERT *
|
|
* *
|
|
* Created: 18-Mar-1993 11:55:38 *
|
|
* Author: Takao Kitano [TakaoK] *
|
|
* *
|
|
* Copyright (c) 1993 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
|
|
#include "fd.h"
|
|
//#include "fontfile.h"
|
|
//#include "cvt.h"
|
|
//#include "limits.h"
|
|
//#include "winnls.h"
|
|
|
|
#ifdef DBCS_VERT_DEBUG
|
|
ULONG DebugVertical = 0;
|
|
#endif
|
|
|
|
//
|
|
// Glyph Metamorphosis table (mort) structures
|
|
//
|
|
typedef struct {
|
|
uint16 entrySize; // size in bytes of a lookup entry ( should be 4 )
|
|
uint16 nEntries; // number of lookup entries to be searched
|
|
uint16 searchRange;
|
|
uint16 entrySelector;
|
|
uint16 rangeShift;
|
|
} BinSrchHeader;
|
|
|
|
typedef struct {
|
|
uint16 glyphid1; // the glyph index for the horizontal shape
|
|
uint16 glyphid2; // the glyph index for the vertical shape
|
|
} LookupSingle;
|
|
|
|
typedef struct {
|
|
BYTE constants1[12];
|
|
uint32 length1;
|
|
BYTE onstants2[16];
|
|
BYTE constants3[16];
|
|
BYTE constants4[8];
|
|
uint16 length2;
|
|
BYTE constants5[8];
|
|
BinSrchHeader SearchHeader;
|
|
LookupSingle entries[1];
|
|
} MortTable;
|
|
|
|
//
|
|
// Glyph Substitution table (GSUB) structures
|
|
//
|
|
|
|
#pragma pack(1)
|
|
|
|
typedef uint16 Offset;
|
|
typedef uint16 GlyphID;
|
|
typedef ULONG Tag;
|
|
|
|
typedef struct {
|
|
GlyphID Start;
|
|
GlyphID End;
|
|
uint16 StartCoverageIndex;
|
|
} RangeRecord;
|
|
|
|
typedef struct {
|
|
uint16 CoverageFormat;
|
|
union {
|
|
struct {
|
|
uint16 GlyphCount;
|
|
GlyphID GlyphArray[1];
|
|
} Type1;
|
|
struct {
|
|
uint16 RangeCount;
|
|
RangeRecord RangeRecord[1];
|
|
} Type2;
|
|
} Format;
|
|
} Coverage;
|
|
|
|
typedef struct {
|
|
uint16 SubstFormat;
|
|
union {
|
|
struct {
|
|
Offset Coverage;
|
|
uint16 DeltaGlyphID;
|
|
} Type1;
|
|
struct {
|
|
Offset Coverage;
|
|
uint16 GlyphCount;
|
|
GlyphID Substitute[1];
|
|
} Type2;
|
|
} Format;
|
|
} SingleSubst;
|
|
|
|
typedef struct {
|
|
uint32 Version;
|
|
Offset ScriptListOffset;
|
|
Offset FeatureListOffset;
|
|
Offset LookupListOffset[];
|
|
} GsubTable;
|
|
|
|
typedef struct {
|
|
uint16 LookupType;
|
|
uint16 LookupFlag;
|
|
uint16 SubtableCount;
|
|
Offset Subtable[1];
|
|
} Lookup;
|
|
|
|
typedef struct {
|
|
uint16 LookupCount;
|
|
Lookup Lookup[1];
|
|
} LookupList;
|
|
|
|
typedef struct {
|
|
Offset FeatureParams;
|
|
uint16 LookupCount;
|
|
uint16 LookupListIndex[1];
|
|
} Feature;
|
|
|
|
typedef struct {
|
|
Tag FeatureTag;
|
|
Offset FeatureOffset;
|
|
} FeatureRecord;
|
|
|
|
typedef struct {
|
|
uint16 FeatureCount;
|
|
FeatureRecord FeatureRecord[1];
|
|
} FeatureList;
|
|
|
|
typedef struct {
|
|
Offset LookupOrderOffset;
|
|
uint16 ReqFeatureIndex;
|
|
uint16 FeatureCount;
|
|
uint16 FeatureIndex[1];
|
|
} LangSys;
|
|
|
|
typedef struct {
|
|
Tag LangSysTag;
|
|
Offset LangSysOffset;
|
|
} LangSysRecord;
|
|
|
|
typedef struct {
|
|
Offset DefaultLangSysOffset;
|
|
uint16 LangSysCount;
|
|
LangSysRecord LangSysRecord[1];
|
|
} Script;
|
|
|
|
typedef struct {
|
|
Tag ScriptTag;
|
|
Offset ScriptOffset;
|
|
} ScriptRecord;
|
|
|
|
typedef struct {
|
|
uint16 ScriptCount;
|
|
ScriptRecord ScriptRecord[1];
|
|
} ScriptList;
|
|
|
|
#pragma pack()
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bCheckVerticalTable()
|
|
*
|
|
* History:
|
|
* 12-Apr-1995 -by- Hideyuki Nagase [HideyukN]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bCheckVerticalTable(
|
|
PFONTFILE pff
|
|
)
|
|
{
|
|
//
|
|
// Is mort table present ?
|
|
//
|
|
if( pff->tp.ateOpt[ IT_OPT_MORT ].cj != 0 &&
|
|
pff->tp.ateOpt[ IT_OPT_MORT ].dp != 0 )
|
|
{
|
|
pff->ulVerticalTableOffset = pff->tp.ateOpt[ IT_OPT_MORT ].dp;
|
|
pff->hgSearchVerticalGlyph = SearchMortTable;
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Is GSUB table present ?
|
|
//
|
|
else if( pff->tp.ateOpt[ IT_OPT_GSUB ].cj != 0 &&
|
|
pff->tp.ateOpt[ IT_OPT_GSUB ].dp != 0 )
|
|
{
|
|
//
|
|
// Check this GSUB table is for Vertical Glyphs ?
|
|
//
|
|
|
|
GsubTable *pGsubTable;
|
|
ScriptList *pScriptList;
|
|
FeatureList *pFeatureList;
|
|
LookupList *pLookupList;
|
|
|
|
ULONG dpGsubTable;
|
|
ULONG dpScriptList;
|
|
ULONG dpFeatureList;
|
|
ULONG dpLookupList;
|
|
|
|
INT ii;
|
|
USHORT LookupIndex;
|
|
ULONG VerticalLookupOffset = 0;
|
|
ULONG VerticalFeatureOffset = 0;
|
|
ULONG VerticalSubtableOffset = 0;
|
|
|
|
Feature *pFeature;
|
|
Lookup *pLookup;
|
|
|
|
dpGsubTable = pff->tp.ateOpt[ IT_OPT_GSUB ].dp;
|
|
pGsubTable = (GsubTable *)((BYTE *)(pff->pvView) + dpGsubTable);
|
|
|
|
dpScriptList = BE_UINT16(&pGsubTable->ScriptListOffset);
|
|
dpFeatureList = BE_UINT16(&pGsubTable->FeatureListOffset);
|
|
dpLookupList = BE_UINT16(&pGsubTable->LookupListOffset);
|
|
|
|
pScriptList = (ScriptList *)((BYTE *)pGsubTable + dpScriptList);
|
|
pFeatureList = (FeatureList *)((BYTE *)pGsubTable + dpFeatureList);
|
|
pLookupList = (LookupList *)((BYTE *)pGsubTable + dpLookupList);
|
|
|
|
#if DBG_MORE
|
|
TtfdDbgPrint("TTFD!GsubTable - %x\n",pGsubTable);
|
|
TtfdDbgPrint("TTFD!ScriptList - %x\n",pScriptList);
|
|
TtfdDbgPrint("TTFD!FeatureList - %x\n",pFeatureList);
|
|
TtfdDbgPrint("TTFD!LookupList - %x\n",pLookupList);
|
|
#endif
|
|
|
|
//
|
|
// Search 'vert' Tag from FeatureList....
|
|
//
|
|
#define tag_vert 0x74726576
|
|
|
|
for( ii = 0;
|
|
ii < BE_INT16(&pFeatureList->FeatureCount) ;
|
|
ii++ )
|
|
{
|
|
if( pFeatureList->FeatureRecord[ii].FeatureTag == tag_vert )
|
|
{
|
|
VerticalFeatureOffset = BE_UINT16(
|
|
&(pFeatureList->FeatureRecord[ii].FeatureOffset)
|
|
);
|
|
#if DBG_MORE
|
|
TtfdDbgPrint("TTFD:VerticalFeature - %x\n",VerticalFeatureOffset);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if we could not find out 'vert' tag, this is a not vertical font.
|
|
//
|
|
|
|
if( VerticalFeatureOffset == 0 )
|
|
{
|
|
WARNING("TTFD!Could not find 'vert' tag in FeatureList\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Vertical feature offset contains offset from FeatureList...
|
|
// adjust it to offset from GsubTable..
|
|
//
|
|
|
|
VerticalFeatureOffset += dpFeatureList;
|
|
|
|
//
|
|
// Compute pointer to Feature offset.
|
|
//
|
|
|
|
pFeature = (Feature *)((BYTE *)pGsubTable + VerticalFeatureOffset);
|
|
|
|
//
|
|
// for Vertical glyph substitution, the lookup count should be 1.
|
|
//
|
|
|
|
if( BE_UINT16(&pFeature->LookupCount) != 1 )
|
|
{
|
|
WARNING("pFeature->LookupCount != 1\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// make sure the Lookup list has a entry for this feature....
|
|
//
|
|
|
|
LookupIndex = BE_UINT16(&(pFeature->LookupListIndex[0]));
|
|
|
|
if( BE_UINT16(&pLookupList->LookupCount) < LookupIndex )
|
|
{
|
|
WARNING("LookupIndex < LookupCount\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Compute pointer to Lookup..
|
|
//
|
|
|
|
VerticalLookupOffset = BE_UINT16(&(pLookupList->Lookup[LookupIndex]));
|
|
pLookup = (Lookup *)((BYTE *)pLookupList + VerticalLookupOffset);
|
|
|
|
#if DBG_MORE
|
|
TtfdDbgPrint("pLookup - %x\n",pLookup);
|
|
#endif
|
|
|
|
//
|
|
// Check Lookup Type, it should be 1 (='Single') for vertical font.
|
|
//
|
|
|
|
if( BE_UINT16(&pLookup->LookupType) != 1 )
|
|
{
|
|
WARNING("LookupType != 1\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Check subtable count.. it should be 1 for vertical font.
|
|
//
|
|
|
|
if( BE_UINT16(&pLookup->SubtableCount) != 1 )
|
|
{
|
|
WARNING("SubTableCount != 1\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Compute offset to subtable from FileTop...
|
|
//
|
|
|
|
VerticalSubtableOffset = BE_UINT16(&(pLookup->Subtable[0]));
|
|
VerticalSubtableOffset += VerticalLookupOffset;
|
|
VerticalSubtableOffset += dpLookupList;
|
|
VerticalSubtableOffset += dpGsubTable;
|
|
|
|
#if DBG_MORE
|
|
TtfdDbgPrint("Subtable Offset - %x\n",VerticalSubtableOffset);
|
|
#endif
|
|
|
|
pff->ulVerticalTableOffset = VerticalSubtableOffset;
|
|
pff->hgSearchVerticalGlyph = SearchGsubTable;
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set dummy..
|
|
//
|
|
pff->ulVerticalTableOffset = 0;
|
|
pff->hgSearchVerticalGlyph = SearchDummyTable;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* SearchDummyTable()
|
|
*
|
|
* History:
|
|
* 14-Jan-1996 -by- Hideyuki Nagase [HideyukN]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG SearchDummyTable(
|
|
FONTCONTEXT *pfc,
|
|
ULONG ig // glyph index
|
|
)
|
|
{
|
|
return ig;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* SearhVerticalGlyphIndex( FONTCONTEXT *pfc, ULONG ig )
|
|
*
|
|
* If there is glyph index for the vertical shape, returns
|
|
* the glyph index of vertical shape, else returns same
|
|
* glyph index as specified.
|
|
*
|
|
* History:
|
|
* 04-Apr-1993 -by- Takao Kitano [TakaoK]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG SearchMortTable(
|
|
FONTCONTEXT *pfc,
|
|
ULONG ig // glyph index
|
|
)
|
|
{
|
|
MortTable *pMortTable;
|
|
BinSrchHeader *pHeader;
|
|
LookupSingle *pLookup;
|
|
USHORT n;
|
|
|
|
pMortTable = (MortTable *)((BYTE *)(pfc->pff->pvView) +
|
|
(pfc->pff->ulVerticalTableOffset));
|
|
|
|
#if DBG
|
|
if ( pMortTable == NULL )
|
|
{
|
|
WARNING("pMortTable == NULL\n");
|
|
return ig;
|
|
}
|
|
#endif
|
|
|
|
pHeader = &pMortTable->SearchHeader;
|
|
|
|
//
|
|
// If you have time, you may want to change the loop from the straight search
|
|
// to the binary search. Currently kanji truetype font has about 110 entries
|
|
// for alternative glyphs. [takaok]
|
|
//
|
|
for ( pLookup = &pMortTable->entries[0], n = BE_UINT16(&pHeader->nEntries);
|
|
n > 0;
|
|
n--, pLookup++
|
|
)
|
|
{
|
|
if ( ig == (ULONG)BE_UINT16( &pLookup->glyphid1 ) )
|
|
return ( BE_UINT16( &pLookup->glyphid2 ) );
|
|
}
|
|
return ( ig );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* SearchGsubTable()
|
|
*
|
|
* History:
|
|
* 12-Apr-1995 -by- Hideyuki Nagase [HideyukN]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG SearchGsubTable(
|
|
FONTCONTEXT *pfc,
|
|
ULONG ig // glyph index
|
|
)
|
|
{
|
|
SingleSubst *pSingleSubst;
|
|
|
|
pSingleSubst = (SingleSubst *)((BYTE *)(pfc->pff->pvView) +
|
|
(pfc->pff->ulVerticalTableOffset));
|
|
|
|
//
|
|
// Check subtable format...
|
|
//
|
|
|
|
if( BE_UINT16(&pSingleSubst->SubstFormat) == 2 )
|
|
{
|
|
Coverage *pCoverage;
|
|
|
|
pCoverage = (Coverage *)
|
|
((BYTE *)pSingleSubst +
|
|
BE_UINT16(&(pSingleSubst->Format.Type2.Coverage)));
|
|
|
|
//
|
|
// Check Coverage format...
|
|
//
|
|
|
|
if( BE_UINT16(&pCoverage->CoverageFormat) == 1 )
|
|
{
|
|
USHORT ii;
|
|
GlyphID *pGlyphArray;
|
|
GlyphID *pGlyphSubstArray;
|
|
|
|
pGlyphArray = pCoverage->Format.Type1.GlyphArray;
|
|
pGlyphSubstArray = pSingleSubst->Format.Type2.Substitute;
|
|
|
|
for( ii = 0;
|
|
ii < BE_UINT16(&(pCoverage->Format.Type1.GlyphCount)) ;
|
|
ii ++ )
|
|
{
|
|
if( ig == (ULONG)BE_UINT16(&(pGlyphArray[ii])) )
|
|
return( (ULONG)BE_UINT16(&(pGlyphSubstArray[ii])) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("TTFD:Unsupported CoverageFormat\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("TTFD:Unsupported SubstFormat\n");
|
|
}
|
|
|
|
return(ig);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vCalcXformVertical
|
|
*
|
|
* Right now, we assume all the width of glyphs that need to be rotated
|
|
* for @face are same. ( I mean all kanji character has same width. )
|
|
* So a single transformation is applied to all rotated glyphs.
|
|
*
|
|
* Before the final release, we need to change this scheme. We will
|
|
* check the advanceWidth in notional space ( please refer to
|
|
* vGetNotionalGlyphMetrics ). If the advanceWidth of specified
|
|
* glyph is different than the maxCharInc, we will compute the
|
|
* transformation matrix dynamically. [takaok]
|
|
*
|
|
* History:
|
|
* 19-Mar-1993 -by- Takao Kitano [TakaoK]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vCalcXformVertical ( FONTCONTEXT *pfc )
|
|
{
|
|
LONG lWidth, lHeight, lAscender, lDescender;
|
|
|
|
lWidth = (LONG)pfc->pff->ifi.fwdMaxCharInc;
|
|
lAscender = (LONG)pfc->pff->ifi.fwdWinAscender;
|
|
lDescender = (LONG)pfc->pff->ifi.fwdWinDescender;
|
|
lHeight = lAscender + lDescender;
|
|
|
|
#ifdef DBCS_VERT_DEBUG
|
|
if ( DebugVertical & DEBUG_VERTICAL_CALL )
|
|
{
|
|
TtfdDbgPrint("TTFD!bGetNotionalHeightAndWidth( Width=%ld, Ascent=%ld, Descent=%ld )\n",
|
|
lWidth, lAscender, lDescender);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// [ 90 degree rotation ]
|
|
//
|
|
// In the truetype rasterizer, 90 degree rotation matrix looks like this:
|
|
//
|
|
// A
|
|
// Y| [ cos90 sin90 ] [ 0 1 ]
|
|
// | [ ] = [ ]
|
|
// | X [ -sin90 cos90 ] [ -1 0 ]
|
|
// +------->
|
|
//
|
|
// [ X-Y scaling ]
|
|
//
|
|
// We don't want to change the character box shape after the rotation.
|
|
//
|
|
// [ h/w 0 ] where w: notional space width = IFIMETRICS.aveCharWidth
|
|
// [ ]
|
|
// [ 0 w/h ] h: notional space height = IFIMETRICS.Ascender +
|
|
// IFIMETRICS.Descender
|
|
//
|
|
// We are multiplying the scaling matrix from the left because the
|
|
// scaling matrix acts first on the notinal space vectors on the left
|
|
//
|
|
// ((x,y)*A)*B = (x,y)*(A*B)
|
|
//
|
|
// [ h/w 0 ] [ 0 1 ] [ 0 h/w ]
|
|
// [ ] * [ ] = [ ]
|
|
// [ 0 w/h ] [ -1 0 ] [ -w/h 0 ] ... this is it! [rotation] * [scaling] matrix
|
|
//
|
|
// We are multiplying from the left because the [ scaling * rotation ] matrix
|
|
// acts first on the notional space vectors on the left
|
|
//
|
|
// [ 0 h/w ] [ m00 m01 ] [ m10 * h / w m11 * h / w ]
|
|
// [ ] * [ ] = [ ]
|
|
// [-w/h 0 ] [ m10 m11 ] [ -m00 * w / h -m01 * w / h ]
|
|
|
|
if ( lHeight == lWidth )
|
|
{
|
|
pfc->mxv.transform[0][0] = pfc->mxn.transform[1][0];
|
|
pfc->mxv.transform[0][1] = pfc->mxn.transform[1][1];
|
|
pfc->mxv.transform[1][0] = -pfc->mxn.transform[0][0];
|
|
pfc->mxv.transform[1][1] = -pfc->mxn.transform[0][1];
|
|
}
|
|
else
|
|
{
|
|
pfc->mxv.transform[0][0] = LongMulDiv( pfc->mxn.transform[1][0], lHeight, lWidth);
|
|
pfc->mxv.transform[0][1] = LongMulDiv( pfc->mxn.transform[1][1], lHeight, lWidth);
|
|
pfc->mxv.transform[1][0] = LongMulDiv( pfc->mxn.transform[0][0], -lWidth, lHeight);
|
|
pfc->mxv.transform[1][1] = LongMulDiv( pfc->mxn.transform[0][1], -lWidth, lHeight);
|
|
}
|
|
|
|
pfc->mxv.transform[2][2] = ONEFIX;
|
|
pfc->mxv.transform[0][2] = (Fixed)0;
|
|
pfc->mxv.transform[1][2] = (Fixed)0;
|
|
pfc->mxv.transform[2][0] = (Fixed)0;
|
|
pfc->mxv.transform[2][1] = (Fixed)0;
|
|
|
|
//
|
|
// compute shift parameters in device space
|
|
// coordinate system is truetype coordinate.
|
|
//
|
|
// At early stage of development, I put the following shift
|
|
// information into the matrix passed to the scaler.
|
|
// However I don't know why but the scaler just ignores
|
|
// the X and Y shift values. In windows 3.1J, they
|
|
// changes the scaler interface ( fs_xxx ) and give the scaler
|
|
// X and Y shift information. For NT-J, I don't want to change
|
|
// the scaler interface. Following shift values are applied
|
|
// after we got bitmap information from scaler. [takaok]
|
|
//
|
|
{
|
|
Fixed lX;
|
|
Fixed lY;
|
|
|
|
//
|
|
// shift value in notional space
|
|
//
|
|
lX = LTOF16_16( lWidth - LongMulDiv(lDescender, lWidth, lHeight) );
|
|
lY = LTOF16_16( - lDescender );
|
|
|
|
//
|
|
// shift value in device space
|
|
//
|
|
pfc->fxdevShiftX = FixMul(pfc->mx.transform[0][0], lX) +
|
|
FixMul(pfc->mx.transform[1][0], lY);
|
|
pfc->fxdevShiftY = FixMul(pfc->mx.transform[0][1], lX) +
|
|
FixMul(pfc->mx.transform[1][1], lY);
|
|
}
|
|
|
|
#ifdef DBCS_VERT_DEBUG
|
|
if ( DebugVertical & DEBUG_VERTICAL_XFORM )
|
|
{
|
|
TtfdDbgPrint("vCalcXformVertical pfc->mx00 =0x%lx, 11=0x%lx, 01=0x%lx, 10=0x%lx \n",
|
|
pfc->mx.transform[0][0],
|
|
pfc->mx.transform[1][1],
|
|
pfc->mx.transform[0][1],
|
|
pfc->mx.transform[1][0] );
|
|
TtfdDbgPrint("vCalcXformVertical mxn:00=0x%lx, 11=0x%lx, 01=0x%lx, 10=0x%lx \n",
|
|
pfc->mxn.transform[0][0],
|
|
pfc->mxn.transform[1][1],
|
|
pfc->mxn.transform[0][1],
|
|
pfc->mxn.transform[1][0] );
|
|
TtfdDbgPrint(" mxv:00=0x%lx, 11=0x%lx, 01=0x%lx, 10=0x%lx \n",
|
|
pfc->mxv.transform[0][0],
|
|
pfc->mxv.transform[1][1],
|
|
pfc->mxv.transform[0][1],
|
|
pfc->mxv.transform[1][0] );
|
|
TtfdDbgPrint(" devShiftX=%ld, devShiftY=%ld \n",
|
|
F16_16TOLROUND(pfc->fxdevShiftX),F16_16TOLROUND(pfc->fxdevShiftY));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL IsFullWidth( WCHAR wc)
|
|
*
|
|
* Returns TRUE if specified unicode codepoint is corresponding to
|
|
* double byte character in multibyte codepage.
|
|
*
|
|
* History:
|
|
* 10-Nov-1995 Hideyuki Nagase [hideyukn]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
typedef struct _VERTICAL_UNICODE {
|
|
WCHAR Start;
|
|
WCHAR End;
|
|
} VERTICAL_UNICODE, *PVERTICAL_UNICODE;
|
|
|
|
#define NUM_VERTICAL_UNICODES 4
|
|
|
|
VERTICAL_UNICODE VerticalUnicodes[] = {
|
|
{ 0x4E00, 0x9FFF }, // CJK_UNIFIED_IDOGRAPHS
|
|
{ 0x3040, 0x309F }, // HIRAGANA
|
|
{ 0x30A0, 0x30FF }, // KATAKANA
|
|
{ 0xAC00, 0xD7A3 } // HANGUL
|
|
};
|
|
|
|
BOOL IsFullWidthCharacter( UINT FontCodePage, WCHAR wc )
|
|
{
|
|
int cwc;
|
|
char ach[2];
|
|
int index;
|
|
|
|
for (index = 0; index < NUM_VERTICAL_UNICODES; index++)
|
|
{
|
|
if ((wc >= VerticalUnicodes[index].Start) &&
|
|
(wc <= VerticalUnicodes[index].End) )
|
|
{
|
|
return (TRUE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// if this Unicode character is mapped to Double-Byte character,
|
|
// this is also full-width character..
|
|
//
|
|
|
|
cwc = EngWideCharToMultiByte(FontCodePage,&wc,sizeof(WCHAR),ach,2);
|
|
|
|
return( cwc > 1 ? TRUE : FALSE );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL bChangeXform( PFONTCONTEXT pfc, BOOL bRotation )
|
|
*
|
|
*
|
|
* if bRotation is TRUE: call the scaler with rotated transform.
|
|
* FALSE: call the scaler with normal transform.
|
|
*
|
|
* History:
|
|
* 19-Mar-1993 -by- Takao Kitano [TakaoK]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bChangeXform( PFONTCONTEXT pfc, BOOL bRotation )
|
|
{
|
|
FS_ENTRY iRet;
|
|
|
|
#ifdef DBCS_VERT_DEBUG
|
|
if ( DebugVertical & DEBUG_VERTICAL_CALL )
|
|
{
|
|
TtfdDbgPrint("TTFD!bChangeXform:bRotation=%s\n", bRotation ? "TRUE":"FALSE");
|
|
}
|
|
#endif
|
|
|
|
vInitGlyphState(&pfc->gstat);
|
|
|
|
if ( bRotation )
|
|
{
|
|
pfc->pgin->param.newtrans.transformMatrix = &(pfc->mxv);
|
|
}
|
|
else
|
|
{
|
|
pfc->pgin->param.newtrans.transformMatrix = &(pfc->mxn);
|
|
}
|
|
|
|
pfc->pgin->param.newtrans.pointSize = pfc->pointSize;
|
|
pfc->pgin->param.newtrans.xResolution = (int16)pfc->sizLogResPpi.cx;
|
|
pfc->pgin->param.newtrans.yResolution = (int16)pfc->sizLogResPpi.cy;
|
|
pfc->pgin->param.newtrans.pixelDiameter = FIXEDSQRT2;
|
|
pfc->pgin->param.newtrans.traceFunc = (FntTraceFunc)NULL;
|
|
|
|
if ((iRet = fs_NewTransformation(pfc->pgin, pfc->pgout)) != NO_ERR)
|
|
{
|
|
V_FSERROR(iRet);
|
|
#if DBG
|
|
TtfdDbgPrint("bChangeXform(%-#x,%d) failed\n", pfc, bRotation);
|
|
#endif
|
|
return(FALSE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* VOID vShiftBitmapInfo( FONTCONTEXT *pfc, fs_GlyphInfoType *pgout )
|
|
*
|
|
*
|
|
* Modifies following values.
|
|
*
|
|
* Using pfc->devShiftX and pfc->devShiftY:
|
|
*
|
|
* gout.bitMapInfo.bounds.right
|
|
* gout.bitMapInfo.bounds.left
|
|
* gout.bitMapInfo.bounds.top
|
|
* gout.bitMapInfo.bounds.bottom
|
|
* gout.metricInfo.devLeftSideBearing.x
|
|
* gout.metricInfo.devLeftSideBearing.y
|
|
*
|
|
* Using -90 degree rotation
|
|
*
|
|
* gout.metricInfo.devAdvanceWidth.x
|
|
* gout.metricInfo.devAdvanceWidth.y
|
|
*
|
|
* History:
|
|
* 04-Apr-1993 -by- Takao Kitano [TakaoK]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vShiftBitmapInfo(
|
|
FONTCONTEXT *pfc,
|
|
fs_GlyphInfoType *pgoutDst,
|
|
fs_GlyphInfoType *pgoutSrc)
|
|
{
|
|
SHORT sdevShiftX = (SHORT) F16_16TOLROUND(pfc->fxdevShiftX);
|
|
SHORT sdevShiftY = (SHORT) F16_16TOLROUND(pfc->fxdevShiftY);
|
|
|
|
pgoutDst->bitMapInfo.bounds.right = pgoutSrc->bitMapInfo.bounds.right + sdevShiftX;
|
|
pgoutDst->bitMapInfo.bounds.left = pgoutSrc->bitMapInfo.bounds.left + sdevShiftX;
|
|
pgoutDst->bitMapInfo.bounds.top = pgoutSrc->bitMapInfo.bounds.top + sdevShiftY;
|
|
pgoutDst->bitMapInfo.bounds.bottom = pgoutSrc->bitMapInfo.bounds.bottom + sdevShiftY;
|
|
|
|
pgoutDst->metricInfo.devLeftSideBearing.x = pgoutSrc->metricInfo.devLeftSideBearing.x + pfc->fxdevShiftX;
|
|
pgoutDst->metricInfo.devLeftSideBearing.y = pgoutSrc->metricInfo.devLeftSideBearing.y + pfc->fxdevShiftY;
|
|
|
|
//
|
|
// -90degree rotation in truetype coordinate system
|
|
//
|
|
// [ 0 -1 ]
|
|
// (newX, newY) = ( x, y ) * [ ] = (y, -x )
|
|
// [ 1 0 ]
|
|
// A
|
|
// Y|
|
|
// |
|
|
// |
|
|
// +----->
|
|
// X
|
|
//
|
|
pgoutDst->metricInfo.devAdvanceWidth.x = pgoutSrc->metricInfo.devAdvanceWidth.y;
|
|
pgoutDst->metricInfo.devAdvanceWidth.y = - pgoutSrc->metricInfo.devAdvanceWidth.x;
|
|
|
|
#ifdef DBCS_VERT_DEBUG
|
|
if ( DebugVertical & DEBUG_VERTICAL_BITMAPINFO )
|
|
{
|
|
TtfdDbgPrint("=====TTFD:vShiftBitmapInfo() before \n");
|
|
TtfdDbgPrint("bitMapInfo.bounds:right=%ld, left=%ld, top=%ld, bottom=%ld\n",
|
|
pgoutSrc->bitMapInfo.bounds.right,
|
|
pgoutSrc->bitMapInfo.bounds.left,
|
|
pgoutSrc->bitMapInfo.bounds.top,
|
|
pgoutSrc->bitMapInfo.bounds.bottom);
|
|
TtfdDbgPrint("metricInfo.devLeftSideBearing x = %ld, y=%ld \n",
|
|
F16_16TOLROUND(pgoutSrc->metricInfo.devLeftSideBearing.x),
|
|
F16_16TOLROUND(pgoutSrc->metricInfo.devLeftSideBearing.y));
|
|
TtfdDbgPrint("metricInfo.devAdvanceWidth x = %ld, y=%ld \n",
|
|
F16_16TOLROUND(pgoutSrc->metricInfo.devAdvanceWidth.x),
|
|
F16_16TOLROUND(pgoutSrc->metricInfo.devAdvanceWidth.y));
|
|
|
|
TtfdDbgPrint("=====TTFD:vShiftBitmapInfo() after \n");
|
|
TtfdDbgPrint("bitMapInfo.bounds:right=%ld, left=%ld, top=%ld, bottom=%ld\n",
|
|
pgoutDst->bitMapInfo.bounds.right,
|
|
pgoutDst->bitMapInfo.bounds.left,
|
|
pgoutDst->bitMapInfo.bounds.top,
|
|
pgoutDst->bitMapInfo.bounds.bottom);
|
|
TtfdDbgPrint("metricInfo.devLeftSideBearing x = %ld, y=%ld \n",
|
|
F16_16TOLROUND(pgoutDst->metricInfo.devLeftSideBearing.x),
|
|
F16_16TOLROUND(pgoutDst->metricInfo.devLeftSideBearing.y));
|
|
TtfdDbgPrint("metricInfo.devAdvanceWidth x = %ld, y=%ld \n",
|
|
F16_16TOLROUND(pgoutDst->metricInfo.devAdvanceWidth.x),
|
|
F16_16TOLROUND(pgoutDst->metricInfo.devAdvanceWidth.y));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vShiftOutlineInfo()
|
|
*
|
|
* History:
|
|
* 04-Apr-1993 -by- Hideyuki Nagase [HideyukN]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#define CJ_CRV(pcrv) \
|
|
( \
|
|
offsetof(TTPOLYCURVE,apfx) + ((pcrv)->cpfx * sizeof(POINTFX)) \
|
|
)
|
|
|
|
VOID vAdd16FixTo16Fix(
|
|
FIXED *A ,
|
|
FIXED *B ,
|
|
BOOL bForceMinus
|
|
)
|
|
{
|
|
A->fract += B->fract;
|
|
A->value += B->value;
|
|
}
|
|
|
|
VOID vAdd16FixTo28Fix(
|
|
FIXED *A ,
|
|
FIXED *B ,
|
|
BOOL bForceMinus
|
|
)
|
|
{
|
|
Fixed longA , longB;
|
|
|
|
ASSERTDD( sizeof(FIXED) == sizeof(Fixed) , "TTFD:FIXED != ULONG\n" );
|
|
|
|
longA = *(Fixed *)A;
|
|
longB = *(Fixed *)B;
|
|
|
|
// !!! BUG BUG BUG !!!
|
|
//
|
|
// if outline request from PostScript printer driver, the driver
|
|
// can not get correct outline without following super hack.
|
|
// we most need feather investigation.
|
|
//
|
|
// propably, we should compute shift value accoring
|
|
// to device coordinate ???. Y axis is different
|
|
// between device and truetype coordinate.
|
|
// how about GetGlyphOutline() ???
|
|
// I just tested using gdi\test\fonttest.nt\fonttest.exe
|
|
// It seems work fine.
|
|
//
|
|
// start super-hack.
|
|
|
|
if(bForceMinus) longB = -longB;
|
|
|
|
// end super-hack.
|
|
|
|
longB = longB >> 12;
|
|
|
|
longA += longB;
|
|
|
|
*A = *(FIXED *)&longA;
|
|
}
|
|
|
|
VOID vShiftOutlineInfo(
|
|
FONTCONTEXT *pfc, // IN font context
|
|
BOOL b16Dot16, // IN Fixed format 16.16 or 28.4
|
|
BYTE *pBuffer, // OUT output buffer
|
|
ULONG cjTotal // IN buffer size
|
|
)
|
|
{
|
|
TTPOLYGONHEADER *ppoly, *ppolyStart, *ppolyEnd;
|
|
TTPOLYCURVE *pcrv, * pcrvEnd;
|
|
FIXED fxShiftX , fxShiftY;
|
|
ULONG cSpli , cSpliMax;
|
|
POINTFX *pptfix;
|
|
VOID (*vAddFunc)(FIXED *A,FIXED *B,BOOL bForceMinus);
|
|
BOOL bForceMinus;
|
|
|
|
*((Fixed *)&fxShiftX) = LTOF16_16( F16_16TOLROUND(pfc->fxdevShiftX) );
|
|
*((Fixed *)&fxShiftY) = LTOF16_16( F16_16TOLROUND(pfc->fxdevShiftY) );
|
|
|
|
if( b16Dot16 ) {
|
|
vAddFunc = vAdd16FixTo16Fix;
|
|
bForceMinus = FALSE;
|
|
} else {
|
|
vAddFunc = vAdd16FixTo28Fix;
|
|
bForceMinus = TRUE;
|
|
}
|
|
|
|
#ifdef DBCS_VERT_DEBUG
|
|
TtfdDbgPrint("====== START DUMP VERTICAL POLYGON ======\n");
|
|
TtfdDbgPrint("devShiftX=%ld, devShiftY=%ld \n"
|
|
,F16_16TOLROUND(*(Fixed *)&fxShiftX),
|
|
F16_16TOLROUND(*(Fixed *)&fxShiftY));
|
|
#endif // DBCS_VERT_DEBUG
|
|
|
|
ppolyStart = (TTPOLYGONHEADER *)pBuffer;
|
|
ppolyEnd = (TTPOLYGONHEADER *)(pBuffer + cjTotal);
|
|
|
|
for (
|
|
ppoly = ppolyStart;
|
|
ppoly < ppolyEnd;
|
|
ppoly = (TTPOLYGONHEADER *)((PBYTE)ppoly + ppoly->cb)
|
|
)
|
|
{
|
|
ASSERTDD(ppoly->dwType == TT_POLYGON_TYPE,"ppoly->dwType != TT_POLYGON_TYPE\n");
|
|
|
|
#ifdef DBCS_VERT_DEBUG
|
|
TtfdDbgPrint("ppoly->cb - %d\n",ppoly->cb);
|
|
#endif // DBCS_VERT_DEBUG
|
|
|
|
(*vAddFunc)( &ppoly->pfxStart.x , &fxShiftX , FALSE );
|
|
(*vAddFunc)( &ppoly->pfxStart.y , &fxShiftY , bForceMinus );
|
|
|
|
#ifdef DBCS_VERT_DEBUG
|
|
TtfdDbgPrint("StartPoint - ( %x , %x )\n",ppoly->pfxStart.x,ppoly->pfxStart.y);
|
|
#endif // DBCS_VERT_DEBUG
|
|
|
|
for (
|
|
pcrv = (TTPOLYCURVE *)(ppoly + 1),pcrvEnd = (TTPOLYCURVE *)((PBYTE)ppoly + ppoly->cb);
|
|
pcrv < pcrvEnd;
|
|
pcrv = (TTPOLYCURVE *)((PBYTE)pcrv + CJ_CRV(pcrv))
|
|
)
|
|
{
|
|
#ifdef DBCS_VERT_DEBUG
|
|
TtfdDbgPrint("Contents of TTPOLYCURVE (%d)\n",pcrv->cpfx);
|
|
#endif // DBCS_VERT_DEBUG
|
|
|
|
for (
|
|
cSpli = 0,cSpliMax = pcrv->cpfx,pptfix = &(pcrv->apfx[0]);
|
|
cSpli < cSpliMax;
|
|
cSpli ++,pptfix ++
|
|
)
|
|
{
|
|
(*vAddFunc)( &pptfix->x , &fxShiftX , FALSE );
|
|
(*vAddFunc)( &pptfix->y , &fxShiftY , bForceMinus );
|
|
|
|
#ifdef DBCS_VERT_DEBUG
|
|
TtfdDbgPrint(" - ( %x , %x )\n",pptfix->x,pptfix->y);
|
|
#endif // DBCS_VERT_DEBUG
|
|
}
|
|
}
|
|
|
|
#ifdef DBCS_VERT_DEBUG
|
|
TtfdDbgPrint("\n");
|
|
#endif // DBCS_VERT_DEBUG
|
|
}
|
|
|
|
#ifdef DBCS_VERT_DEBUG
|
|
TtfdDbgPrint("====== END DUMP VERTICAL POLYGON ======\n");
|
|
#endif // DBCS_VERT_DEBUG
|
|
}
|
|
|