Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
335 lines (290 sloc) 11.7 KB
/* Modified for use with ttf2eot, originally from WebKit. */
/*
* Copyright (C) 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <vector>
#ifndef _MSC_VER
# include <stdint.h>
#else
typedef unsigned char uint8_t;
#endif
#include "OpenTypeUtilities.h"
using std::vector;
typedef unsigned Fixed;
#define DEFAULT_CHARSET 1
struct BigEndianUShort {
operator unsigned short() const { return (v & 0x00ff) << 8 | v >> 8; }
BigEndianUShort(unsigned short u) : v((u & 0x00ff) << 8 | u >> 8) { }
unsigned short v;
};
struct BigEndianULong {
operator unsigned() const { return (v & 0xff) << 24 | (v & 0xff00) << 8 | (v & 0xff0000) >> 8 | v >> 24; }
BigEndianULong(unsigned u) : v((u & 0xff) << 24 | (u & 0xff00) << 8 | (u & 0xff0000) >> 8 | u >> 24) { }
unsigned v;
};
#pragma pack(1)
struct EOTPrefix {
unsigned eotSize;
unsigned fontDataSize;
unsigned version;
unsigned flags;
uint8_t fontPANOSE[10];
uint8_t charset;
uint8_t italic;
unsigned weight;
unsigned short fsType;
unsigned short magicNumber;
unsigned unicodeRange[4];
unsigned codePageRange[2];
unsigned checkSumAdjustment;
unsigned reserved[4];
unsigned short padding1;
};
struct TableDirectoryEntry {
BigEndianULong tag;
BigEndianULong checkSum;
BigEndianULong offset;
BigEndianULong length;
};
struct sfntHeader {
Fixed version;
BigEndianUShort numTables;
BigEndianUShort searchRange;
BigEndianUShort entrySelector;
BigEndianUShort rangeShift;
TableDirectoryEntry tables[1];
};
struct OS2Table {
BigEndianUShort version;
BigEndianUShort avgCharWidth;
BigEndianUShort weightClass;
BigEndianUShort widthClass;
BigEndianUShort fsType;
BigEndianUShort subscriptXSize;
BigEndianUShort subscriptYSize;
BigEndianUShort subscriptXOffset;
BigEndianUShort subscriptYOffset;
BigEndianUShort superscriptXSize;
BigEndianUShort superscriptYSize;
BigEndianUShort superscriptXOffset;
BigEndianUShort superscriptYOffset;
BigEndianUShort strikeoutSize;
BigEndianUShort strikeoutPosition;
BigEndianUShort familyClass;
uint8_t panose[10];
BigEndianULong unicodeRange[4];
uint8_t vendID[4];
BigEndianUShort fsSelection;
BigEndianUShort firstCharIndex;
BigEndianUShort lastCharIndex;
BigEndianUShort typoAscender;
BigEndianUShort typoDescender;
BigEndianUShort typoLineGap;
BigEndianUShort winAscent;
BigEndianUShort winDescent;
BigEndianULong codePageRange[2];
BigEndianUShort xHeight;
BigEndianUShort capHeight;
BigEndianUShort defaultChar;
BigEndianUShort breakChar;
BigEndianUShort maxContext;
};
struct headTable {
Fixed version;
Fixed fontRevision;
BigEndianULong checkSumAdjustment;
BigEndianULong magicNumber;
BigEndianUShort flags;
BigEndianUShort unitsPerEm;
long long created;
long long modified;
BigEndianUShort xMin;
BigEndianUShort xMax;
BigEndianUShort yMin;
BigEndianUShort yMax;
BigEndianUShort macStyle;
BigEndianUShort lowestRectPPEM;
BigEndianUShort fontDirectionHint;
BigEndianUShort indexToLocFormat;
BigEndianUShort glyphDataFormat;
};
struct nameRecord {
BigEndianUShort platformID;
BigEndianUShort encodingID;
BigEndianUShort languageID;
BigEndianUShort nameID;
BigEndianUShort length;
BigEndianUShort offset;
};
struct nameTable {
BigEndianUShort format;
BigEndianUShort count;
BigEndianUShort stringOffset;
nameRecord nameRecords[1];
};
#pragma pack()
static void appendBigEndianStringToEOTHeader(vector<uint8_t>&eotHeader, const BigEndianUShort* string, unsigned short length)
{
size_t size = eotHeader.size();
eotHeader.resize(size + length + 2 * sizeof(unsigned short));
unsigned short* dst = reinterpret_cast<unsigned short*>(&eotHeader[0] + size);
unsigned i = 0;
dst[i++] = length;
unsigned numCharacters = length / 2;
for (unsigned j = 0; j < numCharacters; j++)
dst[i++] = string[j];
dst[i] = 0;
}
bool getEOTHeader(unsigned char* fontData, size_t fontSize, vector<uint8_t>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength)
{
overlayDst = 0;
overlaySrc = 0;
overlayLength = 0;
size_t dataLength = fontSize;
const char* data = (const char *) fontData;
eotHeader.resize(sizeof(EOTPrefix));
EOTPrefix* prefix = reinterpret_cast<EOTPrefix*>(&eotHeader[0]);
prefix->fontDataSize = dataLength;
prefix->version = 0x00020001;
prefix->flags = 0;
if (dataLength < offsetof(sfntHeader, tables))
return false;
const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(data);
if (dataLength < offsetof(sfntHeader, tables) + sfnt->numTables * sizeof(TableDirectoryEntry))
return false;
bool haveOS2 = false;
bool haveHead = false;
bool haveName = false;
const BigEndianUShort* familyName = 0;
unsigned short familyNameLength = 0;
const BigEndianUShort* subfamilyName = 0;
unsigned short subfamilyNameLength = 0;
const BigEndianUShort* fullName = 0;
unsigned short fullNameLength = 0;
const BigEndianUShort* versionString = 0;
unsigned short versionStringLength = 0;
for (unsigned i = 0; i < sfnt->numTables; i++) {
unsigned tableOffset = sfnt->tables[i].offset;
unsigned tableLength = sfnt->tables[i].length;
if (dataLength < tableOffset || dataLength < tableLength || dataLength < tableOffset + tableLength)
return false;
unsigned tableTag = sfnt->tables[i].tag;
switch (tableTag) {
case 'OS/2':
{
if (dataLength < tableOffset + sizeof(OS2Table))
return false;
haveOS2 = true;
const OS2Table* OS2 = reinterpret_cast<const OS2Table*>(data + tableOffset);
for (unsigned j = 0; j < 10; j++)
prefix->fontPANOSE[j] = OS2->panose[j];
prefix->italic = OS2->fsSelection & 0x01;
prefix->weight = OS2->weightClass;
// FIXME: Should use OS2->fsType, but some TrueType fonts set it to an over-restrictive value.
// Since ATS does not enforce this on Mac OS X, we do not enforce it either.
prefix->fsType = 0;
for (unsigned j = 0; j < 4; j++)
prefix->unicodeRange[j] = OS2->unicodeRange[j];
for (unsigned j = 0; j < 2; j++)
prefix->codePageRange[j] = OS2->codePageRange[j];
break;
}
case 'head':
{
if (dataLength < tableOffset + sizeof(headTable))
return false;
haveHead = true;
const headTable* head = reinterpret_cast<const headTable*>(data + tableOffset);
prefix->checkSumAdjustment = head->checkSumAdjustment;
break;
}
case 'name':
{
if (dataLength < tableOffset + offsetof(nameTable, nameRecords))
return false;
haveName = true;
const nameTable* name = reinterpret_cast<const nameTable*>(data + tableOffset);
for (int j = 0; j < name->count; j++) {
if (dataLength < tableOffset + offsetof(nameTable, nameRecords) + (j + 1) * sizeof(nameRecord))
return false;
if (name->nameRecords[j].platformID == 3 && name->nameRecords[j].encodingID == 1 && name->nameRecords[j].languageID == 0x0409) {
if (dataLength < tableOffset + name->stringOffset + name->nameRecords[j].offset + name->nameRecords[j].length)
return false;
unsigned short nameLength = name->nameRecords[j].length;
const BigEndianUShort* nameString = reinterpret_cast<const BigEndianUShort*>(data + tableOffset + name->stringOffset + name->nameRecords[j].offset);
switch (name->nameRecords[j].nameID) {
case 1:
familyNameLength = nameLength;
familyName = nameString;
break;
case 2:
subfamilyNameLength = nameLength;
subfamilyName = nameString;
break;
case 4:
fullNameLength = nameLength;
fullName = nameString;
break;
case 5:
versionStringLength = nameLength;
versionString = nameString;
break;
default:
break;
}
}
}
break;
}
default:
break;
}
if (haveOS2 && haveHead && haveName)
break;
}
prefix->charset = DEFAULT_CHARSET;
prefix->magicNumber = 0x504c;
prefix->reserved[0] = 0;
prefix->reserved[1] = 0;
prefix->reserved[2] = 0;
prefix->reserved[3] = 0;
prefix->padding1 = 0;
appendBigEndianStringToEOTHeader(eotHeader, familyName, familyNameLength);
appendBigEndianStringToEOTHeader(eotHeader, subfamilyName, subfamilyNameLength);
appendBigEndianStringToEOTHeader(eotHeader, versionString, versionStringLength);
// If possible, ensure that the family name is a prefix of the full name.
if (fullNameLength >= familyNameLength && memcmp(familyName, fullName, familyNameLength)) {
overlaySrc = reinterpret_cast<const char*>(fullName) - data;
overlayDst = reinterpret_cast<const char*>(familyName) - data;
overlayLength = familyNameLength;
}
appendBigEndianStringToEOTHeader(eotHeader, fullName, fullNameLength);
unsigned short padding = 0;
eotHeader.push_back(padding);
eotHeader.push_back(padding);
prefix = reinterpret_cast<EOTPrefix*>(&eotHeader[0]);
prefix->eotSize = eotHeader.size() + fontSize;
return true;
}
You can’t perform that action at this time.