Bug 1064737 pt 3 - Read metadata from a WOFF2 font if present. r=jdaggett

This commit is contained in:
Jonathan Kew 2014-10-04 11:46:54 +01:00
parent 0d2cfaf334
commit 21fd93a194
4 changed files with 73 additions and 16 deletions

View File

@ -254,7 +254,8 @@ 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;
@ -280,6 +281,7 @@ gfxUserFontEntry::StoreUserFontData(gfxFontEntry* aFontEntry,
if (aMetadata) {
userFontData->mMetadata.SwapElements(*aMetadata);
userFontData->mMetaOrigLen = aMetaOrigLen;
userFontData->mCompression = aCompression;
}
}
@ -317,7 +319,25 @@ struct WOFFHeader {
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,
@ -329,10 +349,11 @@ CopyWOFFMetadata(const uint8_t* aFontData,
// 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) {
@ -397,7 +418,8 @@ gfxUserFontEntry::LoadNextSrc()
// 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;
@ -596,8 +618,15 @@ gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
// 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
@ -606,7 +635,7 @@ gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
fe->mLanguageOverride = mLanguageOverride;
fe->mFamilyName = mFamilyName;
StoreUserFontData(fe, mFontSet->GetPrivateBrowsing(), originalFullName,
&metadata, metaOrigLen);
&metadata, metaOrigLen, compression);
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
nsAutoCString fontURI;

View File

@ -92,7 +92,8 @@ 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() { }
@ -106,8 +107,15 @@ public:
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
@ -603,7 +611,8 @@ protected:
bool aPrivate,
const nsAString& aOriginalName,
FallibleTArray<uint8_t>* aMetadata,
uint32_t aMetaOrigLen);
uint32_t aMetaOrigLen,
uint8_t aCompression);
// general load state
UserFontLoadState mUserFontLoadState;

View File

@ -9,6 +9,7 @@
#include "gfxUserFontSet.h"
#include "nsFontFaceLoader.h"
#include "mozilla/gfx/2D.h"
#include "decode.h"
#include "zlib.h"
#include "mozilla/dom/FontFaceSet.h"
@ -202,13 +203,30 @@ nsFontFace::GetMetadata(nsAString & aMetadata)
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;
}
}
}

View File

@ -612,3 +612,4 @@ 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