Bug 1064737 pt 2 - Support for WOFF2 as a webfont format. r=jdaggett
authorJonathan Kew <jkew@mozilla.com>
Sat, 04 Oct 2014 11:36:05 +0100
changeset 232032 f9c7c0ea55700422809f442ae16bdb2ca6e015c4
parent 232031 689da8627d4d1b05988353924fc915557546e3c1
child 232033 8845b784128aaa36e3d8f7adcd0c907d70a71fdc
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs1064737
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1064737 pt 2 - Support for WOFF2 as a webfont format. r=jdaggett
gfx/thebes/gfxAndroidPlatform.cpp
gfx/thebes/gfxFontUtils.cpp
gfx/thebes/gfxFontUtils.h
gfx/thebes/gfxPlatformGtk.cpp
gfx/thebes/gfxPlatformMac.cpp
gfx/thebes/gfxQtPlatform.cpp
gfx/thebes/gfxUserFontSet.cpp
gfx/thebes/gfxUserFontSet.h
gfx/thebes/gfxWindowsPlatform.cpp
layout/inspector/nsFontFace.cpp
layout/style/FontFaceSet.cpp
modules/libpref/init/all.js
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -278,19 +278,17 @@ gfxAndroidPlatform::CreatePlatformFontLi
 bool
 gfxAndroidPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t 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 |
-                        gfxUserFontSet::FLAG_FORMAT_WOFF |
-                        gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
+    if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) {
         return true;
     }
 
     // reject all other formats, known and unknown
     if (aFormatFlags != 0) {
         return false;
     }
 
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -950,16 +950,20 @@ gfxFontUtils::DetermineFontDataType(cons
     
     // test for WOFF
     if (aFontDataLength >= sizeof(AutoSwap_PRUint32)) {
         const AutoSwap_PRUint32 *version = 
             reinterpret_cast<const AutoSwap_PRUint32*>(aFontData);
         if (uint32_t(*version) == TRUETYPE_TAG('w','O','F','F')) {
             return GFX_USERFONT_WOFF;
         }
+        if (Preferences::GetBool(GFX_PREF_WOFF2_ENABLED) &&
+            uint32_t(*version) == TRUETYPE_TAG('w','O','F','2')) {
+            return GFX_USERFONT_WOFF2;
+        }
     }
     
     // tests for other formats here
     
     return GFX_USERFONT_UNKNOWN;
 }
 
 nsresult
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -650,18 +650,20 @@ struct FontDataOverlay {
     uint32_t  overlaySrcLen; // src length
     uint32_t  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
+    GFX_USERFONT_WOFF = 3,
+    GFX_USERFONT_WOFF2 = 4
 };
+#define GFX_PREF_WOFF2_ENABLED "gfx.downloadable_fonts.woff2.enabled"
 
 extern const uint8_t sCJKCompatSVSTable[];
 
 class gfxFontUtils {
 
 public:
     // these are public because gfxFont.cpp also looks into the name table
     enum {
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -193,19 +193,17 @@ gfxPlatformGtk::IsFontFormatSupported(ns
     // 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_WOFF     |
-                        gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 
-                        gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
+    if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) {
         return true;
     }
 
     // reject all other formats, known and unknown
     if (aFormatFlags != 0) {
         return false;
     }
 
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -163,19 +163,17 @@ gfxPlatformMac::MakePlatformFont(const n
 bool
 gfxPlatformMac::IsFontFormatSupported(nsIURI *aFontURI, uint32_t 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_WOFF     |
-                        gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 
-                        gfxUserFontSet::FLAG_FORMAT_TRUETYPE | 
+    if (aFormatFlags & (gfxUserFontSet::FLAG_FORMATS_COMMON |
                         gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT)) {
         return true;
     }
 
     // reject all other formats, known and unknown
     if (aFormatFlags != 0) {
         return false;
     }
--- a/gfx/thebes/gfxQtPlatform.cpp
+++ b/gfx/thebes/gfxQtPlatform.cpp
@@ -160,19 +160,17 @@ gfxQtPlatform::IsFontFormatSupported(nsI
     // 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_WOFF     |
-                        gfxUserFontSet::FLAG_FORMAT_OPENTYPE |
-                        gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
+    if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) {
         return true;
     }
 
     // reject all other formats, known and unknown
     if (aFormatFlags != 0) {
         return false;
     }
 
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -216,21 +216,32 @@ private:
 };
 
 // Call the OTS library to sanitize an sfnt before attempting to use it.
 // Returns a newly-allocated block, or nullptr in case of fatal errors.
 const uint8_t*
 gfxUserFontEntry::SanitizeOpenTypeData(const uint8_t* aData,
                                        uint32_t       aLength,
                                        uint32_t&      aSaneLength,
-                                       bool           aIsCompressed)
+                                       gfxUserFontType aFontType)
 {
+    if (aFontType == GFX_USERFONT_UNKNOWN) {
+        aSaneLength = 0;
+        return nullptr;
+    }
+
+    uint32_t lengthHint = aLength;
+    if (aFontType == GFX_USERFONT_WOFF) {
+        lengthHint *= 2;
+    } else if (aFontType == GFX_USERFONT_WOFF2) {
+        lengthHint *= 3;
+    }
+
     // limit output/expansion to 256MB
-    ExpandingMemoryStream output(aIsCompressed ? aLength * 2 : aLength,
-                                 1024 * 1024 * 256);
+    ExpandingMemoryStream output(lengthHint, 1024 * 1024 * 256);
 
     gfxOTSContext otsContext(this);
 
     if (otsContext.Process(&output, aData, aLength)) {
         aSaneLength = output.Tell();
         return static_cast<uint8_t*>(output.forget());
     } else {
         aSaneLength = 0;
@@ -549,18 +560,17 @@ gfxUserFontEntry::LoadPlatformFont(const
     // in the font with a synthetic one, we save the original name so that
     // it can be reported via the nsIDOMFontFace API.
     nsAutoString originalFullName;
 
     // Call the OTS sanitizer; this will also decode WOFF to sfnt
     // if necessary. The original data in aFontData is left unchanged.
     uint32_t saneLen;
     const uint8_t* saneData =
-        SanitizeOpenTypeData(aFontData, aLength, saneLen,
-                             fontType == GFX_USERFONT_WOFF);
+        SanitizeOpenTypeData(aFontData, aLength, saneLen, fontType);
     if (!saneData) {
         mFontSet->LogMessage(this, "rejected by sanitizer");
     }
     if (saneData) {
         // The sanitizer ensures that we have a valid sfnt and a usable
         // name table, so this should never fail unless we're out of
         // memory, and GetFullNameFromSFNT is not directly exposed to
         // arbitrary/malicious data from the web.
@@ -685,16 +695,21 @@ gfxUserFontEntry::FontDataDownloadComple
 gfxUserFontSet::gfxUserFontSet()
     : mFontFamilies(4), mLocalRulesUsed(false)
 {
     IncrementGeneration(true);
     gfxPlatformFontList* fp = gfxPlatformFontList::PlatformFontList();
     if (fp) {
         fp->AddUserFontSet(this);
     }
+
+    // This is a one-time global switch for OTS. However, as long as we use
+    // a preference to control the availability of WOFF2 support, we will
+    // not actually pass any WOFF2 data to OTS unless the pref is on.
+    ots::EnableWOFF2();
 }
 
 gfxUserFontSet::~gfxUserFontSet()
 {
     gfxPlatformFontList* fp = gfxPlatformFontList::PlatformFontList();
     if (fp) {
         fp->RemoveUserFontSet(this);
     }
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -168,19 +168,26 @@ public:
         // 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,
+        FLAG_FORMAT_WOFF2          = 1 << 7,
+
+        // the common formats that we support everywhere
+        FLAG_FORMATS_COMMON        = FLAG_FORMAT_OPENTYPE |
+                                     FLAG_FORMAT_TRUETYPE |
+                                     FLAG_FORMAT_WOFF     |
+                                     FLAG_FORMAT_WOFF2,
 
         // mask of all unused bits, update when adding new formats
-        FLAG_FORMAT_NOT_USED       = ~((1 << 7)-1)
+        FLAG_FORMAT_NOT_USED       = ~((1 << 8)-1)
     };
 
 
     // creates a font face without adding it to a particular family
     // weight - [100, 900] (multiples of 100)
     // stretch = [NS_FONT_STRETCH_ULTRA_CONDENSED, NS_FONT_STRETCH_ULTRA_EXPANDED]
     // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
     // language override = result of calling gfxFontStyle::ParseFontLanguageOverride
@@ -563,17 +570,17 @@ public:
     uint32_t GetSrcIndex() { return mSrcIndex; }
     void GetFamilyNameAndURIForLogging(nsACString& aFamilyName,
                                        nsACString& aURI);
 
 protected:
     const uint8_t* SanitizeOpenTypeData(const uint8_t* aData,
                                         uint32_t aLength,
                                         uint32_t& aSaneLength,
-                                        bool aIsCompressed);
+                                        gfxUserFontType aFontType);
 
     // attempt to load the next resource in the src list.
     void LoadNextSrc();
 
     // change the load state
     virtual void SetLoadState(UserFontLoadState aLoadState);
 
     // when download has been completed, pass back data here
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -964,19 +964,17 @@ gfxWindowsPlatform::MakePlatformFont(con
 bool
 gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t 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_WOFF     |
-                        gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 
-                        gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
+    if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) {
         return true;
     }
 
     // reject all other formats, known and unknown
     if (aFormatFlags != 0) {
         return false;
     }
 
--- a/layout/inspector/nsFontFace.cpp
+++ b/layout/inspector/nsFontFace.cpp
@@ -178,16 +178,19 @@ nsFontFace::GetFormat(nsAString & aForma
       AppendToFormat(aFormat, "embedded-opentype");
     }
     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_SVG) {
       AppendToFormat(aFormat, "svg");
     }
     if (formatFlags & gfxUserFontSet::FLAG_FORMAT_WOFF) {
       AppendToFormat(aFormat, "woff");
     }
+    if (formatFlags & gfxUserFontSet::FLAG_FORMAT_WOFF2) {
+      AppendToFormat(aFormat, "woff2");
+    }
   }
   return NS_OK;
 }
 
 /* readonly attribute DOMString metadata; */
 NS_IMETHODIMP
 nsFontFace::GetMetadata(nsAString & aMetadata)
 {
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -12,16 +12,17 @@
 #include "prlog.h"
 
 #include "mozilla/css/Loader.h"
 #include "mozilla/dom/CSSFontFaceLoadEvent.h"
 #include "mozilla/dom/CSSFontFaceLoadEventBinding.h"
 #include "mozilla/dom/FontFaceSetBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/AsyncEventDispatcher.h"
+#include "mozilla/Preferences.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsFontFaceLoader.h"
 #include "nsIChannelPolicy.h"
 #include "nsIConsoleService.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
@@ -897,16 +898,19 @@ FontFaceSet::FindOrCreateUserFontEntryFr
 
           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("woff")) {
               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_WOFF;
+            } else if (Preferences::GetBool(GFX_PREF_WOFF2_ENABLED) &&
+                       valueString.LowerCaseEqualsASCII("woff2")) {
+              face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_WOFF2;
             } 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;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -529,16 +529,21 @@ pref("gfx.perf-warnings.enabled", false)
 // See eCMSMode in gfx/thebes/gfxPlatform.h
 pref("gfx.color_management.mode", 2);
 pref("gfx.color_management.display_profile", "");
 pref("gfx.color_management.rendering_intent", 0);
 pref("gfx.color_management.enablev4", false);
 
 pref("gfx.downloadable_fonts.enabled", true);
 pref("gfx.downloadable_fonts.fallback_delay", 3000);
+#ifdef RELEASE_BUILD
+pref("gfx.downloadable_fonts.woff2.enabled", false);
+#else
+pref("gfx.downloadable_fonts.woff2.enabled", true);
+#endif
 
 #ifdef ANDROID
 pref("gfx.bundled_fonts.enabled", true);
 pref("gfx.bundled_fonts.force-enabled", false);
 #endif
 
 pref("gfx.filter.nearest.force-enabled", false);