Bug 1163877 - Part 3: Update state on, and reflow documents for, all FontFaceSets that contain a FontFace whose user font entry updated. r=jdaggett

This commit is contained in:
Cameron McCormack 2015-10-16 17:10:14 +11:00
parent a049f1a983
commit 4872fb60dc
6 changed files with 90 additions and 18 deletions

View File

@ -413,7 +413,13 @@ gfxUserFontEntry::LoadNextSrc()
mWeight,
mStretch,
mItalic);
mFontSet->SetLocalRulesUsed();
nsTArray<gfxUserFontSet*> fontSets;
GetUserFontSets(fontSets);
for (gfxUserFontSet* fontSet : fontSets) {
// We need to note on each gfxUserFontSet that contains the user
// font entry that we used a local() rule.
fontSet->SetLocalRulesUsed();
}
if (fe) {
LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
mFontSet, mSrcIndex,
@ -680,6 +686,16 @@ gfxUserFontEntry::Load()
}
}
void
gfxUserFontEntry::IncrementGeneration()
{
nsTArray<gfxUserFontSet*> fontSets;
GetUserFontSets(fontSets);
for (gfxUserFontSet* fontSet : fontSets) {
fontSet->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().
@ -698,7 +714,7 @@ gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
aFontData = nullptr;
if (loaded) {
mFontSet->IncrementGeneration();
IncrementGeneration();
return true;
}
@ -720,10 +736,17 @@ gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
// even if loading failed, we need to bump the font-set generation
// and return true in order to trigger reflow, so that fallback
// will be used where the text was "masked" by the pending download
mFontSet->IncrementGeneration();
IncrementGeneration();
return true;
}
void
gfxUserFontEntry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult)
{
aResult.Clear();
aResult.AppendElement(mFontSet);
}
gfxUserFontSet::gfxUserFontSet()
: mFontFamilies(4), mLocalRulesUsed(false)
{

View File

@ -625,6 +625,15 @@ protected:
uint32_t aMetaOrigLen,
uint8_t aCompression);
// Clears and then adds to aResult all of the user font sets that this user
// font entry has been added to. This will at least include mFontSet, the
// owner of this user font entry.
virtual void GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult);
// Calls IncrementGeneration() on all user font sets that contain this
// user font entry.
void IncrementGeneration();
// general load state
UserFontLoadState mUserFontLoadState;
@ -650,7 +659,7 @@ protected:
// This field is managed by the nsFontFaceLoader. In the destructor and Cancel()
// methods of nsFontFaceLoader this reference is nulled out.
nsFontFaceLoader* MOZ_NON_OWNING_REF mLoader; // current loader for this entry, if any
gfxUserFontSet* mFontSet; // font-set to which the userfont entry belongs
gfxUserFontSet* mFontSet; // font-set which owns this userfont entry
nsCOMPtr<nsIPrincipal> mPrincipal;
};

View File

@ -5,6 +5,7 @@
#include "mozilla/dom/FontFace.h"
#include <algorithm>
#include "mozilla/dom/FontFaceBinding.h"
#include "mozilla/dom/FontFaceSet.h"
#include "mozilla/dom/Promise.h"
@ -737,5 +738,25 @@ FontFace::Entry::SetLoadState(UserFontLoadState aLoadState)
}
}
/* virtual */ void
FontFace::Entry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult)
{
aResult.Clear();
for (FontFace* f : mFontFaces) {
if (f->mInFontFaceSet) {
aResult.AppendElement(f->mFontFaceSet->GetUserFontSet());
}
for (FontFaceSet* s : f->mOtherFontFaceSets) {
aResult.AppendElement(s->GetUserFontSet());
}
}
// Remove duplicates.
aResult.Sort();
auto it = std::unique(aResult.begin(), aResult.end());
aResult.TruncateLength(it - aResult.begin());
}
} // namespace dom
} // namespace mozilla

View File

@ -53,6 +53,7 @@ public:
aUnicodeRanges) {}
virtual void SetLoadState(UserFontLoadState aLoadState) override;
virtual void GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) override;
const nsAutoTArray<FontFace*,1>& GetFontFaces() { return mFontFaces; }
protected:

View File

@ -149,6 +149,12 @@ public:
void FlushUserFontSet();
static nsPresContext* GetPresContextFor(gfxUserFontSet* aUserFontSet)
{
FontFaceSet* set = static_cast<UserFontSet*>(aUserFontSet)->mFontFaceSet;
return set ? set->GetPresContext() : nullptr;
}
// -- Web IDL --------------------------------------------------------------
IMPL_EVENT_HANDLER(loading)

View File

@ -24,6 +24,7 @@
#include "mozilla/gfx/2D.h"
using namespace mozilla;
using namespace mozilla::dom;
#define LOG(args) MOZ_LOG(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug, args)
#define LOG_ENABLED() MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), \
@ -31,7 +32,7 @@ using namespace mozilla;
nsFontFaceLoader::nsFontFaceLoader(gfxUserFontEntry* aUserFontEntry,
nsIURI* aFontURI,
mozilla::dom::FontFaceSet* aFontFaceSet,
FontFaceSet* aFontFaceSet,
nsIChannel* aChannel)
: mUserFontEntry(aUserFontEntry),
mFontURI(aFontURI),
@ -73,7 +74,7 @@ nsFontFaceLoader::StartedLoading(nsIStreamLoader* aStreamLoader)
mStreamLoader = aStreamLoader;
}
void
/* static */ void
nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure)
{
nsFontFaceLoader* loader = static_cast<nsFontFaceLoader*>(aClosure);
@ -117,11 +118,16 @@ nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure)
// font will be used in the meantime, and tell the context to refresh.
if (updateUserFontSet) {
ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
nsPresContext* ctx = loader->mFontFaceSet->GetPresContext();
if (ctx) {
loader->mFontFaceSet->IncrementGeneration();
ctx->UserFontSetUpdated(loader->GetUserFontEntry());
LOG(("userfonts (%p) timeout reflow\n", loader));
nsTArray<gfxUserFontSet*> fontSets;
ufe->GetUserFontSets(fontSets);
for (gfxUserFontSet* fontSet : fontSets) {
nsPresContext* ctx = FontFaceSet::GetPresContextFor(fontSet);
if (ctx) {
fontSet->IncrementGeneration();
ctx->UserFontSetUpdated(ufe);
LOG(("userfonts (%p) timeout reflow for pres context %p\n",
loader, ctx));
}
}
}
}
@ -179,16 +185,22 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
// 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.
nsPresContext* ctx = mFontFaceSet->GetPresContext();
bool fontUpdate =
mUserFontEntry->FontDataDownloadComplete(aString, aStringLen, aStatus);
// when new font loaded, need to reflow
if (fontUpdate && ctx) {
// Update layout for the presence of the new font. Since this is
// asynchronous, reflows will coalesce.
ctx->UserFontSetUpdated(mUserFontEntry);
LOG(("userfonts (%p) reflow\n", this));
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));
}
}
}
// done with font set
@ -214,7 +226,7 @@ nsFontFaceLoader::Cancel()
mChannel->Cancel(NS_BINDING_ABORTED);
}
nsresult
/* static */ nsresult
nsFontFaceLoader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
nsIURI* aTargetURI,
nsISupports* aContext)