mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-10 23:03:14 +08:00
581 lines
16 KiB
C++
581 lines
16 KiB
C++
/*
|
|
* (c) Copyright Ascensio System SIA 2010-2023
|
|
*
|
|
* This program is a free software product. You can redistribute it and/or
|
|
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
|
* version 3 as published by the Free Software Foundation. In accordance with
|
|
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
|
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
|
* of any third-party rights.
|
|
*
|
|
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
|
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
|
*
|
|
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
|
* street, Riga, Latvia, EU, LV-1050.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of the Program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU AGPL version 3.
|
|
*
|
|
* Pursuant to Section 7(b) of the License you must retain the original Product
|
|
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
|
* grant you any rights under trademark law for use of our trademarks.
|
|
*
|
|
* All the Product's GUI elements, including illustrations and icon sets, as
|
|
* well as technical writing content are licensed under the terms of the
|
|
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
|
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
*
|
|
*/
|
|
#include "FontCidTT.h"
|
|
#include "Document.h"
|
|
#include "Streams.h"
|
|
#include "Utils.h"
|
|
#include "FontTTWriter.h"
|
|
|
|
#include "../../DesktopEditor/graphics/pro/Fonts.h"
|
|
#include "../../DesktopEditor/common/File.h"
|
|
|
|
#include <string>
|
|
|
|
#include FT_TRUETYPE_TABLES_H
|
|
|
|
namespace PdfWriter
|
|
{
|
|
static const char* c_sToUnicodeHeader = "/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n";
|
|
static const char* c_sToUnicodeInfo = "/CIDSystemInfo\n<< /Registry (Adobe)\n /Ordering (UCS)\n /Supplement 0\n >> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n1 begincodespacerange\n<0000> <FFFF>\nendcodespacerange\n";
|
|
static const char* c_sToUnicodeFooter = "endcmap\nCMapName currentdict /CMap defineresource pop\nend\nend\n";
|
|
|
|
static int GetSymbolicCmapIndex(FT_Face pFace)
|
|
{
|
|
TT_OS2 *pOs2 = (TT_OS2 *)FT_Get_Sfnt_Table(pFace, ft_sfnt_os2);
|
|
if (NULL == pOs2 || 0xFFFF == pOs2->version)
|
|
return -1;
|
|
|
|
// Check if bit 31 is set
|
|
if (!(pOs2->ulCodePageRange1 & 0x80000000) && !(pOs2->ulCodePageRange1 == 0 && pOs2->ulCodePageRange2 == 0))
|
|
return -1;
|
|
|
|
|
|
for (int nIndex = 0; nIndex < pFace->num_charmaps; nIndex++)
|
|
{
|
|
// Symbol
|
|
if (0 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id)
|
|
return nIndex;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
// CFontFileBase
|
|
//----------------------------------------------------------------------------------------
|
|
CFontCidTrueType::CFontCidTrueType(CXref* pXref, CDocument* pDocument, const std::wstring& wsFontPath, unsigned int unIndex, CFontFileTrueType* pFontTT) : CFontDict(pXref, pDocument)
|
|
{
|
|
m_bNeedAddFontName = true;
|
|
m_pFontFile = pFontTT;
|
|
|
|
m_wsFontPath = wsFontPath;
|
|
m_unFontIndex = unIndex;
|
|
|
|
Add("Type", "Font");
|
|
Add("Subtype", "Type0");
|
|
Add("Encoding", "Identity-H");
|
|
|
|
CDictObject* pFont = new CDictObject();
|
|
m_pXref->Add(pFont);
|
|
|
|
CArrayObject* pDescendantFonts = new CArrayObject();
|
|
pDescendantFonts->Add(pFont);
|
|
|
|
Add("DescendantFonts", pDescendantFonts);
|
|
CDictObject* pToUnicodeDict = new CDictObject(m_pXref);
|
|
Add("ToUnicode", pToUnicodeDict);
|
|
pToUnicodeDict->SetFilter(STREAM_FILTER_FLATE_DECODE);
|
|
m_pToUnicodeStream = pToUnicodeDict->GetStream();
|
|
|
|
CreateCIDFont(pFont);
|
|
if (pFontTT->GetOpenTypeCFF())
|
|
CreateCIDFont0(pFont);
|
|
else
|
|
CreateCIDFont2(pFont);
|
|
|
|
m_pFace = NULL;
|
|
m_pFaceMemory = NULL;
|
|
m_nGlyphsCount = 0;
|
|
m_nSymbolicCmap = -1;
|
|
m_ushCodesCount = 0;
|
|
}
|
|
CFontCidTrueType::~CFontCidTrueType()
|
|
{
|
|
if (m_pFontFile)
|
|
delete m_pFontFile;
|
|
|
|
if (m_pFace)
|
|
FT_Done_Face(m_pFace);
|
|
|
|
if (m_pFaceMemory)
|
|
delete[] m_pFaceMemory;
|
|
}
|
|
void CFontCidTrueType::CreateCIDFont(CDictObject* pFont)
|
|
{
|
|
m_pFont = pFont;
|
|
pFont->Add("Type", "Font");
|
|
|
|
CDictObject* pSystemInfo = new CDictObject();
|
|
pSystemInfo->Add("Registry", new CStringObject("Adobe"));
|
|
pSystemInfo->Add("Ordering", new CStringObject("Identity"));
|
|
pSystemInfo->Add("Supplement", 0);
|
|
|
|
pFont->Add("CIDSystemInfo", pSystemInfo);
|
|
|
|
CDictObject* pFontDescriptor = new CDictObject();
|
|
// FontDescriptor must be a reference
|
|
m_pXref->Add(pFontDescriptor);
|
|
pFontDescriptor->Add("Type", "FontDescriptor");
|
|
m_pFontDescriptor = pFontDescriptor;
|
|
|
|
// Set Symbolic bit and clear NonSymbolic bit
|
|
unsigned int nFlags = 0;
|
|
if (!(nFlags & 4))
|
|
UIntChangeBit(nFlags, 2);
|
|
if (nFlags & 32)
|
|
UIntChangeBit(nFlags, 4);
|
|
|
|
pFontDescriptor->Add("Flags", nFlags);
|
|
|
|
if (m_pFontFile)
|
|
{
|
|
CArrayObject* pBBox = new CArrayObject();
|
|
int* pFontBBox = m_pFontFile->GetBBox();
|
|
pBBox->Add(pFontBBox[0]);
|
|
pBBox->Add(pFontBBox[1]);
|
|
pBBox->Add(pFontBBox[2]);
|
|
pBBox->Add(pFontBBox[3]);
|
|
pFontDescriptor->Add("FontBBox", pBBox);
|
|
}
|
|
pFontDescriptor->Add("ItalicAngle", 0);
|
|
pFontDescriptor->Add("Ascent", m_pFontFile ? m_pFontFile->GetAscent() : 1000);
|
|
pFontDescriptor->Add("Descent", m_pFontFile ? m_pFontFile->GetDescent() : -500);
|
|
pFontDescriptor->Add("CapHeight", m_pFontFile ? m_pFontFile->GetCapHeight() : 800);
|
|
pFontDescriptor->Add("StemV", 0);
|
|
pFontDescriptor->Add("FontWeight", m_pFontFile ? m_pFontFile->GetWeight() : 400);
|
|
|
|
m_pFontFileDict = new CDictObject(m_pXref);
|
|
|
|
pFont->Add("FontDescriptor", pFontDescriptor);
|
|
}
|
|
void CFontCidTrueType::CreateCIDFont0(CDictObject* pFont)
|
|
{
|
|
pFont->Add("Subtype", "CIDFontType0");
|
|
|
|
pFont->Add("DW", 1000);
|
|
|
|
m_pFontDescriptor->Add("FontFile3", m_pFontFileDict);
|
|
|
|
m_pFontDescriptor->Add("CIDSet", new CDictObject(m_pXref));
|
|
}
|
|
void CFontCidTrueType::CreateCIDFont2(CDictObject* pFont)
|
|
{
|
|
pFont->Add("Subtype", "CIDFontType2");
|
|
|
|
m_pFontDescriptor->Add("FontFile2", m_pFontFileDict);
|
|
|
|
CDictObject* pCIDToGIDMapDict = new CDictObject(m_pXref);
|
|
pFont->Add("CIDToGIDMap", pCIDToGIDMapDict);
|
|
pCIDToGIDMapDict->SetFilter(STREAM_FILTER_FLATE_DECODE);
|
|
m_pCidToGidMapStream = pCIDToGIDMapDict->GetStream();
|
|
|
|
if (m_pXref->IsPDFA())
|
|
{
|
|
//pFontDescriptor->Add("CIDSet", new CDictObject(m_pXref));
|
|
}
|
|
}
|
|
bool CFontCidTrueType::HaveChar(const unsigned int &unUnicode)
|
|
{
|
|
if (!OpenFontFace())
|
|
return false;
|
|
|
|
return (!!GetGID(m_pFace, unUnicode));
|
|
}
|
|
unsigned int CFontCidTrueType::GetChar(const unsigned int &unUnicode)
|
|
{
|
|
if (!OpenFontFace())
|
|
return 0;
|
|
|
|
return GetGID(m_pFace, unUnicode);
|
|
}
|
|
unsigned int CFontCidTrueType::GetWidth(unsigned short ushCode)
|
|
{
|
|
if (ushCode >= m_vWidths.size())
|
|
return 0;
|
|
|
|
return m_vWidths.at(ushCode);
|
|
}
|
|
unsigned int CFontCidTrueType::GetGlyphWidth(unsigned short ushCode)
|
|
{
|
|
if (ushCode >= m_vGlypWidths.size())
|
|
return 0;
|
|
|
|
return m_vGlypWidths.at(ushCode);
|
|
}
|
|
bool CFontCidTrueType::IsItalic()
|
|
{
|
|
if (!OpenFontFace() || !m_pFace)
|
|
return false;
|
|
|
|
return ((m_pFace->style_flags & FT_STYLE_FLAG_ITALIC) != 0);
|
|
}
|
|
bool CFontCidTrueType::IsBold()
|
|
{
|
|
if (!OpenFontFace() || !m_pFace)
|
|
return false;
|
|
|
|
TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(m_pFace, ft_sfnt_os2);
|
|
if (pOS2 && pOS2->version != 0xFFFF && pOS2->usWeightClass >= 800)
|
|
return true;
|
|
|
|
return ((m_pFace->style_flags & FT_STYLE_FLAG_BOLD) != 0);
|
|
}
|
|
void CFontCidTrueType::BeforeWrite()
|
|
{
|
|
if (m_pFontDescriptor)
|
|
{
|
|
CDictObject* pCIDSet = (CDictObject*)m_pFontDescriptor->Get("CIDSet");
|
|
if (pCIDSet)
|
|
{
|
|
#ifndef FILTER_FLATE_DECODE_DISABLED
|
|
pCIDSet->SetFilter(STREAM_FILTER_FLATE_DECODE);
|
|
#endif
|
|
CStream* pStream = pCIDSet->GetStream();
|
|
|
|
unsigned int unBytes = (m_ushCodesCount) / 8;
|
|
|
|
if (unBytes * 8 < m_ushCodesCount)
|
|
unBytes++;
|
|
|
|
if (1 == unBytes)
|
|
{
|
|
BYTE nValue = 0xFF;
|
|
nValue = (BYTE)(nValue << (8 - m_ushCodesCount));
|
|
nValue &= 0x7F;
|
|
pStream->WriteChar(nValue);
|
|
}
|
|
else
|
|
{
|
|
BYTE nStartValue = 0x7F, nMidValue = 0xFF;
|
|
pStream->WriteChar(nStartValue);
|
|
|
|
for (unsigned int unIndex = 0; unIndex < unBytes - 2; ++unIndex)
|
|
{
|
|
pStream->WriteChar(nMidValue);
|
|
}
|
|
|
|
BYTE nEndValue = 0xFF;
|
|
nEndValue = (BYTE)(nEndValue << (unBytes * 8 - m_ushCodesCount));
|
|
|
|
pStream->WriteChar(nEndValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_pFontFile)
|
|
{
|
|
unsigned short* pCodeToGid;
|
|
unsigned int* pWidths;
|
|
unsigned char* pGlyphs;
|
|
unsigned int unGlyphsCount;
|
|
|
|
if (!GetWidthsAndGids(&pCodeToGid, &pWidths, &pGlyphs, unGlyphsCount))
|
|
return;
|
|
|
|
CStream* pStream = m_pFontFileDict->GetStream();
|
|
m_pFontFile->WriteTTF(pStream, NULL, pCodeToGid, m_ushCodesCount, pGlyphs, unGlyphsCount);
|
|
m_pFontFileDict->SetFilter(STREAM_FILTER_FLATE_DECODE);
|
|
|
|
CArrayObject* pWArray = new CArrayObject();
|
|
m_pFont->Add("W", pWArray);
|
|
pWArray->Add(0);
|
|
CArrayObject* pWidthsArray = new CArrayObject();
|
|
pWArray->Add(pWidthsArray);
|
|
for (unsigned short ushIndex = 0; ushIndex < m_ushCodesCount; ushIndex++)
|
|
{
|
|
pWidthsArray->Add(pWidths[ushIndex]);
|
|
}
|
|
|
|
if (!m_pFontFile->GetOpenTypeCFF())
|
|
{
|
|
m_pFontFileDict->Add("Length1", pStream->Size());
|
|
|
|
pStream = m_pCidToGidMapStream;
|
|
for (unsigned short ushCode = 0; ushCode < m_ushCodesCount; ushCode++)
|
|
{
|
|
unsigned short ushGid = pCodeToGid[ushCode];
|
|
pStream->WriteChar(((ushGid >> 8) & 0xFF));
|
|
pStream->WriteChar((ushGid & 0xFF));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pFont->Add("DW", pWidths[0]);
|
|
m_pFontFileDict->Add("Subtype", "CIDFontType0C");
|
|
}
|
|
|
|
RELEASEARRAYOBJECTS(pCodeToGid);
|
|
RELEASEARRAYOBJECTS(pWidths);
|
|
RELEASEARRAYOBJECTS(pGlyphs);
|
|
|
|
WriteToUnicode();
|
|
}
|
|
}
|
|
bool CFontCidTrueType::GetWidthsAndGids(unsigned short** ppCodeToGid, unsigned int** ppWidths, unsigned char** ppGlyphs, unsigned int& unGlyphsCount)
|
|
{
|
|
*ppCodeToGid = NULL;
|
|
*ppWidths = NULL;
|
|
*ppGlyphs = NULL;
|
|
unGlyphsCount = 0;
|
|
|
|
if (!m_nGlyphsCount)
|
|
return false;
|
|
|
|
unsigned short* pCodeToGID = new unsigned short[m_ushCodesCount];
|
|
if (!pCodeToGID)
|
|
return false;
|
|
|
|
unsigned int* pWidths = new unsigned int[m_ushCodesCount];
|
|
if (!pWidths)
|
|
{
|
|
delete[] pCodeToGID;
|
|
return false;
|
|
}
|
|
memset((void*)pWidths, 0x00, m_ushCodesCount * sizeof(unsigned int));
|
|
|
|
for (unsigned short ushCode = 0; ushCode < m_ushCodesCount; ushCode++)
|
|
{
|
|
pCodeToGID[ushCode] = m_vCodeToGid.at(ushCode);
|
|
pWidths[ushCode] = m_vWidths.at(ushCode);
|
|
}
|
|
|
|
unsigned char *pGlyphs = new unsigned char[m_nGlyphsCount];
|
|
if (!pGlyphs)
|
|
{
|
|
delete[] pCodeToGID;
|
|
delete[] pWidths;
|
|
return false;
|
|
}
|
|
|
|
memset((void *)pGlyphs, 0x00, m_nGlyphsCount * sizeof(unsigned char));
|
|
if (m_nGlyphsCount >= m_mGlyphs.size())
|
|
{
|
|
for (auto oIt : m_mGlyphs)
|
|
{
|
|
pGlyphs[oIt.first] = 1;
|
|
}
|
|
}
|
|
|
|
*ppCodeToGid = pCodeToGID;
|
|
*ppWidths = pWidths;
|
|
*ppGlyphs = pGlyphs;
|
|
unGlyphsCount = m_nGlyphsCount;
|
|
return true;
|
|
}
|
|
void CFontCidTrueType::WriteToUnicode()
|
|
{
|
|
CStream* pS = m_pToUnicodeStream;
|
|
|
|
pS->WriteStr(c_sToUnicodeHeader);
|
|
pS->WriteStr(c_sToUnicodeInfo);
|
|
|
|
int pCodesCount = pS->Tell();
|
|
int nCodesCount = 0;
|
|
pS->WriteInt(m_ushCodesCount);
|
|
pS->WriteStr(" beginbfchar\n");
|
|
for (unsigned short ushCode = 0; ushCode < m_ushCodesCount; ushCode++)
|
|
{
|
|
if (!m_mGlyphs[m_vCodeToGid[ushCode]])
|
|
continue;
|
|
pS->WriteChar('<');
|
|
pS->WriteHex(ushCode, 4);
|
|
pS->WriteStr("> <");
|
|
for (unsigned int i = 0, nLen = m_vUnicodes[ushCode].size(); i < nLen; i++)
|
|
{
|
|
unsigned int unUnicode = m_vUnicodes[ushCode][i];
|
|
if (unUnicode < 0x10000)
|
|
{
|
|
pS->WriteHex(unUnicode, 4);
|
|
}
|
|
else
|
|
{
|
|
unUnicode = unUnicode - 0x10000;
|
|
|
|
unsigned short ushLo = 0xDC00 | (unUnicode & 0x3FF);
|
|
unsigned short ushHi = 0xD800 | (unUnicode >> 10);
|
|
|
|
pS->WriteHex(ushHi, 4);
|
|
pS->WriteHex(ushLo, 4);
|
|
}
|
|
}
|
|
|
|
pS->WriteStr(">\n");
|
|
nCodesCount++;
|
|
}
|
|
pS->WriteStr("endbfchar\n");
|
|
pS->WriteStr(c_sToUnicodeFooter);
|
|
pS->Seek(pCodesCount, SeekSet);
|
|
pS->WriteInt(nCodesCount);
|
|
}
|
|
void CFontCidTrueType::CloseFontFace()
|
|
{
|
|
if (m_pFace)
|
|
{
|
|
FT_Done_Face(m_pFace);
|
|
m_pFace = NULL;
|
|
}
|
|
|
|
RELEASEARRAYOBJECTS(m_pFaceMemory);
|
|
}
|
|
bool CFontCidTrueType::OpenFontFace()
|
|
{
|
|
if (m_pFace)
|
|
{
|
|
m_pDocument->AddFreeTypeFont(this);
|
|
return true;
|
|
}
|
|
|
|
m_nGlyphsCount = 0;
|
|
m_nSymbolicCmap = -1;
|
|
|
|
FT_Library pLibrary = m_pDocument->GetFreeTypeLibrary();
|
|
if (!pLibrary)
|
|
return false;
|
|
|
|
DWORD dwFileSize;
|
|
m_pFaceMemory = NULL;
|
|
NSFile::CFileBinary::ReadAllBytes(m_wsFontPath, &m_pFaceMemory, dwFileSize);
|
|
if (!m_pFaceMemory)
|
|
return false;
|
|
|
|
FT_New_Memory_Face(pLibrary, m_pFaceMemory, dwFileSize, m_unFontIndex, &m_pFace);
|
|
|
|
if (!m_pFace)
|
|
{
|
|
RELEASEARRAYOBJECTS(m_pFaceMemory);
|
|
return false;
|
|
}
|
|
|
|
m_pDocument->AddFreeTypeFont(this);
|
|
m_nGlyphsCount = m_pFace->num_glyphs;
|
|
m_nSymbolicCmap = GetSymbolicCmapIndex(m_pFace);
|
|
|
|
if (m_bNeedAddFontName)
|
|
{
|
|
// Add font name to all necessary dictionaries and fill in descriptor
|
|
std::string sFontName = m_pDocument->GetTTFontTag();
|
|
sFontName += (m_pFace->family_name ? std::string(m_pFace->family_name) : std::string());
|
|
if (m_pFace->style_flags & FT_STYLE_FLAG_ITALIC)
|
|
sFontName += "-Italic";
|
|
if (m_pFace->style_flags & FT_STYLE_FLAG_BOLD)
|
|
sFontName += "-Bold";
|
|
|
|
const char* sName = sFontName.c_str();
|
|
|
|
Add("BaseFont", sName);
|
|
m_pFont->Add("BaseFont", sName);
|
|
m_pFontDescriptor->Add("FontName", sName);
|
|
m_bNeedAddFontName = false;
|
|
|
|
m_pFontFile->SetName(sFontName);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
unsigned short CFontCidTrueType::EncodeUnicode(const unsigned int &unUnicode)
|
|
{
|
|
std::map<unsigned int, unsigned short>::const_iterator oIter = m_mUnicodeToCode.find(unUnicode);
|
|
if (oIter != m_mUnicodeToCode.end())
|
|
return oIter->second;
|
|
|
|
unsigned int unGID = GetGID(m_pFace, unUnicode);
|
|
if (0 == unGID && -1 != m_nSymbolicCmap)
|
|
unGID = GetGID(m_pFace, unUnicode + 0xF000);
|
|
|
|
unsigned short ushCode = EncodeGID(unGID, &unUnicode, 1);
|
|
m_mUnicodeToCode.insert(std::pair<unsigned int, unsigned short>(unUnicode, ushCode));
|
|
return ushCode;
|
|
}
|
|
unsigned short CFontCidTrueType::EncodeGID(const unsigned int& unGID, const unsigned int* pUnicodes, const unsigned int& unCount)
|
|
{
|
|
for (unsigned short ushCurCode = 0, ushCodesCount = m_vCodeToGid.size(); ushCurCode < ushCodesCount; ushCurCode++)
|
|
{
|
|
if (unGID == m_vCodeToGid.at(ushCurCode))
|
|
{
|
|
if (m_vUnicodes.at(ushCurCode).empty() && unCount)
|
|
{
|
|
std::vector<unsigned int> vUnicodes;
|
|
for (unsigned int i = 0; i < unCount; i++)
|
|
vUnicodes.push_back(pUnicodes[i]);
|
|
m_vUnicodes[ushCurCode] = vUnicodes;
|
|
m_mGlyphs[unGID] = true;
|
|
}
|
|
return ushCurCode;
|
|
}
|
|
}
|
|
|
|
if (!OpenFontFace())
|
|
return 0;
|
|
|
|
unsigned short ushCode = m_ushCodesCount++;
|
|
|
|
std::vector<unsigned int> vUnicodes;
|
|
for (unsigned int i = 0; i < unCount; i++)
|
|
{
|
|
vUnicodes.push_back(pUnicodes[i]);
|
|
}
|
|
|
|
m_vUnicodes.push_back(vUnicodes);
|
|
m_vCodeToGid.push_back(unGID);
|
|
|
|
m_mGlyphs.insert(std::pair<unsigned int, bool>(unGID, true));
|
|
|
|
// If this character is composite (CompositeGlyf), then we must account for all its child characters (subglyfs)
|
|
if (0 == FT_Load_Glyph(m_pFace, unGID, FT_LOAD_NO_SCALE | FT_LOAD_NO_RECURSE))
|
|
{
|
|
if (0 != m_pFace->units_per_EM)
|
|
{
|
|
m_vWidths.push_back((unsigned int)m_pFace->glyph->metrics.horiAdvance * 1000 / m_pFace->units_per_EM);
|
|
m_vGlypWidths.push_back((unsigned int)(m_pFace->glyph->metrics.width) * 1000 / m_pFace->units_per_EM);
|
|
}
|
|
else
|
|
{
|
|
m_vWidths.push_back((unsigned int)m_pFace->glyph->metrics.horiAdvance);
|
|
m_vGlypWidths.push_back((unsigned int)(m_pFace->glyph->metrics.width) * 1000 / m_pFace->units_per_EM);
|
|
}
|
|
|
|
for (int nSubIndex = 0; nSubIndex < m_pFace->glyph->num_subglyphs; nSubIndex++)
|
|
{
|
|
FT_Int nSubGID;
|
|
FT_UInt unFlags;
|
|
FT_Int nArg1;
|
|
FT_Int nArg2;
|
|
FT_Matrix oMatrix;
|
|
FT_Get_SubGlyph_Info(m_pFace->glyph, nSubIndex, &nSubGID, &unFlags, &nArg1, &nArg2, &oMatrix);
|
|
|
|
m_mGlyphs.insert(std::pair<unsigned short, bool>(nSubGID, false));
|
|
|
|
EncodeGID(nSubGID, NULL, 0);
|
|
FT_Load_Glyph(m_pFace, unGID, FT_LOAD_NO_SCALE | FT_LOAD_NO_RECURSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_vWidths.push_back(0);
|
|
m_vGlypWidths.push_back(0);
|
|
m_vCodeToGid.back() = 0;
|
|
return 0;
|
|
}
|
|
|
|
return ushCode;
|
|
}
|
|
}
|