tdf#125234 Qt5 implement CreateFontSubset

This abstracts the just refactored vcl::TrueTypeFont class, so the
Qt5 backend can provide it's own QRawFont based font table access.

Change-Id: Ic71bc95bc8fe39bc7a32086d4adc78cfa00d15be
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100718
Tested-by: Jenkins
Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de>
This commit is contained in:
Jan-Marek Glogowski
2020-08-14 05:53:26 +02:00
parent 4c05d61a43
commit 5a888c5fd2
7 changed files with 226 additions and 49 deletions

View File

@@ -45,6 +45,7 @@ public:
sal_IntPtr GetFontId() const override;
QFont CreateFont() const;
int GetFontTable(const char pTagName[5], unsigned char*) const;
const FontCharMapRef& GetFontCharMap() const;

View File

@@ -447,6 +447,7 @@ constexpr sal_uInt32 T_fpgm = 0x6670676D;
constexpr sal_uInt32 T_gsub = 0x47535542;
constexpr sal_uInt32 T_CFF = 0x43464620;
class AbstractTrueTypeFont;
class TrueTypeFont;
/**
@@ -512,7 +513,7 @@ class TrueTypeFont;
* @ingroup sft
*
*/
int GetTTGlyphPoints(TrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray);
int GetTTGlyphPoints(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray);
/**
* Extracts raw glyph data from the 'glyf' table and returns it in an allocated
@@ -526,7 +527,7 @@ class TrueTypeFont;
* @ingroup sft
*
*/
GlyphData *GetTTRawGlyphData(TrueTypeFont *ttf, sal_uInt32 glyphID);
GlyphData *GetTTRawGlyphData(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID);
/**
* For a specified glyph adds all component glyphs IDs to the list and
@@ -543,7 +544,7 @@ class TrueTypeFont;
* @ingroup sft
*
*/
int GetTTGlyphComponents(TrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< sal_uInt32 >& glyphlist);
int GetTTGlyphComponents(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< sal_uInt32 >& glyphlist);
/**
* Extracts all Name Records from the font and stores them in an allocated
@@ -556,7 +557,7 @@ class TrueTypeFont;
* @ingroup sft
*/
int GetTTNameRecords(TrueTypeFont const *ttf, NameRecord **nr);
int GetTTNameRecords(AbstractTrueTypeFont const *ttf, NameRecord **nr);
/**
* Deallocates previously allocated array of NameRecords.
@@ -604,7 +605,7 @@ class TrueTypeFont;
* @ingroup sft
*
*/
VCL_DLLPUBLIC SFErrCodes CreateTTFromTTGlyphs(TrueTypeFont *ttf,
VCL_DLLPUBLIC SFErrCodes CreateTTFromTTGlyphs(AbstractTrueTypeFont *ttf,
const char *fname,
sal_uInt16 const *glyphArray,
sal_uInt8 const *encoding,
@@ -647,7 +648,7 @@ class TrueTypeFont;
* @ingroup sft
*
*/
VCL_DLLPUBLIC std::unique_ptr<sal_uInt16[]> GetTTSimpleGlyphMetrics(TrueTypeFont const *ttf, const sal_uInt16 *glyphArray, int nGlyphs, bool vertical);
VCL_DLLPUBLIC std::unique_ptr<sal_uInt16[]> GetTTSimpleGlyphMetrics(AbstractTrueTypeFont const *ttf, const sal_uInt16 *glyphArray, int nGlyphs, bool vertical);
#if defined(_WIN32) || defined(MACOSX) || defined(IOS)
/**
@@ -709,7 +710,7 @@ constexpr int O_gsub = 15; /* 'GSUB' */
constexpr int O_CFF = 16; /* 'CFF' */
constexpr int NUM_TAGS = 17;
class TrueTypeFont final
class VCL_DLLPUBLIC AbstractTrueTypeFont
{
char* m_pFileName;
sal_uInt32 m_nGlyphs;
@@ -718,6 +719,26 @@ class TrueTypeFont final
sal_uInt32 m_nVertMetrics; /* if not 0 => font has vertical metrics information */
sal_uInt32 m_nUnitsPerEm;
protected:
SFErrCodes indexGlyphData();
public:
AbstractTrueTypeFont(const char* fileName = nullptr);
virtual ~AbstractTrueTypeFont();
const char* fileName() const { return m_pFileName; }
sal_uInt32 glyphCount() const { return m_nGlyphs; }
sal_uInt32 glyphOffset(sal_uInt32 glyphID) const { return m_pGlyphOffsets[glyphID]; }
sal_uInt32 horzMetricCount() const { return m_nHorzMetrics; }
sal_uInt32 vertMetricCount() const { return m_nVertMetrics; }
sal_uInt32 unitsPerEm() const { return m_nUnitsPerEm; }
virtual bool hasTable(sal_uInt32 ord) const = 0;
virtual const sal_uInt8* table(sal_uInt32 ord, sal_uInt32& size) const = 0;
};
class TrueTypeFont final : public AbstractTrueTypeFont
{
struct TTFontTable_
{
const sal_uInt8* pData = nullptr; /* pointer to a raw subtable in the SFNT file */
@@ -726,8 +747,6 @@ class TrueTypeFont final
std::array<struct TTFontTable_, NUM_TAGS> m_aTableList;
SFErrCodes indexGlyphData();
public:
sal_Int32 fsize;
sal_uInt8 *ptr;
@@ -744,19 +763,12 @@ public:
sal_uInt32 (*mapper)(const sal_uInt8 *, sal_uInt32, sal_uInt32); /* character to glyphID translation function */
TrueTypeFont(const char* pFileName = nullptr);
~TrueTypeFont();
~TrueTypeFont() override;
SFErrCodes open(sal_uInt32 facenum);
const char* fileName() const { return m_pFileName; }
sal_uInt32 glyphCount() const { return m_nGlyphs; }
sal_uInt32 glyphOffset(sal_uInt32 glyphID) const { return m_pGlyphOffsets[glyphID]; }
sal_uInt32 horzMetricCount() const { return m_nHorzMetrics; }
sal_uInt32 vertMetricCount() const { return m_nVertMetrics; }
sal_uInt32 unitsPerEm() const { return m_nUnitsPerEm; }
bool hasTable(sal_uInt32 ord) const { return m_aTableList[ord].pData != nullptr; }
inline const sal_uInt8* table(sal_uInt32 ord, sal_uInt32& size) const;
bool hasTable(sal_uInt32 ord) const override { return m_aTableList[ord].pData != nullptr; }
inline const sal_uInt8* table(sal_uInt32 ord, sal_uInt32& size) const override;
};
const sal_uInt8* TrueTypeFont::table(sal_uInt32 ord, sal_uInt32& size) const

View File

@@ -149,6 +149,13 @@ Qt5FontFace::Qt5FontFace(const FontAttributes& rFA, const QString& rFontID)
sal_IntPtr Qt5FontFace::GetFontId() const { return reinterpret_cast<sal_IntPtr>(&m_aFontId); }
QFont Qt5FontFace::CreateFont() const
{
QFont aFont;
aFont.fromString(m_aFontId);
return aFont;
}
rtl::Reference<LogicalFontInstance>
Qt5FontFace::CreateFontInstance(const FontSelectPattern& rFSD) const
{

View File

@@ -22,6 +22,7 @@
#include <Qt5Font.hxx>
#include <Qt5Painter.hxx>
#include <fontsubset.hxx>
#include <vcl/fontcharmap.hxx>
#include <unx/geninst.h>
#include <unx/fontmanager.hxx>
@@ -129,12 +130,161 @@ bool Qt5Graphics::AddTempDevFont(PhysicalFontCollection*, const OUString& /*rFil
return false;
}
bool Qt5Graphics::CreateFontSubset(const OUString& /*rToFile*/, const PhysicalFontFace* /*pFont*/,
const sal_GlyphId* /*pGlyphIds*/, const sal_uInt8* /*pEncoding*/,
sal_Int32* /*pWidths*/, int /*nGlyphs*/,
FontSubsetInfo& /*rInfo*/)
namespace
{
return false;
class Qt5TrueTypeFont : public vcl::AbstractTrueTypeFont
{
const QRawFont& m_aRawFont;
mutable QByteArray m_aFontTable[vcl::NUM_TAGS];
public:
Qt5TrueTypeFont(const QRawFont& aRawFont);
bool hasTable(sal_uInt32 ord) const override;
const sal_uInt8* table(sal_uInt32 ord, sal_uInt32& size) const override;
};
Qt5TrueTypeFont::Qt5TrueTypeFont(const QRawFont& aRawFont)
: m_aRawFont(aRawFont)
{
indexGlyphData();
}
const char* vclFontTableAsChar(sal_uInt32 ord)
{
switch (ord)
{
case vcl::O_maxp:
return "maxp";
case vcl::O_glyf:
return "glyf";
case vcl::O_head:
return "head";
case vcl::O_loca:
return "loca";
case vcl::O_name:
return "name";
case vcl::O_hhea:
return "hhea";
case vcl::O_hmtx:
return "hmtx";
case vcl::O_cmap:
return "cmap";
case vcl::O_vhea:
return "vhea";
case vcl::O_vmtx:
return "vmtx";
case vcl::O_OS2:
return "OS/2";
case vcl::O_post:
return "post";
case vcl::O_cvt:
return "cvt ";
case vcl::O_prep:
return "prep";
case vcl::O_fpgm:
return "fpgm";
case vcl::O_gsub:
return "gsub";
case vcl::O_CFF:
return "CFF ";
default:
return nullptr;
}
}
bool Qt5TrueTypeFont::hasTable(sal_uInt32 ord) const
{
const char* table_char = vclFontTableAsChar(ord);
if (!table_char)
return false;
if (m_aFontTable[ord].isEmpty())
m_aFontTable[ord] = m_aRawFont.fontTable(table_char);
return !m_aFontTable[ord].isEmpty();
}
const sal_uInt8* Qt5TrueTypeFont::table(sal_uInt32 ord, sal_uInt32& size) const
{
const char* table_char = vclFontTableAsChar(ord);
if (!table_char)
return nullptr;
if (m_aFontTable[ord].isEmpty())
m_aFontTable[ord] = m_aRawFont.fontTable(table_char);
size = m_aFontTable[ord].size();
return reinterpret_cast<const sal_uInt8*>(m_aFontTable[ord].data());
}
}
bool Qt5Graphics::CreateFontSubset(const OUString& rToFile, const PhysicalFontFace* pFontFace,
const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding,
sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo)
{
// prepare the requested file name for writing the font-subset file
OUString aSysPath;
if (osl_File_E_None != osl_getSystemPathFromFileURL(rToFile.pData, &aSysPath.pData))
return false;
// get the raw-bytes from the font to be subset
const QFont aFont = static_cast<const Qt5FontFace*>(pFontFace)->CreateFont();
const QRawFont aRawFont(QRawFont::fromFont(aFont));
const QFontInfo aFontInfo(aFont);
const OString aToFile(OUStringToOString(aSysPath, osl_getThreadTextEncoding()));
const int nOrigGlyphCount = nGlyphCount;
// get details about the subsetted font
rInfo.m_nFontType = FontType::SFNT_TTF;
rInfo.m_aPSName = toOUString(aRawFont.familyName());
rInfo.m_nCapHeight = aRawFont.capHeight();
rInfo.m_nAscent = aRawFont.ascent();
rInfo.m_nDescent = aRawFont.descent();
sal_uInt16 aShortIDs[nGlyphCount + 1];
sal_uInt8 aTempEncs[nGlyphCount + 1];
quint32 aQtGlyphId[nGlyphCount + 1];
int nNotDef = -1;
for (int i = 0; i < nGlyphCount; ++i)
{
aTempEncs[i] = pEncoding[i];
sal_GlyphId aGlyphId(pGlyphIds[i]);
aShortIDs[i] = static_cast<sal_uInt16>(aGlyphId);
aQtGlyphId[i] = aShortIDs[i];
if (!aGlyphId && nNotDef < 0)
nNotDef = i; // first NotDef glyph found
}
if (nNotDef != 0)
{
// add fake NotDef glyph if needed
if (nNotDef < 0)
nNotDef = nGlyphCount++;
// NotDef glyph must be in pos 0 => swap glyphids
aShortIDs[nNotDef] = aShortIDs[0];
aTempEncs[nNotDef] = aTempEncs[0];
aQtGlyphId[nNotDef] = aQtGlyphId[0];
aShortIDs[0] = 0;
aTempEncs[0] = 0;
aQtGlyphId[0] = 0;
}
QPointF anAdvanceList[nGlyphCount];
if (!aRawFont.advancesForGlyphIndexes(aQtGlyphId, anAdvanceList, nGlyphCount))
return false;
QPointF nNotDefAdv = anAdvanceList[0];
anAdvanceList[0] = anAdvanceList[nNotDef];
anAdvanceList[nNotDef] = nNotDefAdv;
for (int i = 0; i < nOrigGlyphCount; ++i)
pGlyphWidths[i] = round(anAdvanceList[i].x());
// write subset into destination file
Qt5TrueTypeFont aTTF(aRawFont);
vcl::SFErrCodes nRC
= vcl::CreateTTFromTTGlyphs(&aTTF, aToFile.getStr(), aShortIDs, aTempEncs, nGlyphCount);
return (nRC == vcl::SFErrCodes::Ok);
}
const void* Qt5Graphics::GetEmbedFontData(const PhysicalFontFace*, long* /*pDataLen*/)

View File

@@ -315,7 +315,7 @@ static void HexFmtBlockWrite(HexFmt *_this, const void *ptr, sal_uInt32 size)
/* Outline Extraction functions */
/* fills the aw and lsb entries of the TTGlyphMetrics structure from hmtx table -*/
static void GetMetrics(TrueTypeFont const *ttf, sal_uInt32 glyphID, TTGlyphMetrics *metrics)
static void GetMetrics(AbstractTrueTypeFont const *ttf, sal_uInt32 glyphID, TTGlyphMetrics *metrics)
{
sal_uInt32 nSize;
const sal_uInt8* table = ttf->table(O_hmtx, nSize);
@@ -345,10 +345,10 @@ static void GetMetrics(TrueTypeFont const *ttf, sal_uInt32 glyphID, TTGlyphMetri
metrics->ah = GetUInt16(table, 4 * (ttf->vertMetricCount() - 1));
}
static int GetTTGlyphOutline(TrueTypeFont *, sal_uInt32 , ControlPoint **, TTGlyphMetrics *, std::vector< sal_uInt32 >* );
static int GetTTGlyphOutline(AbstractTrueTypeFont *, sal_uInt32 , ControlPoint **, TTGlyphMetrics *, std::vector< sal_uInt32 >* );
/* returns the number of control points, allocates the pointArray */
static int GetSimpleTTOutline(TrueTypeFont const *ttf, sal_uInt32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics)
static int GetSimpleTTOutline(AbstractTrueTypeFont const *ttf, sal_uInt32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics)
{
sal_uInt32 nTableSize;
const sal_uInt8* table = ttf->table(O_glyf, nTableSize);
@@ -474,7 +474,7 @@ static F16Dot16 fromF2Dot14(sal_Int16 n)
return sal_uInt32(n) << 2;
}
static int GetCompoundTTOutline(TrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics, std::vector< sal_uInt32 >& glyphlist)
static int GetCompoundTTOutline(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics, std::vector< sal_uInt32 >& glyphlist)
{
sal_uInt16 flags, index;
sal_Int16 e, f;
@@ -643,7 +643,7 @@ static int GetCompoundTTOutline(TrueTypeFont *ttf, sal_uInt32 glyphID, ControlPo
* a composite glyph. This is a safeguard against endless recursion
* in corrupted fonts.
*/
static int GetTTGlyphOutline(TrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics, std::vector< sal_uInt32 >* glyphlist)
static int GetTTGlyphOutline(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray, TTGlyphMetrics *metrics, std::vector< sal_uInt32 >* glyphlist)
{
sal_uInt32 nSize;
const sal_uInt8 *table = ttf->table(O_glyf, nSize);
@@ -1448,13 +1448,26 @@ bool withinBounds(sal_uInt32 tdoffset, sal_uInt32 moreoffset, sal_uInt32 len, sa
}
}
TrueTypeFont::TrueTypeFont(const char* pFileName)
AbstractTrueTypeFont::AbstractTrueTypeFont(const char* pFileName)
: m_pFileName(nullptr)
, m_nGlyphs(0xFFFFFFFF)
, m_pGlyphOffsets(nullptr)
, m_nHorzMetrics(0)
, m_nVertMetrics(0)
, m_nUnitsPerEm(0)
{
if (pFileName)
m_pFileName = strdup(pFileName);
}
AbstractTrueTypeFont::~AbstractTrueTypeFont()
{
free(m_pFileName);
free(m_pGlyphOffsets);
}
TrueTypeFont::TrueTypeFont(const char* pFileName)
: AbstractTrueTypeFont(pFileName)
, fsize(-1)
, ptr(nullptr)
, psname(nullptr)
@@ -1466,18 +1479,14 @@ TrueTypeFont::TrueTypeFont(const char* pFileName)
, cmap(nullptr)
, cmapType(0)
{
if (pFileName)
m_pFileName = strdup(pFileName);
}
TrueTypeFont::~TrueTypeFont()
{
#if !defined(_WIN32)
if (m_pFileName)
if (fileName())
munmap(ptr, fsize);
#endif
free(m_pFileName);
free(m_pGlyphOffsets);
free(psname);
free(family);
free(ufamily);
@@ -1487,7 +1496,7 @@ TrueTypeFont::~TrueTypeFont()
void CloseTTFont(TrueTypeFont* ttf) { delete ttf; }
SFErrCodes TrueTypeFont::indexGlyphData()
SFErrCodes AbstractTrueTypeFont::indexGlyphData()
{
if (!(hasTable(O_maxp) && hasTable(O_head) && hasTable(O_name) && hasTable(O_cmap)))
return SFErrCodes::TtFormat;
@@ -1699,12 +1708,12 @@ SFErrCodes TrueTypeFont::open(sal_uInt32 facenum)
return SFErrCodes::Ok;
}
int GetTTGlyphPoints(TrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray)
int GetTTGlyphPoints(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray)
{
return GetTTGlyphOutline(ttf, glyphID, pointArray, nullptr, nullptr);
}
int GetTTGlyphComponents(TrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< sal_uInt32 >& glyphlist)
int GetTTGlyphComponents(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< sal_uInt32 >& glyphlist)
{
int n = 1;
@@ -1902,7 +1911,7 @@ SFErrCodes CreateT3FromTTGlyphs(TrueTypeFont *ttf, FILE *outf, const char *fname
return SFErrCodes::Ok;
}
SFErrCodes CreateTTFromTTGlyphs(TrueTypeFont *ttf,
SFErrCodes CreateTTFromTTGlyphs(AbstractTrueTypeFont *ttf,
const char *fname,
sal_uInt16 const *glyphArray,
sal_uInt8 const *encoding,
@@ -2285,7 +2294,7 @@ sal_uInt16 MapChar(TrueTypeFont const *ttf, sal_uInt16 ch)
#endif
std::unique_ptr<sal_uInt16[]> GetTTSimpleGlyphMetrics(TrueTypeFont const *ttf, const sal_uInt16 *glyphArray, int nGlyphs, bool vertical)
std::unique_ptr<sal_uInt16[]> GetTTSimpleGlyphMetrics(AbstractTrueTypeFont const *ttf, const sal_uInt16 *glyphArray, int nGlyphs, bool vertical)
{
const sal_uInt8* pTable;
sal_uInt32 n;
@@ -2415,7 +2424,7 @@ void GetTTGlobalFontInfo(TrueTypeFont *ttf, TTGlobalFontInfo *info)
}
}
GlyphData *GetTTRawGlyphData(TrueTypeFont *ttf, sal_uInt32 glyphID)
GlyphData *GetTTRawGlyphData(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID)
{
sal_uInt32 length;
const sal_uInt8* hmtx = ttf->table(O_hmtx, length);
@@ -2479,7 +2488,7 @@ GlyphData *GetTTRawGlyphData(TrueTypeFont *ttf, sal_uInt32 glyphID)
return d;
}
int GetTTNameRecords(TrueTypeFont const *ttf, NameRecord **nr)
int GetTTNameRecords(AbstractTrueTypeFont const *ttf, NameRecord **nr)
{
sal_uInt32 nTableSize;
const sal_uInt8* table = ttf->table(O_name, nTableSize);
@@ -2538,14 +2547,12 @@ int GetTTNameRecords(TrueTypeFont const *ttf, NameRecord **nr)
continue;
}
const sal_uInt8* rec_string = table + nStrBase + nStrOffset;
// sanity check
const sal_uInt8* end_table = ttf->ptr + ttf->fsize;
const size_t available_space = rec_string > end_table ? 0 : (end_table - rec_string);
const sal_uInt32 rec_string = nStrBase + nStrOffset;
const size_t available_space = rec_string > nTableSize ? 0 : (nTableSize - rec_string);
if (rec[i].slen <= available_space)
{
rec[i].sptr = static_cast<sal_uInt8 *>(malloc(rec[i].slen)); assert(rec[i].sptr != nullptr);
memcpy(rec[i].sptr, rec_string, rec[i].slen);
memcpy(rec[i].sptr, table + rec_string, rec[i].slen);
}
else
{

View File

@@ -1142,7 +1142,7 @@ void cmapAdd(TrueTypeTable *table, sal_uInt32 id, sal_uInt32 c, sal_uInt32 g)
s[i].n++;
}
sal_uInt32 glyfAdd(TrueTypeTable *table, GlyphData *glyphdata, TrueTypeFont *fnt)
sal_uInt32 glyfAdd(TrueTypeTable *table, GlyphData *glyphdata, AbstractTrueTypeFont *fnt)
{
list l;
sal_uInt32 currentID;

View File

@@ -192,7 +192,7 @@ namespace vcl
* NOTE: This function does not duplicate GlyphData, so memory will be
* deallocated in the table destructor
*/
sal_uInt32 glyfAdd(TrueTypeTable *, GlyphData *glyphdata, TrueTypeFont *fnt);
sal_uInt32 glyfAdd(TrueTypeTable *, GlyphData *glyphdata, AbstractTrueTypeFont *fnt);
/**
* Query the number of glyphs currently stored in the 'glyf' table