Bug 1490792 - Part 4: Perform OpenType sanitization OMT. r=jfkthame

Differential Revision: https://phabricator.services.mozilla.com/D33897
This commit is contained in:
Cameron McCormack
2019-06-06 19:08:52 +00:00
parent 24fb837902
commit 8eee8c8dc9
7 changed files with 184 additions and 45 deletions

View File

@@ -688,6 +688,27 @@ bool gfxUserFontEntry::LoadPlatformFontSync(const uint8_t* aFontData,
return LoadPlatformFont(aFontData, aLength, fontType, saneData, saneLen); return LoadPlatformFont(aFontData, aLength, fontType, saneData, saneLen);
} }
void gfxUserFontEntry::StartPlatformFontLoadOnWorkerThread(
const uint8_t* aFontData, uint32_t aLength,
nsMainThreadPtrHandle<nsIFontLoadCompleteCallback> aCallback) {
MOZ_ASSERT(sFontLoadingThread);
MOZ_ASSERT(sFontLoadingThread->IsOnCurrentThread());
uint32_t saneLen;
gfxUserFontType fontType;
const uint8_t* saneData =
SanitizeOpenTypeData(aFontData, aLength, saneLen, fontType);
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod<const uint8_t*, uint32_t, gfxUserFontType,
const uint8_t*, uint32_t,
nsMainThreadPtrHandle<nsIFontLoadCompleteCallback>>(
"gfxUserFontEntry::ContinuePlatformFontLoadOnMainThread", this,
&gfxUserFontEntry::ContinuePlatformFontLoadOnMainThread, aFontData,
aLength, fontType, saneData, saneLen, aCallback);
NS_DispatchToMainThread(event.forget());
}
bool gfxUserFontEntry::LoadPlatformFont(const uint8_t* aOriginalFontData, bool gfxUserFontEntry::LoadPlatformFont(const uint8_t* aOriginalFontData,
uint32_t aOriginalLength, uint32_t aOriginalLength,
gfxUserFontType aFontType, gfxUserFontType aFontType,
@@ -829,9 +850,11 @@ void gfxUserFontEntry::IncrementGeneration() {
// This is called when a font download finishes. // This is called when a font download finishes.
// Ownership of aFontData passes in here, and the font set must // Ownership of aFontData passes in here, and the font set must
// ensure that it is eventually deleted via free(). // ensure that it is eventually deleted via free().
bool gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData, void gfxUserFontEntry::FontDataDownloadComplete(
uint32_t aLength, const uint8_t* aFontData, uint32_t aLength, nsresult aDownloadStatus,
nsresult aDownloadStatus) { nsIFontLoadCompleteCallback* aCallback) {
MOZ_ASSERT(NS_IsMainThread());
// forget about the loader, as we no longer potentially need to cancel it // forget about the loader, as we no longer potentially need to cancel it
// if the entry is obsoleted // if the entry is obsoleted
mLoader = nullptr; mLoader = nullptr;
@@ -839,27 +862,73 @@ bool gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
// download successful, make platform font using font data // download successful, make platform font using font data
if (NS_SUCCEEDED(aDownloadStatus) && if (NS_SUCCEEDED(aDownloadStatus) &&
mFontDataLoadingState != LOADING_TIMED_OUT) { mFontDataLoadingState != LOADING_TIMED_OUT) {
bool loaded = LoadPlatformFontSync(aFontData, aLength); LoadPlatformFontAsync(aFontData, aLength, aCallback);
aFontData = nullptr; return;
if (loaded) {
IncrementGeneration();
return true;
} }
} else {
// download failed // download failed
mFontSet->LogMessage( mFontSet->LogMessage(
this, this,
(mFontDataLoadingState != LOADING_TIMED_OUT ? "download failed" (mFontDataLoadingState != LOADING_TIMED_OUT ? "download failed"
: "download timed out"), : "download timed out"),
nsIScriptError::errorFlag, aDownloadStatus); nsIScriptError::errorFlag, aDownloadStatus);
}
if (aFontData) { if (aFontData) {
free((void*)aFontData); free((void*)aFontData);
} }
FontLoadFailed(aCallback);
}
void gfxUserFontEntry::LoadPlatformFontAsync(
const uint8_t* aFontData, uint32_t aLength,
nsIFontLoadCompleteCallback* aCallback) {
// Ensure the font loading thread is available.
if (!sFontLoadingThread) {
sFontLoadingThread =
new LazyIdleThread(5000, NS_LITERAL_CSTRING("FontLoader"));
}
nsMainThreadPtrHandle<nsIFontLoadCompleteCallback> cb(
new nsMainThreadPtrHolder<nsIFontLoadCompleteCallback>("FontLoader",
aCallback));
// Do the OpenType sanitization over on the font loading thread. Once that is
// complete, we'll continue in ContinuePlatformFontLoadOnMainThread.
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod<const uint8_t*, uint32_t,
nsMainThreadPtrHandle<nsIFontLoadCompleteCallback>>(
"gfxUserFontEntry::StartPlatformFontLoadOnWorkerThread", this,
&gfxUserFontEntry::StartPlatformFontLoadOnWorkerThread, aFontData,
aLength, cb);
MOZ_ALWAYS_SUCCEEDS(
sFontLoadingThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL));
}
void gfxUserFontEntry::ContinuePlatformFontLoadOnMainThread(
const uint8_t* aOriginalFontData, uint32_t aOriginalLength,
gfxUserFontType aFontType, const uint8_t* aSanitizedFontData,
uint32_t aSanitizedLength,
nsMainThreadPtrHandle<nsIFontLoadCompleteCallback> aCallback) {
MOZ_ASSERT(NS_IsMainThread());
bool loaded = LoadPlatformFont(aOriginalFontData, aOriginalLength, aFontType,
aSanitizedFontData, aSanitizedLength);
aOriginalFontData = nullptr;
aSanitizedFontData = nullptr;
if (loaded) {
IncrementGeneration();
aCallback->FontLoadComplete();
return;
}
FontLoadFailed(aCallback);
}
void gfxUserFontEntry::FontLoadFailed(nsIFontLoadCompleteCallback* aCallback) {
MOZ_ASSERT(NS_IsMainThread());
// Error occurred. Make sure the FontFace's promise is rejected if the // Error occurred. Make sure the FontFace's promise is rejected if the
// load timed out, or else load the next src. // load timed out, or else load the next src.
if (mFontDataLoadingState == LOADING_TIMED_OUT) { if (mFontDataLoadingState == LOADING_TIMED_OUT) {
@@ -874,7 +943,7 @@ bool gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
// and return true in order to trigger reflow, so that fallback // and return true in order to trigger reflow, so that fallback
// will be used where the text was "masked" by the pending download // will be used where the text was "masked" by the pending download
IncrementGeneration(); IncrementGeneration();
return true; aCallback->FontLoadComplete();
} }
void gfxUserFontEntry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) { void gfxUserFontEntry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) {
@@ -1295,6 +1364,8 @@ gfxUserFontSet::UserFontCache::MemoryReporter::CollectReports(
return NS_OK; return NS_OK;
} }
StaticRefPtr<LazyIdleThread> gfxUserFontEntry::sFontLoadingThread;
#ifdef DEBUG_USERFONT_CACHE #ifdef DEBUG_USERFONT_CACHE
void gfxUserFontSet::UserFontCache::Entry::Dump() { void gfxUserFontSet::UserFontCache::Entry::Dump() {

View File

@@ -10,8 +10,10 @@
#include "gfxFontFamilyList.h" #include "gfxFontFamilyList.h"
#include "gfxFontSrcPrincipal.h" #include "gfxFontSrcPrincipal.h"
#include "gfxFontSrcURI.h" #include "gfxFontSrcURI.h"
#include "nsProxyRelease.h"
#include "nsRefPtrHashtable.h" #include "nsRefPtrHashtable.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsIFontLoadCompleteCallback.h"
#include "nsIMemoryReporter.h" #include "nsIMemoryReporter.h"
#include "nsIPrincipal.h" #include "nsIPrincipal.h"
#include "nsIRunnable.h" #include "nsIRunnable.h"
@@ -22,6 +24,8 @@
#include "mozilla/ServoStyleConsts.h" #include "mozilla/ServoStyleConsts.h"
#include "mozilla/net/ReferrerPolicy.h" #include "mozilla/net/ReferrerPolicy.h"
#include "gfxFontConstants.h" #include "gfxFontConstants.h"
#include "mozilla/LazyIdleThread.h"
#include "mozilla/StaticPtr.h"
class gfxFont; class gfxFont;
@@ -635,6 +639,8 @@ class gfxUserFontEntry : public gfxFontEntry {
MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder"); MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder");
} }
static void Shutdown() { sFontLoadingThread = nullptr; }
protected: protected:
const uint8_t* SanitizeOpenTypeData(const uint8_t* aData, uint32_t aLength, const uint8_t* SanitizeOpenTypeData(const uint8_t* aData, uint32_t aLength,
uint32_t& aSaneLength, uint32_t& aSaneLength,
@@ -650,12 +656,11 @@ class gfxUserFontEntry : public gfxFontEntry {
// when download has been completed, pass back data here // when download has been completed, pass back data here
// aDownloadStatus == NS_OK ==> download succeeded, error otherwise // aDownloadStatus == NS_OK ==> download succeeded, error otherwise
// returns true if platform font creation sucessful (or local()
// reference was next in line)
// Ownership of aFontData is passed in here; the font set must // Ownership of aFontData is passed in here; the font set must
// ensure that it is eventually deleted with free(). // ensure that it is eventually deleted with free().
bool FontDataDownloadComplete(const uint8_t* aFontData, uint32_t aLength, void FontDataDownloadComplete(const uint8_t* aFontData, uint32_t aLength,
nsresult aDownloadStatus); nsresult aDownloadStatus,
nsIFontLoadCompleteCallback* aCallback);
// helper method for creating a platform font // helper method for creating a platform font
// returns true if platform font creation successful // returns true if platform font creation successful
@@ -663,12 +668,32 @@ class gfxUserFontEntry : public gfxFontEntry {
// ensure that it is eventually deleted with free(). // ensure that it is eventually deleted with free().
bool LoadPlatformFontSync(const uint8_t* aFontData, uint32_t aLength); bool LoadPlatformFontSync(const uint8_t* aFontData, uint32_t aLength);
// helper method for LoadPlatformFontSync void LoadPlatformFontAsync(const uint8_t* aFontData, uint32_t aLength,
nsIFontLoadCompleteCallback* aCallback);
// helper method for LoadPlatformFontAsync; runs on the FontLoader thread
void StartPlatformFontLoadOnWorkerThread(
const uint8_t* aFontData, uint32_t aLength,
nsMainThreadPtrHandle<nsIFontLoadCompleteCallback> aCallback);
// helper method for LoadPlatformFontAsync; runs on the main thread
void ContinuePlatformFontLoadOnMainThread(
const uint8_t* aOriginalFontData, uint32_t aOriginalLength,
gfxUserFontType aFontType, const uint8_t* aSanitizedFontData,
uint32_t aSanitizedLength,
nsMainThreadPtrHandle<nsIFontLoadCompleteCallback> aCallback);
// helper method for LoadPlatformFontSync and
// ContinuePlatformFontLoadOnMainThread; runs on the main thread
bool LoadPlatformFont(const uint8_t* aOriginalFontData, bool LoadPlatformFont(const uint8_t* aOriginalFontData,
uint32_t aOriginalLength, gfxUserFontType aFontType, uint32_t aOriginalLength, gfxUserFontType aFontType,
const uint8_t* aSanitizedFontData, const uint8_t* aSanitizedFontData,
uint32_t aSanitizedLength); uint32_t aSanitizedLength);
// helper method for FontDataDownloadComplete and
// ContinuePlatformFontLoadOnMainThread; runs on the main thread
void FontLoadFailed(nsIFontLoadCompleteCallback* aCallback);
// store metadata and src details for current src into aFontEntry // store metadata and src details for current src into aFontEntry
void StoreUserFontData(gfxFontEntry* aFontEntry, bool aPrivate, void StoreUserFontData(gfxFontEntry* aFontEntry, bool aPrivate,
const nsACString& aOriginalName, const nsACString& aOriginalName,
@@ -715,6 +740,8 @@ class gfxUserFontEntry : public gfxFontEntry {
gfxUserFontSet* MOZ_NON_OWNING_REF gfxUserFontSet* MOZ_NON_OWNING_REF
mFontSet; // font-set which owns this userfont entry mFontSet; // font-set which owns this userfont entry
RefPtr<gfxFontSrcPrincipal> mPrincipal; RefPtr<gfxFontSrcPrincipal> mPrincipal;
static mozilla::StaticRefPtr<mozilla::LazyIdleThread> sFontLoadingThread;
}; };
#endif /* GFX_USER_FONT_SET_H */ #endif /* GFX_USER_FONT_SET_H */

View File

@@ -10,6 +10,12 @@ with Files('*Text*'):
with Files('*DWrite*'): with Files('*DWrite*'):
BUG_COMPONENT = ('Core', 'Graphics: Text') BUG_COMPONENT = ('Core', 'Graphics: Text')
XPIDL_SOURCES += [
'nsIFontLoadCompleteCallback.idl',
]
XPIDL_MODULE = 'gfx'
EXPORTS += [ EXPORTS += [
'DrawMode.h', 'DrawMode.h',
'gfx2DGlue.h', 'gfx2DGlue.h',

View File

@@ -0,0 +1,13 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
[uuid(302dbf09-079b-4648-8a06-a0486c1749c0)]
interface nsIFontLoadCompleteCallback : nsISupports
{
void fontLoadComplete();
};

View File

@@ -129,6 +129,7 @@
#include "mozilla/net/UrlClassifierFeatureFactory.h" #include "mozilla/net/UrlClassifierFeatureFactory.h"
#include "nsThreadManager.h" #include "nsThreadManager.h"
#include "mozilla/css/ImageLoader.h" #include "mozilla/css/ImageLoader.h"
#include "gfxUserFontSet.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::net; using namespace mozilla::net;
@@ -433,4 +434,6 @@ void nsLayoutStatics::Shutdown() {
css::ImageLoader::Shutdown(); css::ImageLoader::Shutdown();
mozilla::net::UrlClassifierFeatureFactory::Shutdown(); mozilla::net::UrlClassifierFeatureFactory::Shutdown();
gfxUserFontEntry::Shutdown();
} }

View File

@@ -57,6 +57,11 @@ nsFontFaceLoader::nsFontFaceLoader(gfxUserFontEntry* aUserFontEntry,
MOZ_ASSERT(mFontFaceSet, MOZ_ASSERT(mFontFaceSet,
"We should get a valid FontFaceSet from the caller!"); "We should get a valid FontFaceSet from the caller!");
mStartTime = TimeStamp::Now(); mStartTime = TimeStamp::Now();
// We add an explicit load block rather than just rely on the network
// request's block, since we need to do some OMT work after the load
// is finished before we unblock load.
mFontFaceSet->Document()->BlockOnload();
} }
nsFontFaceLoader::~nsFontFaceLoader() { nsFontFaceLoader::~nsFontFaceLoader() {
@@ -71,6 +76,7 @@ nsFontFaceLoader::~nsFontFaceLoader() {
} }
if (mFontFaceSet) { if (mFontFaceSet) {
mFontFaceSet->RemoveLoader(this); mFontFaceSet->RemoveLoader(this);
mFontFaceSet->Document()->UnblockOnload(false);
} }
} }
@@ -206,6 +212,11 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
DropChannel(); DropChannel();
if (mLoadTimer) {
mLoadTimer->Cancel();
mLoadTimer = nullptr;
}
if (!mFontFaceSet) { if (!mFontFaceSet) {
// We've been canceled // We've been canceled
return aStatus; return aStatus;
@@ -257,19 +268,25 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
} }
} }
mFontFaceSet->GetUserFontSet()->RecordFontLoadDone(aStringLen, doneTime);
// The userFontEntry is responsible for freeing the downloaded data // The userFontEntry is responsible for freeing the downloaded data
// (aString) when finished with it; the pointer is no longer valid // (aString) when finished with it; the pointer is no longer valid
// after FontDataDownloadComplete returns. // after FontDataDownloadComplete returns.
// This is called even in the case of a failed download (HTTP 404, etc), // This is called even in the case of a failed download (HTTP 404, etc),
// as there may still be data to be freed (e.g. an error page), // as there may still be data to be freed (e.g. an error page),
// and we need to load the next source. // and we need to load the next source.
bool fontUpdate =
mUserFontEntry->FontDataDownloadComplete(aString, aStringLen, aStatus);
mFontFaceSet->GetUserFontSet()->RecordFontLoadDone(aStringLen, doneTime); // FontDataDownloadComplete will load the platform font on a worker thread,
// and will call FontLoadComplete when it has finished its work.
mUserFontEntry->FontDataDownloadComplete(aString, aStringLen, aStatus, this);
return NS_SUCCESS_ADOPTED_DATA;
}
nsresult nsFontFaceLoader::FontLoadComplete() {
MOZ_ASSERT(NS_IsMainThread());
// when new font loaded, need to reflow // when new font loaded, need to reflow
if (fontUpdate) {
nsTArray<gfxUserFontSet*> fontSets; nsTArray<gfxUserFontSet*> fontSets;
mUserFontEntry->GetUserFontSets(fontSets); mUserFontEntry->GetUserFontSets(fontSets);
for (gfxUserFontSet* fontSet : fontSets) { for (gfxUserFontSet* fontSet : fontSets) {
@@ -281,18 +298,13 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
LOG(("userfonts (%p) reflow for pres context %p\n", this, ctx)); LOG(("userfonts (%p) reflow for pres context %p\n", this, ctx));
} }
} }
}
MOZ_DIAGNOSTIC_ASSERT(mFontFaceSet); MOZ_DIAGNOSTIC_ASSERT(mFontFaceSet);
mFontFaceSet->RemoveLoader(this); mFontFaceSet->RemoveLoader(this);
// done with font set mFontFaceSet->Document()->UnblockOnload(false);
mFontFaceSet = nullptr; mFontFaceSet = nullptr;
if (mLoadTimer) {
mLoadTimer->Cancel();
mLoadTimer = nullptr;
}
return NS_SUCCESS_ADOPTED_DATA; return NS_OK;
} }
// nsIRequestObserver // nsIRequestObserver
@@ -323,6 +335,7 @@ void nsFontFaceLoader::Cancel() {
mUserFontEntry->LoadCanceled(); mUserFontEntry->LoadCanceled();
mUserFontEntry = nullptr; mUserFontEntry = nullptr;
mFontFaceSet->Document()->UnblockOnload(false);
mFontFaceSet = nullptr; mFontFaceSet = nullptr;
if (mLoadTimer) { if (mLoadTimer) {
mLoadTimer->Cancel(); mLoadTimer->Cancel();

View File

@@ -13,6 +13,7 @@
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "mozilla/dom/FontFaceSet.h" #include "mozilla/dom/FontFaceSet.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsIFontLoadCompleteCallback.h"
#include "nsIStreamLoader.h" #include "nsIStreamLoader.h"
#include "nsIChannel.h" #include "nsIChannel.h"
#include "nsIRequestObserver.h" #include "nsIRequestObserver.h"
@@ -23,7 +24,8 @@
class nsIPrincipal; class nsIPrincipal;
class nsFontFaceLoader final : public nsIStreamLoaderObserver, class nsFontFaceLoader final : public nsIStreamLoaderObserver,
public nsIRequestObserver { public nsIRequestObserver,
public nsIFontLoadCompleteCallback {
public: public:
nsFontFaceLoader(gfxUserFontEntry* aFontToLoad, nsIURI* aFontURI, nsFontFaceLoader(gfxUserFontEntry* aFontToLoad, nsIURI* aFontURI,
mozilla::dom::FontFaceSet* aFontFaceSet, mozilla::dom::FontFaceSet* aFontFaceSet,
@@ -46,6 +48,10 @@ class nsFontFaceLoader final : public nsIStreamLoaderObserver,
gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; } gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
// Called by the gfxUserFontEntry once it has finished the platform font
// loading.
NS_IMETHODIMP FontLoadComplete() final;
protected: protected:
virtual ~nsFontFaceLoader(); virtual ~nsFontFaceLoader();