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:
committed by
Tomaž Vajngerl
parent
56d64a40c1
commit
d0ee08cfbf
@@ -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: */
|
||||
@@ -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: */
|
||||
@@ -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: */
|
||||
@@ -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:
|
||||
|
||||
@@ -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: */
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
@@ -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 \
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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: */
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
@@ -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: */
|
||||
Reference in New Issue
Block a user