Bug 1490792 - Part 4: Perform OpenType sanitization OMT. r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D33897
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
} else {
|
||||
// download failed
|
||||
mFontSet->LogMessage(
|
||||
this,
|
||||
(mFontDataLoadingState != LOADING_TIMED_OUT ? "download failed"
|
||||
: "download timed out"),
|
||||
nsIScriptError::errorFlag, aDownloadStatus);
|
||||
LoadPlatformFontAsync(aFontData, aLength, aCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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() {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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',
|
||||
|
||||
13
gfx/thebes/nsIFontLoadCompleteCallback.idl
Normal file
13
gfx/thebes/nsIFontLoadCompleteCallback.idl
Normal 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();
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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,42 +268,43 @@ 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) {
|
||||
nsPresContext* ctx = FontFaceSet::GetPresContextFor(fontSet);
|
||||
if (ctx) {
|
||||
// Update layout for the presence of the new font. Since this is
|
||||
// asynchronous, reflows will coalesce.
|
||||
ctx->UserFontSetUpdated(mUserFontEntry);
|
||||
LOG(("userfonts (%p) reflow for pres context %p\n", this, ctx));
|
||||
}
|
||||
nsTArray<gfxUserFontSet*> fontSets;
|
||||
mUserFontEntry->GetUserFontSets(fontSets);
|
||||
for (gfxUserFontSet* fontSet : fontSets) {
|
||||
nsPresContext* ctx = FontFaceSet::GetPresContextFor(fontSet);
|
||||
if (ctx) {
|
||||
// Update layout for the presence of the new font. Since this is
|
||||
// asynchronous, reflows will coalesce.
|
||||
ctx->UserFontSetUpdated(mUserFontEntry);
|
||||
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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user