1/* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkOTUtils.h" 9 10#include "SkAdvancedTypefaceMetrics.h" 11#include "SkData.h" 12#include "SkEndian.h" 13#include "SkOTTableTypes.h" 14#include "SkOTTable_head.h" 15#include "SkOTTable_name.h" 16#include "SkSFNTHeader.h" 17#include "SkStream.h" 18 19extern const uint8_t SK_OT_GlyphData_NoOutline[] = { 20 0x0,0x0, //SkOTTableGlyphData::numberOfContours 21 0x0,0x0, //SkOTTableGlyphData::xMin 22 0x0,0x0, //SkOTTableGlyphData::yMin 23 0x0,0x0, //SkOTTableGlyphData::xMax 24 0x0,0x0, //SkOTTableGlyphData::yMax 25 26 0x0,0x0, //SkOTTableGlyphDataInstructions::length 27}; 28 29uint32_t SkOTUtils::CalcTableChecksum(SK_OT_ULONG *data, size_t length) { 30 uint32_t sum = 0; 31 SK_OT_ULONG *dataEnd = data + ((length + 3) & ~3) / sizeof(SK_OT_ULONG); 32 for (; data < dataEnd; ++data) { 33 sum += SkEndian_SwapBE32(*data); 34 } 35 return sum; 36} 37 38SkData* SkOTUtils::RenameFont(SkStreamAsset* fontData, const char* fontName, int fontNameLen) { 39 40 // Get the sfnt header. 41 SkSFNTHeader sfntHeader; 42 if (fontData->read(&sfntHeader, sizeof(sfntHeader)) < sizeof(sfntHeader)) { 43 return nullptr; 44 } 45 46 // Find the existing 'name' table. 47 int tableIndex; 48 SkSFNTHeader::TableDirectoryEntry tableEntry; 49 int numTables = SkEndian_SwapBE16(sfntHeader.numTables); 50 for (tableIndex = 0; tableIndex < numTables; ++tableIndex) { 51 if (fontData->read(&tableEntry, sizeof(tableEntry)) < sizeof(tableEntry)) { 52 return nullptr; 53 } 54 if (SkOTTableName::TAG == tableEntry.tag) { 55 break; 56 } 57 } 58 if (tableIndex == numTables) { 59 return nullptr; 60 } 61 62 if (!fontData->rewind()) { 63 return nullptr; 64 } 65 66 // The required 'name' record types: Family, Style, Unique, Full and PostScript. 67 const SkOTTableName::Record::NameID::Predefined::Value namesToCreate[] = { 68 SkOTTableName::Record::NameID::Predefined::FontFamilyName, 69 SkOTTableName::Record::NameID::Predefined::FontSubfamilyName, 70 SkOTTableName::Record::NameID::Predefined::UniqueFontIdentifier, 71 SkOTTableName::Record::NameID::Predefined::FullFontName, 72 SkOTTableName::Record::NameID::Predefined::PostscriptName, 73 }; 74 const int namesCount = SK_ARRAY_COUNT(namesToCreate); 75 76 // Copy the data, leaving out the old name table. 77 // In theory, we could also remove the DSIG table if it exists. 78 size_t nameTableLogicalSize = sizeof(SkOTTableName) + (namesCount * sizeof(SkOTTableName::Record)) + (fontNameLen * sizeof(wchar_t)); 79 size_t nameTablePhysicalSize = (nameTableLogicalSize + 3) & ~3; // Rounded up to a multiple of 4. 80 81 size_t oldNameTablePhysicalSize = (SkEndian_SwapBE32(tableEntry.logicalLength) + 3) & ~3; // Rounded up to a multiple of 4. 82 size_t oldNameTableOffset = SkEndian_SwapBE32(tableEntry.offset); 83 84 //originalDataSize is the size of the original data without the name table. 85 size_t originalDataSize = fontData->getLength() - oldNameTablePhysicalSize; 86 size_t newDataSize = originalDataSize + nameTablePhysicalSize; 87 88 auto rewrittenFontData = SkData::MakeUninitialized(newDataSize); 89 SK_OT_BYTE* data = static_cast<SK_OT_BYTE*>(rewrittenFontData->writable_data()); 90 91 if (fontData->read(data, oldNameTableOffset) < oldNameTableOffset) { 92 return nullptr; 93 } 94 if (fontData->skip(oldNameTablePhysicalSize) < oldNameTablePhysicalSize) { 95 return nullptr; 96 } 97 if (fontData->read(data + oldNameTableOffset, originalDataSize - oldNameTableOffset) < originalDataSize - oldNameTableOffset) { 98 return nullptr; 99 } 100 101 //Fix up the offsets of the directory entries after the old 'name' table entry. 102 SkSFNTHeader::TableDirectoryEntry* currentEntry = reinterpret_cast<SkSFNTHeader::TableDirectoryEntry*>(data + sizeof(SkSFNTHeader)); 103 SkSFNTHeader::TableDirectoryEntry* endEntry = currentEntry + numTables; 104 SkSFNTHeader::TableDirectoryEntry* headTableEntry = nullptr; 105 for (; currentEntry < endEntry; ++currentEntry) { 106 uint32_t oldOffset = SkEndian_SwapBE32(currentEntry->offset); 107 if (oldOffset > oldNameTableOffset) { 108 currentEntry->offset = SkEndian_SwapBE32(SkToU32(oldOffset - oldNameTablePhysicalSize)); 109 } 110 if (SkOTTableHead::TAG == currentEntry->tag) { 111 headTableEntry = currentEntry; 112 } 113 } 114 115 // Make the table directory entry point to the new 'name' table. 116 SkSFNTHeader::TableDirectoryEntry* nameTableEntry = reinterpret_cast<SkSFNTHeader::TableDirectoryEntry*>(data + sizeof(SkSFNTHeader)) + tableIndex; 117 nameTableEntry->logicalLength = SkEndian_SwapBE32(SkToU32(nameTableLogicalSize)); 118 nameTableEntry->offset = SkEndian_SwapBE32(SkToU32(originalDataSize)); 119 120 // Write the new 'name' table after the original font data. 121 SkOTTableName* nameTable = reinterpret_cast<SkOTTableName*>(data + originalDataSize); 122 unsigned short stringOffset = sizeof(SkOTTableName) + (namesCount * sizeof(SkOTTableName::Record)); 123 nameTable->format = SkOTTableName::format_0; 124 nameTable->count = SkEndian_SwapBE16(namesCount); 125 nameTable->stringOffset = SkEndian_SwapBE16(stringOffset); 126 127 SkOTTableName::Record* nameRecords = reinterpret_cast<SkOTTableName::Record*>(data + originalDataSize + sizeof(SkOTTableName)); 128 for (int i = 0; i < namesCount; ++i) { 129 nameRecords[i].platformID.value = SkOTTableName::Record::PlatformID::Windows; 130 nameRecords[i].encodingID.windows.value = SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2; 131 nameRecords[i].languageID.windows.value = SkOTTableName::Record::LanguageID::Windows::English_UnitedStates; 132 nameRecords[i].nameID.predefined.value = namesToCreate[i]; 133 nameRecords[i].offset = SkEndian_SwapBE16(0); 134 nameRecords[i].length = SkEndian_SwapBE16(SkToU16(fontNameLen * sizeof(wchar_t))); 135 } 136 137 SK_OT_USHORT* nameString = reinterpret_cast<SK_OT_USHORT*>(data + originalDataSize + stringOffset); 138 for (int i = 0; i < fontNameLen; ++i) { 139 nameString[i] = SkEndian_SwapBE16(fontName[i]); 140 } 141 142 unsigned char* logical = data + originalDataSize + nameTableLogicalSize; 143 unsigned char* physical = data + originalDataSize + nameTablePhysicalSize; 144 for (; logical < physical; ++logical) { 145 *logical = 0; 146 } 147 148 // Update the table checksum in the directory entry. 149 nameTableEntry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum(reinterpret_cast<SK_OT_ULONG*>(nameTable), nameTableLogicalSize)); 150 151 // Update the checksum adjustment in the head table. 152 if (headTableEntry) { 153 size_t headTableOffset = SkEndian_SwapBE32(headTableEntry->offset); 154 if (headTableOffset + sizeof(SkOTTableHead) < originalDataSize) { 155 SkOTTableHead* headTable = reinterpret_cast<SkOTTableHead*>(data + headTableOffset); 156 headTable->checksumAdjustment = SkEndian_SwapBE32(0); 157 uint32_t unadjustedFontChecksum = SkOTUtils::CalcTableChecksum(reinterpret_cast<SK_OT_ULONG*>(data), originalDataSize + nameTablePhysicalSize); 158 headTable->checksumAdjustment = SkEndian_SwapBE32(SkOTTableHead::fontChecksum - unadjustedFontChecksum); 159 } 160 } 161 162 return rewrittenFontData.release(); 163} 164 165 166SkOTUtils::LocalizedStrings_NameTable* 167SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(const SkTypeface& typeface) { 168 static const SkFontTableTag nameTag = SkSetFourByteTag('n','a','m','e'); 169 size_t nameTableSize = typeface.getTableSize(nameTag); 170 if (0 == nameTableSize) { 171 return nullptr; 172 } 173 std::unique_ptr<uint8_t[]> nameTableData(new uint8_t[nameTableSize]); 174 size_t copied = typeface.getTableData(nameTag, 0, nameTableSize, nameTableData.get()); 175 if (copied != nameTableSize) { 176 return nullptr; 177 } 178 179 return new SkOTUtils::LocalizedStrings_NameTable((SkOTTableName*)nameTableData.release(), 180 SkOTUtils::LocalizedStrings_NameTable::familyNameTypes, 181 SK_ARRAY_COUNT(SkOTUtils::LocalizedStrings_NameTable::familyNameTypes)); 182} 183 184bool SkOTUtils::LocalizedStrings_NameTable::next(SkTypeface::LocalizedString* localizedString) { 185 do { 186 SkOTTableName::Iterator::Record record; 187 if (fFamilyNameIter.next(record)) { 188 localizedString->fString = record.name; 189 localizedString->fLanguage = record.language; 190 return true; 191 } 192 if (fTypesCount == fTypesIndex + 1) { 193 return false; 194 } 195 ++fTypesIndex; 196 fFamilyNameIter.reset(fTypes[fTypesIndex]); 197 } while (true); 198} 199 200SkOTTableName::Record::NameID::Predefined::Value 201SkOTUtils::LocalizedStrings_NameTable::familyNameTypes[3] = { 202 SkOTTableName::Record::NameID::Predefined::FontFamilyName, 203 SkOTTableName::Record::NameID::Predefined::PreferredFamily, 204 SkOTTableName::Record::NameID::Predefined::WWSFamilyName, 205}; 206 207void SkOTUtils::SetAdvancedTypefaceFlags(SkOTTableOS2_V4::Type fsType, 208 SkAdvancedTypefaceMetrics* info) { 209 SkASSERT(info); 210 // The logic should be identical to SkTypeface_FreeType::onGetAdvancedMetrics(). 211 if (fsType.raw.value != 0) { 212 if (SkToBool(fsType.field.Restricted) || SkToBool(fsType.field.Bitmap)) { 213 info->fFlags |= SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag; 214 } 215 if (SkToBool(fsType.field.NoSubsetting)) { 216 info->fFlags |= SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag; 217 } 218 } 219} 220