mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
1960 lines
52 KiB
C++
1960 lines
52 KiB
C++
#include "stdafx.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "MemoryUtils.h"
|
|
#include "Object.h"
|
|
#include "Dict.h"
|
|
#include "GlobalParams.h"
|
|
#include "CMap.h"
|
|
#include "CharCodeToUnicode.h"
|
|
#include "EncodingTables.h"
|
|
#include "BuiltinFontTables.h"
|
|
#include "FontFileType1.h"
|
|
#include "FontFileType1C.h"
|
|
#include "FontFileTrueType.h"
|
|
#include "GFont.h"
|
|
#include "File.h"
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
struct StandardFontMapEntry
|
|
{
|
|
char *sAlternativeName;
|
|
char *sProperName;
|
|
};
|
|
|
|
// PDF ïîääåðæèâàåò 14 ñòàíäàðòíûõ ôîíòîâ(Type1) áåç óêàçàíèÿõ øèðèí è FontDescriptor,
|
|
// ïîýòîìó ìû ñîñòîâëÿåì êàðòó îòîáðàæàþùóþ ñòàíäàðòíûå ôîíòû â 14 îñíîâíûõ ôîíòîâ PDF.
|
|
// Ýòà òàáëèöà ñîñòàâëåíà íà îñíîâå "implementation note 44 in the PDF 1.4 spec", ñ
|
|
// íåáîëüøèìè äîáàâêàìè.
|
|
static StandardFontMapEntry c_sStandardFontMap[] =
|
|
{
|
|
{ "Arial", "Helvetica" },
|
|
{ "Arial,Bold", "Helvetica-Bold" },
|
|
{ "Arial,BoldItalic", "Helvetica-BoldOblique" },
|
|
{ "Arial,Italic", "Helvetica-Oblique" },
|
|
{ "Arial-Bold", "Helvetica-Bold" },
|
|
{ "Arial-BoldItalic", "Helvetica-BoldOblique" },
|
|
{ "Arial-BoldItalicMT", "Helvetica-BoldOblique" },
|
|
{ "Arial-BoldMT", "Helvetica-Bold" },
|
|
{ "Arial-Italic", "Helvetica-Oblique" },
|
|
{ "Arial-ItalicMT", "Helvetica-Oblique" },
|
|
{ "ArialMT", "Helvetica" },
|
|
{ "Courier,Bold", "Courier-Bold" },
|
|
{ "Courier,BoldItalic", "Courier-BoldOblique" },
|
|
{ "Courier,Italic", "Courier-Oblique" },
|
|
{ "CourierNew", "Courier" },
|
|
{ "CourierNew,Bold", "Courier-Bold" },
|
|
{ "CourierNew,BoldItalic", "Courier-BoldOblique" },
|
|
{ "CourierNew,Italic", "Courier-Oblique" },
|
|
{ "CourierNew-Bold", "Courier-Bold" },
|
|
{ "CourierNew-BoldItalic", "Courier-BoldOblique" },
|
|
{ "CourierNew-Italic", "Courier-Oblique" },
|
|
{ "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" },
|
|
{ "CourierNewPS-BoldMT", "Courier-Bold" },
|
|
{ "CourierNewPS-ItalicMT", "Courier-Oblique" },
|
|
{ "CourierNewPSMT", "Courier" },
|
|
{ "Helvetica,Bold", "Helvetica-Bold" },
|
|
{ "Helvetica,BoldItalic", "Helvetica-BoldOblique" },
|
|
{ "Helvetica,Italic", "Helvetica-Oblique" },
|
|
{ "Helvetica-BoldItalic", "Helvetica-BoldOblique" },
|
|
{ "Helvetica-Italic", "Helvetica-Oblique" },
|
|
{ "Symbol,Bold", "Symbol" },
|
|
{ "Symbol,BoldItalic", "Symbol" },
|
|
{ "Symbol,Italic", "Symbol" },
|
|
{ "TimesNewRoman", "Times-Roman" },
|
|
{ "TimesNewRoman,Bold", "Times-Bold" },
|
|
{ "TimesNewRoman,BoldItalic", "Times-BoldItalic" },
|
|
{ "TimesNewRoman,Italic", "Times-Italic" },
|
|
{ "TimesNewRoman-Bold", "Times-Bold" },
|
|
{ "TimesNewRoman-BoldItalic", "Times-BoldItalic" },
|
|
{ "TimesNewRoman-Italic", "Times-Italic" },
|
|
{ "TimesNewRomanPS", "Times-Roman" },
|
|
{ "TimesNewRomanPS-Bold", "Times-Bold" },
|
|
{ "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" },
|
|
{ "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" },
|
|
{ "TimesNewRomanPS-BoldMT", "Times-Bold" },
|
|
{ "TimesNewRomanPS-Italic", "Times-Italic" },
|
|
{ "TimesNewRomanPS-ItalicMT", "Times-Italic" },
|
|
{ "TimesNewRomanPSMT", "Times-Roman" },
|
|
{ "TimesNewRomanPSMT,Bold", "Times-Bold" },
|
|
{ "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" },
|
|
{ "TimesNewRomanPSMT,Italic", "Times-Italic" }
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
// GrFont
|
|
//------------------------------------------------------------------------
|
|
|
|
GrFont *GrFont::MakeFont(XRef *pXref, char *sTag, Ref oID, Dict *pFontDict, GlobalParams *pGlobalParams)
|
|
{
|
|
// Ñ÷èòûâàåì íàçâàíèå øðèôòà
|
|
StringExt *seName = NULL;
|
|
|
|
Object oTemp;
|
|
pFontDict->Search( "BaseFont", &oTemp);
|
|
if ( oTemp.IsName() )
|
|
{
|
|
seName = new StringExt( oTemp.GetName() );
|
|
}
|
|
oTemp.Free();
|
|
|
|
// Òèï øðèôòà
|
|
GrFont *pFont = NULL;
|
|
pFontDict->Search( "Subtype", &oTemp );
|
|
if ( oTemp.IsName("Type1") || oTemp.IsName("MMType1") )
|
|
{
|
|
pFont = new Gr8BitFont( pXref, sTag, oID, seName, fontType1, pFontDict, pGlobalParams);
|
|
}
|
|
else if ( oTemp.IsName("Type1C") )
|
|
{
|
|
pFont = new Gr8BitFont( pXref, sTag, oID, seName, fontType1C, pFontDict, pGlobalParams);
|
|
}
|
|
else if ( oTemp.IsName("Type3") )
|
|
{
|
|
pFont = new Gr8BitFont( pXref, sTag, oID, seName, fontType3, pFontDict, pGlobalParams);
|
|
}
|
|
else if ( oTemp.IsName("TrueType") )
|
|
{
|
|
pFont = new Gr8BitFont( pXref, sTag, oID, seName, fontTrueType, pFontDict, pGlobalParams);
|
|
}
|
|
else if ( oTemp.IsName("Type0") )
|
|
{
|
|
pFont = new GrCIDFont( pXref, sTag, oID, seName, pFontDict, pGlobalParams);
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Unknown font type"
|
|
pFont = new Gr8BitFont( pXref, sTag, oID, seName, fontUnknownType, pFontDict, pGlobalParams);
|
|
}
|
|
oTemp.Free();
|
|
|
|
return pFont;
|
|
}
|
|
|
|
GrFont::GrFont(char *sTag, Ref oID, StringExt *seName, GlobalParams *pGlobalParams)
|
|
{
|
|
m_pGlobalParams = pGlobalParams;
|
|
|
|
m_bValid = FALSE;
|
|
m_seTag = new StringExt( sTag );
|
|
m_oID = oID;
|
|
m_seName = seName;
|
|
m_seOriginalName = seName;
|
|
m_seEmbeddedFontName = NULL;
|
|
m_wsExternalFontFilePath = _T("");
|
|
}
|
|
|
|
GrFont::~GrFont()
|
|
{
|
|
if ( m_seTag )
|
|
{
|
|
delete m_seTag;
|
|
}
|
|
if ( m_seOriginalName && m_seOriginalName != m_seName )
|
|
{
|
|
delete m_seOriginalName;
|
|
}
|
|
if ( m_seName )
|
|
{
|
|
delete m_seName;
|
|
}
|
|
if ( m_seEmbeddedFontName )
|
|
{
|
|
delete m_seEmbeddedFontName;
|
|
}
|
|
}
|
|
|
|
void GrFont::ReadFontDescriptor(XRef *pXref, Dict *pFontDict)
|
|
{
|
|
m_nFlags = fontSerif;
|
|
|
|
m_oEmbFontFileRef.nNum = -1;
|
|
m_oEmbFontFileRef.nGen = -1;
|
|
m_dMissingWidth = 0;
|
|
|
|
Object oFontDescriptor;
|
|
if ( pFontDict->Search("FontDescriptor", &oFontDescriptor)->IsDict() )
|
|
{
|
|
// Flags
|
|
Object oDictItem;
|
|
if ( oFontDescriptor.DictLookup("Flags", &oDictItem)->IsInt() )
|
|
{
|
|
m_nFlags = oDictItem.GetInt();
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// FontName
|
|
oFontDescriptor.DictLookup("FontName", &oDictItem);
|
|
if ( oDictItem.IsName() )
|
|
{
|
|
m_seEmbeddedFontName = new StringExt( oDictItem.GetName());
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// Èùåì âíåäðåííûé FontFile
|
|
if ( oFontDescriptor.DictLookupAndCopy("FontFile", &oDictItem)->IsRef() )
|
|
{
|
|
m_oEmbFontFileRef = oDictItem.GetRef();
|
|
if ( m_eType != fontType1 )
|
|
{
|
|
// TO DO: Error "Mismatch between font type and embedded font file"
|
|
m_eType = fontType1;
|
|
}
|
|
}
|
|
oDictItem.Free();
|
|
|
|
if ( m_oEmbFontFileRef.nNum == -1 && oFontDescriptor.DictLookupAndCopy("FontFile2", &oDictItem)->IsRef() )
|
|
{
|
|
m_oEmbFontFileRef = oDictItem.GetRef();
|
|
if ( m_eType != fontTrueType && m_eType != fontCIDType2 )
|
|
{
|
|
// TO DO: Error "Mismatch between font type and embedded font file"
|
|
m_eType = (m_eType == fontCIDType0 ? fontCIDType2 : fontTrueType);
|
|
}
|
|
}
|
|
oDictItem.Free();
|
|
|
|
if ( m_oEmbFontFileRef.nNum == -1 && oFontDescriptor.DictLookupAndCopy("FontFile3", &oDictItem)->IsRef() )
|
|
{
|
|
Object oStream;
|
|
if ( oDictItem.Fetch( pXref, &oStream)->IsStream() )
|
|
{
|
|
Object oTemp;
|
|
oStream.StreamGetDict()->Search("Subtype", &oTemp);
|
|
if ( oTemp.IsName("Type1") )
|
|
{
|
|
m_oEmbFontFileRef = oDictItem.GetRef();
|
|
if ( m_eType != fontType1 )
|
|
{
|
|
// TO DO: Error "Mismatch between font type and embedded font file"
|
|
m_eType = fontType1;
|
|
}
|
|
}
|
|
else if ( oTemp.IsName("Type1C") )
|
|
{
|
|
m_oEmbFontFileRef = oDictItem.GetRef();
|
|
if ( m_eType != fontType1 && m_eType != fontType1C)
|
|
{
|
|
// TO DO: Error "Mismatch between font type and embedded font file"
|
|
}
|
|
m_eType = fontType1C;
|
|
}
|
|
else if ( oTemp.IsName("TrueType") )
|
|
{
|
|
m_oEmbFontFileRef = oDictItem.GetRef();
|
|
if ( m_eType != fontTrueType )
|
|
{
|
|
// TO DO: Error "Mismatch between font type and embedded font file"
|
|
m_eType = fontTrueType;
|
|
}
|
|
}
|
|
else if ( oTemp.IsName("CIDFontType0C") )
|
|
{
|
|
m_oEmbFontFileRef = oDictItem.GetRef();
|
|
if ( m_eType != fontCIDType0 )
|
|
{
|
|
// TO DO: Error "Mismatch between font type and embedded font file"
|
|
}
|
|
m_eType = fontCIDType0C;
|
|
}
|
|
else if ( oTemp.IsName("OpenType") )
|
|
{
|
|
m_oEmbFontFileRef = oDictItem.GetRef();
|
|
if ( m_eType == fontTrueType )
|
|
{
|
|
m_eType = fontTrueTypeOT;
|
|
}
|
|
else if ( m_eType == fontType1 )
|
|
{
|
|
m_eType = fontType1COT;
|
|
}
|
|
else if ( m_eType == fontCIDType0 )
|
|
{
|
|
m_eType = fontCIDType0COT;
|
|
}
|
|
else if ( m_eType == fontCIDType2 )
|
|
{
|
|
m_eType = fontCIDType2OT;
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Mismatch between font type and embedded font file"
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Unknown embedded font type"
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
oStream.Free();
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// MissingWidth
|
|
oFontDescriptor.DictLookup("MissingWidth", &oDictItem);
|
|
if ( oDictItem.IsNum() )
|
|
{
|
|
m_dMissingWidth = oDictItem.GetNum();
|
|
}
|
|
oDictItem.Free();
|
|
|
|
double dTemp = 0;
|
|
// Ascent
|
|
oFontDescriptor.DictLookup("Ascent", &oDictItem);
|
|
if ( oDictItem.IsNum() )
|
|
{
|
|
dTemp = 0.001 * oDictItem.GetNum();
|
|
// Íåêîòîðûå íåïðàâèëüíàå øðèôòû óñòàíàâëèâàþò Ascent è Descent ðàâíûìè 0
|
|
if ( dTemp != 0 )
|
|
{
|
|
m_dAscent = dTemp;
|
|
}
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// Descent
|
|
oFontDescriptor.DictLookup("Descent", &oDictItem);
|
|
if ( oDictItem.IsNum() )
|
|
{
|
|
dTemp = 0.001 * oDictItem.GetNum();
|
|
// Íåêîòîðûå íåïðàâèëüíàå øðèôòû óñòàíàâëèâàþò Ascent è Descent ðàâíûìè 0
|
|
if ( dTemp != 0 )
|
|
{
|
|
m_dDescent = dTemp;
|
|
}
|
|
// Descent äîëæíî áûòü îòðèöàòåëüíûì çíà÷åíèåì
|
|
if ( m_dDescent > 0 )
|
|
{
|
|
m_dDescent = -m_dDescent;
|
|
}
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// FontBBox
|
|
if ( oFontDescriptor.DictLookup("FontBBox", &oDictItem)->IsArray() )
|
|
{
|
|
for ( int nIndex = 0; nIndex < 4 && nIndex < oDictItem.ArrayGetLength(); ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
if ( oDictItem.ArrayGet( nIndex, &oTemp)->IsNum() )
|
|
{
|
|
m_arrFontBBox[nIndex] = 0.001 * oTemp.GetNum();
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
oDictItem.Free();
|
|
|
|
}
|
|
oFontDescriptor.Free();
|
|
}
|
|
|
|
CharCodeToUnicode *GrFont::ReadToUnicodeCMap(Dict *pFontDict, int nBitsCount, CharCodeToUnicode *pCharToUnicode)
|
|
{
|
|
Object oTemp;
|
|
if ( !pFontDict->Search("ToUnicode", &oTemp)->IsStream() )
|
|
{
|
|
oTemp.Free();
|
|
return NULL;
|
|
}
|
|
StringExt *seBuffer = new StringExt();
|
|
oTemp.StreamReset();
|
|
int nChar = 0;
|
|
while ( ( nChar = oTemp.StreamGetChar() ) != EOF )
|
|
{
|
|
seBuffer->Append( nChar );
|
|
}
|
|
oTemp.StreamClose();
|
|
oTemp.Free();
|
|
if ( pCharToUnicode )
|
|
{
|
|
pCharToUnicode->MergeCMap( seBuffer, nBitsCount, m_pGlobalParams );
|
|
}
|
|
else
|
|
{
|
|
pCharToUnicode = CharCodeToUnicode::ParseCMap( seBuffer, nBitsCount, m_pGlobalParams );
|
|
}
|
|
delete seBuffer;
|
|
return pCharToUnicode;
|
|
}
|
|
|
|
void GrFont::FindExternalFontFile()
|
|
{
|
|
static wchar_t *c_wsType1Ext[] = { _T(".pfa"), _T(".pfb"), _T(".ps"), _T(""), NULL };
|
|
static wchar_t *c_wsTTFExts[] = { _T(".ttf"), NULL };
|
|
|
|
if ( m_pGlobalParams && m_seName )
|
|
{
|
|
if ( m_eType == fontType1 )
|
|
{
|
|
m_wsExternalFontFilePath = m_pGlobalParams->FindFontFile( m_seName, c_wsType1Ext );
|
|
}
|
|
else if ( m_eType == fontTrueType )
|
|
{
|
|
m_wsExternalFontFilePath = m_pGlobalParams->FindFontFile( m_seName, c_wsTTFExts );
|
|
}
|
|
}
|
|
}
|
|
|
|
char *GrFont::ReadExternalFontFile(int *pnLen)
|
|
{
|
|
FILE *pFile = NULL;
|
|
|
|
if ( !( pFile = _wfopen( m_wsExternalFontFilePath.GetBuffer(), _T("rb") ) ) )
|
|
{
|
|
// TO DO: Error "External font file vanished"
|
|
return NULL;
|
|
}
|
|
fseek( pFile, 0, SEEK_END);
|
|
*pnLen = (int)ftell( pFile );
|
|
fseek( pFile, 0, SEEK_SET);
|
|
|
|
char *sBuffer = (char *)MemUtilsMalloc( *pnLen );
|
|
if ( (int)fread( sBuffer, 1, *pnLen, pFile) != *pnLen )
|
|
{
|
|
// TO DO: Error "Error reading external font file"
|
|
}
|
|
fclose( pFile );
|
|
return sBuffer;
|
|
}
|
|
|
|
char *GrFont::ReadEmbeddedFontFile(XRef *pXref, int *pnLen)
|
|
{
|
|
Object oFontFile;
|
|
oFontFile.InitRef( m_oEmbFontFileRef.nNum, m_oEmbFontFileRef.nGen );
|
|
Object oStream;
|
|
oFontFile.Fetch( pXref, &oStream );
|
|
if ( !oStream.IsStream() )
|
|
{
|
|
// TO DO: Error "Embedded font file is not a stream"
|
|
oStream.Free();
|
|
oFontFile.Free();
|
|
m_oEmbFontFileRef.nNum = -1;
|
|
return NULL;
|
|
}
|
|
Stream *pStream = oStream.GetStream();
|
|
char *sBuffer = NULL;
|
|
int nSize = 0;
|
|
int nIndex = 0;
|
|
pStream->Reset();
|
|
int nChar = 0;
|
|
while ( ( nChar = pStream->GetChar() ) != EOF )
|
|
{
|
|
if ( nIndex == nSize )
|
|
{
|
|
nSize += 4096;
|
|
sBuffer = (char *)MemUtilsRealloc( sBuffer, nSize);
|
|
}
|
|
sBuffer[nIndex++] = nChar;
|
|
}
|
|
*pnLen = nIndex;
|
|
pStream->Close();
|
|
|
|
oStream.Free();
|
|
oFontFile.Free();
|
|
|
|
return sBuffer;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Gr8BitFont
|
|
//------------------------------------------------------------------------
|
|
|
|
Gr8BitFont::Gr8BitFont(XRef *pXref, char *sTag, Ref oID, StringExt *seName, GrFontType eType, Dict *pFontDict, GlobalParams *pGlobalParams):
|
|
GrFont(sTag, oID, seName, pGlobalParams)
|
|
{
|
|
m_eType = eType;
|
|
m_pCharToUnicode = NULL;
|
|
|
|
if ( m_seName )
|
|
{
|
|
StringExt *seName2 = m_seName->Copy();
|
|
int nIndex = 0;
|
|
while ( nIndex < seName2->GetLength() )
|
|
{
|
|
if ( seName2->GetAt(nIndex) == ' ' )
|
|
{
|
|
seName2->Delete(nIndex);
|
|
}
|
|
else
|
|
{
|
|
++nIndex;
|
|
}
|
|
}
|
|
int nFirst = 0;
|
|
int nLast = sizeof(c_sStandardFontMap) / sizeof(StandardFontMapEntry);
|
|
|
|
// Ïîèñê ìåòîäîì äåëåíèÿ îòðåçêà ïîïîëàì
|
|
while ( nLast - nFirst > 1 )
|
|
{
|
|
int nMiddle = (nFirst + nLast) / 2;
|
|
if ( seName2->Compare( c_sStandardFontMap[nMiddle].sAlternativeName) >= 0 )
|
|
{
|
|
nFirst = nMiddle;
|
|
}
|
|
else
|
|
{
|
|
nLast = nMiddle;
|
|
}
|
|
}
|
|
if ( !seName2->Compare( c_sStandardFontMap[nFirst].sAlternativeName ) )
|
|
{
|
|
m_seName = new StringExt( c_sStandardFontMap[nFirst].sProperName );
|
|
}
|
|
delete seName2;
|
|
}
|
|
|
|
// Ñìîòðèì ÿâëÿåòñÿ ëè íàø ôîíò îäíèì èç 14 ñòàíäàðòíûõ
|
|
BuiltinFont *pBuiltinFont = NULL;
|
|
if ( m_seName )
|
|
{
|
|
for ( int nIndex = 0; nIndex < BuiltinFontsCount; ++nIndex )
|
|
{
|
|
if ( !m_seName->Compare( c_arrBuiltinFonts[nIndex].sName ) )
|
|
{
|
|
pBuiltinFont = &c_arrBuiltinFonts[nIndex];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Âûñòàâëÿåì ñòàíäàðòíûå çíà÷åíèÿ äëÿ Ascent/Descent/BBox
|
|
if ( pBuiltinFont )
|
|
{
|
|
m_dAscent = 0.001 * pBuiltinFont->nAscent;
|
|
m_dDescent = 0.001 * pBuiltinFont->nDescent;
|
|
m_arrFontBBox[0] = 0.001 * pBuiltinFont->arrBBox[0];
|
|
m_arrFontBBox[1] = 0.001 * pBuiltinFont->arrBBox[1];
|
|
m_arrFontBBox[2] = 0.001 * pBuiltinFont->arrBBox[2];
|
|
m_arrFontBBox[3] = 0.001 * pBuiltinFont->arrBBox[3];
|
|
}
|
|
else
|
|
{
|
|
m_dAscent = 0.95;
|
|
m_dDescent = -0.35;
|
|
m_arrFontBBox[0] = m_arrFontBBox[1] = m_arrFontBBox[2] = m_arrFontBBox[3] = 0;
|
|
}
|
|
|
|
// Ñ÷èòûâàåì äàííûå èç FontDescriptor
|
|
ReadFontDescriptor( pXref, pFontDict);
|
|
|
|
// Äëÿ ñòàíäàðòíûõ ôîíòîâ âûñòàâëÿåì ñòàíäàðòíûå çíà÷åíèÿ Ascent/Descent/BBox
|
|
if ( pBuiltinFont && m_oEmbFontFileRef.nNum < 0 )
|
|
{
|
|
m_dAscent = 0.001 * pBuiltinFont->nAscent;
|
|
m_dDescent = 0.001 * pBuiltinFont->nDescent;
|
|
m_arrFontBBox[0] = 0.001 * pBuiltinFont->arrBBox[0];
|
|
m_arrFontBBox[1] = 0.001 * pBuiltinFont->arrBBox[1];
|
|
m_arrFontBBox[2] = 0.001 * pBuiltinFont->arrBBox[2];
|
|
m_arrFontBBox[3] = 0.001 * pBuiltinFont->arrBBox[3];
|
|
}
|
|
|
|
// Èùåì âíåøíèé FontFile
|
|
FindExternalFontFile();
|
|
|
|
// FontMatrix
|
|
m_arrFontMatrix[0] = m_arrFontMatrix[3] = 1;
|
|
m_arrFontMatrix[1] = m_arrFontMatrix[2] = m_arrFontMatrix[4] = m_arrFontMatrix[5] = 0;
|
|
|
|
Object oDictItem;
|
|
if ( pFontDict->Search("FontMatrix", &oDictItem)->IsArray() )
|
|
{
|
|
for ( int nIndex = 0; nIndex < 6 && nIndex < oDictItem.ArrayGetLength(); ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
if ( oDictItem.ArrayGet( nIndex, &oTemp)->IsNum() )
|
|
{
|
|
m_arrFontMatrix[nIndex] = oTemp.GetNum();
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// Ñ÷èòûâàåì äàííûå, õàðàêòåðíûå äëÿ øðèôòà Type 3
|
|
if ( m_eType == fontType3 )
|
|
{
|
|
if ( pFontDict->Search("FontBBox", &oDictItem)->IsArray() )
|
|
{
|
|
for ( int nIndex = 0; nIndex < 4 && nIndex < oDictItem.ArrayGetLength(); ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
if ( oDictItem.ArrayGet( nIndex, &oTemp)->IsNum() )
|
|
{
|
|
m_arrFontBBox[nIndex] = oTemp.GetNum();
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
oDictItem.Free();
|
|
|
|
if ( !pFontDict->Search("CharProcs", &m_oCharProcs)->IsDict() )
|
|
{
|
|
// TO DO: Error "Missing or invalid CharProcs dictionary in Type 3 font"
|
|
m_oCharProcs.Free();
|
|
}
|
|
|
|
if ( !pFontDict->Search("Resources", &m_oResources)->IsDict() )
|
|
{
|
|
m_oResources.Free();
|
|
}
|
|
}
|
|
|
|
//----- Ñòðîèì Encoding -----
|
|
|
|
// Encodings íà÷èíàåòñÿ ñ BaseEncoding, êîòîðóþ ìû ìîæåì íàéòè â
|
|
// (â ïîðÿäêå ïðèîðèòåòà):
|
|
// 1. pFontDict.Encoding or pFontDict.Encoding.BaseEncoding
|
|
// - MacRoman / MacExpert / WinAnsi / Standard
|
|
// 2. Âî âíåäðåííîì èëè âíåøíåì FontFile
|
|
// 3. Ñòàíäàðòíûå çíà÷åíèÿ(åñëè äî ýòîãî íå íàøëè):
|
|
// - Builtin --> Builtin encoding
|
|
// - TrueType --> WinAnsiEncoding
|
|
// - Îñòàëüíûå --> StandardEncoding
|
|
|
|
// Èùåì BaseEncoding â pFontDict
|
|
m_bHasEncoding = FALSE;
|
|
m_bUsesMacRomanEncoding = FALSE;
|
|
char **ppBaseEncoding = NULL;
|
|
BOOL bBaseEncodingFromFontFile = FALSE;
|
|
|
|
pFontDict->Search("Encoding", &oDictItem);
|
|
if ( oDictItem.IsDict() )
|
|
{
|
|
Object oTemp;
|
|
oDictItem.DictLookup("BaseEncoding", &oTemp);
|
|
if ( oTemp.IsName("MacRomanEncoding") )
|
|
{
|
|
m_bHasEncoding = TRUE;
|
|
m_bUsesMacRomanEncoding = TRUE;
|
|
ppBaseEncoding = c_arrMacRomanEncoding;
|
|
}
|
|
else if ( oTemp.IsName("MacExpertEncoding") )
|
|
{
|
|
m_bHasEncoding = TRUE;
|
|
ppBaseEncoding = c_arrMacExpertEncoding;
|
|
}
|
|
else if ( oTemp.IsName("WinAnsiEncoding") )
|
|
{
|
|
m_bHasEncoding = TRUE;
|
|
ppBaseEncoding = c_arrWinAnsiEncoding;
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
else if ( oDictItem.IsName("MacRomanEncoding") )
|
|
{
|
|
m_bHasEncoding = TRUE;
|
|
m_bUsesMacRomanEncoding = TRUE;
|
|
ppBaseEncoding = c_arrMacRomanEncoding;
|
|
}
|
|
else if ( oDictItem.IsName("MacExpertEncoding") )
|
|
{
|
|
m_bHasEncoding = TRUE;
|
|
ppBaseEncoding = c_arrMacExpertEncoding;
|
|
}
|
|
else if ( oDictItem.IsName("WinAnsiEncoding") )
|
|
{
|
|
m_bHasEncoding = TRUE;
|
|
ppBaseEncoding = c_arrWinAnsiEncoding;
|
|
}
|
|
|
|
// Èùåì BaseEncoding â FontFile(òîëüêî äëÿ Type1)
|
|
CFontFileType1 *pFFT1 = NULL;
|
|
CFontFileType1C *pFFT1C = NULL;
|
|
char *sBuffer = NULL;
|
|
int nLen = 0;
|
|
|
|
if ( m_eType == fontType1 && ( _T("") != m_wsExternalFontFilePath || m_oEmbFontFileRef.nNum >= 0 ) )
|
|
{
|
|
if ( _T("") != m_wsExternalFontFilePath )
|
|
{
|
|
pFFT1 = CFontFileType1::LoadFromFile( m_wsExternalFontFilePath.GetBuffer() );
|
|
}
|
|
else
|
|
{
|
|
sBuffer = ReadEmbeddedFontFile( pXref, &nLen);
|
|
pFFT1 = CFontFileType1::LoadFromBuffer( sBuffer, nLen);
|
|
}
|
|
if ( pFFT1 )
|
|
{
|
|
if ( pFFT1->GetName() )
|
|
{
|
|
if ( m_seEmbeddedFontName )
|
|
{
|
|
delete m_seEmbeddedFontName;
|
|
}
|
|
m_seEmbeddedFontName = new StringExt( pFFT1->GetName() );
|
|
}
|
|
if ( !ppBaseEncoding )
|
|
{
|
|
ppBaseEncoding = pFFT1->GetEncoding();
|
|
bBaseEncodingFromFontFile = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else if ( m_eType == fontType1C && ( _T("") != m_wsExternalFontFilePath || m_oEmbFontFileRef.nNum >= 0 ) )
|
|
{
|
|
if ( _T("") != m_wsExternalFontFilePath )
|
|
{
|
|
pFFT1C = CFontFileType1C::LoadFromFile( m_wsExternalFontFilePath.GetBuffer() );
|
|
}
|
|
else
|
|
{
|
|
sBuffer = ReadEmbeddedFontFile( pXref, &nLen);
|
|
pFFT1C = CFontFileType1C::LoadFromBuffer( sBuffer, nLen);
|
|
}
|
|
if ( pFFT1C )
|
|
{
|
|
if ( pFFT1C->GetName() )
|
|
{
|
|
if ( m_seEmbeddedFontName )
|
|
{
|
|
delete m_seEmbeddedFontName;
|
|
}
|
|
m_seEmbeddedFontName = new StringExt( pFFT1C->GetName() );
|
|
}
|
|
if ( !ppBaseEncoding )
|
|
{
|
|
ppBaseEncoding = pFFT1C->GetEncoding();
|
|
bBaseEncodingFromFontFile = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if ( sBuffer )
|
|
{
|
|
MemUtilsFree( sBuffer );
|
|
}
|
|
|
|
// Ñòàíäàðòíûå çíà÷åíèÿ BaseEncoding
|
|
if ( !ppBaseEncoding )
|
|
{
|
|
if ( pBuiltinFont && m_oEmbFontFileRef.nNum < 0 )
|
|
{
|
|
ppBaseEncoding = pBuiltinFont->ppDefaultBaseEncoding;
|
|
m_bHasEncoding = TRUE;
|
|
}
|
|
else if ( m_eType == fontTrueType )
|
|
{
|
|
ppBaseEncoding = c_arrWinAnsiEncoding;
|
|
}
|
|
else
|
|
{
|
|
ppBaseEncoding = c_arrStandardEncoding;
|
|
}
|
|
}
|
|
|
|
// copy the base encoding
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
m_ppEncoding[nIndex] = ppBaseEncoding[nIndex];
|
|
if ( ( m_arrEncFree[nIndex] = bBaseEncodingFromFontFile ) && m_ppEncoding[nIndex] )
|
|
{
|
|
m_ppEncoding[nIndex] = CopyString( ppBaseEncoding[nIndex] );
|
|
}
|
|
}
|
|
|
|
// Íåêîòîðûå Type 1C Font Files èìåþ ïóñòûå êîäèðîâêè, ÷òî ìîæåò íàâðåäèòü êîíâåðòàöèè T1C->T1,
|
|
// ïîýòîìó ìû çàïîëíÿåì âñå ïóñòûå ìåñòà èç StandardEncoding
|
|
if ( m_eType == fontType1C && ( _T("") != m_wsExternalFontFilePath || m_oEmbFontFileRef.nNum >= 0 ) && bBaseEncodingFromFontFile )
|
|
{
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
if ( !m_ppEncoding[nIndex] && c_arrStandardEncoding[nIndex] )
|
|
{
|
|
m_ppEncoding[nIndex] = c_arrStandardEncoding[nIndex];
|
|
m_arrEncFree[nIndex] = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Differences
|
|
if ( oDictItem.IsDict() )
|
|
{
|
|
Object oDifferences;
|
|
oDictItem.DictLookup("Differences", &oDifferences);
|
|
if ( oDifferences.IsArray() )
|
|
{
|
|
m_bHasEncoding = TRUE;
|
|
int nCode = 0;
|
|
for ( int nIndex = 0; nIndex < oDifferences.ArrayGetLength(); ++nIndex )
|
|
{
|
|
Object oTemp;
|
|
oDifferences.ArrayGet( nIndex, &oTemp);
|
|
if ( oTemp.IsInt() )
|
|
{
|
|
nCode = oTemp.GetInt();
|
|
}
|
|
else if ( oTemp.IsName() )
|
|
{
|
|
if ( nCode >= 0 && nCode < 256 )
|
|
{
|
|
if ( m_arrEncFree[nCode] )
|
|
{
|
|
MemUtilsFree( m_ppEncoding[nCode] );
|
|
}
|
|
m_ppEncoding[nCode] = CopyString( oTemp.GetName() );
|
|
m_arrEncFree[nCode] = TRUE;
|
|
}
|
|
++nCode;
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Wrong type in font encoding resource differences"
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
oDifferences.Free();
|
|
}
|
|
oDictItem.Free();
|
|
|
|
if ( pFFT1 )
|
|
{
|
|
delete pFFT1;
|
|
}
|
|
if ( pFFT1C )
|
|
{
|
|
delete pFFT1C;
|
|
}
|
|
|
|
//----- build the mapping to Unicode -----
|
|
|
|
// Øàã 1: Èñïîëüçóåì ñîîòâåòñòâèå Name-to-Unicode
|
|
BOOL bMissing = FALSE, bHex = FALSE;
|
|
char *sCharName;
|
|
Unicode arrToUnicode[256];
|
|
for ( int nCode = 0; nCode < 256; ++nCode )
|
|
{
|
|
if ( ( sCharName = m_ppEncoding[nCode] ) )
|
|
{
|
|
if ( m_pGlobalParams && !( arrToUnicode[nCode] = m_pGlobalParams->MapNameToUnicode(sCharName) ) && strcmp( sCharName, ".notdef") )
|
|
{
|
|
// Åñëè äàííîãî ñèìâîëà íå áûëî â òàáëèöå Name-to-Unicode table, ïðîâåðÿåì
|
|
// êàê âûãëÿäèò Name. ( ëèáî 'Axx', ëèáî 'xx', ãäå 'A' - ïðîèçâîëüíàÿ áóêâà
|
|
// è 'xx' - äâà øåñòíàäöàòèðè÷íûõ ÷èñëà
|
|
if ( ( strlen(sCharName) == 3 && isalpha(sCharName[0]) &&
|
|
isxdigit(sCharName[1]) && isxdigit(sCharName[2]) &&
|
|
(( sCharName[1] >= 'a' && sCharName[1] <= 'f' ) ||
|
|
( sCharName[1] >= 'A' && sCharName[1] <= 'F' ) ||
|
|
( sCharName[2] >= 'a' && sCharName[2] <= 'f' ) ||
|
|
( sCharName[2] >= 'A' && sCharName[2] <= 'F' ) )
|
|
) ||
|
|
( strlen(sCharName) == 2 &&
|
|
isxdigit(sCharName[0]) && isxdigit(sCharName[1]) &&
|
|
(( sCharName[0] >= 'a' && sCharName[0] <= 'f' ) ||
|
|
( sCharName[0] >= 'A' && sCharName[0] <= 'F' ) ||
|
|
( sCharName[1] >= 'a' && sCharName[1] <= 'f' ) ||
|
|
( sCharName[1] >= 'A' && sCharName[1] <= 'F' ) )
|
|
) )
|
|
{
|
|
bHex = TRUE;
|
|
}
|
|
bMissing = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
arrToUnicode[nCode] = 0;
|
|
}
|
|
}
|
|
|
|
// Øàã 2: Çàïîëíÿåì ïðîïóùåííûå ñèìâîëû, èùåì èìåíà îäíîãî èç âèäîâ
|
|
// 'Axx', 'xx', 'Ann', 'ABnn' èëè 'nn', ãäå 'A' è 'B' - ëþáûå áóêâû,
|
|
// 'xx' - äâà øåñòíàäöàòèðè÷íûõ ÷èñëà, è 'nn' - 2-4 äåñÿòè÷íûõ ÷èñëà
|
|
if ( bMissing && m_pGlobalParams && m_pGlobalParams->GetMapNumericCharNames() )
|
|
{
|
|
for ( int nCode = 0; nCode < 256; ++nCode )
|
|
{
|
|
if ( ( sCharName = m_ppEncoding[nCode] ) && !arrToUnicode[nCode] && strcmp(sCharName, ".notdef") )
|
|
{
|
|
int nCount = strlen(sCharName);
|
|
int nCode2 = -1;
|
|
if ( bHex && nCount == 3 && isalpha(sCharName[0]) && isxdigit(sCharName[1]) && isxdigit(sCharName[2]) )
|
|
{
|
|
sscanf(sCharName + 1, "%x", &nCode2);
|
|
}
|
|
else if ( bHex && nCount == 2 && isxdigit(sCharName[0]) && isxdigit(sCharName[1]) )
|
|
{
|
|
sscanf(sCharName, "%x", &nCode2);
|
|
}
|
|
else if ( !bHex && nCount >= 2 && nCount <= 4 && isdigit(sCharName[0]) && isdigit(sCharName[1]) )
|
|
{
|
|
nCode2 = atoi(sCharName);
|
|
}
|
|
else if ( nCount >= 3 && nCount <= 5 && isdigit(sCharName[1]) && isdigit(sCharName[2]) )
|
|
{
|
|
nCode2 = atoi(sCharName + 1);
|
|
}
|
|
else if ( nCount >= 4 && nCount <= 6 && isdigit(sCharName[2]) && isdigit(sCharName[3]) )
|
|
{
|
|
nCode2 = atoi(sCharName + 2);
|
|
}
|
|
if ( nCode2 >= 0 && nCode2 <= 0xff )
|
|
{
|
|
arrToUnicode[nCode] = (Unicode)nCode2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( bMissing && m_pGlobalParams && m_pGlobalParams->GetMapUnknownCharNames() ) // Åñëè óñòàíîâëåí ôëàã 'mapUnknownCharNames'
|
|
{
|
|
for ( int nCode = 0; nCode < 256; ++nCode )
|
|
{
|
|
if ( !arrToUnicode[nCode] )
|
|
{
|
|
arrToUnicode[nCode] = nCode;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_pCharToUnicode = CharCodeToUnicode::Make8BitToUnicode( arrToUnicode );
|
|
|
|
// ToUnicode CMap
|
|
ReadToUnicodeCMap( pFontDict, 8, m_pCharToUnicode);
|
|
|
|
// Èùåì Unicode-to-Unicode
|
|
CharCodeToUnicode *pUnicodeToUnicode, *pCharToUnicode;
|
|
if ( m_seName && m_pGlobalParams && ( pUnicodeToUnicode = m_pGlobalParams->GetUnicodeToUnicode(m_seName) ) )
|
|
{
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
arrToUnicode[nIndex] = 0;
|
|
}
|
|
pCharToUnicode = CharCodeToUnicode::Make8BitToUnicode( arrToUnicode );
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
Unicode arrUnicodeBuf[8];
|
|
int nCount = m_pCharToUnicode->MapToUnicode( (CharCode)nIndex, arrUnicodeBuf, 8);
|
|
if ( nCount >= 1 )
|
|
{
|
|
nCount = pUnicodeToUnicode->MapToUnicode( (CharCode)arrUnicodeBuf[0], arrUnicodeBuf, 8);
|
|
if ( nCount >= 1 )
|
|
{
|
|
pCharToUnicode->SetMapping( (CharCode)nIndex, arrUnicodeBuf, nCount);
|
|
}
|
|
}
|
|
}
|
|
pUnicodeToUnicode->Release();
|
|
if ( m_pCharToUnicode )
|
|
delete m_pCharToUnicode;
|
|
m_pCharToUnicode = pCharToUnicode;
|
|
}
|
|
|
|
// Widths
|
|
|
|
for ( int nCode = 0; nCode < 256; ++nCode )
|
|
{
|
|
m_arrWidths[nCode] = m_dMissingWidth * 0.001;
|
|
}
|
|
|
|
// Èñïîëüçóåì øèðèíûå èç pFontDict, åñëè îíè òàì çàäàíû
|
|
pFontDict->Search("FirstChar", &oDictItem);
|
|
int nFirstChar = oDictItem.IsInt() ? oDictItem.GetInt() : 0;
|
|
oDictItem.Free();
|
|
|
|
if ( nFirstChar < 0 || nFirstChar > 255 )
|
|
{
|
|
nFirstChar = 0;
|
|
}
|
|
pFontDict->Search("LastChar", &oDictItem);
|
|
int nLastChar = oDictItem.IsInt() ? oDictItem.GetInt() : 255;
|
|
oDictItem.Free();
|
|
|
|
if ( nLastChar < 0 || nLastChar > 255 )
|
|
{
|
|
nLastChar = 255;
|
|
}
|
|
double dMult = ( m_eType == fontType3 ) ? m_arrFontMatrix[0] : 0.001;
|
|
|
|
pFontDict->Search("Widths", &oDictItem);
|
|
if ( oDictItem.IsArray() )
|
|
{
|
|
m_nFlags |= fontFixedWidth;
|
|
if ( oDictItem.ArrayGetLength() < nLastChar - nFirstChar + 1 )
|
|
{
|
|
nLastChar = nFirstChar + oDictItem.ArrayGetLength() - 1;
|
|
}
|
|
for ( int nCode = nFirstChar; nCode <= nLastChar; ++nCode )
|
|
{
|
|
Object oTemp;
|
|
oDictItem.ArrayGet( nCode - nFirstChar, &oTemp);
|
|
if ( oTemp.IsNum() )
|
|
{
|
|
m_arrWidths[nCode] = oTemp.GetNum() * dMult;
|
|
if ( m_arrWidths[nCode] != m_arrWidths[nFirstChar] )
|
|
{
|
|
m_nFlags &= ~fontFixedWidth;
|
|
}
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
else if ( pBuiltinFont ) // Èñïîëüçóåì øèðèíû èç Built-in øðèôòà
|
|
{
|
|
// Íåêîððåêòíûå PDF-ôàéëû êîäèðóþò ñèìâîë ñ íîìåðîì 32 êàê .notdef(õîòÿ ýòî ïðîáåë)
|
|
unsigned short unWidth = 0;
|
|
if ( BuiltinFontGetWidth( pBuiltinFont, "space", &unWidth ) )
|
|
{
|
|
m_arrWidths[32] = 0.001 * unWidth;
|
|
}
|
|
for ( int nCode = 0; nCode < 256; ++nCode )
|
|
{
|
|
if ( m_ppEncoding[nCode] && BuiltinFontGetWidth( pBuiltinFont, m_ppEncoding[nCode], &unWidth ) )
|
|
{
|
|
m_arrWidths[nCode] = 0.001 * unWidth;
|
|
}
|
|
}
|
|
}
|
|
else // Øèðèíû íå çàäàíû - çàïîëíÿåì ñòàíäàðòíûìè çíà÷åíèÿìè
|
|
{
|
|
int nIndex = 0;
|
|
if ( IsFixedWidth() )
|
|
{
|
|
nIndex = 0;
|
|
}
|
|
else if ( IsSerif() )
|
|
{
|
|
nIndex = 8;
|
|
}
|
|
else
|
|
{
|
|
nIndex = 4;
|
|
}
|
|
if ( IsBold() )
|
|
{
|
|
nIndex += 2;
|
|
}
|
|
if ( IsItalic() )
|
|
{
|
|
nIndex += 1;
|
|
}
|
|
pBuiltinFont = c_arrBuiltinFontSubset[nIndex];
|
|
|
|
// Íåêîððåêòíûå PDF-ôàéëû êîäèðóþò ñèìâîë ñ íîìåðîì 32 êàê .notdef(õîòÿ ýòî ïðîáåë)
|
|
unsigned short unWidth = 0;
|
|
if ( BuiltinFontGetWidth( pBuiltinFont, "space", &unWidth ) )
|
|
{
|
|
m_arrWidths[32] = 0.001 * unWidth;
|
|
}
|
|
for ( int nCode = 0; nCode < 256; ++nCode )
|
|
{
|
|
if ( m_ppEncoding[nCode] && BuiltinFontGetWidth( pBuiltinFont, m_ppEncoding[nCode], &unWidth ) )
|
|
{
|
|
m_arrWidths[nCode] = 0.001 * unWidth;
|
|
}
|
|
}
|
|
}
|
|
oDictItem.Free();
|
|
|
|
m_bValid = TRUE;
|
|
}
|
|
|
|
Gr8BitFont::~Gr8BitFont()
|
|
{
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
if ( m_arrEncFree[nIndex] && m_ppEncoding[nIndex] )
|
|
{
|
|
MemUtilsFree(m_ppEncoding[nIndex]);
|
|
}
|
|
}
|
|
m_pCharToUnicode->Release();
|
|
if ( m_oCharProcs.IsDict() )
|
|
{
|
|
m_oCharProcs.Free();
|
|
}
|
|
if ( m_oResources.IsDict() )
|
|
{
|
|
m_oResources.Free();
|
|
}
|
|
}
|
|
|
|
int Gr8BitFont::GetNextChar(char *sText, int nLen, CharCode *punCode, Unicode *punUnicode, int uSize, int *uLen, double *pdDx, double *pdDy, double *pdVx, double *pdVy)
|
|
{
|
|
CharCode nCharCode;
|
|
|
|
*punCode = nCharCode = (CharCode)(*sText & 0xff);
|
|
*uLen = m_pCharToUnicode->MapToUnicode( nCharCode, punUnicode, uSize);
|
|
*pdDx = m_arrWidths[nCharCode];
|
|
*pdDy = *pdVx = *pdVy = 0;
|
|
return 1;
|
|
}
|
|
|
|
CharCodeToUnicode *Gr8BitFont::GetToUnicode()
|
|
{
|
|
m_pCharToUnicode->AddRef();
|
|
return m_pCharToUnicode;
|
|
}
|
|
|
|
unsigned short *Gr8BitFont::GetCodeToGIDMap(CFontFileTrueType *pTTF)
|
|
{
|
|
unsigned short *pMap = (unsigned short *)MemUtilsMallocArray( 256, sizeof(unsigned short) );
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
pMap[nIndex] = 0;
|
|
}
|
|
|
|
// 1. Åñëè â PDF çàäàíà êîäèðîâêà:
|
|
// 1a. Åñëè â PDF øðèôòå îïðåäåëíà êîäèðîâêà MacRomanEncoding è
|
|
// TrueType-øðèôò èìååò Macintosh Roman CMap, èñïîëüçóåì åãî,
|
|
// è ïîëó÷åì îáàòíî ïî èìåíàì êîäû ñèìâîëîâ.
|
|
// 1b. Åñëè TrueType-øðèôò èìååò Microsoft Unicode CMap èëè
|
|
// non-Microsoft Unicode CMap, èñïîëüçóåì åãî, è èñïîëüçóåì
|
|
// þíèêîäíûå íîìåðà, à íå êîäû ñèìâîëîâ.
|
|
// 1c. Åñëè PDF-øðèôò - Symbolic è TrueType-øðèôò èìååò
|
|
// Microsoft Symbol CMap, èñïîëüçóåì åãî, è èñïîëüçóåì ñàìè
|
|
// êîäû ñèìâîëîâ (âîçìîæíî ñî ñäâèãîì 0xf000).
|
|
// 1d. Åñëè TrueType-øðèôò èìååò Macintosh Roman CMap, èñïîëüçóåì
|
|
// åãî êàê è â ñëó÷àå 1a.
|
|
// 2. Åñëè PDF-øðèôò íå èìååò êîäèðîâêè èëè PDF-øðèôò - Symbolic:
|
|
// 2a. Åñëè TrueType-øðèôò èìååò Macintosh Roman CMap, èñïîëüçóåì
|
|
// åãî, è èñïîëüçóåì ñàìè êîäû ñèìâîëîâ (âîçìîæíî ñî ñäâèãîì
|
|
// 0xf000).
|
|
// 2b. Åñëè TrueType-øðèôò èìååò Microsoft Symbol CMap, èñïîëüçóåì
|
|
// åãî, è èñïîëüçóåì ñàìè êîäû ñèìâîëîâ (âîçìîæíî ñî ñäâèãîì
|
|
// 0xf000).
|
|
// 3. Åñëè íå îäèí èç ýòèõ ñëó÷àåâ íå ïðèìåíèì, òîãäà èñïîëüçóåì ïåðâûé
|
|
// CMap. (íî òàêîãî íå äîëæíî ïðîèñõîäèòü)
|
|
|
|
|
|
// TO DO: Âîçìîæíà ñèòóàöèÿ, êîãäà îäèíàêîâûõ êîäèðîâîê íåñêîëüêî, è â îíè ñîäåððæàò
|
|
// ðàçíûå ñèìâîëû.  òàêèõ ñëó÷àÿõ íàäî áû äåëàòü îáùóþ êîäèðîâêó, à íå ñ÷èòûâàòü
|
|
// îäíó êîíêðåòíóþ.
|
|
|
|
int nUnicodeCmap = -1, nMacRomanCmap = -1, nMSSymbolCmap = -1;
|
|
int nCmapPlatform = 0, nCmapEncoding = 0;
|
|
for ( int nIndex = 0; nIndex < pTTF->GetCmapsCount(); ++nIndex )
|
|
{
|
|
nCmapPlatform = pTTF->GetCmapPlatform(nIndex);
|
|
nCmapEncoding = pTTF->GetCmapEncoding(nIndex);
|
|
|
|
if ( ( nCmapPlatform == 3 && nCmapEncoding == 1 ) || nCmapPlatform == 0 )
|
|
{
|
|
nUnicodeCmap = nIndex;
|
|
}
|
|
else if ( nCmapPlatform == 1 && nCmapEncoding == 0 )
|
|
{
|
|
nMacRomanCmap = nIndex;
|
|
}
|
|
else if ( nCmapPlatform == 3 && nCmapEncoding == 0 )
|
|
{
|
|
nMSSymbolCmap = nIndex;
|
|
}
|
|
}
|
|
int nCmap = 0;
|
|
BOOL bUseMacRoman = FALSE;
|
|
BOOL bUseUnicode = FALSE;
|
|
if ( m_bHasEncoding )
|
|
{
|
|
if ( m_bUsesMacRomanEncoding && nMacRomanCmap >= 0)
|
|
{
|
|
nCmap = nMacRomanCmap;
|
|
bUseMacRoman = TRUE;
|
|
}
|
|
else if ( nUnicodeCmap >= 0 )
|
|
{
|
|
nCmap = nUnicodeCmap;
|
|
bUseUnicode = TRUE;
|
|
}
|
|
else if ( ( m_nFlags & fontSymbolic ) && nMSSymbolCmap >= 0 )
|
|
{
|
|
nCmap = nMSSymbolCmap;
|
|
}
|
|
else if ( ( m_nFlags & fontSymbolic ) && nMacRomanCmap >= 0 )
|
|
{
|
|
nCmap = nMacRomanCmap;
|
|
}
|
|
else if ( nMacRomanCmap >= 0 )
|
|
{
|
|
nCmap = nMacRomanCmap;
|
|
bUseMacRoman = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( nMSSymbolCmap >= 0 )
|
|
{
|
|
nCmap = nMSSymbolCmap;
|
|
}
|
|
else if ( nMacRomanCmap >= 0 )
|
|
{
|
|
nCmap = nMacRomanCmap;
|
|
}
|
|
}
|
|
|
|
char *sCharName;
|
|
int nCode = 0;
|
|
|
|
if ( bUseMacRoman )
|
|
{
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
if ( ( sCharName = m_ppEncoding[nIndex] ) )
|
|
{
|
|
if ( m_pGlobalParams && ( nCode = m_pGlobalParams->GetMacRomanCharCode(sCharName) ) )
|
|
{
|
|
pMap[nIndex] = pTTF->MapCodeToGID( nCmap, nCode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( bUseUnicode )
|
|
{
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
int nLen = 0;
|
|
Unicode nUnicode = 0;
|
|
if ( ( ( sCharName = m_ppEncoding[nIndex] ) && ( m_pGlobalParams ) && ( nUnicode = m_pGlobalParams->MapNameToUnicode(sCharName) ) ) || ( nLen = m_pCharToUnicode->MapToUnicode((CharCode)nIndex, &nUnicode, 1) ) )
|
|
{
|
|
pMap[nIndex] = pTTF->MapCodeToGID( nCmap, nUnicode);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
if ( !( pMap[nIndex] = pTTF->MapCodeToGID( nCmap, nIndex) ) )
|
|
{
|
|
pMap[nIndex] = pTTF->MapCodeToGID( nCmap, 0xf000 + nIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
if ( !pMap[nIndex] && ( sCharName = m_ppEncoding[nIndex] ) )
|
|
{
|
|
pMap[nIndex] = (unsigned short)(int)pTTF->MapNameToGID(sCharName);
|
|
}
|
|
}
|
|
|
|
return pMap;
|
|
}
|
|
|
|
Dict *Gr8BitFont::GetCharProcs()
|
|
{
|
|
return m_oCharProcs.IsDict() ? m_oCharProcs.GetDict() : (Dict *)NULL;
|
|
}
|
|
|
|
Object *Gr8BitFont::GetCharProc(int nCode, Object *pProc)
|
|
{
|
|
if ( m_ppEncoding[nCode] && m_oCharProcs.IsDict() )
|
|
{
|
|
m_oCharProcs.DictLookup( m_ppEncoding[nCode], pProc);
|
|
}
|
|
else
|
|
{
|
|
pProc->InitNull();
|
|
}
|
|
return pProc;
|
|
}
|
|
|
|
Dict *Gr8BitFont::GetResources()
|
|
{
|
|
return m_oResources.IsDict() ? m_oResources.GetDict() : (Dict *)NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// GrCIDFont
|
|
//------------------------------------------------------------------------
|
|
|
|
static int CompareWidthExceptions(const void *pWidth1, const void *pWidth2)
|
|
{
|
|
return ((GrFontCIDWidthException *)pWidth1)->nFirst - ((GrFontCIDWidthException *)pWidth2)->nFirst;
|
|
}
|
|
|
|
static int CompareWidthExceptionsV(const void *pWidth1, const void *pWidth2)
|
|
{
|
|
return ((GrFontCIDWidthExceptionV *)pWidth1)->nFirst - ((GrFontCIDWidthExceptionV *)pWidth2)->nFirst;
|
|
}
|
|
|
|
GrCIDFont::GrCIDFont(XRef *pXref, char *sTag, Ref oID, StringExt *seName, Dict *pFontDict, GlobalParams *pGlobalParams):
|
|
GrFont(sTag, oID, seName, pGlobalParams)
|
|
{
|
|
m_dAscent = 0.95;
|
|
m_dDescent = -0.35;
|
|
m_arrFontBBox[0] = m_arrFontBBox[1] = m_arrFontBBox[2] = m_arrFontBBox[3] = 0;
|
|
m_pCMap = NULL;
|
|
m_pCharToUnicode = NULL;
|
|
m_oWidths.dDefaultWidth = 1.0;
|
|
m_oWidths.dDefaultHeight = -1.0;
|
|
m_oWidths.dDefaultV = 0.880;
|
|
m_oWidths.pExceptions = NULL;
|
|
m_oWidths.nExceptionsCount = 0;
|
|
m_oWidths.pExceptionsV = NULL;
|
|
m_oWidths.nExceptionsVCount = 0;
|
|
m_pCidToGID = NULL;
|
|
m_nCidToGIDLen = 0;
|
|
|
|
// Descendant font
|
|
Object oDictItem;
|
|
if ( !pFontDict->Search("DescendantFonts", &oDictItem)->IsArray() )
|
|
{
|
|
// TO DO: Error "Missing DescendantFonts entry in Type 0 font"
|
|
oDictItem.Free();
|
|
return;
|
|
}
|
|
Object oDescendantObject;
|
|
if ( !oDictItem.ArrayGet(0, &oDescendantObject)->IsDict() )
|
|
{
|
|
// TO DO: Error "Bad descendant font in Type 0 font"
|
|
oDescendantObject.Free();
|
|
oDictItem.Free();
|
|
return;
|
|
}
|
|
oDictItem.Free();
|
|
|
|
Dict *pDescendantDict = oDescendantObject.GetDict();
|
|
|
|
// Subtype
|
|
|
|
if ( !pDescendantDict->Search("Subtype", &oDictItem) )
|
|
{
|
|
// TO DO: Error "Missing Subtype entry in Type 0 descendant font"
|
|
oDescendantObject.Free();
|
|
oDictItem.Free();
|
|
return;
|
|
}
|
|
if ( oDictItem.IsName("CIDFontType0") )
|
|
{
|
|
m_eType = fontCIDType0;
|
|
}
|
|
else if ( oDictItem.IsName("CIDFontType2") )
|
|
{
|
|
m_eType = fontCIDType2;
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Unknown Type 0 descendant font type"
|
|
oDictItem.Free();
|
|
oDescendantObject.Free();
|
|
return;
|
|
}
|
|
oDictItem.Free();
|
|
|
|
ReadFontDescriptor( pXref, pDescendantDict);
|
|
|
|
// Èùåì âíåøíèé FontFile
|
|
FindExternalFontFile();
|
|
|
|
// Êîäèðîâêà
|
|
|
|
// Char collection
|
|
if ( !pDescendantDict->Search("CIDSystemInfo", &oDictItem)->IsDict() )
|
|
{
|
|
// TO DO: Error "Missing CIDSystemInfo dictionary in Type 0 descendant font"
|
|
oDescendantObject.Free();
|
|
oDictItem.Free();
|
|
return;
|
|
}
|
|
Object oRegistry;
|
|
oDictItem.DictLookup("Registry", &oRegistry);
|
|
Object oOrdering;
|
|
oDictItem.DictLookup("Ordering", &oOrdering);
|
|
|
|
if ( !oRegistry.IsString() || !oOrdering.IsString() )
|
|
{
|
|
// TO DO: Error "Invalid CIDSystemInfo dictionary in Type 0 descendant font"
|
|
oRegistry.Free();
|
|
oOrdering.Free();
|
|
oDescendantObject.Free();
|
|
oDictItem.Free();
|
|
return;
|
|
}
|
|
|
|
StringExt *seCollection = oRegistry.GetString()->Copy()->Append('-')->Append( oOrdering.GetString() );
|
|
oOrdering.Free();
|
|
oRegistry.Free();
|
|
oDictItem.Free();
|
|
|
|
// ToUnicode CMap
|
|
if ( !( m_pCharToUnicode = ReadToUnicodeCMap( pFontDict, 16, NULL) ) )
|
|
{
|
|
|
|
// "Adobe-Identity" è "Adobe-UCS" collections íå èìåþò ôàéëîâ ÑidToUnicode
|
|
if ( seCollection->Compare("Adobe-Identity") && seCollection->Compare("Adobe-UCS") )
|
|
{
|
|
// Èùåì ôàéëû cidToUnicode, äàííûå èçâíå
|
|
if ( m_pGlobalParams && !( m_pCharToUnicode = m_pGlobalParams->GetCIDToUnicode(seCollection) ) )
|
|
{
|
|
// TO DO: Error "Unknown character collection"
|
|
}
|
|
}
|
|
}
|
|
|
|
// Èùåì Unicode-to-Unicode
|
|
CharCodeToUnicode *pUnicodeToUnicode = NULL;
|
|
if ( m_seName && m_pGlobalParams && ( pUnicodeToUnicode = m_pGlobalParams->GetUnicodeToUnicode(m_seName) ) )
|
|
{
|
|
if ( m_pCharToUnicode )
|
|
{
|
|
for ( CharCode nCharCode = 0; nCharCode < m_pCharToUnicode->GetLength(); ++nCharCode )
|
|
{
|
|
Unicode arrUnicodeBuffer[8];
|
|
int nCount = m_pCharToUnicode->MapToUnicode( nCharCode, arrUnicodeBuffer, 8);
|
|
if ( nCount >= 1 )
|
|
{
|
|
nCount = pUnicodeToUnicode->MapToUnicode((CharCode)arrUnicodeBuffer[0], arrUnicodeBuffer, 8);
|
|
if ( nCount >= 1)
|
|
{
|
|
m_pCharToUnicode->SetMapping( nCharCode, arrUnicodeBuffer, nCount);
|
|
}
|
|
}
|
|
}
|
|
pUnicodeToUnicode->Release();
|
|
}
|
|
else
|
|
{
|
|
m_pCharToUnicode = pUnicodeToUnicode;
|
|
}
|
|
}
|
|
|
|
// Êîäèðîâêà (ò.å. CMap)
|
|
pFontDict->Search("Encoding", &oDictItem);
|
|
|
|
if ( oDictItem.IsName() )
|
|
{
|
|
StringExt *seCMapName = new StringExt( oDictItem.GetName() );
|
|
|
|
if ( m_pGlobalParams && !( m_pCMap = m_pGlobalParams->GetCMap( seCollection, seCMapName ) ) )
|
|
{
|
|
// TO DO: Error "Unknown CMap for character collection"
|
|
if ( seCollection )
|
|
delete seCollection;
|
|
if ( seCMapName )
|
|
delete seCMapName;
|
|
|
|
oDictItem.Free();
|
|
oDescendantObject.Free();
|
|
return;
|
|
}
|
|
if ( seCMapName )
|
|
delete seCMapName;
|
|
}
|
|
else if ( oDictItem.IsStream() )
|
|
{
|
|
Stream *pStream = oDictItem.GetStream();
|
|
Dict *pEncDict = pStream->GetDict();
|
|
|
|
Object oEncItem;
|
|
|
|
pEncDict->Search("CMapName", &oEncItem);
|
|
if ( !oEncItem.IsName() )
|
|
{
|
|
if ( seCollection )
|
|
delete seCollection;
|
|
oEncItem.Free();
|
|
oDictItem.Free();
|
|
oDescendantObject.Free();
|
|
return;
|
|
}
|
|
|
|
StringExt *seCMapName = new StringExt( oEncItem.GetName() );
|
|
oEncItem.Free();
|
|
|
|
CString wsTempFile;
|
|
FILE *pFile = NULL;
|
|
if ( !OpenTempFile( &wsTempFile, &pFile, _T("wb"), _T(".cmap"), m_pGlobalParams->GetTempFolder() ) )
|
|
{
|
|
if ( seCollection )
|
|
delete seCollection;
|
|
|
|
if ( seCMapName )
|
|
delete seCMapName;
|
|
|
|
oDictItem.Free();
|
|
oDescendantObject.Free();
|
|
return;
|
|
}
|
|
pStream->Reset();
|
|
int nChar = 0;
|
|
while ( EOF != ( nChar = pStream->GetChar() ) )
|
|
{
|
|
::fputc( nChar, pFile );
|
|
}
|
|
|
|
fclose( pFile );
|
|
|
|
if ( !(m_pCMap = pGlobalParams->GetCMap( seCollection, seCMapName, wsTempFile.GetBuffer() ) ) )
|
|
{
|
|
_wunlink( wsTempFile.GetBuffer() );
|
|
|
|
if ( seCollection )
|
|
delete seCollection;
|
|
|
|
if ( seCMapName )
|
|
delete seCMapName;
|
|
|
|
oDictItem.Free();
|
|
oDescendantObject.Free();
|
|
return;
|
|
}
|
|
|
|
_wunlink( wsTempFile.GetBuffer() );
|
|
|
|
if ( seCMapName )
|
|
delete seCMapName;
|
|
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Missing or invalid Encoding entry in Type 0 font"
|
|
if ( seCollection )
|
|
delete seCollection;
|
|
oDictItem.Free();
|
|
oDescendantObject.Free();
|
|
return;
|
|
}
|
|
oDictItem.Free();
|
|
|
|
if ( seCollection )
|
|
delete seCollection;
|
|
|
|
// CIDToGIDMap (äëÿ âíåäðåííûõ øðèôòîâ-TrueType)
|
|
if ( m_eType == fontCIDType2 )
|
|
{
|
|
pDescendantDict->Search("CIDToGIDMap", &oDictItem);
|
|
if ( oDictItem.IsStream() )
|
|
{
|
|
int nChar1 = 0, nChar2 = 0;
|
|
m_nCidToGIDLen = 0;
|
|
int nLen = 64;
|
|
m_pCidToGID = (unsigned short *)MemUtilsMallocArray( nLen, sizeof(unsigned short));
|
|
oDictItem.StreamReset();
|
|
while ( ( nChar1 = oDictItem.StreamGetChar() ) != EOF && ( nChar2 = oDictItem.StreamGetChar() ) != EOF )
|
|
{
|
|
if ( m_nCidToGIDLen == nLen )
|
|
{
|
|
nLen *= 2;
|
|
m_pCidToGID = (unsigned short *)MemUtilsReallocArray(m_pCidToGID, nLen, sizeof(unsigned short));
|
|
}
|
|
m_pCidToGID[ m_nCidToGIDLen++ ] = (unsigned short)((nChar1 << 8) + nChar2);
|
|
}
|
|
}
|
|
else if ( !oDictItem.IsName("Identity") && !oDictItem.IsNull() )
|
|
{
|
|
// TO DO: Error "Invalid CIDToGIDMap entry in CID font"
|
|
}
|
|
oDictItem.Free();
|
|
}
|
|
|
|
// Ìåòðèêè
|
|
|
|
// Ñòàíäàðòíîå çíà÷åíèå øèðèí
|
|
if ( pDescendantDict->Search("DW", &oDictItem)->IsInt() )
|
|
{
|
|
m_oWidths.dDefaultWidth = oDictItem.GetInt() * 0.001;
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// Èñêëþ÷åíèÿ
|
|
if ( pDescendantDict->Search("W", &oDictItem)->IsArray() )
|
|
{
|
|
int nExceptionsSize = 0;
|
|
int nCounter = 0;
|
|
while ( nCounter + 1 < oDictItem.ArrayGetLength() )
|
|
{
|
|
Object oFirst, oSecond;
|
|
oDictItem.ArrayGet( nCounter, &oFirst);
|
|
oDictItem.ArrayGet( nCounter + 1, &oSecond);
|
|
if ( oFirst.IsInt() && oSecond.IsInt() && nCounter + 2 < oDictItem.ArrayGetLength() )
|
|
{
|
|
// ôîðìàò: C_first C_last W
|
|
Object oWidth;
|
|
if ( oDictItem.ArrayGet( nCounter + 2, &oWidth)->IsNum() )
|
|
{
|
|
if ( m_oWidths.nExceptionsCount == nExceptionsSize )
|
|
{
|
|
nExceptionsSize += 16;
|
|
m_oWidths.pExceptions = (GrFontCIDWidthException *)MemUtilsReallocArray( m_oWidths.pExceptions, nExceptionsSize, sizeof(GrFontCIDWidthException));
|
|
}
|
|
m_oWidths.pExceptions[m_oWidths.nExceptionsCount].nFirst = oFirst.GetInt();
|
|
m_oWidths.pExceptions[m_oWidths.nExceptionsCount].nLast = oSecond.GetInt();
|
|
m_oWidths.pExceptions[m_oWidths.nExceptionsCount].dWidth = oWidth.GetNum() * 0.001;
|
|
++m_oWidths.nExceptionsCount;
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Bad widths array in Type 0 font"
|
|
}
|
|
oWidth.Free();
|
|
nCounter += 3;
|
|
}
|
|
else if ( oFirst.IsInt() && oSecond.IsArray() )
|
|
{
|
|
// Ôîðìàò: c [ w1 w2 … wn ]
|
|
if ( m_oWidths.nExceptionsCount + oSecond.ArrayGetLength() > nExceptionsSize )
|
|
{
|
|
nExceptionsSize = ( m_oWidths.nExceptionsCount + oSecond.ArrayGetLength() + 15) & ~15;
|
|
m_oWidths.pExceptions = (GrFontCIDWidthException *) MemUtilsReallocArray( m_oWidths.pExceptions, nExceptionsSize, sizeof(GrFontCIDWidthException));
|
|
}
|
|
int nCurFirst = oFirst.GetInt();
|
|
for ( int nArrayIndex = 0; nArrayIndex < oSecond.ArrayGetLength(); ++nArrayIndex )
|
|
{
|
|
Object oTemp;
|
|
if ( oSecond.ArrayGet( nArrayIndex, &oTemp)->IsNum() )
|
|
{
|
|
m_oWidths.pExceptions[m_oWidths.nExceptionsCount].nFirst = nCurFirst;
|
|
m_oWidths.pExceptions[m_oWidths.nExceptionsCount].nLast = nCurFirst;
|
|
m_oWidths.pExceptions[m_oWidths.nExceptionsCount].dWidth = oTemp.GetNum() * 0.001;
|
|
++nCurFirst;
|
|
++m_oWidths.nExceptionsCount;
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Bad widths array in Type 0 font"
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
nCounter += 2;
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Bad widths array in Type 0 font");
|
|
++nCounter;
|
|
}
|
|
oSecond.Free();
|
|
oFirst.Free();
|
|
}
|
|
qsort(m_oWidths.pExceptions, m_oWidths.nExceptionsCount, sizeof(GrFontCIDWidthException), &CompareWidthExceptions);
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// Ñòàíäàðòíûå ìåòðèêè ïî âåðòèêàëè
|
|
if ( pDescendantDict->Search("DW2", &oDictItem)->IsArray() && oDictItem.ArrayGetLength() == 2 )
|
|
{
|
|
Object oTemp;
|
|
if ( oDictItem.ArrayGet( 0, &oTemp)->IsNum() )
|
|
{
|
|
m_oWidths.dDefaultV = oTemp.GetNum() * 0.001;
|
|
}
|
|
oTemp.Free();
|
|
|
|
if ( oDictItem.ArrayGet( 1, &oTemp)->IsNum() )
|
|
{
|
|
m_oWidths.dDefaultHeight = oTemp.GetNum() * 0.001;
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
oDictItem.Free();
|
|
|
|
// Èñêëþ÷åíèÿ
|
|
if ( pDescendantDict->Search("W2", &oDictItem)->IsArray() )
|
|
{
|
|
int nExceptionsSize = 0;
|
|
int nCounter = 0;
|
|
while ( nCounter + 1 < oDictItem.ArrayGetLength() )
|
|
{
|
|
Object oFirst, oSecond;
|
|
oDictItem.ArrayGet( nCounter, &oFirst);
|
|
oDictItem.ArrayGet( nCounter + 1, &oSecond);
|
|
if ( oFirst.IsInt() && oSecond.IsInt() && nCounter + 4 < oDictItem.ArrayGetLength() )
|
|
{
|
|
// Ôîðìàò: Ñ_first Ñ_last W11y V1x V1y
|
|
Object oHeight, oVx, oVy;
|
|
if ( oDictItem.ArrayGet( nCounter + 2, &oHeight)->IsNum() && oDictItem.ArrayGet( nCounter + 3, &oVx)->IsNum() && oDictItem.ArrayGet( nCounter + 4, &oVy)->IsNum() )
|
|
{
|
|
if ( m_oWidths.nExceptionsVCount == nExceptionsSize )
|
|
{
|
|
nExceptionsSize += 16;
|
|
m_oWidths.pExceptionsV = (GrFontCIDWidthExceptionV *) MemUtilsReallocArray(m_oWidths.pExceptionsV, nExceptionsSize, sizeof(GrFontCIDWidthExceptionV));
|
|
}
|
|
m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].nFirst = oFirst.GetInt();
|
|
m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].nLast = oSecond.GetInt();
|
|
m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dHeight = oHeight.GetNum() * 0.001;
|
|
m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dVx = oVx.GetNum() * 0.001;
|
|
m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dVy = oVy.GetNum() * 0.001;
|
|
++m_oWidths.nExceptionsVCount;
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Bad widths (W2) array in Type 0 font"
|
|
}
|
|
oVy.Free();
|
|
oVx.Free();
|
|
oHeight.Free();
|
|
nCounter += 5;
|
|
}
|
|
else if ( oFirst.IsInt() && oSecond.IsArray() )
|
|
{
|
|
if ( m_oWidths.nExceptionsVCount + oSecond.ArrayGetLength() / 3 > nExceptionsSize )
|
|
{
|
|
nExceptionsSize = ( m_oWidths.nExceptionsVCount + oSecond.ArrayGetLength() / 3 + 15 ) & ~15;
|
|
m_oWidths.pExceptionsV = (GrFontCIDWidthExceptionV *) MemUtilsReallocArray( m_oWidths.pExceptionsV, nExceptionsSize, sizeof(GrFontCIDWidthExceptionV));
|
|
}
|
|
int nCurFirst = oFirst.GetInt();
|
|
for ( int nArrayIndex = 0; nArrayIndex < oSecond.ArrayGetLength(); nArrayIndex += 3 )
|
|
{
|
|
Object oHeight, oVx, oVy;
|
|
if ( oSecond.ArrayGet( nArrayIndex, &oHeight)->IsNum() && oSecond.ArrayGet( nArrayIndex + 1, &oVx)->IsNum() && oSecond.ArrayGet( nArrayIndex + 2, &oVy)->IsNum() )
|
|
{
|
|
// TO DO: Çäåñü áûëî èñïðàâëåíî!!! íåïðàâèëüíûå èíäåêñû ïåðåäàâàëèñü -> âìåñòî nExceptionsVCount ïåðåäàâàëèñü nExceptionsCount
|
|
m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].nFirst = nCurFirst;
|
|
m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].nLast = nCurFirst;
|
|
m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dHeight = oHeight.GetNum() * 0.001;
|
|
m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dVx = oVx.GetNum() * 0.001;
|
|
m_oWidths.pExceptionsV[m_oWidths.nExceptionsVCount].dVy = oVy.GetNum() * 0.001;
|
|
++nCurFirst;
|
|
++m_oWidths.nExceptionsVCount;
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Bad widths (W2) array in Type 0 font"
|
|
}
|
|
oVy.Free();
|
|
oVx.Free();
|
|
oHeight.Free();
|
|
}
|
|
nCounter += 2;
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Bad widths (W2) array in Type 0 font"
|
|
++nCounter;
|
|
}
|
|
oSecond.Free();
|
|
oFirst.Free();
|
|
}
|
|
qsort( m_oWidths.pExceptionsV, m_oWidths.nExceptionsVCount, sizeof(GrFontCIDWidthExceptionV), &CompareWidthExceptionsV);
|
|
}
|
|
oDictItem.Free();
|
|
|
|
oDescendantObject.Free();
|
|
m_bValid = TRUE;
|
|
return;
|
|
}
|
|
|
|
GrCIDFont::~GrCIDFont()
|
|
{
|
|
if ( m_pCMap )
|
|
{
|
|
m_pCMap->Release();
|
|
}
|
|
if ( m_pCharToUnicode )
|
|
{
|
|
m_pCharToUnicode->Release();
|
|
}
|
|
|
|
MemUtilsFree(m_oWidths.pExceptions);
|
|
MemUtilsFree(m_oWidths.pExceptionsV);
|
|
|
|
if ( m_pCidToGID )
|
|
{
|
|
MemUtilsFree(m_pCidToGID);
|
|
}
|
|
}
|
|
|
|
int GrCIDFont::GetNextChar(char *sText, int nLen, CharCode *punCode, Unicode *punUnicode, int uSize, int *uLen, double *pdDx, double *pdDy, double *pdVx, double *pdVy)
|
|
{
|
|
CID nCID = 0;
|
|
int nCount = 0;
|
|
|
|
if ( !m_pCMap )
|
|
{
|
|
*punCode = 0;
|
|
*uLen = 0;
|
|
*pdDx = *pdDy = 0;
|
|
return 1;
|
|
}
|
|
|
|
*punCode = (CharCode)( nCID = m_pCMap->GetCID( sText, nLen, &nCount) );
|
|
// Âðåìåííî
|
|
|
|
*uLen = nCount;
|
|
if ( 1 == nCount )
|
|
*punUnicode = sText[0];
|
|
else if ( 2 == nCount )
|
|
{
|
|
*punUnicode = 0;
|
|
*punUnicode |= sText[0] & 0xFF;
|
|
*punUnicode <<= 8;
|
|
*punUnicode |= sText[1] & 0xFF;
|
|
}
|
|
else
|
|
{
|
|
*uLen = 0;
|
|
*punUnicode = 0;
|
|
}
|
|
|
|
//if ( m_pCharToUnicode )
|
|
//{
|
|
// *uLen = m_pCharToUnicode->MapToUnicode( nCID, punUnicode, uSize);
|
|
//}
|
|
//else
|
|
//{
|
|
// *uLen = 0;
|
|
//}
|
|
|
|
double dWidth = 0, dHeight = 0, dVx = 0, dVy = 0;
|
|
// Horizontal
|
|
if ( m_pCMap->GetWMode() == 0)
|
|
{
|
|
dWidth = m_oWidths.dDefaultWidth;
|
|
dHeight = dVx = dVy = 0;
|
|
if ( m_oWidths.nExceptionsCount > 0 && nCID >= m_oWidths.pExceptions[0].nFirst )
|
|
{
|
|
int nFirst = 0;
|
|
int nLast = m_oWidths.nExceptionsCount;
|
|
|
|
while ( nLast - nFirst > 1 )
|
|
{
|
|
int nMiddle = (nFirst + nLast) / 2;
|
|
if ( m_oWidths.pExceptions[nMiddle].nFirst <= nCID )
|
|
{
|
|
nFirst = nMiddle;
|
|
}
|
|
else
|
|
{
|
|
nLast = nMiddle;
|
|
}
|
|
}
|
|
if ( nCID <= m_oWidths.pExceptions[nFirst].nLast )
|
|
{
|
|
dWidth = m_oWidths.pExceptions[nFirst].dWidth;
|
|
}
|
|
}
|
|
}
|
|
else // Vertical
|
|
{
|
|
dWidth = 0;
|
|
dHeight = m_oWidths.dDefaultHeight;
|
|
dVx = m_oWidths.dDefaultWidth / 2;
|
|
dVy = m_oWidths.dDefaultV;
|
|
if ( m_oWidths.nExceptionsVCount > 0 && nCID >= m_oWidths.pExceptionsV[0].nFirst )
|
|
{
|
|
int nFirst = 0;
|
|
int nLast = m_oWidths.nExceptionsVCount;
|
|
|
|
while ( nLast - nFirst > 1 )
|
|
{
|
|
int nMiddle = (nFirst + nLast) / 2;
|
|
if ( m_oWidths.pExceptionsV[nMiddle].nLast <= nCID )
|
|
{
|
|
nFirst = nMiddle;
|
|
}
|
|
else
|
|
{
|
|
nLast = nMiddle;
|
|
}
|
|
}
|
|
if ( nCID <= m_oWidths.pExceptionsV[nFirst].nLast )
|
|
{
|
|
dHeight = m_oWidths.pExceptionsV[nFirst].dHeight;
|
|
dVx = m_oWidths.pExceptionsV[nFirst].dVx;
|
|
dVy = m_oWidths.pExceptionsV[nFirst].dVy;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pdDx = dWidth;
|
|
*pdDy = dHeight;
|
|
*pdVx = dVx;
|
|
*pdVy = dVy;
|
|
|
|
return nCount;
|
|
}
|
|
|
|
int GrCIDFont::GetWMode()
|
|
{
|
|
return m_pCMap ? m_pCMap->GetWMode() : 0;
|
|
}
|
|
|
|
CharCodeToUnicode *GrCIDFont::GetToUnicode()
|
|
{
|
|
if ( m_pCharToUnicode )
|
|
{
|
|
m_pCharToUnicode->AddRef();
|
|
}
|
|
return m_pCharToUnicode;
|
|
}
|
|
|
|
StringExt *GrCIDFont::GetCollection()
|
|
{
|
|
return m_pCMap ? m_pCMap->GetCollection() : (StringExt *)NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// GrFontDict
|
|
//------------------------------------------------------------------------
|
|
|
|
GrFontDict::GrFontDict(XRef *pXref, Ref *pFontDictRef, Dict *pFontDict, GlobalParams *pGlobalParams)
|
|
{
|
|
m_pGlobalParams = pGlobalParams;
|
|
|
|
Ref oRef;
|
|
|
|
m_nFontsCount = pFontDict->GetEntryCount();
|
|
m_ppFonts = (GrFont **)MemUtilsMallocArray( m_nFontsCount, sizeof(GrFont *));
|
|
for ( int nIndex = 0; nIndex < m_nFontsCount; ++nIndex )
|
|
{
|
|
Object oFontRef, oFont;
|
|
pFontDict->GetValueCopy( nIndex, &oFontRef);
|
|
oFontRef.Fetch( pXref, &oFont);
|
|
if ( oFont.IsDict() )
|
|
{
|
|
if ( oFontRef.IsRef())
|
|
{
|
|
oRef = oFontRef.GetRef();
|
|
}
|
|
else
|
|
{
|
|
// Íåò ññûëêè íà äàííûé øðèôò, íî ññûëêà íàì íóæíà êàê èäåíòåôèêàòîð, ïîýòîìó âûáèðàåì íåêîòûé óíèêàëüíûé íîìåð
|
|
// (ïîñêîëüêó êîððåêòíîå âåðñèîííîå ÷èñëî ñîñòîèò èç 5 öèôð, ïîýòîìó ëþáîå 6-öèôåðíîå ÷èñëî áóäåò áåçîïàñíûì ðåøåíèåì)
|
|
oRef.nNum = nIndex;
|
|
if ( pFontDictRef )
|
|
{
|
|
oRef.nGen = 100000 + pFontDictRef->nNum;
|
|
}
|
|
else
|
|
{
|
|
oRef.nGen = 999999;
|
|
}
|
|
}
|
|
m_ppFonts[nIndex] = GrFont::MakeFont( pXref, pFontDict->GetKey(nIndex), oRef, oFont.GetDict(), pGlobalParams );
|
|
if ( m_ppFonts[nIndex] && !m_ppFonts[nIndex]->CheckValidate() )
|
|
{
|
|
if ( m_ppFonts[nIndex] )
|
|
delete m_ppFonts[nIndex];
|
|
m_ppFonts[nIndex] = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "font resource is not a dictionary"
|
|
m_ppFonts[nIndex] = NULL;
|
|
}
|
|
oFontRef.Free();
|
|
oFont.Free();
|
|
}
|
|
}
|
|
|
|
GrFontDict::~GrFontDict()
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nFontsCount; ++nIndex )
|
|
{
|
|
if ( m_ppFonts[nIndex] )
|
|
{
|
|
delete m_ppFonts[nIndex];
|
|
}
|
|
}
|
|
MemUtilsFree(m_ppFonts);
|
|
}
|
|
|
|
GrFont *GrFontDict::Search(char *sTag)
|
|
{
|
|
for ( int nIndex = 0; nIndex < m_nFontsCount; ++nIndex )
|
|
{
|
|
if ( m_ppFonts[nIndex] && m_ppFonts[nIndex]->CheckTag(sTag) )
|
|
{
|
|
return m_ppFonts[nIndex];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|