summaryrefslogtreecommitdiffstats
path: root/gfx/2d/SFNTData.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/2d/SFNTData.cpp')
-rw-r--r--gfx/2d/SFNTData.cpp251
1 files changed, 251 insertions, 0 deletions
diff --git a/gfx/2d/SFNTData.cpp b/gfx/2d/SFNTData.cpp
new file mode 100644
index 000000000..fd29f6694
--- /dev/null
+++ b/gfx/2d/SFNTData.cpp
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "SFNTData.h"
+
+#include <algorithm>
+
+#include "BigEndianInts.h"
+#include "Logging.h"
+#include "mozilla/HashFunctions.h"
+#include "SFNTNameTable.h"
+
+namespace mozilla {
+namespace gfx {
+
+#define TRUETYPE_TAG(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
+
+#pragma pack(push, 1)
+
+struct TTCHeader
+{
+ BigEndianUint32 ttcTag; // Always 'ttcf'
+ BigEndianUint32 version; // Fixed, 0x00010000
+ BigEndianUint32 numFonts;
+};
+
+struct OffsetTable
+{
+ BigEndianUint32 sfntVersion; // Fixed, 0x00010000 for version 1.0.
+ BigEndianUint16 numTables;
+ BigEndianUint16 searchRange; // (Maximum power of 2 <= numTables) x 16.
+ BigEndianUint16 entrySelector; // Log2(maximum power of 2 <= numTables).
+ BigEndianUint16 rangeShift; // NumTables x 16-searchRange.
+};
+
+struct TableDirEntry
+{
+ BigEndianUint32 tag; // 4 -byte identifier.
+ BigEndianUint32 checkSum; // CheckSum for this table.
+ BigEndianUint32 offset; // Offset from beginning of TrueType font file.
+ BigEndianUint32 length; // Length of this table.
+
+ friend bool operator<(const TableDirEntry& lhs, const uint32_t aTag)
+ {
+ return lhs.tag < aTag;
+ }
+};
+
+#pragma pack(pop)
+
+class SFNTData::Font
+{
+public:
+ Font(const OffsetTable *aOffsetTable, const uint8_t *aFontData,
+ uint32_t aDataLength)
+ : mFontData(aFontData)
+ , mFirstDirEntry(reinterpret_cast<const TableDirEntry*>(aOffsetTable + 1))
+ , mEndOfDirEntries(mFirstDirEntry + aOffsetTable->numTables)
+ , mDataLength(aDataLength)
+ {
+ }
+
+ bool GetU16FullName(mozilla::u16string& aU16FullName)
+ {
+ const TableDirEntry* dirEntry =
+ GetDirEntry(TRUETYPE_TAG('n', 'a', 'm', 'e'));
+ if (!dirEntry) {
+ gfxWarning() << "Name table entry not found.";
+ return false;
+ }
+
+ UniquePtr<SFNTNameTable> nameTable =
+ SFNTNameTable::Create((mFontData + dirEntry->offset), dirEntry->length);
+ if (!nameTable) {
+ return false;
+ }
+
+ return nameTable->GetU16FullName(aU16FullName);
+ }
+
+private:
+
+ const TableDirEntry*
+ GetDirEntry(const uint32_t aTag)
+ {
+ const TableDirEntry* foundDirEntry =
+ std::lower_bound(mFirstDirEntry, mEndOfDirEntries, aTag);
+
+ if (foundDirEntry == mEndOfDirEntries || foundDirEntry->tag != aTag) {
+ gfxWarning() << "Font data does not contain tag.";
+ return nullptr;
+ }
+
+ if (mDataLength < (foundDirEntry->offset + foundDirEntry->length)) {
+ gfxWarning() << "Font data too short to contain table.";
+ return nullptr;
+ }
+
+ return foundDirEntry;
+ }
+
+ const uint8_t *mFontData;
+ const TableDirEntry *mFirstDirEntry;
+ const TableDirEntry *mEndOfDirEntries;
+ uint32_t mDataLength;
+};
+
+/* static */
+UniquePtr<SFNTData>
+SFNTData::Create(const uint8_t *aFontData, uint32_t aDataLength)
+{
+ MOZ_ASSERT(aFontData);
+
+ // Check to see if this is a font collection.
+ if (aDataLength < sizeof(TTCHeader)) {
+ gfxWarning() << "Font data too short.";
+ return nullptr;
+ }
+
+ const TTCHeader *ttcHeader = reinterpret_cast<const TTCHeader*>(aFontData);
+ if (ttcHeader->ttcTag == TRUETYPE_TAG('t', 't', 'c', 'f')) {
+ uint32_t numFonts = ttcHeader->numFonts;
+ if (aDataLength < sizeof(TTCHeader) + (numFonts * sizeof(BigEndianUint32))) {
+ gfxWarning() << "Font data too short to contain full TTC Header.";
+ return nullptr;
+ }
+
+ UniquePtr<SFNTData> sfntData(new SFNTData);
+ const BigEndianUint32* offset =
+ reinterpret_cast<const BigEndianUint32*>(aFontData + sizeof(TTCHeader));
+ const BigEndianUint32* endOfOffsets = offset + numFonts;
+ while (offset != endOfOffsets) {
+ if (!sfntData->AddFont(aFontData, aDataLength, *offset)) {
+ return nullptr;
+ }
+ ++offset;
+ }
+
+ return Move(sfntData);
+ }
+
+ UniquePtr<SFNTData> sfntData(new SFNTData);
+ if (!sfntData->AddFont(aFontData, aDataLength, 0)) {
+ return nullptr;
+ }
+
+ return Move(sfntData);
+}
+
+/* static */
+uint64_t
+SFNTData::GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength)
+{
+ uint64_t hash;
+ UniquePtr<SFNTData> sfntData = SFNTData::Create(aFontData, aDataLength);
+ mozilla::u16string firstName;
+ if (sfntData && sfntData->GetU16FullName(0, firstName)) {
+ hash = HashString(firstName.c_str(), firstName.length());
+ } else {
+ gfxWarning() << "Failed to get name from font data hashing whole font.";
+ hash = HashString(aFontData, aDataLength);
+ }
+
+ return hash << 32 | aDataLength;;
+}
+
+SFNTData::~SFNTData()
+{
+ for (size_t i = 0; i < mFonts.length(); ++i) {
+ delete mFonts[i];
+ }
+}
+
+bool
+SFNTData::GetU16FullName(uint32_t aIndex, mozilla::u16string& aU16FullName)
+{
+ if (aIndex >= mFonts.length()) {
+ gfxWarning() << "aIndex to font data too high.";
+ return false;
+ }
+
+ return mFonts[aIndex]->GetU16FullName(aU16FullName);
+}
+
+bool
+SFNTData::GetU16FullNames(Vector<mozilla::u16string>& aU16FullNames)
+{
+ bool fontFound = false;
+ for (size_t i = 0; i < mFonts.length(); ++i) {
+ mozilla::u16string name;
+ if (mFonts[i]->GetU16FullName(name)) {
+ fontFound = true;
+ }
+ if (!aU16FullNames.append(Move(name))) {
+ return false;
+ }
+ }
+
+ return fontFound;
+}
+
+bool
+SFNTData::GetIndexForU16Name(const mozilla::u16string& aU16FullName,
+ uint32_t* aIndex, size_t aTruncatedLen)
+{
+ for (size_t i = 0; i < mFonts.length(); ++i) {
+ mozilla::u16string name;
+ if (!mFonts[i]->GetU16FullName(name)) {
+ continue;
+ }
+
+ if (aTruncatedLen) {
+ MOZ_ASSERT(aU16FullName.length() <= aTruncatedLen);
+ name = name.substr(0, aTruncatedLen);
+ }
+
+ if (name == aU16FullName) {
+ *aIndex = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+SFNTData::AddFont(const uint8_t *aFontData, uint32_t aDataLength,
+ uint32_t aOffset)
+{
+ uint32_t remainingLength = aDataLength - aOffset;
+ if (remainingLength < sizeof(OffsetTable)) {
+ gfxWarning() << "Font data too short to contain OffsetTable " << aOffset;
+ return false;
+ }
+
+ const OffsetTable *offsetTable =
+ reinterpret_cast<const OffsetTable*>(aFontData + aOffset);
+ if (remainingLength <
+ sizeof(OffsetTable) + (offsetTable->numTables * sizeof(TableDirEntry))) {
+ gfxWarning() << "Font data too short to contain tables.";
+ return false;
+ }
+
+ return mFonts.append(new Font(offsetTable, aFontData, aDataLength));
+}
+
+} // gfx
+} // mozilla