bug 467669 - pt 5 - expose WOFF metadata (if present) for downloaded fonts. r=roc
authorJonathan Kew <jfkthame@gmail.com>
Wed, 15 Jun 2011 20:17:52 +0100
changeset 71671 e843b8a89772304318c883ec9df71277f159c45c
parent 71670 66fd359aa53c080b72ccedd667cc463036a6349f
child 71672 a83c312c64ab3d27534776b87324f04e6316059d
push id159
push usereakhgari@mozilla.com
push dateTue, 16 Aug 2011 17:53:11 +0000
treeherdermozilla-beta@8786e3e49240 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs467669
milestone7.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 467669 - pt 5 - expose WOFF metadata (if present) for downloaded fonts. r=roc
gfx/thebes/gfxUserFontSet.cpp
layout/inspector/src/nsFontFace.cpp
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -368,52 +368,113 @@ SanitizeOpenTypeData(const PRUint8* aDat
         return static_cast<PRUint8*>(output.forget());
     } else {
         aSaneLength = 0;
         return nsnull;
     }
 }
 
 static void
-StoreUserFontData(gfxFontEntry* aFontEntry, gfxProxyFontEntry* aProxy)
+StoreUserFontData(gfxFontEntry* aFontEntry, gfxProxyFontEntry* aProxy,
+                  nsTArray<PRUint8>* aMetadata, PRUint32 aMetaOrigLen)
 {
     if (!aFontEntry->mUserFontData) {
         aFontEntry->mUserFontData = new gfxUserFontData;
     }
     gfxUserFontData* userFontData = aFontEntry->mUserFontData;
     userFontData->mSrcIndex = aProxy->mSrcIndex;
     const gfxFontFaceSrc& src = aProxy->mSrcList[aProxy->mSrcIndex];
     if (src.mIsLocal) {
         userFontData->mLocalName = src.mLocalName;
     } else {
         userFontData->mURI = src.mURI;
     }
     userFontData->mFormat = src.mFormatFlags;
+    if (aMetadata) {
+        userFontData->mMetadata.SwapElements(*aMetadata);
+        userFontData->mMetaOrigLen = aMetaOrigLen;
+    }
+}
+
+static void
+CopyWOFFMetadata(const PRUint8* aFontData, PRUint32 aLength,
+                 nsTArray<PRUint8>* aMetadata, PRUint32* 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.
+    struct WOFFHeader {
+        AutoSwap_PRUint32 signature;
+        AutoSwap_PRUint32 flavor;
+        AutoSwap_PRUint32 length;
+        AutoSwap_PRUint16 numTables;
+        AutoSwap_PRUint16 reserved;
+        AutoSwap_PRUint32 totalSfntSize;
+        AutoSwap_PRUint16 majorVersion;
+        AutoSwap_PRUint16 minorVersion;
+        AutoSwap_PRUint32 metaOffset;
+        AutoSwap_PRUint32 metaCompLen;
+        AutoSwap_PRUint32 metaOrigLen;
+        AutoSwap_PRUint32 privOffset;
+        AutoSwap_PRUint32 privLen;
+    };
+    if (aLength < sizeof(WOFFHeader)) {
+        return;
+    }
+    const WOFFHeader* woff = reinterpret_cast<const WOFFHeader*>(aFontData);
+    PRUint32 metaOffset = woff->metaOffset;
+    PRUint32 metaCompLen = woff->metaCompLen;
+    if (!metaOffset || !metaCompLen || !woff->metaOrigLen) {
+        return;
+    }
+    if (metaOffset >= aLength || metaCompLen > aLength - metaOffset) {
+        return;
+    }
+    if (!aMetadata->SetLength(woff->metaCompLen)) {
+        return;
+    }
+    memcpy(aMetadata->Elements(), aFontData + metaOffset, metaCompLen);
+    *aMetaOrigLen = woff->metaOrigLen;
 }
 
 // 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(gfxProxyFontEntry *aProxy,
                                const PRUint8 *aFontData, PRUint32 aLength, 
                                nsresult aDownloadStatus)
 {
     // download successful, make platform font using font data
     if (NS_SUCCEEDED(aDownloadStatus)) {
         gfxFontEntry *fe = nsnull;
 
+        gfxUserFontType fontType =
+            gfxFontUtils::DetermineFontDataType(aFontData, aLength);
+
+        // 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.
+        // NOTE: after the non-OTS codepath using PrepareOpenTypeData is
+        // removed, we should defer this until after we've created the new
+        // fontEntry.
+        nsTArray<PRUint8> metadata;
+        PRUint32 metaOrigLen = 0;
+        if (fontType == GFX_USERFONT_WOFF) {
+            CopyWOFFMetadata(aFontData, aLength, &metadata, &metaOrigLen);
+        }
+
         // Unwrap/decompress/sanitize or otherwise munge the downloaded data
         // to make a usable sfnt structure.
 
         if (gfxPlatform::GetPlatform()->SanitizeDownloadedFonts()) {
-            gfxUserFontType fontType =
-                gfxFontUtils::DetermineFontDataType(aFontData, aLength);
-
-            // Call the OTS sanitizer; this will also decode WOFF to sfnt
+           // Call the OTS sanitizer; this will also decode WOFF to sfnt
             // if necessary. The original data in aFontData is left unchanged.
             PRUint32 saneLen;
             const PRUint8* saneData =
                 SanitizeOpenTypeData(aFontData, aLength, saneLen,
                                      fontType == GFX_USERFONT_WOFF);
 #ifdef DEBUG
             if (!saneData) {
                 char buf[1000];
@@ -459,17 +520,17 @@ gfxUserFontSet::OnLoadComplete(gfxProxyF
             aFontData = nsnull;
         }
 
         if (fe) {
             // copy OpenType feature/language settings from the proxy to the
             // newly-created font entry
             fe->mFeatureSettings.AppendElements(aProxy->mFeatureSettings);
             fe->mLanguageOverride = aProxy->mLanguageOverride;
-            StoreUserFontData(fe, aProxy);
+            StoreUserFontData(fe, aProxy, &metadata, metaOrigLen);
 #ifdef PR_LOGGING
             // must do this before ReplaceFontEntry() because that will
             // clear the proxy's mFamily pointer!
             if (LOG_ENABLED()) {
                 nsCAutoString fontURI;
                 aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
                 LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
                      this, aProxy->mSrcIndex, fontURI.get(),
@@ -551,17 +612,17 @@ gfxUserFontSet::LoadNext(gfxProxyFontEnt
             if (fe) {
                 LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n", 
                      this, aProxyEntry->mSrcIndex, 
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(), 
                      NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get(), 
                      PRUint32(mGeneration)));
                 fe->mFeatureSettings.AppendElements(aProxyEntry->mFeatureSettings);
                 fe->mLanguageOverride = aProxyEntry->mLanguageOverride;
-                StoreUserFontData(fe, aProxyEntry);
+                StoreUserFontData(fe, aProxyEntry, nsnull, 0);
                 ReplaceFontEntry(aProxyEntry, fe);
                 return STATUS_LOADED;
             } else {
                 LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n", 
                      this, aProxyEntry->mSrcIndex, 
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(), 
                      NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));            
             }
--- a/layout/inspector/src/nsFontFace.cpp
+++ b/layout/inspector/src/nsFontFace.cpp
@@ -35,16 +35,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #define _IMPL_NS_LAYOUT
 
 #include "nsFontFace.h"
 #include "nsIDOMCSSFontFaceRule.h"
 #include "nsCSSRules.h"
 #include "gfxUserFontSet.h"
+#include "zlib.h"
 
 nsFontFace::nsFontFace(gfxFontEntry*      aFontEntry,
                        PRUint8            aMatchType,
                        nsCSSFontFaceRule* aRule)
   : mFontEntry(aFontEntry),
     mMatchType(aMatchType),
     mRule(aRule)
 {
@@ -193,10 +194,29 @@ nsFontFace::GetFormat(nsAString & aForma
   }
   return NS_OK;
 }
 
 /* readonly attribute DOMString metadata; */
 NS_IMETHODIMP
 nsFontFace::GetMetadata(nsAString & aMetadata)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  aMetadata.Truncate();
+  if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
+    NS_ASSERTION(mFontEntry->mUserFontData, "missing userFontData");
+    const gfxUserFontData* userFontData = mFontEntry->mUserFontData;
+    if (userFontData->mMetadata.Length() && userFontData->mMetaOrigLen) {
+      nsCAutoString 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);
+        }
+      }
+    }
+  }
+  return NS_OK;
 }