/**************************************************************************\ * * 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 #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; ifwdTypoAscender - 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(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; iLookup(glyphs[i]) * designToIdeal)); } } else { INT commonVerticalAdvance = GpRound(TOREAL( //(pifi->fwdMacAscender - pifi->fwdMacDescender) pifi->fwdUnitsPerEm * designToIdeal )); for (INT i=0; iLookup(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; if (!Cmap) status = OutOfMemory; else status = Cmap->GetStatus(); if (status == Ok) { DesignAdvance = new IntMap; 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 cmapCopy(new BYTE [cmapLength]); // copy of cmap table if (!cmapCopy) status = OutOfMemory; else GpMemcpy (cmapCopy.Get(), cmapTable, cmapLength); 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 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 GpMemcpy (hmtxCopy.Get(), hmtxTable, hmtxLength); ReleaseFontData(); // deref hmtx if (status == Ok) { status = ReadMtx( hmtxCopy.Get(), hmtxLength, NumGlyphs, byteSwapUINT16(((HheaTable *)hheaTable)->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 vmtxCopy(new BYTE [vmtxLength]); // copy of vmtx table if (!vmtxCopy) status = OutOfMemory; else GpMemcpy (vmtxCopy.Get(), vmtxTable, vmtxLength); ReleaseFontData(); // deref vmtx UINT16 numOfLongVerMetrics = byteSwapUINT16(((VheaTable *)vheaTable)->numOfLongVerMetrics); if (status == Ok) { DesignVerticalAdvance = new IntMap; if (!DesignVerticalAdvance) status = OutOfMemory; else { status = ReadMtx( vmtxCopy.Get(), vmtxLength, NumGlyphs, numOfLongVerMetrics, DesignVerticalAdvance ); } if (status == Ok) { DesignTopSidebearing = new IntMap; 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 { memcpy(Gsub, tableAddress, tableSize); // 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 { memcpy(Mort, tableAddress, tableSize); // 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 { memcpy(Gpos, tableAddress, tableSize); ((UINT32 *)Gpos)[0] = tableSize; } ReleaseFontData(); } if (status == Ok && GetFontData('FEDG', &tableSize, &tableAddress) == Ok) // GDEF { Gdef = new BYTE[tableSize]; if (!Gdef) status = OutOfMemory; else { memcpy(Gdef, tableAddress, tableSize); ((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((const_cast(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((const_cast(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; }