mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 458861. Validate TrueType headers before activating downloaded font. r=roc, sr=vlad,roc
This commit is contained in:
parent
b189b1fd41
commit
f37b60578a
@ -317,11 +317,11 @@ public:
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength,
|
||||
ReadCMAPTableFormat12(PRUint8 *aBuf, PRUint32 aLength,
|
||||
gfxSparseBitSet& aCharacterMap);
|
||||
|
||||
static nsresult
|
||||
ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength,
|
||||
ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength,
|
||||
gfxSparseBitSet& aCharacterMap);
|
||||
|
||||
static nsresult
|
||||
@ -336,9 +336,15 @@ public:
|
||||
// EOT header on output aIsCFF returns whether the font has PS style
|
||||
// glyphs or not (as opposed to TrueType glyphs)
|
||||
static nsresult
|
||||
MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader, PRBool *aIsCFF);
|
||||
MakeEOTHeader(const PRUint8 *aFontData, PRUint32 aFontDataLength,
|
||||
nsTArray<PRUint8> *aHeader, PRBool *aIsCFF);
|
||||
#endif
|
||||
|
||||
// checks for valid SFNT table structure, returns true if valid
|
||||
// does *not* guarantee that all font data is valid
|
||||
static PRBool
|
||||
ValidateSFNTHeaders(const PRUint8 *aFontData, PRUint32 aFontDataLength);
|
||||
|
||||
static inline bool IsJoiner(PRUint32 ch) {
|
||||
return (ch == 0x200C ||
|
||||
ch == 0x200D ||
|
||||
|
@ -60,7 +60,6 @@ class gfxFont;
|
||||
class gfxFontGroup;
|
||||
struct gfxFontStyle;
|
||||
class gfxUserFontSet;
|
||||
struct gfxDownloadedFontData;
|
||||
class gfxFontEntry;
|
||||
class nsIURI;
|
||||
|
||||
@ -200,10 +199,8 @@ public:
|
||||
/**
|
||||
* Activate a platform font (needed to support @font-face src url() )
|
||||
*
|
||||
* Note: MakePlatformFont implementation is responsible for removing font file data, since data may need to
|
||||
* persist beyond this call.
|
||||
*/
|
||||
virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData) { return nsnull; }
|
||||
virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const PRUint8 *aFontData, PRUint32 aLength) { return nsnull; }
|
||||
|
||||
/**
|
||||
* Whether to allow downloadable fonts via @font-face rules
|
||||
|
@ -71,7 +71,7 @@ public:
|
||||
|
||||
gfxFontEntry* LookupLocalFont(const nsAString& aFontName);
|
||||
|
||||
gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData);
|
||||
gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const PRUint8 *aFontData, PRUint32 aLength);
|
||||
|
||||
PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
|
||||
|
||||
|
@ -63,20 +63,6 @@ struct gfxFontFaceSrc {
|
||||
PRUint32 mFormatFlags;
|
||||
};
|
||||
|
||||
// data needed to initialize platform font
|
||||
// After download completes, platform-specific code is responsible for
|
||||
// removing temp file and managing cache token. Depending on the
|
||||
// platform, these may need to persist after the platform font has been
|
||||
// created.
|
||||
// lifetime: time during which font is downloaded and active
|
||||
struct gfxDownloadedFontData {
|
||||
nsCOMPtr<nsIFile> mFontFile; // file containing font data
|
||||
nsCOMPtr<nsISupports> mDownloader; // need to a ref to this to prevent file from being deleted
|
||||
|
||||
// format hint flags, union of all possible formats
|
||||
PRUint32 mFormatFlags; // opentype, truetype, svg, etc. (if known)
|
||||
};
|
||||
|
||||
// subclassed by loader code to contain needed context info
|
||||
// lifetime: user font set lifetime
|
||||
class gfxFontLoaderContext {
|
||||
@ -216,7 +202,7 @@ public:
|
||||
// returns true if platform font creation sucessful (or local()
|
||||
// reference was next in line)
|
||||
PRBool OnLoadComplete(gfxFontEntry *aFontToLoad,
|
||||
const gfxDownloadedFontData& aFontData,
|
||||
const PRUint8 *aFontData, PRUint32 aLength,
|
||||
nsresult aDownloadStatus);
|
||||
|
||||
// generation - each time a face is loaded, generation is
|
||||
|
@ -86,7 +86,7 @@ public:
|
||||
/**
|
||||
* Activate a platform font (needed to support @font-face src url() )
|
||||
*/
|
||||
virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData);
|
||||
virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const PRUint8 *aFontData, PRUint32 aLength);
|
||||
|
||||
/**
|
||||
* Check whether format is supported on a platform or not (if unclear, returns true)
|
||||
|
@ -222,7 +222,7 @@ static const struct UnicodeRangeTableEntry gUnicodeRanges[] = {
|
||||
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap)
|
||||
gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBitSet& aCharacterMap)
|
||||
{
|
||||
enum {
|
||||
OffsetFormat = 0,
|
||||
@ -262,7 +262,7 @@ gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBit
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap)
|
||||
gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBitSet& aCharacterMap)
|
||||
{
|
||||
enum {
|
||||
OffsetFormat = 0,
|
||||
@ -471,34 +471,31 @@ void gfxFontUtils::GetPrefsFontList(const char *aPrefName, nsTArray<nsString>& a
|
||||
|
||||
}
|
||||
|
||||
// for now, this is only needed on Windows
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
||||
// TrueType/OpenType table handling code
|
||||
|
||||
// need byte aligned structs
|
||||
#pragma pack(1)
|
||||
|
||||
struct AutoSwap_PRUint16 {
|
||||
operator PRUint16() { return NS_SWAP16(value); }
|
||||
operator PRUint32() { return NS_SWAP16(value); }
|
||||
PRUint16 value;
|
||||
operator PRUint16() const { return NS_SWAP16(value); }
|
||||
operator PRUint32() const { return NS_SWAP16(value); }
|
||||
operator PRUint64() const { return NS_SWAP16(value); }
|
||||
PRUint16 value;
|
||||
};
|
||||
|
||||
struct AutoSwap_PRInt16 {
|
||||
operator PRInt16() { return NS_SWAP16(value); }
|
||||
operator PRUint32() { return NS_SWAP16(value); }
|
||||
operator PRInt16() const { return NS_SWAP16(value); }
|
||||
operator PRUint32() const { return NS_SWAP16(value); }
|
||||
PRInt16 value;
|
||||
};
|
||||
|
||||
struct AutoSwap_PRUint32 {
|
||||
operator PRUint32() { return NS_SWAP32(value); }
|
||||
operator PRUint32() const { return NS_SWAP32(value); }
|
||||
PRUint32 value;
|
||||
};
|
||||
|
||||
struct AutoSwap_PRUint64 {
|
||||
operator PRUint64() { return NS_SWAP64(value); }
|
||||
operator PRUint64() const { return NS_SWAP64(value); }
|
||||
PRUint64 value;
|
||||
};
|
||||
|
||||
@ -519,7 +516,8 @@ struct TableDirEntry {
|
||||
|
||||
struct HeadTable {
|
||||
enum {
|
||||
HEAD_MAGIC_NUMBER = 0x5F0F3CF5
|
||||
HEAD_MAGIC_NUMBER = 0x5F0F3CF5,
|
||||
HEAD_CHECKSUM_CALC_CONST = 0xB1B0AFBA
|
||||
};
|
||||
|
||||
AutoSwap_PRUint32 tableVersionNumber; // Fixed, 0x00010000 for version 1.0.
|
||||
@ -568,6 +566,15 @@ struct NameRecord {
|
||||
};
|
||||
};
|
||||
|
||||
// name table stores set of name record structures, followed by
|
||||
// large block containing all the strings. name record offset and length
|
||||
// indicates the offset and length within that block.
|
||||
// http://www.microsoft.com/typography/otspec/name.htm
|
||||
struct NameRecordData {
|
||||
PRUint32 offset;
|
||||
PRUint32 length;
|
||||
};
|
||||
|
||||
struct OS2Table {
|
||||
AutoSwap_PRUint16 version; // 0004 = OpenType 1.5
|
||||
AutoSwap_PRInt16 xAvgCharWidth;
|
||||
@ -608,6 +615,189 @@ struct OS2Table {
|
||||
AutoSwap_PRUint16 usMaxContext;
|
||||
};
|
||||
|
||||
static PRBool
|
||||
IsValidSFNTVersion(PRUint32 version)
|
||||
{
|
||||
// normally 0x00010000, CFF-style OT fonts == 'OTTO' and Apple TT fonts = 'true'
|
||||
// 'typ1' is also possible for old Type 1 fonts in a SFNT container but not supported
|
||||
return version == 0x10000 || version == 'OTTO' || version == 'true';
|
||||
}
|
||||
|
||||
// copy and swap UTF-16 values, assume no surrogate pairs, can be in place
|
||||
static void
|
||||
CopySwapUTF16(const PRUint16 *aInBuf, PRUint16 *aOutBuf, PRUint32 aLen)
|
||||
{
|
||||
const PRUint16 *end = aInBuf + aLen;
|
||||
while (aInBuf < end) {
|
||||
PRUint16 value = *aInBuf;
|
||||
*aOutBuf = (value >> 8) | (value & 0xff) << 8;
|
||||
aOutBuf++;
|
||||
aInBuf++;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
gfxFontUtils::ValidateSFNTHeaders(const PRUint8 *aFontData, PRUint32 aFontDataLength)
|
||||
{
|
||||
NS_ASSERTION(aFontData && aFontDataLength != 0, "null font data");
|
||||
|
||||
PRUint64 dataLength(aFontDataLength);
|
||||
|
||||
// read in the sfnt header
|
||||
if (sizeof(SFNTHeader) > aFontDataLength) {
|
||||
NS_WARNING("invalid font (insufficient data)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
|
||||
PRUint32 sfntVersion = sfntHeader->sfntVersion;
|
||||
if (!IsValidSFNTVersion(sfntVersion)) {
|
||||
NS_WARNING("invalid font (SFNT version)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// iterate through the table headers to find the head, name and OS/2 tables
|
||||
PRBool foundHead = PR_FALSE, foundOS2 = PR_FALSE, foundName = PR_FALSE;
|
||||
PRBool foundGlyphs = PR_FALSE, foundCFF = PR_FALSE;
|
||||
PRUint32 headOffset, headLen, nameOffset, nameLen;
|
||||
PRUint32 i, numTables;
|
||||
|
||||
numTables = sfntHeader->numTables;
|
||||
PRUint32 headerLen = sizeof(SFNTHeader) + sizeof(TableDirEntry) * numTables;
|
||||
if (headerLen > aFontDataLength) {
|
||||
NS_WARNING("invalid font (table directory)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// table directory entries begin immediately following SFNT header
|
||||
const TableDirEntry *dirEntry = reinterpret_cast<const TableDirEntry*>(aFontData + sizeof(SFNTHeader));
|
||||
PRUint32 checksum = 0;
|
||||
|
||||
// checksum for font = (checksum of header) + (checksum of tables)
|
||||
const AutoSwap_PRUint32 *headerData = reinterpret_cast<const AutoSwap_PRUint32*>(aFontData);
|
||||
|
||||
// header length is in bytes, checksum calculated in longwords
|
||||
for (i = 0; i < (headerLen >> 2); i++, headerData++) {
|
||||
checksum += *headerData;
|
||||
}
|
||||
|
||||
for (i = 0; i < numTables; i++, dirEntry++) {
|
||||
|
||||
// sanity check on offset, length values
|
||||
if (PRUint64(dirEntry->offset) + PRUint64(dirEntry->length) > dataLength) {
|
||||
NS_WARNING("invalid font (table directory entry)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
checksum += dirEntry->checkSum;
|
||||
|
||||
switch (dirEntry->tag) {
|
||||
|
||||
case 'head':
|
||||
foundHead = PR_TRUE;
|
||||
headOffset = dirEntry->offset;
|
||||
headLen = dirEntry->length;
|
||||
if (headLen < sizeof(HeadTable)) {
|
||||
NS_WARNING("invalid font (head table length)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'name':
|
||||
foundName = PR_TRUE;
|
||||
nameOffset = dirEntry->offset;
|
||||
nameLen = dirEntry->length;
|
||||
break;
|
||||
|
||||
case 'OS/2':
|
||||
foundOS2 = PR_TRUE;
|
||||
break;
|
||||
|
||||
case 'glyf': // TrueType-style quadratic glyph table
|
||||
foundGlyphs = PR_TRUE;
|
||||
break;
|
||||
|
||||
case 'CFF ': // PS-style cubic glyph table
|
||||
foundCFF = PR_TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// simple sanity checks
|
||||
|
||||
// -- fonts need head, name tables
|
||||
if (!foundHead || !foundName) {
|
||||
NS_WARNING("invalid font (missing head/name table)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// -- on Windows need OS/2 table
|
||||
#ifdef XP_WIN
|
||||
if (!foundOS2) {
|
||||
NS_WARNING("invalid font (missing OS/2 table)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
// -- head table data
|
||||
const HeadTable *headData = reinterpret_cast<const HeadTable*>(aFontData + headOffset);
|
||||
|
||||
if (headData->magicNumber != HeadTable::HEAD_MAGIC_NUMBER) {
|
||||
NS_WARNING("invalid font (head magic number)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (headData->checkSumAdjustment != (HeadTable::HEAD_CHECKSUM_CALC_CONST - checksum)) {
|
||||
NS_WARNING("invalid font (bad checksum)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// need glyf or CFF table based on sfnt version
|
||||
if (sfntVersion == 'OTTO') {
|
||||
if (!foundCFF) {
|
||||
NS_WARNING("invalid font (missing CFF table)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
} else {
|
||||
if (!foundGlyphs) {
|
||||
NS_WARNING("invalid font (missing glyf table)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// -- name table data
|
||||
const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(aFontData + nameOffset);
|
||||
|
||||
PRUint32 nameCount = nameHeader->count;
|
||||
|
||||
// -- sanity check the number of name records
|
||||
if (PRUint64(nameCount) * sizeof(NameRecord) + PRUint64(nameOffset) > dataLength) {
|
||||
NS_WARNING("invalid font (name records)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// -- iterate through name records
|
||||
const NameRecord *nameRecord = reinterpret_cast<const NameRecord*>(aFontData + nameOffset + sizeof(NameHeader));
|
||||
PRUint64 nameStringsBase = PRUint64(nameOffset) + PRUint64(nameHeader->stringOffset);
|
||||
|
||||
for (i = 0; i < nameCount; i++, nameRecord++) {
|
||||
PRUint32 namelen = nameRecord->length;
|
||||
PRUint32 nameoff = nameRecord->offset; // offset from base of string storage
|
||||
|
||||
if (nameStringsBase + PRUint64(nameoff) + PRUint64(namelen) > dataLength) {
|
||||
NS_WARNING("invalid font (name table strings)");
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// everything seems consistent
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Embedded OpenType (EOT) handling
|
||||
// needed for dealing with downloadable fonts on Windows
|
||||
//
|
||||
@ -657,6 +847,10 @@ struct EOTFixedHeader {
|
||||
|
||||
};
|
||||
|
||||
// EOT headers are only used on Windows
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
||||
// EOT variable-sized header (version 0x00020001 - contains 4 name
|
||||
// fields, each with the structure):
|
||||
//
|
||||
@ -676,61 +870,9 @@ struct EOTFixedHeader {
|
||||
// rootString - used to restrict font usage to a specific domain
|
||||
//
|
||||
|
||||
class AutoCloseFile {
|
||||
public:
|
||||
AutoCloseFile(PRFileDesc *aFileDesc)
|
||||
: mFile(aFileDesc) { }
|
||||
~AutoCloseFile() { PR_Close(mFile); }
|
||||
PRFileDesc *mFile;
|
||||
};
|
||||
|
||||
static PRFileDesc *
|
||||
OpenFontFile(nsIFile *aFontData)
|
||||
{
|
||||
// open up the font file
|
||||
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFontData);
|
||||
if (!localFile)
|
||||
return nsnull;
|
||||
|
||||
PRFileDesc *fd;
|
||||
nsresult rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
|
||||
if (NS_FAILED(rv) || !fd)
|
||||
return nsnull;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
IsValidVersion(PRUint32 version)
|
||||
{
|
||||
// normally 0x00010000, CFF-style OT fonts == 'OTTO' and Apple TT fonts = 'true'
|
||||
return version == 0x10000 || version == 'OTTO' || version == 'true';
|
||||
}
|
||||
|
||||
// copy and swap UTF-16 values, assume no surrogate pairs, can be in place
|
||||
static void
|
||||
CopySwapUTF16(PRUint16 *aInBuf, PRUint16 *aOutBuf, PRUint32 aLen)
|
||||
{
|
||||
PRUint16 *end = aInBuf + aLen;
|
||||
while (aInBuf < end) {
|
||||
PRUint16 value = *aInBuf;
|
||||
*aOutBuf = (value >> 8) | (value & 0xff) << 8;
|
||||
aOutBuf++;
|
||||
aInBuf++;
|
||||
}
|
||||
}
|
||||
|
||||
// name table stores set of name record structures, followed by
|
||||
// large block containing all the strings. name record offset and length
|
||||
// indicates the offset and length within that block.
|
||||
// http://www.microsoft.com/typography/otspec/name.htm
|
||||
struct NameRecordData {
|
||||
PRUint32 offset;
|
||||
PRUint32 length;
|
||||
};
|
||||
|
||||
#if DEBUG
|
||||
static void DumpEOTHeader(PRUint8 *aHeader, PRUint32 aHeaderLen)
|
||||
static void
|
||||
DumpEOTHeader(PRUint8 *aHeader, PRUint32 aHeaderLen)
|
||||
{
|
||||
PRUint32 offset = 0;
|
||||
PRUint8 *ch = aHeader;
|
||||
@ -749,37 +891,25 @@ static void DumpEOTHeader(PRUint8 *aHeader, PRUint32 aHeaderLen)
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader,
|
||||
PRBool *aIsCFF)
|
||||
gfxFontUtils::MakeEOTHeader(const PRUint8 *aFontData, PRUint32 aFontDataLength,
|
||||
nsTArray<PRUint8> *aHeader, PRBool *aIsCFF)
|
||||
{
|
||||
PRInt32 bytesRead;
|
||||
|
||||
// assume TrueType
|
||||
*aIsCFF = PR_FALSE;
|
||||
|
||||
NS_ASSERTION(aFontData && aFontDataLength != 0, "null font data");
|
||||
NS_ASSERTION(aHeader, "null header");
|
||||
NS_ASSERTION(aHeader->Length() == 0, "non-empty header passed in");
|
||||
NS_ASSERTION(aIsCFF, "null boolean ptr");
|
||||
|
||||
// assume TrueType
|
||||
*aIsCFF = PR_FALSE;
|
||||
|
||||
if (!aHeader->AppendElements(sizeof(EOTFixedHeader)))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
EOTFixedHeader *eotHeader = reinterpret_cast<EOTFixedHeader*> (aHeader->Elements());
|
||||
memset(eotHeader, 0, sizeof(EOTFixedHeader));
|
||||
|
||||
// open the font file
|
||||
PRFileDesc *fd = OpenFontFile(aFontData);
|
||||
if (!fd)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
AutoCloseFile autoCloseFile(fd);
|
||||
|
||||
PRFileInfo64 fileInfo;
|
||||
if (PR_GetOpenFileInfo64(fd, &fileInfo) != PR_SUCCESS
|
||||
|| fileInfo.size > PRInt64(0xFFFFFFFF))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PRUint32 fontDataSize = PRUint32(fileInfo.size);
|
||||
PRUint32 fontDataSize = aFontDataLength;
|
||||
|
||||
// set up header fields
|
||||
eotHeader->fontDataSize = fontDataSize;
|
||||
@ -790,9 +920,11 @@ gfxFontUtils::MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader,
|
||||
eotHeader->magicNumber = EOTFixedHeader::EOT_MAGIC_NUMBER;
|
||||
|
||||
// read in the sfnt header
|
||||
SFNTHeader sfntHeader;
|
||||
bytesRead = PR_Read(fd, &sfntHeader, sizeof(SFNTHeader));
|
||||
if (bytesRead != sizeof(SFNTHeader) || !IsValidVersion(sfntHeader.sfntVersion))
|
||||
if (sizeof(SFNTHeader) > aFontDataLength)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
|
||||
if (!IsValidSFNTVersion(sfntHeader->sfntVersion))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// iterate through the table headers to find the head, name and OS/2 tables
|
||||
@ -800,33 +932,41 @@ gfxFontUtils::MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader,
|
||||
PRUint32 headOffset, headLen, nameOffset, nameLen, os2Offset, os2Len;
|
||||
PRUint32 i, numTables;
|
||||
|
||||
numTables = sfntHeader.numTables;
|
||||
for (i = 0; i < numTables; i++) {
|
||||
TableDirEntry dirEntry;
|
||||
bytesRead = PR_Read(fd, &dirEntry, sizeof(TableDirEntry));
|
||||
if (bytesRead != sizeof(TableDirEntry))
|
||||
numTables = sfntHeader->numTables;
|
||||
if (sizeof(SFNTHeader) + sizeof(TableDirEntry) * numTables > aFontDataLength)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PRUint64 dataLength(aFontDataLength);
|
||||
|
||||
// table directory entries begin immediately following SFNT header
|
||||
const TableDirEntry *dirEntry = reinterpret_cast<const TableDirEntry*>(aFontData + sizeof(SFNTHeader));
|
||||
|
||||
for (i = 0; i < numTables; i++, dirEntry++) {
|
||||
|
||||
// sanity check on offset, length values
|
||||
if (PRUint64(dirEntry->offset) + PRUint64(dirEntry->length) > dataLength)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
switch (dirEntry.tag) {
|
||||
switch (dirEntry->tag) {
|
||||
|
||||
case 'head':
|
||||
foundHead = PR_TRUE;
|
||||
headOffset = dirEntry.offset;
|
||||
headLen = dirEntry.length;
|
||||
headOffset = dirEntry->offset;
|
||||
headLen = dirEntry->length;
|
||||
if (headLen < sizeof(HeadTable))
|
||||
return NS_ERROR_FAILURE;
|
||||
break;
|
||||
|
||||
case 'name':
|
||||
foundName = PR_TRUE;
|
||||
nameOffset = dirEntry.offset;
|
||||
nameLen = dirEntry.length;
|
||||
nameOffset = dirEntry->offset;
|
||||
nameLen = dirEntry->length;
|
||||
break;
|
||||
|
||||
case 'OS/2':
|
||||
foundOS2 = PR_TRUE;
|
||||
os2Offset = dirEntry.offset;
|
||||
os2Len = dirEntry.length;
|
||||
os2Offset = dirEntry->offset;
|
||||
os2Len = dirEntry->length;
|
||||
break;
|
||||
|
||||
case 'glyf': // TrueType-style quadratic glyph table
|
||||
@ -850,72 +990,62 @@ gfxFontUtils::MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader,
|
||||
if (!foundHead || !foundName || !foundOS2)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// at this point, all table offset/length values are within bounds
|
||||
|
||||
// read in the data from those tables
|
||||
PROffset64 offset;
|
||||
|
||||
// -- head table data
|
||||
HeadTable headData;
|
||||
offset = PR_Seek64(fd, PROffset64(headOffset), PR_SEEK_SET);
|
||||
if (offset == -1)
|
||||
return NS_ERROR_FAILURE;
|
||||
bytesRead = PR_Read(fd, &headData, sizeof(HeadTable));
|
||||
if (bytesRead != sizeof(HeadTable) || headData.magicNumber != HeadTable::HEAD_MAGIC_NUMBER)
|
||||
const HeadTable *headData = reinterpret_cast<const HeadTable*>(aFontData + headOffset);
|
||||
|
||||
if (headData->magicNumber != HeadTable::HEAD_MAGIC_NUMBER)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
eotHeader->checkSumAdjustment = headData.checkSumAdjustment;
|
||||
eotHeader->checkSumAdjustment = headData->checkSumAdjustment;
|
||||
|
||||
// -- name table data
|
||||
|
||||
// -- first, read name table header
|
||||
NameHeader nameHeader;
|
||||
const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(aFontData + nameOffset);
|
||||
|
||||
offset = PR_Seek64(fd, PROffset64(nameOffset), PR_SEEK_SET);
|
||||
if (offset == -1)
|
||||
PRUint32 nameCount = nameHeader->count;
|
||||
|
||||
// -- sanity check the number of name records
|
||||
if (PRUint64(nameCount) * sizeof(NameRecord) + PRUint64(nameOffset) > dataLength)
|
||||
return NS_ERROR_FAILURE;
|
||||
bytesRead = PR_Read(fd, &nameHeader, sizeof(NameHeader));
|
||||
if (bytesRead != sizeof(NameHeader))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// -- seek point is now at the start of name records
|
||||
|
||||
|
||||
// -- iterate through name records, look for specific name ids with
|
||||
// matching platform/encoding/etc. and store offset/lengths
|
||||
NameRecordData names[EOTFixedHeader::EOT_NUM_NAMES] = {0};
|
||||
PRUint32 nameCount = nameHeader.count;
|
||||
const NameRecord *nameRecord = reinterpret_cast<const NameRecord*>(aFontData + nameOffset + sizeof(NameHeader));
|
||||
|
||||
for (i = 0; i < nameCount; i++) {
|
||||
NameRecord nameRecord;
|
||||
|
||||
bytesRead = PR_Read(fd, &nameRecord, sizeof(NameRecord));
|
||||
if (bytesRead != sizeof(NameRecord))
|
||||
return NS_ERROR_FAILURE;
|
||||
for (i = 0; i < nameCount; i++, nameRecord++) {
|
||||
|
||||
// looking for Microsoft English US name strings, skip others
|
||||
if (PRUint32(nameRecord.platformID) != NameRecord::PLATFORM_ID_MICROSOFT ||
|
||||
PRUint32(nameRecord.encodingID) != NameRecord::ENCODING_ID_MICROSOFT_UNICODEBMP ||
|
||||
PRUint32(nameRecord.languageID) != NameRecord::LANG_ID_MICROSOFT_EN_US)
|
||||
if (PRUint32(nameRecord->platformID) != NameRecord::PLATFORM_ID_MICROSOFT ||
|
||||
PRUint32(nameRecord->encodingID) != NameRecord::ENCODING_ID_MICROSOFT_UNICODEBMP ||
|
||||
PRUint32(nameRecord->languageID) != NameRecord::LANG_ID_MICROSOFT_EN_US)
|
||||
continue;
|
||||
|
||||
switch ((PRUint32)nameRecord.nameID) {
|
||||
switch ((PRUint32)nameRecord->nameID) {
|
||||
|
||||
case NameRecord::NAME_ID_FAMILY:
|
||||
names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].offset = nameRecord.offset;
|
||||
names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length = nameRecord.length;
|
||||
names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].offset = nameRecord->offset;
|
||||
names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length = nameRecord->length;
|
||||
break;
|
||||
|
||||
case NameRecord::NAME_ID_STYLE:
|
||||
names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].offset = nameRecord.offset;
|
||||
names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length = nameRecord.length;
|
||||
names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].offset = nameRecord->offset;
|
||||
names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length = nameRecord->length;
|
||||
break;
|
||||
|
||||
case NameRecord::NAME_ID_FULL:
|
||||
names[EOTFixedHeader::EOT_FULL_NAME_INDEX].offset = nameRecord.offset;
|
||||
names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length = nameRecord.length;
|
||||
names[EOTFixedHeader::EOT_FULL_NAME_INDEX].offset = nameRecord->offset;
|
||||
names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length = nameRecord->length;
|
||||
break;
|
||||
|
||||
case NameRecord::NAME_ID_VERSION:
|
||||
names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].offset = nameRecord.offset;
|
||||
names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].length = nameRecord.length;
|
||||
names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].offset = nameRecord->offset;
|
||||
names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].length = nameRecord->length;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -952,31 +1082,25 @@ gfxFontUtils::MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader,
|
||||
|
||||
// append the string data to the end of the EOT header
|
||||
PRUint8 *eotEnd = aHeader->Elements() + sizeof(EOTFixedHeader);
|
||||
PROffset64 strOffset;
|
||||
PRUint32 strLen;
|
||||
PRUint32 strOffset, strLen;
|
||||
|
||||
for (i = 0; i < EOTFixedHeader::EOT_NUM_NAMES; i++) {
|
||||
PRUint32 namelen = names[i].length;
|
||||
PRUint32 nameoff = names[i].offset; // offset from base of string storage
|
||||
|
||||
strOffset = nameOffset + PRUint32(nameHeader.stringOffset) + nameoff;
|
||||
offset = PR_Seek64(fd, strOffset, PR_SEEK_SET);
|
||||
if (offset == -1)
|
||||
// sanity check the name string location
|
||||
if (PRUint64(nameOffset) + PRUint64(PRUint32(nameHeader->stringOffset)) + PRUint64(nameoff) + PRUint64(namelen) > dataLength)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
strOffset = nameOffset + PRUint32(nameHeader->stringOffset) + nameoff + namelen;
|
||||
|
||||
// output 2-byte str size
|
||||
strLen = namelen & (~1); // UTF-16 string len must be even
|
||||
*((PRUint16*) eotEnd) = PRUint16(strLen);
|
||||
eotEnd += 2;
|
||||
|
||||
// read in actual string and swap bytes from big-endian
|
||||
// (TrueType/OpenType) to little-endian (EOT)
|
||||
bytesRead = PR_Read(fd, eotEnd, strLen);
|
||||
if (PRUint32(bytesRead) != strLen)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// length is number of UTF-16 chars, not bytes
|
||||
CopySwapUTF16(reinterpret_cast<PRUint16*>(eotEnd),
|
||||
CopySwapUTF16(reinterpret_cast<const PRUint16*>(aFontData + strOffset),
|
||||
reinterpret_cast<PRUint16*>(eotEnd),
|
||||
(strLen >> 1));
|
||||
eotEnd += strLen;
|
||||
@ -999,24 +1123,18 @@ gfxFontUtils::MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader,
|
||||
"header length calculation incorrect");
|
||||
|
||||
// -- OS/2 table data
|
||||
OS2Table os2Data;
|
||||
offset = PR_Seek64(fd, PROffset64(os2Offset), PR_SEEK_SET);
|
||||
if (offset == -1)
|
||||
return NS_ERROR_FAILURE;
|
||||
bytesRead = PR_Read(fd, &os2Data, sizeof(OS2Table));
|
||||
if (bytesRead != sizeof(OS2Table))
|
||||
return NS_ERROR_FAILURE;
|
||||
const OS2Table *os2Data = reinterpret_cast<const OS2Table*>(aFontData + os2Offset);
|
||||
|
||||
memcpy(eotHeader->panose, os2Data.panose, sizeof(eotHeader->panose));
|
||||
memcpy(eotHeader->panose, os2Data->panose, sizeof(eotHeader->panose));
|
||||
|
||||
eotHeader->italic = (PRUint16) os2Data.fsSelection & 0x01;
|
||||
eotHeader->weight = os2Data.usWeightClass;
|
||||
eotHeader->unicodeRange1 = os2Data.unicodeRange1;
|
||||
eotHeader->unicodeRange2 = os2Data.unicodeRange2;
|
||||
eotHeader->unicodeRange3 = os2Data.unicodeRange3;
|
||||
eotHeader->unicodeRange4 = os2Data.unicodeRange4;
|
||||
eotHeader->codePageRange1 = os2Data.codePageRange1;
|
||||
eotHeader->codePageRange2 = os2Data.codePageRange2;
|
||||
eotHeader->italic = (PRUint16) os2Data->fsSelection & 0x01;
|
||||
eotHeader->weight = os2Data->usWeightClass;
|
||||
eotHeader->unicodeRange1 = os2Data->unicodeRange1;
|
||||
eotHeader->unicodeRange2 = os2Data->unicodeRange2;
|
||||
eotHeader->unicodeRange3 = os2Data->unicodeRange3;
|
||||
eotHeader->unicodeRange4 = os2Data->unicodeRange4;
|
||||
eotHeader->codePageRange1 = os2Data->codePageRange1;
|
||||
eotHeader->codePageRange2 = os2Data->codePageRange2;
|
||||
|
||||
eotHeader->eotSize = aHeader->Length() + fontDataSize;
|
||||
|
||||
@ -1025,4 +1143,4 @@ gfxFontUtils::MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
@ -129,9 +129,9 @@ gfxPlatformMac::LookupLocalFont(const nsAString& aFontName)
|
||||
}
|
||||
|
||||
gfxFontEntry*
|
||||
gfxPlatformMac::MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData)
|
||||
gfxPlatformMac::MakePlatformFont(const gfxFontEntry *aProxyEntry, const PRUint8 *aFontData, PRUint32 aLength)
|
||||
{
|
||||
return gfxQuartzFontCache::SharedFontCache()->MakePlatformFont(aProxyEntry, aFontData);
|
||||
return gfxQuartzFontCache::SharedFontCache()->MakePlatformFont(aProxyEntry, aFontData, aLength);
|
||||
}
|
||||
|
||||
PRBool
|
||||
|
@ -227,7 +227,7 @@ public:
|
||||
|
||||
gfxFontEntry* LookupLocalFont(const nsAString& aFontName);
|
||||
|
||||
gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData);
|
||||
gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const PRUint8 *aFontData, PRUint32 aLength);
|
||||
|
||||
private:
|
||||
static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
|
||||
|
@ -142,7 +142,7 @@ MacOSFontEntry::MacOSFontEntry(ATSUFontID aFontID, PRUint16 aWeight, PRUint16 aS
|
||||
mTraits = (mItalic ? NSItalicFontMask : NSUnitalicFontMask) |
|
||||
(mFixedPitch ? NSFixedPitchFontMask : 0) |
|
||||
(mWeight >= 600 ? NSBoldFontMask : NSUnboldFontMask);
|
||||
|
||||
|
||||
// get the postscript name
|
||||
OSStatus err;
|
||||
NSString *psname = NULL;
|
||||
@ -154,11 +154,11 @@ MacOSFontEntry::MacOSFontEntry(ATSUFontID aFontID, PRUint16 aWeight, PRUint16 aS
|
||||
[psname release];
|
||||
} else {
|
||||
mIsValid = PR_FALSE;
|
||||
#if DEBUG
|
||||
#ifdef DEBUG
|
||||
char warnBuf[1024];
|
||||
sprintf(warnBuf, "ATSFontGetPostScriptName err = %d", (PRInt32)err);
|
||||
NS_WARNING(warnBuf);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1301,10 +1301,8 @@ enum {
|
||||
|
||||
class MacOSUserFontData : public gfxUserFontData {
|
||||
public:
|
||||
MacOSUserFontData(ATSFontContainerRef aContainerRef, nsIFile *aFontFile,
|
||||
nsISupports *aDownloader)
|
||||
: mContainerRef(aContainerRef), mFontFile(aFontFile),
|
||||
mDownloader(aDownloader)
|
||||
MacOSUserFontData(ATSFontContainerRef aContainerRef)
|
||||
: mContainerRef(aContainerRef)
|
||||
{ }
|
||||
|
||||
virtual ~MacOSUserFontData()
|
||||
@ -1312,84 +1310,83 @@ public:
|
||||
// deactivate font
|
||||
if (mContainerRef)
|
||||
ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault);
|
||||
|
||||
if (mFontFile) {
|
||||
mFontFile->Remove(PR_FALSE); // ignore errors
|
||||
}
|
||||
}
|
||||
|
||||
ATSFontContainerRef mContainerRef;
|
||||
nsCOMPtr<nsIFile> mFontFile;
|
||||
|
||||
// maintaining a ref to this keeps temp file around or cache file pinned
|
||||
nsCOMPtr<nsISupports> mDownloader;
|
||||
};
|
||||
|
||||
static OSStatus
|
||||
MakeFSSpec(FSSpec *aFSSpec, NSString *path)
|
||||
{
|
||||
FSRef fsref;
|
||||
OSStatus err = FSPathMakeRef((UInt8*)([path fileSystemRepresentation]), &fsref, NULL);
|
||||
|
||||
if (err == noErr)
|
||||
err = FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, aFSSpec, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gfxFontEntry*
|
||||
gfxQuartzFontCache::MakePlatformFont(const gfxFontEntry *aProxyEntry,
|
||||
const gfxDownloadedFontData* aFontData)
|
||||
const PRUint8 *aFontData, PRUint32 aLength)
|
||||
{
|
||||
OSStatus err;
|
||||
FSSpec spec;
|
||||
nsAutoString filePath;
|
||||
|
||||
NS_ASSERTION(aFontData && aFontData->mFontFile,
|
||||
"MakePlatformFont called with null file ptr");
|
||||
|
||||
if (!aFontData->mFontFile)
|
||||
return nsnull;
|
||||
|
||||
aFontData->mFontFile->GetPath(filePath);
|
||||
|
||||
NSString *path = GetNSStringForString(filePath);
|
||||
if (!path)
|
||||
return nsnull;
|
||||
|
||||
// assumption: filename is already in the form xxx.ttf, otherwise
|
||||
// ATS will reject
|
||||
|
||||
err = MakeFSSpec(&spec, path);
|
||||
if (err != noErr)
|
||||
|
||||
NS_ASSERTION(aFontData && aLength != 0,
|
||||
"MakePlatformFont called with null data ptr");
|
||||
|
||||
// do simple validation check on font data before
|
||||
// attempting to activate it
|
||||
if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength)) {
|
||||
#if DEBUG
|
||||
char warnBuf[1024];
|
||||
const gfxProxyFontEntry *proxyEntry =
|
||||
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
|
||||
sprintf(warnBuf, "downloaded font error, invalid font data for (%s)",
|
||||
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
|
||||
NS_WARNING(warnBuf);
|
||||
#endif
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
ATSUFontID fontID;
|
||||
ATSFontContainerRef containerRef;
|
||||
|
||||
err = ATSFontActivateFromFileSpecification(&spec,
|
||||
kPrivateATSFontContextPrivate,
|
||||
kATSFontFormatUnspecified,
|
||||
NULL,
|
||||
kATSOptionFlagsDoNotNotify,
|
||||
&containerRef);
|
||||
if (err != noErr)
|
||||
err = ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength,
|
||||
kPrivateATSFontContextPrivate,
|
||||
kATSFontFormatUnspecified,
|
||||
NULL,
|
||||
kATSOptionFlagsDoNotNotify,
|
||||
&containerRef);
|
||||
|
||||
if (err != noErr) {
|
||||
#if DEBUG
|
||||
char warnBuf[1024];
|
||||
const gfxProxyFontEntry *proxyEntry =
|
||||
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
|
||||
sprintf(warnBuf, "downloaded font error, ATSFontActivateFromMemory err: %d for (%s)",
|
||||
PRInt32(err),
|
||||
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
|
||||
NS_WARNING(warnBuf);
|
||||
#endif
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
mATSGeneration = ATSGeneration();
|
||||
|
||||
// ignoring containers with multiple fonts, use the first face only for now
|
||||
err = ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1,
|
||||
(ATSFontRef*)&fontID, NULL);
|
||||
if (err != noErr)
|
||||
if (err != noErr) {
|
||||
#if DEBUG
|
||||
char warnBuf[1024];
|
||||
const gfxProxyFontEntry *proxyEntry =
|
||||
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
|
||||
sprintf(warnBuf, "downloaded font error, ATSFontFindFromContainer err: %d for (%s)",
|
||||
PRInt32(err),
|
||||
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
|
||||
NS_WARNING(warnBuf);
|
||||
#endif
|
||||
ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
|
||||
return nsnull;
|
||||
|
||||
}
|
||||
|
||||
// font entry will own this
|
||||
MacOSUserFontData *userFontData = new MacOSUserFontData(containerRef,
|
||||
aFontData->mFontFile,
|
||||
aFontData->mDownloader);
|
||||
if (!userFontData)
|
||||
MacOSUserFontData *userFontData = new MacOSUserFontData(containerRef);
|
||||
|
||||
if (!userFontData) {
|
||||
ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
PRUint16 w = aProxyEntry->mWeight;
|
||||
NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
|
||||
@ -1401,14 +1398,18 @@ gfxQuartzFontCache::MakePlatformFont(const gfxFontEntry *aProxyEntry,
|
||||
FONT_STYLE_NORMAL),
|
||||
userFontData);
|
||||
|
||||
if (!newFontEntry) {
|
||||
delete userFontData;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// if something is funky about this font, delete immediately
|
||||
if (newFontEntry && !newFontEntry->mIsValid) {
|
||||
#if DEBUG
|
||||
char warnBuf[1024];
|
||||
const gfxProxyFontEntry *proxyEntry =
|
||||
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
|
||||
sprintf(warnBuf, "downloaded font not loaded properly, removed (%s) for (%s)",
|
||||
[path UTF8String],
|
||||
sprintf(warnBuf, "downloaded font not loaded properly, removed face for (%s)",
|
||||
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
|
||||
NS_WARNING(warnBuf);
|
||||
#endif
|
||||
|
@ -210,7 +210,7 @@ gfxUserFontSet::FindFontEntry(const nsAString& aName,
|
||||
|
||||
PRBool
|
||||
gfxUserFontSet::OnLoadComplete(gfxFontEntry *aFontToLoad,
|
||||
const gfxDownloadedFontData& aFontData,
|
||||
const PRUint8 *aFontData, PRUint32 aLength,
|
||||
nsresult aDownloadStatus)
|
||||
{
|
||||
NS_ASSERTION(aFontToLoad->mIsProxy, "trying to load font data for wrong font entry type");
|
||||
@ -222,7 +222,8 @@ gfxUserFontSet::OnLoadComplete(gfxFontEntry *aFontToLoad,
|
||||
|
||||
// download successful, make platform font using font data
|
||||
if (NS_SUCCEEDED(aDownloadStatus)) {
|
||||
gfxFontEntry *fe = gfxPlatform::GetPlatform()->MakePlatformFont(pe, &aFontData);
|
||||
gfxFontEntry *fe =
|
||||
gfxPlatform::GetPlatform()->MakePlatformFont(pe, aFontData, aLength);
|
||||
if (fe) {
|
||||
pe->mFamily->ReplaceFontEntry(pe, fe);
|
||||
IncrementGeneration();
|
||||
@ -231,13 +232,10 @@ gfxUserFontSet::OnLoadComplete(gfxFontEntry *aFontToLoad,
|
||||
nsCAutoString fontURI;
|
||||
pe->mSrcList[pe->mSrcIndex].mURI->GetSpec(fontURI);
|
||||
|
||||
nsAutoString filePath;
|
||||
aFontData.mFontFile->GetPath(filePath);
|
||||
|
||||
LOG(("userfonts (%p) [src %d] loaded uri: (%s) file: (%s) for (%s) gen: %8.8x\n",
|
||||
LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
|
||||
this, pe->mSrcIndex, fontURI.get(),
|
||||
NS_ConvertUTF16toUTF8(filePath).get(),
|
||||
NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get(), PRUint32(mGeneration)));
|
||||
NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get(),
|
||||
PRUint32(mGeneration)));
|
||||
}
|
||||
#endif
|
||||
return PR_TRUE;
|
||||
|
@ -722,58 +722,33 @@ public:
|
||||
|
||||
class EOTFontStreamReader {
|
||||
public:
|
||||
EOTFontStreamReader(nsILocalFile *aFontFile, PRUint8 *aEOTHeader,
|
||||
EOTFontStreamReader(const PRUint8 *aFontData, PRUint32 aLength, PRUint8 *aEOTHeader,
|
||||
PRUint32 aEOTHeaderLen)
|
||||
: mFontFile(aFontFile), mFd(nsnull), mOpenError(PR_FALSE),
|
||||
mInHeader(PR_TRUE), mHeaderOffset(0), mEOTHeader(aEOTHeader),
|
||||
mEOTHeaderLen(aEOTHeaderLen)
|
||||
: mInHeader(PR_TRUE), mHeaderOffset(0), mEOTHeader(aEOTHeader),
|
||||
mEOTHeaderLen(aEOTHeaderLen), mFontData(aFontData), mFontDataLen(aLength),
|
||||
mFontDataOffset(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~EOTFontStreamReader()
|
||||
{
|
||||
if (mFd) {
|
||||
PR_Close(mFd);
|
||||
}
|
||||
|
||||
mFontFile->Remove(PR_FALSE);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILocalFile> mFontFile;
|
||||
PRFileDesc *mFd;
|
||||
PRPackedBool mOpenError;
|
||||
PRPackedBool mInHeader;
|
||||
PRUint32 mHeaderOffset;
|
||||
PRUint8 *mEOTHeader;
|
||||
PRUint32 mEOTHeaderLen;
|
||||
|
||||
PRBool OpenFontFile()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = mFontFile->OpenNSPRFileDesc(PR_RDONLY, 0, &mFd);
|
||||
if (NS_FAILED(rv) || !mFd)
|
||||
return PR_FALSE;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
const PRUint8 *mFontData;
|
||||
PRUint32 mFontDataLen;
|
||||
PRUint32 mFontDataOffset;
|
||||
|
||||
unsigned long Read(void *outBuffer, const unsigned long aBytesToRead)
|
||||
{
|
||||
PRUint32 bytesLeft = aBytesToRead;
|
||||
PRUint8 *out = static_cast<PRUint8*> (outBuffer);
|
||||
|
||||
if (mOpenError)
|
||||
return 0;
|
||||
|
||||
if (!mFd) {
|
||||
if (!OpenFontFile()) {
|
||||
mOpenError = PR_TRUE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// read from EOT header
|
||||
if (mInHeader) {
|
||||
PRUint32 toCopy = PR_MIN(aBytesToRead, mEOTHeaderLen - mHeaderOffset);
|
||||
@ -786,7 +761,10 @@ public:
|
||||
}
|
||||
|
||||
if (bytesLeft) {
|
||||
PRInt32 bytesRead = PR_Read(mFd, out, bytesLeft);
|
||||
PRInt32 bytesRead = PR_MIN(bytesLeft, mFontDataLen - mFontDataOffset);
|
||||
memcpy(out, mFontData, bytesRead);
|
||||
mFontData += bytesRead;
|
||||
mFontDataOffset += bytesRead;
|
||||
if (bytesRead > 0)
|
||||
bytesLeft -= bytesRead;
|
||||
}
|
||||
@ -806,12 +784,15 @@ public:
|
||||
|
||||
gfxFontEntry*
|
||||
gfxWindowsPlatform::MakePlatformFont(const gfxFontEntry *aProxyEntry,
|
||||
const gfxDownloadedFontData* aFontData)
|
||||
const PRUint8 *aFontData, PRUint32 aLength)
|
||||
{
|
||||
// if calls aren't available, bail
|
||||
if (!TTLoadEmbeddedFontPtr || !TTDeleteEmbeddedFontPtr)
|
||||
return nsnull;
|
||||
|
||||
if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength))
|
||||
return nsnull;
|
||||
|
||||
// create an eot header
|
||||
nsAutoTArray<PRUint8,2048> eotHeader;
|
||||
PRUint8 *buffer;
|
||||
@ -824,11 +805,7 @@ gfxWindowsPlatform::MakePlatformFont(const gfxFontEntry *aProxyEntry,
|
||||
PRInt32 ret;
|
||||
|
||||
{
|
||||
nsCOMPtr<nsILocalFile> fontFile(do_QueryInterface(aFontData->mFontFile, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
rv = gfxFontUtils::MakeEOTHeader(fontFile, &eotHeader, &isCFF);
|
||||
rv = gfxFontUtils::MakeEOTHeader(aFontData, aLength, &eotHeader, &isCFF);
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
@ -838,7 +815,7 @@ gfxWindowsPlatform::MakePlatformFont(const gfxFontEntry *aProxyEntry,
|
||||
|
||||
ULONG privStatus, pulStatus;
|
||||
MakeUniqueFontName(fontName);
|
||||
EOTFontStreamReader eotReader(fontFile, buffer, eotlen);
|
||||
EOTFontStreamReader eotReader(aFontData, aLength, buffer, eotlen);
|
||||
|
||||
ret = TTLoadEmbeddedFontPtr(&fontRef, TTLOAD_PRIVATE, &privStatus,
|
||||
LICENSE_PREVIEWPRINT, &pulStatus,
|
||||
|
@ -110,69 +110,14 @@ nsFontFaceLoader::~nsFontFaceLoader()
|
||||
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsFontFaceLoader, nsIDownloadObserver)
|
||||
|
||||
static nsresult
|
||||
MakeTempFileName(nsIFile** tempFile)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, tempFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// xxx - need something a little less lame here...
|
||||
static PRUint16 count = 0;
|
||||
PRTime now = PR_Now();
|
||||
PRUint32 current = (PRUint32) now;
|
||||
|
||||
++count;
|
||||
char buf[256];
|
||||
sprintf(buf, "mozfont_%8.8x%4.4x.ttf", current, count);
|
||||
|
||||
rv = (*tempFile)->AppendNative(nsDependentCString(buf));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return (*tempFile)->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
|
||||
}
|
||||
|
||||
// initiate the load
|
||||
nsresult
|
||||
nsFontFaceLoader::Init()
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (LOG_ENABLED()) {
|
||||
nsCAutoString fontURI;
|
||||
mFontURI->GetSpec(fontURI);
|
||||
LOG(("fontdownloader (%p) download start - font uri: (%s)\n",
|
||||
this, fontURI.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIFile> tempFile;
|
||||
rv = MakeTempFileName(getter_AddRefs(tempFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = NS_NewDownloader(getter_AddRefs(mDownloader), this, tempFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker
|
||||
= nsContentUtils::GetSameOriginChecker();
|
||||
|
||||
rv = NS_OpenURI(mDownloader, nsnull, mFontURI, nsnull, nsnull,
|
||||
sameOriginChecker);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMPL_ISUPPORTS1(nsFontFaceLoader, nsIStreamLoaderObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFontFaceLoader::OnDownloadComplete(nsIDownloader *aDownloader,
|
||||
nsIRequest *aRequest,
|
||||
nsISupports *aContext,
|
||||
nsresult aStatus,
|
||||
nsIFile *aFile)
|
||||
nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
nsISupports* aContext,
|
||||
nsresult aStatus,
|
||||
PRUint32 aStringLen,
|
||||
const PRUint8* aString)
|
||||
{
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
@ -191,16 +136,9 @@ nsFontFaceLoader::OnDownloadComplete(nsIDownloader *aDownloader,
|
||||
|
||||
PRBool fontUpdate;
|
||||
|
||||
if (NS_SUCCEEDED(aStatus) && aFile) {
|
||||
// font data download succeeded, try to load the font
|
||||
mFaceData.mFormatFlags = 0;
|
||||
mFaceData.mFontFile = aFile;
|
||||
mFaceData.mDownloader = aDownloader;
|
||||
}
|
||||
|
||||
// whether an error occurred or not, notify the user font set of the completion
|
||||
fontUpdate = mLoaderContext->mUserFontSet->OnLoadComplete(mFontEntry,
|
||||
mFaceData,
|
||||
aString, aStringLen,
|
||||
aStatus);
|
||||
|
||||
// when new font loaded, need to reflow
|
||||
@ -216,7 +154,7 @@ nsFontFaceLoader::OnDownloadComplete(nsIDownloader *aDownloader,
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return aStatus;
|
||||
}
|
||||
|
||||
PRBool
|
||||
@ -234,12 +172,30 @@ nsFontFaceLoader::CreateHandler(gfxFontEntry *aFontToLoad, nsIURI *aFontURI,
|
||||
if (!CheckMayLoad(ps->GetDocument(), aFontURI))
|
||||
return PR_FALSE;
|
||||
|
||||
nsRefPtr<nsFontFaceLoader> loader = new nsFontFaceLoader(aFontToLoad,
|
||||
aFontURI,
|
||||
aContext);
|
||||
if (!loader)
|
||||
nsRefPtr<nsFontFaceLoader> fontLoader = new nsFontFaceLoader(aFontToLoad,
|
||||
aFontURI,
|
||||
aContext);
|
||||
if (!fontLoader)
|
||||
return PR_FALSE;
|
||||
|
||||
nsresult rv = loader->Init();
|
||||
#ifdef PR_LOGGING
|
||||
if (LOG_ENABLED()) {
|
||||
nsCAutoString fontURI;
|
||||
aFontURI->GetSpec(fontURI);
|
||||
LOG(("fontdownloader (%p) download start - font uri: (%s)\n",
|
||||
fontLoader.get(), fontURI.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIStreamLoader> streamLoader;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup(ps->GetDocument()->GetDocumentLoadGroup());
|
||||
nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker
|
||||
= nsContentUtils::GetSameOriginChecker();
|
||||
|
||||
nsresult rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), aFontURI,
|
||||
fontLoader, nsnull, loadGroup,
|
||||
sameOriginChecker);
|
||||
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@
|
||||
#ifndef nsFontFaceLoader_h_
|
||||
#define nsFontFaceLoader_h_
|
||||
|
||||
#include "nsIDownloader.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "nsIURI.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
|
||||
@ -50,7 +50,7 @@ class nsIRequest;
|
||||
class nsISupports;
|
||||
class nsPresContext;
|
||||
|
||||
class nsFontFaceLoader : public nsIDownloadObserver
|
||||
class nsFontFaceLoader : public nsIStreamLoaderObserver
|
||||
{
|
||||
public:
|
||||
|
||||
@ -59,7 +59,7 @@ public:
|
||||
virtual ~nsFontFaceLoader();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOWNLOADOBSERVER
|
||||
NS_DECL_NSISTREAMLOADEROBSERVER
|
||||
|
||||
// initiate the load
|
||||
nsresult Init();
|
||||
@ -72,8 +72,6 @@ private:
|
||||
nsRefPtr<gfxFontEntry> mFontEntry;
|
||||
nsCOMPtr<nsIURI> mFontURI;
|
||||
gfxUserFontSet::LoaderContext* mLoaderContext;
|
||||
gfxDownloadedFontData mFaceData;
|
||||
nsCOMPtr<nsIStreamListener> mDownloader;
|
||||
};
|
||||
|
||||
class nsFontFaceLoaderContext : public gfxUserFontSet::LoaderContext {
|
||||
|
Loading…
Reference in New Issue
Block a user