oox: export embedded font used in a presentation document

This adds support to export the fonts that are used in an
presentation document. The fonts are converted to EOT fonts.

Adds an EOT converter, which converts a TTF font to EOT font by
writing a EOT header and adding the TTF font data.

Adds BigEndianTypes so we can read a structure that is defined in
big endian and the types get converted (if needed) to system
endian when accessed. + test

Adds TTF reader which reads the true type font structure in an
easy way that is used by the EOTConverter. + test

Change-Id: I8b0bcb69e47943c2a8679edf881d7c2bab45c450
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184288
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
This commit is contained in:
Tomaž Vajngerl
2025-04-30 08:30:48 +02:00
committed by Tomaž Vajngerl
parent 56d64a40c1
commit d0ee08cfbf
17 changed files with 1190 additions and 20 deletions
+62
View File
@@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <sal/config.h>
#include <sal/types.h>
#include <osl/endian.h>
namespace o3tl
{
/** 16-bit unsigned integer type that can be used in a struct to read from data that is big endian.
*
* Type can't be instantiated but only used in a struct which is reinterpret_cast from bytes.
*/
class sal_uInt16_BE
{
private:
sal_uInt16 mnValue;
sal_uInt16_BE() = delete;
public:
constexpr operator sal_uInt16() const
{
#ifdef OSL_LITENDIAN
return OSL_SWAPWORD(mnValue);
#else
return mnValue;
#endif
}
};
/** 32-bit unsigned integer type that can be used in a struct to read from data that is big endian.
*
* Type can't be instantiated but only used in a struct which is reinterpret_cast from bytes.
*/
class sal_uInt32_BE
{
private:
sal_uInt32 mnValue;
sal_uInt32_BE() = delete;
public:
constexpr operator sal_uInt32() const
{
#ifdef OSL_LITENDIAN
return OSL_SWAPDWORD(mnValue);
#else
return mnValue;
#endif
}
};
} // namespace o3tl
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+67
View File
@@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <vcl/dllapi.h>
#include <vcl/font/FontDataContainer.hxx>
namespace font
{
#pragma pack(push, 1)
/** Main EOT Header
*
* See: https://www.w3.org/submissions/EOT/ */
struct EOTHeader
{
sal_uInt32 nEotSize;
sal_uInt32 nFontDataSize;
sal_uInt32 nVersion;
sal_uInt32 nFlags;
sal_uInt8 nFontPANOSE[10];
sal_uInt8 nCharset;
sal_uInt8 nItalic;
sal_uInt32 nWeight;
sal_uInt16 nFsType;
sal_uInt16 nMagicNumber;
sal_uInt32 nUnicodeRange1;
sal_uInt32 nUnicodeRange2;
sal_uInt32 nUnicodeRange3;
sal_uInt32 nUnicodeRange4;
sal_uInt32 nCodePageRange1;
sal_uInt32 nCodePageRange2;
sal_uInt32 nCheckSumAdjustment;
sal_uInt32 nReserved1;
sal_uInt32 nReserved2;
sal_uInt32 nReserved3;
sal_uInt32 nReserved4;
// variable length types come after this
};
#pragma pack(pop)
/** Converts TTF Font wrapped in a FontDataContainer to EOT type */
class VCL_DLLPUBLIC EOTConverter
{
private:
font::FontDataContainer const& mrFontDataContainer;
public:
explicit EOTConverter(font::FontDataContainer const& rFontDataContainer)
: mrFontDataContainer(rFontDataContainer)
{
}
bool convert(std::vector<sal_uInt8>& rEmbeddedOutput);
};
} // end font namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+36
View File
@@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <vector>
namespace font
{
/** Font data container wraps binary content of a TTF font */
class FontDataContainer
{
std::vector<sal_uInt8> const& mrFontBytes;
public:
FontDataContainer(std::vector<sal_uInt8> const& rFontBytes)
: mrFontBytes(rFontBytes)
{
}
const char* getPointer() const { return reinterpret_cast<const char*>(mrFontBytes.data()); }
size_t size() const { return mrFontBytes.size(); }
std::vector<sal_uInt8>::const_iterator begin() const { return mrFontBytes.begin(); }
std::vector<sal_uInt8>::const_iterator end() const { return mrFontBytes.end(); }
};
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+1
View File
@@ -40,6 +40,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,o3tl_tests,\
o3tl/qa/test-unit_conversion \
o3tl/qa/test-vector_pool \
o3tl/qa/test-hash_combine \
o3tl/qa/BigEndianTypesTest \
))
# vim: set noet sw=4:
+107
View File
@@ -0,0 +1,107 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
*/
#include <cppunit/TestAssert.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <o3tl/BigEndianTypes.hxx>
#include <array>
namespace
{
// Struct using endian of the system with 16-bit variables
struct SystemEndian16
{
sal_uInt16 x;
sal_uInt16 y;
sal_uInt16 z;
sal_uInt16 w;
};
// Struct using big endian with 16-bit variables
struct BigEndian16
{
o3tl::sal_uInt16_BE x;
o3tl::sal_uInt16_BE y;
o3tl::sal_uInt16_BE z;
o3tl::sal_uInt16_BE w;
};
// Struct using endian of the system with 32-bit variables
struct SystemEndian32
{
sal_uInt32 x;
sal_uInt32 y;
};
// Struct using big endian with 32-bit variables
struct BigEndian32
{
o3tl::sal_uInt32_BE x;
o3tl::sal_uInt32_BE y;
};
// Test data
constexpr std::array<sal_uInt8, 8> aDataArray = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
class BigEndianTypesTest : public CppUnit::TestFixture
{
public:
void testCast()
{
auto* pSystem16 = reinterpret_cast<const SystemEndian16*>(aDataArray.data());
// We expect different results depending on the system endian
#ifdef OSL_LITENDIAN
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0201), pSystem16->x);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0403), pSystem16->y);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0605), pSystem16->z);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0807), pSystem16->w);
#else
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0102), pSystem16->x);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0304), pSystem16->y);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0506), pSystem16->z);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0708), pSystem16->w);
#endif
// Reading in big endian should read the same independent of system endian
auto* pBig16 = reinterpret_cast<const BigEndian16*>(aDataArray.data());
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0102), sal_uInt16(pBig16->x));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0304), sal_uInt16(pBig16->y));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0506), sal_uInt16(pBig16->z));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x0708), sal_uInt16(pBig16->w));
// We expect different results depending on the system endian
auto* pSystem32 = reinterpret_cast<const SystemEndian32*>(aDataArray.data());
#ifdef OSL_LITENDIAN
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0x04030201), pSystem32->x);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0x08070605), pSystem32->y);
#else
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0x01020304), pSystem32->x);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0x05060708), pSystem32->y);
#endif
// Reading in big endian should read the same independent of system endian
auto* pBig32 = reinterpret_cast<const BigEndian32*>(aDataArray.data());
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0x01020304), sal_uInt32(pBig32->x));
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0x05060708), sal_uInt32(pBig32->y));
}
CPPUNIT_TEST_SUITE(BigEndianTypesTest);
CPPUNIT_TEST(testCast);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(BigEndianTypesTest);
} // end anonymous namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+2 -1
View File
@@ -1216,7 +1216,8 @@ void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const std::vector<
{ u"xml"_ustr, u"application/xml"_ustr },
{ u"rels"_ustr, u"application/vnd.openxmlformats-package.relationships+xml"_ustr },
{ u"png"_ustr, u"image/png"_ustr },
{ u"jpeg"_ustr, u"image/jpeg"_ustr }
{ u"jpeg"_ustr, u"image/jpeg"_ustr },
{ u"fntdata"_ustr, u"application/x-fontdata"_ustr }
};
uno::Sequence< beans::StringPair > aOverridesSequence(aManList.size());
+8
View File
@@ -201,6 +201,14 @@ private:
void WriteVBA();
void WriteModifyVerifier();
bool mbEmbedFonts = false;
bool mbEmbedUsedOnly = false;
bool mbEmbedLatinScript = true;
bool mbEmbedAsianScript = true;
bool mbEmbedComplexScript = true;
void WriteEmbeddedFontList();
};
}
+222 -1
View File
@@ -27,6 +27,7 @@
#include <oox/export/shapes.hxx>
#include <svx/svdlayer.hxx>
#include <unokywds.hxx>
#include <osl/file.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <comphelper/storagehelper.hxx>
@@ -60,6 +61,8 @@
#include <com/sun/star/container/XNamed.hpp>
#include <com/sun/star/presentation/XPresentationSupplier.hpp>
#include <comphelper/diagnose_ex.hxx>
#include <comphelper/hash.hxx>
#include <vcl/embeddedfontshelper.hxx>
#include <oox/export/utils.hxx>
#include <oox/export/ThemeExport.hxx>
@@ -76,13 +79,18 @@
#include <svx/ColorSets.hxx>
#include <sdmod.hxx>
#include <sdpage.hxx>
#include <unomodel.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <vcl/font/EOTConverter.hxx>
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
#include <com/sun/star/document/XStorageBasedDocument.hpp>
#include <utility>
#include <unordered_map>
#include <unordered_set>
#if OSL_DEBUG_LEVEL > 1
#include <com/sun/star/drawing/RectanglePoint.hpp>
#endif
@@ -393,6 +401,12 @@ void PowerPointExport::writeDocumentProperties()
try
{
xSettings->getPropertyValue(u"LoadReadonly"_ustr) >>= bSecurityOptOpenReadOnly;
xSettings->getPropertyValue(u"EmbedFonts"_ustr) >>= mbEmbedFonts;
xSettings->getPropertyValue(u"EmbedOnlyUsedFonts"_ustr) >>= mbEmbedUsedOnly;
xSettings->getPropertyValue(u"EmbedLatinScriptFonts"_ustr) >>= mbEmbedLatinScript;
xSettings->getPropertyValue(u"EmbedAsianScriptFonts"_ustr) >>= mbEmbedAsianScript;
xSettings->getPropertyValue(u"EmbedComplexScriptFonts"_ustr) >>= mbEmbedComplexScript;
}
catch( Exception& )
{
@@ -454,7 +468,10 @@ bool PowerPointExport::exportDocument()
oox::getRelationship(Relationship::THEME),
u"theme/theme1.xml");
mPresentationFS->startElementNS(XML_p, XML_presentation, presentationNamespaces(*this));
auto pAttributes = presentationNamespaces(*this);
if (mbEmbedFonts)
pAttributes->add(XML_embedTrueTypeFonts, "1");
mPresentationFS->startElementNS(XML_p, XML_presentation, pAttributes);
mXStatusIndicator = getStatusIndicator();
@@ -473,6 +490,7 @@ bool PowerPointExport::exportDocument()
mPresentationFS->singleElementNS(XML_p, XML_notesSz,
XML_cx, OString::number(PPTtoEMU(maNotesPageSize.Width)),
XML_cy, OString::number(PPTtoEMU(maNotesPageSize.Height)));
WriteEmbeddedFontList();
WriteCustomSlideShow();
@@ -512,6 +530,209 @@ bool PowerPointExport::exportDocument()
return new ::oox::ole::VbaProject(getComponentContext(), getModel(), u"Impress");
}
namespace
{
struct EmbeddedFont
{
OUString sFamilyName;
OString aRegularRelID;
OString aBoldRelID;
OString aItalicRelID;
OString aBoldItalicRelID;
};
} // end anonymous namespace
// Writers the list of all embedded fonts and reference to the fonts
void PowerPointExport::WriteEmbeddedFontList()
{
if (!mbEmbedFonts)
return;
SdDrawDocument* pDocument = nullptr;
if (auto* pSdXImpressDocument = dynamic_cast<SdXImpressDocument*>(mXModel.get()))
pDocument = pSdXImpressDocument->GetDoc();
if (!pDocument)
return;
int nextFontId = 1;
std::unordered_set<OUString> aFontFamilyNameSet;
std::unordered_map<std::string, OString> aFontDeduplicationMap;
std::vector<EmbeddedFont> aEmbeddedFontInfo;
uno::Reference<beans::XPropertySet> xProperties(mXModel, UNO_QUERY);
if (!xProperties.is())
return;
uno::Sequence<uno::Any> aAnySeq;
if (!(xProperties->getPropertyValue("Fonts") >>= aAnySeq))
return;
if (aAnySeq.getLength() % 5 != 0)
return;
int nLen = aAnySeq.getLength() / 5;
int nSeqIndex = 0;
for (int i = 0; i < nLen; i++)
{
OUString sFamilyName;
OUString sStyleName;
sal_uInt16 eFamily = FAMILY_DONTKNOW;
sal_uInt16 ePitch = PITCH_DONTKNOW;
sal_uInt16 eCharSet = RTL_TEXTENCODING_DONTKNOW;
aAnySeq[nSeqIndex++] >>= sFamilyName;
aAnySeq[nSeqIndex++] >>= sStyleName;
aAnySeq[nSeqIndex++] >>= eFamily;
aAnySeq[nSeqIndex++] >>= ePitch;
aAnySeq[nSeqIndex++] >>= eCharSet;
if (aFontFamilyNameSet.contains(sFamilyName))
continue;
static std::vector<std::pair<FontItalic, FontWeight>> aFontVariantCombinations =
{
{ ITALIC_NONE, WEIGHT_NORMAL },
{ ITALIC_NONE, WEIGHT_BOLD },
{ ITALIC_NORMAL, WEIGHT_NORMAL },
{ ITALIC_NORMAL, WEIGHT_BOLD }
};
EmbeddedFont aInfo;
aInfo.sFamilyName = sFamilyName;
for (auto [eItalic, eWeight] : aFontVariantCombinations)
{
OUString sFontUrl = EmbeddedFontsHelper::fontFileUrl(
sFamilyName, FontFamily(eFamily), eItalic, eWeight, FontPitch(ePitch),
EmbeddedFontsHelper::FontRights::ViewingAllowed);
if (sFontUrl.isEmpty())
continue;
osl::File aFile(sFontUrl);
if (aFile.open(osl_File_OpenFlag_Read ) != osl::File::E_None)
continue;
std::vector<sal_uInt8> rFontData;
std::array<sal_uInt8, 4096> buffer;
sal_uInt64 readSize;
comphelper::Hash aHashCalc(comphelper::HashType::SHA256);
OString uRelID;
// Read file
for(;;)
{
sal_Bool eof;
if (aFile.isEndOfFile(&eof) != osl::File::E_None)
{
SAL_WARN("sw.ww8", "Error reading font file " << sFontUrl);
break;
}
if (eof)
break;
if (aFile.read(buffer.data(), 4096, readSize) != osl::File::E_None)
{
SAL_WARN("sw.ww8", "Error reading font file " << sFontUrl);
break;
}
if (readSize == 0)
break;
rFontData.insert(rFontData.end(), buffer.data(), buffer.data() + readSize);
aHashCalc.update(reinterpret_cast<const unsigned char*>(buffer.data()), readSize);
}
std::string aHash = comphelper::hashToString(aHashCalc.finalize());
auto iterator = aFontDeduplicationMap.find(aHash);
if (iterator == aFontDeduplicationMap.end())
{
std::vector<sal_uInt8> rEOT;
font::FontDataContainer aContainer(rFontData);
font::EOTConverter aConverter(aContainer);
if (!aConverter.convert(rEOT))
continue;
OUString sFontFileName = "font" + OUString::number(nextFontId) + ".fntdata";
OUString sArchivePath = "ppt/fonts/" + sFontFileName;
uno::Reference<css::io::XOutputStream> xOutStream = openFragmentStream(sArchivePath, u"application/x-fontdata"_ustr);
xOutStream->writeBytes(uno::Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(rEOT.data()), rEOT.size()));
xOutStream->closeOutput();
OUString sRelID = addRelation(mPresentationFS->getOutputStream(),
oox::getRelationship(Relationship::FONT),
Concat2View("fonts/font" + OUString::number(nextFontId) + ".fntdata"));
++nextFontId;
uRelID = OUStringToOString(sRelID, RTL_TEXTENCODING_UTF8);
aFontDeduplicationMap.emplace(aHash, uRelID);
}
else
{
uRelID = iterator->second;
}
if (eItalic == ITALIC_NONE && eWeight == WEIGHT_NORMAL)
{
aInfo.aRegularRelID = uRelID;
}
else if (eItalic == ITALIC_NONE && eWeight == WEIGHT_BOLD)
{
aInfo.aBoldRelID = uRelID;
}
else if (eItalic == ITALIC_NORMAL && eWeight == WEIGHT_NORMAL)
{
aInfo.aItalicRelID = uRelID;
}
else if (eItalic == ITALIC_NORMAL && eWeight == WEIGHT_BOLD)
{
aInfo.aBoldItalicRelID = uRelID;
}
}
aEmbeddedFontInfo.push_back(aInfo);
aFontFamilyNameSet.insert(sFamilyName);
}
// if there are fonts to embed and font embeding enabled
mPresentationFS->startElementNS(XML_p, XML_embeddedFontLst);
for (auto const& rInfo : aEmbeddedFontInfo)
{
mPresentationFS->startElementNS(XML_p, XML_embeddedFont);
mPresentationFS->singleElementNS(XML_p, XML_font,
//XML_charset, OUString::number(0),
XML_typeface, rInfo.sFamilyName);
if (!rInfo.aRegularRelID.isEmpty())
mPresentationFS->singleElementNS(XML_p, XML_regular, FSNS(XML_r, XML_id), rInfo.aRegularRelID);
if (!rInfo.aBoldRelID.isEmpty())
mPresentationFS->singleElementNS(XML_p, XML_bold, FSNS(XML_r, XML_id), rInfo.aBoldRelID);
if (!rInfo.aItalicRelID.isEmpty())
mPresentationFS->singleElementNS(XML_p, XML_italic, FSNS(XML_r, XML_id), rInfo.aItalicRelID);
if (!rInfo.aBoldItalicRelID.isEmpty())
mPresentationFS->singleElementNS(XML_p, XML_boldItalic, FSNS(XML_r, XML_id), rInfo.aBoldItalicRelID);
mPresentationFS->endElementNS(XML_p, XML_embeddedFont);
}
mPresentationFS->endElementNS(XML_p, XML_embeddedFontLst);
}
void PowerPointExport::WriteCustomSlideShow()
{
Reference<XCustomPresentationSupplier> aXCPSup(mXModel, css::uno::UNO_QUERY);
@@ -0,0 +1,44 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
$(eval $(call gb_CppunitTest_CppunitTest,vcl_font_ttf_structure_test))
$(eval $(call gb_CppunitTest_set_include,vcl_font_ttf_structure_test,\
$$(INCLUDE) \
-I$(SRCDIR)/vcl/inc \
))
$(eval $(call gb_CppunitTest_add_exception_objects,vcl_font_ttf_structure_test, \
vcl/qa/cppunit/font/TTFStructureTest \
))
$(eval $(call gb_CppunitTest_use_externals,vcl_font_ttf_structure_test,boost_headers))
$(eval $(call gb_CppunitTest_use_libraries,vcl_font_ttf_structure_test, \
basegfx \
comphelper \
cppu \
cppuhelper \
sal \
subsequenttest \
test \
unotest \
utl \
tl \
vcl \
xmlsecurity \
))
$(eval $(call gb_CppunitTest_use_sdk_api,vcl_font_ttf_structure_test))
$(eval $(call gb_CppunitTest_use_ure,vcl_font_ttf_structure_test))
$(eval $(call gb_CppunitTest_use_vcl,vcl_font_ttf_structure_test))
$(eval $(call gb_CppunitTest_use_rdb,vcl_font_ttf_structure_test,services))
$(eval $(call gb_CppunitTest_use_configuration,vcl_font_ttf_structure_test))
# vim: set noet sw=4 ts=4:
+1
View File
@@ -553,6 +553,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/font/fontcharmap \
vcl/source/font/fontmetric \
vcl/source/font/font \
vcl/source/font/EOTConverter \
vcl/source/fontsubset/cff \
vcl/source/fontsubset/fontsubset \
vcl/source/fontsubset/sft \
+1
View File
@@ -229,6 +229,7 @@ $(eval $(call gb_Module_add_check_targets,vcl,\
CppunitTest_vcl_fontmetric \
CppunitTest_vcl_text \
CppunitTest_vcl_textlayout \
CppunitTest_vcl_font_ttf_structure_test \
CppunitTest_vcl_filters_test \
CppunitTest_vcl_mnemonic \
CppunitTest_vcl_outdev \
+201
View File
@@ -0,0 +1,201 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <font/TTFStructure.hxx>
#include <vcl/font/FontDataContainer.hxx>
#include <rtl/ustrbuf.hxx>
namespace font
{
/** Handles reading of the name table */
class NameTableHandler
{
private:
FontDataContainer const& mrFontDataContainer;
const TableDirectoryEntry* mpTableDirectoryEntry;
const char* mpNameTablePointer;
const NameTable* mpNameTable;
const char* getTablePointer(const TableDirectoryEntry* pEntry)
{
return mrFontDataContainer.getPointer() + pEntry->offset;
}
public:
NameTableHandler(FontDataContainer const& rFontDataContainer,
const TableDirectoryEntry* pTableDirectoryEntry)
: mrFontDataContainer(rFontDataContainer)
, mpTableDirectoryEntry(pTableDirectoryEntry)
, mpNameTablePointer(getTablePointer(mpTableDirectoryEntry))
, mpNameTable(reinterpret_cast<const NameTable*>(mpNameTablePointer))
{
}
sal_uInt32 getTableOffset() { return mpTableDirectoryEntry->offset; }
const NameTable* getNameTable() { return mpNameTable; }
/** Number of tables */
sal_uInt16 getNumberOfRecords() { return mpNameTable->nCount; }
/** Get a name table record for index */
const NameRecord* getNameRecord(sal_uInt32 index)
{
const char* pPointer = mpNameTablePointer + sizeof(NameTable);
pPointer += sizeof(NameRecord) * index;
return reinterpret_cast<const NameRecord*>(pPointer);
}
/** Get offset to english unicode string
*
* See: https://learn.microsoft.com/en-us/typography/opentype/spec/name#name-ids
*/
bool findEnglishUnicodeNameOffset(font::NameID eNameID, sal_uInt64& rOffset,
sal_uInt16& rLength)
{
rOffset = 0;
rLength = 0;
for (int n = 0; n < getNumberOfRecords(); n++)
{
const font::NameRecord* pNameRecord = getNameRecord(n);
if (pNameRecord->nPlatformID == 3 // Windows
&& pNameRecord->nEncodingID == 1 // Unicode BMP
&& pNameRecord->nLanguageID == 0x0409 // en-us
&& pNameRecord->nNameID == sal_uInt16(eNameID))
{
rLength = pNameRecord->nLength;
rOffset = getTableOffset() + getNameTable()->nStorageOffset
+ pNameRecord->nStringOffset;
return true;
}
}
return false;
}
};
/** Handles reading of table entries */
class TableEntriesHandler
{
private:
FontDataContainer const& mrFontDataContainer;
const char* mpFirstPosition;
sal_uInt16 mnNumberOfTables;
const char* getTablePointer(const TableDirectoryEntry* pEntry)
{
return mrFontDataContainer.getPointer() + pEntry->offset;
}
public:
TableEntriesHandler(FontDataContainer const& rFontDataContainer, const char* pPosition,
sal_uInt16 nNumberOfTables)
: mrFontDataContainer(rFontDataContainer)
, mpFirstPosition(pPosition)
, mnNumberOfTables(nNumberOfTables)
{
}
const TableDirectoryEntry* getEntry(sal_uInt32 nTag)
{
for (sal_uInt32 i = 0; i < mnNumberOfTables; i++)
{
const char* pPosition = mpFirstPosition + sizeof(TableDirectoryEntry) * i;
const auto* pEntry = reinterpret_cast<const TableDirectoryEntry*>(pPosition);
if (nTag == pEntry->tag)
return pEntry;
}
return nullptr;
}
const OS2Table* getOS2Table()
{
const auto* pEntry = getEntry(T_OS2);
if (!pEntry)
return nullptr;
return reinterpret_cast<const OS2Table*>(getTablePointer(pEntry));
}
const HeadTable* getHeadTable()
{
const auto* pEntry = getEntry(T_head);
if (!pEntry)
return nullptr;
return reinterpret_cast<const HeadTable*>(getTablePointer(pEntry));
}
const NameTable* getNameTable()
{
const auto* pEntry = getEntry(T_name);
if (!pEntry)
return nullptr;
return reinterpret_cast<const NameTable*>(getTablePointer(pEntry));
}
std::unique_ptr<NameTableHandler> getNameTableHandler()
{
const auto* pEntry = getEntry(T_name);
if (!pEntry)
return nullptr;
return std::unique_ptr<NameTableHandler>(new NameTableHandler(mrFontDataContainer, pEntry));
}
};
/** Entry point handler for the TTF Font */
class TTFFont
{
private:
FontDataContainer const& mrFontDataContainer;
const char* getTablePointer(const TableDirectoryEntry* pEntry)
{
return mrFontDataContainer.getPointer() + pEntry->offset;
}
public:
TTFFont(FontDataContainer const& rFontDataContainer)
: mrFontDataContainer(rFontDataContainer)
{
}
const TableDirectory* getTableDirector()
{
return reinterpret_cast<const TableDirectory*>(mrFontDataContainer.getPointer());
}
std::unique_ptr<TableEntriesHandler> getTableEntriesHandler()
{
auto* pDirectory = getTableDirector();
const char* pPosition = mrFontDataContainer.getPointer() + sizeof(TableDirectory);
std::unique_ptr<TableEntriesHandler> pHandler(
new TableEntriesHandler(mrFontDataContainer, pPosition, pDirectory->nNumberOfTables));
return pHandler;
}
/** Gets the string from a name table */
OUString getNameTableString(sal_uInt64 nOffset, sal_uInt16 nLength)
{
const auto* pString = reinterpret_cast<const o3tl::sal_uInt16_BE*>(
mrFontDataContainer.getPointer() + nOffset);
OUStringBuffer aStringBuffer;
for (sal_uInt16 i = 0; i < (nLength / 2); i++)
aStringBuffer.append(sal_Unicode(pString[i]));
return aStringBuffer.makeStringAndClear();
}
};
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+183
View File
@@ -0,0 +1,183 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <o3tl/BigEndianTypes.hxx>
namespace font
{
// make sure no padding bytes are added for the struct
#pragma pack(push, 1)
/** Table directory of a TTF font, values are all in big endian */
struct TableDirectory
{
o3tl::sal_uInt32_BE nSfntVersion;
o3tl::sal_uInt16_BE nNumberOfTables;
o3tl::sal_uInt16_BE nSearchRange;
o3tl::sal_uInt16_BE nEntrySelector;
o3tl::sal_uInt16_BE nRangeShift;
};
/** Table directory entry
*
* Array of those follows TableDirectory structure.
*/
struct TableDirectoryEntry
{
o3tl::sal_uInt32_BE tag;
o3tl::sal_uInt32_BE checkSum;
o3tl::sal_uInt32_BE offset;
o3tl::sal_uInt32_BE length;
};
/** Structure of the OS2 table (Version 4)
*
* See: https://learn.microsoft.com/en-us/typography/opentype/spec/os2
*/
struct OS2Table
{
o3tl::sal_uInt16_BE nVersion;
o3tl::sal_uInt16_BE nXAvgCharWidth; // FWORD
o3tl::sal_uInt16_BE nWeightClass;
o3tl::sal_uInt16_BE nWidthClass;
o3tl::sal_uInt16_BE nFsType;
o3tl::sal_uInt16_BE nSubscriptXSize; // FWORD
o3tl::sal_uInt16_BE nSubscriptYSize; // FWORD
o3tl::sal_uInt16_BE nSubscriptXOffset; // FWORD
o3tl::sal_uInt16_BE nSubscriptYOffset; // FWORD
o3tl::sal_uInt16_BE nSuperscriptXSize; // FWORD
o3tl::sal_uInt16_BE nSuperscriptYSize; // FWORD
o3tl::sal_uInt16_BE nSuperscriptXOffset; // FWORD
o3tl::sal_uInt16_BE nSuperscriptYOffset; // FWORD
o3tl::sal_uInt16_BE nStrikeoutSize; // FWORD
o3tl::sal_uInt16_BE nStrikeoutPosition; // FWORD
o3tl::sal_uInt16_BE nFamilyClass;
sal_uInt8 nPanose[10];
o3tl::sal_uInt32_BE nUnicodeRange1;
o3tl::sal_uInt32_BE nUnicodeRange2;
o3tl::sal_uInt32_BE nUnicodeRange3;
o3tl::sal_uInt32_BE nUnicodeRange4;
sal_uInt8 nFontVendorID[4]; // Tag type
o3tl::sal_uInt16_BE nFsSelection;
o3tl::sal_uInt16_BE nFirstCharIndex;
o3tl::sal_uInt16_BE nLastCharIndex;
o3tl::sal_uInt16_BE nTypoAscender; // FWORD
o3tl::sal_uInt16_BE nTypoDescender; // FWORD
o3tl::sal_uInt16_BE nTypoLineGap; // FWORD
o3tl::sal_uInt16_BE nWinAscent; // UFWORD
o3tl::sal_uInt16_BE nWinDescent; // UFWORD
o3tl::sal_uInt32_BE nCodePageRange1;
o3tl::sal_uInt32_BE nCodePageRange2;
o3tl::sal_uInt16_BE nXHeight; // FWORD
o3tl::sal_uInt16_BE nCapHeight; // FWORD
o3tl::sal_uInt16_BE nDefaultChar;
o3tl::sal_uInt16_BE nBreakChar;
o3tl::sal_uInt16_BE nMaxContext;
o3tl::sal_uInt16_BE nLowerOpticalPointSize;
o3tl::sal_uInt16_BE nUpperOpticalPointSize;
};
// Check the size of OS2Table struct is as expected
static_assert(sizeof(OS2Table) == 100);
/** Structure of "head" table.
*
* See: https://learn.microsoft.com/en-us/typography/opentype/spec/head
*/
struct HeadTable
{
sal_uInt16 nMajorVersion;
sal_uInt16 nMinorVersion;
sal_uInt32 nFontRevision;
o3tl::sal_uInt32_BE nCheckSumAdjustment;
o3tl::sal_uInt32_BE nMagicNumber;
o3tl::sal_uInt16_BE nFlags;
o3tl::sal_uInt16_BE nUnitsPerEm;
sal_Int64 nCreated; // LONGDATETIME - signed 64-bit (TODO: need a BE type)
sal_Int64 nModified; // LONGDATETIME - signed 64-bit (TODO: need a BE type)
o3tl::sal_uInt16_BE nXMin;
o3tl::sal_uInt16_BE nXMax;
o3tl::sal_uInt16_BE nYMin;
o3tl::sal_uInt16_BE nYMax;
o3tl::sal_uInt16_BE nMacStyle;
o3tl::sal_uInt16_BE nLowestRectPPEM;
o3tl::sal_uInt16_BE nFontDirectionHint;
o3tl::sal_uInt16_BE nIndexToLocFormat;
o3tl::sal_uInt16_BE nGlyphDataFormat;
};
// Check the size of HeadTable struct is as expected
static_assert(sizeof(HeadTable) == 54);
/** Structure of "name" table (Version 0)
*
* See: https://learn.microsoft.com/en-us/typography/opentype/spec/name
*/
struct NameTable
{
o3tl::sal_uInt16_BE nVersion;
o3tl::sal_uInt16_BE nCount;
o3tl::sal_uInt16_BE nStorageOffset;
// Following this are NameRecords -> nCount times
};
/** Name record structure
*
* Array of those follows NameTable structure.
*/
struct NameRecord
{
o3tl::sal_uInt16_BE nPlatformID;
o3tl::sal_uInt16_BE nEncodingID;
o3tl::sal_uInt16_BE nLanguageID;
o3tl::sal_uInt16_BE nNameID;
o3tl::sal_uInt16_BE nLength; // (in bytes)
o3tl::sal_uInt16_BE nStringOffset; // offset from start of storage area (in bytes)
};
/** Name IDs
*
* See https://learn.microsoft.com/en-us/typography/opentype/spec/name#name-ids
*/
enum class NameID : sal_uInt16
{
Copyright = 0, // example: "© Copyright..."
FamilyName = 1, // example: "Times New Roman"
SubfamilyName = 2, // example: "Bold"
UniqueID = 3, // example: "Monotype: Times New Roman Bold: 1990"
FullFontName = 4, // example: "Times New Roman Bold"
Version = 5, // example: "Version 1.00 June 1, 1990, initial release"
PostScriptName = 6, // example: "TimesNewRoman-Bold"
};
#pragma pack(pop)
} // end font namespace
// Standard TrueType table tags
constexpr sal_uInt32 T_maxp = 0x6D617870;
constexpr sal_uInt32 T_glyf = 0x676C7966;
constexpr sal_uInt32 T_head = 0x68656164;
constexpr sal_uInt32 T_loca = 0x6C6F6361;
constexpr sal_uInt32 T_name = 0x6E616D65;
constexpr sal_uInt32 T_hhea = 0x68686561;
constexpr sal_uInt32 T_hmtx = 0x686D7478;
constexpr sal_uInt32 T_cmap = 0x636D6170;
constexpr sal_uInt32 T_vhea = 0x76686561;
constexpr sal_uInt32 T_vmtx = 0x766D7478;
constexpr sal_uInt32 T_OS2 = 0x4F532F32;
constexpr sal_uInt32 T_post = 0x706F7374;
constexpr sal_uInt32 T_cvt = 0x63767420;
constexpr sal_uInt32 T_prep = 0x70726570;
constexpr sal_uInt32 T_fpgm = 0x6670676D;
constexpr sal_uInt32 T_CFF = 0x43464620;
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+2 -18
View File
@@ -53,6 +53,8 @@
#include <memory>
#include <vector>
#include "font/TTFStructure.hxx"
class SvStream;
namespace vcl
@@ -433,24 +435,6 @@ constexpr sal_uInt32 T_true = 0x74727565; /* 'true' */
constexpr sal_uInt32 T_ttcf = 0x74746366; /* 'ttcf' */
constexpr sal_uInt32 T_otto = 0x4f54544f; /* 'OTTO' */
// standard TrueType table tags
constexpr sal_uInt32 T_maxp = 0x6D617870;
constexpr sal_uInt32 T_glyf = 0x676C7966;
constexpr sal_uInt32 T_head = 0x68656164;
constexpr sal_uInt32 T_loca = 0x6C6F6361;
constexpr sal_uInt32 T_name = 0x6E616D65;
constexpr sal_uInt32 T_hhea = 0x68686561;
constexpr sal_uInt32 T_hmtx = 0x686D7478;
constexpr sal_uInt32 T_cmap = 0x636D6170;
constexpr sal_uInt32 T_vhea = 0x76686561;
constexpr sal_uInt32 T_vmtx = 0x766D7478;
constexpr sal_uInt32 T_OS2 = 0x4F532F32;
constexpr sal_uInt32 T_post = 0x706F7374;
constexpr sal_uInt32 T_cvt = 0x63767420;
constexpr sal_uInt32 T_prep = 0x70726570;
constexpr sal_uInt32 T_fpgm = 0x6670676D;
constexpr sal_uInt32 T_CFF = 0x43464620;
class AbstractTrueTypeFont;
class TrueTypeFont;
+87
View File
@@ -0,0 +1,87 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <test/bootstrapfixture.hxx>
#include <test/unoapi_test.hxx>
#include <font/TTFStructure.hxx>
#include <font/TTFReader.hxx>
#include <font/TTFReader.hxx>
namespace
{
class TTFTest : public UnoApiTest
{
public:
TTFTest()
: UnoApiTest("/vcl/qa/cppunit/font/data/")
{
}
};
CPPUNIT_TEST_FIXTURE(TTFTest, testReadTTFStructure)
{
OUString aFileName = createFileURL(u"Ahem.ttf");
SvFileStream aStream(aFileName, StreamMode::READ);
std::vector<sal_uInt8> aFontBytes(aStream.remainingSize());
aStream.ReadBytes(aFontBytes.data(), aFontBytes.size());
CPPUNIT_ASSERT(aStream.good());
aStream.Close();
font::FontDataContainer aContainer(aFontBytes);
font::TTFFont aFont(aContainer);
auto pHanlder = aFont.getTableEntriesHandler();
const font::OS2Table* pOS2 = pHanlder->getOS2Table();
CPPUNIT_ASSERT(pOS2);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(400), sal_uInt16(pOS2->nWeightClass));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(5), sal_uInt16(pOS2->nWidthClass));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(1000), sal_uInt16(pOS2->nXAvgCharWidth));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), sal_uInt16(pOS2->nFamilyClass));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(175), sal_uInt16(pOS2->nUnicodeRange1));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(8264), sal_uInt16(pOS2->nUnicodeRange2));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), sal_uInt16(pOS2->nUnicodeRange3));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), sal_uInt16(pOS2->nUnicodeRange4));
const font::HeadTable* pHeadTable = pHanlder->getHeadTable();
CPPUNIT_ASSERT(pHeadTable);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(1000), sal_uInt16(pHeadTable->nUnitsPerEm));
auto pNameTableHanlder = pHanlder->getNameTableHandler();
CPPUNIT_ASSERT(pNameTableHanlder);
sal_uInt64 nOffset = 0;
sal_uInt16 nLength = 0;
CPPUNIT_ASSERT(pNameTableHanlder->findEnglishUnicodeNameOffset(font::NameID::FamilyName,
nOffset, nLength));
OUString aFamilyName = aFont.getNameTableString(nOffset, nLength);
CPPUNIT_ASSERT_EQUAL(u"Ahem"_ustr, aFamilyName);
CPPUNIT_ASSERT(pNameTableHanlder->findEnglishUnicodeNameOffset(font::NameID::FullFontName,
nOffset, nLength));
OUString aFullFontName = aFont.getNameTableString(nOffset, nLength);
CPPUNIT_ASSERT_EQUAL(u"Ahem"_ustr, aFullFontName);
CPPUNIT_ASSERT(pNameTableHanlder->findEnglishUnicodeNameOffset(font::NameID::SubfamilyName,
nOffset, nLength));
OUString aSubFamilyName = aFont.getNameTableString(nOffset, nLength);
CPPUNIT_ASSERT_EQUAL(u"Regular"_ustr, aSubFamilyName);
CPPUNIT_ASSERT(
pNameTableHanlder->findEnglishUnicodeNameOffset(font::NameID::Version, nOffset, nLength));
OUString aVersion = aFont.getNameTableString(nOffset, nLength);
CPPUNIT_ASSERT_EQUAL(u"Version 1.1"_ustr, aVersion);
}
} // end anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Binary file not shown.
+166
View File
@@ -0,0 +1,166 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <string.h>
#include <vector>
#include <tools/vcompat.hxx>
#include <cstdio>
#include <tools/stream.hxx>
#include <vcl/font/EOTConverter.hxx>
#include <osl/endian.h>
#include <font/TTFStructure.hxx>
#include <font/TTFReader.hxx>
namespace font
{
namespace
{
// Writes padding, length and string data to font output
void writeNameTableString(font::TTFFont& rFont,
std::unique_ptr<NameTableHandler>& pNameTableHanlder,
font::NameID eNameID, std::vector<sal_uInt8>& rEotOutput)
{
sal_uInt64 nOffset = 0;
sal_uInt16 nLength = 0;
// Padding
rEotOutput.push_back(0);
rEotOutput.push_back(0);
if (pNameTableHanlder
&& pNameTableHanlder->findEnglishUnicodeNameOffset(eNameID, nOffset, nLength))
{
// Length
rEotOutput.push_back(sal_uInt8((nLength + 2) & 0xff));
rEotOutput.push_back(sal_uInt8((nLength + 2) >> 8));
OUString aString = rFont.getNameTableString(nOffset, nLength);
for (sal_Int32 i = 0; i < aString.getLength(); i++)
{
sal_Unicode nUniChar = aString[i];
rEotOutput.push_back(sal_uInt8(nUniChar & 0xff));
rEotOutput.push_back(sal_uInt8(nUniChar >> 8));
}
// null terminated
rEotOutput.push_back(sal_uInt8(0));
rEotOutput.push_back(sal_uInt8(0));
}
else
{
// Length 0
rEotOutput.push_back(sal_uInt8(0));
rEotOutput.push_back(sal_uInt8(0));
}
}
}
bool EOTConverter::convert(std::vector<sal_uInt8>& rEotOutput)
{
font::TTFFont aFont(mrFontDataContainer);
rEotOutput.clear();
rEotOutput.resize(sizeof(EOTHeader));
EOTHeader* pEot = reinterpret_cast<EOTHeader*>(rEotOutput.data());
pEot->nFontDataSize = mrFontDataContainer.size();
pEot->nVersion = 0x00020002;
pEot->nFlags = 0;
pEot->nCharset = 0;
pEot->nMagicNumber = 0x504c;
pEot->nReserved1 = 0;
pEot->nReserved2 = 0;
pEot->nReserved3 = 0;
pEot->nReserved4 = 0;
auto pHanlder = aFont.getTableEntriesHandler();
const font::OS2Table* pOS2 = pHanlder->getOS2Table();
if (pOS2)
{
for (sal_uInt32 n = 0; n < 10; n++)
pEot->nFontPANOSE[n] = pOS2->nPanose[n];
pEot->nItalic = pOS2->nFsSelection & 0x01;
pEot->nWeight = pOS2->nWeightClass;
// FIXME: Should use OS2->fsType, but some TrueType fonts set it to an over-restrictive value.
// Since ATS does not enforce this on Mac OS X, we do not enforce it either.
pEot->nFsType = 0x0000;
pEot->nUnicodeRange1 = pOS2->nUnicodeRange1;
pEot->nUnicodeRange2 = pOS2->nUnicodeRange2;
pEot->nUnicodeRange3 = pOS2->nUnicodeRange3;
pEot->nUnicodeRange4 = pOS2->nUnicodeRange4;
pEot->nCodePageRange1 = pOS2->nCodePageRange1;
pEot->nCodePageRange2 = pOS2->nCodePageRange2;
}
const font::HeadTable* pHeadTable = pHanlder->getHeadTable();
if (pHeadTable)
{
pEot->nCheckSumAdjustment = pHeadTable->nCheckSumAdjustment;
}
auto pNameTableHanlder = pHanlder->getNameTableHandler();
writeNameTableString(aFont, pNameTableHanlder, font::NameID::FamilyName, rEotOutput);
writeNameTableString(aFont, pNameTableHanlder, font::NameID::SubfamilyName, rEotOutput);
writeNameTableString(aFont, pNameTableHanlder, font::NameID::Version, rEotOutput);
writeNameTableString(aFont, pNameTableHanlder, font::NameID::FullFontName, rEotOutput);
// Padding5
rEotOutput.push_back(0);
rEotOutput.push_back(0);
// Root String Size
rEotOutput.push_back(0);
rEotOutput.push_back(0);
// Root String CheckSum (for size 0)
rEotOutput.push_back(0x42);
rEotOutput.push_back(0x53);
rEotOutput.push_back(0x47);
rEotOutput.push_back(0x50);
// EUDC CodePage
rEotOutput.push_back(0xE4);
rEotOutput.push_back(0x04);
rEotOutput.push_back(0x00);
rEotOutput.push_back(0x00);
// Padding6
rEotOutput.push_back(0);
rEotOutput.push_back(0);
// Signature Size = should be 0x0000
rEotOutput.push_back(0);
rEotOutput.push_back(0);
// EUDC Flags
rEotOutput.push_back(0);
rEotOutput.push_back(0);
rEotOutput.push_back(0);
rEotOutput.push_back(0);
// EUDC Font Size = 0
rEotOutput.push_back(0);
rEotOutput.push_back(0);
rEotOutput.push_back(0);
rEotOutput.push_back(0);
// rEOTOutput could've been reallocated - need to reinterpret that.
pEot = reinterpret_cast<EOTHeader*>(rEotOutput.data());
pEot->nEotSize = rEotOutput.size() + mrFontDataContainer.size();
rEotOutput.insert(rEotOutput.end(), mrFontDataContainer.begin(), mrFontDataContainer.end());
return true;
}
} // end font namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */