Home | History | Annotate | Download | only in sfnt
      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 
     19 extern 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 
     29 uint32_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 
     38 SkData* 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 
    166 SkOTUtils::LocalizedStrings_NameTable*
    167 SkOTUtils::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 
    184 bool 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 
    200 SkOTTableName::Record::NameID::Predefined::Value
    201 SkOTUtils::LocalizedStrings_NameTable::familyNameTypes[3] = {
    202     SkOTTableName::Record::NameID::Predefined::FontFamilyName,
    203     SkOTTableName::Record::NameID::Predefined::PreferredFamily,
    204     SkOTTableName::Record::NameID::Predefined::WWSFamilyName,
    205 };
    206 
    207 void 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