|
|
/**************************************************************************\
* * Copyright (c) 1999 Microsoft Corporation * * Module Name: * * font.cpp * * Revision History: * * Aug/12/1999 Xudong Wu [tessiew] * Created it. * \**************************************************************************/
#include "precomp.hpp"
const DOUBLE PI = 3.1415926535897932384626433832795;
#if DBG
#include <mmsystem.h>
#endif
//
// Masks for supported code pages in the font
//
#define Latine1CodePageMask 0x0000000000000001
#define Latine2CodePageMask 0x0000000000000002
#define CyrillicCodePageMask 0x0000000000000004
#define GreekCodePageMask 0x0000000000000008
#define TurkishCodePageMask 0x0000000000000010
#define HebrewCodePageMask 0x0000000000000020
#define ArabicCodePageMask 0x0000000000000040
#define BalticCodePageMask 0x0000000000000080
#define Reserved1CodePageMask 0x000000000000FF00
#define ThaiCodePageMask 0x0000000000010000
#define JapanCodePageMask 0x0000000000020000
#define ChineseCodePageMask 0x0000000000040000
#define KoreanCodePageMask 0x0000000000080000
#define TraditionalChineseCodePageMask 0x0000000000100000
#define KoreanJohabCodePageMask 0x0000000000200000
#define Reserved2CodePageMask 0x000000001FC00000
#define MacintoshPageMask 0x0000000020000000
#define OEMCodePageMask 0x0000000040000000
#define SymbolCodePageMask 0x0000000080000000
#define Reserved3CodePageMask 0x0000FFFF00000000
#define IBMGreekCodePageMask 0x0001000000000000
#define RussianMsDosCodePageMask 0x0002000000000000
#define NordicCodePageMask 0x0004000000000000
#define ArabicMsDosCodePageMask 0x0008000000000000
#define CanandianMsDosCodePageMask 0x0010000000000000
#define HebrewMsDosCodePageMask 0x0020000000000000
#define IcelandicMsDosCodePageMask 0x0040000000000000
#define PortugueseMsDosCodePageMask 0x0080000000000000
#define IBMTurkishCodePageMask 0x0100000000000000
#define IBMCyrillicCodePageMask 0x0200000000000000
#define Latin2MsDosCodePageMask 0x0400000000000000
#define BalticMsDosCodePageMask 0x0800000000000000
#define Greek437CodePageMask 0x1000000000000000
#define ArabicAsmoCodePageMask 0x2000000000000000
#define WeLatinCodePageMask 0x4000000000000000
#define USCodePageMask 0x8000000000000000
///// Create fonts from DC and optional ANSI or Unicode logfont
//
//
GpFont::GpFont( REAL size, const GpFontFamily *family, INT style, Unit unit ) : Family (family), EmSize (size), Style (style), SizeUnit (unit) { SetValid(TRUE); // default is valid
if (!(Family && Family->IsFileLoaded())) Family = NULL; }
GpFont::GpFont( HDC hdc ) { SetValid(TRUE); // default is valid
// intialize it as invalid
Family = NULL; InitializeFromDc(hdc); }
GpFont::GpFont( HDC hdc, LOGFONTW *logfont ) { SetValid(TRUE); // default is valid
HFONT hOldFont = NULL; // intialize it as invalid
Family = NULL;
if (!hdc) return;
HFONT hFont = CreateFontIndirectW(logfont);
if (!hFont) return;
hOldFont = (HFONT) SelectObject(hdc, hFont);
InitializeFromDc(hdc);
if (!hOldFont) return;
DeleteObject(SelectObject(hdc, hOldFont)); }
GpFont::GpFont( HDC hdc, LOGFONTA *logfont ) { SetValid(TRUE); // default is valid
HFONT hOldFont = NULL; // intialize it as invalid
Family = NULL;
if (!hdc) return;
HFONT hFont = CreateFontIndirectA(logfont);
if (!hFont) return;
hOldFont = (HFONT) SelectObject(hdc, hFont);
InitializeFromDc(hdc);
if (!hOldFont) return;
DeleteObject(SelectObject(hdc, hOldFont)); }
VOID GpFont::InitializeFromDc( HDC hdc ) { WCHAR faceName[LF_FACESIZE]; GpFontTable *fontTable;
fontTable = (GpInstalledFontCollection::GetGpInstalledFontCollection())->GetFontTable();
if (!fontTable->IsValid()) return;
if (!fontTable->IsPrivate() && !fontTable->IsFontLoaded()) fontTable->LoadAllFonts();
if (Globals::IsNt) { TEXTMETRICW tmw;
if (!GetTextMetricsW(hdc, &tmw)) { return; }
GetTextFaceW(hdc, LF_FACESIZE, faceName);
EmSize = REAL(tmw.tmHeight-tmw.tmInternalLeading);
Style = FontStyleRegular; if (tmw.tmWeight > 400) {Style |= FontStyleBold;} if (tmw.tmItalic) {Style |= FontStyleItalic;} if (tmw.tmUnderlined) {Style |= FontStyleUnderline;} if (tmw.tmStruckOut) {Style |= FontStyleStrikeout;} } else { TEXTMETRICA tma;
if (!GetTextMetricsA(hdc, &tma)) { return; }
char faceNameA[LF_FACESIZE]; GetTextFaceA(hdc, LF_FACESIZE, faceNameA); AnsiToUnicodeStr(faceNameA, faceName, LF_FACESIZE);
EmSize = REAL(tma.tmHeight-tma.tmInternalLeading);
Style = FontStyleRegular; if (tma.tmWeight > 400) {Style |= FontStyleBold;} if (tma.tmItalic) {Style |= FontStyleItalic;} if (tma.tmUnderlined) {Style |= FontStyleUnderline;} if (tma.tmStruckOut) {Style |= FontStyleStrikeout;} }
if (faceName[0] == L'@') UnicodeStringCopy(&faceName[0], &faceName[1]);
Family = fontTable->GetFontFamily(faceName);
if (Family == NULL) { GetFamilySubstitution(faceName, (GpFontFamily **) &Family); }
if (!(Family && Family->IsFileLoaded())) Family = NULL;
SizeUnit = UnitWorld; }
GpStatus GpFont::GetLogFontA( GpGraphics * g, LOGFONTA * lfa ) { PointF scale; REAL rotateRadians; REAL shear; PointF translate; GpMatrix worldToDevice;
g->GetWorldToDeviceTransform(&worldToDevice);
SplitTransform( worldToDevice, scale, rotateRadians, shear, translate);
INT rotateDeciDegrees = 3600 - (INT) (rotateRadians * 1800 / PI);
if (rotateDeciDegrees == 3600) rotateDeciDegrees = 0;
REAL emHeight = EmSize * scale.Y * g->GetScaleForAlternatePageUnit(SizeUnit);
lfa->lfHeight = -GpRound(emHeight); lfa->lfWidth = 0; lfa->lfEscapement = rotateDeciDegrees; lfa->lfOrientation = rotateDeciDegrees; lfa->lfWeight = Style & FontStyleBold ? 700 : 400; lfa->lfItalic = Style & FontStyleItalic ? 1 : 0; lfa->lfUnderline = Style & FontStyleUnderline ? 1 : 0; lfa->lfStrikeOut = Style & FontStyleStrikeout ? 1 : 0; lfa->lfCharSet = (((GpFontFamily *)Family)->GetFace(Style))->GetCharset(g->GetHdc()); lfa->lfOutPrecision = 0; lfa->lfClipPrecision = 0; lfa->lfQuality = 0; lfa->lfPitchAndFamily = 0;
UnicodeToAnsiStr((WCHAR*)( (BYTE*)(((GpFontFamily *)Family)->GetFace(Style))->pifi + (((GpFontFamily *)Family)->GetFace(Style))->pifi->dpwszFamilyName), lfa->lfFaceName, LF_FACESIZE);
// Do we need to have a scale value for width????
// We still need to think about it.
return Ok; }
GpStatus GpFont::GetLogFontW( GpGraphics * g, LOGFONTW * lfw) { PointF scale; REAL rotateRadians; REAL shear; PointF translate; GpMatrix worldToDevice;
g->GetWorldToDeviceTransform(&worldToDevice);
SplitTransform( worldToDevice, scale, rotateRadians, shear, translate);
INT rotateDeciDegrees = 3600 - (INT) (rotateRadians * 1800 / PI);
if (rotateDeciDegrees == 3600) rotateDeciDegrees = 0;
REAL emHeight = EmSize * scale.Y * g->GetScaleForAlternatePageUnit(SizeUnit);
lfw->lfHeight = -GpRound(emHeight); lfw->lfWidth = 0; lfw->lfEscapement = rotateDeciDegrees; lfw->lfOrientation = rotateDeciDegrees; lfw->lfWeight = Style & FontStyleBold ? 700 : 400; lfw->lfItalic = Style & FontStyleItalic ? 1 : 0; lfw->lfUnderline = Style & FontStyleUnderline ? 1 : 0; lfw->lfStrikeOut = Style & FontStyleStrikeout ? 1 : 0;
ASSERT(((GpFontFamily *)Family)->GetFace(Style)); lfw->lfCharSet = (((GpFontFamily *)Family)->GetFace(Style))->GetCharset(g->GetHdc());
lfw->lfOutPrecision = 0; lfw->lfClipPrecision = 0; lfw->lfQuality = 0; lfw->lfPitchAndFamily = 0;
memcpy(lfw->lfFaceName, (WCHAR*)( (BYTE*)(((GpFontFamily *)Family)->GetFace(Style))->pifi + (((GpFontFamily *)Family)->GetFace(Style))->pifi->dpwszFamilyName), sizeof(lfw->lfFaceName));
return Ok; }
/**************************************************************************\
* * * Revision History: * * 02/11/1999 YungT * Created it. * \**************************************************************************/
int CALLBACK GpFontFace::EnumFontFamExProcW( const ENUMLOGFONTEXW *lpelfe, // pointer to logical-font data
const NEWTEXTMETRICEXW *lpntme, // pointer to physical-font data
int FontType, // type of font
LPARAM lParam // application-defined data
) { if (FontType == TRUETYPE_FONTTYPE) { (*(BYTE *) lParam) = lpelfe->elfLogFont.lfCharSet;
return 0; } else { return 1; // Don't stop!
} }
/**************************************************************************\
* * * Revision History: * * 02/11/1999 YungT * Created it. * \**************************************************************************/
int CALLBACK GpFontFace::EnumFontFamExProcA( const ENUMLOGFONTEXA *lpelfe, // pointer to logical-font data
const NEWTEXTMETRICEXA *lpntme, // pointer to physical-font data
int FontType, // type of font
LPARAM lParam // application-defined data
) { if (FontType == TRUETYPE_FONTTYPE) { (*(BYTE *) lParam) = lpelfe->elfLogFont.lfCharSet;
return 0; } else { return 1; // Don't stop!
} }
/**************************************************************************\
* * Function Description: * * Get the charset from GDI * * Arguments: * * We need it for we need to select a logfont into DC. Or * Convert a GpFont to LOGFONT * * Returns: * * BYTE value of charset * * History: * * 02/11/2000 YungT * Created it. * \**************************************************************************/
BYTE GpFontFace::GetCharset(HDC hDc) const { if (lfCharset == DEFAULT_CHARSET) { if (Globals::IsNt) {
LOGFONTW lfw = { 0, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, // charset
0, 0, 0, 0, L"" };
memcpy(lfw.lfFaceName, (WCHAR*)( (BYTE*)pifi + pifi->dpwszFamilyName), sizeof(lfw.lfFaceName));
EnumFontFamiliesExW(hDc, &lfw, (FONTENUMPROCW) EnumFontFamExProcW, (LPARAM) &lfCharset, 0); } else { // ANSI version for Win9X
LOGFONTA lfa = { 0, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, // charset
0, 0, 0, 0, "" };
UnicodeToAnsiStr((WCHAR*)( (BYTE*)pifi + pifi->dpwszFamilyName), lfa.lfFaceName, LF_FACESIZE);
EnumFontFamiliesExA(hDc, &lfa, (FONTENUMPROCA) EnumFontFamExProcA, (LPARAM) &lfCharset, 0); } }
return lfCharset; }
///// InitializeImagerTables
//
// Load character to glyph map and design advance widths
static inline UINT16 byteSwapUINT16(UINT16 u) { return ((u & 0x00FF) << 8) | ((u & 0xFF00) >> 8); }
#pragma pack(push, 1)
struct HheaTable {
// NOTE: all fields are stored in Big Endian (Motorola) ordering
UINT32 version; // Table version number 0x00010000 for version 1.0.
INT16 Ascender; // Typographic ascent.
INT16 Descender; // Typographic descent.
INT16 LineGap; // Typographic line gap. Negative LineGap values are
// treated as zero in Windows 3.1, System 6, and System 7.
UINT16 advanceWidthMax; // Maximum advance width value in 'hmtx' table.
INT16 minLeftSideBearing; // Minimum left sidebearing value in 'hmtx' table.
INT16 minRightSideBearing; // Minimum right sidebearing value; calculated as Min(aw - lsb - (xMax - xMin)).
INT16 xMaxExtent; // Max(lsb + (xMax - xMin)).
INT16 caretSlopeRise; // Used to calculate the slope of the cursor (rise/run); 1 for vertical.
INT16 caretSlopeRun; // 0 for vertical.
INT16 reserved1; // set to 0
INT16 reserved2; // set to 0
INT16 reserved3; // set to 0
INT16 reserved4; // set to 0
INT16 reserved5; // set to 0
INT16 metricDataFormat; // 0 for current format.
UINT16 numberOfHMetrics; // Number of hMetric entries in 'hmtx' table; must be equal to the CharStrings INDEX count in the 'CFF ' table.
};
struct VheaTable {
// NOTE: all fields are stored in Big Endian (Motorola) ordering
UINT32 version; // Version number of the vertical header table (0x00010000 for the initial version).
INT16 ascent; // Distance in FUnits from the centerline to the previous line's descent.
INT16 descent; // Distance in FUnits from the centerline to the next line's ascent.
INT16 lineGap; // Reserved; set to 0
INT16 advanceHeightMax; // The maximum advance height measurement -in FUnits found in the font.
// This value must be consistent with the entries in the vertical metrics table.
INT16 minTop; // SideBearing The minimum top sidebearing measurement found in the font, in FUnits.
// This value must be consistent with the entries in the vertical metrics table.
INT16 minBottom; // SideBearing The minimum bottom sidebearing measurement found in the font, in FUnits.
// This value must be consistent with the entries in the vertical metrics table.
INT16 yMaxExtent; // Defined as yMaxExtent=minTopSideBearing+(yMax-yMin)
INT16 caretSlopeRise; // The value of the caretSlopeRise field divided by the value of the caretSlopeRun Field
// determines the slope of the caret. A value of 0 for the rise and a value of 1 for the
// run specifies a horizontal caret. A value of 1 for the rise and a value of 0 for the
// run specifies a vertical caret. Intermediate values are desirable for fonts whose
// glyphs are oblique or italic. For a vertical font, a horizontal caret is best.
INT16 caretSlopeRun; // See the caretSlopeRise field. Value=1 for nonslanted vertical fonts.
INT16 caretOffset; // The amount by which the highlight on a slanted glyph needs to be shifted away from
// the glyph in order to produce the best appearance. Set value equal to 0 for nonslanted fonts.
INT16 reserved1; // Set to 0.
INT16 reserved2; // Set to 0.
INT16 reserved3; // Set to 0.
INT16 reserved4; // Set to 0.
INT16 metricDataFormat; // Set to 0.
UINT16 numOfLongVerMetrics; // Number of advance heights in the vertical metrics table; must be equal to the
// CharStrings INDEX count field in the 'CFF ' table.
};
#pragma pack(pop)
GpStatus GpFontFace::GetFontData(UINT32 tag, INT* tableSize, BYTE** pjTable) const { GpStatus status = Ok; ULONG cjTable;
if (ttfdSemGetTrueTypeTable (pff->hff, iFont, tag, pjTable, &cjTable) == FD_ERROR) { return GenericError; } *tableSize = cjTable;
return status; }
void GpFontFace::ReleaseFontData() const { ttfdSemReleaseTrueTypeTable (pff->hff); }
///// GetGlyphDesignAdvances
//
// Returns advance widths along or perpendicular to baseline in
// font design units.
void GpFontFace::GetGlyphDesignAdvances( const UINT16 *glyphs, // In
INT glyphCount, // In
INT style, // In - causes adjustment for algorithmic style emulation
BOOL vertical, // In - Use vmtx, not hmtx
REAL tracking, // In - expansion factor
UINT16 *advances // Out
) const { if (vertical) { if (DesignVerticalAdvance) { DesignVerticalAdvance->Lookup(glyphs, glyphCount, advances); } else { // There's no vmtx - fallback appropriately
// Win 9x uses the typographic height (typo ascender - typo descender),
// but NT uses the cell height (cell ascender + cell descender).
// Which shall we use? The problem with the cell height is that in a
// multilingual font it may be much taller than the Far East glyphs,
// causing the common case (Far East vertical text) to appear too
// widely spaced. The problem with the typographic height is that it
// includes little or no extra space for diacritic marks.
// Choice: use the Typographic height: It is best for FE, and the font
// can fix non FE diacritic cases if it wishes by providing a vmtx.
for (INT i=0; i<glyphCount; i++) { advances[i] = pifi->fwdTypoAscender - pifi->fwdTypoDescender; }
} } else { DesignAdvance->Lookup(glyphs, glyphCount, advances);
if ( (style & FontStyleBold) && !(GetFaceStyle() & FontStyleBold)) { // Algorithmic emboldening increases glyph width
UINT16 extraAdvance = ((pifi->fwdUnitsPerEm * 2 - 1) / 100);
for (INT i=0; i<glyphCount; i++) { if (advances[i] != 0) { advances[i] += extraAdvance; } } }
if (tracking != 1.0) { for (INT i=0; i<glyphCount; i++) { advances[i] = static_cast<UINT16>(GpRound(advances[i] * tracking)); } } } }
///// GetGlyphDesignAdvancesIdeal
//
// Returns advance widths along or perpendicular to baseline scaled to
// ideal units.
void GpFontFace::GetGlyphDesignAdvancesIdeal( const UINT16 *glyphs, // In
INT glyphCount, // In
INT style, // In - Causes adjustment for algorithmic style emulation
BOOL vertical, // In - Use vtmx, not htmx
REAL designToIdeal, // In - Scale factor for each advance width
REAL tracking, // In - Expansion factor
INT *advances // Out
) const { if (vertical) { if (DesignVerticalAdvance) { for (INT i=0; i<glyphCount; i++) { advances[i] = GpRound(TOREAL(DesignVerticalAdvance->Lookup(glyphs[i]) * designToIdeal)); } } else { INT commonVerticalAdvance = GpRound(TOREAL( //(pifi->fwdMacAscender - pifi->fwdMacDescender)
pifi->fwdUnitsPerEm * designToIdeal )); for (INT i=0; i<glyphCount; i++) { advances[i] = commonVerticalAdvance; } } } else { // Horizontal advance width
for (INT i=0; i<glyphCount; i++) { advances[i] = GpRound(TOREAL(DesignAdvance->Lookup(glyphs[i]) * designToIdeal * tracking)); }
if ( (style & FontStyleBold) && !(GetFaceStyle() & FontStyleBold)) { // Algorithmic emboldening increases glyph width
UINT16 extraAdvance = ((pifi->fwdUnitsPerEm * 2 - 1) / 100);
for (INT i=0; i<glyphCount; i++) { if (advances[i] != 0) { advances[i] += extraAdvance; } } } } }
BOOL GpFontFace::IsCodePageSupported(UINT codePage) { switch (codePage) { case 1252: return SupportedCodePages & Latine1CodePageMask ? TRUE : FALSE; break;
case 1250: return SupportedCodePages & Latine2CodePageMask ? TRUE : FALSE; break;
case 1251: return SupportedCodePages & CyrillicCodePageMask ? TRUE : FALSE; break;
case 1253: return SupportedCodePages & GreekCodePageMask ? TRUE : FALSE; break;
case 1254: return SupportedCodePages & TurkishCodePageMask ? TRUE : FALSE; break;
case 1255: return SupportedCodePages & HebrewCodePageMask ? TRUE : FALSE; break;
case 1256: return SupportedCodePages & ArabicCodePageMask ? TRUE : FALSE; break;
case 1257: return SupportedCodePages & BalticCodePageMask ? TRUE : FALSE; break;
case 874: return SupportedCodePages & ThaiCodePageMask ? TRUE : FALSE; break;
case 932: return SupportedCodePages & JapanCodePageMask ? TRUE : FALSE; break;
case 936: return SupportedCodePages & ChineseCodePageMask ? TRUE : FALSE; break;
case 949: return SupportedCodePages & KoreanCodePageMask ? TRUE : FALSE; break;
case 950: return SupportedCodePages & TraditionalChineseCodePageMask ? TRUE : FALSE; break;
case 1361: return SupportedCodePages & KoreanJohabCodePageMask? TRUE : FALSE; break;
case 869: return SupportedCodePages & IBMGreekCodePageMask ? TRUE : FALSE; break;
case 866: return SupportedCodePages & RussianMsDosCodePageMask ? TRUE : FALSE; break;
case 865: return SupportedCodePages & NordicCodePageMask ? TRUE : FALSE; break;
case 864: return SupportedCodePages & ArabicMsDosCodePageMask ? TRUE : FALSE; break;
case 863: return SupportedCodePages & CanandianMsDosCodePageMask ? TRUE : FALSE; break;
case 862: return SupportedCodePages & HebrewMsDosCodePageMask ? TRUE : FALSE; break;
case 861: return SupportedCodePages & IcelandicMsDosCodePageMask ? TRUE : FALSE; break;
case 860: return SupportedCodePages & PortugueseMsDosCodePageMask ? TRUE : FALSE; break;
case 857: return SupportedCodePages & IBMTurkishCodePageMask ? TRUE : FALSE; break;
case 855: return SupportedCodePages & IBMCyrillicCodePageMask ? TRUE : FALSE; break;
case 852: return SupportedCodePages & Latin2MsDosCodePageMask ? TRUE : FALSE; break;
case 775: return SupportedCodePages & BalticMsDosCodePageMask ? TRUE : FALSE; break;
case 737: return SupportedCodePages & Greek437CodePageMask ? TRUE : FALSE; break;
case 708: return SupportedCodePages & ArabicAsmoCodePageMask ? TRUE : FALSE; break;
case 850: return SupportedCodePages & WeLatinCodePageMask ? TRUE : FALSE; break;
case 437: return SupportedCodePages & USCodePageMask ? TRUE : FALSE; break; } return FALSE; }
static inline UINT16 MapGetUINT16(UINT16 *p, Status* pStatus) { UINT16 r; __try { r = *p; } __except (EXCEPTION_EXECUTE_HANDLER) { *pStatus = GenericError; } return r; }
BOOL GpFontFace::InitializeImagerTables() { // MissingGlyph Should be initialized before calling Shaping.Create()
// because it depends on it.
MissingGlyph = 0; // !!! Not true for all FE fonts
// We goining to initialize it correctly in shaping.cpp
SupportedCodePages = 0;
// Initialise tables to default values
Cmap = 0; DesignAdvance = 0;
DesignVerticalAdvance = NULL; DesignTopSidebearing = NULL; MissingGlyph = 0; // !!! Not true for all FE fonts
BlankGlyph = 0; RequiresFullText = FALSE; Shaping.Cache = NULL; Gsub = NULL; Mort = NULL; Gpos = NULL; Gdef = NULL; VerticalSubstitutionCount = 0; VerticalSubstitutionOriginals = NULL; VerticalSubstitutionSubstitutions = NULL;
BYTE * hheaTable = 0; INT hheaLength = 0;
if (GetFontData('aehh', &hheaLength, &hheaTable) != Ok) { return FALSE; }
// from now on we can't return early, because we need to release font data in the end of the function
GpStatus status = Ok;
Cmap = new IntMap<UINT16>; if (!Cmap) status = OutOfMemory; else status = Cmap->GetStatus();
if (status == Ok) { DesignAdvance = new IntMap<UINT16>; if (!DesignAdvance) status = OutOfMemory; else status = DesignAdvance->GetStatus(); } /// Load CMAP
//
//
if (status == Ok) { INT cmapLength = 0; BYTE *cmapTable = 0;
if (Cmap && GetFontData('pamc', &cmapLength, &cmapTable) == Ok) { AutoArray<BYTE> cmapCopy(new BYTE [cmapLength]); // copy of cmap table
if (!cmapCopy) status = OutOfMemory; else MapCopy (cmapCopy.Get(), cmapTable, cmapLength, &status);
ReleaseFontData(); // deref cmap
if (status == Ok) { bSymbol = FALSE;
status = ReadCmap(cmapCopy.Get(), cmapLength, Cmap, &bSymbol);
// !!! Fix up CMAP for special font types here
// We fallback to Microsoft Sans serif for Arabic scripts which does not have
// a glyph for Arabic percent sign (before Whistler)
// We replace its glyph with the Latin precent sign.
if (status == Ok && !UnicodeStringCompareCI((PWSTR)((BYTE*)pifi + pifi->dpwszFamilyName),L"Microsoft Sans Serif") && Cmap->Lookup(0x066A) == 0) { status = Cmap->Insert(0x066A, Cmap->Lookup(0x0025)); } } } }
/// Load horizontal metrics
//
//
if (status == Ok) { INT hmtxLength = 0; BYTE *hmtxTable = 0;
if (DesignAdvance && GetFontData('xtmh', &hmtxLength, &hmtxTable) == Ok) { AutoArray<BYTE> hmtxCopy(new BYTE [hmtxLength]); // copy of hmtx table
// Copy the hmtx so we can party on it (byte swap for example)
if (!hmtxCopy) status = OutOfMemory; else MapCopy (hmtxCopy.Get(), hmtxTable, hmtxLength, &status);
ReleaseFontData(); // deref hmtx
if (status == Ok) { UINT16 numberOfHMetrics = MapGetUINT16( &((HheaTable *)hheaTable)->numberOfHMetrics, &status);
if (status == Ok) status = ReadMtx( hmtxCopy.Get(), hmtxLength, NumGlyphs, byteSwapUINT16(numberOfHMetrics), DesignAdvance ); } } }
/// Load vertical metrics, if any
//
//
if (status == Ok) { BYTE *vheaTable = 0; INT vheaLength = 0;
if (GetFontData('aehv', &vheaLength, &vheaTable) == Ok) { INT vmtxLength = 0; BYTE *vmtxTable = 0; if (GetFontData('xtmv', &vmtxLength, &vmtxTable) == Ok) { AutoArray<BYTE> vmtxCopy(new BYTE [vmtxLength]); // copy of vmtx table
if (!vmtxCopy) status = OutOfMemory; else MapCopy (vmtxCopy.Get(), vmtxTable, vmtxLength, &status);
ReleaseFontData(); // deref vmtx
if (status == Ok) { UINT16 numOfLongVerMetrics = MapGetUINT16( &((VheaTable *)vheaTable)->numOfLongVerMetrics, &status);
if (status == Ok) { numOfLongVerMetrics = byteSwapUINT16(numOfLongVerMetrics);
DesignVerticalAdvance = new IntMap<UINT16>; if (!DesignVerticalAdvance) status = OutOfMemory; else { status = ReadMtx( vmtxCopy.Get(), vmtxLength, NumGlyphs, numOfLongVerMetrics, DesignVerticalAdvance ); }
if (status == Ok) { DesignTopSidebearing = new IntMap<UINT16>; if (!DesignTopSidebearing) status = OutOfMemory; else { status = ReadMtxSidebearing( vmtxCopy.Get(), vmtxLength, NumGlyphs, numOfLongVerMetrics, DesignTopSidebearing ); } } } } } ReleaseFontData(); // deref vhea
} }
/// Load OTL tables
//
//
if (status == Ok) { INT tableSize = 0; BYTE *tableAddress = 0;
if (GetFontData('BUSG', &tableSize, &tableAddress) == Ok) // GSUB
{ Gsub = new BYTE[tableSize]; if (!Gsub) status = OutOfMemory; else { MapCopy(Gsub, tableAddress, tableSize, &status); // Override the table first fix32 version field to our own use,
// it now contains the size of each table in byte.
((UINT32 *)Gsub)[0] = tableSize; } ReleaseFontData(); } else { if (GetFontData('trom', &tableSize, &tableAddress) == Ok) // mort
{ Mort = new BYTE[tableSize]; if (!Mort) status = OutOfMemory; else { MapCopy(Mort, tableAddress, tableSize, &status); // Override the table first fix32 version field to our own use,
// it now contains the size of each table in byte.
((UINT32 *)Mort)[0] = tableSize; } ReleaseFontData(); } }
if (status == Ok && GetFontData('SOPG', &tableSize, &tableAddress) == Ok) // GPOS
{ Gpos = new BYTE[tableSize]; if (!Gpos) status = OutOfMemory; else { MapCopy(Gpos, tableAddress, tableSize, &status); ((UINT32 *)Gpos)[0] = tableSize; } ReleaseFontData(); }
if (status == Ok && GetFontData('FEDG', &tableSize, &tableAddress) == Ok) // GDEF
{ Gdef = new BYTE[tableSize]; if (!Gdef) status = OutOfMemory; else { MapCopy(Gdef, tableAddress, tableSize, &status); ((UINT32 *)Gdef)[0] = tableSize; } ReleaseFontData(); }
if (status == Ok) { if (Gsub) { // Get address of vertical substitution info, if any
LoadVerticalSubstitution( Gsub, &VerticalSubstitutionCount, &VerticalSubstitutionOriginals, &VerticalSubstitutionSubstitutions ); } else if (Mort) { LoadMortVerticalSubstitution( Mort, &VerticalSubstitutionCount, &VerticalSubstitutionOriginals, &VerticalSubstitutionSubstitutions ); } } }
/// Build shaping cache
//
//
if (status == Ok) status = Shaping.Create(this);
if (status == Ok) BlankGlyph = Cmap->Lookup(' ');
// All done
ReleaseFontData(); // deref hhea
if (status != Ok) { FreeImagerTables(); return FALSE; } return TRUE; }
void GpFontFace::FreeImagerTables() { delete Cmap, Cmap = NULL; delete DesignAdvance, DesignAdvance = NULL;
Shaping.Destroy();
delete DesignVerticalAdvance, DesignVerticalAdvance = NULL; delete DesignTopSidebearing, DesignTopSidebearing = NULL; delete [] Gsub, Gsub = NULL; delete [] Mort, Mort = NULL; delete [] Gpos, Gpos = NULL; delete [] Gdef, Gdef = NULL; } // GpFontFace::FreeImagerTables
GpStatus GpGlyphPath::CopyPath(GpPath *path) { ASSERT(path->IsValid());
INT count;
curveCount = path->GetSubpathCount(); hasBezier = path->HasCurve(); pointCount = count = path->GetPointCount();
if (count) { points = (GpPointF*) ((BYTE*)this + sizeof(GpGlyphPath)); types = (BYTE*) ((BYTE*)points + sizeof(GpPointF) * count);
const GpPointF *pathPoints = path->GetPathPoints(); const BYTE *pathTypes = path->GetPathTypes();
GpMemcpy(points, pathPoints, count * sizeof(GpPointF)); GpMemcpy(types, pathTypes, count * sizeof(BYTE)); } else // 'blank' glyph
{ points = NULL; types = NULL; }
return Ok; }
///// GetHeight
//
// Returns height in world units for a given graphics. If graphics passed
// as NULL works as if passed a graphics derived from GetDC(NULL).
GpStatus GpFont::GetHeightAtWorldEmSize(REAL worldEmSize, REAL *height) const { const GpFontFace *face = Family->GetFace(Style);
if (!face) { return InvalidParameter; }
*height = TOREAL(worldEmSize * face->GetDesignLineSpacing() / face->GetDesignEmHeight());
return Ok; }
GpStatus GpFont::GetHeight(REAL dpi, REAL *height) const { REAL worldEmSize = EmSize;
switch (SizeUnit) { case UnitPoint: worldEmSize = EmSize * dpi / 72.0f; break; case UnitInch: worldEmSize = EmSize * dpi; break; case UnitDocument: worldEmSize = EmSize * dpi / 300.0f; break; case UnitMillimeter: worldEmSize = EmSize * dpi / 25.4f; break; }
return GetHeightAtWorldEmSize(worldEmSize, height); }
GpStatus GpFont::GetHeight(const GpGraphics *graphics, REAL *height) const { REAL worldEmSize = EmSize * graphics->GetScaleForAlternatePageUnit(SizeUnit);
return GetHeightAtWorldEmSize(worldEmSize, height); }
class FontRecordData : public ObjectData { public: REAL EmSize; Unit SizeUnit; INT Style; UINT Flag; UINT Length; };
/**************************************************************************\
* * Function Description: * * Get the font data. * * Arguments: * * [IN] dataBuffer - fill this buffer with the data * [IN/OUT] size - IN - size of buffer; OUT - number bytes written * * Return Value: * * GpStatus - Ok or error code * * Created: * * 9/13/1999 DCurtis * \**************************************************************************/ GpStatus GpFont::GetData( IStream * stream ) const { ASSERT (stream != NULL);
WCHAR * familyName = const_cast<WCHAR *>((const_cast<GpFontFamily *>(Family))->GetCaptializedName()); UINT length = 0;
if (familyName) { length = UnicodeStringLength(familyName); }
FontRecordData fontData;
fontData.EmSize = EmSize; fontData.SizeUnit = SizeUnit; fontData.Style = Style;
// !!! For now, we assume the next block of bytes is the
// family name (flag == 0). In the future, we need to handle
// memory images (flag == 1).
fontData.Flag = 0; fontData.Length = length;
stream->Write(&fontData, sizeof(fontData), NULL); stream->Write(familyName, length * sizeof(WCHAR), NULL);
// align
if ((length & 0x01) != 0) { length = 0; stream->Write(&length, sizeof(WCHAR), NULL); }
return Ok; }
UINT GpFont::GetDataSize() const { UINT dataSize = sizeof(FontRecordData); WCHAR * familyName = const_cast<WCHAR *>((const_cast<GpFontFamily *>(Family))->GetCaptializedName());
if (familyName) { dataSize += (UnicodeStringLength(familyName) * sizeof(WCHAR)); }
return ((dataSize + 3) & (~3)); // align
}
/**************************************************************************\
* * Function Description: * * Read the font object from memory. * * Arguments: * * [IN] dataBuffer - the data that was read from the stream * [IN] size - the size of the data * * Return Value: * * GpStatus - Ok or failure status * * Created: * * 4/26/1999 DCurtis * \**************************************************************************/ GpStatus GpFont::SetData( const BYTE * dataBuffer, UINT size ) { if ((dataBuffer == NULL) || (size < sizeof(FontRecordData))) { WARNING(("dataBuffer is NULL or size is too small")); return InvalidParameter; }
UINT flag; UINT length; WCHAR familyName[FamilyNameMax]; const FontRecordData * fontData = (const FontRecordData *)dataBuffer;
if (!fontData->MajorVersionMatches()) { WARNING(("Version number mismatch")); return InvalidParameter; }
EmSize = fontData->EmSize; SizeUnit = fontData->SizeUnit; Style = fontData->Style; length = fontData->Length; dataBuffer += sizeof(FontRecordData);
if (size < (sizeof(FontRecordData) + (length * sizeof(WCHAR)))) { WARNING(("size is too small")); return InvalidParameter; }
// !!! For now, we assume the next block of bytes is the
// family name (flag == 0). In the future, we need to handle
// memory images (flag == 1).
if (length > FamilyNameMax) { length = FamilyNameMax; }
// read in the familyName/data
UnicodeStringCopyCount (familyName, (WCHAR *)dataBuffer, length);
familyName[length] = 0;
// !!! For now, we assume that the font family comes from
// the installed font collection
//
// also make sure the font table is loaded the application may play
// the meta file before loading the font table.
GpFontTable *fontTable = Globals::FontCollection->GetFontTable();
if (!fontTable->IsValid()) return OutOfMemory;
if (!fontTable->IsPrivate() && !fontTable->IsFontLoaded()) fontTable->LoadAllFonts();
Family = fontTable->GetFontFamily(familyName);
if (Family == NULL) { GpStatus status = GpFontFamily::GetGenericFontFamilySansSerif((GpFontFamily **) &Family); if (status != Ok) { Family = NULL; return status; } }
if (!(Family && Family->IsFileLoaded())) { Family = NULL; }
if (Family == NULL) { return GenericError; }
UpdateUid(); return Ok; }
|