You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3574 lines
129 KiB
3574 lines
129 KiB
/******************************************************************************
|
|
|
|
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 [email protected] Began work on this monster
|
|
02-01-1998 [email protected] aka Rick Mallonee rewrote nearly the whole thing.
|
|
|
|
******************************************************************************/
|
|
|
|
#include "StdAfx.H"
|
|
#include <gpdparse.h>
|
|
#include "MiniDev.H"
|
|
#include "utility.h"
|
|
#include "FontInfo.H"
|
|
#include "ChildFrm.H" // Definition of Tool Tips Property Page class
|
|
#include "comctrls.h"
|
|
#include "FontView.H"
|
|
#include <uni16res.h>
|
|
#include "rcfile.h"
|
|
#include "ProjRec.H"
|
|
|
|
static const double gdConvertRadToDegree = 900.0 / atan2(1.0, 0.0); // A handy constant for converting radians to 10's of a degree
|
|
static CCodePageInformation* pccpi = NULL ; // Use a static CCodePageInformation to derive more benefit from caching
|
|
|
|
/******************************************************************************
|
|
|
|
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; }
|
|
CKern(WCHAR wcf, WCHAR wcs, short sa) {
|
|
m_fdkp.wcFirst = wcf ;
|
|
m_fdkp.wcSecond = wcs ;
|
|
m_fdkp.fwdKern = sa ;
|
|
}
|
|
|
|
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 SetAll(WCHAR wcf, WCHAR wcs, short sa) {
|
|
m_fdkp.wcFirst = wcf ;
|
|
m_fdkp.wcSecond = wcs ;
|
|
m_fdkp.fwdKern = sa ;
|
|
}
|
|
|
|
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, CBasicNode *pcbn)
|
|
{
|
|
FONTDIFF *pfd = (FONTDIFF *) pb;
|
|
m_pcbnOwner = pcbn;
|
|
|
|
m_cwaMetrics.Add(pfd -> usWinWeight);
|
|
m_cwaMetrics.Add(pfd -> fwdMaxCharInc);
|
|
m_cwaMetrics.Add(pfd -> fwdAveCharWidth);
|
|
|
|
// NOTE: The conversion done in this statement is reversed in a statement
|
|
// in the CFontDifference::Store() routine. For whatever reason,
|
|
// this two steps can repeatedly reduce the user supplied value by
|
|
// 1. To prevent this, 1 is added back in the following statement.
|
|
|
|
m_cwaMetrics.Add((WORD) (gdConvertRadToDegree *
|
|
atan2((double) pfd -> ptlCaret.x, (double) pfd -> ptlCaret.y)) + 1);
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
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;
|
|
|
|
/* Verification isn't needed and removing it solves other problems in the
|
|
UFM Editor.
|
|
|
|
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: if (wNew > 899) return TooBig; // Angle
|
|
}
|
|
*/
|
|
gdConvertRadToDegree;
|
|
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;
|
|
|
|
if(gdConvertRadToDegree) // raid 116588 Prefix :: constant value;
|
|
fd.ptlCaret.x = !m_cwaMetrics[Angle] ? 0 :
|
|
(long) (10000.0 * tan(((double) m_cwaMetrics[Angle]) / gdConvertRadToDegree));
|
|
|
|
fd.ptlCaret.y = m_cwaMetrics[Angle] ? 10000 : 1;
|
|
|
|
cf.Write(&fd, sizeof fd);
|
|
}
|
|
|
|
/******************************************************************************
|
|
And now, for the hardest working class in show business (and a personal friend
|
|
of mine):
|
|
|
|
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);
|
|
|
|
int CFontInfo::GetTranslation(CSafeObArray& csoagtts)
|
|
{
|
|
// 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 -IDS_FileReadError ;
|
|
|
|
// 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 -IDS_PFMTooSmall ;
|
|
|
|
// YA Sanity check
|
|
|
|
if (pspfmh -> m_bLastChar < pspfmh -> m_bFirstChar)
|
|
return -IDS_PFMCharError ;
|
|
|
|
// 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 -IDS_PFMTooSmall ;
|
|
|
|
// 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 -IDS_BadPFMInfoOffset ;
|
|
|
|
// 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 -IDS_BadPFMInfoVersion ;
|
|
|
|
// See if the original CTT ID needs to be converted to a new codepage
|
|
// number. If not, leave it alone. In any case, set the font's GTT ID.
|
|
|
|
//TRACE("GetTrans: UFM = %s CTT ID = %d GTT ID = %d\n", Name(), pspfmdi -> m_widCTT, ICttID2GttID((long) (short) pspfmdi -> m_widCTT)) ;
|
|
// m_widTranslation = (WORD) ICttID2GttID((long) (short) pspfmdi -> m_widCTT); // rm ori
|
|
m_lGlyphSetDataRCID = (WORD) ICttID2GttID((long) (short) pspfmdi -> m_widCTT); // rm new
|
|
|
|
|
|
if (!m_lGlyphSetDataRCID) { // Raid 135623
|
|
|
|
switch (pspfmh ->m_bCharSet) {
|
|
case SHIFTJIS_CHARSET:
|
|
m_lGlyphSetDataRCID = -17;
|
|
break;
|
|
case GB2312_CHARSET:
|
|
m_lGlyphSetDataRCID = -16;
|
|
break;
|
|
case HANGEUL_CHARSET:
|
|
case JOHAB_CHARSET:
|
|
m_lGlyphSetDataRCID = -18;
|
|
break;
|
|
case CHINESEBIG5_CHARSET:
|
|
m_lGlyphSetDataRCID = -10;
|
|
break;
|
|
} ;
|
|
} ;
|
|
// GTTs will be renumbered when the new, W2K RC file is written. Because of
|
|
// this, the GTT ID set above needs to be translated to the new number. This
|
|
// number corresponds to the GTT's position in GlyphTable. NOTE: The ID is
|
|
// not changed if it is <= 0. (The IDs in the GlyphMaps will be changed in
|
|
// CDriverResources::LoadFontData().)
|
|
|
|
if (m_lGlyphSetDataRCID > 0 && m_lGlyphSetDataRCID == pspfmdi->m_widCTT) {
|
|
for (unsigned uGTT = 0; uGTT < csoagtts.GetSize(); uGTT++)
|
|
if (m_lGlyphSetDataRCID
|
|
== ((LONG) ((CGlyphMap *) csoagtts[uGTT])->nGetRCID()))
|
|
m_lGlyphSetDataRCID = uGTT + 1 ;
|
|
} ;
|
|
|
|
Changed();
|
|
return 0 ;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
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()
|
|
{
|
|
// m_wMaximumIncrement = 0; // Assume max width is 0, then prove otherwise. Also collect the
|
|
// raw information needed to correctly calculate the average width.
|
|
|
|
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_IFIMETRICS.fwdMaxCharInc = max(m_IFIMETRICS.fwdMaxCharInc, wWidth); // rm new
|
|
// m_wMaximumIncrement = max(m_wMaximumIncrement, wWidth); // rm ori
|
|
|
|
uOverallWidth += wWidth;
|
|
if (!wWidth) uZeroPoints++;
|
|
// if (Glyph(u).CodePoint() == m_cwaSignificant[Break] || // rm ori
|
|
if (Glyph(u).CodePoint() == m_IFIMETRICS.wcBreakChar || // rm new
|
|
(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_IFIMETRICS.fwdAveCharWidth = (uPointsToAverage == 27) ? // rm new
|
|
|
|
// m_wAverageWidth = (uPointsToAverage == 27) ? // rm ori
|
|
(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_fEXTTEXTMETRIC = FALSE; // rm new
|
|
|
|
m_pcmdt = NULL;
|
|
m_pcgmTranslation = NULL;
|
|
m_pcfdBold = m_pcfdItalic = m_pcfdBoth = NULL;
|
|
m_cfn.SetExtension(_T(".UFM"));
|
|
m_ulDefaultCodepage = 0 ;
|
|
m_bRCIDChanged = 0 ; // raid 0003
|
|
|
|
// m_bCharacterSet = m_bPitchAndFamily = 0; // rm no longer needed
|
|
|
|
// m_wMaximumIncrement = m_wfStyle = m_wWeight = m_wAverageWidth = // rm ori
|
|
// m_wHeight = m_widTranslation = 0; // rm ori
|
|
m_wHeight = 0;
|
|
m_lGlyphSetDataRCID = 0; // rm new
|
|
|
|
// m_bLocation = m_bTechnology = m_bfGeneral = 0; // rm ori
|
|
// m_wType = m_fCaps = 0; // rm no longer needed
|
|
// m_bScalable = FALSE; // rm no longer needed
|
|
|
|
// m_wXResolution = m_wYResolution = m_wPrivateData = 0; // rm ori
|
|
// m_sPreAdjustY = m_sPostAdjustY = m_sCenterAdjustment = 0; // rm ori
|
|
|
|
// m_wXRes = m_wYRes = m_wPrivateData = 0; // rm no longer needed
|
|
// m_sYAdjust = m_sYMoved = m_sCenterAdjustment = 0; // rm no longer needed
|
|
|
|
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_CopyItem);
|
|
m_cwaMenuID.Add(ID_RenameItem);
|
|
m_cwaMenuID.Add(ID_DeleteItem);
|
|
m_cwaMenuID.Add(0);
|
|
m_cwaMenuID.Add(ID_ExpandBranch);
|
|
m_cwaMenuID.Add(ID_CollapseBranch);
|
|
|
|
// Allocate a CCodePageInformation class if needed.
|
|
|
|
if (pccpi == NULL)
|
|
pccpi = new CCodePageInformation ;
|
|
|
|
// Assume the font is NOT being loaded from a workspace.
|
|
|
|
m_bLoadedByWorkspace = false ;
|
|
|
|
// Assume that a GTT/CP will be found for the UFM.
|
|
|
|
m_bWSLoadButNoGTTCP = false ;
|
|
|
|
// Another method is used for now.
|
|
//
|
|
// // Assume there is no width table offset and that the font not variable
|
|
// // pitch. These variables are both used to determine if this is a variable
|
|
// // pitch font.
|
|
//
|
|
// m_loWidthTable = 0 ;
|
|
// m_IFIMETRICS.jWinPitchAndFamily = 0 ;
|
|
|
|
m_ctReloadWidthsTimeStamp = (time_t) 0 ; // Widths never reloaded
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
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) // r31
|
|
{
|
|
|
|
m_fEXTTEXTMETRIC = FALSE; // rm new
|
|
|
|
m_pcmdt = cfiRef.m_pcmdt;
|
|
m_pcfdBold = m_pcfdItalic = m_pcfdBoth = NULL;
|
|
m_pcgmTranslation = NULL;
|
|
m_cfn.SetExtension(_T(".UFM"));
|
|
CString csWork;
|
|
|
|
// Generate what will hopefully be a unique file name for the UFM
|
|
|
|
ReTitle(cfiRef.Name()) ;
|
|
m_cfn.UniqueName(true, true, cfiRef.m_cfn.Path()) ;
|
|
//m_cfn.Rename(cfiRef.m_cfn.Path() + cfiRef.Name() + csWork);
|
|
|
|
// Generate a new display name for the UFM using the CTT number
|
|
|
|
csWork.Format(_T("(CTT %d)"), (long)(short)widCTT); // r 31
|
|
m_csSource = cfiRef.m_csSource;
|
|
Rename(cfiRef.Name() + csWork);
|
|
|
|
// m_bCharacterSet = m_bPitchAndFamily = 0; // rm no longer needed
|
|
|
|
// m_wMaximumIncrement = m_wfStyle = m_wWeight = m_wAverageWidth = // rm ori
|
|
m_wHeight = 0;
|
|
|
|
// m_bLocation = m_bTechnology = m_bfGeneral = 0; // rm ori
|
|
// m_wType = m_fCaps = 0; // rm no longer needed
|
|
// m_bScalable = FALSE; // rm no longer needed
|
|
|
|
// m_wXResolution = m_wYResolution = m_wPrivateData = 0; // rm ori
|
|
// m_sPreAdjustY = m_sPostAdjustY = m_sCenterAdjustment = 0; // rm ori
|
|
|
|
// m_wXRes = m_wYRes = m_wPrivateData = 0; // rm no longer needed
|
|
// m_sYAdjust = m_sYMoved = m_sCenterAdjustment = 0; // rm no longer needed
|
|
|
|
m_wMaxScale = m_wMinScale = m_wScaleDevice = 0;
|
|
// m_bfScaleOrientation = 0;
|
|
|
|
m_cwaSpecial.InsertAt(0, 0, 1 + InternalLeading); // Initialize this array.
|
|
|
|
// m_widTranslation = widCTT; // rm ori
|
|
m_lGlyphSetDataRCID = widCTT; // rm new
|
|
// Build the context menu control
|
|
m_cwaMenuID.Copy(cfiRef.m_cwaMenuID);
|
|
|
|
// Allocate a CCodePageInformation class if needed.
|
|
|
|
if (pccpi == NULL)
|
|
pccpi = new CCodePageInformation ;
|
|
|
|
// Assume the font is NOT being loaded from a workspace.
|
|
|
|
m_bLoadedByWorkspace = false ;
|
|
|
|
// Assume that a GTT/CP will be found for the UFM.
|
|
|
|
m_bWSLoadButNoGTTCP = false ;
|
|
|
|
m_ctReloadWidthsTimeStamp = (time_t) 0 ; // Widths never reloaded
|
|
}
|
|
|
|
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) // rm ori
|
|
if ((short) m_lGlyphSetDataRCID <= 0) // r31 re visit // rm new
|
|
// csName.LoadString(IDS_DefaultPage + (short) m_widTranslation); // rm ori
|
|
csName.LoadString(IDS_DefaultPage + (short) m_lGlyphSetDataRCID); // rm new
|
|
|
|
if (!csName.GetLength())
|
|
// csName.Format(IDS_ResourceID, (short) m_widTranslation); // rm ori
|
|
csName.Format(IDS_ResourceID, (short) m_lGlyphSetDataRCID); // rm new
|
|
|
|
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]) /
|
|
gdConvertRadToDegree) * ((double) m_IFIMETRICS.fwdWinAscender); // rm new
|
|
// gdConvertRadToDegree) * ((double) m _cwaSpecial[Baseline])); rm ori
|
|
|
|
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])) /
|
|
gdConvertRadToDegree) * ((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 suck up some glyph
|
|
// data, temporarily.
|
|
|
|
BOOL bDispose = !IsVariableWidth();
|
|
|
|
if (bDispose)
|
|
m_pcgmTranslation -> Collect(m_cpaGlyphs);
|
|
|
|
unsigned rm = m_pcgmTranslation->Glyphs(); // rm
|
|
|
|
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::GetKernFirst
|
|
|
|
Return the kerning pairs' first character.
|
|
|
|
******************************************************************************/
|
|
|
|
WCHAR CFontInfo::GetKernFirst(unsigned u) const
|
|
{
|
|
CKern &ck = *(CKern *) m_csoaKern[u] ;
|
|
|
|
return (ck.First()) ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfo::GetKernSecond
|
|
|
|
Return the kerning pairs' second character.
|
|
|
|
******************************************************************************/
|
|
|
|
WCHAR CFontInfo::GetKernSecond(unsigned u) const
|
|
{
|
|
CKern &ck = *(CKern *) m_csoaKern[u] ;
|
|
return (ck.Second()) ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfo::GetKernAmount
|
|
|
|
Return the kerning pairs' kerning amount.
|
|
|
|
******************************************************************************/
|
|
|
|
short CFontInfo::GetKernAmount(unsigned u) const
|
|
{
|
|
CKern &ck = *(CKern *) m_csoaKern[u] ;
|
|
return (ck.Amount()) ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfo::SetSourceName
|
|
|
|
This takes and stores the source file name so we can load and convert later.
|
|
This takes and stores the name for the project node for this UFM. It begins
|
|
with the PFM file name. If the extension is PFM, it is used. Otherwise, the
|
|
dot in the file name is changed to an underscore and the whole thing is used.
|
|
|
|
******************************************************************************/
|
|
|
|
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::SetFileName
|
|
|
|
This sets the new file name. It is done differently than in SetSourceName()
|
|
because the base file name must not be more than 8 characters long. (The
|
|
extra info is left in the node name by SetSourceName() because it is useful
|
|
there and it has no length limit.)
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CFontInfo::SetFileName(LPCTSTR lpstrNew)
|
|
{
|
|
CString csnew ; // CString version of input parameter
|
|
|
|
csnew = lpstrNew ;
|
|
|
|
// If the input filespec contains an extension, remove it and pass the
|
|
// resulting string to the file node's rename routine. Otherwise, just
|
|
// pass the original string to the rename routine.
|
|
//
|
|
// This check is complicated by the fact that one of the path components
|
|
// might have a dot in it too. We need to check for the last dot and make
|
|
// sure it comes before a path separator.
|
|
|
|
if (csnew.ReverseFind(_T('.')) > csnew.ReverseFind(_T('\\')))
|
|
return m_cfn.Rename(csnew.Left(csnew.ReverseFind(_T('.')))) ;
|
|
else
|
|
return m_cfn.Rename(csnew) ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
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 DwGetCodePageFromGTTID(LONG lPredefinedCTTId);
|
|
}
|
|
|
|
int 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); // rm ori
|
|
//csWork.Format(IDS_BadCTTID, (LPCTSTR) m_csSource, (long) (short) m_lGlyphSetDataRCID); // rm new
|
|
|
|
|
|
//AfxMessageBox(csWork);
|
|
return IDS_BadCTTID;
|
|
}
|
|
|
|
// Determine whether a GTT file or code page is to be used
|
|
// DWORD dwCodePage = DwGetCodePageFromCTTID((LONG) - (short) m_widTranslation); // rm ori
|
|
DWORD dwCodePage = DwGetCodePageFromGTTID((LONG) - (short) m_lGlyphSetDataRCID); // r 31 // rm new
|
|
|
|
// Load the GTT file, if we need to. This handles predefined, as well
|
|
|
|
CByteArray cbaMap;
|
|
|
|
m_pcgmTranslation -> Load(cbaMap);
|
|
|
|
if (!cbaMap.GetSize())
|
|
return IDS_UFMGenError ;
|
|
|
|
// Load the PFM file into memory (should already be there)
|
|
|
|
if (!MapPFM())
|
|
return IDS_UFMGenError ; // 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());
|
|
if (!SUCCEEDED(StringCchCopyA((LPSTR) cbaIn.GetData(), cbaIn.GetSize(), (LPCTSTR) m_csUnique)))
|
|
{
|
|
return IDS_UFMGenError;
|
|
}
|
|
|
|
pccpi->Convert(cbaIn, cwaOut, GetACP());
|
|
|
|
// DO IT!
|
|
|
|
//TRACE("%s UFM has CP = %d and RCID = %d\n", Name(), dwCodePage, m_lGlyphSetDataRCID) ;
|
|
|
|
// If both the code page and GTT ID are 0, set the code page to 1252.
|
|
|
|
if (dwCodePage == 0 && m_lGlyphSetDataRCID == 0)
|
|
dwCodePage = 1252 ;
|
|
|
|
//TRACE("*** GTT Pointer = %d\n", cbaMap.GetData()) ;
|
|
ASSERT(cbaMap.GetData()) ;
|
|
BOOL brc = BConvertPFM(m_cbaPFM.GetData(), dwCodePage, cbaMap.GetData(),
|
|
// cwaOut.GetData(), FileName(), (short) m_widTranslation); // rm ori
|
|
cwaOut.GetData(), FileName(), (short) m_lGlyphSetDataRCID); //r 31 short -> INT // rm new
|
|
return ((brc) ? 0 : IDS_UFMGenError) ;
|
|
|
|
// return BConvertPFM(m_cbaPFM.GetData(), dwCodePage, cbaMap.GetData(),
|
|
//// cwaOut.GetData(), FileName(), (short) m_widTranslation); // rm ori
|
|
// cwaOut.GetData(), FileName(), (short) m_lGlyphSetDataRCID); // rm new
|
|
}
|
|
return 0 ;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
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_IFIMETRICS.fwdAveCharWidth = DBCSFont() ? (1 + m_IFIMETRICS.fwdMaxCharInc) >> 1 : m_IFIMETRICS.fwdMaxCharInc; // rm new
|
|
|
|
// m_wAverageWidth = DBCSFont() ? (1 + m_IFIMETRICS.fwdMaxCharInc) >> 1 : m_IFIMETRICS.fwdMaxCharInc; // rm ori
|
|
// 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_IFIMETRICS.fwdMaxCharInc; //m_wMaximumIncrement; // rm ori, rm new
|
|
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < m_cpaGlyphs.GetSize() && Glyph(i).CodePoint() < 0x80;)
|
|
m_cwaWidth[i++] = m_IFIMETRICS.fwdAveCharWidth; //m_wAverageWidth; // rm ori, rm new // 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_InternalLeading
|
|
// 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_Lowerd = m_IFIMETRICS.fwdWinAscender - m_InternalLeading;
|
|
m_Lowerp = m_wHeight - m_IFIMETRICS.fwdWinAscender;
|
|
}
|
|
*/
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
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_IFIMETRICS.fwdMaxCharInc) return; // Nothing to do!
|
|
// if (wWidth == m_wMaximumIncrement) return; // Nothing to do!
|
|
|
|
m_IFIMETRICS.fwdMaxCharInc = wWidth; // rm new
|
|
|
|
// m_wMaximumIncrement = wWidth; // rm ori
|
|
|
|
|
|
m_IFIMETRICS.fwdAveCharWidth = DBCSFont() ? (wWidth + 1) >> 1 : wWidth; // rm new
|
|
|
|
// m_wAverageWidth = DBCSFont() ? (wWidth + 1) >> 1 : wWidth; // rm old
|
|
|
|
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])); // rm ori
|
|
short sBaseline = (short) (min(wHeight, m_IFIMETRICS.fwdWinAscender));
|
|
|
|
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_InternalLeading) //m _cwaSpecial[InternalLeading])
|
|
m_wScaleDevice = m_wHeight - m_InternalLeading; //m _cwaSpecial[InternalLeading];
|
|
if (m_wMinScale > m_wHeight - m_InternalLeading) //m _cwaSpecial[InternalLeading])
|
|
m_wMinScale = m_wHeight - m_InternalLeading; //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) { // rm - need to replace this functionality
|
|
// 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); // rm no longer needed
|
|
|
|
if (!bUnicode && wChar > 255) return DoubleByte;
|
|
|
|
CWaitCursor cwc; // Unfortunately, if not Unicode, this 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);
|
|
pccpi->Convert(cba, cwa, cdaPage[cgh.CodePage()]);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i)
|
|
cwa.SetAt(0, cgh.CodePoint());
|
|
else
|
|
cwa.Add(cgh.CodePoint());
|
|
|
|
pccpi->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!!!! // rm ori - no longer needed, incorporated below
|
|
|
|
|
|
if (wItem == Default)
|
|
{
|
|
if (m_IFIMETRICS.wcDefaultChar == cwa[0]) return OK; // Nothing changed!!!!
|
|
m_IFIMETRICS.wcDefaultChar = cwa[0];
|
|
m_IFIMETRICS.chDefaultChar = cba[0];
|
|
}
|
|
else
|
|
{
|
|
m_IFIMETRICS.wcBreakChar = cwa[0];
|
|
m_IFIMETRICS.chBreakChar = cba[0];
|
|
}
|
|
|
|
// m_cwaSignificant[wItem] = cwa[0]; // rm ori no longer needed
|
|
// m_cbaSignificant[wItem] = cba[0]; // rm ori no longer needed
|
|
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_InternalLeading) //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.
|
|
|
|
IA64 : 1. conversion change loXXX in UNIFI_HDR to 8 byte aligned
|
|
2. this part also changed accordingly
|
|
3. what if we load 32 bit UFM(not conversion in new source) in IA64?
|
|
->1. Need to new converstion tool from UFM32 to UFM64
|
|
->2. this tool Can't be embedded in MDT because this take some time
|
|
(loading ->checking -> storing after that structure on every loXXX)
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CFontInfo::Load(bool bloadedbyworkspace /*= false*/)
|
|
{
|
|
// Save the load location flag.
|
|
|
|
m_bLoadedByWorkspace = bloadedbyworkspace ;
|
|
|
|
// Prepare to open the file.
|
|
|
|
CFile cfUFM;
|
|
char pszFullName[128] = "";
|
|
if (!SUCCEEDED(StringCchCopyA(pszFullName, CCHOF(pszFullName), (const char *) m_cfn.FullName())))
|
|
{
|
|
throw;
|
|
}
|
|
|
|
// Open the UFM file
|
|
|
|
if (!cfUFM.Open(m_cfn.FullName(), CFile::modeRead | CFile::shareDenyWrite)) {
|
|
CString csMessage;
|
|
csMessage.Format(IDS_LoadFailure, (LPCTSTR) m_cfn.FullName());
|
|
AfxMessageBox(csMessage);
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the length of the UFM file. If it is too short to be correctly
|
|
// formed, complain and return FALSE; ie, load failure.
|
|
|
|
int i = cfUFM.GetLength() ;
|
|
if (i < sizeof(UNIFM_HDR)) {
|
|
CString csmsg ;
|
|
csmsg.Format(IDS_UFMTooSmallError, m_cfn.NameExt()) ;
|
|
AfxMessageBox(csmsg, MB_ICONEXCLAMATION) ;
|
|
return FALSE ;
|
|
} ;
|
|
|
|
CByteArray cbaUFM; // Loaded with file's contents
|
|
|
|
// Try to load the file- proclaim defeat on any exception.
|
|
|
|
try {
|
|
cbaUFM.SetSize(i);
|
|
cfUFM.Read(cbaUFM.GetData(), (unsigned)cbaUFM.GetSize());
|
|
}
|
|
catch (CException *pce) {
|
|
pce -> ReportError();
|
|
pce -> Delete();
|
|
CString csMessage;
|
|
csMessage.Format(IDS_LoadFailure, (LPCTSTR) m_cfn.FullName());
|
|
AfxMessageBox(csMessage);
|
|
return FALSE;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
PUNIFM_HDR pufmh = (PUNIFM_HDR) cbaUFM.GetData(); // UNIFM_HDR
|
|
|
|
m_ulDefaultCodepage = (WORD) pufmh -> ulDefaultCodepage;
|
|
m_lGlyphSetDataRCID = (WORD) pufmh -> lGlyphSetDataRCID; // Store the GTT ID
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
union { //raid 154639
|
|
PBYTE pbudi;
|
|
PUNIDRVINFO pudi;
|
|
};
|
|
pudi = (PUNIDRVINFO) (cbaUFM.GetData() + pufmh->loUnidrvInfo); // UNIDRVINFO
|
|
if (!pudi -> dwSize || !pudi -> wXRes || !pudi -> wYRes) //raid 154639
|
|
pbudi +=4; // normally converion from 32 bit OS.
|
|
memcpy((void *) &m_UNIDRVINFO, pudi, sizeof(UNIDRVINFO)); // Bulk copy everything
|
|
|
|
if (pudi -> SelectFont.loOffset) // Fill in the two invocation strings - why it is
|
|
m_ciSelect.Init((PBYTE) pudi + pudi->SelectFont.loOffset, // the offset is NULL and the count is garbage
|
|
pudi->SelectFont.dwCount); // when there is none is beyond me, but so be it.
|
|
|
|
if (pudi->UnSelectFont.loOffset)
|
|
m_ciDeselect.Init((PBYTE) pudi + pudi->UnSelectFont.loOffset,
|
|
pudi->UnSelectFont.dwCount);
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
// IFIMETRICS
|
|
union {
|
|
PBYTE pbIFI;
|
|
PIFIMETRICS pIFI;
|
|
};
|
|
|
|
pbIFI = cbaUFM.GetData() + pufmh->loIFIMetrics; // Assign byte pointer to file IFIMETRICS data
|
|
if (!pIFI -> cjThis || !pIFI ->chLastChar) //raid 154639
|
|
pbIFI +=4;
|
|
|
|
memcpy((void *) &m_IFIMETRICS, pIFI, sizeof(IFIMETRICS) ); // Bulk copy everything
|
|
|
|
if ( !(m_IFIMETRICS.fsSelection & FM_SEL_REGULAR) // If font isn't defined as regular, or bold,
|
|
&& !(m_IFIMETRICS.fsSelection & FM_SEL_BOLD) ) // then just set it to regular.
|
|
m_IFIMETRICS.fsSelection |= FM_SEL_REGULAR;
|
|
|
|
//-----------------------------------------------------
|
|
m_csUnique = (PWSTR) (pbIFI + pIFI->dpwszUniqueName); // dpwszUniqueName
|
|
m_csStyle = (PWSTR) (pbIFI + pIFI->dpwszStyleName); // dpwszStyleName
|
|
m_csFace = (PWSTR) (pbIFI + pIFI->dpwszFaceName); // dpwszFaceName
|
|
//-----------------------------------------------------
|
|
m_csaFamily.RemoveAll(); // Just in case it isn't clean
|
|
|
|
PWSTR pwstrFamily = (PWSTR) (pbIFI + pIFI->dpwszFamilyName); // dpwszFamilyName
|
|
CString csWork(pwstrFamily); // Let CString handle the Unicode conversions for us,
|
|
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);
|
|
}
|
|
//-----------------------------------------------------
|
|
m_ItalicAngle = (WORD) (gdConvertRadToDegree * // m_ItalicAngle
|
|
atan2((double) pIFI->ptlCaret.x, (double) pIFI->ptlCaret.y));
|
|
|
|
m_wHeight = m_IFIMETRICS.fwdWinAscender + m_IFIMETRICS.fwdWinDescender; // m_wHeight // rm new
|
|
m_InternalLeading = m_wHeight - m_IFIMETRICS.fwdUnitsPerEm; // fwdUnitsPerEm // rm new
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Try to find and load the GTT referenced by this UFM iff this UFM is being
|
|
// loaded directly.
|
|
|
|
if (!m_bLoadedByWorkspace)
|
|
if (!FindAndLoadGTT()) {
|
|
CString csmsg;
|
|
csmsg.Format(IDS_NoGTTForUFMFatalError, m_cfn.NameExt()) ;
|
|
AfxMessageBox(csmsg, MB_ICONEXCLAMATION) ;
|
|
return FALSE ;
|
|
} ;
|
|
|
|
// DEAD_BUG: This is a good place to add code to find and associate the UFM
|
|
// with its GTT so that the UFM doesn't have to be loaded twice
|
|
// when the UFM is loaded as part of a workspace load.
|
|
//
|
|
// best solution is just skipping EXTTEXTMETRIC, but almost no influence.
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
if ( !m_pcgmTranslation && m_bLoadedByWorkspace )
|
|
return FALSE;
|
|
// EXTTEXTMETRIC
|
|
|
|
for (i = 0; i < 26; i++) // Preload zeroes into the m_EXTTEXTMETRIC structure.
|
|
*(SHORT *)((SHORT *)&m_EXTTEXTMETRIC + i) = 0;
|
|
|
|
//raid 154639
|
|
union {
|
|
PBYTE pbetm;
|
|
PEXTTEXTMETRIC petm;
|
|
};
|
|
|
|
petm = (PEXTTEXTMETRIC) (pufmh->loExtTextMetric ? // Get pointer - if EXTTEXTMETRIC data exists
|
|
(cbaUFM.GetData() + pufmh->loExtTextMetric) : NULL);
|
|
if (petm)
|
|
{
|
|
if (!petm -> emSize || !petm -> emPointSize)
|
|
pbetm += 4;
|
|
|
|
m_fSave_EXT = TRUE;
|
|
|
|
m_fEXTTEXTMETRIC = TRUE;
|
|
|
|
memcpy((void *) &m_EXTTEXTMETRIC, petm, sizeof(EXTTEXTMETRIC) ); // Bulk copy everything
|
|
|
|
m_wMinScale = m_EXTTEXTMETRIC.emMinScale;
|
|
m_wMaxScale = m_EXTTEXTMETRIC.emMaxScale;
|
|
m_Lowerd = m_EXTTEXTMETRIC.emLowerCaseAscent;
|
|
m_Lowerp = m_EXTTEXTMETRIC.emLowerCaseDescent;
|
|
m_ItalicAngle = m_EXTTEXTMETRIC.emSlant;
|
|
// m_bfScaleOrientation = (BYTE) m_EXTTEXTMETRIC.emOrientation;
|
|
m_wScaleDevice = m_EXTTEXTMETRIC.emMasterHeight;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
if (pIFI->dpFontSim) // FONTSIM, if any.
|
|
{
|
|
union {
|
|
PBYTE pbfs;
|
|
FONTSIM *pfs;
|
|
};
|
|
|
|
pbfs = pbIFI + pIFI -> dpFontSim;
|
|
|
|
if (m_pcfdBold) delete m_pcfdBold; // If we're reloading, clean these up!
|
|
if (m_pcfdItalic) delete m_pcfdItalic;
|
|
if (m_pcfdBoth) delete m_pcfdBoth;
|
|
|
|
if (pfs->dpBold) m_pcfdBold = new CFontDifference(pbfs + pfs->dpBold, this); // Bold simulation
|
|
if (pfs->dpItalic) m_pcfdItalic = new CFontDifference(pbfs + pfs->dpItalic, this); // Italic Simulation
|
|
if (pfs->dpBoldItalic) m_pcfdBoth = new CFontDifference(pbfs + pfs->dpBoldItalic, this); // Bold Italic Simulation
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
//if (m_pcgmTranslation && (m_loWidthTable = pufmh -> loWidthTable)) // WIDTH TABLE, but only if there is an associated GTT.
|
|
|
|
if (m_pcgmTranslation && pufmh->loWidthTable ) //pufmh->loWidthTable) // WIDTH TABLE, but only if there is an associated GTT.
|
|
{
|
|
union {
|
|
PBYTE pbwt;
|
|
PWIDTHTABLE pwt;
|
|
};
|
|
|
|
pbwt = cbaUFM.GetData() + pufmh -> loWidthTable;
|
|
// dwSize has problem ; there are case: dwAdd_ in pfm2ifi has not 4 byte, so dwSize has number in some case
|
|
// data before wGlyphCount is dwRunNum: impossible to beyond ff ff 00 00 (65536), as long as dwAdd is 4,2 not 1 & dwRun > 256
|
|
// nicer solution is required : BUG_BUG.
|
|
if( !pwt ->dwSize || !pwt ->WidthRun ->wGlyphCount)
|
|
pbwt += 4;
|
|
|
|
m_pcgmTranslation -> Collect(m_cpaGlyphs); // Collect all the handles
|
|
m_pcgmTranslation -> Collect(m_cpaOldGlyphs); //244123
|
|
//244123 // when delete glyph, memory is occupied with dddd, so we have to save original data in here
|
|
m_cwaOldGlyphs.SetSize(m_cpaOldGlyphs.GetSize()) ;
|
|
for ( i = 0 ; i < m_cpaOldGlyphs.GetSize() ; i ++ ) {
|
|
CGlyphHandle& cghThis = *(CGlyphHandle *) m_cpaOldGlyphs[i];
|
|
m_cwaOldGlyphs.SetAt(i,cghThis.CodePoint() ) ;
|
|
}
|
|
|
|
m_cwaWidth.RemoveAll();
|
|
if (m_cpaGlyphs.GetSize() > 0)
|
|
m_cwaWidth.InsertAt(0, 0, m_cpaGlyphs.GetSize());
|
|
|
|
|
|
unsigned uWidth = (unsigned)m_cwaWidth.GetSize(); // rm fix VC compiler problem?
|
|
unsigned uWidthIdx ;
|
|
|
|
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++)
|
|
{
|
|
// For whatever reason, there are times when the index value is
|
|
// < 0 or > uWidth. An AV would occur if m_cwaWidth were allowed
|
|
// to be indexed by such a value. Just keep this from happening
|
|
// for now. A better fix is needed. BUG_BUG : won't fix
|
|
|
|
uWidthIdx = uGlyph + -1 + pwt->WidthRun[u].wStartGlyph ; // Glyph handles start at 1, not 0!
|
|
if ((int) uWidthIdx < 0) {
|
|
//AfxMessageBox("Negative width table index") ;
|
|
//TRACE("***Negative width table index (%d) found in %s. Table size=%d uGlyph=%d wGlyphCount=%d wStartGlyph=%d u=%d dwRunNum=%d\n", uWidthIdx, Name(), uWidth, uGlyph, pwt->WidthRun[u].wGlyphCount, pwt->WidthRun[u].wStartGlyph, u, pwt->dwRunNum) ;
|
|
continue ;
|
|
} else if (uWidthIdx >= uWidth) {
|
|
//AfxMessageBox("Width table index (%d) > table size") ;
|
|
//TRACE("***Width table index (%d) > table size (%d) found in %s. Table size=%d uGlyph=%d wGlyphCount=%d wStartGlyph=%d u=%d dwRunNum=%d\n", uWidthIdx, uWidth, Name(), uWidth, uGlyph, pwt->WidthRun[u].wGlyphCount, pwt->WidthRun[u].wStartGlyph, u, pwt->dwRunNum) ;
|
|
break ; // rm fix VC IDE compiler problem?
|
|
} ;
|
|
|
|
//m_cwaWidth[uGlyph + -1 + pwt->WidthRun[u].wStartGlyph] = *pwWidth++; // Glyph handles start at 1, not 0!
|
|
m_cwaWidth[uWidthIdx] = *pwWidth++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
m_csoaKern.RemoveAll(); // KERNING TABLE, if any
|
|
|
|
if (pufmh -> loKernPair)
|
|
{
|
|
union {
|
|
PBYTE pbkd;
|
|
PKERNDATA pkd;
|
|
};
|
|
|
|
pkd = (PKERNDATA) (cbaUFM.GetData() + pufmh -> loKernPair);
|
|
if (!pkd ->dwSize || !pkd->KernPair ->wcSecond || !pkd->KernPair ->wcFirst)
|
|
pbkd += 4;
|
|
|
|
unsigned rm = pkd->dwKernPairNum; // rm - debugging
|
|
for (unsigned u = 0; u < pkd -> dwKernPairNum; u++)
|
|
m_csoaKern.Add(new CKern(pkd -> KernPair[u]));
|
|
}
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
return TRUE; // Return triumphant to whoever deigned to need this service.
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
CFontInfo::FindAndLoadGTT
|
|
|
|
This function is called when a UFM is being loaded directly. Its job is to
|
|
find the associated GTT, load it, and set the UFM's pointer to this GTT. If
|
|
this fails, the user is told that no changes to this UFM can be saved if he
|
|
decides to continue loading it.
|
|
|
|
True is returned if a GTT was found and loaded. Return false if the GTT
|
|
wasn't loaded and the user doesn't want to continue to load the UFM.
|
|
|
|
******************************************************************************/
|
|
|
|
bool CFontInfo::FindAndLoadGTT()
|
|
{
|
|
// Load a predefined GTT/codepage if that is what is referenced by the UFM.
|
|
|
|
CGlyphMap* pcgm ;
|
|
pcgm = CGlyphMap::Public((WORD)Translation(), (WORD) m_ulDefaultCodepage, 0,
|
|
GetFirst(), GetLast()) ;
|
|
if (pcgm) {
|
|
SetTranslation(pcgm) ;
|
|
m_pcgmTranslation->NoteOwner(*m_pcdOwner) ; // Is this right/necessary?
|
|
m_bLoadedByWorkspace = true ;
|
|
return true ;
|
|
} ;
|
|
|
|
// Looks like no easy way out. Now I need to try to find and read the
|
|
// corresponding RC file so that it can be read to find a filespec for this
|
|
// UFM's GTT. First, build a file spec for the RC file. Assume it is in
|
|
// the directory above the one containing this UFM.
|
|
|
|
CString csrcfspec(FilePath()) ;
|
|
if (csrcfspec.GetLength() > 3)
|
|
csrcfspec = csrcfspec.Left(csrcfspec.GetLength() - 1) ;
|
|
csrcfspec = csrcfspec.Left(csrcfspec.ReverseFind(_T('\\')) + 1) ;
|
|
CString csrcpath(csrcfspec.Left(csrcfspec.GetLength() - 1)) ;
|
|
csrcfspec += _T("*.rc") ;
|
|
|
|
// I don't know the name of the RC file so look for it in the specified
|
|
// directory. Assume that the file is the first RC file in the directory
|
|
// that is NOT called "common.rc".
|
|
|
|
CFileFind cff ;
|
|
CString cstmp ;
|
|
BOOL bfound = cff.FindFile(csrcfspec) ;
|
|
bool breallyfound = false ;
|
|
while (bfound) {
|
|
bfound = cff.FindNextFile() ;
|
|
cstmp = cff.GetFileTitle() ;
|
|
cstmp.MakeLower() ;
|
|
if (cstmp != _T("common")) {
|
|
csrcfspec = cff.GetFilePath() ;
|
|
breallyfound = true ;
|
|
break ;
|
|
} ;
|
|
} ;
|
|
|
|
// Prepare to ask the user what to do if any of the next few steps fail.
|
|
|
|
CString csnext ;
|
|
csnext.Format(IDS_StandAloneFontLoad, m_cfn.NameExt()) ;
|
|
|
|
// If the RC file is not found, ...
|
|
|
|
if (!breallyfound) {
|
|
// ...Ask the user if he wants to tell us where it is. If he says no,
|
|
// ask if he want to stop or open it restricted.
|
|
|
|
cstmp.Format(IDS_RCForUFMPrompt, m_cfn.NameExt()) ;
|
|
if (AfxMessageBox(cstmp, MB_YESNO+MB_ICONQUESTION) == IDNO)
|
|
return (AfxMessageBox(csnext, MB_YESNO+MB_ICONQUESTION) == IDYES) ;
|
|
|
|
// Prompt the use for the path to the RC file. If he cancels, ask if
|
|
// he want to stop or open it restricted.
|
|
|
|
// Prompt the user for a new RC file. If the operation is canceled,
|
|
// ask if he wants to stop or open it restricted.
|
|
|
|
cstmp.LoadString(IDS_CommonRCFile) ;
|
|
CFileDialog cfd(TRUE, _T(".RC"), NULL,
|
|
OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, cstmp) ;
|
|
cfd.m_ofn.lpstrInitialDir = csrcpath ;
|
|
if (cfd.DoModal() != IDOK)
|
|
return (AfxMessageBox(csnext, MB_YESNO+MB_ICONQUESTION) == IDYES) ;
|
|
|
|
// Prepare to check the new filespec
|
|
|
|
csrcfspec = cfd.GetPathName() ;
|
|
csrcpath = csrcfspec.Left(csrcfspec.ReverseFind(_T('\\'))) ;
|
|
} ;
|
|
|
|
// I've got an RC filespec now so try to open it and read its contents.
|
|
// If the operation fails, ask if he wants to stop or open it restricted.
|
|
|
|
CStringArray csarclines ;
|
|
if (!LoadFile(csrcfspec, csarclines))
|
|
return (AfxMessageBox(csnext, MB_YESNO+MB_ICONQUESTION) == IDYES) ;
|
|
|
|
// Now try to find the line in the RC file that contains the ID for this
|
|
// UFM's GTT. If the operation fails, ask if he wants to stop or open it
|
|
// restricted.
|
|
|
|
for (int n = 0 ; n < csarclines.GetSize() ; n++) {
|
|
if (csarclines[n].Find(_T("RC_GTT")) == -1)
|
|
continue ;
|
|
if (atoi(csarclines[n]) == Translation())
|
|
break ;
|
|
} ;
|
|
if (n >= csarclines.GetSize())
|
|
return (AfxMessageBox(csnext, MB_YESNO+MB_ICONQUESTION) == IDYES) ;
|
|
|
|
// The GTT filespec in the RC file should be relative to the location of
|
|
// the RC file. So, combine the filespec with the RC file path to get
|
|
// the complete filespec for the GTT file.
|
|
|
|
CString csgttfspec ;
|
|
int nloc = csarclines[n].ReverseFind(_T(' ')) ;
|
|
csgttfspec = csarclines[n].Right(csarclines[n].GetLength() - nloc - 1) ;
|
|
csgttfspec = csrcpath + _T("\\") + csgttfspec ;
|
|
|
|
// Allocate a new Glyph class instance, initialize it, and load it. If the
|
|
// operations fails, ask if the user wants to stop or open it restricted.
|
|
|
|
pcgm = new CGlyphMap ;
|
|
pcgm->nSetRCID((int) Translation()) ;
|
|
pcgm->NoteOwner(*m_pcdOwner) ; // Is this right/necessary?
|
|
if (!pcgm->Load(csgttfspec))
|
|
return (AfxMessageBox(csnext, MB_YESNO+MB_ICONQUESTION) == IDYES) ;
|
|
|
|
// The GTT has been loaded so set the UFM's GTT pointer variable, set
|
|
// m_bLoadedByWorkspace since everything has been fixed up as if it had
|
|
// been loaded from a workspace, and return true to indicate success.
|
|
|
|
SetTranslation(pcgm) ;
|
|
m_bLoadedByWorkspace = true ;
|
|
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.
|
|
|
|
// typedef struct _UNIDRVINFO
|
|
// {
|
|
// DWORD dwSize; // Size of this structure
|
|
// DWORD flGenFlags; // General flags
|
|
// WORD wType; // Type of the font like CAPSL
|
|
// WORD fCaps; // Font Capability flags
|
|
// WORD wXRes; // Horizontal resolution of the font
|
|
// WORD wYRes; // Vertical Resolution of the font
|
|
// short sYAdjust; // Vertical Cursor position Adjustment
|
|
// short sYMoved; // Adjustment to Y position after printing
|
|
// WORD wPrivateData; // For backward compatibility, don't show in UI.
|
|
// short sShift; // For backward compatibility, don't show in UI.
|
|
// INVOCATION SelectFont;
|
|
// INVOCATION UnSelectFont;
|
|
// WORD wReserved[4];
|
|
// } UNIDRVINFO, *PUNIDRVINFO;
|
|
//
|
|
//
|
|
// And now, ladies and gentlemen, direct from the pages of WINDDI.H,
|
|
// I present to you:
|
|
//
|
|
// "rather than adding the fields of IFIEXTRA to IFIMETRICS itself
|
|
// we add them as a separate structure. This structure, if present at all,
|
|
// lies below IFIMETRICS in memory.
|
|
// If IFIEXTRA is present at all, ifi.cjIfiExtra (formerly ulVersion)
|
|
// will contain size of IFIEXTRA including any reserved fields.
|
|
// That way ulVersion = 0 (NT 3.51 or less) printer minidrivers
|
|
// will work with NT 4.0."
|
|
//
|
|
// typedef struct _IFIEXTRA
|
|
// {
|
|
// ULONG ulIdentifier; // used for Type 1 fonts only
|
|
// PTRDIFF dpFontSig; // nontrivial for tt only, at least for now.
|
|
// ULONG cig; // maxp->numGlyphs, # of distinct glyph indicies
|
|
// PTRDIFF dpDesignVector; // offset to design vector for mm instances
|
|
// PTRDIFF dpAxesInfoW; // offset to full axes info for base mm font
|
|
// ULONG aulReserved[1]; // in case we need even more stuff in the future
|
|
// } IFIEXTRA, *PIFIEXTRA;
|
|
//
|
|
******************************************************************************/
|
|
|
|
BOOL CFontInfo::Store(LPCTSTR lpstrFile, BOOL bStoreFormWokspace)
|
|
{
|
|
// Fonts loaded standalone cannot be saved because m_pcgmTranslation is not
|
|
// set. Tell the user and exit. TRUE is returned to keep this from
|
|
// happening again.
|
|
|
|
if (!m_bLoadedByWorkspace) {
|
|
CString csmsg ;
|
|
csmsg.LoadString(IDS_CantStoreStandAlone) ;
|
|
AfxMessageBox(csmsg) ;
|
|
return TRUE ;
|
|
} ;
|
|
|
|
DWORD dwAdd_UniDrv = 0;
|
|
DWORD dwAdd_IFI = 0;
|
|
DWORD dwAdd_ExtTextM = 0;
|
|
DWORD dwAdd_WidthTable = 0;
|
|
DWORD dwAdd_KerPair = 0;
|
|
|
|
// DWORD dwAdd_SelectedFont;
|
|
// DWORD dwAdd_UnSelectedFont;
|
|
|
|
static const BYTE InsertZero[8] = {0,0,0,0,0,0,0,0};
|
|
|
|
const short OS_BYTE = 0x08;
|
|
// If a UFM loaded from a workspace can't be saved normally because it did
|
|
// not have a valid GTT/CP, call another routine to handle this case and
|
|
// return whatever it returns.
|
|
|
|
if (m_bWSLoadButNoGTTCP)
|
|
return StoreGTTCPOnly(lpstrFile) ;
|
|
|
|
try { // Any exxceptions, we'll just fail gracelessly
|
|
|
|
CFile cfUFM(lpstrFile, // Create/open the output file.
|
|
CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive);
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
// UNIFM_HDR
|
|
UNIFM_HDR ufmh = {sizeof ufmh, UNIFM_VERSION_1_0, 0, // Create the output UNIFM_HDR
|
|
(short) m_lGlyphSetDataRCID, sizeof ufmh}; // rm new
|
|
|
|
|
|
// int q = m_pcgmTranslation -> m_csoaCodePage.GetSize(); // rm test
|
|
// int r = m_pcgmTranslation -> CodePages(); // rm test
|
|
|
|
// ufmh.ulDefaultCodepage = m_pcgmTranslation -> CodePage(0).Page(); // rm test
|
|
|
|
// Previously, the default code page in the UFM's GTT was always saved.
|
|
// This ignored the user's changes in the UFM editor. Now, the user's
|
|
// choice is saved if it is valid (other checking done in other places).
|
|
// Otherwise, the GTT's default code page is used when there is a GTT
|
|
// associated with the UFM. If not, assert.
|
|
|
|
if (m_ulDefaultCodepage > 0)
|
|
ufmh.ulDefaultCodepage = m_ulDefaultCodepage ;
|
|
else if (m_pcgmTranslation)
|
|
ufmh.ulDefaultCodepage = m_pcgmTranslation->DefaultCodePage() ;
|
|
else
|
|
ASSERT(0) ;
|
|
//ufmh.ulDefaultCodepage = m_pcgmTranslation -> DefaultCodePage(); // Use Glyph Map default code page if at all possible.
|
|
|
|
memset((PBYTE) ufmh.dwReserved, 0, sizeof ufmh.dwReserved); // Zero fill reserved bytes.
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
ufmh.loUnidrvInfo = ufmh.dwSize; // UNIDRVINFO
|
|
if (dwAdd_UniDrv = ufmh.loUnidrvInfo & 0x07) {
|
|
dwAdd_UniDrv = OS_BYTE - dwAdd_UniDrv;
|
|
ufmh.loUnidrvInfo += dwAdd_UniDrv;
|
|
}
|
|
|
|
m_UNIDRVINFO.dwSize = sizeof (UNIDRVINFO);
|
|
|
|
m_UNIDRVINFO.SelectFont.loOffset = m_ciSelect.Length() ? m_UNIDRVINFO.dwSize : 0; // Invocation Strings affect the size,
|
|
/* if (dwAdd_SelectedFont = m_UNIDRVINFO.SelectFont.loOffset & 0x07) {
|
|
dwAdd_SelectedFont += OS_BYTE - dwAdd_SelectedFont;
|
|
m_UNIDRVINFO.SelectFont.loOffset += dwAdd_SelectedFont;
|
|
} */
|
|
m_UNIDRVINFO.dwSize += m_UNIDRVINFO.SelectFont.dwCount = m_ciSelect.Length(); // so get their specifics and
|
|
|
|
m_UNIDRVINFO.UnSelectFont.loOffset = m_ciDeselect.Length() ? m_UNIDRVINFO.dwSize : 0; // store them, updating the affected
|
|
/* if (dwAdd_UnSelectedFont = m_UNIDRVINFO.UnSelectFont.loOffset & 0x07) {
|
|
dwAdd_UnSelectedFont += OS_BYTE - dwAdd_UnSelectedFont;
|
|
ufmh.loUnidrvInfo += dwAdd_UnSelectedFont;
|
|
} */
|
|
m_UNIDRVINFO.dwSize += m_UNIDRVINFO.UnSelectFont.dwCount = m_ciDeselect.Length(); // size fields as we go.
|
|
|
|
unsigned uAdjustUDI = (4 - (m_UNIDRVINFO.dwSize % 4)) % 4; // you can delte this // Pad this to keep everything
|
|
// DWORD aligned in the file image!
|
|
ufmh.loIFIMetrics = ufmh.dwSize += m_UNIDRVINFO.dwSize += uAdjustUDI + dwAdd_UniDrv; // Store IFIMETRICS offset
|
|
|
|
if (dwAdd_IFI = ufmh.loIFIMetrics & 0x07) {
|
|
dwAdd_IFI = OS_BYTE - dwAdd_IFI;
|
|
ufmh.loIFIMetrics += dwAdd_IFI;
|
|
}
|
|
memset((PSTR) m_UNIDRVINFO.wReserved, 0, sizeof m_UNIDRVINFO.wReserved); // zero out reserved section.
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
IFIEXTRA ifie = {0, 0, m_pcgmTranslation->Glyphs(), 0, 0, 0}; // Create the IFIEXTRA structure.
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
// IFIMETRICS
|
|
|
|
IFIMETRICS ifi = {sizeof ifi + sizeof ifie, sizeof ifie}; // Create the output IFIMETRICS structure, being sure to add
|
|
// in the size of the IFIMETRICS structure, as well as the
|
|
// size of the IFIEXTRA structure.
|
|
|
|
// int iSizeOf_IFIMETRICS = sizeof(IFIMETRICS);
|
|
|
|
// memcpy((void *) &ifi, (void *) &m_IFIMETRICS, iSizeOf_IFIMETRICS ); // IFIMETRICS structure
|
|
|
|
// Store the IFIMETRICS data
|
|
|
|
ifi.lEmbedId = ifi.lItalicAngle = ifi.lCharBias = 0; //
|
|
|
|
ifi.dpCharSets = 0; // dpCharSets = 0 for now
|
|
|
|
ifi.jWinCharSet = m_IFIMETRICS.jWinCharSet; // jWinCharSet // rm new
|
|
ifi.jWinPitchAndFamily = m_IFIMETRICS.jWinPitchAndFamily; // jWinPitchAndFamily // rm new
|
|
ifi.usWinWeight = m_IFIMETRICS.usWinWeight; // usWinWeight // rm new
|
|
ifi.flInfo = m_IFIMETRICS.flInfo; // flInfo // rm new
|
|
ifi.fsSelection = m_IFIMETRICS.fsSelection; // fsSelection // rm new
|
|
ifi.fsType = FM_NO_EMBEDDING; // fsType // rm new
|
|
|
|
ifi.fwdUnitsPerEm = m_IFIMETRICS.fwdUnitsPerEm; // fwdUnitsPerEm // rm new
|
|
ifi.fwdLowestPPEm = m_IFIMETRICS.fwdLowestPPEm; // fwdLowestPPEm // rm new
|
|
|
|
ifi.fwdWinAscender = m_IFIMETRICS.fwdWinAscender; // fwdWinAscender // rm new
|
|
ifi.fwdWinDescender = m_IFIMETRICS.fwdWinDescender; // fwdWinDescender // rm new
|
|
|
|
ifi.fwdMacAscender = m_IFIMETRICS.fwdWinAscender; // fwdMacAscender // rm replaced
|
|
ifi.fwdMacDescender = m_IFIMETRICS.fwdWinAscender - m_wHeight; // fwdMacDescender // rm replaced
|
|
|
|
ifi.fwdMacLineGap = m_IFIMETRICS.fwdMacLineGap; // fwdMacLineGap
|
|
|
|
ifi.fwdTypoAscender = m_IFIMETRICS.fwdWinAscender; // fwdTypoAscender // rm replaced
|
|
ifi.fwdTypoDescender = m_IFIMETRICS.fwdWinAscender - m_wHeight; // fwdTypoDescender // rm replaced
|
|
|
|
ifi.fwdTypoLineGap = m_IFIMETRICS.fwdMacLineGap; // fwdTypoLineGap
|
|
|
|
ifi.fwdAveCharWidth = m_IFIMETRICS.fwdAveCharWidth; // fwdAveCharWidth // rm new
|
|
ifi.fwdMaxCharInc = m_IFIMETRICS.fwdMaxCharInc; // fwdMaxCharInc // rm new
|
|
|
|
|
|
ifi.fwdCapHeight = m_IFIMETRICS.fwdCapHeight; // fwdCapHeight // rm new
|
|
ifi.fwdXHeight = m_IFIMETRICS.fwdXHeight; // fwdXHeight // rm new
|
|
ifi.fwdSubscriptXSize = m_IFIMETRICS.fwdSubscriptXSize; // fwdSubscriptXSize // rm new
|
|
ifi.fwdSubscriptYSize = m_IFIMETRICS.fwdSubscriptYSize; // fwdSubscriptYSize // rm new
|
|
ifi.fwdSubscriptXOffset = m_IFIMETRICS.fwdSubscriptXOffset; // fwdSubscriptXOffset // rm new
|
|
ifi.fwdSubscriptYOffset = m_IFIMETRICS.fwdSubscriptYOffset; // fwdSuperscriptYOffset // rm new
|
|
ifi.fwdSuperscriptXSize = m_IFIMETRICS.fwdSuperscriptXSize; // fwdSuperscriptXSize // rm new
|
|
ifi.fwdSuperscriptYSize = m_IFIMETRICS.fwdSuperscriptYSize; // fwdSubscriptYOffset // rm new
|
|
ifi.fwdSuperscriptXOffset = m_IFIMETRICS.fwdSuperscriptXOffset; // fwdSuperscriptXOffset // rm new
|
|
ifi.fwdSuperscriptYOffset = m_IFIMETRICS.fwdSuperscriptYOffset; // fwdSuperscriptYOffset // rm new
|
|
|
|
|
|
ifi.fwdUnderscoreSize = m_IFIMETRICS.fwdUnderscoreSize; // fwdUnderscoreSize // rm new
|
|
ifi.fwdUnderscorePosition = m_IFIMETRICS.fwdUnderscorePosition; // fwdUnderscorePosition // rm new
|
|
ifi.fwdStrikeoutSize = m_IFIMETRICS.fwdStrikeoutSize; // fwdStrikeoutSize // rm new
|
|
ifi.fwdStrikeoutPosition = m_IFIMETRICS.fwdStrikeoutPosition; // fwdStrikeoutPosition // rm new
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
ifi.chFirstChar = m_IFIMETRICS.chFirstChar; // chFirstChar // rm new
|
|
ifi.chLastChar = m_IFIMETRICS.chLastChar; // chLastChar // rm new
|
|
ifi.chDefaultChar = m_IFIMETRICS.chDefaultChar; // chDefaultChar // rm new
|
|
ifi.chBreakChar = m_IFIMETRICS.chBreakChar; // chBreakChar // rm new
|
|
|
|
ifi.wcFirstChar = m_IFIMETRICS.wcFirstChar; // wcFirstChar // rm new
|
|
ifi.wcLastChar = m_IFIMETRICS.wcLastChar; // wcLastChar // rm new
|
|
ifi.wcDefaultChar = m_IFIMETRICS.wcDefaultChar; // wcDefaultChar // rm new
|
|
ifi.wcBreakChar = m_IFIMETRICS.wcBreakChar; // wcBreakChar // rm new
|
|
|
|
ifi.ptlBaseline.x = m_IFIMETRICS.ptlBaseline.x; // ptlBaseline.x
|
|
ifi.ptlBaseline.y = m_IFIMETRICS.ptlBaseline.y; // ptlBaseline.y
|
|
|
|
ifi.ptlAspect.x = m_IFIMETRICS.ptlAspect.x; // ptlAspect.x // rm new
|
|
ifi.ptlAspect.y = m_IFIMETRICS.ptlAspect.y; // ptlAspect.y // rm new
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
// ifi.ptlBaseline.x = 1; // ptlBaseline.x
|
|
// ifi.ptlBaseline.y = 0; // ptlBaseline.y
|
|
//
|
|
// ifi.ptlAspect.x = m_UNIDRVINFO.wXRes; // ptlAspect.x // rm new
|
|
// ifi.ptlAspect.y = m_UNIDRVINFO.wYRes; // ptlAspect.y // rm new
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
ifi.ptlCaret.x = m_IFIMETRICS.ptlCaret.x; // ptlCaret.x // rm new
|
|
ifi.ptlCaret.y = m_IFIMETRICS.ptlCaret.y; // ptlCaret.y // rm new
|
|
|
|
|
|
// ifi.ptlCaret.x = m_ItalicAngle ? (long) ((double) 10000.0 * // ptlCaret.x // rm ori
|
|
// tan(((double) m_ItalicAngle) / gdConvertRadToDegree)) : 0;
|
|
// ifi.ptlCaret.y = m_ItalicAngle ? 10000 : 1; // ptlCaret.y // rm ori
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
memcpy(ifi.achVendId, "Unkn", 4); // achVendId // rm ori
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
ifi.cKerningPairs = m_csoaKern.GetSize(); // cKerningPairs // rm ori
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
ifi.rclFontBox.left = m_IFIMETRICS.rclFontBox.left; // rclFontBox.left // rm new
|
|
ifi.rclFontBox.top = m_IFIMETRICS.rclFontBox.top; // rclFontBox.top // rm new
|
|
ifi.rclFontBox.right = m_IFIMETRICS.rclFontBox.right; // rclFontBox.right // rm new
|
|
ifi.rclFontBox.bottom = m_IFIMETRICS.rclFontBox.bottom; // rclFontBox.bottom // rm new
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
ifi.ulPanoseCulture = FM_PANOSE_CULTURE_LATIN; // ulPanoseCulture // rm ori
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// panose .bWeight // rm ori
|
|
ifi.panose.bWeight = (m_IFIMETRICS.usWinWeight >= FW_BOLD) ? PAN_WEIGHT_BOLD :
|
|
(m_IFIMETRICS.usWinWeight > FW_EXTRALIGHT) ? PAN_WEIGHT_MEDIUM : PAN_WEIGHT_LIGHT;
|
|
|
|
ifi.panose.bFamilyType = m_IFIMETRICS.panose.bFamilyType; // panose // rm new
|
|
ifi.panose.bSerifStyle = m_IFIMETRICS.panose.bSerifStyle;
|
|
ifi.panose.bProportion = m_IFIMETRICS.panose.bProportion;
|
|
ifi.panose.bContrast = m_IFIMETRICS.panose.bContrast;
|
|
ifi.panose.bStrokeVariation = m_IFIMETRICS.panose.bStrokeVariation;
|
|
ifi.panose.bArmStyle = m_IFIMETRICS.panose.bArmStyle;
|
|
ifi.panose.bLetterform = m_IFIMETRICS.panose.bLetterform;
|
|
ifi.panose.bMidline = m_IFIMETRICS.panose.bMidline;
|
|
ifi.panose.bXHeight = m_IFIMETRICS.panose.bXHeight;
|
|
|
|
|
|
// ifi.panose.bFamilyType = ifi.panose.bSerifStyle = // panose // rm ori
|
|
// 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;
|
|
|
|
unsigned uSim = !!m_pcfdBold + !!m_pcfdItalic + !!m_pcfdBoth; // Finally, Allow for the size of any Font Difference structures.
|
|
|
|
ifi.dpFontSim = uSim ? ifi.cjThis : 0;
|
|
ufmh.dwSize += ifi.cjThis += uSim * sizeof(FONTDIFF) + !!uSim * sizeof(FONTSIM) + dwAdd_IFI;
|
|
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
// EXTTEXTMETRIC
|
|
|
|
ufmh.loExtTextMetric = 0; // Preset ufm exttextmetric offset to 0.
|
|
|
|
if(m_fSave_EXT) // If user wants to save the EXTTEXTMETRIC data
|
|
{
|
|
ufmh.loExtTextMetric = ufmh.dwSize; // Set ufm exttextmetric offset. Note, this
|
|
// offset just happens to be the current ufmh.dwSize.
|
|
if(dwAdd_ExtTextM = ufmh.loExtTextMetric & 0x07){
|
|
dwAdd_ExtTextM = OS_BYTE - dwAdd_ExtTextM;
|
|
ufmh.loExtTextMetric += dwAdd_ExtTextM;
|
|
}
|
|
|
|
ufmh.dwSize += m_EXTTEXTMETRIC.emSize = sizeof(EXTTEXTMETRIC); // Increase size of ufmh.dwSize to accomodate
|
|
// exttextmetric structure.
|
|
ufmh.dwSize +=dwAdd_ExtTextM;
|
|
}
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
// CHARACTER WIDTHS DATA
|
|
|
|
// Calculate size of width table (if there is one)
|
|
//raid 154639
|
|
ufmh.loWidthTable = IsVariableWidth() * ufmh.dwSize; // set ufm width table offset. Note, this
|
|
|
|
if(dwAdd_WidthTable = ufmh.loWidthTable & 0x07){ // offset just happens to be the current ufmh.dwSize.
|
|
dwAdd_WidthTable = OS_BYTE - dwAdd_WidthTable;
|
|
ufmh.loWidthTable += dwAdd_WidthTable;
|
|
}
|
|
|
|
if (IsVariableWidth()) // Width table, but only if there is an associated GTT.
|
|
{ // For now, we just need to calculate the size of the table
|
|
unsigned uRuns = 0, uGlyphs = 0;
|
|
|
|
if (DBCSFont()) // DBCS
|
|
{
|
|
unsigned u = (unsigned) m_cpaGlyphs.GetSize(); // Determine the number of runs needed
|
|
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 = (unsigned)m_cwaWidth.GetSize();
|
|
}
|
|
|
|
ufmh.dwSize += sizeof (WIDTHTABLE) + --uRuns * sizeof (WIDTHRUN) +
|
|
uGlyphs * sizeof (WORD) + dwAdd_WidthTable;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
// KERNING PAIRS DATA
|
|
|
|
// Calculate size of Kerning table (if there is one)
|
|
ufmh.loKernPair = CanKern() ? ufmh.dwSize : 0; // set ufm Kerning table offset. Note, this
|
|
// offset just happens to be the current ufmh.dwSize.
|
|
|
|
// 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.
|
|
if (CanKern()){
|
|
if(dwAdd_KerPair = ufmh.loKernPair & 0x07) { // offset just happens to be the current ufmh.dwSize.
|
|
dwAdd_KerPair = OS_BYTE - dwAdd_KerPair;
|
|
ufmh.loKernPair += dwAdd_KerPair;
|
|
}
|
|
ufmh.dwSize +=
|
|
((sizeof (KERNDATA) - sizeof (FD_KERNINGPAIR)) & 0xFFFC) +
|
|
((1 + m_csoaKern.GetSize()) * sizeof (FD_KERNINGPAIR)) + dwAdd_KerPair;
|
|
}
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
// All sizes have been calculated, and the important structures have
|
|
// been initialized. Time to start writing all this great stuff!
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
cfUFM.Write(&ufmh, sizeof ufmh); // write UNIFM_HDR Header
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
if (dwAdd_UniDrv)
|
|
cfUFM.Write(InsertZero, dwAdd_UniDrv);
|
|
|
|
cfUFM.Write(&m_UNIDRVINFO, sizeof m_UNIDRVINFO); // write UNIDRVINFO // rm new
|
|
/* if (dwAdd_SelectedFont)
|
|
cfUFM.Write (InsertZero,dwAdd_SelectedFont); */
|
|
m_ciSelect.WriteEncoding(cfUFM);
|
|
|
|
/* if (dwAdd_UnSelectedFont)
|
|
cfUFM.Write (InsertZero,dwAdd_UnSelectedFont); */
|
|
m_ciDeselect.WriteEncoding(cfUFM);
|
|
|
|
cfUFM.Write(ufmh.dwReserved, uAdjustUDI); // write Padding
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
if (dwAdd_IFI)
|
|
cfUFM.Write(InsertZero, dwAdd_IFI);
|
|
|
|
cfUFM.Write(&ifi, sizeof ifi); // write IFIMETRICS
|
|
cfUFM.Write(&ifie, sizeof ifie); // write IFIEXTRA
|
|
cusFamily.Write(cfUFM); // write "Family"
|
|
cusFace.Write(cfUFM); // write "Face"
|
|
cusUnique.Write(cfUFM); // write "Unique name"
|
|
cusStyle.Write(cfUFM); // write "Style"
|
|
cfUFM.Write(ufmh.dwReserved, uAdjustIFI); // write Padding
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
if (m_pcfdBold || m_pcfdItalic || m_pcfdBoth) // Any Font difference structures
|
|
{
|
|
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);
|
|
//TRACE("Italic metrics = %d, %d %d %d\n", m_pcfdItalic->Metric(0), m_pcfdItalic->Metric(1), m_pcfdItalic->Metric(2), m_pcfdItalic->Metric(3)) ;
|
|
fs.dpBoldItalic = m_pcfdBoth ? uWhere : 0;
|
|
|
|
cfUFM.Write(&fs, sizeof fs);
|
|
|
|
|
|
if (m_pcfdBold) m_pcfdBold->Store(cfUFM, m_IFIMETRICS.fsSelection | FM_SEL_BOLD); // rm new
|
|
if (m_pcfdItalic) m_pcfdItalic->Store(cfUFM, m_IFIMETRICS.fsSelection | FM_SEL_ITALIC);
|
|
if (m_pcfdBoth) m_pcfdBoth->Store(cfUFM, m_IFIMETRICS.fsSelection | FM_SEL_BOLD| FM_SEL_ITALIC);
|
|
|
|
|
|
// if (m_pcfdBold) m_pcfdBold->Store(cfUFM, m_wfStyle | FM_SEL_BOLD); // rm ori
|
|
// 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);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
if (m_fSave_EXT) // write EXTTEXTMETRIC
|
|
if (dwAdd_ExtTextM)
|
|
cfUFM.Write(InsertZero, dwAdd_ExtTextM);
|
|
cfUFM.Write(&m_EXTTEXTMETRIC, sizeof(EXTTEXTMETRIC) );
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
// Width table
|
|
|
|
if (IsVariableWidth())
|
|
if (!DBCSFont()) // Not DBCS - easy! (Handles always start at 1
|
|
{
|
|
|
|
WIDTHTABLE wdt = { sizeof wdt, 1,
|
|
{1, (WORD)m_cpaGlyphs.GetSize(), sizeof wdt}};
|
|
if(dwAdd_WidthTable) // 154639
|
|
cfUFM.Write(InsertZero, dwAdd_WidthTable);
|
|
cfUFM.Write(&wdt, sizeof wdt);
|
|
|
|
cfUFM.Write(m_cwaWidth.GetData(),
|
|
(unsigned)(m_cwaWidth.GetSize() * sizeof (WORD)));
|
|
}
|
|
else // DBCS - 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, // Add a run to the table
|
|
sizeof (WIDTHRUN));
|
|
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 =
|
|
(DWORD)(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 = (DWORD)cbaTable.GetSize();
|
|
for (u = 0; u < pwdt->dwRunNum; u++)
|
|
pwdt->WidthRun[u].loCharWidthOffset += pwdt->dwSize;
|
|
|
|
if(dwAdd_WidthTable) // 154639
|
|
cfUFM.Write(InsertZero, dwAdd_WidthTable);
|
|
|
|
cfUFM.Write(pwdt, pwdt -> dwSize); // write width table
|
|
for (u = 0; u < pwdt -> dwRunNum; u++)
|
|
cfUFM.Write(cwaSize.GetData() +
|
|
pwdt -> WidthRun[u].wStartGlyph - 1,
|
|
pwdt -> WidthRun[u].wGlyphCount * sizeof (WORD));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------------------
|
|
if (CanKern()) // Kern Pairs
|
|
{
|
|
// 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;
|
|
|
|
if(dwAdd_KerPair) // 154639
|
|
cfUFM.Write(InsertZero, dwAdd_KerPair);
|
|
|
|
cfUFM.Write(&kd, 0xFFFC & (sizeof kd - sizeof kd.KernPair));
|
|
|
|
for (unsigned u = 0; u < m_csoaKern.GetSize(); u++) {
|
|
CKern *pck = (CKern *) m_csoaKern[u] ;
|
|
WCHAR wcf = pck->First() ;
|
|
WCHAR wcs = pck->Second() ;
|
|
short sa = pck->Amount() ;
|
|
((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;
|
|
}
|
|
if(!bStoreFormWokspace) //raid 244123
|
|
Changed(FALSE);
|
|
return TRUE; // Return triumphant to whoever deigned to need this service.
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
CFontInfo::StoreGTTCPOnly
|
|
|
|
When a UFM is loaded during a workspace load and the UFM does not have a
|
|
valid GTT or CP, the UFM cannot be saved normally because there are several
|
|
parts of the UFM that were not loaded correctly or at all because of the
|
|
missing data.
|
|
|
|
When this situation is detected, this routine is called so the - supposedly -
|
|
good info in the disk file is not overwritten by bad data. In addition,
|
|
Store() will blow when it tries to use nonexistent UFM data.
|
|
|
|
This routine will just save the what we hope is corrected GTT and/or CP data.
|
|
This is done without changing any of the other data in the file. Next, the
|
|
UFM is reloaded. If all goes well, the UFM is correctly loaded so that
|
|
normal editting and saving can be performed from this point on.
|
|
|
|
TRUE is returned if the GTT and CP are successfully saved. Otherwise, FALSE
|
|
is returned.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CFontInfo::StoreGTTCPOnly(LPCTSTR lpstrFile)
|
|
{
|
|
// Remind the user about what is going to happen.
|
|
|
|
AfxMessageBox(IDS_GTTCPOnlySaved, MB_ICONINFORMATION) ;
|
|
|
|
// Perform the steps required to update the GTT/CP in the UFM file.
|
|
|
|
try {
|
|
// Begin by opening the file in a way that will not truncate existing
|
|
// files.
|
|
|
|
UINT nopenflags = CFile::modeNoTruncate | CFile::modeCreate ;
|
|
nopenflags |= CFile::modeWrite | CFile::shareExclusive ;
|
|
CFile cfufm(lpstrFile, nopenflags) ;
|
|
|
|
// Seek to the file positon that we want change.
|
|
|
|
UNIFM_HDR ufmh ;
|
|
DWORD dwseekpos ;
|
|
dwseekpos = (DWORD)PtrToUlong(&ufmh.ulDefaultCodepage) - (DWORD)PtrToUlong(&ufmh) ;
|
|
cfufm.Seek(dwseekpos, CFile::begin) ;
|
|
|
|
// Load the fields in the UFM header that we want to save and write
|
|
// them out.
|
|
|
|
ufmh.ulDefaultCodepage = m_ulDefaultCodepage ;
|
|
ufmh.lGlyphSetDataRCID = m_lGlyphSetDataRCID ;
|
|
UINT nwritebytes = sizeof(ufmh.ulDefaultCodepage)
|
|
+ sizeof(ufmh.lGlyphSetDataRCID) ;
|
|
cfufm.Write((void*) &ufmh.ulDefaultCodepage, nwritebytes) ;
|
|
|
|
// Move the file pointer to the end of the file and close it.
|
|
|
|
cfufm.SeekToEnd() ;
|
|
cfufm.Close() ;
|
|
}
|
|
catch (CException *pce) {
|
|
pce->ReportError() ;
|
|
pce->Delete() ;
|
|
return FALSE ;
|
|
} ;
|
|
Changed(FALSE) ;
|
|
|
|
// If the UFM was loaded from a workspace, try to use the workspace data to
|
|
// find and load a pointer to the new GTT and finish loading the font.
|
|
|
|
m_pcgmTranslation = NULL ;
|
|
if (m_bLoadedByWorkspace) {
|
|
CDriverResources* pcdr = (CDriverResources*) GetWorkspace() ;
|
|
if (pcdr)
|
|
pcdr->LinkAndLoadFont(*this, false) ;
|
|
else
|
|
Load(false) ;
|
|
|
|
// If the UFM was loaded stand alone the first time, reload it the same way
|
|
// and let the load routine handle finding the GTT info.
|
|
|
|
} else
|
|
Load(false) ;
|
|
|
|
// If reloading the UFM successfully associated a GTT or CP with the UFM,
|
|
// clear the m_bWSLoadButNoGTTCP flag. Then tell the user that the UFM
|
|
// can be editted normally now.
|
|
|
|
if (m_pcgmTranslation) {
|
|
SetNoGTTCP(false) ;
|
|
CString csmsg ;
|
|
csmsg.Format(IDS_UFMOKNow, Name()) ;
|
|
AfxMessageBox(csmsg, MB_ICONINFORMATION) ;
|
|
} ;
|
|
|
|
// All went well so...
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
CFontInfo::CreateEditor
|
|
|
|
This member function launches an editing view for the font.
|
|
|
|
******************************************************************************/
|
|
|
|
CMDIChildWnd* CFontInfo::CreateEditor()
|
|
{
|
|
CFontInfoContainer* pcficMe= new CFontInfoContainer(this, FileName());
|
|
|
|
pcficMe -> SetTitle(m_pcbnWorkspace -> Name() + _TEXT(": ") + Name()); // Make up a cool title
|
|
|
|
CMDIChildWnd *pcmcwNew;
|
|
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::GetFontSimDataPtr
|
|
|
|
Return a pointer to the requested font simulation data.
|
|
|
|
******************************************************************************/
|
|
|
|
CWordArray* CFontInfo::GetFontSimDataPtr(int nid)
|
|
{
|
|
switch (nid) {
|
|
case ItalicDiff:
|
|
if (m_pcfdItalic == NULL)
|
|
ASSERT(0) ;
|
|
return m_pcfdItalic->GetFontSimDataPtr() ;
|
|
case BoldDiff:
|
|
if (m_pcfdBold == NULL)
|
|
ASSERT(0) ;
|
|
return m_pcfdBold->GetFontSimDataPtr() ;
|
|
case BothDiff:
|
|
if (m_pcfdBoth == NULL)
|
|
ASSERT(0) ;
|
|
return m_pcfdBoth->GetFontSimDataPtr() ;
|
|
default:
|
|
ASSERT(0) ;
|
|
} ;
|
|
|
|
// This point should never be reached.
|
|
|
|
return NULL ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
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;
|
|
|
|
if (bOn == !!pcfd && pcfdTarget == pcfd) return; // Clear out any irrelevant calls
|
|
|
|
if (bOn && pcfdTarget) // If this call is just to init pcfd, do it and leave
|
|
{
|
|
pcfd = pcfdTarget;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
if (bOn)
|
|
// pcfd = pcfdTarget = pcfd ? pcfd : new CFontDifference(m_wWeight, m_wMaximumIncrement, m_wAverageWidth, // rm ori
|
|
// uSim == BoldDiff ? m _cwaSpecial[ItalicAngle] : 175, this);
|
|
|
|
pcfd = pcfdTarget = pcfd ? pcfd : new CFontDifference(m_IFIMETRICS.usWinWeight, m_IFIMETRICS.fwdMaxCharInc, m_IFIMETRICS.fwdAveCharWidth,
|
|
uSim == BoldDiff ? m_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::LoadBadKerningInfo
|
|
|
|
Check the kerning pairs to see if they reference code points that are not in
|
|
the UFM's GTT. If any are found, load them into the specified list control.
|
|
Return true if any bad kerning pairs were found. Otherwise, return false.
|
|
|
|
******************************************************************************/
|
|
|
|
bool CFontInfo::LoadBadKerningInfo(CListCtrl& clcbaddata)
|
|
{
|
|
// Declare the variables needed to check for bad kerning data
|
|
|
|
unsigned unumkerns = m_csoaKern.GetSize() ;
|
|
CString cs ;
|
|
bool bfoundbad = false ;
|
|
|
|
// Loop through each kerning class and check it.
|
|
|
|
for (unsigned u = 0 ; u < unumkerns ; u++) {
|
|
CKern& ckThis = *(CKern *) m_csoaKern[u] ;
|
|
|
|
// If each code point in this kerning pair is still a valid code point
|
|
// for the GTT, skip this kerning pair.
|
|
|
|
if (CodePointInGTT(ckThis.First()) && CodePointInGTT(ckThis.Second()))
|
|
continue ;
|
|
|
|
// Add this kerning pair's data to the list of bad data.
|
|
|
|
cs.Format("%d", ckThis.Amount()) ;
|
|
int idItem = clcbaddata.InsertItem(u, cs) ;
|
|
clcbaddata.SetItemData(idItem, u) ;
|
|
|
|
cs.Format("0x%X", ckThis.First()) ;
|
|
clcbaddata.SetItem(idItem, 1, LVIF_TEXT, cs, -1, 0, 0, u) ;
|
|
|
|
cs.Format("0x%X", ckThis.Second()) ;
|
|
clcbaddata.SetItem(idItem, 2, LVIF_TEXT, cs, -1, 0, 0, u) ;
|
|
|
|
bfoundbad = true ;
|
|
} ;
|
|
|
|
return bfoundbad ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfo::CodePointInGTT
|
|
|
|
Return true if the specified code point is in the GTT. Otherwise, return
|
|
false.
|
|
|
|
******************************************************************************/
|
|
|
|
bool CFontInfo::CodePointInGTT(WORD wcodepoint)
|
|
{
|
|
int nelts = (int)m_cpaGlyphs.GetSize() ;// Number of elements in glyphs array
|
|
int nleft, nright, ncheck ; // Variables needed to search array
|
|
WORD wgttcp ;
|
|
|
|
// Try to find the codepoint in the GTT
|
|
|
|
for (nleft = 0, nright = nelts - 1 ; nleft <= nright ; ) {
|
|
ncheck = (nleft + nright) >> 1 ;
|
|
|
|
wgttcp = ((CGlyphHandle *) m_cpaGlyphs[ncheck])->CodePoint() ;
|
|
//TRACE("Key[%d] = '0x%x', CP = '0x%x'\n", ncheck, wgttcp, wcodepoint) ;
|
|
|
|
if (wgttcp > wcodepoint)
|
|
nright = ncheck - 1 ;
|
|
else if (wgttcp < wcodepoint)
|
|
nleft = ncheck + 1 ;
|
|
else
|
|
return true ; //*** Return true here if match found.
|
|
} ;
|
|
|
|
// Return false here because no match found.
|
|
|
|
return false ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
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::MakeKernCopy
|
|
|
|
Make a copy of the kerning pairs table.
|
|
|
|
******************************************************************************/
|
|
|
|
void CFontInfo::MakeKernCopy()
|
|
{
|
|
// Find out how many entries are in the kerning pairs table.
|
|
|
|
int numkerns = m_csoaKern.GetSize() ;
|
|
|
|
// Get rid of any entries already in the kerning copy table and set it to
|
|
// the correct size.
|
|
|
|
m_csoaKernCopy.RemoveAll() ;
|
|
m_csoaKernCopy.SetSize(numkerns) ;
|
|
|
|
// Copy the kerning pairs table entries one at a time so that a new CKern
|
|
// class instance can be allocated, initialized, and saved.
|
|
|
|
CKern* pck ;
|
|
for (int n = 0 ; n < numkerns ; n++) {
|
|
pck = new CKern(((CKern*) m_csoaKern[n])->First(),
|
|
((CKern*) m_csoaKern[n])->Second(),
|
|
((CKern*) m_csoaKern[n])->Amount()) ;
|
|
m_csoaKernCopy.SetAt(n, pck) ;
|
|
} ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
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((int)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%04X", cghThis.CodePoint());
|
|
clcView.SetItem(idItem, 1, LVIF_TEXT, csWork, -1, 0, 0, u);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfo::WidthsTableIsOK
|
|
|
|
Perform the only consistency check on the widths table that I can think of:
|
|
Make sure that there aren't more widths in the UFM than there are Glyphs in
|
|
the GTT. Return true if the table appears to be ok. Otherwise, return false.
|
|
|
|
******************************************************************************/
|
|
|
|
bool CFontInfo::WidthsTableIsOK()
|
|
{
|
|
return (m_cwaWidth.GetSize() <= m_cpaGlyphs.GetSize()) ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
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 and the user
|
|
requests it.
|
|
|
|
******************************************************************************/
|
|
|
|
void CFontInfo::SetWidth(unsigned uGlyph, WORD wWidth, bool bcalc /*=true*/)
|
|
{
|
|
m_cwaWidth[uGlyph] = wWidth;
|
|
|
|
if (bcalc && !DBCSFont())
|
|
CalculateWidths();
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfo::CompareGlyphsEx(WORD wOld, WORD wNew, CLinkedList* pcll)
|
|
|
|
to Do ; check the old glyph table and new, then change the old linked list
|
|
according to the new glyph table.
|
|
|
|
parameter : wOld, wNew ; code point index of new, old glyph table
|
|
CLinkedList* pcll ; linked node containing the codepoint data
|
|
|
|
return : new linked list of new gtt.
|
|
|
|
******************************************************************************/
|
|
|
|
CLinkedList* CFontInfo::CompareGlyphsEx(WORD wOld, WORD wNew, CLinkedList* pcll)
|
|
{ // pcll
|
|
static UINT_PTR dwLinked ;
|
|
static CLinkedList* pcllpre = NULL ;
|
|
static CLinkedList* pclltmp = NULL ;
|
|
static int ncOldGlyphs ;
|
|
static int ncNewGlyphs ;
|
|
|
|
if (wOld == 0 && wNew == 0 ) {
|
|
dwLinked = (UINT_PTR)pcll ;
|
|
ncNewGlyphs = (int)m_cwaNewGlyphs.GetSize() ;
|
|
ncOldGlyphs = (int)m_cwaOldGlyphs.GetSize() ;
|
|
|
|
}
|
|
if (wNew >= ncNewGlyphs && wOld >= ncOldGlyphs ) {
|
|
pcllpre = NULL ;
|
|
return (CLinkedList*) dwLinked;
|
|
}
|
|
|
|
// delete at the end of the glyphs tree
|
|
if (wOld < ncOldGlyphs && wNew >= ncNewGlyphs ) {
|
|
pcllpre = pcll->Next ;
|
|
delete pcll ;
|
|
return CompareGlyphsEx(++wOld,wNew,pcllpre) ;
|
|
}
|
|
|
|
// add at the end of the glyphs tree
|
|
// BUG_BUG :: this is called at the second end of the code points.
|
|
// added coded is located between seconde end and first end. // almost fixed.
|
|
if (wNew < ncNewGlyphs && wOld >= ncOldGlyphs - 1 && m_cwaOldGlyphs[wOld] <= m_cwaNewGlyphs[wNew] ) {
|
|
|
|
CLinkedList* pcllnew = new CLinkedList ;
|
|
if (!pcllnew) {
|
|
CString csError ;
|
|
csError.LoadString(IDS_ResourceError) ;
|
|
AfxMessageBox(csError,MB_ICONEXCLAMATION) ;
|
|
return (CLinkedList*) dwLinked;
|
|
}
|
|
pcllnew->data = 0 ;
|
|
pcll->Next = pcllnew ;
|
|
return CompareGlyphsEx(wOld,++wNew,pcll->Next) ;
|
|
|
|
}
|
|
|
|
// Delete
|
|
if (m_cwaOldGlyphs[wOld] < m_cwaNewGlyphs[wNew] ) {
|
|
|
|
if (!pcllpre || (pcllpre == pcll) ) {
|
|
pcllpre = pcll->Next ;
|
|
dwLinked = (UINT_PTR)pcllpre ;
|
|
delete pcll ;
|
|
return CompareGlyphsEx(++wOld, wNew,pcllpre) ;
|
|
|
|
}
|
|
else{
|
|
if (pclltmp && pclltmp->Next == pcllpre->Next )
|
|
pcllpre = pclltmp ;
|
|
pcllpre->Next = pcll->Next ;
|
|
delete pcll ;
|
|
return CompareGlyphsEx(++wOld, wNew,pcllpre->Next ) ;
|
|
}
|
|
}// Add
|
|
else if (m_cwaOldGlyphs[wOld] > m_cwaNewGlyphs[wNew] ) {
|
|
CLinkedList * pcllnew = new CLinkedList ;
|
|
|
|
pcllnew->data = 0 ;
|
|
if (!pcllpre) {
|
|
dwLinked = (UINT_PTR) pcllnew ;
|
|
pcllpre = pcllnew ;
|
|
pcllnew ->Next = pcll ;
|
|
}
|
|
else { // problem when pcllnew->next == pcll
|
|
if (pclltmp && pclltmp == pcllpre->Next )
|
|
pcllpre = pclltmp ;
|
|
pcllnew ->Next = pcllpre->Next ;
|
|
|
|
pcllpre->Next = pcllnew ;
|
|
pclltmp = pcllnew ;
|
|
|
|
}
|
|
return CompareGlyphsEx(wOld, ++wNew,pcllnew ->Next) ;
|
|
} // no change
|
|
else {
|
|
pcllpre = pcll ;
|
|
return CompareGlyphsEx(++wOld,++wNew,pcll->Next ) ;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfo::CheckReloadWidths
|
|
|
|
It is possible that the code points in the UFM's GTT have changed. If that
|
|
is the case, reload the widths info so that they can use the new code point
|
|
info.
|
|
|
|
Return true if the widths were reloaded. Otherwise, return false.
|
|
|
|
NOTE: This function uses several pieces of CFontInfo::Load(). If changes
|
|
are made to those pieces of code, similar changes may need be made in Load()
|
|
too.
|
|
|
|
sunggch : Modify the code in order to synchronize the Widthtable with
|
|
GTT change (add or delete code point)
|
|
Get m_cwaWidth from the CompareGlyphsEx instead of UFM load table
|
|
******************************************************************************/
|
|
|
|
DWORD CLinkedList::m_dwSize ;
|
|
#define MAX_CODE_COUNT 1000
|
|
bool CFontInfo::CheckReloadWidths()
|
|
{
|
|
// Do nothing if this class was loaded standalone or it has no GTT pointer.
|
|
|
|
if (!m_bLoadedByWorkspace || m_pcgmTranslation == NULL)
|
|
return false ;
|
|
|
|
// Do nothing if the GTT has not changes since the last time the UFM's
|
|
// widths were reloaded.
|
|
|
|
if (m_pcgmTranslation->m_ctSaveTimeStamp <= m_ctReloadWidthsTimeStamp && !IsRCIDChanged())
|
|
return false ;
|
|
|
|
// Open the UFM file
|
|
|
|
CFile cfUFM ;
|
|
if (!cfUFM.Open(m_cfn.FullName(), CFile::modeRead | CFile::shareDenyWrite))
|
|
return false ;
|
|
|
|
// Try to load the file- proclaim defeat on any exception.
|
|
|
|
CByteArray cbaUFM ; // Loaded with file's contents
|
|
try {
|
|
cbaUFM.SetSize(cfUFM.GetLength()) ;
|
|
cfUFM.Read(cbaUFM.GetData(), (unsigned)cbaUFM.GetSize()) ;
|
|
}
|
|
catch (CException *pce) {
|
|
pce->ReportError() ;
|
|
pce->Delete() ;
|
|
return false ;
|
|
} ;
|
|
|
|
PUNIFM_HDR pufmh = (PUNIFM_HDR) cbaUFM.GetData() ; // UNIFM_HDR
|
|
|
|
// Do nothing if there is no width table except update the timestamp so that
|
|
// this code isn't executed again.
|
|
|
|
if (pufmh->loWidthTable == NULL) {
|
|
m_ctReloadWidthsTimeStamp = CTime::GetCurrentTime() ;
|
|
return false ;
|
|
} ;
|
|
|
|
union {
|
|
PBYTE pbwt ;
|
|
PWIDTHTABLE pwt ;
|
|
} ;
|
|
|
|
pbwt = cbaUFM.GetData() + pufmh->loWidthTable ;
|
|
|
|
// Synchronization of UFM width and Gtt is only supported in the SBCS.
|
|
// BUG_BUG : the interupt happend in the DBCS gtt.
|
|
int oldGlyphs = PtrToInt((PVOID)m_cpaGlyphs.GetSize());
|
|
m_pcgmTranslation->Collect(m_cpaGlyphs) ;
|
|
|
|
m_cwaNewGlyphs.SetSize(m_cpaGlyphs.GetSize()) ;
|
|
|
|
if (!DBCSFont() && m_cpaGlyphs.GetSize() < MAX_CODE_COUNT && oldGlyphs < MAX_CODE_COUNT && m_cwaOldGlyphs.GetSize()) {
|
|
|
|
for (int i = 0 ; i < m_cpaGlyphs.GetSize() ; i ++ ) {
|
|
CGlyphHandle& cghThis = *(CGlyphHandle *) m_cpaGlyphs[i];
|
|
m_cwaNewGlyphs.SetAt(i,cghThis.CodePoint() ) ;
|
|
}
|
|
CLinkedList* pcll = new CLinkedList ;
|
|
CLinkedList* pcll_pre = NULL ;
|
|
UINT_PTR dwLinked = (UINT_PTR) pcll ;
|
|
|
|
// convert WordArray into LinkedList
|
|
for( i = 0 ; i < m_cwaWidth.GetSize() ; i ++ ) {
|
|
pcll->data = m_cwaWidth[i];
|
|
pcll->Next = new CLinkedList ; // at the end of array, it create redundant one more CLinkedList;
|
|
pcll = pcll->Next ;
|
|
}
|
|
|
|
dwLinked = (UINT_PTR)CompareGlyphsEx(0,0,(CLinkedList* )dwLinked) ;
|
|
|
|
int size = CLinkedList::Size() ;
|
|
|
|
m_cwaWidth.RemoveAll() ;
|
|
m_cwaWidth.SetSize(m_cwaNewGlyphs.GetSize()) ;
|
|
ASSERT(size >= m_cwaNewGlyphs.GetSize() ) ;
|
|
|
|
CLinkedList* pgarbage = NULL ;
|
|
for ( pcll =(CLinkedList*) dwLinked, i = 0 ; i < m_cwaNewGlyphs.GetSize() ; i++ ,pgarbage=pcll, pcll = pcll->Next ) {
|
|
m_cwaWidth[i] = pcll->data ;
|
|
delete pgarbage;
|
|
}
|
|
|
|
|
|
m_cwaOldGlyphs.RemoveAll();
|
|
m_cwaOldGlyphs.Copy(m_cwaNewGlyphs) ;
|
|
|
|
}
|
|
else {
|
|
|
|
// Collect all the handles
|
|
|
|
m_pcgmTranslation->Collect(m_cpaGlyphs) ;
|
|
m_cwaWidth.RemoveAll() ;
|
|
|
|
if (m_cpaGlyphs.GetSize() > 0)
|
|
m_cwaWidth.InsertAt(0, 0, m_cpaGlyphs.GetSize()) ;
|
|
|
|
unsigned uWidth = (unsigned)m_cwaWidth.GetSize();
|
|
unsigned uWidthIdx ;
|
|
|
|
// Build the widths table.
|
|
|
|
for (unsigned u = 0; u < pwt->dwRunNum; u++) {
|
|
PWORD pwWidth = (PWORD) (pbwt + pwt->WidthRun[u].loCharWidthOffset) ;
|
|
|
|
unsigned uGlyph = 0 ;
|
|
for ( ; uGlyph < pwt->WidthRun[u].wGlyphCount ; uGlyph++) {
|
|
// For whatever reason, there are times when the index value is
|
|
// < 0 or > uWidth. An AV would occur if m_cwaWidth were allowed
|
|
// to be indexed by such a value. Just keep this from happening
|
|
// for now. A better fix is needed. BUG_BUG : won't fix
|
|
|
|
// Glyph handles start at 1, not 0!
|
|
|
|
uWidthIdx = uGlyph + -1 + pwt->WidthRun[u].wStartGlyph ;
|
|
if ((int) uWidthIdx < 0) {
|
|
//AfxMessageBox("Negative width table index") ;
|
|
//TRACE("***Negative width table index (%d) found in %s. Table size=%d uGlyph=%d wGlyphCount=%d wStartGlyph=%d u=%d dwRunNum=%d\n", uWidthIdx, Name(), uWidth, uGlyph, pwt->WidthRun[u].wGlyphCount, pwt->WidthRun[u].wStartGlyph, u, pwt->dwRunNum) ;
|
|
continue ;
|
|
} else if (uWidthIdx >= uWidth) {
|
|
//AfxMessageBox("Width table index (%d) > table size") ;
|
|
//TRACE("***Width table index (%d) > table size (%d) found in %s. Table size=%d uGlyph=%d wGlyphCount=%d wStartGlyph=%d u=%d dwRunNum=%d\n", uWidthIdx, uWidth, Name(), uWidth, uGlyph, pwt->WidthRun[u].wGlyphCount, pwt->WidthRun[u].wStartGlyph, u, pwt->dwRunNum) ;
|
|
break ; // rm fix VC IDE compiler problem?
|
|
} ;
|
|
|
|
//m_cwaWidth[uGlyph + -1 + pwt->WidthRun[u].wStartGlyph] = *pwWidth++; // Glyph handles start at 1, not 0!
|
|
m_cwaWidth[uWidthIdx] = *pwWidth++;
|
|
} ;
|
|
} ;
|
|
|
|
}
|
|
// The widths were successfully reloaded so update the reload time and
|
|
// return true.
|
|
|
|
m_ctReloadWidthsTimeStamp = CTime::GetCurrentTime() ;
|
|
return true ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfo::GetFirstPFM
|
|
CFontInfo::GetLastPFM
|
|
|
|
******************************************************************************/
|
|
|
|
WORD CFontInfo::GetFirstPFM()
|
|
{
|
|
res_PFMHEADER *pPFM ;
|
|
pPFM = (res_PFMHEADER *) m_cbaPFM.GetData() ;
|
|
return ((WORD) pPFM->dfFirstChar) ;
|
|
//return ((WORD) ((res_PFMHEADER *) m_cbaPFM.GetData())->dfFirstChar) ;
|
|
}
|
|
|
|
WORD CFontInfo::GetLastPFM()
|
|
{
|
|
res_PFMHEADER *pPFM ;
|
|
pPFM = (res_PFMHEADER *) m_cbaPFM.GetData() ;
|
|
return ((WORD) pPFM->dfLastChar) ;
|
|
//return ((WORD) ((res_PFMHEADER *) m_cbaPFM.GetData())->dfLastChar) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
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.
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfoContainer::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); // raid 104822 temp
|
|
// return FALSE;
|
|
|
|
return m_pcfi && CDocument::OnNewDocument();// raid 104822 temp
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfoContainer::~CFontInfoContainer
|
|
|
|
Our erstwhile destructor must destroy the font info if this wasn't an
|
|
embedded view; ie, the UFM was loaded standalone.
|
|
|
|
It should also destroy the font's GTT iff the UFM was loaded standalone and
|
|
the GTT was based on a real, file-based GTT; not a code page loaded as a GTT
|
|
and not one of the predefined, built-in GTTs. (In the latter case, the
|
|
predefined GTTs are freed when the program exits.)
|
|
|
|
******************************************************************************/
|
|
|
|
CFontInfoContainer::~CFontInfoContainer()
|
|
{
|
|
if (!m_bEmbedded && m_pcfi) {
|
|
int ngttid = (int) (short) m_pcfi->m_lGlyphSetDataRCID ;
|
|
|
|
if (m_pcfi->m_pcgmTranslation && ngttid != 0)
|
|
if ((ngttid < CGlyphMap::Wansung || ngttid > CGlyphMap::Big5)
|
|
&& (ngttid < CGlyphMap::CodePage863 || ngttid > CGlyphMap::CodePage437)
|
|
&& ngttid != -IDR_CP1252)
|
|
delete m_pcfi->m_pcgmTranslation ;
|
|
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::SaveModified
|
|
|
|
o If the file is saved, get rid of the copy of the kerning pairs table.
|
|
Otherwise, restore the saved copy of the original kerning pairs table.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CFontInfoContainer::SaveModified()
|
|
{
|
|
m_UFMSaved = false ; // No save attempt made yet.
|
|
|
|
// If the file needs to be saved prompt the user about it and do it if the
|
|
// user concurs. Save the result so I can tell if the document is going
|
|
// to close.
|
|
|
|
BOOL bclose = CDocument::SaveModified() ;
|
|
|
|
// If the doc is not closing, just return bclose without doing anything
|
|
// else.
|
|
|
|
if (!bclose)
|
|
return bclose ;
|
|
|
|
// If the file was saved, the kerning table copy is no longer needed so zap
|
|
// it in a way that will free all associated memory.
|
|
|
|
if (m_UFMSaved)
|
|
m_pcfi->m_csoaKernCopy.RemoveAll() ;
|
|
|
|
// Otherwise, the user wants to revert back to the original kern copy. So,
|
|
// zap the kerning table and replace it with the copy.
|
|
|
|
else {
|
|
m_pcfi->m_csoaKern.RemoveAll() ; // This frees ALL associated memory
|
|
m_pcfi->m_csoaKern.Copy(m_pcfi->m_csoaKernCopy) ;
|
|
|
|
// Now clear the copy in a way that will not delete the class instances
|
|
// referenced by it because copies of those pointers are in m_csoaKern
|
|
// now.
|
|
|
|
CObArray* pcoacopy = m_pcfi->m_csoaKernCopy.GetCOA() ;
|
|
pcoacopy->RemoveAll() ;
|
|
} ;
|
|
|
|
// Return whatever CDocument::SaveModified() returned.
|
|
|
|
return bclose ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfoContainer::PublicSaveModified
|
|
|
|
The Class Wizard made SaveModified() a protected class and I didn't want to
|
|
change that. Instead, I added this routine so that outsiders can call it.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CFontInfoContainer::PublicSaveModified()
|
|
{
|
|
return (SaveModified()) ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
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. (Actually saving the UFM is the last --
|
|
ie, final -- thing this routine does.)
|
|
|
|
Before the document is actually saved, validate the contents of the UFM. If
|
|
the UFM passes all of the checks or the user doesn't want to fix the problems,
|
|
continue processing. Otherwise, return FALSE to make sure the document is
|
|
left open.
|
|
|
|
Once the UFM has been validated, copy the data in the UFM Editor's controls
|
|
back into the CFontInfo class instance. New data is maintain in the editor
|
|
until this point so that the CFontInfo class instance is not updated
|
|
unnecessarily. That would be a problem since the UFMs are always kept
|
|
loaded in CFontInfo class instances. That means that even unsaved data that
|
|
the user wanted to discard would still be displayed the next time the UFM
|
|
is loaded into the editor. Keeping unsaved data in the editor allows it to
|
|
be discarded without affecting the CFontInfo class so the problem is avoided.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CFontInfoContainer::OnSaveDocument(LPCTSTR lpszPathName)
|
|
{
|
|
// Get a pointer to the associate view class instance.
|
|
|
|
POSITION pos = GetFirstViewPosition() ;
|
|
ASSERT(pos != NULL) ;
|
|
CFontViewer* pcfv = (CFontViewer*) GetNextView(pos) ;
|
|
|
|
// Call the view class to validate the UFM's contents. If one of the
|
|
// checks fails and the user wants to fix it, do not close the document.
|
|
|
|
// if rcid changed, upgraded the Widthtable.
|
|
if (m_pcfi->IsRCIDChanged() && m_bEmbedded)
|
|
pcfv->HandleCPGTTChange(true) ;
|
|
|
|
// validate the value of the UFMs
|
|
if (pcfv != NULL && pcfv->ValidateSelectedUFMDataFields())
|
|
return FALSE ;
|
|
|
|
|
|
// Update the UFM's fields with the new data in the editor.
|
|
|
|
if (pcfv != NULL && pcfv->SaveEditorDataInUFM())
|
|
return FALSE ;
|
|
|
|
m_UFMSaved = true ; // Indicate that an attempt to save will be made
|
|
|
|
return m_pcfi -> Store(lpszPathName);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CFontInfoContainer::OnOpenDocument
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CFontInfoContainer::OnOpenDocument(LPCTSTR lpstrFile)
|
|
{
|
|
// SetFileName() is just called to set a few variables. (Since the file
|
|
// exists, we don't need to do a creation check.)
|
|
|
|
m_pcfi->m_cfn.EnableCreationCheck(FALSE) ;
|
|
m_pcfi->SetFileName(lpstrFile) ;
|
|
|
|
// Load the UFM and mark it as a file that cannot be saved. That is the
|
|
// case when a UFM is loaded standalone because its associated GTT is not
|
|
// loaded too. (Some data that is saved in the UFM comes from the GTT.)
|
|
|
|
return m_pcfi->Load(false) ;
|
|
}
|
|
|
|
|
|
|
|
|