1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/sfnt/SkOTUtils.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,203 @@ 1.4 +/* 1.5 + * Copyright 2012 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkData.h" 1.12 +#include "SkEndian.h" 1.13 +#include "SkSFNTHeader.h" 1.14 +#include "SkStream.h" 1.15 +#include "SkOTTable_head.h" 1.16 +#include "SkOTTable_name.h" 1.17 +#include "SkOTTableTypes.h" 1.18 +#include "SkOTUtils.h" 1.19 + 1.20 +extern const uint8_t SK_OT_GlyphData_NoOutline[] = { 1.21 + 0x0,0x0, //SkOTTableGlyphData::numberOfContours 1.22 + 0x0,0x0, //SkOTTableGlyphData::xMin 1.23 + 0x0,0x0, //SkOTTableGlyphData::yMin 1.24 + 0x0,0x0, //SkOTTableGlyphData::xMax 1.25 + 0x0,0x0, //SkOTTableGlyphData::yMax 1.26 + 1.27 + 0x0,0x0, //SkOTTableGlyphDataInstructions::length 1.28 +}; 1.29 + 1.30 +uint32_t SkOTUtils::CalcTableChecksum(SK_OT_ULONG *data, size_t length) { 1.31 + uint32_t sum = 0; 1.32 + SK_OT_ULONG *dataEnd = data + ((length + 3) & ~3) / sizeof(SK_OT_ULONG); 1.33 + for (; data < dataEnd; ++data) { 1.34 + sum += SkEndian_SwapBE32(*data); 1.35 + } 1.36 + return sum; 1.37 +} 1.38 + 1.39 +SkData* SkOTUtils::RenameFont(SkStream* fontData, const char* fontName, int fontNameLen) { 1.40 + 1.41 + // Get the sfnt header. 1.42 + SkSFNTHeader sfntHeader; 1.43 + if (fontData->read(&sfntHeader, sizeof(sfntHeader)) < sizeof(sfntHeader)) { 1.44 + return NULL; 1.45 + } 1.46 + 1.47 + // Find the existing 'name' table. 1.48 + int tableIndex; 1.49 + SkSFNTHeader::TableDirectoryEntry tableEntry; 1.50 + int numTables = SkEndian_SwapBE16(sfntHeader.numTables); 1.51 + for (tableIndex = 0; tableIndex < numTables; ++tableIndex) { 1.52 + if (fontData->read(&tableEntry, sizeof(tableEntry)) < sizeof(tableEntry)) { 1.53 + return NULL; 1.54 + } 1.55 + if (SkOTTableName::TAG == tableEntry.tag) { 1.56 + break; 1.57 + } 1.58 + } 1.59 + if (tableIndex == numTables) { 1.60 + return NULL; 1.61 + } 1.62 + 1.63 + if (!fontData->rewind()) { 1.64 + return NULL; 1.65 + } 1.66 + 1.67 + // The required 'name' record types: Family, Style, Unique, Full and PostScript. 1.68 + const SkOTTableName::Record::NameID::Predefined::Value namesToCreate[] = { 1.69 + SkOTTableName::Record::NameID::Predefined::FontFamilyName, 1.70 + SkOTTableName::Record::NameID::Predefined::FontSubfamilyName, 1.71 + SkOTTableName::Record::NameID::Predefined::UniqueFontIdentifier, 1.72 + SkOTTableName::Record::NameID::Predefined::FullFontName, 1.73 + SkOTTableName::Record::NameID::Predefined::PostscriptName, 1.74 + }; 1.75 + const int namesCount = SK_ARRAY_COUNT(namesToCreate); 1.76 + 1.77 + // Copy the data, leaving out the old name table. 1.78 + // In theory, we could also remove the DSIG table if it exists. 1.79 + size_t nameTableLogicalSize = sizeof(SkOTTableName) + (namesCount * sizeof(SkOTTableName::Record)) + (fontNameLen * sizeof(wchar_t)); 1.80 + size_t nameTablePhysicalSize = (nameTableLogicalSize + 3) & ~3; // Rounded up to a multiple of 4. 1.81 + 1.82 + size_t oldNameTablePhysicalSize = (SkEndian_SwapBE32(tableEntry.logicalLength) + 3) & ~3; // Rounded up to a multiple of 4. 1.83 + size_t oldNameTableOffset = SkEndian_SwapBE32(tableEntry.offset); 1.84 + 1.85 + //originalDataSize is the size of the original data without the name table. 1.86 + size_t originalDataSize = fontData->getLength() - oldNameTablePhysicalSize; 1.87 + size_t newDataSize = originalDataSize + nameTablePhysicalSize; 1.88 + 1.89 + SK_OT_BYTE* data = static_cast<SK_OT_BYTE*>(sk_malloc_throw(newDataSize)); 1.90 + SkAutoTUnref<SkData> rewrittenFontData(SkData::NewFromMalloc(data, newDataSize)); 1.91 + 1.92 + if (fontData->read(data, oldNameTableOffset) < oldNameTableOffset) { 1.93 + return NULL; 1.94 + } 1.95 + if (fontData->skip(oldNameTablePhysicalSize) < oldNameTablePhysicalSize) { 1.96 + return NULL; 1.97 + } 1.98 + if (fontData->read(data + oldNameTableOffset, originalDataSize - oldNameTableOffset) < originalDataSize - oldNameTableOffset) { 1.99 + return NULL; 1.100 + } 1.101 + 1.102 + //Fix up the offsets of the directory entries after the old 'name' table entry. 1.103 + SkSFNTHeader::TableDirectoryEntry* currentEntry = reinterpret_cast<SkSFNTHeader::TableDirectoryEntry*>(data + sizeof(SkSFNTHeader)); 1.104 + SkSFNTHeader::TableDirectoryEntry* endEntry = currentEntry + numTables; 1.105 + SkSFNTHeader::TableDirectoryEntry* headTableEntry = NULL; 1.106 + for (; currentEntry < endEntry; ++currentEntry) { 1.107 + uint32_t oldOffset = SkEndian_SwapBE32(currentEntry->offset); 1.108 + if (oldOffset > oldNameTableOffset) { 1.109 + currentEntry->offset = SkEndian_SwapBE32(oldOffset - oldNameTablePhysicalSize); 1.110 + } 1.111 + if (SkOTTableHead::TAG == currentEntry->tag) { 1.112 + headTableEntry = currentEntry; 1.113 + } 1.114 + } 1.115 + 1.116 + // Make the table directory entry point to the new 'name' table. 1.117 + SkSFNTHeader::TableDirectoryEntry* nameTableEntry = reinterpret_cast<SkSFNTHeader::TableDirectoryEntry*>(data + sizeof(SkSFNTHeader)) + tableIndex; 1.118 + nameTableEntry->logicalLength = SkEndian_SwapBE32(nameTableLogicalSize); 1.119 + nameTableEntry->offset = SkEndian_SwapBE32(originalDataSize); 1.120 + 1.121 + // Write the new 'name' table after the original font data. 1.122 + SkOTTableName* nameTable = reinterpret_cast<SkOTTableName*>(data + originalDataSize); 1.123 + unsigned short stringOffset = sizeof(SkOTTableName) + (namesCount * sizeof(SkOTTableName::Record)); 1.124 + nameTable->format = SkOTTableName::format_0; 1.125 + nameTable->count = SkEndian_SwapBE16(namesCount); 1.126 + nameTable->stringOffset = SkEndian_SwapBE16(stringOffset); 1.127 + 1.128 + SkOTTableName::Record* nameRecords = reinterpret_cast<SkOTTableName::Record*>(data + originalDataSize + sizeof(SkOTTableName)); 1.129 + for (int i = 0; i < namesCount; ++i) { 1.130 + nameRecords[i].platformID.value = SkOTTableName::Record::PlatformID::Windows; 1.131 + nameRecords[i].encodingID.windows.value = SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2; 1.132 + nameRecords[i].languageID.windows.value = SkOTTableName::Record::LanguageID::Windows::English_UnitedStates; 1.133 + nameRecords[i].nameID.predefined.value = namesToCreate[i]; 1.134 + nameRecords[i].offset = SkEndian_SwapBE16(0); 1.135 + nameRecords[i].length = SkEndian_SwapBE16(fontNameLen * sizeof(wchar_t)); 1.136 + } 1.137 + 1.138 + SK_OT_USHORT* nameString = reinterpret_cast<SK_OT_USHORT*>(data + originalDataSize + stringOffset); 1.139 + for (int i = 0; i < fontNameLen; ++i) { 1.140 + nameString[i] = SkEndian_SwapBE16(fontName[i]); 1.141 + } 1.142 + 1.143 + unsigned char* logical = data + originalDataSize + nameTableLogicalSize; 1.144 + unsigned char* physical = data + originalDataSize + nameTablePhysicalSize; 1.145 + for (; logical < physical; ++logical) { 1.146 + *logical = 0; 1.147 + } 1.148 + 1.149 + // Update the table checksum in the directory entry. 1.150 + nameTableEntry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum(reinterpret_cast<SK_OT_ULONG*>(nameTable), nameTableLogicalSize)); 1.151 + 1.152 + // Update the checksum adjustment in the head table. 1.153 + if (headTableEntry) { 1.154 + size_t headTableOffset = SkEndian_SwapBE32(headTableEntry->offset); 1.155 + if (headTableOffset + sizeof(SkOTTableHead) < originalDataSize) { 1.156 + SkOTTableHead* headTable = reinterpret_cast<SkOTTableHead*>(data + headTableOffset); 1.157 + headTable->checksumAdjustment = SkEndian_SwapBE32(0); 1.158 + uint32_t unadjustedFontChecksum = SkOTUtils::CalcTableChecksum(reinterpret_cast<SK_OT_ULONG*>(data), originalDataSize + nameTablePhysicalSize); 1.159 + headTable->checksumAdjustment = SkEndian_SwapBE32(SkOTTableHead::fontChecksum - unadjustedFontChecksum); 1.160 + } 1.161 + } 1.162 + 1.163 + return rewrittenFontData.detach(); 1.164 +} 1.165 + 1.166 + 1.167 +SkOTUtils::LocalizedStrings_NameTable* 1.168 +SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(const SkTypeface& typeface) { 1.169 + static const SkFontTableTag nameTag = SkSetFourByteTag('n','a','m','e'); 1.170 + size_t nameTableSize = typeface.getTableSize(nameTag); 1.171 + if (0 == nameTableSize) { 1.172 + return NULL; 1.173 + } 1.174 + SkAutoTDeleteArray<uint8_t> nameTableData(new uint8_t[nameTableSize]); 1.175 + size_t copied = typeface.getTableData(nameTag, 0, nameTableSize, nameTableData.get()); 1.176 + if (copied != nameTableSize) { 1.177 + return NULL; 1.178 + } 1.179 + 1.180 + return new SkOTUtils::LocalizedStrings_NameTable((SkOTTableName*)nameTableData.detach(), 1.181 + SkOTUtils::LocalizedStrings_NameTable::familyNameTypes, 1.182 + SK_ARRAY_COUNT(SkOTUtils::LocalizedStrings_NameTable::familyNameTypes)); 1.183 +} 1.184 + 1.185 +bool SkOTUtils::LocalizedStrings_NameTable::next(SkTypeface::LocalizedString* localizedString) { 1.186 + do { 1.187 + SkOTTableName::Iterator::Record record; 1.188 + if (fFamilyNameIter.next(record)) { 1.189 + localizedString->fString = record.name; 1.190 + localizedString->fLanguage = record.language; 1.191 + return true; 1.192 + } 1.193 + if (fTypesCount == fTypesIndex + 1) { 1.194 + return false; 1.195 + } 1.196 + ++fTypesIndex; 1.197 + fFamilyNameIter.reset(fTypes[fTypesIndex]); 1.198 + } while (true); 1.199 +} 1.200 + 1.201 +SkOTTableName::Record::NameID::Predefined::Value 1.202 +SkOTUtils::LocalizedStrings_NameTable::familyNameTypes[3] = { 1.203 + SkOTTableName::Record::NameID::Predefined::FontFamilyName, 1.204 + SkOTTableName::Record::NameID::Predefined::PreferredFamily, 1.205 + SkOTTableName::Record::NameID::Predefined::WWSFamilyName, 1.206 +};