truetype.cpp

来自「Windows 图形编程 书籍」· C++ 代码 · 共 1,028 行 · 第 1/2 页

CPP
1,028
字号
//-----------------------------------------------------------------------------------//
//              Windows Graphics Programming: Win32 GDI and DirectDraw               //
//                             ISBN  0-13-086985-6                                   //
//                                                                                   //
//  Written            by  Yuan, Feng                             www.fengyuan.com   //
//  Copyright (c) 2000 by  Hewlett-Packard Company                www.hp.com         //
//  Published          by  Prentice Hall PTR, Prentice-Hall, Inc. www.phptr.com      //
//                                                                                   //
//  FileName   : truetype.cpp					                                     //
//  Description: Truetype font decoding                                              //
//  Version    : 1.00.000, May 31, 2000                                              //
//-----------------------------------------------------------------------------------//

#define STRICT
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <assert.h>
#include <tchar.h>
#include <math.h>

#include "..\..\include\win.h"
#include "..\..\include\LogWindow.h"
#include "TrueType.h"
#include "resource.h"

const char tag_cmap[] = "cmap"; // character to glyph mapping
const char tag_glyf[] = "glyf"; // glyph data
const char tag_head[] = "head"; // font header
const char tag_hhea[] = "hhea"; // horizontal header
const char tag_hmtx[] = "hmtx"; // horizontal metrics
const char tag_loca[] = "loca"; // index to location
const char tag_maxp[] = "maxp"; // maximum profile
const char tag_name[] = "name"; // naming
const char tag_post[] = "post"; // PostScript
const char tag_ttcf[] = "ttcf"; // TrueType font collection
const char tag_kern[] = "kern"; // Kerning table



void KTrueType::Release(void)
{
	if ( m_pFontData )
	{
		delete [] (BYTE *) m_pFontData;
		m_pFontData = NULL;
	}
}

const BYTE * KTrueType::GetTable(const char * tag) const
{
	int no = GetTableNo();

	for (int i=0; i<no; i++)
		if ( memcmp(m_pFontData->entries[i].tag, tag, 4)==0 )
			return GetTable(i);

	return NULL;
}


const GlyphHeader * KTrueType::GetGlyph(int index) const
{
	if ( (index<0) || (index>=m_nNumGlyphs) )
		return NULL;

	if ( m_pGlyphTable==NULL )
		return NULL;

	if ( m_pShortGlyphIndex )
		return (const GlyphHeader *) ( m_pGlyphTable + reverse(m_pShortGlyphIndex[index]) * 2);
	
	if ( m_pLongGlyphIndex )
		return (const GlyphHeader *) ( m_pGlyphTable + reverse(m_pLongGlyphIndex[index]) );

	return NULL;
}

///////////////////////////////////////////////////////
//				h e a d		T A B L E				 //
///////////////////////////////////////////////////////

typedef struct
{
	Fixed	Table;				// version number 0x00010000 for version 1.0. 
	Fixed	fontRevision;		// Set by font manufacturer. 
	ULONG	checkSumAdjustment;	// To compute: set it to 0, sum the entire font as ULONG, then store 0xB1B0AFBA - sum. 
	ULONG	magicNumber;		// Set to 0x5F0F3CF5. 
	USHORT	flags;				// Bit 0 - baseline for font at y=0; 
								// Bit 1 - left sidebearing at x=0;
								// Bit 2 - instructions may depend on point size; 
								// Bit 3 - force ppem to integer values for all internal scaler math; may use fractional ppem sizes if this bit is clear; 
								// Bit 4 - instructions may alter advance width (the advance widths might not scale linearly); 
								// Bits 5-10 - defined by Apple; 
								// Bit 11 - font compressed with Agfa MicroType Compression. 
								// Note: All other bits must be zero. 
	USHORT	unitsPerEm;			// Valid range is from 16 to 16384 
	longDT	created;			// International date (8-byte field). 
	longDT	modified;			// International date (8-byte field). 
	FWord	xMin;				// For all glyph bounding boxes. 
	FWord	yMin;				// For all glyph bounding boxes. 
	FWord	xMax;				// For all glyph bounding boxes. 
	FWord	yMax;				// For all glyph bounding boxes. 
	USHORT	macStyle;			// Bit 0 bold (if set to 1); Bit 1 italic (if set to 1) 
								// Bits 2-15 reserved (set to 0). 
	USHORT  lowestRecPPEM;		// Smallest readable size in pixels. 
	SHORT	fontDirectionHint;	//  0 Fully mixed directional glyphs; 
								//  1 Only strongly left to right; 
								//  2 Like 1 but also contains neutrals; 
								// -1 Only strongly right to left; 
								// -2 Like -1 but also contains neutrals. 
	SHORT	indexToLocFormat;	// 0 for short offsets, 1 for long. 
	SHORT	glyphDataFormat;	// 0 for current format. 
}	Table_head;


///////////////////////////////////////////////////////
//				m a x p		T A B L E				 //
///////////////////////////////////////////////////////

typedef struct
{
	Fixed  Version;					// 0x00010000 for version 1.0. 
	USHORT numGlyphs;				// The number of glyphs in the font. 
	USHORT maxPoints;				// Maximum points in a non-composite glyph. 
	USHORT maxContours;				// Maximum contours in a non-composite glyph. 
	USHORT maxCompositePoints;		// Maximum points in a composite glyph. 
	USHORT maxCompositeContours;	// Maximum contours in a composite glyph. 
	USHORT maxZones;				// 1 if instructions do not use the twilight zone (Z0), 
									// or 2 if instructions do use Z0; should be set to 2 in most cases. 
	USHORT maxTwilightPoints;		// Maximum points used in Z0. 
	USHORT maxStorage;				// Number of Storage Area locations.  
	USHORT maxFunctionDefs;			// Number of FDEFs. 
	USHORT maxInstructionDefs;		// Number of IDEFs. 
	USHORT maxStackElements;		// Maximum stack depth2. 
	USHORT maxSizeOfInstructions;	// Maximum byte count for glyph instructions. 
	USHORT maxComponentElements;	// Maximum number of components referenced at "top level" for any composite glyph. 
	USHORT maxComponentDepth;		// Maximum levels of recursion; 1 for simple components. 
}	Table_maxp;
   

/////////////////////////////////////
//  CMAP						   //
/////////////////////////////////////

typedef struct
{
	USHORT	Platform;		// platform ID
	USHORT	EncodingID;		// encoding ID
	ULONG	TableOffset;	// offset to encoding table
}	submap;

typedef struct
{
	USHORT	TableVersion;	 // table version 0
	USHORT	NumSubTable;	 // number of encoding tables
	submap  TableHead[1];    // heads for encoding tables
}	Table_cmap;

typedef struct
{
	USHORT	format;			// format: 0, 2, 4, 6
	USHORT	length;			// size
	USHORT	version;		// version
	BYTE	map[1];			// mapping data
}	Table_Encode;


//////////////////////////////////////
// HHEA Horizontal Header
//////////////////////////////////////

typedef struct
{
	Fixed  version;				// 0x00010000 for version 1.0. 
	FWord  Ascender;			// Typographic ascent. 
	FWord  Descender;			// Typographic descent. 
	FWord  LineGap;				// Typographic line gap. 
	FWord  advanceWidthMax;		// Maximum advance width value in 'hmtx' table. 
	FWord  minLeftSideBearing;	// Minimum left sidebearing value in 'hmtx' table. 
	FWord  minRightSideBearing; // Minimum right sidebearing value; calculated as Min(aw - lsb - (xMax - xMin)). 
	FWord  xMaxExtent;			// Max(lsb + (xMax - xMin)). 
	SHORT  caretSlopeRise;		// Used to calculate the slope of the cursor (rise/run); 1 for vertical. 
	SHORT  caretSlopeRun;		// 0 for vertical. 
	SHORT  reserved[5];		    // set to 0 
	SHORT  metricDataFormat;	// 0 for current format. 
	USHORT numberOfHMetrics;	// Number of hMetric entries in 'hmtx' table; 
							    // must be equal to the CharStrings INDEX count in the 'CFF ' table. 
}	Table_HoriHeader;


//////////////////////////////////////
// KERN Kerning Table
//////////////////////////////////////

typedef struct
{
	FWord	leftglyph;
	FWord	rightglyph;
	FWord	move;
}	KerningPair;

typedef struct
{
	FWord		Version;
	FWord		nSubTables;
	
	FWord		SubTableVersion;
	FWord		Bytesinsubtable;
	FWord		Coveragebits;
	FWord		Numberpairs;
	FWord		SearchRange;
	FWord		EntrySelector;
	FWord		RangeShift;
	KerningPair KerningPair[1];		// variable size
}	Table_Kerning;


////////////////////////////////////

typedef struct
{
	USHORT	version;			// 0x0001 
	SHORT	xAvgCharWidth;		// weighted average width of a..z
	USHORT	usWeightClass;      // FW_THIN..FW_BLACK
	USHORT	usWidthClass;		// FWIDTH_ULTRA_CONDENSED..FWIDTH_ULTRA_EXPANDED
	SHORT	fsType;				// embedding licensing rights
	SHORT	ySubscriptXSize;   
	SHORT	ySubscriptYSize;   
	SHORT	ySubscriptXOffset;   
	SHORT	ySubscriptYOffset;   
	SHORT	ySuperscriptXSize;   
	SHORT	ySuperscriptYSize;   
	SHORT	ySuperscriptXOffset;   
	SHORT	ySuperscriptYOffset;   
	SHORT	yStrikeoutSize;     // strikeout stroke width in design units.
	SHORT	yStrikeoutPosition;   
	SHORT	sFamilyClass;       // IBM font class
	PANOSE	panose;   
	ULONG	ulUnicodeRange1;	// Bits 0-31   Unicode Character Range
	ULONG	ulUnicodeRange2;	// Bits 32-63 
	ULONG	ulUnicodeRange3;	// Bits 64-95 
	ULONG	ulUnicodeRange4;	// Bits 96-127 
	CHAR	achVendID[4];		// vendor ID 
	USHORT	fsSelection;        // ITALIC UNDERSCORE NEGATIVE OUTLINE STRIKEOUT BOLD REGULAR
	USHORT	usFirstCharIndex;   // first UNICODE char
	USHORT	usLastCharIndex;    // last UNICODE char
	USHORT	sTypoAscender;      // typographic ascender 
	USHORT	sTypoDescender;     // typographic ascender 
	USHORT	sTypoLineGap;		// typographic line gap
	USHORT	usWinAscent;		// ascender metric for Windows
	USHORT	usWinDescent;		// descender metric for Windows
	ULONG	ulCodePageRange1;	// Bits 0-31 
	ULONG	ulCodePageRange2;	// Bits 32-63 
}	Table_OS2;

/////////////////////////////////////

TableDirectory * GetTrueTypeFont(HDC hDC)
{
	// read font size
	DWORD FontSize = GetFontData(hDC, 0, 0, NULL, 0);
	
	TableDirectory * pFont = (TableDirectory *) new BYTE[FontSize];
	if ( pFont==NULL )
		return NULL;

	GetFontData(hDC, 0, 0, pFont, FontSize);

	return pFont;
}


BOOL KTrueType::Load(LOGFONT & logfont)
{
	HFONT hFont  = CreateFontIndirect(& logfont);
	HDC   hDC	 = GetDC(NULL);
	HGDIOBJ hOld = SelectObject(hDC, hFont);

	Release();

	// read font collection size
	DWORD FCsize = GetFontData(hDC, * (DWORD *) tag_ttcf, 0, NULL, 0);
	
	// read font size
	m_nFontSize = GetFontData(hDC, NULL, 0, NULL, 0);
	
	if ( (m_nFontSize==0) || (m_nFontSize==0xFFFFFFFF) )
		return FALSE;
	
	if ( (FCsize==0) || (FCsize==0xFFFFFFFF) )	// not a font collecton
		m_nBias = 0;
	else										// is font collection, calculate bias
		m_nBias = m_nFontSize - FCsize;

	m_pFontData = (TableDirectory *) new BYTE[m_nFontSize];
	GetFontData(hDC, NULL, 0, m_pFontData, m_nFontSize);

	SelectObject(hDC, hOld);
	ReleaseDC(NULL, hDC);
	DeleteObject(hFont);

	const Table_maxp * pmaxp = (const Table_maxp *) GetTable(tag_maxp);
	
	if ( pmaxp )
		m_nNumGlyphs = reverse(pmaxp->numGlyphs);

	const Table_head * phead = (const Table_head *) GetTable(tag_head);

	if ( phead->indexToLocFormat )
		m_pLongGlyphIndex  = (const DWORD *)  GetTable(tag_loca);
	else
		m_pShortGlyphIndex = (const WORD *) GetTable(tag_loca);

	m_pGlyphTable = GetTable(tag_glyf);
	m_unitsPerEm  = reverse(phead->unitsPerEm);
	
	{
		const Table_HoriHeader * phhea = (const Table_HoriHeader *) GetTable(tag_hhea);

		m_Ascender		   = (short) reverse((WORD) phhea->Ascender);
		m_Descender		   = (short) reverse((WORD) phhea->Descender);
		m_LineGap		   = (short) reverse((WORD) phhea->LineGap);
		m_numberOfHMetrics = (short) reverse((WORD) phhea->numberOfHMetrics);

		SetHTMX(GetTable(tag_hmtx));
	}

	{
		const Table_Kerning * pKern = (const Table_Kerning *) GetTable(tag_kern);
		
		int i = 0;
	}
	return TRUE;
}


///////////////////////////////////////////////////////
//				g l y p		T A B L E				 //
///////////////////////////////////////////////////////

// Simple Glyph
//	USHORT endPtsOfContours[n];	// Array of last points of each contour; n is the number of contours. 
//	USHORT instructionLength;	// Total number of bytes for instructions. 
//	BYTE instructions[n];		// Array of instructions for each glyph; n is the number of instructions. 
//	BYTE flags[n];				// Array of flags for each coordinate in outline; n is the number of flags. 
//	BYTE or SHORT xCoordinates[ ] First coordinates relative to (0,0); others are relative to previous point. 
//	BYTE or SHORT yCoordinates[ ] First coordinates relative to (0,0); others are relative to previous point. 

typedef enum
{
	G_ONCURVE	= 0x01,		// on curve, off curve
	G_REPEAT	= 0x08,		// next byte is flag repeat count

	G_XMASK		= 0x12,
	G_XADDBYTE  = 0x12,		// X is positive byte
	G_XSUBBYTE	= 0x02,     // X is negative byte
	G_XSAME		= 0x10,		// X is same
	G_XADDINT	= 0x00,		// X is signed word

	G_YMASK		= 0x24,
	G_YADDBYTE  = 0x24,		// Y is positive byte
	G_YSUBBYTE	= 0x04,     // Y is negative byte
	G_YSAME		= 0x20,		// Y is same
	G_YADDINT	= 0x00,		// Y is signed word
};  

// Simple Glyph
//	USHORT endPtsOfContours[n];	// Array of last points of each contour; n is the number of contours. 
//	USHORT instructionLength;	// Total number of bytes for instructions. 
//	BYTE instructions[n];		// Array of instructions for each glyph; n is the number of instructions. 
//	BYTE flags[n];				// Array of flags for each coordinate in outline; n is the number of flags. 
//	BYTE or SHORT xCoordinates[ ] First coordinates relative to (0,0); others are relative to previous point. 
//	BYTE or SHORT yCoordinates[ ] First coordinates relative to (0,0); others are relative to previous point. 

void Mark(HDC hDC, int x, int y, COLORREF cr)
{
	SetPixel(hDC, x, y, cr);
	
	SetPixel(hDC, x-2, y-1, cr);
	SetPixel(hDC, x-2, y,   cr);
	SetPixel(hDC, x-2, y+1, cr);
	
	SetPixel(hDC, x+2, y-1, cr);
	SetPixel(hDC, x+2, y,   cr);
	SetPixel(hDC, x+2, y+1, cr);

	SetPixel(hDC, x-1, y-2, cr);
	SetPixel(hDC, x,   y-2, cr);
	SetPixel(hDC, x+1, y-2, cr);

	SetPixel(hDC, x-1, y+2, cr);
	SetPixel(hDC, x,   y+2, cr);
	SetPixel(hDC, x+1, y+2, cr);
}


// draw a 2nd degree Bezier curve segment
BOOL Bezier(HDC hDC, int & x0, int & y0, int x1, int y1, int x2, int y2)
{
	// p0 p1 p2 -> p0 (p0+2p1)/3 (2p1+p2)/3, p2
				
	POINT P[3] = { { (x0+2*x1)/3, (y0+2*y1)/3 }, { (2*x1+x2)/3, (2*y1+y2)/3 }, { x2, y2 } };
	x0 = x2; y0 = y2;

	return PolyBezierTo(hDC, P, 3);
}


class KScale
{
	int    _x;
	int    _y;
	double _scale;

public:
	KScale(int x, int y, double scale)
	{
		_x     = x;
		_y     = y;
		_scale = scale;
	}

	void Map(POINT & p)
	{
		p.x = (int) (_x + p.x * _scale);
		p.y = (int) (_y - p.y * _scale);
	}

	void Line(HDC hDC, int x0, int y0, int x1, int y1)
	{
		MoveToEx(hDC, (int) (_x + x0 * _scale), (int) (_y - y0 * _scale), NULL);
		LineTo  (hDC, (int) (_x + x1 * _scale), (int) (_y - y1 * _scale));
	}
};


class KCurve
{
	typedef enum { MAX_POINTS = 1024 };

	POINT m_Point[MAX_POINTS];
	BYTE  m_Flag [MAX_POINTS];

	RECT  m_bound;
	int   m_len;
	int   m_open;

public:

	int   m_glyphsize;
	int   m_instrsize;
	int   m_glyphindex;
	int   m_Ascender;
	int	  m_Descender;
	int   m_LineGap;
	int   m_advancewidth;
	int   m_lsb;
	
	typedef enum { FLAG_ON=1, FLAG_OPEN=2, FLAG_EXTRA=4 };

	void SetBound(signed short x0, signed short y0, signed short x1, signed short y1)
	{
		m_bound.left   = x0;
		m_bound.top    = y0;
		m_bound.right  = x1;
		m_bound.bottom = y1;
	}

	void Reset(void)
	{
		m_len    = 0;
		m_open   = 0;
	}

	void Append(int x, int y, BYTE flag)
	{
		m_Point[m_len].x = x;
		m_Point[m_len].y = y;

		if ( m_open==m_len )
			flag |= FLAG_OPEN;

		m_Flag[m_len]    = flag;
	
		assert(m_len<= MAX_POINTS);
		m_len ++;
	}

	void Add(int x, int y, BYTE flag)
	{
		if ( m_len && ( (flag & FLAG_ON)==0 ) && ( (m_Flag[m_len-1] & FLAG_ON)==0 ) )
		{
			Append((m_Point[m_len-1].x+x)/2, (m_Point[m_len-1].y+y)/2, FLAG_ON | FLAG_EXTRA); // add a middle point
		}

		Append(x, y, flag);
	}

	void Close(void)
	{
		Append(m_Point[m_open].x, m_Point[m_open].y, FLAG_ON | FLAG_EXTRA);
		m_open = m_len;
	}

	int GetLength(void) const
	{
		return m_len;
	}

	BOOL Draw(HDC hDC, int x, int y, double scale, int mark, int emsquare)
	{
		KScale sc(x, y, scale);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?