Bug 458861. Validate TrueType headers before activating downloaded font. r=roc, sr=vlad,roc
authorJohn Daggett <jdaggett@mozilla.com>
Wed, 29 Oct 2008 11:09:50 -0700
changeset 21067 c18b83a877357b1e06a24c714ae011c5dc2287c9
parent 21059 c8b770c2fe89f80fc134da3489a0cf7a3d0181a8
child 21068 b9f15c32ee8ff8463a9602c896fdd51532407d17
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, vlad, roc
bugs458861
milestone1.9.1b2pre
Bug 458861. Validate TrueType headers before activating downloaded font. r=roc, sr=vlad,roc
gfx/thebes/public/gfxFontUtils.h
gfx/thebes/public/gfxPlatform.h
gfx/thebes/public/gfxPlatformMac.h
gfx/thebes/public/gfxUserFontSet.h
gfx/thebes/public/gfxWindowsPlatform.h
gfx/thebes/src/gfxFontUtils.cpp
gfx/thebes/src/gfxPlatformMac.cpp
gfx/thebes/src/gfxQuartzFontCache.h
gfx/thebes/src/gfxQuartzFontCache.mm
gfx/thebes/src/gfxUserFontSet.cpp
gfx/thebes/src/gfxWindowsPlatform.cpp
layout/style/nsFontFaceLoader.cpp
layout/style/nsFontFaceLoader.h
--- a/gfx/thebes/public/gfxFontUtils.h
+++ b/gfx/thebes/public/gfxFontUtils.h
@@ -312,38 +312,44 @@ public:
     static inline PRUint32
     ReadLongAt(const PRUint8 *aBuf, PRUint32 aIndex)
     {
         return ((aBuf[aIndex] << 24) | (aBuf[aIndex + 1] << 16) | 
                 (aBuf[aIndex + 2] << 8) | (aBuf[aIndex + 3]));
     }
     
     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
     ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
              PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont);
       
 #ifdef XP_WIN
     // given a TrueType/OpenType data file, produce a EOT-format header
     // for use with Windows T2Embed API AddFontResource type API's
     // effectively hide existing fonts with matching names aHeaderLen is
     // the size of the header buffer on input, the actual size of the
     // 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 ||
                 ch == 0x2060);
     }
 
     static inline bool IsInvalid(PRUint32 ch) {
         return (ch == 0xFFFD);
--- a/gfx/thebes/public/gfxPlatform.h
+++ b/gfx/thebes/public/gfxPlatform.h
@@ -55,17 +55,16 @@
 typedef void* cmsHPROFILE;
 typedef void* cmsHTRANSFORM;
 
 class gfxImageSurface;
 class gfxFont;
 class gfxFontGroup;
 struct gfxFontStyle;
 class gfxUserFontSet;
-struct gfxDownloadedFontData;
 class gfxFontEntry;
 class nsIURI;
 
 // pref lang id's for font prefs
 // !!! needs to match the list of pref font.default.xx entries listed in all.js !!!
 
 enum eFontPrefLang {
     eFontPrefLang_Western     =  0,
@@ -195,20 +194,18 @@ public:
     /**
      * Look up a local platform font using the full font face name (needed to support @font-face src local() )
      */
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName) { return nsnull; }
 
     /**
      * 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
      */
     virtual PRBool DownloadableFontsEnabled();
 
     // check whether format is supported on a platform or not (if unclear, returns true)
     virtual PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags) { return PR_FALSE; }
--- a/gfx/thebes/public/gfxPlatformMac.h
+++ b/gfx/thebes/public/gfxPlatformMac.h
@@ -66,17 +66,17 @@ public:
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
                                   const gfxFontStyle *aStyle,
                                   gfxUserFontSet *aUserFontSet);
 
     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);
 
     nsresult GetFontList(const nsACString& aLangGroup,
                          const nsACString& aGenericFamily,
                          nsStringArray& aListOfFonts);
     nsresult UpdateFontList();
 
--- a/gfx/thebes/public/gfxUserFontSet.h
+++ b/gfx/thebes/public/gfxUserFontSet.h
@@ -58,30 +58,16 @@ struct gfxFontFaceSrc {
     nsCOMPtr<nsIURI>       mURI;           // uri if url 
 
     // format hint flags, union of all possible formats
     // (e.g. TrueType, EOT, SVG, etc.)
     // see FLAG_FORMAT_* enum values below
     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 {
 public:
   gfxFontLoaderContext() { }
   virtual ~gfxFontLoaderContext() { }
 };
 
@@ -211,17 +197,17 @@ public:
     gfxFontEntry *FindFontEntry(const nsAString& aName, 
                                 const gfxFontStyle& aFontStyle, PRBool& aNeedsBold);
 
     // when download has been completed, pass back data here
     // aDownloadStatus == NS_OK ==> download succeeded, error otherwise
     // 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
     // incremented so that the change can be recognized 
     PRUint64 GetGeneration() { return mGeneration; }
 
 protected:
     // for a given proxy font entry, attempt to load the next resource
--- a/gfx/thebes/public/gfxWindowsPlatform.h
+++ b/gfx/thebes/public/gfxWindowsPlatform.h
@@ -81,17 +81,17 @@ public:
     /**
      * Look up a local platform font using the full font face name (needed to support @font-face src local() )
      */
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName);
 
     /**
      * 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)
      */
     virtual PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
 
     /* Given a string and a font we already have find the font that
      * supports the most code points and most closely resembles aFont
--- a/gfx/thebes/src/gfxFontUtils.cpp
+++ b/gfx/thebes/src/gfxFontUtils.cpp
@@ -217,17 +217,17 @@ static const struct UnicodeRangeTableEnt
     { 109, 0x1D300, 0x1D35F, "Tai Xuan Jing Symbols" },
     { 110, 0x12000, 0x123FF, "Cuneiform" },
     { 110, 0x12400, 0x1247F, "Cuneiform Numbers and Punctuation" },
     { 111, 0x1D360, 0x1D37F, "Counting Rod Numerals" }
 };
 
 
 nsresult
-gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap) 
+gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBitSet& aCharacterMap) 
 {
     enum {
         OffsetFormat = 0,
         OffsetReserved = 2,
         OffsetTableLength = 4,
         OffsetLanguage = 8,
         OffsetNumberGroups = 12,
         OffsetGroups = 16,
@@ -257,17 +257,17 @@ gfxFontUtils::ReadCMAPTableFormat12(PRUi
         const PRUint32 endCharCode = ReadLongAt(groups, GroupOffsetEndCode);
         aCharacterMap.SetRange(startCharCode, endCharCode);
     }
 
     return NS_OK;
 }
 
 nsresult 
-gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap)
+gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBitSet& aCharacterMap)
 {
     enum {
         OffsetFormat = 0,
         OffsetLength = 2,
         OffsetLanguage = 4,
         OffsetSegCountX2 = 6
     };
 
@@ -466,44 +466,41 @@ void gfxFontUtils::GetPrefsFontList(cons
         
         // append it to the list
         aFontList.AppendElement(fontname);
         ++p;
     }
 
 }
 
-// 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;
 };
 
 struct SFNTHeader {
     AutoSwap_PRUint32    sfntVersion;            // Fixed, 0x00010000 for version 1.0.
     AutoSwap_PRUint16    numTables;              // Number of tables.
     AutoSwap_PRUint16    searchRange;            // (Maximum power of 2 <= numTables) x 16.
     AutoSwap_PRUint16    entrySelector;          // Log2(maximum power of 2 <= numTables).
@@ -514,17 +511,18 @@ struct TableDirEntry {
     AutoSwap_PRUint32    tag;                    // 4 -byte identifier.
     AutoSwap_PRUint32    checkSum;               // CheckSum for this table.
     AutoSwap_PRUint32    offset;                 // Offset from beginning of TrueType font file.
     AutoSwap_PRUint32    length;                 // Length of this table.        
 };
 
 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.
     AutoSwap_PRUint32    fontRevision;          // Set by font manufacturer.
     AutoSwap_PRUint32    checkSumAdjustment;    // To compute: set it to 0, sum the entire font as ULONG, then store 0xB1B0AFBA - sum.
     AutoSwap_PRUint32    magicNumber;           // Set to 0x5F0F3CF5.
     AutoSwap_PRUint16    flags;
     AutoSwap_PRUint16    unitsPerEm;            // Valid range is from 16 to 16384. This value should be a power of 2 for fonts that have TrueType outlines.
@@ -563,16 +561,25 @@ struct NameRecord {
         NAME_ID_VERSION = 5,
         PLATFORM_ID_UNICODE = 0,                 // Mac OS uses this typically
         PLATFORM_ID_MICROSOFT = 3,
         ENCODING_ID_MICROSOFT_UNICODEBMP = 1,    // with Microsoft platformID, BMP-only Unicode encoding
         LANG_ID_MICROSOFT_EN_US = 0x0409         // with Microsoft platformID, EN US lang code
     };
 };
 
+// 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;
     AutoSwap_PRUint16    usWeightClass;
     AutoSwap_PRUint16    usWidthClass;
     AutoSwap_PRUint16    fsType;
     AutoSwap_PRInt16     ySubscriptXSize;
     AutoSwap_PRInt16     ySubscriptYSize;
@@ -603,16 +610,199 @@ struct OS2Table {
     AutoSwap_PRUint32    codePageRange2;
     AutoSwap_PRInt16     sxHeight;
     AutoSwap_PRInt16     sCapHeight;
     AutoSwap_PRUint16    usDefaultChar;
     AutoSwap_PRUint16    usBreakChar;
     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
 //
 // EOT version 0x00020001
 // based on http://www.w3.org/Submission/2008/SUBM-EOT-20080305/
 //
 // EOT header consists of a fixed-size portion containing general font
 // info, followed by a variable-sized portion containing name data,
@@ -652,16 +842,20 @@ struct EOTFixedHeader {
         EOT_STYLE_NAME_INDEX = 1,
         EOT_VERSION_NAME_INDEX = 2,
         EOT_FULL_NAME_INDEX = 3,
         EOT_NUM_NAMES = 4
     };
 
 };
 
+// EOT headers are only used on Windows
+
+#ifdef XP_WIN
+
 // EOT variable-sized header (version 0x00020001 - contains 4 name
 // fields, each with the structure):
 //
 //   // number of bytes in the name array
 //   PRUint16 size;
 //   // array of UTF-16 chars, total length = <size> bytes
 //   // note: english version of name record string
 //   PRUint8  name[size]; 
@@ -671,71 +865,19 @@ struct EOTFixedHeader {
 //
 //   familyName  - based on name ID = 1
 //   styleName   - based on name ID = 2
 //   versionName - based on name ID = 5
 //   fullName    - based on name ID = 4
 //   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;
 
     printf("\n\nlen == %d\n\n", aHeaderLen);
     while (offset < aHeaderLen) {
         printf("%7.7x    ", offset);
         int i;
@@ -744,94 +886,92 @@ static void DumpEOTHeader(PRUint8 *aHead
         }
         printf("\n");
         offset += 16;
     }
 }
 #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;
+
+    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;
 
-    NS_ASSERTION(aHeader, "null header");
-    NS_ASSERTION(aHeader->Length() == 0, "non-empty header passed in");
-    NS_ASSERTION(aIsCFF, "null boolean ptr");
-
     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;
     eotHeader->version = EOTFixedHeader::EOT_VERSION;
     eotHeader->flags = 0;  // don't specify any special processing
     eotHeader->charset = EOTFixedHeader::EOT_DEFAULT_CHARSET;
     eotHeader->fsType = EOTFixedHeader::EOT_EMBED_PRINT_PREVIEW;
     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
     PRBool foundHead = PR_FALSE, foundOS2 = PR_FALSE, foundName = PR_FALSE, foundGlyphs = PR_FALSE;
     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
             foundGlyphs = PR_TRUE;
             break;
 
         case 'CFF ':  // PS-style cubic glyph table
             foundGlyphs = PR_TRUE;
@@ -845,82 +985,72 @@ gfxFontUtils::MakeEOTHeader(nsIFile *aFo
         if (foundHead && foundName && foundOS2 && foundGlyphs)
             break;
     }
 
     // require these three tables on Windows
     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:
             break;
         }
 
         if (names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length &&
             names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length &&
@@ -947,41 +1077,35 @@ gfxFontUtils::MakeEOTHeader(nsIFile *aFo
                                                          + 2 /* padding */) +
                         2 /* null root string size */;
 
     if (!aHeader->AppendElements(eotVariableLength))
         return NS_ERROR_OUT_OF_MEMORY;
 
     // 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;
 
         // add 2-byte zero padding to the end of each string
         *eotEnd++ = 0;
         *eotEnd++ = 0;
 
@@ -994,35 +1118,29 @@ gfxFontUtils::MakeEOTHeader(nsIFile *aFo
     // append null root string size
     *eotEnd++ = 0;
     *eotEnd++ = 0;
 
     NS_ASSERTION(eotEnd == aHeader->Elements() + aHeader->Length(), 
                  "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;
 
     // DumpEOTHeader(aHeader->Elements(), aHeader->Length());
 
     return NS_OK;
 }
 
-#endif
+#endif
\ No newline at end of file
--- a/gfx/thebes/src/gfxPlatformMac.cpp
+++ b/gfx/thebes/src/gfxPlatformMac.cpp
@@ -124,19 +124,19 @@ gfxPlatformMac::CreateFontGroup(const ns
 
 gfxFontEntry* 
 gfxPlatformMac::LookupLocalFont(const nsAString& aFontName)
 {
     return gfxQuartzFontCache::SharedFontCache()->LookupLocalFont(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
 gfxPlatformMac::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
 {
     // reject based on format flags
     if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_EOT | gfxUserFontSet::FLAG_FORMAT_SVG)) {
         return PR_FALSE;
--- a/gfx/thebes/src/gfxQuartzFontCache.h
+++ b/gfx/thebes/src/gfxQuartzFontCache.h
@@ -222,17 +222,17 @@ public:
     
     PRBool GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> > *array);
     void SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<MacOSFamilyEntry> >& array);
     
     void AddOtherFamilyName(MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherFamilyName);
 
     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,
                                                nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
                                                void* userArg);
 
     static gfxQuartzFontCache *sSharedFontCache;
 
--- a/gfx/thebes/src/gfxQuartzFontCache.mm
+++ b/gfx/thebes/src/gfxQuartzFontCache.mm
@@ -137,33 +137,33 @@ MacOSFontEntry::MacOSFontEntry(ATSUFontI
     mWeight = aWeight;
     mStretch = aStretch;
     mFixedPitch = PR_FALSE; // xxx - do we need this for downloaded fonts?
     mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
     
     mTraits = (mItalic ? NSItalicFontMask : NSUnitalicFontMask) |
               (mFixedPitch ? NSFixedPitchFontMask : 0) |
               (mWeight >= 600 ? NSBoldFontMask : NSUnboldFontMask);
-              
+
     // get the postscript name
     OSStatus err;
     NSString *psname = NULL;
 
     // now lookup the Postscript name
     err = ATSFontGetPostScriptName((ATSFontRef) aFontID, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
     if (err == noErr) {
         GetStringForNSString(psname, mName);
         [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        
     }
 }
 
 const nsString& 
 MacOSFontEntry::FamilyName()
 {
     return mFamily->Name();
 }
@@ -1296,124 +1296,125 @@ gfxQuartzFontCache::LookupLocalFont(cons
 // needed to prevent one doc from finding a font used in a separate doc
 
 enum {
     kPrivateATSFontContextPrivate = 3
 };
 
 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()
     {
         // 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)
+    
+    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;
-
-    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)
-        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!");
 
     MacOSFontEntry *newFontEntry = 
         new MacOSFontEntry(fontID, w, aProxyEntry->mStretch, 
                            (PRUint32(aProxyEntry->mItalic) ? 
                                        FONT_STYLE_ITALIC : 
                                        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    
         delete newFontEntry;
         return nsnull;
     }
 
     return newFontEntry;
--- a/gfx/thebes/src/gfxUserFontSet.cpp
+++ b/gfx/thebes/src/gfxUserFontSet.cpp
@@ -205,44 +205,42 @@ gfxUserFontSet::FindFontEntry(const nsAS
 
     // if either loading or an error occurred, return null
     return nsnull;
 }
 
 
 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");
 
     if (!aFontToLoad->mIsProxy)
         return PR_FALSE;
 
     gfxProxyFontEntry *pe = static_cast<gfxProxyFontEntry*> (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();
 #ifdef PR_LOGGING
             if (LOG_ENABLED()) {
                 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;
         } else {
 #ifdef PR_LOGGING
             if (LOG_ENABLED()) {
                 nsCAutoString fontURI;
                 pe->mSrcList[pe->mSrcIndex].mURI->GetSpec(fontURI);
--- a/gfx/thebes/src/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/src/gfxWindowsPlatform.cpp
@@ -717,81 +717,59 @@ public:
     
     HANDLE mFontRef;
 };
 
 // used to control stream read by Windows TTLoadEmbeddedFont API
 
 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);
             memcpy(out, mEOTHeader + mHeaderOffset, toCopy);
             bytesLeft -= toCopy;
             mHeaderOffset += toCopy;
             out += toCopy;
             if (mHeaderOffset == mEOTHeaderLen)
                 mInHeader = PR_FALSE;
         }
 
         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;
         }
 
         return aBytesToRead - bytesLeft;
     }
 
     static unsigned long ReadEOTStream(void *aReadStream, void *outBuffer, 
@@ -801,49 +779,48 @@ public:
                                static_cast<EOTFontStreamReader*> (aReadStream);
         return eotReader->Read(outBuffer, aBytesToRead);
     }        
         
 };
 
 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;
     PRUint32 eotlen;
     PRUnichar fontName[LF_FACESIZE];
     PRBool isCFF;
     
     nsresult rv;
     HANDLE fontRef;
     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;
 
         // load in embedded font data
         eotlen = eotHeader.Length();
         buffer = reinterpret_cast<PRUint8*> (eotHeader.Elements());
         
         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, 
                                    EOTFontStreamReader::ReadEOTStream, 
                                    &eotReader, fontName, 0, 0);
     }
 
     if (ret != E_NONE)
--- a/layout/style/nsFontFaceLoader.cpp
+++ b/layout/style/nsFontFaceLoader.cpp
@@ -105,79 +105,24 @@ nsFontFaceLoader::nsFontFaceLoader(gfxFo
 
 }
 
 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
   if (LOG_ENABLED()) {
     nsCAutoString fontURI;
     mFontURI->GetSpec(fontURI);
     if (NS_SUCCEEDED(aStatus)) {
       LOG(("fontdownloader (%p) download completed - font uri: (%s)\n", 
@@ -186,42 +131,35 @@ nsFontFaceLoader::OnDownloadComplete(nsI
       LOG(("fontdownloader (%p) download failed - font uri: (%s) error: %8.8x\n", 
            this, fontURI.get(), aStatus));
     }
   }
 #endif
 
   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
   if (fontUpdate) {
     nsFontFaceLoaderContext *loaderCtx 
                        = static_cast<nsFontFaceLoaderContext*> (mLoaderContext);
 
     nsIPresShell *ps = loaderCtx->mPresContext->PresShell();
     if (ps) {
       // reflow async so that reflows coalesce
       ps->StyleChangeReflow();
       LOG(("fontdownloader (%p) reflow\n", this));
     }
   }
 
-  return NS_OK;
+  return aStatus;
 }
 
 PRBool
 nsFontFaceLoader::CreateHandler(gfxFontEntry *aFontToLoad, nsIURI *aFontURI, 
                                 gfxUserFontSet::LoaderContext *aContext)
 {
   // check same-site origin
   nsFontFaceLoaderContext *loaderCtx 
@@ -229,17 +167,35 @@ nsFontFaceLoader::CreateHandler(gfxFontE
 
   nsIPresShell *ps = loaderCtx->mPresContext->PresShell();
   if (!ps)
     return PR_FALSE;
 
   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);
 }
+
--- a/layout/style/nsFontFaceLoader.h
+++ b/layout/style/nsFontFaceLoader.h
@@ -37,48 +37,46 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /* code for loading in @font-face defined font data */
 
 #ifndef nsFontFaceLoader_h_
 #define nsFontFaceLoader_h_
 
-#include "nsIDownloader.h"
+#include "nsIStreamLoader.h"
 #include "nsIURI.h"
 #include "gfxUserFontSet.h"
 
 class nsIRequest;
 class nsISupports;
 class nsPresContext;
 
-class nsFontFaceLoader : public nsIDownloadObserver
+class nsFontFaceLoader : public nsIStreamLoaderObserver
 {
 public:
 
   nsFontFaceLoader(gfxFontEntry *aFontToLoad, nsIURI *aFontURI, 
                    gfxUserFontSet::LoaderContext *aContext);
   virtual ~nsFontFaceLoader();
 
   NS_DECL_ISUPPORTS
-  NS_DECL_NSIDOWNLOADOBSERVER 
+  NS_DECL_NSISTREAMLOADEROBSERVER 
 
   // initiate the load
   nsresult Init();  
 
   // returns whether create succeeded or not
   static PRBool CreateHandler(gfxFontEntry *aFontToLoad, nsIURI *aFontURI, 
                               gfxUserFontSet::LoaderContext *aContext);
 
 private:
   nsRefPtr<gfxFontEntry>              mFontEntry;
   nsCOMPtr<nsIURI>                    mFontURI;
   gfxUserFontSet::LoaderContext*      mLoaderContext;
-  gfxDownloadedFontData               mFaceData;
-  nsCOMPtr<nsIStreamListener>         mDownloader;
 };
 
 class nsFontFaceLoaderContext : public gfxUserFontSet::LoaderContext {
 public:
   nsFontFaceLoaderContext(nsPresContext* aContext)
     : gfxUserFontSet::LoaderContext(nsFontFaceLoader::CreateHandler), 
       mPresContext(aContext)
   {