From: Jonathan Kew <jfkthame@gmail.com>

bug 507970, implement WOFF font support (roll-up patch for 1.9.2). r=bzbarsky,jdaggett

diff --git a/gfx/thebes/public/gfxFT2Fonts.h b/gfx/thebes/public/gfxFT2Fonts.h
--- a/gfx/thebes/public/gfxFT2Fonts.h
+++ b/gfx/thebes/public/gfxFT2Fonts.h
@@ -81,22 +81,24 @@ public:
     FontEntry(const FontEntry& aFontEntry);
     ~FontEntry();
 
     const nsString& GetName() const {
         return mFaceName;
     }
 
     static FontEntry* 
-    CreateFontEntry(const gfxProxyFontEntry &aProxyEntry, nsISupports *aLoader,
+    CreateFontEntry(const gfxProxyFontEntry &aProxyEntry,
                     const PRUint8 *aFontData, PRUint32 aLength);
-    
+
     static FontEntry* 
-    CreateFontEntryFromFace(FT_Face aFace);
-    
+    CreateFontEntryFromFace(FT_Face aFace, const PRUint8 *aFontData = nsnull);
+        // aFontData is NS_Malloc'ed data that aFace depends on, to be freed
+        // after the face is destroyed; null if there is no such buffer
+
     cairo_font_face_t *CairoFontFace();
     nsresult ReadCMAP();
 
     FT_Face mFTFace;
     cairo_font_face_t *mFontFace;
 
     nsString mFaceName;
     nsCString mFilename;
diff --git a/gfx/thebes/public/gfxFontUtils.h b/gfx/thebes/public/gfxFontUtils.h
--- a/gfx/thebes/public/gfxFontUtils.h
+++ b/gfx/thebes/public/gfxFontUtils.h
@@ -354,16 +354,23 @@ struct AutoSwap_PRUint64 {
 // used for overlaying name changes without touching original font data
 struct FontDataOverlay {
     // overlaySrc != 0 ==> use overlay
     PRUint32  overlaySrc;    // src offset from start of font data
     PRUint32  overlaySrcLen; // src length
     PRUint32  overlayDest;   // dest offset from start of font data
 };
     
+enum gfxUserFontType {
+    GFX_USERFONT_UNKNOWN = 0,
+    GFX_USERFONT_OPENTYPE = 1,
+    GFX_USERFONT_SVG = 2,
+    GFX_USERFONT_WOFF = 3
+};
+
 class THEBES_API gfxFontUtils {
 
 public:
     // these are public because gfxFont.cpp also looks into the name table
     enum {
         NAME_ID_FAMILY = 1,
         NAME_ID_STYLE = 2,
         NAME_ID_UNIQUE = 3,
@@ -479,23 +486,32 @@ public:
     // 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
     static nsresult
     MakeEOTHeader(const PRUint8 *aFontData, PRUint32 aFontDataLength,
                   nsTArray<PRUint8> *aHeader, FontDataOverlay *aOverlay);
+
+    // determine whether a font (which has already passed ValidateSFNTHeaders)
+    // is CFF format rather than TrueType
+    static PRBool
+    IsCffFont(const PRUint8* aFontData);
+
 #endif
 
+    // determine the format of font data
+    static gfxUserFontType
+    DetermineFontDataType(const PRUint8 *aFontData, PRUint32 aFontDataLength);
+
     // 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,
-                        PRBool *aIsCFF = nsnull);
+    ValidateSFNTHeaders(const PRUint8 *aFontData, PRUint32 aFontDataLength);
     
     // create a new name table and build a new font with that name table
     // appended on the end, returns true on success
     static nsresult
     RenameFont(const nsAString& aName, const PRUint8 *aFontData, 
                PRUint32 aFontDataLength, nsTArray<PRUint8> *aNewFont);
     
     // read all names matching aNameID, returning in aNames array
diff --git a/gfx/thebes/public/gfxPangoFonts.h b/gfx/thebes/public/gfxPangoFonts.h
--- a/gfx/thebes/public/gfxPangoFonts.h
+++ b/gfx/thebes/public/gfxPangoFonts.h
@@ -83,17 +83,16 @@ public:
 
     static void Shutdown();
 
     // Used for @font-face { src: local(); }
     static gfxFontEntry *NewFontEntry(const gfxProxyFontEntry &aProxyEntry,
                                       const nsAString &aFullname);
     // Used for @font-face { src: url(); }
     static gfxFontEntry *NewFontEntry(const gfxProxyFontEntry &aProxyEntry,
-                                      nsISupports *aLoader,
                                       const PRUint8 *aFontData,
                                       PRUint32 aLength);
 
     // Interfaces used internally
     // (but public so that they can be accessed from non-member functions):
 
     // The FontGroup holds the reference to the PangoFont (through the FontSet).
     PangoFont *GetBasePangoFont();
diff --git a/gfx/thebes/public/gfxPlatform.h b/gfx/thebes/public/gfxPlatform.h
--- a/gfx/thebes/public/gfxPlatform.h
+++ b/gfx/thebes/public/gfxPlatform.h
@@ -206,25 +206,25 @@ public:
      * who must either AddRef() or delete.
      */
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName)
     { return nsnull; }
 
     /**
      * Activate a platform font.  (Needed to support @font-face src url().)
-     * aFontData must persist as long as a reference is held to aLoader.
+     * aFontData is a NS_Malloc'ed block that must be freed by this function
+     * (or responsibility passed on) when it is no longer needed; the caller
+     * will NOT free it.
      * Ownership of the returned gfxFontEntry is passed to the caller,
      * who must either AddRef() or delete.
      */
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
-                                           nsISupports *aLoader,
                                            const PRUint8 *aFontData,
-                                           PRUint32 aLength)
-    { return nsnull; }
+                                           PRUint32 aLength);
 
     /**
      * 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; }
diff --git a/gfx/thebes/public/gfxPlatformGtk.h b/gfx/thebes/public/gfxPlatformGtk.h
--- a/gfx/thebes/public/gfxPlatformGtk.h
+++ b/gfx/thebes/public/gfxPlatformGtk.h
@@ -97,17 +97,16 @@ public:
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     /**
      * Activate a platform font (needed to support @font-face src url() )
      *
      */
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
-                                           nsISupports *aLoader,
                                            const PRUint8 *aFontData,
                                            PRUint32 aLength);
 
     /**
      * Check whether format is supported on a platform or not (if unclear,
      * returns true).
      */
     virtual PRBool IsFontFormatSupported(nsIURI *aFontURI,
diff --git a/gfx/thebes/public/gfxPlatformMac.h b/gfx/thebes/public/gfxPlatformMac.h
--- a/gfx/thebes/public/gfxPlatformMac.h
+++ b/gfx/thebes/public/gfxPlatformMac.h
@@ -73,17 +73,16 @@ public:
                                   gfxUserFontSet *aUserFontSet);
 
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     virtual gfxPlatformFontList* CreatePlatformFontList();
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
-                                           nsISupports *aLoader,
                                            const PRUint8 *aFontData,
                                            PRUint32 aLength);
 
     PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
 
     nsresult GetFontList(const nsACString& aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts);
diff --git a/gfx/thebes/public/gfxUserFontSet.h b/gfx/thebes/public/gfxUserFontSet.h
--- a/gfx/thebes/public/gfxUserFontSet.h
+++ b/gfx/thebes/public/gfxUserFontSet.h
@@ -147,19 +147,20 @@ public:
         // no flags ==> no hint set
         // unknown ==> unknown format hint set
         FLAG_FORMAT_UNKNOWN        = 1,
         FLAG_FORMAT_OPENTYPE       = 1 << 1,
         FLAG_FORMAT_TRUETYPE       = 1 << 2,
         FLAG_FORMAT_TRUETYPE_AAT   = 1 << 3,
         FLAG_FORMAT_EOT            = 1 << 4,
         FLAG_FORMAT_SVG            = 1 << 5,
-        
+        FLAG_FORMAT_WOFF           = 1 << 6,
+
         // mask of all unused bits, update when adding new formats
-        FLAG_FORMAT_NOT_USED       = ~((1 << 6)-1)
+        FLAG_FORMAT_NOT_USED       = ~((1 << 7)-1)
     };
 
     enum LoadStatus {
         STATUS_LOADING = 0,
         STATUS_LOADED,
         STATUS_FORMAT_NOT_SUPPORTED,
         STATUS_ERROR,
         STATUS_END_OF_LIST
@@ -192,17 +193,19 @@ public:
     // completion will call OnLoadComplete method
     virtual nsresult StartLoad(gfxFontEntry *aFontToLoad, 
                                const gfxFontFaceSrc *aFontFaceSrc) = 0;
 
     // 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, nsISupports *aLoader,
+    // Ownership of aFontData is passed in here; the font set must
+    // ensure that it is eventually deleted with NS_Free().
+    PRBool OnLoadComplete(gfxFontEntry *aFontToLoad,
                           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:
diff --git a/gfx/thebes/public/gfxWindowsFonts.h b/gfx/thebes/public/gfxWindowsFonts.h
--- a/gfx/thebes/public/gfxWindowsFonts.h
+++ b/gfx/thebes/public/gfxWindowsFonts.h
@@ -135,17 +135,16 @@ public:
         mUnicodeRanges(aFontEntry.mUnicodeRanges)
     {
 
     }
     static void InitializeFontEmbeddingProcs();
 
     // create a font entry from downloaded font data
     static FontEntry* LoadFont(const gfxProxyFontEntry &aProxyEntry,
-                               nsISupports *aLoader,
                                const PRUint8 *aFontData,
                                PRUint32 aLength);
 
     // create a font entry for a font with a given name
     static FontEntry* CreateFontEntry(const nsAString& aName, 
                                       gfxWindowsFontType aFontType, 
                                       PRBool aItalic, PRUint16 aWeight, 
                                       gfxUserFontData* aUserFontData, 
diff --git a/gfx/thebes/public/gfxWindowsPlatform.h b/gfx/thebes/public/gfxWindowsPlatform.h
--- a/gfx/thebes/public/gfxWindowsPlatform.h
+++ b/gfx/thebes/public/gfxWindowsPlatform.h
@@ -121,17 +121,16 @@ public:
      */
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName);
 
     /**
      * Activate a platform font (needed to support @font-face src url() )
      */
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
-                                           nsISupports *aLoader,
                                            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);
 
diff --git a/gfx/thebes/src/Makefile.in b/gfx/thebes/src/Makefile.in
--- a/gfx/thebes/src/Makefile.in
+++ b/gfx/thebes/src/Makefile.in
@@ -163,19 +163,21 @@ CPPSRCS += gfxCoreTextFonts.cpp
 endif
 
 CMMSRCS = gfxMacPlatformFontList.mm
 
 # Always link with OpenGL/AGL
 EXTRA_DSO_LDOPTS += -framework OpenGL -framework AGL -framework QuickTime
 endif
 
+CSRCS += woff.c
+
 EXTRA_DSO_LDOPTS += $(TK_LIBS)
 
-DEFINES += -DIMPL_THEBES
+DEFINES += -DIMPL_THEBES -DWOFF_MOZILLA_CLIENT
 
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS)
 CFLAGS += $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 ifdef WINCE
diff --git a/gfx/thebes/src/gfxFT2Fonts.cpp b/gfx/thebes/src/gfxFT2Fonts.cpp
--- a/gfx/thebes/src/gfxFT2Fonts.cpp
+++ b/gfx/thebes/src/gfxFT2Fonts.cpp
@@ -112,43 +112,66 @@ FontEntry::~FontEntry()
         cairo_font_face_destroy(mFontFace);
         mFontFace = nsnull;
     }
 }
 
 /* static */
 FontEntry*
 FontEntry::CreateFontEntry(const gfxProxyFontEntry &aProxyEntry,
-                           nsISupports *aLoader, const PRUint8 *aFontData,
-                           PRUint32 aLength) {
-    if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength))
-        return nsnull;
+                           const PRUint8 *aFontData,
+                           PRUint32 aLength)
+{
+    // Ownership of aFontData is passed in here; the fontEntry must
+    // retain it as long as the FT_Face needs it, and ensure it is
+    // eventually deleted.
     FT_Face face;
     FT_Error error =
         FT_New_Memory_Face(gfxToolkitPlatform::GetPlatform()->GetFTLibrary(),
                            aFontData, aLength, 0, &face);
-    if (error != FT_Err_Ok)
+    if (error != FT_Err_Ok) {
+        NS_Free((void*)aFontData);
         return nsnull;
-    FontEntry* fe = FontEntry::CreateFontEntryFromFace(face);
+    }
+    FontEntry* fe = FontEntry::CreateFontEntryFromFace(face, aFontData);
     fe->mItalic = aProxyEntry.mItalic;
     fe->mWeight = aProxyEntry.mWeight;
     fe->mStretch = aProxyEntry.mStretch;
     return fe;
+}
 
-}
+class FTUserFontData {
+public:
+    FTUserFontData(FT_Face aFace, const PRUint8* aData)
+        : mFace(aFace), mFontData(aData)
+    {
+    }
+
+    ~FTUserFontData()
+    {
+        FT_Done_Face(mFace);
+        if (mFontData) {
+            NS_Free((void*)mFontData);
+        }
+    }
+
+private:
+    FT_Face        mFace;
+    const PRUint8 *mFontData;
+};
 
 static void
 FTFontDestroyFunc(void *data)
 {
-    FT_Face face = (FT_Face)data;
-    FT_Done_Face(face);
+    FTUserFontData *userFontData = static_cast<FTUserFontData*>(data);
+    delete userFontData;
 }
 
 /* static */ FontEntry*
-FontEntry::CreateFontEntryFromFace(FT_Face aFace) {
+FontEntry::CreateFontEntryFromFace(FT_Face aFace, const PRUint8 *aFontData) {
     static cairo_user_data_key_t key;
 
     if (!aFace->family_name) {
         FT_Done_Face(aFace);
         return nsnull;
     }
     // Construct font name from family name and style name, regular fonts
     // do not have the modifier by convention.
@@ -156,20 +179,22 @@ FontEntry::CreateFontEntryFromFace(FT_Fa
     if (aFace->style_name && strcmp("Regular", aFace->style_name)) {
         fontName.AppendLiteral(" ");
         AppendUTF8toUTF16(aFace->style_name, fontName);
     }
     FontEntry *fe = new FontEntry(fontName);
     fe->mItalic = aFace->style_flags & FT_STYLE_FLAG_ITALIC;
     fe->mFTFace = aFace;
     fe->mFontFace = cairo_ft_font_face_create_for_ft_face(aFace, 0);
+
+    FTUserFontData *userFontData = new FTUserFontData(aFace, aFontData);
     cairo_font_face_set_user_data(fe->mFontFace, &key,
-                                  aFace, FTFontDestroyFunc);
+                                  userFontData, FTFontDestroyFunc);
+
     TT_OS2 *os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(aFace, ft_sfnt_os2));
-
     PRUint16 os2weight = 0;
     if (os2 && os2->version != 0xffff) {
         // Technically, only 100 to 900 are valid, but some fonts
         // have this set wrong -- e.g. "Microsoft Logo Bold Italic" has
         // it set to 6 instead of 600.  We try to be nice and handle that
         // as well.
         if (os2->usWeightClass >= 100 && os2->usWeightClass <= 900)
             os2weight = os2->usWeightClass;
@@ -200,17 +225,19 @@ FontEntry::CairoFontFace()
 {
     static cairo_user_data_key_t key;
 
     if (!mFontFace) {
         FT_Face face;
         FT_New_Face(gfxToolkitPlatform::GetPlatform()->GetFTLibrary(), mFilename.get(), mFTFontIndex, &face);
         mFTFace = face;
         mFontFace = cairo_ft_font_face_create_for_ft_face(face, 0);
-        cairo_font_face_set_user_data(mFontFace, &key, face, FTFontDestroyFunc);
+        FTUserFontData *userFontData = new FTUserFontData(face, nsnull);
+        cairo_font_face_set_user_data(mFontFace, &key,
+                                      userFontData, FTFontDestroyFunc);
     }
     return mFontFace;
 }
 
 nsresult
 FontEntry::ReadCMAP()
 {
     if (mCmapInitialized) return NS_OK;
diff --git a/gfx/thebes/src/gfxFontUtils.cpp b/gfx/thebes/src/gfxFontUtils.cpp
--- a/gfx/thebes/src/gfxFontUtils.cpp
+++ b/gfx/thebes/src/gfxFontUtils.cpp
@@ -47,16 +47,18 @@
 #include "nsISupportsPrimitives.h"
 #include "nsIStreamBufferAccess.h"
 #include "nsIUUIDGenerator.h"
 #include "nsMemory.h"
 #include "nsICharsetConverterManager.h"
 
 #include "plbase64.h"
 
+#include "woff.h"
+
 #ifdef XP_MACOSX
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
 #define NO_RANGE_FOUND 126 // bit 126 in the font unicode ranges is required to be 0
 
 /* Unicode subrange table
  *   from: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_63ub.asp
@@ -689,41 +691,64 @@ ValidateKernTable(const PRUint8 *aKernTa
         // for now, assume this is OK
         return PR_TRUE;
     }
 
     // neither the old Windows version nor the newer Apple one; refuse to use it
     return PR_FALSE;
 }
 
+gfxUserFontType
+gfxFontUtils::DetermineFontDataType(const PRUint8 *aFontData, PRUint32 aFontDataLength)
+{
+    // test for OpenType font data
+    // problem: EOT-Lite with 0x10000 length will look like TrueType!
+    if (aFontDataLength >= sizeof(SFNTHeader)) {
+        const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
+        PRUint32 sfntVersion = sfntHeader->sfntVersion;
+        if (IsValidSFNTVersion(sfntVersion)) {
+            return GFX_USERFONT_OPENTYPE;
+        }
+    }
+    
+    // test for WOFF
+    if (aFontDataLength >= sizeof(AutoSwap_PRUint32)) {
+        const AutoSwap_PRUint32 *version = 
+            reinterpret_cast<const AutoSwap_PRUint32*>(aFontData);
+        if (PRUint32(*version) == TRUETYPE_TAG('w','O','F','F')) {
+            return GFX_USERFONT_WOFF;
+        }
+    }
+    
+    // tests for other formats here
+    
+    return GFX_USERFONT_UNKNOWN;
+}
+
 PRBool
 gfxFontUtils::ValidateSFNTHeaders(const PRUint8 *aFontData, 
-                                  PRUint32 aFontDataLength, 
-                                  PRBool *aIsCFF)
+                                  PRUint32 aFontDataLength)
 {
-    NS_ASSERTION(aFontData && aFontDataLength != 0, "null font data");
+    NS_ASSERTION(aFontData, "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;
     }
     
-    if (aIsCFF)
-        *aIsCFF = (sfntVersion == TRUETYPE_TAG('O','T','T','O'));
-
     // 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, foundKern = PR_FALSE;
     PRUint32 headOffset, headLen, nameOffset, nameLen, kernOffset, kernLen;
     PRUint32 i, numTables;
 
     numTables = sfntHeader->numTables;
     PRUint32 headerLen = sizeof(SFNTHeader) + sizeof(TableDirEntry) * numTables;
@@ -1728,9 +1753,19 @@ gfxFontUtils::MakeEOTHeader(const PRUint
 
     eotHeader->eotSize = aHeader->Length() + fontDataSize;
 
     // DumpEOTHeader(aHeader->Elements(), aHeader->Length());
 
     return NS_OK;
 }
 
+/* static */
+PRBool
+gfxFontUtils::IsCffFont(const PRUint8* aFontData)
+{
+    // this is only called after aFontData has passed basic validation,
+    // so we know there is enough data present to allow us to read the version!
+    const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
+    return (sfntHeader->sfntVersion == TRUETYPE_TAG('O','T','T','O'));
+}
+
 #endif
diff --git a/gfx/thebes/src/gfxMacPlatformFontList.mm b/gfx/thebes/src/gfxMacPlatformFontList.mm
--- a/gfx/thebes/src/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/src/gfxMacPlatformFontList.mm
@@ -685,47 +685,33 @@ public:
         if (mContainerRef)
             ::ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault);
     }
 
     ATSFontContainerRef     mContainerRef;
 };
 
 gfxFontEntry* 
-gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry, 
-                                     const PRUint8 *aFontData, PRUint32 aLength)
+gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
+                                         const PRUint8 *aFontData,
+                                         PRUint32 aLength)
 {
     OSStatus err;
     
-    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;
-    }
+    NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
 
     ATSFontRef fontRef;
     ATSFontContainerRef containerRef;
 
     // we get occasional failures when multiple fonts are activated in quick succession
     // if the ATS font cache is damaged; to work around this, we can retry the activation
     const PRUint32 kMaxRetries = 3;
     PRUint32 retryCount = 0;
     while (retryCount++ < kMaxRetries) {
-        err = ::ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength, 
+        err = ::ATSFontActivateFromMemory(const_cast<PRUint8*>(aFontData), aLength,
                                           kPrivateATSFontContextPrivate,
                                           kATSFontFormatUnspecified,
                                           NULL, 
                                           kATSOptionFlagsDoNotNotify, 
                                           &containerRef);
         mATSGeneration = ::ATSGetGeneration();
 
         if (err != noErr) {
diff --git a/gfx/thebes/src/gfxPangoFonts.cpp b/gfx/thebes/src/gfxPangoFonts.cpp
--- a/gfx/thebes/src/gfxPangoFonts.cpp
+++ b/gfx/thebes/src/gfxPangoFonts.cpp
@@ -295,38 +295,42 @@ public:
 /**
  * gfxDownloadedFcFontEntry:
  *
  * An implementation of gfxFcFontEntry for web fonts from src:url().
  */
 
 class gfxDownloadedFcFontEntry : public gfxFcFontEntry {
 public:
-    // This takes ownership of the face.
+    // This takes ownership of the face and its underlying data
     gfxDownloadedFcFontEntry(const gfxProxyFontEntry &aProxyEntry,
-                             nsISupports *aLoader, FT_Face aFace)
-        : gfxFcFontEntry(aProxyEntry), mLoader(aLoader), mFace(aFace)
+                             const PRUint8 *aData, FT_Face aFace)
+        : gfxFcFontEntry(aProxyEntry), mFontData(aData), mFace(aFace)
     {
         NS_PRECONDITION(aFace != NULL, "aFace is NULL!");
         InitPattern();
     }
 
     virtual ~gfxDownloadedFcFontEntry();
 
     // Returns a PangoCoverage owned by the FontEntry.  The caller must add a
     // reference if it wishes to keep the PangoCoverage longer than the
     // lifetime of the FontEntry.
     PangoCoverage *GetPangoCoverage();
 
 protected:
     virtual void InitPattern();
 
-    // mLoader holds a reference to memory used by mFace.
-    nsCOMPtr<nsISupports> mLoader;
+    // mFontData holds the data used to instantiate the FT_Face;
+    // this has to persist until we are finished with the face,
+    // then be released with NS_Free().
+    const PRUint8* mFontData;
+
     FT_Face mFace;
+
     // mPangoCoverage is the charset property of the pattern translated to a
     // format that Pango understands.  A reference is kept here so that it can
     // be shared by multiple PangoFonts (of different sizes).
     nsAutoRef<PangoCoverage> mPangoCoverage;
 };
 
 // A property for recording gfxDownloadedFcFontEntrys on FcPatterns.
 static const char *kFontEntryFcProp = "-moz-font-entry";
@@ -366,16 +370,17 @@ gfxDownloadedFcFontEntry::~gfxDownloaded
         // Remove back reference to this font entry and the face in case
         // anyone holds a reference to the pattern.
         NS_ASSERTION(mPatterns.Length() == 1,
                      "More than one pattern in gfxDownloadedFcFontEntry!");
         DelDownloadedFontEntry(mPatterns[0]);
         FcPatternDel(mPatterns[0], FC_FT_FACE);
     }
     FT_Done_Face(mFace);
+    NS_Free((void*)mFontData);
 }
 
 typedef FcPattern* (*QueryFaceFunction)(const FT_Face face,
                                         const FcChar8 *file, int id,
                                         FcBlanks *blanks);
 
 void
 gfxDownloadedFcFontEntry::InitPattern()
@@ -2213,28 +2218,32 @@ GetFTLibrary()
         gFTLibrary = face.get()->glyph->library;
     }
 
     return gFTLibrary;
 }
 
 /* static */ gfxFontEntry *
 gfxPangoFontGroup::NewFontEntry(const gfxProxyFontEntry &aProxyEntry,
-                                nsISupports *aLoader,
                                 const PRUint8 *aFontData, PRUint32 aLength)
 {
+    // Ownership of aFontData is passed in here, and transferred to the
+    // new fontEntry, which will release it when no longer needed.
+
     // Using face_index = 0 for the first face in the font, as we have no
     // other information.  FT_New_Memory_Face checks for a NULL FT_Library.
     FT_Face face;
     FT_Error error =
         FT_New_Memory_Face(GetFTLibrary(), aFontData, aLength, 0, &face);
-    if (error != 0)
+    if (error != 0) {
+        NS_Free((void*)aFontData);
         return nsnull;
+    }
 
-    return new gfxDownloadedFcFontEntry(aProxyEntry, aLoader, face);
+    return new gfxDownloadedFcFontEntry(aProxyEntry, aFontData, face);
 }
 
 
 static double
 GetPixelSize(FcPattern *aPattern)
 {
     double size;
     if (FcPatternGetDouble(aPattern,
diff --git a/gfx/thebes/src/gfxPlatform.cpp b/gfx/thebes/src/gfxPlatform.cpp
--- a/gfx/thebes/src/gfxPlatform.cpp
+++ b/gfx/thebes/src/gfxPlatform.cpp
@@ -324,16 +324,31 @@ gfxPlatform::DownloadableFontsEnabled()
             if (NS_SUCCEEDED(rv))
                 allowDownloadableFonts = allow;
         }
     }
 
     return allowDownloadableFonts;
 }
 
+gfxFontEntry*
+gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
+                              const PRUint8 *aFontData,
+                              PRUint32 aLength)
+{
+    // Default implementation does not handle activating downloaded fonts;
+    // just free the data and return.
+    // Platforms that support @font-face must override this,
+    // using the data to instantiate the font, and taking responsibility
+    // for freeing it when no longer required.
+    if (aFontData) {
+        NS_Free((void*)aFontData);
+    }
+    return nsnull;
+}
 
 static void
 AppendGenericFontFromPref(nsString& aFonts, const char *aLangGroup, const char *aGenericName)
 {
     nsresult rv;
 
     nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
     if (!prefs)
diff --git a/gfx/thebes/src/gfxPlatformFontList.h b/gfx/thebes/src/gfxPlatformFontList.h
--- a/gfx/thebes/src/gfxPlatformFontList.h
+++ b/gfx/thebes/src/gfxPlatformFontList.h
@@ -103,16 +103,17 @@ public:
     virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle,
                                          PRBool& aNeedsBold) = 0;
 
     // look up a font by name on the host platform
     virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                           const nsAString& aFontName) = 0;
 
     // create a new platform font from downloaded data (@font-face)
+    // this method is responsible to ensure aFontData is NS_Free()'d
     virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry,
                                            const PRUint8 *aFontData,
                                            PRUint32 aLength) = 0;
 
     // get the standard family name on the platform for a given font name
     virtual PRBool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) = 0;
 
 protected:
diff --git a/gfx/thebes/src/gfxPlatformGtk.cpp b/gfx/thebes/src/gfxPlatformGtk.cpp
--- a/gfx/thebes/src/gfxPlatformGtk.cpp
+++ b/gfx/thebes/src/gfxPlatformGtk.cpp
@@ -307,40 +307,36 @@ gfxFontEntry*
 gfxPlatformGtk::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                 const nsAString& aFontName)
 {
     return gfxPangoFontGroup::NewFontEntry(*aProxyEntry, aFontName);
 }
 
 gfxFontEntry* 
 gfxPlatformGtk::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, 
-                                 nsISupports *aLoader,
                                  const PRUint8 *aFontData, PRUint32 aLength)
 {
-    // Just being consistent with other platforms.
-    // This will mean that only fonts in SFNT formats will be accepted.
-    if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength))
-        return nsnull;
-
-    return gfxPangoFontGroup::NewFontEntry(*aProxyEntry, aLoader,
+    // passing ownership of the font data to the new font entry
+    return gfxPangoFontGroup::NewFontEntry(*aProxyEntry,
                                            aFontData, aLength);
 }
 
 PRBool
 gfxPlatformGtk::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
 {
     // check for strange format flags
     NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
                  "strange font format hint set");
 
     // accept supported formats
     // Pango doesn't apply features from AAT TrueType extensions.
     // Assume that if this is the only SFNT format specified,
     // then AAT extensions are required for complex script support.
-    if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 
+    if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF     |
+                        gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 
                         gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
         return PR_TRUE;
     }
 
     // reject all other formats, known and unknown
     if (aFormatFlags != 0) {
         return PR_FALSE;
     }
diff --git a/gfx/thebes/src/gfxPlatformMac.cpp b/gfx/thebes/src/gfxPlatformMac.cpp
--- a/gfx/thebes/src/gfxPlatformMac.cpp
+++ b/gfx/thebes/src/gfxPlatformMac.cpp
@@ -182,31 +182,38 @@ gfxPlatformMac::LookupLocalFont(const gf
                                 const nsAString& aFontName)
 {
     return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, 
                                                                     aFontName);
 }
 
 gfxFontEntry* 
 gfxPlatformMac::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
-                                 nsISupports *aLoader,
                                  const PRUint8 *aFontData, PRUint32 aLength)
 {
-    return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry, aFontData, aLength);
+    // Ownership of aFontData is passed in here.
+    // After activating the font via ATS, we can discard the data.
+    gfxFontEntry *fe =
+        gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
+                                                                  aFontData,
+                                                                  aLength);
+    NS_Free((void*)aFontData);
+    return fe;
 }
 
 PRBool
 gfxPlatformMac::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
 {
     // check for strange format flags
     NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
                  "strange font format hint set");
 
     // accept supported formats
-    if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 
+    if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF     |
+                        gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 
                         gfxUserFontSet::FLAG_FORMAT_TRUETYPE | 
                         gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT)) {
         return PR_TRUE;
     }
 
     // reject all other formats, known and unknown
     if (aFormatFlags != 0) {
         return PR_FALSE;
diff --git a/gfx/thebes/src/gfxUserFontSet.cpp b/gfx/thebes/src/gfxUserFontSet.cpp
--- a/gfx/thebes/src/gfxUserFontSet.cpp
+++ b/gfx/thebes/src/gfxUserFontSet.cpp
@@ -10,21 +10,22 @@
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is thebes gfx code.
  *
  * The Initial Developer of the Original Code is Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2008
+ * Portions created by the Initial Developer are Copyright (C) 2008-2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   John Daggett <jdaggett@mozilla.com>
+ *   Jonathan Kew <jfkthame@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -41,16 +42,18 @@
 #include "prlog.h"
 
 #include "gfxUserFontSet.h"
 #include "gfxPlatform.h"
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "prlong.h"
 
+#include "woff.h"
+
 #ifdef PR_LOGGING
 static PRLogModuleInfo *gUserFontsLog = PR_NewLogModule("userfonts");
 #endif /* PR_LOGGING */
 
 #define LOG(args) PR_LOG(gUserFontsLog, PR_LOG_DEBUG, args)
 #define LOG_ENABLED() PR_LOG_TEST(gUserFontsLog, PR_LOG_DEBUG)
 
 static PRUint64 sFontSetGeneration = LL_INIT(0, 0);
@@ -82,17 +85,16 @@ gfxProxyFontEntry::~gfxProxyFontEntry()
 gfxUserFontSet::gfxUserFontSet()
 {
     mFontFamilies.Init(5);
     IncrementGeneration();
 }
 
 gfxUserFontSet::~gfxUserFontSet()
 {
-
 }
 
 void
 gfxUserFontSet::AddFontFace(const nsAString& aFamilyName, 
                             const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, 
                             PRUint32 aWeight, 
                             PRUint32 aStretch, 
                             PRUint32 aItalicStyle, 
@@ -164,70 +166,146 @@ gfxUserFontSet::FindFontEntry(const nsAS
     // search again
     if (status == STATUS_LOADED)
         return family->FindFontForStyle(aFontStyle, aNeedsBold);
 
     // if either loading or an error occurred, return null
     return nsnull;
 }
 
+// Given a buffer of downloaded font data, do any necessary preparation
+// to make it into usable OpenType.
+// May return the original pointer unchanged, or a newly-allocated
+// block (in which case the passed-in block is NS_Free'd).
+// aLength is updated if necessary to the new length of the data.
+// Returns NULL and NS_Free's the incoming data in case of errors.
+const PRUint8*
+PrepareOpenTypeData(const PRUint8* aData, PRUint32* aLength)
+{
+    switch(gfxFontUtils::DetermineFontDataType(aData, *aLength)) {
+    
+    case GFX_USERFONT_OPENTYPE:
+        // nothing to do
+        return aData;
+        
+    case GFX_USERFONT_WOFF: {
+        PRUint32 status = eWOFF_ok;
+        PRUint32 bufferSize = woffGetDecodedSize(aData, *aLength, &status);
+        if (WOFF_FAILURE(status)) {
+            break;
+        }
+        PRUint8* decodedData = static_cast<PRUint8*>(NS_Alloc(bufferSize));
+        if (!decodedData) {
+            break;
+        }
+        woffDecodeToBuffer(aData, *aLength,
+                           decodedData, bufferSize,
+                           aLength, &status);
+        // replace original data with the decoded version
+        NS_Free((void*)aData);
+        aData = decodedData;
+        if (WOFF_FAILURE(status)) {
+            // something went wrong, discard the data and return NULL
+            break;
+        }
+        // success, return the decoded data
+        return aData;
+    }
 
+    // xxx - add support for other wrappers here
+
+    default:
+        NS_WARNING("unknown font format");
+        break;
+    }
+
+    // discard downloaded data that couldn't be used
+    NS_Free((void*)aData);
+
+    return nsnull;
+}
+
+// This is called when a font download finishes.
+// Ownership of aFontData passes in here, and the font set must
+// ensure that it is eventually deleted via NS_Free().
 PRBool 
 gfxUserFontSet::OnLoadComplete(gfxFontEntry *aFontToLoad,
-                               nsISupports *aLoader,
                                const PRUint8 *aFontData, PRUint32 aLength, 
                                nsresult aDownloadStatus)
 {
     NS_ASSERTION(aFontToLoad->mIsProxy, "trying to load font data for wrong font entry type");
 
-    if (!aFontToLoad->mIsProxy)
+    if (!aFontToLoad->mIsProxy) {
+        NS_Free((void*)aFontData);
         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, aLoader,
-                                                         aFontData, aLength);
+        gfxFontEntry *fe = nsnull;
+
+        // Unwrap/decompress or otherwise munge the downloaded data
+        // to make a usable sfnt structure.
+        // This may cause aFontData to point to a new buffer, or be NULL.
+        aFontData = PrepareOpenTypeData(aFontData, &aLength);
+        if (aFontData &&
+            gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength)) {
+            // Here ownership of aFontData is passed to the platform,
+            // which will delete it when no longer required
+            fe = gfxPlatform::GetPlatform()->MakePlatformFont(pe,
+                                                              aFontData,
+                                                              aLength);
+            aFontData = nsnull; // the platform may have freed the data now!
+        } else {
+            // the data was unusable, so just discard it
+            // (error will be reported below, if logging is enabled)
+            if (aFontData) {
+                NS_Free((void*)aFontData);
+            }
+        }
+
         if (fe) {
             static_cast<gfxMixedFontFamily*>(pe->mFamily)->ReplaceFontEntry(pe, fe);
             IncrementGeneration();
 #ifdef PR_LOGGING
             if (LOG_ENABLED()) {
                 nsCAutoString fontURI;
                 pe->mSrcList[pe->mSrcIndex].mURI->GetSpec(fontURI);
-
-                LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n", 
-                     this, pe->mSrcIndex, fontURI.get(), 
-                     NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get(), 
+                LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
+                     this, pe->mSrcIndex, fontURI.get(),
+                     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);
-                LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) error making platform font\n", 
-                     this, pe->mSrcIndex, fontURI.get(), 
+                LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) error making platform font\n",
+                     this, pe->mSrcIndex, fontURI.get(),
                      NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get()));
             }
 #endif
         }
     } else {
         // download failed
+        if (aFontData) {
+            NS_Free((void*)aFontData);
+        }
 #ifdef PR_LOGGING
         if (LOG_ENABLED()) {
             nsCAutoString fontURI;
             pe->mSrcList[pe->mSrcIndex].mURI->GetSpec(fontURI);
-            LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) error %8.8x downloading font data\n", 
-                 this, pe->mSrcIndex, fontURI.get(), 
-                 NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get(), 
+            LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s) error %8.8x downloading font data\n",
+                 this, pe->mSrcIndex, fontURI.get(),
+                 NS_ConvertUTF16toUTF8(pe->mFamily->Name()).get(),
                  aDownloadStatus));
         }
 #endif
     }
 
     // error occurred, load next src
     LoadStatus status;
 
diff --git a/gfx/thebes/src/gfxWindowsFonts.cpp b/gfx/thebes/src/gfxWindowsFonts.cpp
--- a/gfx/thebes/src/gfxWindowsFonts.cpp
+++ b/gfx/thebes/src/gfxWindowsFonts.cpp
@@ -510,25 +510,24 @@ public:
         return eotReader->Read(outBuffer, aBytesToRead);
     }        
         
 };
 
 /* static */
 FontEntry* 
 FontEntry::LoadFont(const gfxProxyFontEntry &aProxyEntry, 
-                    nsISupports *aLoader,const PRUint8 *aFontData, 
-                    PRUint32 aLength) {
+                    const PRUint8 *aFontData, 
+                    PRUint32 aLength)
+{
     // if calls aren't available, bail
     if (!TTLoadEmbeddedFontPtr || !TTDeleteEmbeddedFontPtr)
         return nsnull;
 
-    PRBool isCFF;
-    if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength, &isCFF))
-        return nsnull;
+    PRBool isCFF = gfxFontUtils::IsCffFont(aFontData);
         
     nsresult rv;
     HANDLE fontRef = nsnull;
     PRBool isEmbedded = PR_FALSE;
 
     nsAutoString uniqueName;
     rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
     if (NS_FAILED(rv))
diff --git a/gfx/thebes/src/gfxWindowsPlatform.cpp b/gfx/thebes/src/gfxWindowsPlatform.cpp
--- a/gfx/thebes/src/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/src/gfxWindowsPlatform.cpp
@@ -836,35 +836,41 @@ gfxWindowsPlatform::LookupLocalFont(cons
     return data.mFontEntry;
 #else
     return FontEntry::LoadLocalFont(*aProxyEntry, aFontName);
 #endif
 }
 
 gfxFontEntry* 
 gfxWindowsPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
-                                     nsISupports *aLoader,
                                      const PRUint8 *aFontData, PRUint32 aLength)
 {
 #ifdef MOZ_FT2_FONTS
-    return FontEntry::CreateFontEntry(*aProxyEntry, aLoader, aFontData, aLength);
+    // The FT2 font needs the font data to persist, so we do NOT free it here
+    // but instead pass ownership to the font entry.
+    // Deallocation will happen later, when the font face is destroyed.
+    return FontEntry::CreateFontEntry(*aProxyEntry, aFontData, aLength);
 #else
-    return FontEntry::LoadFont(*aProxyEntry, aLoader, aFontData, aLength);
+    // With GDI, we can free the downloaded data after activating the font
+    gfxFontEntry *fe = FontEntry::LoadFont(*aProxyEntry, aFontData, aLength);
+    NS_Free((void*)aFontData);
+    return fe;
 #endif    
 }
 
 PRBool
 gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
 {
     // check for strange format flags
     NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
                  "strange font format hint set");
 
     // accept supported formats
-    if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 
+    if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF     |
+                        gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 
                         gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
         return PR_TRUE;
     }
 
     // reject all other formats, known and unknown
     if (aFormatFlags != 0) {
         return PR_FALSE;
     }
diff --git a/gfx/thebes/src/woff-private.h b/gfx/thebes/src/woff-private.h
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/woff-private.h
@@ -0,0 +1,160 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is WOFF font packaging code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef WOFF_PRIVATE_H_
+#define WOFF_PRIVATE_H_
+
+#include "woff.h"
+
+/* private definitions used in the WOFF encoder/decoder functions */
+
+/* create an OT tag from 4 characters */
+#define TAG(a,b,c,d) ((a)<<24 | (b)<<16 | (c)<<8 | (d))
+
+#define WOFF_SIGNATURE    TAG('w','O','F','F')
+
+#define SFNT_VERSION_CFF  TAG('O','T','T','O')
+#define SFNT_VERSION_TT   0x00010000
+#define SFNT_VERSION_true TAG('t','r','u','e')
+
+#define TABLE_TAG_DSIG    TAG('D','S','I','G')
+#define TABLE_TAG_head    TAG('h','e','a','d')
+#define TABLE_TAG_bhed    TAG('b','h','e','d')
+
+#define SFNT_CHECKSUM_CALC_CONST  0xB1B0AFBAU /* from the TT/OT spec */
+
+#ifdef WOFF_MOZILLA_CLIENT
+/* Copies of the NS_SWAP16 and NS_SWAP32 macros; they are defined in
+   a C++ header in mozilla, so we cannot include that here */
+# include "prtypes.h" /* defines IS_LITTLE_ENDIAN / IS_BIG_ENDIAN */
+# if defined IS_LITTLE_ENDIAN
+#  define READ16BE(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
+#  define READ32BE(x) ((READ16BE((x) & 0xffff) << 16) | (READ16BE((x) >> 16)))
+# elif defined IS_BIG_ENDIAN
+#  define READ16BE(x) (x)
+#  define READ32BE(x) (x)
+# else
+#  error "Unknown byte order"
+# endif
+#else
+/* These macros to read values as big-endian only work on "real" variables,
+   not general expressions, because of the use of &(x), but they are
+   designed to work on both BE and LE machines without the need for a
+   configure check. For production code, we might want to replace this
+   with something more efficient. */
+/* read a 32-bit BigEndian value */
+# define READ32BE(x) ( ( (uint32_t) ((uint8_t*)&(x))[0] << 24 ) + \
+                       ( (uint32_t) ((uint8_t*)&(x))[1] << 16 ) + \
+                       ( (uint32_t) ((uint8_t*)&(x))[2] <<  8 ) + \
+                         (uint32_t) ((uint8_t*)&(x))[3]           )
+/* read a 16-bit BigEndian value */
+# define READ16BE(x) ( ( (uint16_t) ((uint8_t*)&(x))[0] << 8 ) + \
+                         (uint16_t) ((uint8_t*)&(x))[1]          )
+#endif
+
+#pragma pack(push,1)
+
+typedef struct {
+  uint32_t version;
+  uint16_t numTables;
+  uint16_t searchRange;
+  uint16_t entrySelector;
+  uint16_t rangeShift;
+} sfntHeader;
+
+typedef struct {
+  uint32_t tag;
+  uint32_t checksum;
+  uint32_t offset;
+  uint32_t length;
+} sfntDirEntry;
+
+typedef struct {
+  uint32_t signature;
+  uint32_t flavor;
+  uint32_t length;
+  uint16_t numTables;
+  uint16_t reserved;
+  uint32_t totalSfntSize;
+  uint16_t majorVersion;
+  uint16_t minorVersion;
+  uint32_t metaOffset;
+  uint32_t metaCompLen;
+  uint32_t metaOrigLen;
+  uint32_t privOffset;
+  uint32_t privLen;
+} woffHeader;
+
+typedef struct {
+  uint32_t tag;
+  uint32_t offset;
+  uint32_t compLen;
+  uint32_t origLen;
+  uint32_t checksum;
+} woffDirEntry;
+
+typedef struct {
+  uint32_t version;
+  uint32_t fontRevision;
+  uint32_t checkSumAdjustment;
+  uint32_t magicNumber;
+  uint16_t flags;
+  uint16_t unitsPerEm;
+  uint32_t created[2];
+  uint32_t modified[2];
+  int16_t xMin;
+  int16_t yMin;
+  int16_t xMax;
+  int16_t yMax;
+  uint16_t macStyle;
+  uint16_t lowestRecPpem;
+  int16_t fontDirectionHint;
+  int16_t indexToLocFormat;
+  int16_t glyphDataFormat;
+} sfntHeadTable;
+
+#define HEAD_TABLE_SIZE 54 /* sizeof(sfntHeadTable) may report 56 because of alignment */
+
+typedef struct {
+  uint32_t offset;
+  uint16_t oldIndex;
+  uint16_t newIndex;
+} tableOrderRec;
+
+#pragma pack(pop)
+
+#endif
diff --git a/gfx/thebes/src/woff.c b/gfx/thebes/src/woff.c
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/woff.c
@@ -0,0 +1,1170 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is WOFF font packaging code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "woff-private.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>
+
+#ifdef WOFF_MOZILLA_CLIENT /* define this when building as part of Gecko */
+# include "prmem.h"
+# define malloc  PR_Malloc
+# define realloc PR_Realloc
+# define free    PR_Free
+#endif
+
+/*
+ * Just simple whole-file encoding and decoding functions; a more extensive
+ * WOFF library could provide support for accessing individual tables from a
+ * compressed font, alternative options for memory allocation/ownership and
+ * error handling, etc.
+ */
+
+/* on errors, each function sets a status variable and jumps to failure: */
+#undef FAIL
+#define FAIL(err) do { status |= err; goto failure; } while (0)
+
+/* adjust an offset for longword alignment */
+#define LONGALIGN(x) (((x) + 3) & ~3)
+
+static int
+compareOffsets(const void * lhs, const void * rhs)
+{
+  const tableOrderRec * a = (const tableOrderRec *) lhs;
+  const tableOrderRec * b = (const tableOrderRec *) rhs;
+  /* don't simply return a->offset - b->offset because these are unsigned
+     offset values; could convert to int, but possible integer overflow */
+  return a->offset > b->offset ? 1 :
+         a->offset < b->offset ? -1 :
+         0;
+}
+
+#ifndef WOFF_MOZILLA_CLIENT
+
+/******************************************************************/
+/* * * * * * * * * * * * * * ENCODING * * * * * * * * * * * * * * */
+/******************************************************************/
+
+static uint32_t
+calcChecksum(const sfntDirEntry * dirEntry,
+             const uint8_t * sfntData, uint32_t sfntLen)
+{
+  /* just returns zero on errors, they will be detected again elsewhere */
+  const uint32_t * csumPtr;
+  const uint32_t * csumEnd;
+  uint32_t csum = 0;
+  uint32_t length = LONGALIGN(READ32BE(dirEntry->length));
+  uint32_t offset = READ32BE(dirEntry->offset);
+  uint32_t tag;
+  if ((offset & 3) != 0) {
+    return csum;
+  }
+  if (length > sfntLen || offset > sfntLen - length) {
+    return csum;
+  }
+  csumPtr = (const uint32_t *) (sfntData + offset);
+  csumEnd = csumPtr + length / 4;
+  while (csumPtr < csumEnd) {
+    csum += READ32BE(*csumPtr);
+    csumPtr++;
+  }
+  tag = READ32BE(dirEntry->tag);
+  if (tag == TABLE_TAG_head || tag == TABLE_TAG_bhed) {
+    const sfntHeadTable * head;
+    if (length < HEAD_TABLE_SIZE) {
+      return 0;
+    }
+    head = (const sfntHeadTable *)(sfntData + offset);
+    csum -= READ32BE(head->checkSumAdjustment);
+  }
+  return csum;
+}
+
+const uint8_t *
+woffEncode(const uint8_t * sfntData, uint32_t sfntLen,
+           uint16_t majorVersion, uint16_t minorVersion,
+           uint32_t * woffLen, uint32_t * pStatus)
+{
+  uint8_t * woffData = NULL;
+  tableOrderRec * tableOrder = NULL;
+
+  uint32_t tableOffset;
+  uint32_t totalSfntSize;
+
+  uint16_t numOrigTables;
+  uint16_t numTables;
+  uint16_t tableIndex;
+  uint16_t order;
+  const sfntDirEntry * sfntDir;
+  uint32_t tableBase;
+  uint32_t checkSumAdjustment = 0;
+  woffHeader * newHeader;
+  uint32_t tag = 0;
+  uint32_t removedDsigSize = 0;
+  uint32_t status = eWOFF_ok;
+
+  const sfntHeader * header = (const sfntHeader *) (sfntData);
+  const sfntHeadTable * head = NULL;
+
+  if (pStatus && WOFF_FAILURE(*pStatus)) {
+    return NULL;
+  }
+
+  if (READ32BE(header->version) != SFNT_VERSION_TT &&
+      READ32BE(header->version) != SFNT_VERSION_CFF &&
+      READ32BE(header->version) != SFNT_VERSION_true) {
+    status |= eWOFF_warn_unknown_version;
+  }
+
+  numOrigTables = READ16BE(header->numTables);
+  sfntDir = (const sfntDirEntry *) (sfntData + sizeof(sfntHeader));
+
+  for (tableIndex = 0; tableIndex < numOrigTables; ++tableIndex) {
+    /* validate table checksums, to figure out if we need to drop DSIG;
+       also check that table directory is correctly sorted */
+    uint32_t prevTag = tag;
+    uint32_t csum = calcChecksum(&sfntDir[tableIndex], sfntData, sfntLen);
+    if (csum != READ32BE(sfntDir[tableIndex].checksum)) {
+      status |= eWOFF_warn_checksum_mismatch;
+    }
+    checkSumAdjustment += csum;
+    tag = READ32BE(sfntDir[tableIndex].tag);
+    if (tag <= prevTag) {
+      FAIL(eWOFF_invalid);
+    }
+    if (tag == TABLE_TAG_head || tag == TABLE_TAG_bhed) {
+      if (READ32BE(sfntDir[tableIndex].length) < HEAD_TABLE_SIZE) {
+        FAIL(eWOFF_invalid);
+      }
+      head = (const sfntHeadTable *)(sfntData +
+                                     READ32BE(sfntDir[tableIndex].offset));
+    }
+  }
+  if (!head) {
+    FAIL(eWOFF_invalid);
+  }
+  if ((status & eWOFF_warn_checksum_mismatch) == 0) {
+    /* no point even checking if we already have an error,
+       as fixing that will change the overall checksum too */
+    const uint32_t * csumPtr = (const uint32_t *) sfntData;
+    const uint32_t * csumEnd = csumPtr + 3 + 4 * numOrigTables;
+    while (csumPtr < csumEnd) {
+      checkSumAdjustment += READ32BE(*csumPtr);
+      ++csumPtr;
+    }
+    checkSumAdjustment = 0xB1B0AFBA - checkSumAdjustment;
+    if (checkSumAdjustment != READ32BE(head->checkSumAdjustment)) {
+      status |= eWOFF_warn_checksum_mismatch;
+    }
+  }
+
+  /* Fixing checkSumAdjustment is tricky, because if there's a DSIG table,
+     we're going to have to remove that, which in turn means that table
+     offsets in the directory will all change.
+     And recalculating checkSumAdjustment requires taking account of any
+     individual table checksum corrections, but they have not actually been
+     applied to the sfnt data at this point.
+     And finally, we'd need to get the corrected checkSumAdjustment into the
+     encoded head table (but we can't modify the original sfnt data).
+     An easier way out seems to be to go ahead and encode the font, knowing
+     that checkSumAdjustment will be wrong; then (if the status flag
+     eWOFF_warn_checksum_mismatch is set) we'll decode the font back to
+     sfnt format. This will fix up the checkSumAdjustment (and return a
+     warning status). We'll ignore that warning, and then re-encode the
+     new, cleaned-up sfnt to get the final WOFF data. Perhaps not the most
+     efficient approach, but it seems simpler than trying to predict the
+     correct final checkSumAdjustment and incorporate it into the head
+     table on the fly. */
+
+  tableOrder = (tableOrderRec *) malloc(numOrigTables * sizeof(tableOrderRec));
+  if (!tableOrder) {
+    FAIL(eWOFF_out_of_memory);
+  }
+  for (tableIndex = 0, numTables = 0;
+       tableIndex < numOrigTables; ++tableIndex) {
+    if ((status & eWOFF_warn_checksum_mismatch) != 0) {
+      /* check for DSIG table that we must drop if we're fixing checksums */
+      tag = READ32BE(sfntDir[tableIndex].tag);
+      if (tag == TABLE_TAG_DSIG) {
+        status |= eWOFF_warn_removed_DSIG;
+        removedDsigSize = READ32BE(sfntDir[tableIndex].length);
+        continue;
+      }
+    }
+    tableOrder[numTables].offset = READ32BE(sfntDir[tableIndex].offset);
+    tableOrder[numTables].oldIndex = tableIndex;
+    tableOrder[numTables].newIndex = numTables;
+    ++numTables;
+  }
+  qsort(tableOrder, numTables, sizeof(tableOrderRec), compareOffsets);
+
+  /* initially, allocate space for header and directory */
+  tableOffset = sizeof(woffHeader) + numTables * sizeof(woffDirEntry);
+  woffData = (uint8_t *) malloc(tableOffset);
+  if (!woffData) {
+    FAIL(eWOFF_out_of_memory);
+  }
+
+  /* accumulator for total expected size of decoded font */
+  totalSfntSize = sizeof(sfntHeader) + numTables * sizeof(sfntDirEntry);
+
+/*
+ * We use a macro for this rather than creating a variable because woffData
+ * will get reallocated during encoding. The macro avoids the risk of using a
+ * stale pointer, and the compiler should optimize multiple successive uses.
+ */
+#define WOFFDIR ((woffDirEntry *) (woffData + sizeof(woffHeader)))
+
+  for (order = 0; order < numTables; ++order) {
+    uLong sourceLen, destLen;
+    uint32_t sourceOffset;
+
+    uint16_t oldIndex = tableOrder[order].oldIndex;
+    uint16_t newIndex = tableOrder[order].newIndex;
+
+    WOFFDIR[newIndex].tag = sfntDir[oldIndex].tag;
+    if ((status & eWOFF_warn_checksum_mismatch) != 0) {
+      uint32_t csum = calcChecksum(&sfntDir[oldIndex], sfntData, sfntLen);
+      WOFFDIR[newIndex].checksum = READ32BE(csum);
+    } else {
+      WOFFDIR[newIndex].checksum = sfntDir[oldIndex].checksum;
+    }
+    WOFFDIR[newIndex].origLen = sfntDir[oldIndex].length;
+
+    /* we always realloc woffData to a long-aligned size, so this is safe */
+    while ((tableOffset & 3) != 0) {
+      woffData[tableOffset++] = 0;
+    }
+    WOFFDIR[newIndex].offset = READ32BE(tableOffset);
+
+    /* allocate enough space for upper bound of compressed size */
+    sourceOffset = READ32BE(sfntDir[oldIndex].offset);
+    if ((sourceOffset & 3) != 0) {
+      status |= eWOFF_warn_misaligned_table;
+    }
+    sourceLen = READ32BE(sfntDir[oldIndex].length);
+    if (sourceLen > sfntLen || sourceOffset > sfntLen - sourceLen) {
+      FAIL(eWOFF_invalid);
+    }
+    destLen = LONGALIGN(compressBound(sourceLen));
+    woffData = (uint8_t *) realloc(woffData, tableOffset + destLen);
+    if (!woffData) {
+      FAIL(eWOFF_out_of_memory);
+    }
+
+    /* do the compression directly into the WOFF data block */
+    if (compress2((Bytef *) (woffData + tableOffset), &destLen,
+                  (const Bytef *) (sfntData + sourceOffset),
+                  sourceLen, 9) != Z_OK) {
+      FAIL(eWOFF_compression_failure);
+    }
+    if (destLen < sourceLen) {
+      /* compressed table was smaller */
+      tableOffset += destLen;
+      WOFFDIR[newIndex].compLen = READ32BE(destLen);
+    } else {
+      /* compression didn't make it smaller, so store original data instead */
+      destLen = sourceLen;
+      /* reallocate to ensure enough space for the table,
+         plus potential padding after it */
+      woffData = (uint8_t *) realloc(woffData,
+                                     tableOffset + LONGALIGN(sourceLen));
+      if (!woffData) {
+        FAIL(eWOFF_out_of_memory);
+      }
+      /* copy the original data into place */
+      memcpy(woffData + tableOffset,
+             sfntData + READ32BE(sfntDir[oldIndex].offset), sourceLen);
+      tableOffset += sourceLen;
+      WOFFDIR[newIndex].compLen = WOFFDIR[newIndex].origLen;
+    }
+
+    /* update total size of uncompressed OpenType with table size */
+    totalSfntSize += sourceLen;
+    totalSfntSize = LONGALIGN(totalSfntSize);
+  }
+
+  if (totalSfntSize > sfntLen) {
+    if (totalSfntSize > LONGALIGN(sfntLen)) {
+      FAIL(eWOFF_invalid);
+    } else {
+      status |= eWOFF_warn_unpadded_table;
+    }
+  } else if (totalSfntSize < sfntLen) {
+    /* check if the remaining data is a DSIG we're removing;
+       if so, we're already warning about that */
+    if ((status & eWOFF_warn_removed_DSIG) != 0 ||
+        sfntLen - totalSfntSize >
+          LONGALIGN(removedDsigSize) + sizeof(sfntDirEntry)) {
+      status |= eWOFF_warn_trailing_data;
+    }
+  }
+
+  /* write the header */
+  newHeader = (woffHeader *) (woffData);
+  newHeader->signature = WOFF_SIGNATURE;
+  newHeader->signature = READ32BE(newHeader->signature);
+  newHeader->flavor = header->version;
+  newHeader->length = READ32BE(tableOffset);
+  newHeader->numTables = READ16BE(numTables);
+  newHeader->reserved = 0;
+  newHeader->totalSfntSize = READ32BE(totalSfntSize);
+  newHeader->majorVersion = READ16BE(majorVersion);
+  newHeader->minorVersion = READ16BE(minorVersion);
+  newHeader->metaOffset = 0;
+  newHeader->metaCompLen = 0;
+  newHeader->metaOrigLen = 0;
+  newHeader->privOffset = 0;
+  newHeader->privLen = 0;
+
+  free(tableOrder);
+
+  if ((status & eWOFF_warn_checksum_mismatch) != 0) {
+    /* The original font had checksum errors, so we now decode our WOFF data
+       back to sfnt format (which fixes checkSumAdjustment), then re-encode
+       to get a clean copy. */
+    const uint8_t * cleanSfnt = woffDecode(woffData, tableOffset,
+                                           &sfntLen, &status);
+    if (WOFF_FAILURE(status)) {
+      FAIL(status);
+    }
+    free(woffData);
+    woffData = (uint8_t *) woffEncode(cleanSfnt, sfntLen,
+                                      majorVersion, minorVersion,
+                                      &tableOffset, &status);
+    free((void *) cleanSfnt);
+    if (WOFF_FAILURE(status)) {
+      FAIL(status);
+    }
+  }
+
+  if (woffLen) {
+    *woffLen = tableOffset;
+  }
+  if (pStatus) {
+    *pStatus |= status;
+  }
+  return woffData;
+
+failure:
+  if (tableOrder) {
+    free(tableOrder);
+  }
+  if (woffData) {
+    free(woffData);
+  }
+  if (pStatus) {
+    *pStatus = status;
+  }
+  return NULL;
+}
+
+static const uint8_t *
+rebuildWoff(const uint8_t * woffData, uint32_t * woffLen,
+            const uint8_t * metaData, uint32_t metaCompLen, uint32_t metaOrigLen,
+            const uint8_t * privData, uint32_t privLen, uint32_t * pStatus)
+{
+  const woffHeader * origHeader;
+  const woffDirEntry * woffDir;
+  uint8_t * newData = NULL;
+  uint8_t * tableData = NULL;
+  woffHeader * newHeader;
+  uint16_t numTables;
+  uint32_t tableLimit, totalSize, offset;
+  uint16_t i;
+  uint32_t status = eWOFF_ok;
+
+  if (*woffLen < sizeof(woffHeader)) {
+    FAIL(eWOFF_invalid);
+  }
+  origHeader = (const woffHeader *) (woffData);
+
+  if (READ32BE(origHeader->signature) != WOFF_SIGNATURE) {
+    FAIL(eWOFF_bad_signature);
+  }
+
+  numTables = READ16BE(origHeader->numTables);
+  woffDir = (const woffDirEntry *) (woffData + sizeof(woffHeader));
+  tableLimit = 0;
+  for (i = 0; i < numTables; ++i) {
+    uint32_t end = READ32BE(woffDir[i].offset) + READ32BE(woffDir[i].compLen);
+    if (end > tableLimit) {
+      tableLimit = end;
+    }
+  }
+  tableLimit = LONGALIGN(tableLimit);
+
+  /* check for broken input (meta/priv data before sfnt tables) */
+  offset = READ32BE(origHeader->metaOffset);
+  if (offset != 0 && offset < tableLimit) {
+    FAIL(eWOFF_illegal_order);
+  }
+  offset = READ32BE(origHeader->privOffset);
+  if (offset != 0 && offset < tableLimit) {
+    FAIL(eWOFF_illegal_order);
+  }
+
+  totalSize = tableLimit; /* already long-aligned */
+  if (metaCompLen) {
+    totalSize += metaCompLen;
+  }
+  if (privLen) {
+    totalSize = LONGALIGN(totalSize) + privLen;
+  }
+  newData = malloc(totalSize);
+  if (!newData) {
+    FAIL(eWOFF_out_of_memory);
+  }
+
+  /* copy the header, directory, and sfnt tables */
+  memcpy(newData, woffData, tableLimit);
+
+  /* then overwrite the header fields that should be changed */
+  newHeader = (woffHeader *) newData;
+  newHeader->length = READ32BE(totalSize);
+  newHeader->metaOffset = 0;
+  newHeader->metaCompLen = 0;
+  newHeader->metaOrigLen = 0;
+  newHeader->privOffset = 0;
+  newHeader->privLen = 0;
+
+  offset = tableLimit;
+  if (metaData && metaCompLen > 0 && metaOrigLen > 0) {
+    newHeader->metaOffset = READ32BE(offset);
+    newHeader->metaCompLen = READ32BE(metaCompLen);
+    newHeader->metaOrigLen = READ32BE(metaOrigLen);
+    memcpy(newData + offset, metaData, metaCompLen);
+    offset += metaCompLen;
+  }
+
+  if (privData && privLen > 0) {
+    while ((offset & 3) != 0) {
+      newData[offset++] = 0;
+    }
+    newHeader->privOffset = READ32BE(offset);
+    newHeader->privLen = READ32BE(privLen);
+    memcpy(newData + offset, privData, privLen);
+    offset += privLen;
+  }
+
+  *woffLen = offset;
+  free((void *) woffData);
+
+  if (pStatus) {
+    *pStatus |= status;
+  }
+  return newData;
+
+failure:
+  if (newData) {
+    free(newData);
+  }
+  if (pStatus) {
+    *pStatus = status;
+  }
+  return NULL;
+}
+
+const uint8_t *
+woffSetMetadata(const uint8_t * woffData, uint32_t * woffLen,
+                const uint8_t * metaData, uint32_t metaLen,
+                uint32_t * pStatus)
+{
+  const woffHeader * header;
+  uLong compLen = 0;
+  uint8_t * compData = NULL;
+  const uint8_t * privData = NULL;
+  uint32_t privLen = 0;
+  uint32_t status = eWOFF_ok;
+
+  if (pStatus && WOFF_FAILURE(*pStatus)) {
+    return NULL;
+  }
+
+  if (!woffData || !woffLen) {
+    FAIL(eWOFF_bad_parameter);
+  }
+
+  if (*woffLen < sizeof(woffHeader)) {
+    FAIL(eWOFF_invalid);
+  }
+  header = (const woffHeader *) (woffData);
+
+  if (READ32BE(header->signature) != WOFF_SIGNATURE) {
+    FAIL(eWOFF_bad_signature);
+  }
+
+  if (header->privOffset != 0 && header->privLen != 0) {
+    privData = woffData + READ32BE(header->privOffset);
+    privLen = READ32BE(header->privLen);
+    if (privData + privLen > woffData + *woffLen) {
+      FAIL(eWOFF_invalid);
+    }
+  }
+
+  if (metaData && metaLen > 0) {
+    compLen = compressBound(metaLen);
+    compData = malloc(compLen);
+    if (!compData) {
+      FAIL(eWOFF_out_of_memory);
+    }
+
+    if (compress2((Bytef *) compData, &compLen,
+                  (const Bytef *) metaData, metaLen, 9) != Z_OK) {
+      FAIL(eWOFF_compression_failure);
+    }
+  }
+
+  woffData = rebuildWoff(woffData, woffLen,
+                         compData, compLen, metaLen,
+                         privData, privLen, pStatus);
+  free(compData);
+  return woffData;
+
+failure:
+  if (compData) {
+    free(compData);
+  }
+  if (pStatus) {
+    *pStatus = status;
+  }
+  return NULL;
+}
+
+const uint8_t *
+woffSetPrivateData(const uint8_t * woffData, uint32_t * woffLen,
+                   const uint8_t * privData, uint32_t privLen,
+                   uint32_t * pStatus)
+{
+  const woffHeader * header;
+  const uint8_t * metaData = NULL;
+  uint32_t metaLen = 0;
+  uint32_t status = eWOFF_ok;
+
+  if (pStatus && WOFF_FAILURE(*pStatus)) {
+    return NULL;
+  }
+
+  if (!woffData || !woffLen) {
+    FAIL(eWOFF_bad_parameter);
+  }
+
+  if (*woffLen < sizeof(woffHeader)) {
+    FAIL(eWOFF_invalid);
+  }
+  header = (const woffHeader *) (woffData);
+
+  if (READ32BE(header->signature) != WOFF_SIGNATURE) {
+    FAIL(eWOFF_bad_signature);
+  }
+
+  if (header->metaOffset != 0 && header->metaCompLen != 0) {
+    metaData = woffData + READ32BE(header->metaOffset);
+    metaLen = READ32BE(header->metaCompLen);
+    if (metaData + metaLen > woffData + *woffLen) {
+      FAIL(eWOFF_invalid);
+    }
+  }
+
+  woffData = rebuildWoff(woffData, woffLen,
+                         metaData, metaLen, READ32BE(header->metaOrigLen),
+                         privData, privLen, pStatus);
+  return woffData;
+
+failure:
+  if (pStatus) {
+    *pStatus = status;
+  }
+  return NULL;
+}
+
+#endif /* WOFF_MOZILLA_CLIENT */
+
+/******************************************************************/
+/* * * * * * * * * * * * * * DECODING * * * * * * * * * * * * * * */
+/******************************************************************/
+
+static uint32_t
+sanityCheck(const uint8_t * woffData, uint32_t woffLen)
+{
+  const woffHeader * header;
+  uint16_t numTables, i;
+  const woffDirEntry * dirEntry;
+  uint32_t tableTotal = 0;
+
+  if (!woffData || !woffLen) {
+    return eWOFF_bad_parameter;
+  }
+
+  if (woffLen < sizeof(woffHeader)) {
+    return eWOFF_invalid;
+  }
+
+  header = (const woffHeader *) (woffData);
+  if (READ32BE(header->signature) != WOFF_SIGNATURE) {
+    return eWOFF_bad_signature;
+  }
+
+  if (READ32BE(header->length) != woffLen || header->reserved != 0) {
+    return eWOFF_invalid;
+  }
+
+  numTables = READ16BE(header->numTables);
+  if (woffLen < sizeof(woffHeader) + numTables * sizeof(woffDirEntry)) {
+    return eWOFF_invalid;
+  }
+
+  dirEntry = (const woffDirEntry *) (woffData + sizeof(woffHeader));
+  for (i = 0; i < numTables; ++i) {
+    uint32_t offs = READ32BE(dirEntry->offset);
+    uint32_t orig = READ32BE(dirEntry->origLen);
+    uint32_t comp = READ32BE(dirEntry->compLen);
+    if (comp > orig || comp > woffLen || offs > woffLen - comp) {
+      return eWOFF_invalid;
+    }
+    orig = (orig + 3) & ~3;
+    if (tableTotal > 0xffffffffU - orig) {
+      return eWOFF_invalid;
+    }
+    tableTotal += orig;
+    ++dirEntry;
+  }
+
+  if (tableTotal > 0xffffffffU - sizeof(sfntHeader) -
+                                 numTables * sizeof(sfntDirEntry) ||
+      READ32BE(header->totalSfntSize) !=
+        tableTotal + sizeof(sfntHeader) + numTables * sizeof(sfntDirEntry)) {
+    return eWOFF_invalid;
+  }
+
+  return eWOFF_ok;
+}
+
+uint32_t
+woffGetDecodedSize(const uint8_t * woffData, uint32_t woffLen,
+                   uint32_t * pStatus)
+{
+  uint32_t status = eWOFF_ok;
+  uint32_t totalLen = 0;
+
+  if (pStatus && WOFF_FAILURE(*pStatus)) {
+    return 0;
+  }
+
+  status = sanityCheck(woffData, woffLen);
+  if (WOFF_FAILURE(status)) {
+    FAIL(status);
+  }
+
+  totalLen = READ32BE(((const woffHeader *) (woffData))->totalSfntSize);
+  /* totalLen must be correctly rounded up to 4-byte alignment, otherwise
+     sanityCheck would have failed */
+
+failure:
+  if (pStatus) {
+    *pStatus = status;
+  }
+  return totalLen;
+}
+
+static void
+woffDecodeToBufferInternal(const uint8_t * woffData, uint32_t woffLen,
+                           uint8_t * sfntData, uint32_t bufferLen,
+                           uint32_t * pActualSfntLen, uint32_t * pStatus)
+{
+  /* this is only called after sanityCheck has verified that
+     (a) basic header fields are ok
+     (b) all the WOFF table offset/length pairs are valid (within the data)
+     (c) the sum of original sizes + header/directory matches totalSfntSize
+     so we don't have to re-check those overflow conditions here */
+  tableOrderRec * tableOrder = NULL;
+  const woffHeader * header;
+  uint16_t numTables;
+  uint16_t tableIndex;
+  uint16_t order;
+  const woffDirEntry * woffDir;
+  uint32_t totalLen;
+  sfntHeader * newHeader;
+  uint16_t searchRange, rangeShift, entrySelector;
+  uint32_t offset;
+  sfntDirEntry * sfntDir;
+  uint32_t headOffset = 0, headLength = 0;
+  sfntHeadTable * head;
+  uint32_t csum = 0;
+  const uint32_t * csumPtr;
+  uint32_t oldCheckSumAdjustment;
+  uint32_t status = eWOFF_ok;
+
+  if (pStatus && WOFF_FAILURE(*pStatus)) {
+    return;
+  }
+
+  /* check basic header fields */
+  header = (const woffHeader *) (woffData);
+  if (READ32BE(header->flavor) != SFNT_VERSION_TT &&
+      READ32BE(header->flavor) != SFNT_VERSION_CFF &&
+      READ32BE(header->flavor) != SFNT_VERSION_true) {
+    status |= eWOFF_warn_unknown_version;
+  }
+
+  numTables = READ16BE(header->numTables);
+  woffDir = (const woffDirEntry *) (woffData + sizeof(woffHeader));
+
+  totalLen = READ32BE(header->totalSfntSize);
+
+  /* construct the sfnt header */
+  newHeader = (sfntHeader *) (sfntData);
+  newHeader->version = header->flavor;
+  newHeader->numTables = READ16BE(numTables);
+  
+  /* calculate header fields for binary search */
+  searchRange = numTables;
+  searchRange |= (searchRange >> 1);
+  searchRange |= (searchRange >> 2);
+  searchRange |= (searchRange >> 4);
+  searchRange |= (searchRange >> 8);
+  searchRange &= ~(searchRange >> 1);
+  searchRange *= 16;
+  newHeader->searchRange = READ16BE(searchRange);
+  rangeShift = numTables * 16 - searchRange;
+  newHeader->rangeShift = READ16BE(rangeShift);
+  entrySelector = 0;
+  while (searchRange > 16) {
+    ++entrySelector;
+    searchRange >>= 1;
+  }
+  newHeader->entrySelector = READ16BE(entrySelector);
+
+  tableOrder = (tableOrderRec *) malloc(numTables * sizeof(tableOrderRec));
+  if (!tableOrder) {
+    FAIL(eWOFF_out_of_memory);
+  }
+  for (tableIndex = 0; tableIndex < numTables; ++tableIndex) {
+    tableOrder[tableIndex].offset = READ32BE(woffDir[tableIndex].offset);
+    tableOrder[tableIndex].oldIndex = tableIndex;
+  }
+  qsort(tableOrder, numTables, sizeof(tableOrderRec), compareOffsets);
+
+  /* process each table, filling in the sfnt directory */
+  offset = sizeof(sfntHeader) + numTables * sizeof(sfntDirEntry);
+  sfntDir = (sfntDirEntry *) (sfntData + sizeof(sfntHeader));
+  for (order = 0; order < numTables; ++order) {
+    uint32_t origLen, compLen, tag, sourceOffset;
+    tableIndex = tableOrder[order].oldIndex;
+
+    /* validity of these was confirmed by sanityCheck */
+    origLen = READ32BE(woffDir[tableIndex].origLen);
+    compLen = READ32BE(woffDir[tableIndex].compLen);
+    sourceOffset = READ32BE(woffDir[tableIndex].offset);
+
+    sfntDir[tableIndex].tag = woffDir[tableIndex].tag;
+    sfntDir[tableIndex].offset = READ32BE(offset);
+    sfntDir[tableIndex].length = woffDir[tableIndex].origLen;
+    sfntDir[tableIndex].checksum = woffDir[tableIndex].checksum;
+    csum += READ32BE(sfntDir[tableIndex].checksum);
+
+    if (compLen < origLen) {
+      uLongf destLen = origLen;
+      if (uncompress((Bytef *)(sfntData + offset), &destLen,
+                     (const Bytef *)(woffData + sourceOffset),
+                     compLen) != Z_OK || destLen != origLen) {
+        FAIL(eWOFF_compression_failure);
+      }
+    } else {
+      memcpy(sfntData + offset, woffData + sourceOffset, origLen);
+    }
+
+    /* note that old Mac bitmap-only fonts have no 'head' table
+       (eg NISC18030.ttf) but a 'bhed' table instead */
+    tag = READ32BE(sfntDir[tableIndex].tag);
+    if (tag == TABLE_TAG_head || tag == TABLE_TAG_bhed) {
+      headOffset = offset;
+      headLength = origLen;
+    }
+
+    offset += origLen;
+
+    while (offset < totalLen && (offset & 3) != 0) {
+      sfntData[offset++] = 0;
+    }
+  }
+
+  if (headOffset > 0) {
+    /* the font checksum in the 'head' table depends on all the individual
+       table checksums (collected above), plus the header and directory
+       which are added in here */
+    if (headLength < HEAD_TABLE_SIZE) {
+      FAIL(eWOFF_invalid);
+    }
+    head = (sfntHeadTable *)(sfntData + headOffset);
+    oldCheckSumAdjustment = READ32BE(head->checkSumAdjustment);
+    head->checkSumAdjustment = 0;
+    csumPtr = (const uint32_t *)sfntData;
+    while (csumPtr < (const uint32_t *)(sfntData + sizeof(sfntHeader) +
+                                        numTables * sizeof(sfntDirEntry))) {
+      csum += READ32BE(*csumPtr);
+      csumPtr++;
+    }
+    csum = SFNT_CHECKSUM_CALC_CONST - csum;
+
+    if (oldCheckSumAdjustment != csum) {
+      /* if the checksum doesn't match, we fix it; but this will invalidate
+         any DSIG that may be present */
+      status |= eWOFF_warn_checksum_mismatch;
+    }
+    head->checkSumAdjustment = READ32BE(csum);
+  }
+
+  if (pActualSfntLen) {
+    *pActualSfntLen = totalLen;
+  }
+  if (pStatus) {
+    *pStatus |= status;
+  }
+  free(tableOrder);
+  return;
+
+failure:
+  if (tableOrder) {
+    free(tableOrder);
+  }
+  if (pActualSfntLen) {
+    *pActualSfntLen = 0;
+  }
+  if (pStatus) {
+    *pStatus = status;
+  }
+}
+
+void
+woffDecodeToBuffer(const uint8_t * woffData, uint32_t woffLen,
+                   uint8_t * sfntData, uint32_t bufferLen,
+                   uint32_t * pActualSfntLen, uint32_t * pStatus)
+{
+  uint32_t status = eWOFF_ok;
+  uint32_t totalLen;
+
+  if (pStatus && WOFF_FAILURE(*pStatus)) {
+    return;
+  }
+
+  status = sanityCheck(woffData, woffLen);
+  if (WOFF_FAILURE(status)) {
+    FAIL(status);
+  }
+
+  if (!sfntData) {
+    FAIL(eWOFF_bad_parameter);
+  }
+
+  totalLen = READ32BE(((const woffHeader *) (woffData))->totalSfntSize);
+  if (bufferLen < totalLen) {
+    FAIL(eWOFF_buffer_too_small);
+  }
+
+  woffDecodeToBufferInternal(woffData, woffLen, sfntData, bufferLen,
+                             pActualSfntLen, pStatus);
+  return;
+
+failure:
+  if (pActualSfntLen) {
+    *pActualSfntLen = 0;
+  }
+  if (pStatus) {
+    *pStatus = status;
+  }
+}
+
+const uint8_t *
+woffDecode(const uint8_t * woffData, uint32_t woffLen,
+           uint32_t * sfntLen, uint32_t * pStatus)
+{
+  uint32_t status = eWOFF_ok;
+  uint8_t * sfntData = NULL;
+  uint32_t bufLen;
+
+  if (pStatus && WOFF_FAILURE(*pStatus)) {
+    return NULL;
+  }
+
+  status = sanityCheck(woffData, woffLen);
+  if (WOFF_FAILURE(status)) {
+    FAIL(status);
+  }
+
+  bufLen = READ32BE(((const woffHeader *) (woffData))->totalSfntSize);
+  sfntData = (uint8_t *) malloc(bufLen);
+  if (!sfntData) {
+    FAIL(eWOFF_out_of_memory);
+  }
+
+  woffDecodeToBufferInternal(woffData, woffLen, sfntData, bufLen,
+                             sfntLen, &status);
+  if (WOFF_FAILURE(status)) {
+    FAIL(status);
+  }
+
+  if (pStatus) {
+    *pStatus |= status;
+  }
+  return sfntData;
+
+failure:
+  if (sfntData) {
+    free(sfntData);
+  }
+  if (pStatus) {
+    *pStatus = status;
+  }
+  return NULL;
+}
+
+#ifndef WOFF_MOZILLA_CLIENT
+
+const uint8_t *
+woffGetMetadata(const uint8_t * woffData, uint32_t woffLen,
+                uint32_t * metaLen, uint32_t * pStatus)
+{
+  const woffHeader * header;
+  uint32_t offset, compLen;
+  uLong origLen;
+  uint8_t * data = NULL;
+  uint32_t status = eWOFF_ok;
+
+  if (pStatus && WOFF_FAILURE(*pStatus)) {
+    return NULL;
+  }
+
+  status = sanityCheck(woffData, woffLen);
+  if (WOFF_FAILURE(status)) {
+    FAIL(status);
+  }
+
+  header = (const woffHeader *) (woffData);
+
+  offset = READ32BE(header->metaOffset);
+  compLen = READ32BE(header->metaCompLen);
+  origLen = READ32BE(header->metaOrigLen);
+  if (offset == 0 || compLen == 0 || origLen == 0) {
+    return NULL;
+  }
+
+  if (compLen > woffLen || offset > woffLen - compLen) {
+    FAIL(eWOFF_invalid);
+  }
+
+  data = malloc(origLen);
+  if (!data) {
+    FAIL(eWOFF_out_of_memory);
+  }
+
+  if (uncompress((Bytef *)data, &origLen,
+                 (const Bytef *)woffData + offset, compLen) != Z_OK ||
+      origLen != READ32BE(header->metaOrigLen)) {
+    FAIL(eWOFF_compression_failure);
+  }
+
+  if (metaLen) {
+    *metaLen = origLen;
+  }
+  if (pStatus) {
+    *pStatus |= status;
+  }
+  return data;
+
+failure:
+  if (data) {
+    free(data);
+  }
+  if (pStatus) {
+    *pStatus = status;
+  }
+  return NULL;    
+}
+
+const uint8_t *
+woffGetPrivateData(const uint8_t * woffData, uint32_t woffLen,
+                   uint32_t * privLen, uint32_t * pStatus)
+{
+  const woffHeader * header;
+  uint32_t offset, length;
+  uint8_t * data = NULL;
+  uint32_t status = eWOFF_ok;
+
+  if (pStatus && WOFF_FAILURE(*pStatus)) {
+    return NULL;
+  }
+
+  status = sanityCheck(woffData, woffLen);
+  if (WOFF_FAILURE(status)) {
+    FAIL(status);
+  }
+
+  header = (const woffHeader *) (woffData);
+
+  offset = READ32BE(header->privOffset);
+  length = READ32BE(header->privLen);
+  if (offset == 0 || length == 0) {
+    return NULL;
+  }
+
+  if (length > woffLen || offset > woffLen - length) {
+    FAIL(eWOFF_invalid);
+  }
+
+  data = malloc(length);
+  if (!data) {
+    FAIL(eWOFF_out_of_memory);
+  }
+
+  memcpy(data, woffData + offset, length);
+
+  if (privLen) {
+    *privLen = length;
+  }
+  if (pStatus) {
+    *pStatus |= status;
+  }
+  return data;
+
+failure:
+  if (data) {
+    free(data);
+  }
+  if (pStatus) {
+    *pStatus = status;
+  }
+  return NULL;    
+}
+
+void
+woffGetFontVersion(const uint8_t * woffData, uint32_t woffLen,
+                   uint16_t * major, uint16_t * minor, uint32_t * pStatus)
+{
+  const woffHeader * header;
+  uint32_t status = eWOFF_ok;
+
+  if (pStatus && WOFF_FAILURE(*pStatus)) {
+    return;
+  }
+
+  status = sanityCheck(woffData, woffLen);
+  if (WOFF_FAILURE(status)) {
+    FAIL(status);
+  }
+
+  if (!major || !minor) {
+    FAIL(eWOFF_bad_parameter);
+  }
+
+  *major = *minor = 0;
+
+  header = (const woffHeader *) (woffData);
+
+  *major = READ16BE(header->majorVersion);
+  *minor = READ16BE(header->minorVersion);
+
+failure:
+  if (pStatus) {
+    *pStatus = status;
+  }
+}
+
+/* utility to print messages corresponding to WOFF encoder/decoder errors */
+void
+woffPrintStatus(FILE * f, uint32_t status, const char * prefix)
+{
+  if (!prefix) {
+    prefix = "";
+  }
+  if (WOFF_WARNING(status)) {
+    const char * template = "%sWOFF warning: %s\n";
+    if (status & eWOFF_warn_unknown_version) {
+      fprintf(f, template, prefix, "unrecognized sfnt version");
+    }
+    if (status & eWOFF_warn_checksum_mismatch) {
+      fprintf(f, template, prefix, "checksum mismatch (corrected)");
+    }
+    if (status & eWOFF_warn_misaligned_table) {
+      fprintf(f, template, prefix, "misaligned font table");
+    }
+    if (status & eWOFF_warn_trailing_data) {
+      fprintf(f, template, prefix, "extraneous input data discarded");
+    }
+    if (status & eWOFF_warn_unpadded_table) {
+      fprintf(f, template, prefix, "final table not correctly padded");
+    }
+    if (status & eWOFF_warn_removed_DSIG) {
+      fprintf(f, template, prefix, "digital signature (DSIG) table removed");
+    }
+  }
+  if (WOFF_FAILURE(status)) {
+    const char * template = "%sWOFF error: %s\n";
+    const char * msg;
+    switch (status & 0xff) {
+    case eWOFF_out_of_memory:
+      msg = "memory allocation failure";
+      break;
+    case eWOFF_invalid:
+      msg = "invalid input font";
+      break;
+    case eWOFF_compression_failure:
+      msg = "zlib compression/decompression failure";
+      break;
+    case eWOFF_bad_signature:
+      msg = "incorrect WOFF file signature";
+      break;
+    case eWOFF_buffer_too_small:
+      msg = "buffer too small";
+      break;
+    case eWOFF_bad_parameter:
+      msg = "bad parameter to WOFF function";
+      break;
+    case eWOFF_illegal_order:
+      msg = "incorrect table directory order";
+      break;
+    default:
+      msg = "unknown internal error";
+      break;
+    }
+    fprintf(f, template, prefix, msg);
+  }
+}
+
+#endif /* not WOFF_MOZILLA_CLIENT */
diff --git a/gfx/thebes/src/woff.h b/gfx/thebes/src/woff.h
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/woff.h
@@ -0,0 +1,211 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is WOFF font packaging code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef WOFF_H_
+#define WOFF_H_
+
+/* API for the WOFF encoder and decoder */
+
+#ifdef _MSC_VER /* MS VC lacks inttypes.h
+                   but we can make do with a few definitons here */
+typedef char           int8_t;
+typedef short          int16_t;
+typedef int            int32_t;
+typedef unsigned char  uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int   uint32_t;
+#else
+#include <inttypes.h>
+#endif
+
+#include <stdio.h> /* only for FILE, needed for woffPrintStatus */
+
+/* error codes returned in the status parameter of WOFF functions */
+enum {
+  /* Success */
+  eWOFF_ok = 0,
+
+  /* Errors: no valid result returned */
+  eWOFF_out_of_memory = 1,       /* malloc or realloc failed */
+  eWOFF_invalid = 2,             /* invalid input file (e.g., bad offset) */
+  eWOFF_compression_failure = 3, /* error in zlib call */
+  eWOFF_bad_signature = 4,       /* unrecognized file signature */
+  eWOFF_buffer_too_small = 5,    /* the provided buffer is too small */
+  eWOFF_bad_parameter = 6,       /* bad parameter (e.g., null source ptr) */
+  eWOFF_illegal_order = 7,       /* improperly ordered chunks in WOFF font */
+
+  /* Warnings: call succeeded but something odd was noticed.
+     Multiple warnings may be OR'd together. */
+  eWOFF_warn_unknown_version = 0x0100,   /* unrecognized version of sfnt,
+                                            not standard TrueType or CFF */
+  eWOFF_warn_checksum_mismatch = 0x0200, /* bad checksum, use with caution;
+                                            any DSIG will be invalid */
+  eWOFF_warn_misaligned_table = 0x0400,  /* table not long-aligned; fixing,
+                                            but DSIG will be invalid */
+  eWOFF_warn_trailing_data = 0x0800,     /* trailing junk discarded,
+                                            any DSIG may be invalid */
+  eWOFF_warn_unpadded_table = 0x1000,    /* sfnt not correctly padded,
+                                            any DSIG may be invalid */
+  eWOFF_warn_removed_DSIG = 0x2000       /* removed digital signature
+                                            while fixing checksum errors */
+};
+
+/* Note: status parameters must be initialized to eWOFF_ok before calling
+   WOFF functions. If the status parameter contains an error code,
+   functions will return immediately. */
+
+#define WOFF_SUCCESS(status) (((uint32_t)(status) & 0xff) == eWOFF_ok)
+#define WOFF_FAILURE(status) (!WOFF_SUCCESS(status))
+#define WOFF_WARNING(status) ((uint32_t)(status) & ~0xff)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef WOFF_DISABLE_ENCODING
+
+/*****************************************************************************
+ * Returns a new malloc() block containing the encoded data, or NULL on error;
+ * caller should free() this when finished with it.
+ * Returns length of the encoded data in woffLen.
+ * The new WOFF has no metadata or private block;
+ * see the following functions to update these elements.
+ */
+const uint8_t * woffEncode(const uint8_t * sfntData, uint32_t sfntLen,
+                           uint16_t majorVersion, uint16_t minorVersion,
+                           uint32_t * woffLen, uint32_t * status);
+
+
+/*****************************************************************************
+ * Add the given metadata block to the WOFF font, replacing any existing
+ * metadata block. The block will be zlib-compressed.
+ * Metadata is required to be valid XML (use of UTF-8 is recommended),
+ * though this function does not currently check this.
+ * The woffData pointer must be a malloc() block (typically from woffEncode);
+ * it will be freed by this function and a new malloc() block will be returned.
+ * Returns NULL if an error occurs, in which case the original WOFF is NOT freed.
+ */
+const uint8_t * woffSetMetadata(const uint8_t * woffData, uint32_t * woffLen,
+                                const uint8_t * metaData, uint32_t metaLen,
+                                uint32_t * status);
+
+
+/*****************************************************************************
+ * Add the given private data block to the WOFF font, replacing any existing
+ * private block. The block will NOT be zlib-compressed.
+ * Private data may be any arbitrary block of bytes; it may be externally
+ * compressed by the client if desired.
+ * The woffData pointer must be a malloc() block (typically from woffEncode);
+ * it will be freed by this function and a new malloc() block will be returned.
+ * Returns NULL if an error occurs, in which case the original WOFF is NOT freed.
+ */
+const uint8_t * woffSetPrivateData(const uint8_t * woffData, uint32_t * woffLen,
+                                   const uint8_t * privData, uint32_t privLen,
+                                   uint32_t * status);
+
+#endif /* WOFF_DISABLE_ENCODING */
+
+/*****************************************************************************
+ * Returns the size of buffer needed to decode the font (or zero on error).
+ */
+uint32_t woffGetDecodedSize(const uint8_t * woffData, uint32_t woffLen,
+                            uint32_t * pStatus);
+
+
+/*****************************************************************************
+ * Decodes WOFF font to a caller-supplied buffer of size bufferLen.
+ * Returns the actual size of the decoded sfnt data in pActualSfntLen
+ * (must be <= bufferLen, otherwise an error will be returned).
+ */
+void woffDecodeToBuffer(const uint8_t * woffData, uint32_t woffLen,
+                        uint8_t * sfntData, uint32_t bufferLen,
+                        uint32_t * pActualSfntLen, uint32_t * pStatus);
+
+
+/*****************************************************************************
+ * Returns a new malloc() block containing the decoded data, or NULL on error;
+ * caller should free() this when finished with it.
+ * Returns length of the decoded data in sfntLen.
+ */
+const uint8_t * woffDecode(const uint8_t * woffData, uint32_t woffLen,
+                           uint32_t * sfntLen, uint32_t * status);
+
+
+/*****************************************************************************
+ * Returns a new malloc() block containing the metadata from the WOFF font,
+ * or NULL if an error occurs or no metadata is present.
+ * Length of the metadata is returned in metaLen.
+ * The metadata is decompressed before returning.
+ */
+const uint8_t * woffGetMetadata(const uint8_t * woffData, uint32_t woffLen,
+                                uint32_t * metaLen, uint32_t * status);
+
+
+/*****************************************************************************
+ * Returns a new malloc() block containing the private data from the WOFF font,
+ * or NULL if an error occurs or no private data is present.
+ * Length of the private data is returned in privLen.
+ */
+const uint8_t * woffGetPrivateData(const uint8_t * woffData, uint32_t woffLen,
+                                   uint32_t * privLen, uint32_t * status);
+
+
+/*****************************************************************************
+ * Returns the font version numbers from the WOFF font in the major and minor
+ * parameters.
+ * Check the status result to know if the function succeeded.
+ */
+void woffGetFontVersion(const uint8_t * woffData, uint32_t woffLen,
+                        uint16_t * major, uint16_t * minor,
+                        uint32_t * status);
+
+
+/*****************************************************************************
+ * Utility to print warning and/or error status to the specified FILE*.
+ * The prefix string will be prepended to each line (ok to pass NULL if no
+ * prefix is wanted).
+ * (Provides terse English messages only, not intended for end-user display;
+ * user-friendly tools should map the status codes to their own messages.)
+ */
+void woffPrintStatus(FILE * f, uint32_t status, const char * prefix);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1727,17 +1727,19 @@ InsertFontFaceRule(nsCSSFontFaceRule *aR
         face->mUseOriginPrincipal = (aSheetType == nsStyleSet::eUserSheet ||
                                      aSheetType == nsStyleSet::eAgentSheet);
                                      
         face->mLocalName.Truncate();
         face->mFormatFlags = 0;
         while (i + 1 < numSrc && (val = srcArr->Item(i+1), 
                  val.GetUnit() == eCSSUnit_Font_Format)) {
           nsDependentString valueString(val.GetStringBufferValue());
-          if (valueString.LowerCaseEqualsASCII("opentype")) {
+          if (valueString.LowerCaseEqualsASCII("woff")) {
+            face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_WOFF; 
+          } else if (valueString.LowerCaseEqualsASCII("opentype")) {
             face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_OPENTYPE; 
           } else if (valueString.LowerCaseEqualsASCII("truetype")) {
             face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE; 
           } else if (valueString.LowerCaseEqualsASCII("truetype-aat")) {
             face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT; 
           } else if (valueString.LowerCaseEqualsASCII("embedded-opentype")) {
             face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_EOT;   
           } else if (valueString.LowerCaseEqualsASCII("svg")) {
diff --git a/layout/reftests/font-face/507960-1-bad-checksums-ttf.html b/layout/reftests/font-face/507960-1-bad-checksums-ttf.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-face/507960-1-bad-checksums-ttf.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<style type="text/css">
+  @font-face {
+    font-family: test;
+    src: url(../fonts/DeLarge/DeLarge-bad-checksums.ttf);
+  }
+  body {
+    font-family: test;
+  }
+</style>
+</head>
+<body>
+  HELLO WORLD
+</body>
+</html>
diff --git a/layout/reftests/font-face/507960-1-bad-checksums-woff.html b/layout/reftests/font-face/507960-1-bad-checksums-woff.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-face/507960-1-bad-checksums-woff.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<style type="text/css">
+  @font-face {
+    font-family: test;
+    src: url(../fonts/DeLarge/DeLarge-bad-checksums.woff);
+  }
+  body {
+    font-family: test;
+  }
+</style>
+</head>
+<body>
+  HELLO WORLD
+</body>
+</html>
diff --git a/layout/reftests/font-face/507960-1-bad-offset-woff.html b/layout/reftests/font-face/507960-1-bad-offset-woff.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-face/507960-1-bad-offset-woff.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<style type="text/css">
+  @font-face {
+    font-family: test;
+    src: url(../fonts/DeLarge/DeLarge-bad-offset.woff);
+  }
+  body {
+    font-family: test;
+  }
+</style>
+</head>
+<body>
+  HELLO WORLD
+</body>
+</html>
diff --git a/layout/reftests/font-face/507960-1-bad-sfnt-version-ttf.html b/layout/reftests/font-face/507960-1-bad-sfnt-version-ttf.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-face/507960-1-bad-sfnt-version-ttf.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<style type="text/css">
+  @font-face {
+    font-family: test;
+    src: url(../fonts/DeLarge/DeLarge-bad-sfnt-version.ttf);
+  }
+  body {
+    font-family: test;
+  }
+</style>
+</head>
+<body>
+  HELLO WORLD
+</body>
+</html>
diff --git a/layout/reftests/font-face/507960-1-bad-sfnt-version-woff.html b/layout/reftests/font-face/507960-1-bad-sfnt-version-woff.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-face/507960-1-bad-sfnt-version-woff.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<style type="text/css">
+  @font-face {
+    font-family: test;
+    src: url(../fonts/DeLarge/DeLarge-bad-sfnt-version.woff);
+  }
+  body {
+    font-family: test;
+  }
+</style>
+</head>
+<body>
+  HELLO WORLD
+</body>
+</html>
diff --git a/layout/reftests/font-face/507960-1-bad-woff-sig.html b/layout/reftests/font-face/507960-1-bad-woff-sig.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-face/507960-1-bad-woff-sig.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<style type="text/css">
+  @font-face {
+    font-family: test;
+    src: url(../fonts/DeLarge/DeLarge-bad-woff-sig.woff);
+  }
+  body {
+    font-family: test;
+  }
+</style>
+</head>
+<body>
+  HELLO WORLD
+</body>
+</html>
diff --git a/layout/reftests/font-face/507960-1-nofont.html b/layout/reftests/font-face/507960-1-nofont.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-face/507960-1-nofont.html
@@ -0,0 +1,11 @@
+<html>
+<head>
+<style type="text/css">
+  body {
+  }
+</style>
+</head>
+<body>
+  HELLO WORLD
+</body>
+</html>
diff --git a/layout/reftests/font-face/507960-1-ref.html b/layout/reftests/font-face/507960-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-face/507960-1-ref.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<style type="text/css">
+  @font-face {
+    font-family: test;
+    src: url(../fonts/DeLarge/DeLarge.ttf);
+  }
+  body {
+    font-family: test;
+  }
+</style>
+</head>
+<body>
+  HELLO WORLD
+</body>
+</html>
diff --git a/layout/reftests/font-face/507960-1-woff-bad-hint.html b/layout/reftests/font-face/507960-1-woff-bad-hint.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-face/507960-1-woff-bad-hint.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<style type="text/css">
+  @font-face {
+    font-family: test;
+    src: url(../fonts/DeLarge/DeLarge.woff) format("not-woff");
+  }
+  body {
+    font-family: test;
+  }
+</style>
+</head>
+<body>
+  HELLO WORLD
+</body>
+</html>
diff --git a/layout/reftests/font-face/507960-1-woff-hint.html b/layout/reftests/font-face/507960-1-woff-hint.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-face/507960-1-woff-hint.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<style type="text/css">
+  @font-face {
+    font-family: test;
+    src: url(../fonts/DeLarge/DeLarge.woff) format("woff");
+  }
+  body {
+    font-family: test;
+  }
+</style>
+</head>
+<body>
+  HELLO WORLD
+</body>
+</html>
diff --git a/layout/reftests/font-face/507960-1-woff.html b/layout/reftests/font-face/507960-1-woff.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-face/507960-1-woff.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<style type="text/css">
+  @font-face {
+    font-family: test;
+    src: url(../fonts/DeLarge/DeLarge.woff);
+  }
+  body {
+    font-family: test;
+  }
+</style>
+</head>
+<body>
+  HELLO WORLD
+</body>
+</html>
diff --git a/layout/reftests/font-face/reftest.list b/layout/reftests/font-face/reftest.list
--- a/layout/reftests/font-face/reftest.list
+++ b/layout/reftests/font-face/reftest.list
@@ -92,8 +92,24 @@ random-if(MOZ_WIDGET_TOOLKIT=="gtk2") HT
 HTTP(..) load 486974-1.html
 
 # compare fonts with and without bad head checksum
 HTTP(..) == load-badchecksum.html load-badchecksum-ref.html
 
 # t2embed lib on windows is picky about fullname
 HTTP(..) == load-badfullname.html load-badfullname-ref.html
 
+# 507960-1-* : a collection of tests using DeLarge from openfontlibrary.org
+# check that the original DeLarge face (ttf) loads; if this fails,
+# none of the following tests are meaningful
+HTTP(..) != 507960-1-nofont.html 507960-1-ref.html
+# check that the WOFF version loads, with and without a format hint
+HTTP(..) == 507960-1-woff.html 507960-1-ref.html
+HTTP(..) == 507960-1-woff-hint.html 507960-1-ref.html
+# try damaged fonts that should still load (bad checksums)
+HTTP(..) == 507960-1-bad-checksums-ttf.html 507960-1-ref.html
+HTTP(..) == 507960-1-bad-checksums-woff.html 507960-1-ref.html
+# try versions that should NOT load (bad offsets, signatures, hint)
+HTTP(..) != 507960-1-bad-sfnt-version-ttf.html 507960-1-ref.html
+HTTP(..) != 507960-1-bad-sfnt-version-woff.html 507960-1-ref.html
+HTTP(..) != 507960-1-bad-woff-sig.html 507960-1-ref.html
+HTTP(..) != 507960-1-bad-offset-woff.html 507960-1-ref.html
+HTTP(..) != 507960-1-woff-bad-hint.html 507960-1-ref.html
diff --git a/layout/reftests/fonts/DeLarge/DeLarge-bad-checksums.ttf b/layout/reftests/fonts/DeLarge/DeLarge-bad-checksums.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..22ae2a93f6b553fcc7a32a0f8651fbb2bdeefd8a
GIT binary patch
literal 9700
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
Zw71oFt!Zs<?rQ2;+tse09YP@x{u_+ZyeR+x

diff --git a/layout/reftests/fonts/DeLarge/DeLarge-bad-checksums.woff b/layout/reftests/fonts/DeLarge/DeLarge-bad-checksums.woff
new file mode 100644
index 0000000000000000000000000000000000000000..49eb3c71b2ffce96db78877d80a346ca51493e7b
GIT binary patch
literal 4704
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

diff --git a/layout/reftests/fonts/DeLarge/DeLarge-bad-offset.woff b/layout/reftests/fonts/DeLarge/DeLarge-bad-offset.woff
new file mode 100644
index 0000000000000000000000000000000000000000..7e72ad10cdc1187c329aee6f28e930f3ebd66bd6
GIT binary patch
literal 4704
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

diff --git a/layout/reftests/fonts/DeLarge/DeLarge-bad-sfnt-version.ttf b/layout/reftests/fonts/DeLarge/DeLarge-bad-sfnt-version.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..08bd2fdcf2f601e7e202057ffb3aef0f1d542c73
GIT binary patch
literal 9700
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
Z9qskqYg#*+yPJB~c6aD!hhPwd{|1gNyeR+x

diff --git a/layout/reftests/fonts/DeLarge/DeLarge-bad-sfnt-version.woff b/layout/reftests/fonts/DeLarge/DeLarge-bad-sfnt-version.woff
new file mode 100644
index 0000000000000000000000000000000000000000..8464123f98842a41de6327eb8e1cab55a859c4be
GIT binary patch
literal 4704
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

diff --git a/layout/reftests/fonts/DeLarge/DeLarge-bad-woff-sig.woff b/layout/reftests/fonts/DeLarge/DeLarge-bad-woff-sig.woff
new file mode 100644
index 0000000000000000000000000000000000000000..de73d046285c63ca4869eadc6166573ffa30f95e
GIT binary patch
literal 4704
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

diff --git a/layout/reftests/fonts/DeLarge/DeLarge.ttf b/layout/reftests/fonts/DeLarge/DeLarge.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..d90bac4f4d9c1a337b2ed8b7b308561b042dcced
GIT binary patch
literal 9700
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
Z+S}^8*0i=acQy5_?P}N04xtbT{|${<yeR+x

diff --git a/layout/reftests/fonts/DeLarge/DeLarge.woff b/layout/reftests/fonts/DeLarge/DeLarge.woff
new file mode 100644
index 0000000000000000000000000000000000000000..e8440843b48adbc99a20c5e0a1642a36ca7178de
GIT binary patch
literal 4704
zc${^ZWl&tp)`kZkoFKslcXtRrXy9NWBzUmF0|A1E02$mJf(Hqb;O;tDfZz_n27-HV
zhPiWc?~m`#*Hx>!`>FM=UiH@ARlT>jj;bmE4S*V?765{OXSOZC|1)&-1cU(qv;@@h
z1uFDA#M%lW&X%qK0D3!$&!T3ZYV~MLJ4<&IBQ-?j0RIgn5`ban<ZBB6V2Pr(Pypa5
z!Q?Dt!`{Zy8l?lFa!?!~{)ci`-W~-}?BDu~s9+_*!)CH~_V7Wmb<}<lb;gV87l6&T
zHt*j70EEpbPKRPo5t``Vom?O&EoKTTF9*eWf#*bd&Xzu?UeH|sSC0|%3Sjxp(%A+8
zAX-4_yixhEpL7{at}gB#0KgN}xo9}3cr!b)g5$FUv9PwV0Bi=t1^+mE5I3i8mZSo&
zr@xw#6Qr|bJ4a3;T|gQO+|d1J3XarN0I_TQ-T!Ht?so>)M{9PGg@NvpX@UTi7v0u?
zLR}o0zh0*T1Oe!OEky^A00aPvs4fWp>+xT`WdBNU_i%TQRP<~*6sk+3C}M7{1|hYw
zu&`RU{qzZoK=S~DiaS85g@9fT503y`y4CaH)||0WsErO@jEOyPd)*}>2msJNAy!7!
zt3~w_WHl#<jXmJS=tqGmGNQPx&oom_P8QzdI1gR`orCL$9|QZ|XF;K{Pln`(`V_z|
zvfu#p1U|x7^3+3J=++z<d!~6l@(CT}YF~nf>KXtJ@_8$yi~$cw+A@NKKpgukW<~^A
z1TjXxH_Hlc?<h|GJEPG4M{e{h9ggvUgf9vkzyU_TT1L?<wiIFyoCB3SlL=T18mB=B
zb=Xk4MS7LhA=+)~wh(6UV%{?~=y$Y9ohSQ}R3z_g>XhG048^_>Z>3#G5L}RdK~Rg2
z2{6txi2v(VXyT&Aj4r5OzRN9BxI(nTqZ~At>69tnG|F2yRX;2G*)79u&D&j6!+p&g
zfw8X@u^JRa|1n};CBh8T4Rpw~&$r7IRK1Mo!OU028QWMDxX!*uoMVY{mYxnO$#Q*A
zr$dGo=*}v&sWhcJ=Pq}&dmpZB!`qg}1INv-6u^0M_DE=OPZ$YgHy>8aV)^{%An%|~
zwv4Bg46`uzo#yD`g1g&}K%cp0v&Zc}R#UTEDR1XpR@yzKFSU(ZM>{lBZS@<)I3xtt
zYy~)Zx%s*Hc&bXv3tEdCD?9UR_D=LOPn_RX^-nH&bs>6SabwT_G4LLj58FLDV4wog
z&{NaV+F8AK%*-%qkSU4MuThWf`IH7w6eQCC9eJFG_~xEve{SC-JTdD1!O?l1^JO^Z
zcg28%AhoAzhma94!=gJxMG9VYQR5-!DNX4!h?8an7g@WhndFj-dc8r;V`an(HB2#0
zxSpqdesgK#?}q5loZWU^eDmb^%_Fp5i^8@*ojFw#&pyxjLeZf}X-?K{LPfsABbmwE
zPDoAMpFnV!1Qugq6C^aS#}w|sp27V2<9YQDYw1vOT}7dy6kP?$)K|JnVhuBT&+%i=
zuZ!1=5aE>ndj|j*e2fH;Qix&CX`C(|u)?*QfHS+hIr8iY8AdW`GOZrPG<UI*ra*d8
zdPO=Uol=Ma641lkZPlIBH`P-M-F{j|Qbzao=>a)wbKE7(0kJrtxI`mCBYh)=6T^b!
z!sP<l0__52P1pMR#snM)=Y$*fxW&O~OVI5w?eKT7$4mr=`f)<(O$pUp@zH$31h;Hq
z#At@b>X5(v9U1y-(q2<{UO%+OTau0S*=6^AB78(QH^yQ3ohF4Pwu+hAz%;vD8$!S=
z$)mfQ##PRgD$%m^wdiH*RE)!~-xco;JhZ}V?IT}(W#ludOKW^(MPdAc!eK0kymcz-
zojwfxdL-c5QmNG=@CeR8azipDdvYOnauEQ;<2+Z<5q5CoQE|R%oL!`|be#(hhO`u0
zSWphp{nS$MEB}0jX~>ntb^Q2erdogn%P>uy=evO0Y4uJ&8XCp%+Me78a6Tn@l(3+{
zBpV@FfwL#J8KF;>mqIxUiPOmhl!;mj$!C5-Orz*iNqfm9$0{&cr1*LB!)bRCzKYMa
zx)E5>VCwP!LGv~4tz?fi*JQWn41fpk#h|#~Cq}%-^!}2Yn?zYjwTmEPiH$BI@IHHT
zY7-q*b`C7rXN(NGv6FiNK3LPPgt;fJ6w(hkP*Tm6xfdP=VN)lwM)b@v2e{Fj6CR<V
zQ96N=`8tDLHlj~rmzr=rzo5}JZ@8~ld}~z4W*;`5n(4qEOiz@jbbgE3YcNw^3N5w}
zp$#kcgO=v^AB2DtfWn8%^V1g-_A9nZgWean34B#DGr`A5nmd)4rlPNv*;Q#{CR5*D
z+1Aa|-R8;^FxEFH_^^h3NaiTIDF*NGZ`ezphjq~vJ&t%XHmeVJhLvr9E$q*eI4^@A
zTm2q@^{((sNv^j1@+@8x^4Cee5ABF+xVD>MoVDl_*dLAvF*OW!_$*y;L{a^`bJ}}R
zyrUg1=do=$DB3F3gily}%^>$Hej*qDvtHxK*+fRbpIJ%|pJoJQl$DuH>o+NktnVz<
z#=Sq6^e{rH5MdK5N(@gaE*(@NOACc_5WLelCbw^-*Lt~b-KtVA@Wpl~(tl9Iir{{q
z+a-=I(qol#xJv3wVEYh%_mNpNq@)X(A~iiM9JwhG-=EAP`SHTejrynG$gMDbpPecl
zRR>XoyRawoNQFpM_Jj1R>!Ti>_DlZko%_H)!}m8-kFKEHN3!IfM^}Zv)4a72H~u}>
z_9hI#s`g`O;%yJ!qhzmJ@<8H^A$%Sk>gA_dAX1G{KHV%BOgYOH3L(9yLSS?~>^u?w
z^i-=$829|xwhkF-YxOD%Lz$1xqUUW6QMF3dYoo;aYnEqKyc+wa=|YT}u>-&`SRdo&
zf;v|V9x%$U!imSswin)B!2ec|ls@S!p%?CMorXEl?zCR*#;zphD8;19Ll+^Hx5{fg
z?(<M=_>!S{LejK0#Mps-bl&@_Ahe%60Dq0McUO!Z9tC`uGdRPVDf*q#x%y*srIz+?
zjgI%?4fDr?5y@qU?)eI@@t@j8iRdi{>-dLkr^~6KJ>}AY_*+315zEmLRt)MYbOyJw
zGa33*uEIjR9rNj6IYk-!+0&c?E)1b)jVQ=-iRquW1|U9A(nLYiXh}DL{T);;Sn?O;
z(+-^WD=Jy+3pDWq^~c}50q5Hhn%=L4Foqo+d<7Te0J)C{{D8P)3LZ1H<Q1COl|FkM
z2aa?67ni4JhZaEuo~ugn_dcfRE!=tRCW}6vBqj9^DJq>?q}F03k9~2>=QAmqq`dRE
z{ptig5j7bzYV`(SJKC}*npd^Z*F8!WAD^`_mf=VFXH~}iNYu(Yd7cCIROVssXI(bf
z-PxNaUSi!&(-QfIL>>btORV3cupDNA4IGfA!LEP)L$nPp-TJ5`;1bHDqm$njaK@B*
zZCr-Vqc+0u*@rbjp80|dw|6NXWaRcdCW!Xdl(Dm7_T$^*L{I%xJrcBenX8AZ`k2A9
zUV<&;kad*7sq@EE<Ljx>BwC_3I$4tW=jCVib*eC<x^doDIa-_jknv)h23C>Cmi$Cw
zZLa3=@qA#W_N#h2rd2X6{;%Q6b~!`7p3)8;AoT^@EL+<zgsu8JXBf{gATA=mE~?fZ
zPVs0Wn@#h`*;lGhjLlW-%v<K@A>rU6S=%08@lGH*gYn*!sEN#t&Bh&k!SlI59%!=I
z5>W{bQ`FktE+H#aiVXd6qejCjb7mO0-yk0o8+JY++h@&A%5MUv)Wd3zS@TmJL;TS-
z@ekac(Lndn4gnq>#jC}vk;N4(y4)QKv3tCbH_x1?R&J_1H;ryx=sg>u&vo5?@c9~T
z{^lilbhm~eJMHc2BQQ0+<4!BjGNZ0%Q&8&VcxKXO_7_zsx2Qtco`%cy`%$wXacrfe
zb}8TApC!TZ{;(v@opEwpiIT<m8tsaHI`BLoU-gO0KYvU=`3Jdozm^ZDqikw(l2b?c
zw#`8)-vN^7%CJl$E*w18m=w6@Lj)3NB+?NE%iq+?WPuQz1d5X#O(#xY=Avj5kRoKf
zrHmgZ_M_v~MT7Y0_+3|CXG<2ORqsX^^eaevU1g{_5e9kVdmavcFsnAbKQ@-J&D~lT
zc6T*2Oyt%7iM5sV$%|B-UUkImtsH)M&wf{G>e~&Co7T`6->p8E@}-%<BN+$EWugxZ
z1%=FAjg%$8<EI!B|D?=4ScXc~eF&2=QU{AI?^!xH;`)C#;v>!IG*j84recghH|vJ0
z{nQYa1)u!lPI0OJXyhI=6m*P7NGc_2TAN6kDD}X8TI;_&tckiZlZ@?ER(}X3x|G>5
zD3QVQmt<3@EI{k~X7fFh86E|4x49qq8tK|l!Y#N$v->+u50<#vp`9gEDE=-n*2EhA
zbg^0G|12Msnt;xS>W#6Z9?sHxNFd84OLAz-$ei-vgXuu(nK5j27S6Do=ahBGeVTMM
zg@deBR|mlZEaQ{!i*Azz(l5_WyncckNs*P|golEX<?+6!YlHO(<mwPCj4vd5jzE1e
z(3ALTEpK9@z#r^qSf3x{r%BgYF95Rr$1_)_bWz*f5r<=9OpnA%NU{*!v;W>f_$Fnw
zVPF!hb-O4KplAsbve~x~hqSupN^rG_6n){2{^2W-ld~Csqo$>#prX@H@eIwo8+MVL
zrBk@Lm~lz<2?s<sO?!e%CIhp?o@n_sMb_U*kb-*z9q>{h+t%9_@yqu`YT(bN1b(Sc
zqJ2Gw$Q6&VbG?d{L~Ib)nT)xnZ<1FADtA*oOU9?J{Y|9N&qE!1*G^I67-i^h<%LCP
z&H4E~8;dVLS;la~s5L*n(Gpw5j4!MzPIpAL#9)-;<3%o!H<^d%?DAY;C&6JfKY6%t
zTE?gilSZ5E+#*ihn2eOi&}(x+_juAclL}Q4zml8|w-H!h=810+%+}Gl_&0KCD#)!c
zQ@^A_+r)FVW*q9}b%VnP)ouOjk8|?4&a?$+;7g+bWHd@S5gd`v9Z91~Ekddw8g#?M
z5*Ey~I*RQnn&RnzlN@Z<;d|;NLj#fVIkk_8L=xast;WcmG@YcW8eMcE4)-n)X8~<!
z=`|YF3I6==ZJaEt$HmEQ38d5Wcpz9!;~1QfMOWxu+y;|o0i?Na7GmImllDG6kg6&a
zXNawxf<FP@M?gl6e>2%N@o+QxlthFN-ewu?`@sn^8eqSmK+#3W6Lakg&?%RMVa1pT
z5E5?$U5-^p*QRds?#Ug+_i_xCRD9{JJpL)iCZkDT^9YQ$kDnahty|a$ea<${wo$jG
zd!Kn~Sh<5c`2|mBKV#wBsbq$_csSRjIZ)>yW5EbnSI{+SI(lgeB1>CrmHZ`!sKPq9
z{7UV^&^~fhJ^QW1fl3VSrKnwXW7hD}=+H<XZtv$HqBbS?&i5jqD9O$xR4CEl4X1|Y
zBEE?wNBMIzQe_2MLd_(joUhAAcP&<r`t3UsNiC}65@$fPOtoh37duN$+6AF3GKICV
zeg)py24e<0;TN&@cICPzB@&jV0AfPW`!(>;vmBOf3g*peD(6;V*`mRF0k72D2+y?Y
zA19H@1AqL|!{f_JL1hL$zJ@}JEbl4sA0WGJ0gasH2Vv!)+T5#M5mnPx*!mZ3+xr|)
zU|j5qWb6Ce@__8=!Kc@<tF$pjC7nuxXkx!c<TySk@9+ocN*BQ84AK<XwbqI!F!t`i
zt4iUQ5MPb^(M+vP67REY9gq54NZ<Waui2E=qIadzjtXxKnr5|L>qYyl1eS^A%w}@T
zThlvxk=Bi*bIiN%BWM)&SdkTvlyII#p?{yd9(9p<)K~rlCBLqc5p$;P@XJQ!5HBNc
z3ciSaM%*97$kLj7^p@?)5YaOsJT^k=Hy<f%vpYCOb8`riuP)BO>8?+RqR6)sU<Lip
zHcJiNHrbxB>n6dIik@wJ)zj8UWq%VUGB%vTW)f$*vn45D4#mf#Xel*}eEHebtN-=9
zskc%_*6{1nSKDdJ$E9BLve&bvm)%P7GWsQE!5lPVzWW(FnH>|GMfz3s4)Yrg+Abcr
z9tV>=TNQGMRbQ9xJSLcG42{TfFs`25t<w^vi0#i?$5n|nKEppS9gVb#o9(98f#tVv
qe}x5#JKwrUv+okMW-8^-DVUTtRLPScqC4$_)&BjJfrdl^(EkI37{Ay6

diff --git a/layout/reftests/fonts/DeLarge/README b/layout/reftests/fonts/DeLarge/README
new file mode 100644
--- /dev/null
+++ b/layout/reftests/fonts/DeLarge/README
@@ -0,0 +1,7 @@
+DeLarge by PintassilgoPrints, licensed under the Open Font License
+(http://scripts.sil.org/OFL)
+
+Downloaded from http://openfontlibrary.org/media/files/PintassilgoPrints/429
+
+In addition to the original .ttf file and a .woff conversion,
+there are several "damaged" versions here for testing purposes.
diff --git a/layout/style/nsFontFaceLoader.cpp b/layout/style/nsFontFaceLoader.cpp
--- a/layout/style/nsFontFaceLoader.cpp
+++ b/layout/style/nsFontFaceLoader.cpp
@@ -125,30 +125,33 @@ nsFontFaceLoader::OnStreamComplete(nsISt
   NS_ASSERTION(ctx && !ctx->PresShell()->IsDestroying(),
                "We should have been canceled already");
 
   // whether an error occurred or not, notify the user font set of the completion
   gfxUserFontSet *userFontSet = ctx->GetUserFontSet();
   if (!userFontSet) {
     return aStatus;
   }
-  
-  PRBool fontUpdate = userFontSet->OnLoadComplete(mFontEntry, aLoader,
+
+  // The userFontSet is responsible for freeing the downloaded data
+  // (aString) when finished with it; the pointer is no longer valid
+  // after OnLoadComplete returns.
+  PRBool fontUpdate = userFontSet->OnLoadComplete(mFontEntry,
                                                   aString, aStringLen,
                                                   aStatus);
 
   // when new font loaded, need to reflow
   if (fontUpdate) {
     // Update layout for the presence of the new font.  Since this is
     // asynchronous, reflows will coalesce.
     ctx->UserFontSetUpdated();
     LOG(("fontdownloader (%p) reflow\n", this));
   }
 
-  return aStatus;
+  return NS_SUCCESS_ADOPTED_DATA;
 }
 
 void
 nsFontFaceLoader::Cancel()
 {
   mFontSet = nsnull;
   mChannel->Cancel(NS_BINDING_ABORTED);
 }
diff --git a/netwerk/base/public/nsIStreamLoader.idl b/netwerk/base/public/nsIStreamLoader.idl
--- a/netwerk/base/public/nsIStreamLoader.idl
+++ b/netwerk/base/public/nsIStreamLoader.idl
@@ -50,16 +50,23 @@ interface nsIStreamLoaderObserver : nsIS
      * @param ctxt the context parameter of the underlying channel
      * @param status the status of the underlying channel
      * @param resultLength the length of the data loaded
      * @param result the data
      *
      * This method will always be called asynchronously by the
      * nsIStreamLoader involved, on the thread that called the
      * loader's init() method.
+     *
+     * If the observer wants to take over responsibility for the
+     * data buffer (result), it returns NS_SUCCESS_ADOPTED_DATA
+     * in place of NS_OK as its success code. The loader will then
+     * "forget" about the data, and not free() it in its own
+     * destructor; observer must call free() when the data is
+     * no longer required.
      */
     void onStreamComplete(in nsIStreamLoader loader,
                           in nsISupports ctxt,
                           in nsresult status,
                           in unsigned long resultLength,
                           [const,array,size_is(resultLength)] in octet result);
 };
 
diff --git a/netwerk/base/public/nsNetError.h b/netwerk/base/public/nsNetError.h
--- a/netwerk/base/public/nsNetError.h
+++ b/netwerk/base/public/nsNetError.h
@@ -357,9 +357,22 @@
 
 /**
  * The host string is an IP address.
  */
 #define NS_ERROR_HOST_IS_IP_ADDRESS \
     NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 81)
 
 
+/******************************************************************************
+ * StreamLoader specific result codes:
+ */
+
+/**
+ * Result code returned by nsIStreamLoaderObserver to indicate that
+ * the observer is taking over responsibility for the data buffer,
+ * and the loader should NOT free it.
+ */
+#define NS_SUCCESS_ADOPTED_DATA \
+    NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_NETWORK, 90)
+
+
 #endif // !nsNetError_h__
diff --git a/netwerk/base/src/nsStreamLoader.cpp b/netwerk/base/src/nsStreamLoader.cpp
--- a/netwerk/base/src/nsStreamLoader.cpp
+++ b/netwerk/base/src/nsStreamLoader.cpp
@@ -33,16 +33,33 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsStreamLoader.h"
 #include "nsIInputStream.h"
 #include "nsIChannel.h"
+#include "nsNetError.h"
+
+#include <stdlib.h>
+
+nsStreamLoader::nsStreamLoader()
+  : mData(nsnull),
+    mAllocated(0),
+    mLength(0)
+{
+}
+
+nsStreamLoader::~nsStreamLoader()
+{
+  if (mData) {
+    ::free(mData);
+  }
+}
 
 NS_IMETHODIMP
 nsStreamLoader::Init(nsIStreamLoaderObserver* observer)
 {
   NS_ENSURE_ARG_POINTER(observer);
   mObserver = observer;
   return NS_OK;
 }
@@ -62,17 +79,17 @@ nsStreamLoader::Create(nsISupports *aOut
 }
 
 NS_IMPL_ISUPPORTS3(nsStreamLoader, nsIStreamLoader,
                    nsIRequestObserver, nsIStreamListener)
 
 NS_IMETHODIMP 
 nsStreamLoader::GetNumBytesRead(PRUint32* aNumBytes)
 {
-  *aNumBytes = mData.Length();
+  *aNumBytes = mLength;
   return NS_OK;
 }
 
 /* readonly attribute nsIRequest request; */
 NS_IMETHODIMP 
 nsStreamLoader::GetRequest(nsIRequest **aRequest)
 {
   NS_IF_ADDREF(*aRequest = mRequest);
@@ -83,34 +100,43 @@ NS_IMETHODIMP
 nsStreamLoader::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
 {
   nsCOMPtr<nsIChannel> chan( do_QueryInterface(request) );
   if (chan) {
     PRInt32 contentLength = -1;
     chan->GetContentLength(&contentLength);
     if (contentLength >= 0) {
       // preallocate buffer
-      mData.SetCapacity(contentLength + 1);
+      mData = static_cast<PRUint8*>(::malloc(contentLength));
+      if (!mData) {
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+      mAllocated = contentLength;
     }
   }
   mContext = ctxt;
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsStreamLoader::OnStopRequest(nsIRequest* request, nsISupports *ctxt,
                               nsresult aStatus)
 {
   if (mObserver) {
     // provide nsIStreamLoader::request during call to OnStreamComplete
     mRequest = request;
-    mObserver->OnStreamComplete(this, mContext, aStatus, 
-                                mData.Length(),
-                                reinterpret_cast<const PRUint8*>
-                                                (mData.get()));
+    nsresult rv = mObserver->OnStreamComplete(this, mContext, aStatus,
+                                              mLength, mData);
+    if (rv == NS_SUCCESS_ADOPTED_DATA) {
+      // the observer now owns the data buffer, and the loader must
+      // not deallocate it
+      mData = nsnull;
+      mLength = 0;
+      mAllocated = 0;
+    }
     // done.. cleanup
     mRequest = 0;
     mObserver = 0;
     mContext = 0;
   }
   return NS_OK;
 }
 
@@ -119,17 +145,34 @@ nsStreamLoader::WriteSegmentFun(nsIInput
                                 void *closure,
                                 const char *fromSegment,
                                 PRUint32 toOffset,
                                 PRUint32 count,
                                 PRUint32 *writeCount)
 {
   nsStreamLoader *self = (nsStreamLoader *) closure;
 
-  self->mData.Append(fromSegment, count);
+  if (count > 0xffffffffU - self->mLength) {
+    return NS_ERROR_ILLEGAL_VALUE; // is there a better error to use here?
+  }
+
+  if (self->mLength + count > self->mAllocated) {
+    self->mData = static_cast<PRUint8*>(::realloc(self->mData,
+                                                  self->mLength + count));
+    if (!self->mData) {
+      self->mLength = 0;
+      self->mAllocated = 0;
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    self->mAllocated = self->mLength + count;
+  }
+
+  ::memcpy(self->mData + self->mLength, fromSegment, count);
+  self->mLength += count;
+
   *writeCount = count;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsStreamLoader::OnDataAvailable(nsIRequest* request, nsISupports *ctxt, 
                                 nsIInputStream *inStr, 
diff --git a/netwerk/base/src/nsStreamLoader.h b/netwerk/base/src/nsStreamLoader.h
--- a/netwerk/base/src/nsStreamLoader.h
+++ b/netwerk/base/src/nsStreamLoader.h
@@ -46,25 +46,28 @@
 class nsStreamLoader : public nsIStreamLoader
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTREAMLOADER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
 
-  nsStreamLoader() { }
-  ~nsStreamLoader() {}
+  nsStreamLoader();
+  ~nsStreamLoader();
 
   static NS_METHOD
   Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
 protected:
   static NS_METHOD WriteSegmentFun(nsIInputStream *, void *, const char *,
                                    PRUint32, PRUint32, PRUint32 *);
 
   nsCOMPtr<nsIStreamLoaderObserver> mObserver;
   nsCOMPtr<nsISupports>             mContext;  // the observer's context
-  nsCString                         mData;
   nsCOMPtr<nsIRequest>              mRequest;
+
+  PRUint8  *mData;
+  PRUint32  mAllocated;
+  PRUint32  mLength;
 };
 
 #endif // nsStreamLoader_h__
