summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/sfnt/SkOTUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/sfnt/SkOTUtils.cpp')
-rw-r--r--gfx/skia/skia/src/sfnt/SkOTUtils.cpp231
1 files changed, 231 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/sfnt/SkOTUtils.cpp b/gfx/skia/skia/src/sfnt/SkOTUtils.cpp
new file mode 100644
index 0000000000..0dd44a079a
--- /dev/null
+++ b/gfx/skia/skia/src/sfnt/SkOTUtils.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <array>
+
+#include "src/sfnt/SkOTUtils.h"
+
+#include "include/core/SkData.h"
+#include "include/core/SkStream.h"
+#include "include/private/base/SkTo.h"
+#include "src/base/SkEndian.h"
+#include "src/core/SkAdvancedTypefaceMetrics.h"
+#include "src/sfnt/SkOTTableTypes.h"
+#include "src/sfnt/SkOTTable_head.h"
+#include "src/sfnt/SkOTTable_name.h"
+#include "src/sfnt/SkSFNTHeader.h"
+
+uint32_t SkOTUtils::CalcTableChecksum(SK_OT_ULONG *data, size_t length) {
+ uint32_t sum = 0;
+ SK_OT_ULONG *dataEnd = data + ((length + 3) & ~3) / sizeof(SK_OT_ULONG);
+ for (; data < dataEnd; ++data) {
+ sum += SkEndian_SwapBE32(*data);
+ }
+ return sum;
+}
+
+SkData* SkOTUtils::RenameFont(SkStreamAsset* fontData, const char* fontName, int fontNameLen) {
+
+ // Get the sfnt header.
+ SkSFNTHeader sfntHeader;
+ if (fontData->read(&sfntHeader, sizeof(sfntHeader)) < sizeof(sfntHeader)) {
+ return nullptr;
+ }
+
+ // Find the existing 'name' table.
+ int tableIndex;
+ SkSFNTHeader::TableDirectoryEntry tableEntry;
+ int numTables = SkEndian_SwapBE16(sfntHeader.numTables);
+ for (tableIndex = 0; tableIndex < numTables; ++tableIndex) {
+ if (fontData->read(&tableEntry, sizeof(tableEntry)) < sizeof(tableEntry)) {
+ return nullptr;
+ }
+ if (SkOTTableName::TAG == tableEntry.tag) {
+ break;
+ }
+ }
+ if (tableIndex == numTables) {
+ return nullptr;
+ }
+
+ if (!fontData->rewind()) {
+ return nullptr;
+ }
+
+ // The required 'name' record types: Family, Style, Unique, Full and PostScript.
+ static constexpr std::array<SkOTTableName::Record::NameID::Predefined::Value, 5> names{{
+ SkOTTableName::Record::NameID::Predefined::FontFamilyName,
+ SkOTTableName::Record::NameID::Predefined::FontSubfamilyName,
+ SkOTTableName::Record::NameID::Predefined::UniqueFontIdentifier,
+ SkOTTableName::Record::NameID::Predefined::FullFontName,
+ SkOTTableName::Record::NameID::Predefined::PostscriptName,
+ }};
+
+ // GDI will not use a Symbol cmap table if there is no Symbol encoded name.
+ static constexpr std::array<SkOTTableName::Record::EncodingID::Windows::Value, 2> encodings{{
+ SkOTTableName::Record::EncodingID::Windows::Symbol,
+ SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2,
+ }};
+
+ // Copy the data, leaving out the old name table.
+ // In theory, we could also remove the DSIG table if it exists.
+ size_t nameTableLogicalSize = sizeof(SkOTTableName)
+ + (encodings.size() * names.size() * sizeof(SkOTTableName::Record))
+ + (fontNameLen * sizeof(SK_OT_USHORT));
+ size_t nameTablePhysicalSize = (nameTableLogicalSize + 3) & ~3; // Rounded up to a multiple of 4.
+
+ size_t oldNameTablePhysicalSize = (SkEndian_SwapBE32(tableEntry.logicalLength) + 3) & ~3; // Rounded up to a multiple of 4.
+ size_t oldNameTableOffset = SkEndian_SwapBE32(tableEntry.offset);
+
+ //originalDataSize is the size of the original data without the name table.
+ size_t originalDataSize = fontData->getLength() - oldNameTablePhysicalSize;
+ size_t newDataSize = originalDataSize + nameTablePhysicalSize;
+
+ auto rewrittenFontData = SkData::MakeUninitialized(newDataSize);
+ SK_OT_BYTE* data = static_cast<SK_OT_BYTE*>(rewrittenFontData->writable_data());
+
+ if (fontData->read(data, oldNameTableOffset) < oldNameTableOffset) {
+ return nullptr;
+ }
+ if (fontData->skip(oldNameTablePhysicalSize) < oldNameTablePhysicalSize) {
+ return nullptr;
+ }
+ if (fontData->read(data + oldNameTableOffset, originalDataSize - oldNameTableOffset) < originalDataSize - oldNameTableOffset) {
+ return nullptr;
+ }
+
+ //Fix up the offsets of the directory entries after the old 'name' table entry.
+ SkSFNTHeader::TableDirectoryEntry* currentEntry = reinterpret_cast<SkSFNTHeader::TableDirectoryEntry*>(data + sizeof(SkSFNTHeader));
+ SkSFNTHeader::TableDirectoryEntry* endEntry = currentEntry + numTables;
+ SkSFNTHeader::TableDirectoryEntry* headTableEntry = nullptr;
+ for (; currentEntry < endEntry; ++currentEntry) {
+ uint32_t oldOffset = SkEndian_SwapBE32(currentEntry->offset);
+ if (oldOffset > oldNameTableOffset) {
+ currentEntry->offset = SkEndian_SwapBE32(SkToU32(oldOffset - oldNameTablePhysicalSize));
+ }
+
+ if (SkOTTableHead::TAG == currentEntry->tag) {
+ headTableEntry = currentEntry;
+ }
+ }
+
+ // Make the table directory entry point to the new 'name' table.
+ SkSFNTHeader::TableDirectoryEntry* nameTableEntry = reinterpret_cast<SkSFNTHeader::TableDirectoryEntry*>(data + sizeof(SkSFNTHeader)) + tableIndex;
+ nameTableEntry->logicalLength = SkEndian_SwapBE32(SkToU32(nameTableLogicalSize));
+ nameTableEntry->offset = SkEndian_SwapBE32(SkToU32(originalDataSize));
+
+ // Write the new 'name' table after the original font data.
+ SkOTTableName* nameTable = reinterpret_cast<SkOTTableName*>(data + originalDataSize);
+ unsigned short stringOffset = sizeof(SkOTTableName) + (encodings.size() * names.size() * sizeof(SkOTTableName::Record));
+ nameTable->format = SkOTTableName::format_0;
+ nameTable->count = SkEndian_SwapBE16(encodings.size() * names.size());
+ nameTable->stringOffset = SkEndian_SwapBE16(stringOffset);
+
+ SkOTTableName::Record* nameRecord = reinterpret_cast<SkOTTableName::Record*>(data + originalDataSize + sizeof(SkOTTableName));
+ for (const auto& encoding : encodings) {
+ for (const auto& name : names) {
+ nameRecord->platformID.value = SkOTTableName::Record::PlatformID::Windows;
+ nameRecord->encodingID.windows.value = encoding;
+ nameRecord->languageID.windows.value = SkOTTableName::Record::LanguageID::Windows::English_UnitedStates;
+ nameRecord->nameID.predefined.value = name;
+ nameRecord->offset = SkEndian_SwapBE16(0);
+ nameRecord->length = SkEndian_SwapBE16(SkToU16(fontNameLen * sizeof(SK_OT_USHORT)));
+ ++nameRecord;
+ }
+ }
+
+ SK_OT_USHORT* nameString = reinterpret_cast<SK_OT_USHORT*>(data + originalDataSize + stringOffset);
+ for (int i = 0; i < fontNameLen; ++i) {
+ nameString[i] = SkEndian_SwapBE16(fontName[i]);
+ }
+
+ unsigned char* logical = data + originalDataSize + nameTableLogicalSize;
+ unsigned char* physical = data + originalDataSize + nameTablePhysicalSize;
+ for (; logical < physical; ++logical) {
+ *logical = 0;
+ }
+
+ // Update the table checksum in the directory entry.
+ nameTableEntry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum(reinterpret_cast<SK_OT_ULONG*>(nameTable), nameTableLogicalSize));
+
+ // Update the checksum adjustment in the head table.
+ if (headTableEntry) {
+ size_t headTableOffset = SkEndian_SwapBE32(headTableEntry->offset);
+ if (headTableOffset + sizeof(SkOTTableHead) < originalDataSize) {
+ SkOTTableHead* headTable = reinterpret_cast<SkOTTableHead*>(data + headTableOffset);
+ headTable->checksumAdjustment = SkEndian_SwapBE32(0);
+ uint32_t unadjustedFontChecksum = SkOTUtils::CalcTableChecksum(reinterpret_cast<SK_OT_ULONG*>(data), originalDataSize + nameTablePhysicalSize);
+ headTable->checksumAdjustment = SkEndian_SwapBE32(SkOTTableHead::fontChecksum - unadjustedFontChecksum);
+ }
+ }
+
+ return rewrittenFontData.release();
+}
+
+sk_sp<SkOTUtils::LocalizedStrings_NameTable>
+SkOTUtils::LocalizedStrings_NameTable::Make(const SkTypeface& typeface,
+ SK_OT_USHORT types[],
+ int typesCount)
+{
+ static const SkFontTableTag nameTag = SkSetFourByteTag('n','a','m','e');
+ size_t nameTableSize = typeface.getTableSize(nameTag);
+ if (0 == nameTableSize) {
+ return nullptr;
+ }
+ std::unique_ptr<uint8_t[]> nameTableData(new uint8_t[nameTableSize]);
+ size_t copied = typeface.getTableData(nameTag, 0, nameTableSize, nameTableData.get());
+ if (copied != nameTableSize) {
+ return nullptr;
+ }
+
+ return sk_sp<SkOTUtils::LocalizedStrings_NameTable>(
+ new SkOTUtils::LocalizedStrings_NameTable(std::move(nameTableData), nameTableSize,
+ types, typesCount));
+}
+
+sk_sp<SkOTUtils::LocalizedStrings_NameTable>
+SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(const SkTypeface& typeface) {
+ return Make(typeface,
+ SkOTUtils::LocalizedStrings_NameTable::familyNameTypes,
+ std::size(SkOTUtils::LocalizedStrings_NameTable::familyNameTypes));
+}
+
+bool SkOTUtils::LocalizedStrings_NameTable::next(SkTypeface::LocalizedString* localizedString) {
+ do {
+ SkOTTableName::Iterator::Record record;
+ if (fFamilyNameIter.next(record)) {
+ localizedString->fString = record.name;
+ localizedString->fLanguage = record.language;
+ return true;
+ }
+ if (fTypesCount == fTypesIndex + 1) {
+ return false;
+ }
+ ++fTypesIndex;
+ fFamilyNameIter.reset(fTypes[fTypesIndex]);
+ } while (true);
+}
+
+SK_OT_USHORT SkOTUtils::LocalizedStrings_NameTable::familyNameTypes[3] = {
+ SkOTTableName::Record::NameID::Predefined::FontFamilyName,
+ SkOTTableName::Record::NameID::Predefined::PreferredFamily,
+ SkOTTableName::Record::NameID::Predefined::WWSFamilyName,
+};
+
+void SkOTUtils::SetAdvancedTypefaceFlags(SkOTTableOS2_V4::Type fsType,
+ SkAdvancedTypefaceMetrics* info) {
+ SkASSERT(info);
+ // The logic should be identical to SkTypeface_FreeType::onGetAdvancedMetrics().
+ if (fsType.raw.value != 0) {
+ if (SkToBool(fsType.field.Restricted) || SkToBool(fsType.field.Bitmap)) {
+ info->fFlags |= SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag;
+ }
+ if (SkToBool(fsType.field.NoSubsetting)) {
+ info->fFlags |= SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag;
+ }
+ }
+}