summaryrefslogtreecommitdiff
path: root/Build/source/libs/graphite/engine-2.4/src/segment/FontFace.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/graphite/engine-2.4/src/segment/FontFace.cpp')
-rw-r--r--Build/source/libs/graphite/engine-2.4/src/segment/FontFace.cpp596
1 files changed, 596 insertions, 0 deletions
diff --git a/Build/source/libs/graphite/engine-2.4/src/segment/FontFace.cpp b/Build/source/libs/graphite/engine-2.4/src/segment/FontFace.cpp
new file mode 100644
index 00000000000..e16e15237e6
--- /dev/null
+++ b/Build/source/libs/graphite/engine-2.4/src/segment/FontFace.cpp
@@ -0,0 +1,596 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrEngine.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description: Contains the implementation of the FontFace class.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+#include <functional>
+#ifdef _MSC_VER
+#pragma hdrstop
+#pragma warning (disable: 4706) // assignment within conditional expression
+#endif
+// any other headers (not precompiled)
+
+//:End Ignore
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+FontCache * FontFace::s_pFontCache = 0;
+
+//:>********************************************************************************************
+//:> New interface
+//:>********************************************************************************************
+/*----------------------------------------------------------------------------------------------
+ Return the appropriate FontFace, initialized with Graphite tables.
+ Called from the font constructor.
+----------------------------------------------------------------------------------------------*/
+FontFace * FontFace::GetFontFace(Font * pfont,
+ std::wstring strFaceName, bool fBold, bool fItalic,
+ bool fDumbFallback)
+{
+ if (s_pFontCache == NULL)
+ s_pFontCache = new FontCache;
+
+ FontFace * pfface;
+ s_pFontCache->GetFontFace(strFaceName, fBold, fItalic, &pfface);
+ if (pfface)
+ return pfface;
+
+ // Create a new font face.
+ pfface = new FontFace();
+ pfface->InitFontFace(pfont, strFaceName, fBold, fItalic, fDumbFallback);
+ return pfface;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize the engine using the given Graphite font.
+----------------------------------------------------------------------------------------------*/
+GrResult FontFace::InitFontFace(Font * pfont,
+ std::wstring stuFaceName, bool fBold, bool fItalic,
+ bool fDumbFallback)
+{
+ AssertPtrN(pfont);
+
+ m_pgreng = new GrEngine;
+ m_pgreng->m_pfface = this;
+
+ m_pgreng->m_nScriptTag = 0; // not currently used, but set it to something
+
+ std::wstring stuFeatures;
+
+ //stuFeatures = stuFeaturesArg;
+
+ if (wcscmp(stuFaceName.c_str(), m_pgreng->m_stuFaceName.c_str()) != 0)
+ {
+ s_pFontCache->RemoveFontFace(m_pgreng->FaceName(), m_pgreng->Bold(), m_pgreng->Italic());
+
+ m_pgreng->DestroyEverything(); // nothing we've cached is safe or useful.
+ m_pgreng->m_stuFaceName = stuFaceName; // if this is buggy, using assign might fix it
+ }
+
+ //GrResult res = kresFail;
+//#ifdef GR_FW
+// // Read from the control file indicated by the registry, if any.
+// std::wstring stuFaceNameTmp;
+// stuFaceNameTmp.assign(rgchFaceName, wcslen(rgchFaceName));
+// res = InitFromControlFile(pfont, stuFaceName.c_str(), fBold, fItalic);
+//#endif // GR_FW
+
+ // Read directly from the font.
+ m_pgreng->DestroyContents();
+ GrResult res = kresUnexpected;
+ try {
+ res = m_pgreng->ReadFontTables(pfont, fItalic);
+ }
+ catch (...)
+ {
+ if (fDumbFallback && m_pgreng->DumbFallback() && !m_pgreng->BadFont())
+ {
+ // If we have a basically good font but can't do Graphite,
+ // just go with empty tables, which should be set up.
+ res = m_pgreng->m_resFontRead;
+ }
+ else
+ {
+ if (m_cfonts == 0)
+ {
+ //s_pFontCache->DeleteIfEmpty();
+ //Assert(s_pFontCache == 0);
+ delete this; // will also delete GrEngine
+ }
+ else
+ {
+ delete m_pgreng;
+ }
+ m_pgreng = NULL;
+ throw; // throw original exception
+ }
+ }
+
+ m_pgreng->m_resFontValid = res;
+
+ m_pgreng->m_fBold = fBold;
+ m_pgreng->m_fItalic = fItalic;
+
+ s_pFontCache->CacheFontFace(m_pgreng->FaceName(), fBold, fItalic, this);
+
+ return m_pgreng->m_resFontValid;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the cmap and Graphite tables from the font that is selected into the graphics
+ device.
+
+ @return A GrResult indicating whether we were successful in loading the Graphite font:
+ - kresOk means success
+ - kresFail means the Graphite font could not be found or the basic font tables
+ (head, name, cmap) could not be loaded
+ - kresUnexpected means the Graphite tables could not be loaded
+ - kresFalse means it is not a Graphite font at all (has no Silf table).
+----------------------------------------------------------------------------------------------*/
+GrResult GrEngine::ReadFontTables(Font * pfont, bool fItalic)
+{
+ GrResult res = kresOk;
+ m_ferr = kferrOkay;
+ GrBufferIStream grstrm;
+
+ FontException fexptn;
+ fexptn.version = -1;
+ fexptn.subVersion = -1;
+
+ bool fOk = false;
+
+ const void * pHeadTbl; const void * pSileTbl; const void * pSilfTbl;
+ const void * pFeatTbl; const void * pGlatTbl; const void * pGlocTbl; const void * pSillTbl;
+ //const void * pCmapTbl; const void * pNameTbl;
+ size_t cbHeadSz, cbSilfSz, cbFeatSz, cbGlatSz, cbGlocSz, cbSillSz;
+ //size_t cbCmapSz, cbSileSz, cbNameSz;
+
+ m_fFakeItalic = false;
+
+ bool fBasicTables = false;
+ bool fSilf = false; // does the font have some sort of Silf table?
+ int nCheckSum = 0;
+
+ bool fBadBase = false,
+ fMismatchedBase = false,
+ fFontIsItalic = false;
+
+ // First read the head table. This gives us the checksum that we are using as a
+ // unique identifer. If it is the same as the one stored, and things appear set up,
+ // don't reload the tables.
+ res = (pHeadTbl = pfont->getTable(TtfUtil::TableIdTag(ktiHead), &cbHeadSz)) ? kresOk : kresFail;
+ fOk = pHeadTbl && (cbHeadSz == 0 || TtfUtil::CheckTable(ktiHead, pHeadTbl, cbHeadSz));
+ if (res == kresFail)
+ {
+ m_stuInitError = L"could not locate head table for Graphite rendering";
+ m_ferr = kferrFindHeadTable;
+ goto LUnexpected;
+ }
+ if (!fOk)
+ {
+ m_stuInitError = L"could not read design units for Graphite rendering";
+ m_ferr = kferrReadDesignUnits;
+ goto LUnexpected;
+ }
+ m_mFontEmUnits = TtfUtil::DesignUnits(pHeadTbl);
+ nCheckSum = TtfUtil::HeadTableCheckSum(pHeadTbl);
+ fFontIsItalic = TtfUtil::IsItalic(pHeadTbl);
+
+ if (m_nFontCheckSum == nCheckSum && m_ptman)
+ return m_resFontRead; // already initialized in some form
+
+ DestroyContents();
+
+ Assert(!m_ptman);
+ Assert(!m_pctbl);
+ Assert(!m_pgtbl);
+ Assert(!m_prgpsd);
+ m_prgpsd = NULL;
+ m_cpsd = 0;
+
+ m_ptman = new GrTableManager(this);
+
+ m_fFakeItalic = (fItalic && !fFontIsItalic);
+
+ // Look for an Sile table. If there is one, this is an extension font containing only
+ // the Graphite tables. Read the base font name out of the Sile table, and use it to
+ // read the cmap. Then replace the original font name to read the Graphite tables.
+
+ m_fUseSepBase = false;
+ m_stuBaseFaceName.erase();
+
+ // TODO: rework the handling of the Sile table.
+ pSileTbl = NULL;
+ //pSileTbl = pfont->getTable(TtfUtil::TableIdTag(ktiSile));
+ //if (pSileTbl)
+ //{
+ // pgg->get_FontCharProperties(&chrpOriginal);
+ // grstrm.OpenBuffer(pSileTbl, sile_tbl.size());
+ // m_fUseSepBase = ReadSileTable(pgg, grstrm, 0, &m_mFontEmUnits, &fMismatchedBase);
+ // grstrm.Close();
+
+ // if (!m_fUseSepBase)
+ // {
+ // SwitchGraphicsFont(pgg, false); // back to Graphite table font
+ // m_stuBaseFaceName.erase();
+ // fBadBase = true;
+ // m_fUseSepBase = false;
+ // }
+ // // Otherwise leave the GrGraphics in a state to read from the base font.
+ //}
+
+ // We don't need the offset table, and there's no way to get it anyway
+ // without a font file.
+
+ // cmap and name
+ Assert(!m_fCmapTblCopy);
+ Assert(!m_fNameTblCopy);
+ fOk = SetCmapAndNameTables(pfont);
+ if (!fOk)
+ {
+ goto LUnexpected;
+ }
+
+ fBasicTables = true;
+
+ // If we have a bad base file, don't do Graphite stuff.
+ if (fBadBase || fMismatchedBase)
+ goto LUnexpected;
+
+ /****
+ Obtain font name from InitNew() now instead of reading from font file. InitNew should
+ should have a correct font name passed to it since it should come from a font registered
+ by GrFontInst.exe. This commented code could be use to verify name in font file matches.
+ NOTE: if we ever use this code again, make sure we're using the base font name table,
+ not the Graphite wrapper font name table.
+ // find the font family name
+ if (!TtfUtil::Get31EngFamilyInfo(vbName.Begin(), lnNameOff, lnNameSz))
+ { // use Name table which is Symbol encode instead
+ // this could cause problems if a real Symbol writing system is used in the name table
+ // however normally real Unicode values are used instead a Symbol writing system
+ if (!TtfUtil::Get30EngFamilyInfo(vbName.Begin(), lnNameOff, lnNameSz))
+ {
+ ReturnResult(kresFail);
+ }
+ // test for Symbol writing system. first byte of Unicode id should be 0xF0
+ if (vbName[lnNameOff + 1] == (unsigned char)0xF0) // 1 - Unicode id is big endian
+ ReturnResult(kresFail);
+ }
+ if (!TtfUtil::SwapWString(vbName.Begin() + lnNameOff, lnNameSz / sizeof(utf16)))
+ ReturnResult(kresFail);
+
+ m_stuFaceName = std::wstring((utf16 *)(vbName.begin() + lnNameOff), lnNameSz / sizeof(utf16));
+ ****/
+
+ // Silf
+ res = (pSilfTbl = pfont->getTable(TtfUtil::TableIdTag(ktiSilf), &cbSilfSz)) ? kresOk : kresFail;
+ fOk = pSilfTbl && (cbSilfSz == 0 || TtfUtil::CheckTable(ktiSilf, pSilfTbl, cbSilfSz));
+ if (!fOk)
+ {
+ m_stuInitError = L"could not load Silf table for Graphite rendering";
+ m_ferr = kferrLoadSilfTable;
+ goto LUnexpected;
+ }
+
+ // Feat
+ res = (pFeatTbl = pfont->getTable(TtfUtil::TableIdTag(ktiFeat), &cbFeatSz)) ? kresOk : kresFail;
+ fOk = pFeatTbl && (cbFeatSz == 0 || TtfUtil::CheckTable(ktiFeat, pFeatTbl, cbFeatSz));
+ if (!fOk)
+ {
+ // TODO: just create an empty set of features, since this is not disastrous.
+ m_stuInitError = L"could not load Feat table for Graphite rendering";
+ m_ferr = kferrLoadFeatTable;
+ goto LUnexpected;
+ }
+
+ // Glat
+ res = (pGlatTbl = pfont->getTable(TtfUtil::TableIdTag(ktiGlat), &cbGlatSz)) ? kresOk : kresFail;
+ fOk = pGlatTbl && (cbGlatSz == 0 || TtfUtil::CheckTable(ktiGlat, pGlatTbl, cbGlatSz));
+ if (!fOk)
+ {
+ m_stuInitError = L"could not load Glat table for Graphite rendering";
+ m_ferr = kferrLoadGlatTable;
+ goto LUnexpected;
+ }
+
+ // Gloc
+ res = (pGlocTbl = pfont->getTable(TtfUtil::TableIdTag(ktiGloc), &cbGlocSz)) ? kresOk : kresFail;
+ fOk = pGlocTbl && (cbGlocSz == 0 || TtfUtil::CheckTable(ktiGloc, pGlocTbl, cbGlocSz));
+ if (!fOk)
+ {
+ m_stuInitError = L"could not load Gloc table for Graphite rendering";
+ m_ferr = kferrLoadGlocTable;
+ goto LUnexpected;
+ }
+
+ // Sill
+ try {
+ res = (pSillTbl = pfont->getTable(TtfUtil::TableIdTag(ktiSill), &cbSillSz)) ? kresOk : kresFail;
+ fOk = pSillTbl && (cbSillSz == 0 || TtfUtil::CheckTable(ktiSill, pSillTbl, cbSillSz));
+ }
+ catch (...)
+ {
+ fOk = true;
+ pSillTbl = NULL;
+ }
+ // if table couldn't be loaded, this is not disastrous.
+
+// ibGlocStart = cbGlatTbl;
+ fOk = CheckTableVersions(&grstrm,
+ (const byte *)pSilfTbl, 0,
+ (const byte *)pGlocTbl, 0,
+ (const byte *)pFeatTbl, 0,
+ &m_fxdBadVersion);
+ if (!fOk)
+ {
+// wchar_t rgch1[50];
+// wchar_t rgch2[50];
+//#if defined(_WIN32)
+// // This version does not work in Windows, in spite of being documented:
+// // swprintf(rgch, 50, L"%d", (m_fxdBadVersion >> 16));
+// // Removing the size argument make it work.
+// swprintf(rgch1, L"%d", (m_fxdBadVersion >> 16));
+// swprintf(rgch2, L"%d", (m_fxdBadVersion & 0x0000FFFF));
+//#else
+// swprintf(rgch1, 50, L"%d", (m_fxdBadVersion >> 16));
+// swprintf(rgch2, 50, L"%d", (m_fxdBadVersion & 0x0000FFFF));
+//#endif
+ char rgch[50]; // more than enough space to print two 16-bit ints
+ char *pch = &rgch[0];
+ sprintf(rgch, "%d.%d", (m_fxdBadVersion >> 16), (m_fxdBadVersion & 0x0000FFFF));
+ std::wstring stu = L"unsupported version (";
+ //stu.append(rgch1);
+ //stu.append(L".");
+ //stu.append(rgch2);
+ while (*pch != 0)
+ stu.push_back((wchar_t)*pch++);
+ stu.append(L") of Graphite tables");
+ m_stuInitError.assign(stu.c_str());
+ m_ferr = kferrBadVersion;
+ goto LUnexpected;
+ }
+
+ try
+ {
+ // Parse the "Silf" table.
+ grstrm.OpenBuffer((const byte*)pSilfTbl, cbSilfSz);
+ int chwGlyphIDMax, fxdVersion;
+ bool f = ReadSilfTable(grstrm, 0, 0, cbSilfSz, &chwGlyphIDMax, &fxdVersion);
+ grstrm.Close();
+ if (!f)
+ {
+ m_ferr = kferrReadSilfTable;
+ fexptn.errorCode = m_ferr;
+ throw fexptn;
+ }
+
+ // Parse the "Gloc" and "Glat" tables.
+ {
+ GrBufferIStream grstrmGlat;
+
+ grstrm.OpenBuffer((const byte *)pGlocTbl, cbGlocSz);
+ grstrmGlat.OpenBuffer((const byte *)pGlatTbl, cbGlatSz);
+ f = ReadGlocAndGlatTables(grstrm, 0, grstrmGlat, 0, chwGlyphIDMax, fxdVersion);
+ grstrm.Close();
+ grstrmGlat.Close();
+ if (!f)
+ {
+ m_ferr = kferrReadGlocGlatTable;
+ fexptn.errorCode = m_ferr;
+ throw fexptn;
+ }
+ }
+
+ // Parse the "Feat" table.
+ grstrm.OpenBuffer((const byte *)pFeatTbl, cbFeatSz);
+ f = ReadFeatTable(grstrm, 0);
+ grstrm.Close();
+ if (!f)
+ {
+ m_ferr = kferrReadFeatTable;
+ fexptn.errorCode = m_ferr;
+ throw fexptn;
+ }
+
+ // Parse the "Sill" table.
+ if (pSillTbl)
+ {
+ grstrm.OpenBuffer((const byte *)pSillTbl, cbSillSz);
+ f = ReadSillTable(grstrm, 0);
+ grstrm.Close();
+ if (!f)
+ {
+ m_ferr = kferrReadSillTable;
+ fexptn.errorCode = m_ferr;
+ throw fexptn;
+ }
+ }
+ else
+ m_langtbl.CreateEmpty();
+ }
+ catch (...)
+ {
+ fSilf = false;
+ m_resFontRead = kresUnexpected;
+ try {
+ DestroyContents(false);
+ }
+ catch (...)
+ {}
+ goto LUnexpected;
+ }
+
+ m_stuErrCtrlFile.erase();
+ m_nFontCheckSum = nCheckSum;
+ m_resFontRead = kresOk;
+ m_ferr = kferrOkay;
+ ReturnResult(kresOk);
+
+LUnexpected:
+ // Don't do this, because it is possible to use a base font with an empty Graphite
+ // engine:
+ //if (m_fUseSepBase || m_stuBaseFaceName.Length() > 0)
+ //{
+ // SwitchGraphicsFont(pgg, false); // back to Graphite table font
+ // m_stuBaseFaceName.erase();
+ // m_fUseSepBase = false;
+ //}
+
+ CreateEmpty();
+ m_nFontCheckSum = nCheckSum;
+ if (!fBasicTables)
+ m_resFontRead = kresFail; // bad font
+ else if (!fSilf)
+ m_resFontRead = kresFalse; // no Silf table--not a Graphite font
+ else
+ m_resFontRead = kresUnexpected; // couldn't read the Graphite tables
+
+ fexptn.errorCode = m_ferr;
+ fexptn.version = m_fxdBadVersion >> 16;
+ fexptn.subVersion = m_fxdBadVersion & 0x0000FFFF;
+ throw fexptn;
+
+ ReturnResult(m_resFontRead);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Read the cmap and name tables.
+
+ This is called from two places. One is when we first initialize the engine. Also, if the
+ font tables have not been actually copied from the font, they may have been deleted
+ when the font was deleted. So when reusing the engine, set them to something valid based
+ on the current font.
+----------------------------------------------------------------------------------------------*/
+bool GrEngine::SetCmapAndNameTables(Font * pfont)
+{
+ GrResult res = kresOk;
+ bool fOk;
+ const void * pCmapTbl;
+ const void * pNameTbl;
+ size_t cbCmapSz, cbNameSz;
+
+ // cmap
+ if (!m_fCmapTblCopy)
+ {
+ res = (pCmapTbl = pfont->getTable(TtfUtil::TableIdTag(ktiCmap), &cbCmapSz)) ? kresOk : kresFail;
+ fOk = pCmapTbl && (cbCmapSz == 0 || TtfUtil::CheckTable(ktiCmap, pCmapTbl, cbCmapSz));
+ if (!fOk)
+ {
+ m_stuInitError = L"could not locate cmap table";
+ m_ferr = kferrFindCmapTable;
+ return false;
+ }
+
+ if (pCmapTbl && cbCmapSz > 0)
+ {
+ // Make a private copy of the cmap for the engine's use.
+ m_pCmapTbl = new byte[cbCmapSz];
+ std::copy(reinterpret_cast<const byte*>(pCmapTbl),
+ reinterpret_cast<const byte*>(pCmapTbl) + cbCmapSz, m_pCmapTbl);
+ m_fCmapTblCopy = true;
+ m_cbCmapTbl = cbCmapSz;
+ }
+ else
+ {
+ m_pCmapTbl = const_cast<byte*>(reinterpret_cast<const byte*>(pCmapTbl));
+ m_fCmapTblCopy = false;
+ }
+
+ // MS Unicode cmap
+ m_pCmap_3_1 = TtfUtil::FindCmapSubtable(m_pCmapTbl, 3, 1);
+ m_pCmap_3_10 = TtfUtil::FindCmapSubtable(m_pCmapTbl, 3, 10);
+ if (!m_pCmap_3_1)
+ m_pCmap_3_1 = TtfUtil::FindCmapSubtable(m_pCmapTbl, 3, 0);
+ if (!m_pCmap_3_1)
+ {
+ m_stuInitError = L"failure to load cmap subtable";
+ m_ferr = kferrLoadCmapSubtable;
+ return false;
+ }
+ if (!TtfUtil::CheckCmap31Subtable(m_pCmap_3_1))
+ {
+ m_stuInitError = L"checking cmap subtable failed";
+ m_ferr = kferrCheckCmapSubtable;
+ return false;
+ }
+ }
+ else
+ {
+ Assert(m_pCmapTbl);
+ }
+
+ // name table - eventually need feature label strings
+
+ // Currently the only stuff we're getting from the name table are our feature names,
+ // so use the version from the Graphite font (not the base font if any).
+ //////if (m_fUseSepBase)
+ ////// pgg->SetupGraphics(&chrpOriginal);
+
+ if (!m_fNameTblCopy)
+ {
+ res = (pNameTbl = (const byte *)pfont->getTable(TtfUtil::TableIdTag(ktiName), &cbNameSz)) ? kresOk : kresFail;
+ fOk = pNameTbl && (cbNameSz == 0 || TtfUtil::CheckTable(ktiName, pNameTbl, cbNameSz));
+ if (!fOk)
+ {
+ m_stuInitError = L"could not locate name table";
+ m_ferr = kferrFindNameTable;
+ return false;
+ }
+
+ if (pNameTbl && cbNameSz > 0)
+ {
+ // Make a private copy of the name table for the engine's use.
+ m_pNameTbl = new byte[cbNameSz];
+ std::copy(reinterpret_cast<const byte*>(pNameTbl),
+ reinterpret_cast<const byte*>(pNameTbl) + cbNameSz, m_pNameTbl);
+ m_fNameTblCopy = true;
+ m_cbNameTbl = cbNameSz;
+ }
+ else
+ {
+ m_pNameTbl = const_cast<byte*>(reinterpret_cast<const byte*>(pNameTbl));
+ m_fNameTblCopy = false;
+ }
+ }
+ else
+ {
+ Assert(m_pNameTbl);
+ }
+
+ return true;
+}
+
+
+//void FontFace::DbgCheckFontFace()
+//{
+// Assert(m_cfonts < 5000);
+// Assert(m_cfonts >= 0);
+// wchar_t chw0 = m_pgreng->m_stuFaceName[0];
+// Assert(chw0 >= 0x0040); // A
+// Assert(chw0 <= 0x007A); // z
+//}
+
+} // namespace gr
+
+//:End Ignore