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);
}
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,
uint32_t aOriginalLength,
gfxUserFontType aFontType,
@@ -829,9 +850,11 @@ void gfxUserFontEntry::IncrementGeneration() {
// 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 free().
bool gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
uint32_t aLength,
nsresult aDownloadStatus) {
void gfxUserFontEntry::FontDataDownloadComplete(
const uint8_t* aFontData, uint32_t aLength, nsresult aDownloadStatus,
nsIFontLoadCompleteCallback* aCallback) {
MOZ_ASSERT(NS_IsMainThread());
// forget about the loader, as we no longer potentially need to cancel it
// if the entry is obsoleted
mLoader = nullptr;
@@ -839,27 +862,73 @@ bool gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
// download successful, make platform font using font data
if (NS_SUCCEEDED(aDownloadStatus) &&
mFontDataLoadingState != LOADING_TIMED_OUT) {
bool loaded = LoadPlatformFontSync(aFontData, aLength);
aFontData = nullptr;
if (loaded) {
IncrementGeneration();
return true;
LoadPlatformFontAsync(aFontData, aLength, aCallback);
return;
}
} else {
// download failed
mFontSet->LogMessage(
this,
(mFontDataLoadingState != LOADING_TIMED_OUT ? "download failed"
: "download timed out"),
nsIScriptError::errorFlag, aDownloadStatus);
}
if (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
// load timed out, or else load the next src.
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
// will be used where the text was "masked" by the pending download
IncrementGeneration();
return true;
aCallback->FontLoadComplete();
}
void gfxUserFontEntry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) {
@@ -1295,6 +1364,8 @@ gfxUserFontSet::UserFontCache::MemoryReporter::CollectReports(
return NS_OK;
}
StaticRefPtr<LazyIdleThread> gfxUserFontEntry::sFontLoadingThread;
#ifdef DEBUG_USERFONT_CACHE
void gfxUserFontSet::UserFontCache::Entry::Dump() {

View File

@@ -10,8 +10,10 @@
#include "gfxFontFamilyList.h"
#include "gfxFontSrcPrincipal.h"
#include "gfxFontSrcURI.h"
#include "nsProxyRelease.h"
#include "nsRefPtrHashtable.h"
#include "nsCOMPtr.h"
#include "nsIFontLoadCompleteCallback.h"
#include "nsIMemoryReporter.h"
#include "nsIPrincipal.h"
#include "nsIRunnable.h"
@@ -22,6 +24,8 @@
#include "mozilla/ServoStyleConsts.h"
#include "mozilla/net/ReferrerPolicy.h"
#include "gfxFontConstants.h"
#include "mozilla/LazyIdleThread.h"
#include "mozilla/StaticPtr.h"
class gfxFont;
@@ -635,6 +639,8 @@ class gfxUserFontEntry : public gfxFontEntry {
MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder");
}
static void Shutdown() { sFontLoadingThread = nullptr; }
protected:
const uint8_t* SanitizeOpenTypeData(const uint8_t* aData, uint32_t aLength,
uint32_t& aSaneLength,
@@ -650,12 +656,11 @@ class gfxUserFontEntry : public gfxFontEntry {
// when download has been completed, pass back data here
// 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
// ensure that it is eventually deleted with free().
bool FontDataDownloadComplete(const uint8_t* aFontData, uint32_t aLength,
nsresult aDownloadStatus);
void FontDataDownloadComplete(const uint8_t* aFontData, uint32_t aLength,
nsresult aDownloadStatus,
nsIFontLoadCompleteCallback* aCallback);
// helper method for creating a platform font
// returns true if platform font creation successful
@@ -663,12 +668,32 @@ class gfxUserFontEntry : public gfxFontEntry {
// ensure that it is eventually deleted with free().
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,
uint32_t aOriginalLength, gfxUserFontType aFontType,
const uint8_t* aSanitizedFontData,
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
void StoreUserFontData(gfxFontEntry* aFontEntry, bool aPrivate,
const nsACString& aOriginalName,
@@ -715,6 +740,8 @@ class gfxUserFontEntry : public gfxFontEntry {
gfxUserFontSet* MOZ_NON_OWNING_REF
mFontSet; // font-set which owns this userfont entry
RefPtr<gfxFontSrcPrincipal> mPrincipal;
static mozilla::StaticRefPtr<mozilla::LazyIdleThread> sFontLoadingThread;
};
#endif /* GFX_USER_FONT_SET_H */

View File

@@ -10,6 +10,12 @@ with Files('*Text*'):
with Files('*DWrite*'):
BUG_COMPONENT = ('Core', 'Graphics: Text')
XPIDL_SOURCES += [
'nsIFontLoadCompleteCallback.idl',
]
XPIDL_MODULE = 'gfx'
EXPORTS += [
'DrawMode.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 "nsThreadManager.h"
#include "mozilla/css/ImageLoader.h"
#include "gfxUserFontSet.h"
using namespace mozilla;
using namespace mozilla::net;
@@ -433,4 +434,6 @@ void nsLayoutStatics::Shutdown() {
css::ImageLoader::Shutdown();
mozilla::net::UrlClassifierFeatureFactory::Shutdown();
gfxUserFontEntry::Shutdown();
}

View File

@@ -57,6 +57,11 @@ nsFontFaceLoader::nsFontFaceLoader(gfxUserFontEntry* aUserFontEntry,
MOZ_ASSERT(mFontFaceSet,
"We should get a valid FontFaceSet from the caller!");
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() {
@@ -71,6 +76,7 @@ nsFontFaceLoader::~nsFontFaceLoader() {
}
if (mFontFaceSet) {
mFontFaceSet->RemoveLoader(this);
mFontFaceSet->Document()->UnblockOnload(false);
}
}
@@ -206,6 +212,11 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
DropChannel();
if (mLoadTimer) {
mLoadTimer->Cancel();
mLoadTimer = nullptr;
}
if (!mFontFaceSet) {
// We've been canceled
return aStatus;
@@ -257,19 +268,25 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
}
}
mFontFaceSet->GetUserFontSet()->RecordFontLoadDone(aStringLen, doneTime);
// The userFontEntry is responsible for freeing the downloaded data
// (aString) when finished with it; the pointer is no longer valid
// after FontDataDownloadComplete returns.
// 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),
// 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
if (fontUpdate) {
nsTArray<gfxUserFontSet*> fontSets;
mUserFontEntry->GetUserFontSets(fontSets);
for (gfxUserFontSet* fontSet : fontSets) {
@@ -281,18 +298,13 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
LOG(("userfonts (%p) reflow for pres context %p\n", this, ctx));
}
}
}
MOZ_DIAGNOSTIC_ASSERT(mFontFaceSet);
mFontFaceSet->RemoveLoader(this);
// done with font set
mFontFaceSet->Document()->UnblockOnload(false);
mFontFaceSet = nullptr;
if (mLoadTimer) {
mLoadTimer->Cancel();
mLoadTimer = nullptr;
}
return NS_SUCCESS_ADOPTED_DATA;
return NS_OK;
}
// nsIRequestObserver
@@ -323,6 +335,7 @@ void nsFontFaceLoader::Cancel() {
mUserFontEntry->LoadCanceled();
mUserFontEntry = nullptr;
mFontFaceSet->Document()->UnblockOnload(false);
mFontFaceSet = nullptr;
if (mLoadTimer) {
mLoadTimer->Cancel();

View File

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