2025-04-27 07:49:33 -04:00

2318 lines
77 KiB
C++

/******************************************************************************
Source File: Generic Font Information.CPP
This implements the CFontInfo and all related classes, which describe printer
fonts in all the detail necessary to satisfy all these different operating
systems.
Copyright (c) 1997 by Microsoft Corporation. All Rights Reserved.
A Pretty Penny Enterprises Production
Change History:
03-03-1997 Bob_Kjelgaard@Prodigy.Net Began work on this monster
******************************************************************************/
#include "StdAfx.H"
#if defined(LONG_NAMES)
#include "Glyph Translation.H"
#include "Generic Font Information.H"
#include <Code Page Knowledge Base.H>
#else
#include "GTT.H"
#include "FontInfo.H"
#include "CodePage.H"
#endif
#include "..\Resource.H"
// These are used to glue in UFM-specific stuff
struct INVOCATION {
DWORD dwcbCommand; // Byte size of string
DWORD dwofCommand; // Offset in the file to the string
};
// `Yes, this is a bit sleazy, but DirectDraw has nothing now or ever to
// do with this tool, so why waste time tracking down more files?
#define __DD_INCLUDED__
typedef DWORD PDD_DIRECTDRAW_GLOBAL, PDD_SURFACE_LOCAL, DESIGNVECTOR,
DD_CALLBACKS, DD_HALINFO,
DD_SURFACECALLBACKS, DD_PALETTECALLBACKS, VIDEOMEMORY;
#include "winddi.h"
#include "fmnewfm.h"
#include <math.h>
// A handy constant for converting radians to 10's of a degree
static const double dConvert = 900.0 / atan2(1.0, 0.0);
// Use a static CCodePageInformation to derive more benefit from caching
static CCodePageInformation ccpi;
/******************************************************************************
CKern
This class encapsulates the kerning pair structure. It's pretty trivial.
The CFontInfo class maintains an array of these.
******************************************************************************/
class CKern : public CObject {
FD_KERNINGPAIR m_fdkp;
public:
CKern() { m_fdkp.wcFirst = m_fdkp.wcSecond = m_fdkp.fwdKern = 0; }
CKern(FD_KERNINGPAIR& fdkp) { m_fdkp = fdkp; }
WCHAR First() const { return m_fdkp.wcFirst; }
WCHAR Second() const { return m_fdkp.wcSecond; }
short Amount() const { return m_fdkp.fwdKern; }
void SetAmount(short sNew) { m_fdkp.fwdKern = sNew; }
void Store(CFile& cf) { cf.Write(&m_fdkp, sizeof m_fdkp); }
};
/******************************************************************************
CFontDifference class
This class handles the requisite information content for the Font Difference
structure involved with Font Simulation.
******************************************************************************/
/******************************************************************************
CFontDifference::CFontDifference(PBYTE pb)
This constructor initializes the fields from a FONTDIFF structure in memory.
******************************************************************************/
CFontDifference::CFontDifference(PBYTE pb, CBasicNode *pcbn) {
FONTDIFF *pfd = (FONTDIFF *) pb;
m_pcbnOwner = pcbn;
m_cwaMetrics.Add(pfd -> usWinWeight);
m_cwaMetrics.Add(pfd -> fwdMaxCharInc);
m_cwaMetrics.Add(pfd -> fwdAveCharWidth);
m_cwaMetrics.Add((WORD) (dConvert *
atan2((double) pfd -> ptlCaret.x, (double) pfd -> ptlCaret.y)));
}
/******************************************************************************
CFontDifference::SetMetric
This function will modify one of the four metrics, if it is new, and it meets
our criteria (Max >= Average, 0 <= Angle < 900, Weight <= 1000). Errors are
reported via a public enum return code.
******************************************************************************/
WORD CFontDifference::SetMetric(unsigned u, WORD wNew) {
if (wNew == m_cwaMetrics[u])
return OK;
switch (u) {
case Max:
if (wNew < m_cwaMetrics[Average])
return Reversed;
break;
case Average:
if (wNew > m_cwaMetrics[Max])
return Reversed;
break;
case Weight:
if (wNew > 1000)
return TooBig;
break;
default: // Angle
if (wNew > 899)
return TooBig;
}
m_cwaMetrics[u] = wNew;
m_pcbnOwner -> Changed();
return OK;
}
/******************************************************************************
CFontDifference::Store(CFile& cf)
This member creates a FONTDIFF structure, fills it, and writes it to the
given file. The big calculation is the x and y components for the italic
angle, if there is one.
******************************************************************************/
void CFontDifference::Store(CFile& cf, WORD wfSelection) {
FONTDIFF fd = {0, 0, 0, 0, m_cwaMetrics[Weight], wfSelection,
m_cwaMetrics[Average], m_cwaMetrics[Max]};
fd.bWeight = (m_cwaMetrics[Weight] >= FW_BOLD) ? PAN_WEIGHT_BOLD :
(m_cwaMetrics[Weight] > FW_EXTRALIGHT) ?
PAN_WEIGHT_MEDIUM : PAN_WEIGHT_LIGHT;
fd.ptlCaret.x = !m_cwaMetrics[Angle] ? 0 :
(long) (10000.0 * tan(((double) m_cwaMetrics[Angle]) / dConvert));
fd.ptlCaret.y = m_cwaMetrics[Angle] ? 10000 : 1;
cf.Write(&fd, sizeof fd);
}
/******************************************************************************
CFontInfo class
This class encapsulates all of the font knowledge this application needs.
******************************************************************************/
IMPLEMENT_SERIAL(CFontInfo, CProjectNode, 0)
/******************************************************************************
CFontInfo::MapPFM
This loads a PFM format file, if it isn't already loaded.
******************************************************************************/
BOOL CFontInfo::MapPFM() {
if (m_cbaPFM.GetSize())
return TRUE; // Already has been loaded!
try {
CFile cfLoad(m_csSource, CFile::modeRead | CFile::shareDenyWrite);
m_cbaPFM.SetSize(cfLoad.GetLength());
cfLoad.Read(m_cbaPFM.GetData(), cfLoad.GetLength());
}
catch (CException *pce) {
pce -> ReportError();
pce -> Delete();
m_cbaPFM.RemoveAll();
return FALSE;
}
return TRUE;
}
/******************************************************************************
CFontInfo::GetTranslation
This loads a PFM format file and gets the default CTT ID from it. Nothing
else is done.
******************************************************************************/
extern "C" int ICttID2GttID(long lPredefinedCTTID);
BOOL CFontInfo::GetTranslation() {
// PFM file structures- these are declared at this level to keep them off
// the master class list for the project.
#pragma pack(1) // The following is byte-aligned
struct sPFMHeader {
WORD m_wType, m_wPoints, m_wVertRes, m_wHorizRes, m_wAscent,
m_wInternalLeading, m_wExternalLeading;
BYTE m_bfItalic, m_bfUnderline, m_bfStrikeOut;
WORD m_wWeight;
BYTE m_bCharSet;
WORD m_wPixWidth, m_wPixHeight;
BYTE m_bfPitchAndFamily;
WORD m_wAvgWidth, m_wMaxWidth;
BYTE m_bFirstChar, m_bLastChar, m_bDefaultChar, m_bBreakChar;
WORD m_wcbWidth;
DWORD m_dwDevice, m_dwFace, m_dwBitsPointer, m_dwofBits;
BYTE m_bReserved;
};
struct sPFMExtension {
WORD m_wcbRemaining; // From this point on
DWORD m_dwofExtMetrics, m_dwofExtentTable, m_dwofOriginTable,
m_dwofPairKernTable, m_dwofTrackKernTable, m_dwofDriverInfo,
m_dwReserved;
};
#pragma pack (2) // Everything else has word alignment
struct sOldKernPair {
union {
BYTE m_abEach[2];
WORD m_wBoth;
};
short m_sAmount;
};
struct sKernTrack {
short m_sDegree, m_sMinSize, m_sMinAmount, m_sMaxSize, m_sMaxAmount;
};
struct sPFMDriverInfo {
enum {CurrentVersion = 0x200};
enum {CannotItalicize = 1, CannotUnderline, SendCRAfterUsing = 4,
CannotMakeBold = 8, CannotDoubleUnderline = 0x10,
CannotStrikeThru = 0x20, BackspaceForPairs = 0x40};
WORD m_wcbThis, m_wVersion, m_wfCapabilities, m_widThis, m_wAdjustY,
m_wYMovement, m_widCTT, m_wUnderlinePosition,
m_wDoubleUnderlinePosition, m_wStrikeThruPosition;
DWORD m_dwofSelect, m_dwofDeselect;
WORD m_wPrivateData; /* Used in DeskJet driver for font enumerations */
short m_sShiftFromCenter;
enum {HPIntelliFont, TrueType, PPDSScalable, CapsL, OEMType1, OEMType2};
WORD m_wFontType;
};
#pragma pack() // We now return control to you
if (!MapPFM())
return FALSE;
// Now, map out the rest of the pieces of the structure.
union {
BYTE *pbPFM; // Base of the file for offsets!
sPFMHeader *pspfmh;
};
pbPFM = m_cbaPFM.GetData();
// Screen out evil files- part 1: is length sufficient?
unsigned uSize = sizeof (sPFMHeader) + sizeof (sPFMExtension) +
sizeof (sPFMDriverInfo);
if ((unsigned) m_cbaPFM.GetSize() < uSize)
return FALSE;
// YA Sanity check
if (pspfmh -> m_bLastChar < pspfmh -> m_bFirstChar)
return FALSE;
// Width table, if there is one.
WORD *pwWidth = pspfmh -> m_wPixWidth ? NULL : (PWORD) (pspfmh + 1);
uSize += !!pwWidth * sizeof (WORD) *
(2 + pspfmh -> m_bLastChar - pspfmh -> m_bFirstChar);
// Screen out evil files- part 2: is length still sufficient?
if ((unsigned) m_cbaPFM.GetSize() < uSize)
return FALSE;
// PFMExtension follows width table, otherwise the header
sPFMExtension *pspfme = pwWidth ? (sPFMExtension *)
(pwWidth + 2 + pspfmh -> m_bLastChar - pspfmh -> m_bFirstChar) :
(sPFMExtension *) (pspfmh + 1);
// Penultimate sanity check- is the driver info offset real?
if ((unsigned) m_cbaPFM.GetSize() <
pspfme -> m_dwofDriverInfo + sizeof (sPFMDriverInfo))
return FALSE;
// Text Metrics, DriverInfo and others are pointed at by PFM
// Extension.
sPFMDriverInfo *pspfmdi =
(sPFMDriverInfo *) (pbPFM + pspfme -> m_dwofDriverInfo);
// Final sanity check- is the driver info version real?
if (pspfmdi -> m_wVersion > sPFMDriverInfo::CurrentVersion)
return FALSE;
m_widTranslation = (WORD) ICttID2GttID((long) - (short) pspfmdi -> m_widCTT);
Changed();
return TRUE;
}
/******************************************************************************
CFontInfo::CalculateWidths()
This member function is needed whenever a change is made to a variable pitch
font's width table, or equally well, whenever an arbitrary table is picked up
by a formerly fixed pitch font. It calculates the width using the approved
algorithm (average means average of 26 lower-case plus the space, unless they
don't exist, in which case it is of all non-zero widths).
******************************************************************************/
void CFontInfo::CalculateWidths() {
// Assume the max width is now 0, then prove otherwise. Also collect the
// raw information needed to correctly calculate the average width.
m_wMaximumIncrement = 0;
unsigned uPointsToAverage = 0, uOverallWidth = 0, uAverageWidth = 0,
uZeroPoints = 0;
for (unsigned u = 0; u < (unsigned) m_cpaGlyphs.GetSize(); u++) {
WORD wWidth = m_cwaWidth[u];;
m_wMaximumIncrement = max(m_wMaximumIncrement, wWidth);
uOverallWidth += wWidth;
if (!wWidth) uZeroPoints++;
if (Glyph(u).CodePoint() == m_cwaSignificant[Break] ||
(Glyph(u).CodePoint() >= (WORD) 'a' &&
Glyph(u).CodePoint() <= (WORD) 'z')) {
uAverageWidth += wWidth;
uPointsToAverage++;
}
}
// If we averaged 27 points, then this is the correct width. Otherwise,
// We average all of the widths. cf the IFIMETRICS description in DDK
m_wAverageWidth = (uPointsToAverage == 27) ?
(WORD) (0.5 + ((double) uAverageWidth) / 27.0) :
(WORD) (0.5 + (((double) uOverallWidth) / (double) (u - uZeroPoints)));
}
/******************************************************************************
CFontInfo::CFontInfo()
This class constructor has a lot of work to do. Not only does it have to
initialize 5 zillion fields, it has to build the context menu list, and a few
other glorious items of that ilk.
******************************************************************************/
CFontInfo::CFontInfo() {
m_pcmdt = NULL;
m_pcgmTranslation = NULL;
m_pcfdBold = m_pcfdItalic = m_pcfdBoth = NULL;
m_cfn.SetExtension(_T(".UFM"));
m_bCharacterSet = m_bPitchAndFamily = 0;
m_wMaximumIncrement = m_wfStyle = m_wWeight = m_wAverageWidth =
m_wHeight = m_widTranslation = 0;
m_bLocation = m_bTechnology = m_bfGeneral = 0;
m_bScalable = FALSE;
m_wXResolution = m_wYResolution = m_wPrivateData = 0;
m_sPreAdjustY = m_sPostAdjustY = m_sCenterAdjustment = 0;
m_wMaxScale = m_wMinScale = m_wScaleDevice = 0;
m_bfScaleOrientation = 0;
m_cwaSpecial.InsertAt(0, 0, 1 + InternalLeading); // Initialize this array.
// Build the context menu control
m_cwaMenuID.Add(ID_OpenItem);
m_cwaMenuID.Add(ID_RenameItem);
m_cwaMenuID.Add(0);
m_cwaMenuID.Add(ID_ExpandBranch);
m_cwaMenuID.Add(ID_CollapseBranch);
m_cwaMenuID.Add(0);
m_cwaMenuID.Add(ID_GenerateOne);
}
/******************************************************************************
CFontInfo::CFontInfo(const CFontInfo& cfiRef, WORD widCTT)
This class constructor duplicates an existing font, but changes the CTT ID,
and generates a new name and file name accordingly
******************************************************************************/
CFontInfo::CFontInfo(const CFontInfo& cfiRef, WORD widCTT) {
m_pcmdt = cfiRef.m_pcmdt;
m_pcfdBold = m_pcfdItalic = m_pcfdBoth = NULL;
m_pcgmTranslation = NULL;
m_cfn.SetExtension(_T(".UFM"));
CString csWork;
// Copy the file name and generate new names
csWork.Format(_T("(CTT %d)"), (long) (short) widCTT);
m_cfn.Rename(cfiRef.m_cfn.Path() + cfiRef.Name() + csWork);
m_csSource = cfiRef.m_csSource;
Rename(cfiRef.Name() + csWork);
m_bCharacterSet = m_bPitchAndFamily = 0;
m_wMaximumIncrement = m_wfStyle = m_wWeight = m_wAverageWidth =
m_wHeight = 0;
m_bLocation = m_bTechnology = m_bfGeneral = 0;
m_bScalable = FALSE;
m_wXResolution = m_wYResolution = m_wPrivateData = 0;
m_sPreAdjustY = m_sPostAdjustY = m_sCenterAdjustment = 0;
m_wMaxScale = m_wMinScale = m_wScaleDevice = 0;
m_bfScaleOrientation = 0;
m_cwaSpecial.InsertAt(0, 0, 1 + InternalLeading); // Initialize this array.
m_widTranslation = widCTT;
// Build the context menu control
m_cwaMenuID.Copy(cfiRef.m_cwaMenuID);
}
CFontInfo::~CFontInfo() {
if (m_pcfdBold)
delete m_pcfdBold;
if (m_pcfdItalic)
delete m_pcfdItalic;
if (m_pcfdBoth)
delete m_pcfdBoth;
}
/******************************************************************************
CFontInfo::GTTDescription
This returns a CString naming the GTT associated with this font. It will
come from the workspace if the font is a resource, or the string table, if it
is predefined.
******************************************************************************/
CString CFontInfo::GTTDescription() const {
if (m_pcgmTranslation)
return m_pcgmTranslation -> Name();
CString csName;
if ((short) m_widTranslation <= 0)
csName.LoadString(IDS_DefaultPage + (short) m_widTranslation);
if (!csName.GetLength())
csName.Format(IDS_ResourceID, (short) m_widTranslation);
return csName;
}
/******************************************************************************
CFontInfo::InterceptItalic
This calculates where a line drawn at the italic slant angle would intercept
a rectangle the height of the ascender, and twice the maximum width of the
font. It is used to help draw the image of this line in the font editor.
******************************************************************************/
void CFontInfo::InterceptItalic(CPoint& cpt) const {
if (!m_cwaSpecial[ItalicAngle]) { // Nothing
cpt.x = 5;
cpt.y = 0;
return;
}
// First, assume we will hit the top- it's almost always true.
cpt.x = 5 + (long) (0.5 + tan(((double) m_cwaSpecial[ItalicAngle]) /
dConvert) * ((double) m_cwaSpecial[Baseline]));
if (cpt.x <= -5 + 2 * m_wMaximumIncrement) {
cpt.y = 0;
return;
}
// OK, assume the opposite
cpt.y = (long) (0.5 + tan(((double) (900 - m_cwaSpecial[ItalicAngle])) /
dConvert) * ((double) (-10 + 2 * m_wMaximumIncrement)));
cpt.x = -5 + 2 * m_wMaximumIncrement;
}
/******************************************************************************
CFontInfo::CompareWidths
This compares the character widths for two indices, and returns, Less, More,
or Equal, as need be. It is not const, because Glyph() is not, and I've
already got a bazillion member functions.
******************************************************************************/
unsigned CFontInfo::CompareWidths(unsigned u1, unsigned u2) {
_ASSERT(IsVariableWidth() && u1 < (unsigned) m_cpaGlyphs.GetSize() &&
u2 < (unsigned) m_cpaGlyphs.GetSize());
return (m_cwaWidth[u1] < m_cwaWidth[u2]) ? Less :
(m_cwaWidth[u1] > m_cwaWidth[u2]) ? More : Equal;
}
/******************************************************************************
CFontInfo::MapKerning
This maps out the available code points, and the kern pairs in both
directions, into a CWordArray and a pair of CSafeMapWordToObs (where the
underlying CObjects are CMapWordToDWords), respectively. This allows the
Add Kerning Pair dialog to screen out already defined pairs, and invalid code
points.
******************************************************************************/
void CFontInfo::MapKerning(CSafeMapWordToOb& csmw2o1,
CSafeMapWordToOb& csmw2o2,
CWordArray& cwaPoints) {
// If this isn't variable width, then we'll need to pull up some glyph
// data, temporarily.
BOOL bDispose = !IsVariableWidth();
if (bDispose)
m_pcgmTranslation -> Collect(m_cpaGlyphs);
for (unsigned u = 0; u < m_pcgmTranslation -> Glyphs(); u++)
if (!DBCSFont() || Glyph(u).CodePoint() < 0x80)
cwaPoints.Add(Glyph(u).CodePoint());
else
break;
if (bDispose)
m_cpaGlyphs.RemoveAll();
for (u = 0; u < m_csoaKern.GetSize(); u++) {
CKern& ck = *(CKern *) m_csoaKern[u];
union {
CObject *pco;
CMapWordToDWord *pcmw2d;
};
// Map first word to second
if (csmw2o1.Lookup(ck.First(), pco)) {
_ASSERT(!pcmw2d -> operator[](ck.Second()));
pcmw2d -> operator[](ck.Second()) = (DWORD) ck.Amount();
}
else {
CMapWordToDWord *pcmw2d = new CMapWordToDWord;
pcmw2d -> operator[](ck.Second()) = (DWORD) ck.Amount();
csmw2o1[ck.First()] = pcmw2d;
}
// Now the other direction
if (csmw2o2.Lookup(ck.Second(), pco)) {
_ASSERT(!pcmw2d -> operator[](ck.First()));
pcmw2d -> operator[](ck.First()) = (DWORD) ck.Amount();
}
else {
CMapWordToDWord *pcmw2d = new CMapWordToDWord;
pcmw2d -> operator[](ck.First()) = (DWORD) ck.Amount();
csmw2o2[ck.Second()] = pcmw2d;
}
}
}
/******************************************************************************
CFontInfo::CompareKernAmount
This is an editor sort helper- it tells how two kern amounts compare by
index.
******************************************************************************/
unsigned CFontInfo::CompareKernAmount(unsigned u1, unsigned u2) const {
CKern &ck1 = *(CKern *) m_csoaKern[u1], &ck2 = *(CKern *) m_csoaKern[u2];
return (ck1.Amount() < ck2.Amount()) ? Less :
(ck1.Amount() > ck2.Amount()) ? More : Equal;
}
/******************************************************************************
CFontInfo::CompareKernFirst
This is an editor sort helper- it tells how two kern first characters
compare by index.
******************************************************************************/
unsigned CFontInfo::CompareKernFirst(unsigned u1, unsigned u2) const {
CKern &ck1 = *(CKern *) m_csoaKern[u1], &ck2 = *(CKern *) m_csoaKern[u2];
return (ck1.First() < ck2.First()) ? Less :
(ck1.First() > ck2.First()) ? More : Equal;
}
/******************************************************************************
CFontInfo::CompareKernSecond
This is an editor sort helper- it tells how two kern second characters
compare by index.
******************************************************************************/
unsigned CFontInfo::CompareKernSecond(unsigned u1, unsigned u2) const {
CKern &ck1 = *(CKern *) m_csoaKern[u1], &ck2 = *(CKern *) m_csoaKern[u2];
return (ck1.Second() < ck2.Second()) ? Less :
(ck1.Second() > ck2.Second()) ? More : Equal;
}
/******************************************************************************
CFontInfo::SetSourceName
This takes and stores the source file name so we can load and convert later.
It also renames (or rather, sets the original name) the font data using the
base file name.
******************************************************************************/
void CFontInfo::SetSourceName(LPCTSTR lpstrNew) {
m_csSource = lpstrNew;
m_csName = m_csSource.Mid(m_csSource.ReverseFind(_T('\\')) + 1);
if (m_csName.Find(_T('.')) >= 0)
if (m_csName.Right(4).CompareNoCase(_T(".PFM"))) {
m_csName.SetAt(m_csName.Find(_T('.')), _T('_'));
CProjectNode::Rename(m_csName);
}
else
CProjectNode::Rename(m_csName.Left(m_csName.Find(_T('.'))));
else
CProjectNode::Rename(m_csName);
}
/******************************************************************************
CFontInfo::Generate
This member generates the font information in one of the supported forms. I
determine the desired form from the file's extension.
******************************************************************************/
BOOL ConvertPFMToIFI(LPCTSTR lpstrPFM, LPCTSTR lpstrIFI, LPCTSTR lpstrUniq);
extern "C" {
BOOL BConvertPFM(LPBYTE lpbPFM, DWORD dwCodePage, LPBYTE lpbGTT,
PWSTR pwstrUnique, LPCTSTR lpstrUFM, int iGTTID);
DWORD DwGetCodePage(LONG lPredefinedCTTId);
}
BOOL CFontInfo::Generate(CString csPath) {
CString csExtension = csPath.Right(4);
csExtension.MakeUpper();
if (csExtension == _T(".IFI"))
return ConvertPFMToIFI(m_csSource, csPath, m_csUnique);
if (csExtension == _T(".UFM")) {
if (!m_pcgmTranslation) {
CString csWork;
csWork.Format(IDS_BadCTTID, (LPCTSTR) m_csSource,
(long) (short) m_widTranslation);
AfxMessageBox(csWork);
return FALSE;
}
// Determine whether a GTT file or code page is to be used
DWORD dwCodePage = DwGetCodePage((LONG) - (short) m_widTranslation);
// Load the GTT file, if we need to. This handles predefined, as well
CByteArray cbaMap;
m_pcgmTranslation -> Load(cbaMap);
if (!cbaMap.GetSize())
return FALSE;
// Load the PFM file into memory (should already be there)
if (!MapPFM())
return FALSE; // Couldn't load PFM- impossible at this point!
// Convert the unique name string to Unicode
CByteArray cbaIn;
CWordArray cwaOut;
cbaIn.SetSize(1 + m_csUnique.GetLength());
lstrcpy((LPSTR) cbaIn.GetData(), (LPCTSTR) m_csUnique);
ccpi.Convert(cbaIn, cwaOut, GetACP());
// DO IT!
return BConvertPFM(m_cbaPFM.GetData(), dwCodePage, cbaMap.GetData(),
cwaOut.GetData(), FileName(), (short) m_widTranslation);
}
return TRUE;
}
/******************************************************************************
CFontInfo::AddFamily
This searches for the given name in the list of families, and adds it if it
is not there. It returns TRUE if it succeeded.
******************************************************************************/
BOOL CFontInfo::AddFamily(LPCTSTR lpstrNew) {
for (unsigned u = 0; u < Families(); u++)
if (!Family(u).CompareNoCase(lpstrNew))
break;
if (u < Families())
return FALSE; // Already have it!
try {
m_csaFamily.Add(lpstrNew);
}
catch (CException * pce) {
pce -> ReportError();
pce -> Delete();
return FALSE;
}
Changed();
return TRUE;
}
/******************************************************************************
CFontInfo::RemoveFamily
This function removes the given family name from the list of aliases. This
code is more robust than it needs to be- it'll remove duplicates, even though
the add code won't allow them to be added. No telling what the input data
looks like, though, is there?
******************************************************************************/
void CFontInfo::RemoveFamily(LPCTSTR lpstrDead) {
for (unsigned u = 0; u < Families(); u ++)
if (!Family(u).CompareNoCase(lpstrDead)) {
m_csaFamily.RemoveAt(u--); // Decrement so we don't miss one
Changed();
}
}
/*****************************************************************************
CFontInfo::ChangePitch
We exploit the fact that the widths are maintained in the CGlyphMap
(actually the CGlyphHandle) class. All this method need do for a variable
font flipping to fixed is to toss out the m_cpaGlyphs member's content. To
flip to variable, collect the handles, then check the first one's width- if
it's non-zero, then a previous transition from variable to fixed is being
undone, and we can recycle the old values, thus keeping any edits that may
have been lost. Otherwise, the trick code comes- the initial values get
filled- what's tricky is that for a DBCS character set, only the SBCS values
less than 0x80 can be variable.
******************************************************************************/
void CFontInfo::ChangePitch(BOOL bFixed) {
if (bFixed == !IsVariableWidth())
return; // Nothing to change!
if (bFixed) {
m_cpaGlyphs.RemoveAll(); // CPtrArray doesn't delete anything
m_wAverageWidth = DBCSFont() ? (1 + m_wMaximumIncrement) >> 1 :
m_wMaximumIncrement;
Changed();
return;
}
if (!m_pcgmTranslation) return; // Can't do this with no GTT available
m_pcgmTranslation -> Collect(m_cpaGlyphs);
if (!m_cwaWidth.GetSize())
m_cwaWidth.InsertAt(0, 0, m_cpaGlyphs.GetSize());
Changed(); // It sure has...
if (!m_cpaGlyphs.GetSize() || m_cwaWidth[0]) {
// Update the maximum and average width if this is not DBCS
if (!DBCSFont())
CalculateWidths();
return; // We did all that needed to be done
}
if (!DBCSFont()) {
for (int i = 0; i < m_cpaGlyphs.GetSize(); i++)
m_cwaWidth[i] = m_wMaximumIncrement;
return;
}
for (int i = 0; i < m_cpaGlyphs.GetSize() && Glyph(i).CodePoint() < 0x80;)
m_cwaWidth[i++] = m_wAverageWidth; // In DBCS, this is always it
}
/*****************************************************************************
CFontInfo::SetScalability
This is called to turn scalability on or off. All that really needs to be
done is to establish values for the maximum and minimum scale, the font ->
device units mapping members, and the lowercase ascender /descender, if this
is the first time this information has changed.
******************************************************************************/
void CFontInfo::SetScalability(BOOL bOn) {
if (IsScalable() == !!bOn)
return; // Nothing to change
if (!bOn) {
m_bScalable = FALSE;
Changed();
return;
}
m_bScalable = TRUE;
Changed();
if (m_wMaxScale && m_wMinScale && m_wMaxScale != m_wMinScale)
return; // We've already got data.
m_wMaxScale = m_wMinScale = m_wScaleDevice =
m_wHeight - m_cwaSpecial[InternalLeading];
// Flaky, but set the initial max and min to +- 1 point from nominal
m_wMaxScale += m_wYResolution / 72;
m_wMinScale -= m_wYResolution / 72;
// Finally, set the lowercase ascender and descender to simple defaults
m_cwaSpecial[Lowerd] = m_cwaSpecial[Baseline] -
m_cwaSpecial[InternalLeading];
m_cwaSpecial[Lowerp] = m_wHeight - m_cwaSpecial[Baseline];
}
/*****************************************************************************
CFontInfo::SetSpecial
This adjusts anything that may need adjusting if a special metric is
altered.
******************************************************************************/
void CFontInfo::SetSpecial(unsigned ufMetric, short sSpecial) {
if (m_cwaSpecial[ufMetric] == (WORD) sSpecial)
return; // Nothing changed
m_cwaSpecial[ufMetric] = (WORD) sSpecial;
switch (ufMetric) {
case InternalLeading:
// Adjust the scaling factors if need be
if (m_wScaleDevice > m_wHeight - sSpecial)
m_wScaleDevice = m_wHeight - sSpecial;
if (m_wMinScale > m_wHeight - sSpecial)
m_wMinScale = m_wHeight - sSpecial;
}
Changed();
}
/*****************************************************************************
CFontInfo::SetMaxWidth
This is not as simple as it might seem. If the font is variable, don't do
it. If it is not, then if it is DBCS, set the average width to 1/2 the new
maximum. Otherwise, set it also to the maximum.
******************************************************************************/
void CFontInfo::SetMaxWidth(WORD wWidth) {
if (IsVariableWidth()) return;
if (wWidth == m_wMaximumIncrement) return; // Nothing to do!
m_wMaximumIncrement = wWidth;
m_wAverageWidth = DBCSFont() ? (wWidth + 1) >> 1 : wWidth;
Changed();
}
/*****************************************************************************
CFontInfo::SetHeight
This member checks to see if the new height is non-zero and new. If so, it
uses it for the new height, then adjusts all of the possibly affected
special metrics so they continue to meet the constraints.
******************************************************************************/
BOOL CFontInfo::SetHeight(WORD wHeight) {
if (!wHeight || wHeight == m_wHeight)
return FALSE;
m_wHeight = wHeight;
short sBaseline = (short) (min(wHeight, m_cwaSpecial[Baseline]));
for (unsigned u = 0; u <= InternalLeading; u++) {
switch (u) {
case InterlineGap:
if (m_cwaSpecial[u] > 2 * wHeight)
m_cwaSpecial[u] = 2 * wHeight;
continue;
case UnderOffset:
case SubMoveY:
case Lowerd:
if ((short) m_cwaSpecial[u] < sBaseline - wHeight)
m_cwaSpecial[u] = sBaseline - wHeight;
continue;
case UnderSize:
if (m_cwaSpecial[u] > wHeight - (unsigned) sBaseline)
m_cwaSpecial[u] = wHeight = (unsigned) sBaseline;
if (!m_cwaSpecial[u])
m_cwaSpecial[u] = 1;
continue;
case SuperSizeX:
case SubSizeX:
case SuperMoveX:
case SubMoveX:
case ItalicAngle:
continue; // These aren't affected
default:
if (m_cwaSpecial[u] > (unsigned) sBaseline)
m_cwaSpecial[u] = sBaseline;
}
}
// Adjust the scaling factors if need be
if (m_wScaleDevice > m_wHeight - m_cwaSpecial[InternalLeading])
m_wScaleDevice = m_wHeight - m_cwaSpecial[InternalLeading];
if (m_wMinScale > m_wHeight - m_cwaSpecial[InternalLeading])
m_wMinScale = m_wHeight - m_cwaSpecial[InternalLeading];
Changed();
return TRUE;
}
/*****************************************************************************
CFontInfo::SetCharacterSet
This one is a bit tricky- the new character set must be compatible with the
GTT file associated with this font. So we need to check it before we pass
on it.
ASSUMPTIONS:
(1) Things are bulletproof enough that the existing character set will
already pass this test.
******************************************************************************/
BOOL CFontInfo::SetCharacterSet(BYTE bNew) {
unsigned u;
switch (bNew) {
case SHIFTJIS_CHARSET:
for (u = 0; u < m_pcgmTranslation -> CodePages(); u++)
if (m_pcgmTranslation -> PageID(u) == 932)
break; // We're OK
if (u == m_pcgmTranslation -> CodePages())
return FALSE;
break;
case HANGEUL_CHARSET:
for (u = 0; u < m_pcgmTranslation -> CodePages(); u++)
if (m_pcgmTranslation -> PageID(u) == 949)
break; // We're OK
if (u == m_pcgmTranslation -> CodePages())
return FALSE;
break;
case CHINESEBIG5_CHARSET:
for (u = 0; u < m_pcgmTranslation -> CodePages(); u++)
if (m_pcgmTranslation -> PageID(u) == 950)
break; // We're OK
if (u == m_pcgmTranslation -> CodePages())
return FALSE;
break;
case GB2312_CHARSET:
for (u = 0; u < m_pcgmTranslation -> CodePages(); u++)
if (m_pcgmTranslation -> PageID(u) == 936)
break; // We're OK
if (u == m_pcgmTranslation -> CodePages())
return FALSE;
break;
default:
// Don't accept any DBCS codepages
for (u = 0; u < m_pcgmTranslation -> CodePages(); u++)
switch (m_pcgmTranslation -> PageID(u)) {
case 932:
case 936:
case 949:
case 950:
case 1361: // Johab- but it isn't in the converter!
return FALSE;
}
}
if (m_bCharacterSet != bNew) {
m_bCharacterSet = bNew;
Changed();
}
return TRUE;
}
/******************************************************************************
CFontInfo::SetSignificant
This member is called to change the value of one of the significant code
points (break character or default) encoded in the font. Doing this
correctly means getting the ANSI and UNICODE versions of the code point, and
discarding any out-of-range values.
This function returns an encoded value indicating success or cause of
failure.
******************************************************************************/
WORD CFontInfo::SetSignificant(WORD wItem, WORD wChar, BOOL bUnicode) {
_ASSERT(wItem > Last && wItem <= Break);
if (!bUnicode && wChar > 255)
return DoubleByte;
CWaitCursor cwc; // Unfortunately, if not Unicode, htis is slow
CPtrArray cpaGlyphs;
CWordArray cwa;
CByteArray cba;
CDWordArray cdaPage;
m_pcgmTranslation -> Collect(cpaGlyphs);
m_pcgmTranslation -> CodePages(cdaPage);
for (int i = 0; i < cpaGlyphs.GetSize(); i++) {
CGlyphHandle& cgh = *(CGlyphHandle *) cpaGlyphs[i];
if (bUnicode) {
if (cgh.CodePoint() == wChar) {
cwa.Add(wChar);
ccpi.Convert(cba, cwa, cdaPage[cgh.CodePage()]);
break;
}
}
else {
if (i)
cwa.SetAt(0, cgh.CodePoint());
else
cwa.Add(cgh.CodePoint());
ccpi.Convert(cba, cwa, cdaPage[cgh.CodePage()]);
if (cba.GetSize() == 1 && cba[0] == (BYTE) wChar)
break;
cba.RemoveAll(); // So we can try again
}
}
if (i == cpaGlyphs.GetSize())
return InvalidChar;
if (cba.GetSize() != 1)
return DoubleByte;
// OK, we passed all of the hurdles
if (m_cwaSignificant[wItem] == cwa[0])
return OK; // Nothing changed!!!!
m_cwaSignificant[wItem] = cwa[0];
m_cbaSignificant[wItem] = cba[0];
Changed();
return OK;
}
/******************************************************************************
CFontInfo::SetScaleLimit
This member receives a proposed new maximum or minimum font size in device
units. First, it is compared to the existing size, for a quick exit. Then
we check to see that the ordering of the limits and the nominal size is
preserved. If it is not, we describe the problem and leave. Otherwise, we
update the value, and note that the font information has changed.
******************************************************************************/
WORD CFontInfo::SetScaleLimit(BOOL bMax, WORD wNew) {
if (wNew == (bMax ? m_wMaxScale : m_wMinScale))
return ScaleOK;
if (bMax ? wNew <= m_wMinScale : wNew >= m_wMaxScale)
return Reversed;
if (bMax ? wNew < m_wScaleDevice : wNew > m_wScaleDevice)
return NotWindowed;
if (bMax)
m_wMaxScale = wNew;
else
m_wMinScale = wNew;
Changed();
return ScaleOK;
}
/******************************************************************************
CFontInfo::SetDeviceEmHeight
This member sets the units used for determing the conversion from font units
(in which all metrics are given) to device units. The checking is similar to
that above, except here, we need to make sure that the font units are always
of equal or greater resolution than the device units.
******************************************************************************/
WORD CFontInfo::SetDeviceEmHeight(WORD wNew) {
if (wNew == m_wScaleDevice)
return ScaleOK;
if (wNew > m_wHeight - m_cwaSpecial[InternalLeading])
return Reversed;
if (wNew < m_wMinScale || wNew > m_wMaxScale)
return NotWindowed;
m_wScaleDevice = wNew;
Changed();
return ScaleOK;
}
/******************************************************************************
CFontInfo::Load
This member function loads the UFM file, finally initializing all of the
tons of individual values we're trying to pretend we know how to manage
here.
******************************************************************************/
// These flags have a negative sense, but the UI makes more sense if they
// are positive, so their sense is inverted using the following constant
#define FLIP_FLAGS (DF_NOITALIC | DF_NOUNDER | DF_NO_BOLD |\
DF_NO_DOUBLE_UNDERLINE | DF_NO_STRIKETHRU)
BOOL CFontInfo::Load() {
CFile cfUFM;
if (!cfUFM.Open(m_cfn.FullName(),
CFile::modeRead | CFile::shareDenyWrite)) {
CString csMessage;
csMessage.Format(IDS_LoadFailure, (LPCTSTR) m_cfn.FullName());
AfxMessageBox(csMessage);
return FALSE;
}
// Try to load the file- proclaim defeat on any exception.
CByteArray cbaUFM;
try {
cbaUFM.SetSize(cfUFM.GetLength());
cfUFM.Read(cbaUFM.GetData(), cbaUFM.GetSize());
}
catch (CException *pce) {
pce -> ReportError();
pce -> Delete();
CString csMessage;
csMessage.Format(IDS_LoadFailure, (LPCTSTR) m_cfn.FullName());
AfxMessageBox(csMessage);
return FALSE;
}
// First thing in the file is the header.
PUNIFM_HDR pufmh = (PUNIFM_HDR) cbaUFM.GetData();
// pull up the GTT ID
m_widTranslation = (WORD) pufmh -> lGlyphSetDataRCID;
// Find the UNIDRVINFO
PUNIDRVINFO pudi =
(PUNIDRVINFO) (cbaUFM.GetData() + pufmh -> loUnidrvInfo);
// Fill in the two invocation strings- why it is the offset is NULL
// and the count is garbage when there is none is beyond me, but so be it.
if (pudi -> SelectFont.dwofCommand)
m_ciSelect.Init((PBYTE) pudi + pudi -> SelectFont.dwofCommand,
pudi -> SelectFont.dwcbCommand);
if (pudi -> UnSelectFont.dwofCommand)
m_ciDeselect.Init((PBYTE) pudi + pudi -> UnSelectFont.dwofCommand,
pudi -> UnSelectFont.dwcbCommand);
// Initialize the files of interest from the UNIDRVINFO
m_bScalable = (pudi -> flGenFlags & UFM_SCALABLE);
m_bTechnology = (BYTE) pudi -> wType;
if (pudi -> flGenFlags & UFM_SOFT)
m_bLocation = Download;
else
if (pudi -> flGenFlags & UFM_CART_MAIN)
m_bLocation = MainCartridge;
else
if (pudi -> flGenFlags & UFM_CART)
m_bLocation = Cartridge;
m_wXResolution = pudi -> wXRes;
m_wYResolution = pudi -> wYRes;
m_wPrivateData = pudi -> wPrivateData;
m_sPreAdjustY = pudi -> sYAdjust;
m_sPostAdjustY = pudi -> sYMoved;
m_sCenterAdjustment = pudi -> sShift;
m_bfGeneral = (BYTE) pudi -> fCaps ^ FLIP_FLAGS;
// Time to bite the IFIMETRICS bullet
union {
PBYTE pbIFI;
PIFIMETRICS pifi;
};
pbIFI = cbaUFM.GetData() + pufmh -> loIFIMetrics;
// Get the special metrics loaded first
m_cwaSpecial[CapH] = pifi -> fwdCapHeight;
m_cwaSpecial[LowerX] = pifi -> fwdXHeight;
m_cwaSpecial[SuperMoveX] = pifi -> fwdSuperscriptXOffset;
m_cwaSpecial[SuperMoveY] = pifi -> fwdSuperscriptYOffset;
m_cwaSpecial[SubMoveX] = pifi -> fwdSubscriptXOffset;
m_cwaSpecial[SubMoveY] = pifi -> fwdSubscriptYOffset;
m_cwaSpecial[SuperSizeX] = pifi -> fwdSuperscriptXSize;
m_cwaSpecial[SuperSizeY] = pifi -> fwdSuperscriptYSize;
m_cwaSpecial[SubSizeX] = pifi -> fwdSubscriptXSize;
m_cwaSpecial[SubSizeY] = pifi -> fwdSubscriptYSize;
m_cwaSpecial[UnderOffset] = pifi -> fwdUnderscorePosition;
m_cwaSpecial[UnderSize] = pifi -> fwdUnderscoreSize;
m_cwaSpecial[StrikeOffset] = pifi -> fwdStrikeoutPosition;
m_cwaSpecial[StrikeSize] = pifi -> fwdStrikeoutSize;
m_cwaSpecial[ItalicAngle] = (WORD) (dConvert *
atan2((double) pifi -> ptlCaret.x, (double) pifi -> ptlCaret.y));
m_cwaSpecial[Baseline] = pifi -> fwdWinAscender;
m_cwaSpecial[InterlineGap] = pifi -> fwdMacLineGap;
// Now, see if there is an EXTTEXTMETRIC- if so, fill in some fields from
// it.
PEXTTEXTMETRIC petm = (PEXTTEXTMETRIC) (pufmh -> loExtTextMetric ?
(cbaUFM.GetData() + pufmh -> loExtTextMetric) : NULL);
if (petm) {
m_wMinScale = petm -> emMinScale;
m_wMaxScale = petm -> emMaxScale;
// Scads of special metrics- double underlining will not be preserved.
m_cwaSpecial[Lowerd] = petm -> emLowerCaseAscent;
m_cwaSpecial[Lowerp] = petm -> emLowerCaseDescent;
m_cwaSpecial[ItalicAngle] = petm -> emSlant;
// Orientation, Master Units (Font units are calculated)
m_bfScaleOrientation = (BYTE) petm -> emOrientation;
m_wScaleDevice = petm -> emMasterHeight;
}
// Let's get the rest of the IFIMETRICS stuff, now.
m_cbaSignificant.SetSize(1 + Break);
m_cwaSignificant.SetSize(1 + Break);
m_cbaSignificant[Break] = pifi -> chBreakChar;
m_bCharacterSet = pifi -> jWinCharSet;
m_cbaSignificant[Default] = pifi -> chDefaultChar;
m_cbaSignificant[First] = pifi -> chFirstChar;
m_cbaSignificant[Last] = pifi -> chLastChar;
m_bPitchAndFamily = pifi -> jWinPitchAndFamily;
m_wAverageWidth = pifi -> fwdAveCharWidth;
m_cwaSignificant[Break] = pifi -> wcBreakChar;
m_cwaSignificant[Default] = pifi -> wcDefaultChar;
m_cwaSignificant[First] = pifi -> wcFirstChar;
m_cwaSignificant[Last] = pifi -> wcLastChar;
m_wMaximumIncrement = pifi -> fwdMaxCharInc;
m_wWeight = pifi -> usWinWeight;
m_wHeight = pifi -> fwdWinAscender + pifi -> fwdWinDescender;
m_cwaSpecial[InternalLeading] = m_wHeight - pifi -> fwdUnitsPerEm;
m_wfStyle = pifi -> fsSelection;
// Get the face and other name strings. Let CString handle the
// Unicode conversions for us,
m_csUnique = (PWSTR) (pbIFI + pifi -> dpwszUniqueName);
m_csStyle = (PWSTR) (pbIFI + pifi -> dpwszStyleName);
m_csFace = (PWSTR) (pbIFI + pifi -> dpwszFaceName);
m_csaFamily.RemoveAll(); // Just in case it isn't clean
PWSTR pwstrFamily = (PWSTR) (pbIFI + pifi -> dpwszFamilyName);
CString csWork(pwstrFamily);
m_csaFamily.Add(csWork);
pwstrFamily += 1 + wcslen(pwstrFamily);
if (pifi -> flInfo & FM_INFO_FAMILY_EQUIV)
while (*pwstrFamily) {
csWork = pwstrFamily;
m_csaFamily.Add(csWork);
pwstrFamily += 1 + wcslen(pwstrFamily);
}
// Font Difference structures, if any.
if (pifi -> dpFontSim) {
union {
PBYTE pbfs;
FONTSIM *pfs;
};
pbfs = pbIFI + pifi -> dpFontSim;
// If we're reloading, clean these up!
if (m_pcfdBold)
delete m_pcfdBold;
if (m_pcfdItalic)
delete m_pcfdItalic;
if (m_pcfdBoth)
delete m_pcfdBoth;
// Bold simulation
if (pfs -> dpBold)
m_pcfdBold = new CFontDifference(pbfs + pfs -> dpBold, this);
// Italic Simulation
if (pfs -> dpItalic)
m_pcfdItalic = new CFontDifference(pbfs + pfs -> dpItalic, this);
// Bold Italic Simulation
if (pfs -> dpBoldItalic)
m_pcfdBoth = new CFontDifference(pbfs + pfs -> dpBoldItalic, this);
}
// Width table, but only if there is an associated GTT.
if (m_pcgmTranslation && pufmh -> loWidthTable) {
union {
PBYTE pbwt;
PWIDTHTABLE pwt;
};
pbwt = cbaUFM.GetData() + pufmh -> loWidthTable;
m_pcgmTranslation -> Collect(m_cpaGlyphs); // Collect all the handles
m_cwaWidth.RemoveAll();
m_cwaWidth.InsertAt(0, 0, m_cpaGlyphs.GetSize());
for (unsigned u = 0; u < pwt -> dwRunNum; u++) {
PWORD pwWidth =
(PWORD) (pbwt + pwt -> WidthRun[u].loCharWidthOffset);
for (unsigned uGlyph = 0;
uGlyph < pwt -> WidthRun[u].wGlyphCount;
uGlyph++)
// Glyph handles start at 1, not 0!
m_cwaWidth[uGlyph + -1 + pwt -> WidthRun[u].wStartGlyph] =
*pwWidth++;
}
}
// Kerning Table, if any
m_csoaKern.RemoveAll();
if (pufmh -> loKernPair) {
PKERNDATA pkd = (PKERNDATA) (cbaUFM.GetData() + pufmh -> loKernPair);
for (unsigned u = 0; u < pkd -> dwKernPairNum; u++)
m_csoaKern.Add(new CKern(pkd -> KernPair[u]));
}
// Return triumphant to whoever deigned to need this service.
return TRUE;
}
/*****************************************************************************
CUniString class
This is a little helper class that will convert a CString to a UNICODE
string, and take care of cleanup, etc., so the font storage code doesn't get
any messier than it already will be.
******************************************************************************/
class CUniString : public CWordArray {
public:
CUniString(LPCSTR lpstrInit);
operator PCWSTR() const { return GetData(); }
unsigned GetSize() const {
return sizeof (WCHAR) * (unsigned) CWordArray::GetSize();
}
void Write(CFile& cf) {
cf.Write(GetData(), GetSize());
}
};
CUniString::CUniString(LPCSTR lpstrInit) {
SetSize(MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpstrInit, -1, NULL,
0));
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpstrInit, -1, GetData(),
GetSize());
}
/*****************************************************************************
CFontInfo::Store
This member function stores the UFM format information in the specified file
by assembling it from the information we have cached in this class.
******************************************************************************/
BOOL CFontInfo::Store(LPCTSTR lpstrFile) {
try { // Any exxceptions, we'll just fail gracelessly
CFile cfUFM(lpstrFile,
CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive);
// First thing in the file is the header.
UNIFM_HDR ufmh = {sizeof ufmh, UNIFM_VERSION_1_0, 0,
(short) m_widTranslation, sizeof ufmh};
// Use Glyph Map default code page if at all possible.
ufmh.ulDefaultCodepage = m_pcgmTranslation -> DefaultCodePage();
// Zero fill reserved bytes.
memset((PBYTE) ufmh.dwReserved, 0, sizeof ufmh.dwReserved);
// Next is the UNIDRVINFO
UNIDRVINFO udi = {sizeof udi};
// Invocation Strings affect the size, so get their specifics and
// save them, updating the affected size fields as we go.
udi.SelectFont.dwofCommand = m_ciSelect.Length() ? udi.dwSize : 0;
udi.dwSize += udi.SelectFont.dwcbCommand = m_ciSelect.Length();
udi.UnSelectFont.dwofCommand = m_ciDeselect.Length() ? udi.dwSize : 0;
udi.dwSize += udi.UnSelectFont.dwcbCommand = m_ciDeselect.Length();
// Pad this to keep everything DWORD aligned in the file image!
unsigned uAdjustUDI = (sizeof udi.dwSize -
(udi.dwSize % sizeof udi.dwSize)) % sizeof udi.dwSize;
ufmh.loIFIMetrics = ufmh.dwSize += udi.dwSize += uAdjustUDI;
// Initialize the UNIDRVINFO
switch (m_bLocation) {
case Download:
udi.flGenFlags = UFM_SOFT;
break;
case MainCartridge:
udi.flGenFlags = UFM_CART | UFM_CART_MAIN;
break;
case Cartridge:
udi.flGenFlags = UFM_CART;
break;
default: // Resident;
udi.flGenFlags = 0;
}
if (m_bScalable)
udi.flGenFlags |= UFM_SCALABLE;
udi.wType = m_bTechnology;
udi.wXRes = m_wXResolution;
udi.wYRes = m_wYResolution;
udi.wPrivateData = m_wPrivateData;
udi.sYAdjust = m_sPreAdjustY;
udi.sYMoved = m_sPostAdjustY;
udi.sShift = m_sCenterAdjustment;
udi.fCaps = m_bfGeneral ^ FLIP_FLAGS;
memset((PSTR) udi.wReserved, 0, sizeof udi.wReserved);
// Time to bite the IFIMETRICS bullet
IFIEXTRA ifie = {0, 0, m_pcgmTranslation -> Glyphs(), 0, 0, 0};
IFIMETRICS ifi = {sizeof ifi + sizeof ifie, sizeof ifie};
ifi.lEmbedId = ifi.lItalicAngle = ifi.lCharBias = 0;
ifi.dpCharSets = 0;
ifi.jWinCharSet = m_bCharacterSet;
m_bPitchAndFamily = (m_bPitchAndFamily & 0xF0) |
(IsVariableWidth() ? VARIABLE_PITCH : FIXED_PITCH);
ifi.jWinPitchAndFamily = m_bPitchAndFamily;
ifi.usWinWeight = m_wWeight;
ifi.flInfo = FM_INFO_TECH_BITMAP | FM_INFO_1BPP |
FM_INFO_INTEGER_WIDTH | FM_INFO_NOT_CONTIGUOUS |
FM_INFO_RIGHT_HANDED;
if (DBCSFont())
ifi.flInfo |= FM_INFO_DBCS_FIXED_PITCH;
if (!IsVariableWidth()) {
ifi.flInfo |= FM_INFO_OPTICALLY_FIXED_PITCH;
if (!DBCSFont()) // DBCS is never constant width
ifi.flInfo |= FM_INFO_CONSTANT_WIDTH;
}
if (m_bScalable)
ifi.flInfo |= FM_INFO_ISOTROPIC_SCALING_ONLY;
ifi.fsType = FM_NO_EMBEDDING;
ifi.fwdLowestPPEm = 1;
ifi.fwdUnitsPerEm = m_wHeight - m_cwaSpecial[InternalLeading];
ifi.fwdCapHeight = m_cwaSpecial[CapH];
ifi.fwdSuperscriptXOffset = m_cwaSpecial[SuperMoveX];
ifi.fwdSubscriptXOffset = m_cwaSpecial[SubMoveX];
ifi.fwdSuperscriptXSize = m_cwaSpecial[SuperSizeX];
ifi.fwdSubscriptXSize = m_cwaSpecial[SubSizeX];
ifi.ptlCaret.x = m_cwaSpecial[ItalicAngle] ? (long)
((double) 10000.0 *
tan(((double) m_cwaSpecial[ItalicAngle]) / dConvert)) : 0;
ifi.ptlCaret.y = m_cwaSpecial[ItalicAngle] ? 10000 : 1;
ifi.fwdTypoAscender = ifi.fwdMacAscender = ifi.fwdWinAscender =
m_cwaSpecial[Baseline];
ifi.fwdTypoDescender = ifi.fwdMacDescender = -(ifi.fwdWinDescender =
m_wHeight - ifi.fwdWinAscender);
ifi.fwdTypoLineGap = ifi.fwdMacLineGap = m_cwaSpecial[InterlineGap];
ifi.fwdXHeight = m_cwaSpecial[LowerX];
ifi.fwdSuperscriptYOffset = m_cwaSpecial[SuperMoveY];
ifi.fwdSubscriptYOffset = m_cwaSpecial[SubMoveY];
ifi.fwdSuperscriptYSize = m_cwaSpecial[SuperSizeY];
ifi.fwdSubscriptYSize = m_cwaSpecial[SubSizeY];
ifi.fwdUnderscorePosition = m_cwaSpecial[UnderOffset];
ifi.fwdUnderscoreSize = m_cwaSpecial[UnderSize];
ifi.fwdStrikeoutPosition = m_cwaSpecial[StrikeOffset];
ifi.fwdStrikeoutSize = m_cwaSpecial[StrikeSize];
ifi.fwdAveCharWidth = m_wAverageWidth;
ifi.fwdMaxCharInc = m_wMaximumIncrement;
ifi.fsSelection = m_wfStyle;
ifi.wcBreakChar = m_cwaSignificant[Break];
ifi.wcDefaultChar = m_cwaSignificant[Default];
ifi.chBreakChar = m_cbaSignificant[Break];
ifi.chDefaultChar = m_cbaSignificant[Default];
ifi.chFirstChar = m_cbaSignificant[First];
ifi.chLastChar = m_cbaSignificant[Last];
ifi.wcFirstChar = m_cwaSignificant[First];
ifi.wcLastChar = m_cwaSignificant[Last];
ifi.ptlBaseline.x = 1;
ifi.ptlBaseline.y = 0;
ifi.ptlAspect.x = udi.wXRes;
ifi.ptlAspect.y = udi.wYRes;
memcpy(ifi.achVendId, "Unkn", 4);
ifi.cKerningPairs = m_csoaKern.GetSize();
ifi.rclFontBox.left = 0;
ifi.rclFontBox.top = ifi.fwdWinAscender;
ifi.rclFontBox.right = ifi.fwdMaxCharInc;
ifi.rclFontBox.bottom = ifi.fwdMacDescender;
ifi.ulPanoseCulture = FM_PANOSE_CULTURE_LATIN;
ifi.panose.bWeight = (m_wWeight >= FW_BOLD) ? PAN_WEIGHT_BOLD :
(m_wWeight > FW_EXTRALIGHT) ? PAN_WEIGHT_MEDIUM : PAN_WEIGHT_LIGHT;
ifi.panose.bFamilyType = ifi.panose.bSerifStyle =
ifi.panose.bProportion = ifi.panose.bContrast =
ifi.panose.bStrokeVariation = ifi.panose.bArmStyle =
ifi.panose.bLetterform = ifi.panose.bMidline =
ifi.panose.bXHeight = PAN_ANY;
// Convert and "place" the various name strings
CUniString cusUnique(m_csUnique), cusStyle(m_csStyle),
cusFace(m_csFace), cusFamily(m_csaFamily[0]);
ifi.dpwszFamilyName = ifi.cjThis;
for (int i = 1; i < m_csaFamily.GetSize(); i++) {
CUniString cusWork(m_csaFamily[i]);
cusFamily.Append(cusWork);
}
if (m_csaFamily.GetSize() > 1) {
cusFamily.Add(0);
ifi.flInfo |= FM_INFO_FAMILY_EQUIV;
}
ifi.cjThis += cusFamily.GetSize();
ifi.dpwszFaceName = ifi.cjThis;
ifi.cjThis += cusFace.GetSize();
ifi.dpwszUniqueName = ifi.cjThis;
ifi.cjThis += cusUnique.GetSize();
ifi.dpwszStyleName = ifi.cjThis;
ifi.cjThis += cusStyle.GetSize();
// The next field must be DWORD aligned, so see what padding
// is needed.
unsigned uAdjustIFI = (sizeof ifi.cjThis -
(ifi.cjThis % sizeof ifi.cjThis)) % sizeof ifi.cjThis;
ifi.cjThis += uAdjustIFI;
// Finally, Allow for the size of any Font Difference structures.
unsigned uSim = !!m_pcfdBold + !!m_pcfdItalic + !!m_pcfdBoth;
ifi.dpFontSim = uSim ? ifi.cjThis : 0;
ufmh.dwSize += ifi.cjThis += uSim * sizeof(FONTDIFF) +
!!uSim * sizeof(FONTSIM);
// Now, see if there is an EXTTEXTMETRIC- if so, fill it in.
ufmh.loExtTextMetric = m_bScalable ? ufmh.dwSize : 0;
EXTTEXTMETRIC etm;
if (m_bScalable) {
ufmh.dwSize += etm.emSize = sizeof etm;
etm.emPointSize = (short)((DWORD)((DWORD) m_wScaleDevice * 1440) /
(DWORD) m_wXResolution); // Use DWORD for precision
etm.emOrientation = m_bfScaleOrientation;
etm.emMasterHeight = m_wScaleDevice;
etm.emMinScale = m_wMinScale;
etm.emMaxScale = m_wMaxScale;
etm.emMasterUnits = m_wHeight - m_cwaSpecial[InternalLeading];
etm.emKernPairs = m_csoaKern.GetSize();
etm.emKernTracks = 0;
// Scads of special metrics
etm.emCapHeight = m_cwaSpecial[CapH];
etm.emXHeight = m_cwaSpecial[LowerX];
etm.emSuperScript = m_cwaSpecial[SuperMoveY];
etm.emSubScript = m_cwaSpecial[SubMoveY];
etm.emSuperScriptSize = m_cwaSpecial[SuperSizeY];
etm.emSubScriptSize = m_cwaSpecial[SubSizeY];
etm.emUnderlineOffset = m_cwaSpecial[UnderOffset];
etm.emUnderlineWidth = m_cwaSpecial[UnderSize];
etm.emStrikeOutOffset = m_cwaSpecial[StrikeOffset];
etm.emStrikeOutWidth = m_cwaSpecial[StrikeSize];
etm.emDoubleUpperUnderlineOffset = // Not supported- zero them
etm.emDoubleLowerUnderlineOffset =
etm.emDoubleUpperUnderlineWidth =
etm.emDoubleLowerUnderlineWidth = 0;
etm.emLowerCaseAscent = m_cwaSpecial[Lowerd];
etm.emLowerCaseDescent = m_cwaSpecial[Lowerp];
etm.emSlant = m_cwaSpecial[ItalicAngle];
}
// Width table, but only if there is an associated GTT.
ufmh.loWidthTable = IsVariableWidth() * ufmh.dwSize;
if (IsVariableWidth()) {
// For now, we just need to calculate the size of the table
unsigned uRuns = 0, uGlyphs = 0;
if (DBCSFont()) { //DBCS
// Determine the number of runs needed
unsigned u = (unsigned) m_cpaGlyphs.GetSize();
do {
while (u-- && !m_cwaWidth[u]); // DBCS has 0 width
if (u == (unsigned) -1)
break; // We're done!
uRuns++, uGlyphs++;
while (u-- && m_cwaWidth[u])
uGlyphs++;
}
while (u != (unsigned) -1);
}
else {
uRuns++;
uGlyphs = m_cwaWidth.GetSize();
}
ufmh.dwSize += sizeof (WIDTHTABLE) + --uRuns * sizeof (WIDTHRUN) +
uGlyphs * sizeof (WORD);
}
// Kerning Table, if any
ufmh.loKernPair = CanKern() ? ufmh.dwSize : 0;
//`A "secret" kern pair of all 0's must end this, so this size
// is in fact correct. Also note that padding screws up the size of
// the KERNDATA structure, so the
if (CanKern())
ufmh.dwSize +=
((sizeof (KERNDATA) - sizeof (FD_KERNINGPAIR)) & 0xFFFC) +
((1 + m_csoaKern.GetSize()) * sizeof (FD_KERNINGPAIR));
// All sizes have been calculated, and the important structures have
// been initialized. Time to start writing all this great stuff!
// Header
cfUFM.Write(&ufmh, sizeof ufmh);
// UNIDRVINFO
cfUFM.Write(&udi, sizeof udi);
m_ciSelect.WriteEncoding(cfUFM);
m_ciDeselect.WriteEncoding(cfUFM);
cfUFM.Write(ufmh.dwReserved, uAdjustUDI); // Padding
// IFIMETRICS, IFIEXTRA, and names, follwed by any padding
cfUFM.Write(&ifi, sizeof ifi);
cfUFM.Write(&ifie, sizeof ifie);
cusFamily.Write(cfUFM);
cusFace.Write(cfUFM);
cusUnique.Write(cfUFM);
cusStyle.Write(cfUFM);
cfUFM.Write(ufmh.dwReserved, uAdjustIFI); // PAdding
// Any Font difference structures
if (m_pcfdBold || m_pcfdItalic || m_pcfdBoth) {
FONTSIM fs;
unsigned uWhere = sizeof fs;
fs.dpBold = m_pcfdBold ? uWhere : 0;
uWhere += !!m_pcfdBold * sizeof (FONTDIFF);
fs.dpItalic = m_pcfdItalic ? uWhere : 0;
uWhere += !!m_pcfdItalic * sizeof (FONTDIFF);
fs.dpBoldItalic = m_pcfdBoth ? uWhere : 0;
cfUFM.Write(&fs, sizeof fs);
if (m_pcfdBold)
m_pcfdBold -> Store(cfUFM, m_wfStyle | FM_SEL_BOLD);
if (m_pcfdItalic)
m_pcfdItalic -> Store(cfUFM, m_wfStyle | FM_SEL_ITALIC);
if (m_pcfdBoth)
m_pcfdBoth -> Store(cfUFM,
m_wfStyle | FM_SEL_BOLD| FM_SEL_ITALIC);
}
// EXTTEXTMETRIC
if (m_bScalable)
cfUFM.Write(&etm, sizeof etm);
// Width table
if (IsVariableWidth())
if (!DBCSFont()) {
// Not DBCS- easy! (Handles always start at 1
WIDTHTABLE wdt = { sizeof wdt, 1,
{1, m_cpaGlyphs.GetSize(), sizeof wdt}};
cfUFM.Write(&wdt, sizeof wdt);
cfUFM.Write(m_cwaWidth.GetData(),
m_cwaWidth.GetSize() * sizeof (WORD));
}
else { // This case is a bit nastier
CByteArray cbaTable;
CWordArray cwaSize;
cbaTable.SetSize(sizeof(WIDTHTABLE) - sizeof(WIDTHRUN));
PWIDTHTABLE pwdt = (PWIDTHTABLE) cbaTable.GetData();
pwdt -> dwRunNum = 0;
// Calculate and fill in the WIDTHRUN structures and the
// Size array
unsigned u = 0, uMax = (unsigned) m_cpaGlyphs.GetSize();
do {
while (u < uMax && !m_cwaWidth[u++]);
if (u == uMax)
break; // We're done!
// We've found a run- lots of work to do
cbaTable.InsertAt(cbaTable.GetSize(), 0,
sizeof (WIDTHRUN)); // Add a run to the table
pwdt = (PWIDTHTABLE) cbaTable.GetData();
// Remember the glyph handle is 1-based.
pwdt -> WidthRun[pwdt -> dwRunNum].wStartGlyph = --u + 1;
pwdt -> WidthRun[pwdt -> dwRunNum].wGlyphCount = 0;
pwdt -> WidthRun[pwdt -> dwRunNum].loCharWidthOffset =
cwaSize.GetSize() * sizeof (WORD);
do {
cwaSize.Add(m_cwaWidth[u]);
pwdt -> WidthRun[pwdt -> dwRunNum].wGlyphCount++;
}
while (++u < uMax && m_cwaWidth[u]);
pwdt -> dwRunNum++; // End of the run!
}
while (u < uMax);
// OK, now we have to add the total size of the WIDTHTABLE
// to the various offsets, but we are otherwise ready to rock
// and roll.
pwdt -> dwSize = cbaTable.GetSize();
for (u = 0; u < pwdt -> dwRunNum; u++)
pwdt -> WidthRun[u].loCharWidthOffset += pwdt -> dwSize;
// At last- time to send 'em packing!
cfUFM.Write(pwdt, pwdt -> dwSize);
for (u = 0; u < pwdt -> dwRunNum; u++)
cfUFM.Write(cwaSize.GetData() +
pwdt -> WidthRun[u].wStartGlyph - 1,
pwdt -> WidthRun[u].wGlyphCount * sizeof (WORD));
}
// Kern Pairs
if (CanKern()) {
// KERNDATA is DWORD-packed, but FD_KERNINGPAIR is WORD-packed
// the following trick code allows for any slop.
KERNDATA kd = {0xFFFC & (sizeof kd - sizeof kd.KernPair),
m_csoaKern.GetSize()};
kd.dwSize += (1 + kd.dwKernPairNum) * sizeof kd.KernPair;
cfUFM.Write(&kd, 0xFFFC & (sizeof kd - sizeof kd.KernPair));
for (unsigned u = 0; u < m_csoaKern.GetSize(); u++)
((CKern *) m_csoaKern[u]) -> Store(cfUFM);
// Now for the "secret" sentinel-
CKern ck; // Just happens to 0-init!
ck.Store(cfUFM);
}
}
catch (CException *pce) {
pce -> ReportError();
pce -> Delete();
return FALSE;
}
// Return triumphant to whoever deigned to need this service.
Changed(FALSE);
return TRUE;
}
/*****************************************************************************
CFontInfo::CreateEditor
This member function launches an editing view for the font.
******************************************************************************/
CMDIChildWnd* CFontInfo::CreateEditor() {
CFontInfoContainer* pcficMe= new CFontInfoContainer(this, FileName());
// Make up a cool title
pcficMe -> SetTitle(m_pcbnWorkspace -> Name() + _TEXT(": ") + Name());
CMDIChildWnd *pcmcwNew = (CMDIChildWnd *) m_pcmdt ->
CreateNewFrame(pcficMe, NULL);
if (pcmcwNew) {
m_pcmdt -> InitialUpdateFrame(pcmcwNew, pcficMe, TRUE);
m_pcmdt -> AddDocument(pcficMe);
}
return pcmcwNew;
}
/******************************************************************************
CFontInfo::Serialize
This is responsible for storing and restoring the entire maze of data in
persistent object storage.
******************************************************************************/
void CFontInfo::Serialize(CArchive& car) {
// We only serialize what's needed to use the UFM file in the editor,
// i.e., the glue needed to hold us in the driver workspace.
CProjectNode::Serialize(car);
}
/******************************************************************************
CFontInfo::EnableSim
This method is called to turn simulation on or off for the specified item.
It receives a reference to the editor's pointer for the same item.
******************************************************************************/
void CFontInfo::EnableSim(unsigned uSim, BOOL bOn, CFontDifference*& pcfd) {
CFontDifference*& pcfdTarget =
uSim ? (uSim == BothDiff) ? m_pcfdBoth : m_pcfdBold : m_pcfdItalic;
// Clear out any irrelevant calls
if (bOn == !!pcfd && pcfdTarget == pcfd)
return;
// If this call is just to init pcfd, do it and leave
if (bOn && pcfdTarget) {
pcfd = pcfdTarget;
return;
}
if (bOn)
pcfd = pcfdTarget = pcfd ? pcfd : new CFontDifference(m_wWeight,
m_wMaximumIncrement, m_wAverageWidth,
uSim == BoldDiff ? m_cwaSpecial[ItalicAngle] : 175,
this);
else
pcfdTarget = NULL; // pcfd will already have been set correctly
Changed();
}
/******************************************************************************
CFontInfo::FillKern
This preps the passed CListCtrl, if necessary, and fills it with the kerning
information.
******************************************************************************/
void CFontInfo::FillKern(CListCtrl& clcView) {
for (unsigned u = 0; u < m_csoaKern.GetSize(); u++) {
CString csWork;
CKern& ckThis = *(CKern *) m_csoaKern[u];
csWork.Format("%d", ckThis.Amount());
int idItem = clcView.InsertItem(u, csWork);
clcView.SetItemData(idItem, u);
csWork.Format("0x%X", ckThis.First());
clcView.SetItem(idItem, 1, LVIF_TEXT, csWork, -1, 0, 0, u);
csWork.Format("0x%X", ckThis.Second());
clcView.SetItem(idItem, 2, LVIF_TEXT, csWork, -1, 0, 0, u);
}
}
/******************************************************************************
CFontInfo::AddKern
This method adds an additional kerning pair into the array. and also inserts
it into the list view.
******************************************************************************/
void CFontInfo::AddKern(WORD wFirst, WORD wSecond, short sAmount,
CListCtrl& clcView) {
for (unsigned u = 0; u < KernCount(); u ++) {
CKern& ckThis = *(CKern *) m_csoaKern[u];
if (ckThis.Second() < wSecond)
continue;
if (ckThis.Second() > wSecond)
break;
_ASSERT(ckThis.First() != wFirst);
if (ckThis.First() < wFirst)
continue;
break;
}
FD_KERNINGPAIR fdkp = { wFirst, wSecond, sAmount };
m_csoaKern.InsertAt(u, new CKern(fdkp));
CString csWork;
csWork.Format("%d", sAmount);
int idItem = clcView.InsertItem(u, csWork);
clcView.SetItemData(idItem, u);
csWork.Format("0x%X", wFirst);
clcView.SetItem(idItem, 1, LVIF_TEXT, csWork, -1, 0, 0, u);
csWork.Format("0x%X", wSecond);
clcView.SetItem(idItem, 2, LVIF_TEXT, csWork, -1, 0, 0, u);
Changed();
}
/******************************************************************************
CFontInfo::SetKernAmount
This will change the kern amount entry for the specified item.
******************************************************************************/
void CFontInfo::SetKernAmount(unsigned u, short sAmount) {
if (u >= KernCount()) return;
CKern &ckThis = *(CKern *) m_csoaKern[u];
if (sAmount == ckThis.Amount()) return;
ckThis.SetAmount(sAmount);
Changed();
}
/******************************************************************************
CFontInfo::FillWidths
This preps the passed CListCtrl, if necessary, and fills it with the
character width information.
******************************************************************************/
void CFontInfo::FillWidths(CListCtrl& clcView) {
CWaitCursor cwc;
clcView.SetItemCount(m_cpaGlyphs.GetSize());
for (int u = 0; u < m_cpaGlyphs.GetSize(); u++) {
if (DBCSFont() && !m_cwaWidth[u])
continue; // Don't display these code points.
CString csWork;
CGlyphHandle& cghThis = *(CGlyphHandle *) m_cpaGlyphs[u];
csWork.Format("%d", m_cwaWidth[u]);
int idItem = clcView.InsertItem(u, csWork);
clcView.SetItemData(idItem, u);
csWork.Format("0x%X", cghThis.CodePoint());
clcView.SetItem(idItem, 1, LVIF_TEXT, csWork, -1, 0, 0, u);
}
}
/******************************************************************************
CFontInfo::SetWidth
This member sets the width of a glyph. It also updates the Maximum and
Average width information if the font is not a DBCS font.
******************************************************************************/
void CFontInfo::SetWidth(unsigned uGlyph, WORD wWidth) {
m_cwaWidth[uGlyph] = wWidth;
if (!DBCSFont())
CalculateWidths();
}
/******************************************************************************
CFontInfoContainer class
This class encapsulates one CFontInfo structure, and is used as a document
class so we can leverage the MFC document/view architecture for editing this
information both within the contet of the driver, and as a stand-alone file.
******************************************************************************/
IMPLEMENT_DYNCREATE(CFontInfoContainer, CDocument)
/******************************************************************************
CFontInfoContainer::CFontInfoContainer()
This constructor is used when the document is dynamically created- this will
be when the user opens an existing font file, or creates a new one.
******************************************************************************/
CFontInfoContainer::CFontInfoContainer() {
m_bEmbedded = FALSE;
m_pcfi = new CFontInfo;
m_pcfi -> NoteOwner(*this);
}
/******************************************************************************
CFontInfoContainer::CFontInfoContainer(CFontInfo *pcfi, CString csPath) {
This constructor is called when we invoke an editing view from the driver
editor. It gives us the font information to view and the name of the file
to generate if the user decies to save the data from this view.
******************************************************************************/
CFontInfoContainer::CFontInfoContainer(CFontInfo *pcfi, CString csPath) {
m_pcfi = pcfi;
m_bEmbedded = TRUE;
SetPathName(csPath, FALSE);
m_pcfi -> NoteOwner(*this); // Even when embedded, we're editing a file.
}
/******************************************************************************
CFontInfo::OnNewDocument
This is an override- it is called when we are asked to create new font
information from scratch. For now, this will just fail.
******************************************************************************/
BOOL CFontInfoContainer::OnNewDocument() {
AfxMessageBox(IDS_Unimplemented);
return FALSE;
// return m_pcfi && CDocument::OnNewDocument();
}
/******************************************************************************
CFontInfo::~CFontInfo
Our erstwhile destructor must destroy the font info if this wasn't an
embedded view.
******************************************************************************/
CFontInfoContainer::~CFontInfoContainer() {
if (!m_bEmbedded && m_pcfi)
delete m_pcfi;
}
BEGIN_MESSAGE_MAP(CFontInfoContainer, CDocument)
//{{AFX_MSG_MAP(CFontInfoContainer)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFontInfoContainer diagnostics
#ifdef _DEBUG
void CFontInfoContainer::AssertValid() const {
CDocument::AssertValid();
}
void CFontInfoContainer::Dump(CDumpContext& dc) const {
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CFontInfoContainer serialization
void CFontInfoContainer::Serialize(CArchive& ar) {
if (ar.IsStoring()) {
// TODO: add storing code here
}
else {
// TODO: add loading code here
}
}
/////////////////////////////////////////////////////////////////////////////
// CFontInfoContainer commands
/******************************************************************************
CFontInfoContainer::OnSaveDocument
This is called in response to a Save or Save As. We pass it directly to the
CFontInfo for processing, rather than using the base class implementation,
which would serialize the document.
******************************************************************************/
BOOL CFontInfoContainer::OnSaveDocument(LPCTSTR lpszPathName) {
return m_pcfi -> Store(lpszPathName);
}
/******************************************************************************
CFontInfoContainer::OnOpenDocument
For now, I can not allow this to be done, as no GTT file is available.
******************************************************************************/
BOOL CFontInfoContainer::OnOpenDocument(LPCTSTR lpstrFile) {
/*m_pcfi -> SetFileName(lpstrFile);
return m_pcfi -> Load();*/
return FALSE;
}