Bug 1064737 pt 3 - Read metadata from a WOFF2 font if present. r=jdaggett
authorJonathan Kew <jkew@mozilla.com>
Sat, 04 Oct 2014 11:46:54 +0100
changeset 232033 8845b784128aaa36e3d8f7adcd0c907d70a71fdc
parent 232032 f9c7c0ea55700422809f442ae16bdb2ca6e015c4
child 232034 21e9a5b9a4e388a343f06ed15b430cf5e47436f5
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 3 - Read metadata from a WOFF2 font if present. r=jdaggett
gfx/thebes/gfxUserFontSet.cpp
gfx/thebes/gfxUserFontSet.h
layout/inspector/nsFontFace.cpp
layout/media/symbols.def.in
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -249,17 +249,18 @@ gfxUserFontEntry::SanitizeOpenTypeData(c
     }
 }
 
 void
 gfxUserFontEntry::StoreUserFontData(gfxFontEntry* aFontEntry,
                                     bool aPrivate,
                                     const nsAString& aOriginalName,
                                     FallibleTArray<uint8_t>* aMetadata,
-                                    uint32_t aMetaOrigLen)
+                                    uint32_t aMetaOrigLen,
+                                    uint8_t aCompression)
 {
     if (!aFontEntry->mUserFontData) {
         aFontEntry->mUserFontData = new gfxUserFontData;
     }
     gfxUserFontData* userFontData = aFontEntry->mUserFontData;
     userFontData->mSrcIndex = mSrcIndex;
     const gfxFontFaceSrc& src = mSrcList[mSrcIndex];
     switch (src.mSourceType) {
@@ -275,16 +276,17 @@ gfxUserFontEntry::StoreUserFontData(gfxF
             break;
     }
     userFontData->mPrivate = aPrivate;
     userFontData->mFormat = src.mFormatFlags;
     userFontData->mRealName = aOriginalName;
     if (aMetadata) {
         userFontData->mMetadata.SwapElements(*aMetadata);
         userFontData->mMetaOrigLen = aMetaOrigLen;
+        userFontData->mCompression = aCompression;
     }
 }
 
 void
 gfxUserFontEntry::GetFamilyNameAndURIForLogging(nsACString& aFamilyName,
                                                 nsACString& aURI)
 {
   aFamilyName.Assign(NS_ConvertUTF16toUTF8(mFamilyName));
@@ -312,32 +314,51 @@ struct WOFFHeader {
     AutoSwap_PRUint16 minorVersion;
     AutoSwap_PRUint32 metaOffset;
     AutoSwap_PRUint32 metaCompLen;
     AutoSwap_PRUint32 metaOrigLen;
     AutoSwap_PRUint32 privOffset;
     AutoSwap_PRUint32 privLen;
 };
 
-static void
+struct WOFF2Header {
+    AutoSwap_PRUint32 signature;
+    AutoSwap_PRUint32 flavor;
+    AutoSwap_PRUint32 length;
+    AutoSwap_PRUint16 numTables;
+    AutoSwap_PRUint16 reserved;
+    AutoSwap_PRUint32 totalSfntSize;
+    AutoSwap_PRUint32 totalCompressedSize;
+    AutoSwap_PRUint16 majorVersion;
+    AutoSwap_PRUint16 minorVersion;
+    AutoSwap_PRUint32 metaOffset;
+    AutoSwap_PRUint32 metaCompLen;
+    AutoSwap_PRUint32 metaOrigLen;
+    AutoSwap_PRUint32 privOffset;
+    AutoSwap_PRUint32 privLen;
+};
+
+template<typename HeaderT>
+void
 CopyWOFFMetadata(const uint8_t* aFontData,
                  uint32_t aLength,
                  FallibleTArray<uint8_t>* aMetadata,
                  uint32_t* aMetaOrigLen)
 {
     // This function may be called with arbitrary, unvalidated "font" data
     // from @font-face, so it needs to be careful to bounds-check, etc.,
     // before trying to read anything.
     // This just saves a copy of the compressed data block; it does NOT check
     // that the block can be successfully decompressed, or that it contains
     // well-formed/valid XML metadata.
-    if (aLength < sizeof(WOFFHeader)) {
+    if (aLength < sizeof(HeaderT)) {
         return;
     }
-    const WOFFHeader* woff = reinterpret_cast<const WOFFHeader*>(aFontData);
+    const HeaderT* woff =
+        reinterpret_cast<const HeaderT*>(aFontData);
     uint32_t metaOffset = woff->metaOffset;
     uint32_t metaCompLen = woff->metaCompLen;
     if (!metaOffset || !metaCompLen || !woff->metaOrigLen) {
         return;
     }
     if (metaOffset >= aLength || metaCompLen > aLength - metaOffset) {
         return;
     }
@@ -392,17 +413,18 @@ gfxUserFontEntry::LoadNextSrc()
                      NS_ConvertUTF16toUTF8(mFamilyName).get(),
                      uint32_t(mFontSet->mGeneration)));
                 fe->mFeatureSettings.AppendElements(mFeatureSettings);
                 fe->mLanguageOverride = mLanguageOverride;
                 fe->mFamilyName = mFamilyName;
                 // For src:local(), we don't care whether the request is from
                 // a private window as there's no issue of caching resources;
                 // local fonts are just available all the time.
-                StoreUserFontData(fe, false, nsString(), nullptr, 0);
+                StoreUserFontData(fe, false, nsString(), nullptr, 0,
+                                  gfxUserFontData::kUnknownCompression);
                 mPlatformFontEntry = fe;
                 SetLoadState(STATUS_LOADED);
                 return;
             } else {
                 LOG(("fontset (%p) [src %d] failed local: (%s) for (%s)\n",
                      mFontSet, mSrcIndex,
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
                      NS_ConvertUTF16toUTF8(mFamilyName).get()));
@@ -591,27 +613,34 @@ gfxUserFontEntry::LoadPlatformFont(const
     }
 
     if (fe) {
         // Save a copy of the metadata block (if present) for nsIDOMFontFace
         // to use if required. Ownership of the metadata block will be passed
         // to the gfxUserFontData record below.
         FallibleTArray<uint8_t> metadata;
         uint32_t metaOrigLen = 0;
+        uint8_t compression = gfxUserFontData::kUnknownCompression;
         if (fontType == GFX_USERFONT_WOFF) {
-            CopyWOFFMetadata(aFontData, aLength, &metadata, &metaOrigLen);
+            CopyWOFFMetadata<WOFFHeader>(aFontData, aLength,
+                                         &metadata, &metaOrigLen);
+            compression = gfxUserFontData::kZlibCompression;
+        } else if (fontType == GFX_USERFONT_WOFF2) {
+            CopyWOFFMetadata<WOFF2Header>(aFontData, aLength,
+                                          &metadata, &metaOrigLen);
+            compression = gfxUserFontData::kBrotliCompression;
         }
 
         // copy OpenType feature/language settings from the userfont entry to the
         // newly-created font entry
         fe->mFeatureSettings.AppendElements(mFeatureSettings);
         fe->mLanguageOverride = mLanguageOverride;
         fe->mFamilyName = mFamilyName;
         StoreUserFontData(fe, mFontSet->GetPrivateBrowsing(), originalFullName,
-                          &metadata, metaOrigLen);
+                          &metadata, metaOrigLen, compression);
 #ifdef PR_LOGGING
         if (LOG_ENABLED()) {
             nsAutoCString fontURI;
             mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
             LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
                  this, mSrcIndex, fontURI.get(),
                  NS_ConvertUTF16toUTF8(mFamilyName).get(),
                  uint32_t(mFontSet->mGeneration)));
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -87,32 +87,40 @@ operator==(const gfxFontFaceSrc& a, cons
 // Lifetime: from when platform font is created until it is deactivated.
 // If the platform does not need to add any platform-specific code/data here,
 // then the gfxUserFontSet will allocate a base gfxUserFontData and attach
 // to the entry to track the basic user font info fields here.
 class gfxUserFontData {
 public:
     gfxUserFontData()
         : mSrcIndex(0), mFormat(0), mMetaOrigLen(0),
-          mCRC32(0), mLength(0), mPrivate(false), mIsBuffer(false)
+          mCRC32(0), mLength(0), mCompression(kUnknownCompression),
+          mPrivate(false), mIsBuffer(false)
     { }
     virtual ~gfxUserFontData() { }
 
     nsTArray<uint8_t> mMetadata;  // woff metadata block (compressed), if any
     nsCOMPtr<nsIURI>  mURI;       // URI of the source, if it was url()
     nsCOMPtr<nsIPrincipal> mPrincipal; // principal for the download, if url()
     nsString          mLocalName; // font name used for the source, if local()
     nsString          mRealName;  // original fullname from the font resource
     uint32_t          mSrcIndex;  // index in the rule's source list
     uint32_t          mFormat;    // format hint for the source used, if any
     uint32_t          mMetaOrigLen; // length needed to decompress metadata
     uint32_t          mCRC32;     // Checksum
     uint32_t          mLength;    // Font length
+    uint8_t           mCompression; // compression type
     bool              mPrivate;   // whether font belongs to a private window
     bool              mIsBuffer;  // whether the font source was a buffer
+
+    enum {
+        kUnknownCompression = 0,
+        kZlibCompression = 1,
+        kBrotliCompression = 2
+    };
 };
 
 // initially contains a set of userfont font entry objects, replaced with
 // platform/user fonts as downloaded
 
 class gfxUserFontFamily : public gfxFontFamily {
 public:
     friend class gfxUserFontSet;
@@ -598,17 +606,18 @@ protected:
     // ensure that it is eventually deleted with NS_Free().
     bool LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength);
 
     // store metadata and src details for current src into aFontEntry
     void StoreUserFontData(gfxFontEntry*      aFontEntry,
                            bool               aPrivate,
                            const nsAString&   aOriginalName,
                            FallibleTArray<uint8_t>* aMetadata,
-                           uint32_t           aMetaOrigLen);
+                           uint32_t           aMetaOrigLen,
+                           uint8_t            aCompression);
 
     // general load state
     UserFontLoadState        mUserFontLoadState;
 
     // detailed load state while font data is loading
     // used to determine whether to use fallback font or not
     // note that code depends on the ordering of these values!
     enum FontDataLoadingState {
--- a/layout/inspector/nsFontFace.cpp
+++ b/layout/inspector/nsFontFace.cpp
@@ -4,16 +4,17 @@
 
 #include "nsFontFace.h"
 #include "nsIDOMCSSFontFaceRule.h"
 #include "nsCSSRules.h"
 #include "gfxTextRun.h"
 #include "gfxUserFontSet.h"
 #include "nsFontFaceLoader.h"
 #include "mozilla/gfx/2D.h"
+#include "decode.h"
 #include "zlib.h"
 #include "mozilla/dom/FontFaceSet.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsFontFace::nsFontFace(gfxFontEntry*      aFontEntry,
                        gfxFontGroup*      aFontGroup,
@@ -197,21 +198,38 @@ nsFontFace::GetMetadata(nsAString & aMet
   aMetadata.Truncate();
   if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
     NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
     const gfxUserFontData* userFontData = mFontEntry->mUserFontData;
     if (userFontData->mMetadata.Length() && userFontData->mMetaOrigLen) {
       nsAutoCString str;
       str.SetLength(userFontData->mMetaOrigLen);
       if (str.Length() == userFontData->mMetaOrigLen) {
-        uLongf destLen = userFontData->mMetaOrigLen;
-        if (uncompress((Bytef *)(str.BeginWriting()), &destLen,
-                       (const Bytef *)(userFontData->mMetadata.Elements()),
-                       userFontData->mMetadata.Length()) == Z_OK &&
-            destLen == userFontData->mMetaOrigLen)
-        {
-          AppendUTF8toUTF16(str, aMetadata);
+        switch (userFontData->mCompression) {
+        case gfxUserFontData::kZlibCompression:
+          {
+            uLongf destLen = userFontData->mMetaOrigLen;
+            if (uncompress((Bytef *)(str.BeginWriting()), &destLen,
+                           (const Bytef *)(userFontData->mMetadata.Elements()),
+                           userFontData->mMetadata.Length()) == Z_OK &&
+                destLen == userFontData->mMetaOrigLen) {
+              AppendUTF8toUTF16(str, aMetadata);
+            }
+          }
+          break;
+        case gfxUserFontData::kBrotliCompression:
+          {
+            size_t decodedSize = userFontData->mMetaOrigLen;
+            if (BrotliDecompressBuffer(userFontData->mMetadata.Length(),
+                                       userFontData->mMetadata.Elements(),
+                                       &decodedSize,
+                                       (uint8_t*)str.BeginWriting()) == 1 &&
+                decodedSize == userFontData->mMetaOrigLen) {
+              AppendUTF8toUTF16(str, aMetadata);
+            }
+          }
+          break;
         }
       }
     }
   }
   return NS_OK;
 }
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -607,8 +607,9 @@ hb_unicode_funcs_create
 hb_unicode_funcs_get_empty
 hb_unicode_funcs_set_combining_class_func
 hb_unicode_funcs_set_compose_func
 hb_unicode_funcs_set_decompose_func
 hb_unicode_funcs_set_eastasian_width_func
 hb_unicode_funcs_set_general_category_func
 hb_unicode_funcs_set_mirroring_func
 hb_unicode_funcs_set_script_func
+BrotliDecompressBuffer