mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1028497 - Part 19: Support disconnecting FontFaces that reflect @font-face rules. r=jdaggett,bzbarsky
This adds support for a CSS-connected FontFace to be disconnected from its rule. This causes it to get its own copy of the descriptors on the nsCSSFontFaceStyleDecl, and for the pointers between the FontFace and the nsCSSFontFaceRule to be nulled out. We start tracking now whether a given FontFace is in the FontFaceSet (in the sense that it will appear on the DOM FontFaceSet object if we inspect it with script). All FontFace objects created though, whether they are currently "in" the FontFaceSet or not, are still tracked by the FontFaceSet. We use the new mUnavailableFaces array on the FontFaceSet for that. We need to track these FontFaces that aren't in the FontFaceSet as that's where we store their user font entry -- important if we call load() on a FontFace before adding it to the FontFaceSet.
This commit is contained in:
parent
fccff046d0
commit
4ddb800587
@ -15,7 +15,30 @@
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FontFace, mParent, mLoaded, mRule)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(FontFace)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FontFace)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoaded)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRule)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FontFace)
|
||||
if (!tmp->IsInFontFaceSet()) {
|
||||
tmp->mFontFaceSet->RemoveUnavailableFontFace(tmp);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoaded)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRule)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(FontFace)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FontFace)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
@ -29,11 +52,11 @@ FontFace::FontFace(nsISupports* aParent, nsPresContext* aPresContext)
|
||||
: mParent(aParent)
|
||||
, mPresContext(aPresContext)
|
||||
, mStatus(FontFaceLoadStatus::Unloaded)
|
||||
, mFontFaceSet(aPresContext->Fonts())
|
||||
, mInFontFaceSet(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FontFace);
|
||||
|
||||
MOZ_ASSERT(mPresContext);
|
||||
|
||||
SetIsDOMBinding();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
|
||||
@ -49,6 +72,10 @@ FontFace::~FontFace()
|
||||
MOZ_COUNT_DTOR(FontFace);
|
||||
|
||||
SetUserFontEntry(nullptr);
|
||||
|
||||
if (mFontFaceSet && !IsInFontFaceSet()) {
|
||||
mFontFaceSet->RemoveUnavailableFontFace(this);
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
@ -84,6 +111,7 @@ FontFace::CreateForRule(nsISupports* aGlobal,
|
||||
|
||||
nsRefPtr<FontFace> obj = new FontFace(aGlobal, aPresContext);
|
||||
obj->mRule = aRule;
|
||||
obj->mInFontFaceSet = true;
|
||||
obj->SetUserFontEntry(aUserFontEntry);
|
||||
return obj.forget();
|
||||
}
|
||||
@ -116,6 +144,7 @@ FontFace::Constructor(const GlobalObject& aGlobal,
|
||||
}
|
||||
|
||||
nsRefPtr<FontFace> obj = new FontFace(global, presContext);
|
||||
obj->mFontFaceSet->AddUnavailableFontFace(obj);
|
||||
return obj.forget();
|
||||
}
|
||||
|
||||
@ -433,6 +462,20 @@ FontFace::GetFamilyName(nsString& aResult)
|
||||
return !aResult.IsEmpty();
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::DisconnectFromRule()
|
||||
{
|
||||
MOZ_ASSERT(IsConnected());
|
||||
|
||||
// Make a copy of the descriptors.
|
||||
mDescriptors = new CSSFontFaceDescriptors;
|
||||
mRule->GetDescriptors(*mDescriptors);
|
||||
|
||||
mRule->SetFontFace(nullptr);
|
||||
mRule = nullptr;
|
||||
mInFontFaceSet = false;
|
||||
}
|
||||
|
||||
// -- FontFace::Entry --------------------------------------------------------
|
||||
|
||||
/* virtual */ void
|
||||
|
@ -19,6 +19,7 @@ namespace mozilla {
|
||||
struct CSSFontFaceDescriptors;
|
||||
namespace dom {
|
||||
struct FontFaceDescriptors;
|
||||
class FontFaceSet;
|
||||
class Promise;
|
||||
class StringOrArrayBufferOrArrayBufferView;
|
||||
}
|
||||
@ -78,6 +79,8 @@ public:
|
||||
gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
|
||||
void SetUserFontEntry(gfxUserFontEntry* aEntry);
|
||||
|
||||
bool IsInFontFaceSet() { return mInFontFaceSet; }
|
||||
|
||||
/**
|
||||
* Gets the family name of the FontFace as a raw string (such as 'Times', as
|
||||
* opposed to GetFamily, which returns a CSS-escaped string, such as
|
||||
@ -85,6 +88,17 @@ public:
|
||||
*/
|
||||
bool GetFamilyName(nsString& aResult);
|
||||
|
||||
/**
|
||||
* Returns whether this object is CSS-connected, i.e. reflecting an
|
||||
* @font-face rule.
|
||||
*/
|
||||
bool IsConnected() const { return mRule; }
|
||||
|
||||
/**
|
||||
* Breaks the connection between this FontFace and its @font-face rule.
|
||||
*/
|
||||
void DisconnectFromRule();
|
||||
|
||||
// Web IDL
|
||||
static already_AddRefed<FontFace>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
@ -162,6 +176,13 @@ private:
|
||||
// a CSS-connected FontFace object. For CSS-connected objects, we use
|
||||
// the descriptors stored in mRule.
|
||||
nsAutoPtr<mozilla::CSSFontFaceDescriptors> mDescriptors;
|
||||
|
||||
// The FontFaceSet this FontFace is associated with, regardless of whether
|
||||
// it is currently "in" the set.
|
||||
nsRefPtr<FontFaceSet> mFontFaceSet;
|
||||
|
||||
// Whether this FontFace appears in the FontFaceSet.
|
||||
bool mInFontFaceSet;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -208,9 +208,14 @@ FontFaceSet::DestroyUserFontSet()
|
||||
mPresContext = nullptr;
|
||||
mLoaders.EnumerateEntries(DestroyIterator, nullptr);
|
||||
for (size_t i = 0; i < mConnectedFaces.Length(); i++) {
|
||||
mConnectedFaces[i].mFontFace->DisconnectFromRule();
|
||||
mConnectedFaces[i].mFontFace->SetUserFontEntry(nullptr);
|
||||
}
|
||||
for (size_t i = 0; i < mUnavailableFaces.Length(); i++) {
|
||||
mUnavailableFaces[i]->SetUserFontEntry(nullptr);
|
||||
}
|
||||
mConnectedFaces.Clear();
|
||||
mUnavailableFaces.Clear();
|
||||
mReady = nullptr;
|
||||
mUserFontSet = nullptr;
|
||||
}
|
||||
@ -401,8 +406,8 @@ FontFaceSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules)
|
||||
// it when the FontFace is GCed, if we can detect that.
|
||||
size_t count = oldRecords.Length();
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
gfxUserFontEntry* userFontEntry =
|
||||
oldRecords[i].mFontFace->GetUserFontEntry();
|
||||
nsRefPtr<FontFace> f = oldRecords[i].mFontFace;
|
||||
gfxUserFontEntry* userFontEntry = f->GetUserFontEntry();
|
||||
if (userFontEntry) {
|
||||
nsFontFaceLoader* loader = userFontEntry->GetLoader();
|
||||
if (loader) {
|
||||
@ -410,6 +415,13 @@ FontFaceSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules)
|
||||
RemoveLoader(loader);
|
||||
}
|
||||
}
|
||||
|
||||
// Any left over FontFace objects should also cease being CSS-connected.
|
||||
MOZ_ASSERT(!mUnavailableFaces.Contains(f),
|
||||
"FontFace should not occur in mUnavailableFaces twice");
|
||||
|
||||
mUnavailableFaces.AppendElement(f);
|
||||
f->DisconnectFromRule();
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,6 +467,9 @@ FontFaceSet::InsertConnectedFontFace(
|
||||
return;
|
||||
}
|
||||
|
||||
bool remove = false;
|
||||
size_t removeIndex;
|
||||
|
||||
// This is a CSS-connected FontFace. First, we check in aOldRecords; if
|
||||
// the FontFace for the rule exists there, just move it to the new record
|
||||
// list, and put the entry into the appropriate family.
|
||||
@ -471,6 +486,10 @@ FontFaceSet::InsertConnectedFontFace(
|
||||
aFontFace->GetDesc(eCSSFontDesc_Src, val);
|
||||
nsCSSUnit unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Array && HasLocalSrc(val.GetArrayValue())) {
|
||||
// Remove the old record, but wait to see if we successfully create a
|
||||
// new user font entry below.
|
||||
remove = true;
|
||||
removeIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -502,6 +521,16 @@ FontFaceSet::InsertConnectedFontFace(
|
||||
return;
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
// Although we broke out of the aOldRecords loop above, since we found
|
||||
// src local usage, and we're not using the old user font entry, we still
|
||||
// are adding a record to mConnectedFaces with the same FontFace object.
|
||||
// Remove the old record so that we don't have the same FontFace listed
|
||||
// in both mConnectedFaces and oldRecords, which would cause us to call
|
||||
// DisconnectFromRule on a FontFace that should still be connected.
|
||||
aOldRecords.RemoveElementAt(removeIndex);
|
||||
}
|
||||
|
||||
FontFaceRecord rec;
|
||||
rec.mFontFace = aFontFace;
|
||||
rec.mSheetType = aSheetType;
|
||||
@ -1017,6 +1046,29 @@ FontFaceSet::FontFaceForRule(nsCSSFontFaceRule* aRule)
|
||||
return newFontFace;
|
||||
}
|
||||
|
||||
void
|
||||
FontFaceSet::AddUnavailableFontFace(FontFace* aFontFace)
|
||||
{
|
||||
MOZ_ASSERT(!aFontFace->IsInFontFaceSet());
|
||||
MOZ_ASSERT(!mUnavailableFaces.Contains(aFontFace));
|
||||
|
||||
mUnavailableFaces.AppendElement(aFontFace);
|
||||
}
|
||||
|
||||
void
|
||||
FontFaceSet::RemoveUnavailableFontFace(FontFace* aFontFace)
|
||||
{
|
||||
MOZ_ASSERT(!aFontFace->IsConnected());
|
||||
MOZ_ASSERT(!aFontFace->IsInFontFaceSet());
|
||||
|
||||
// We might not actually find the FontFace in mUnavailableFaces, since we
|
||||
// might be shutting down the document and had DestroyUserFontSet called
|
||||
// on us, which clears out mUnavailableFaces.
|
||||
mUnavailableFaces.RemoveElement(aFontFace);
|
||||
|
||||
MOZ_ASSERT(!mUnavailableFaces.Contains(aFontFace));
|
||||
}
|
||||
|
||||
// -- FontFaceSet::UserFontSet ------------------------------------------------
|
||||
|
||||
/* virtual */ nsresult
|
||||
|
@ -112,6 +112,18 @@ public:
|
||||
|
||||
void IncrementGeneration(bool aIsRebuild = false);
|
||||
|
||||
/**
|
||||
* Adds the specified FontFace to the mUnavailableFaces array. This is called
|
||||
* when a new FontFace object has just been created in JS by the author.
|
||||
*/
|
||||
void AddUnavailableFontFace(FontFace* aFontFace);
|
||||
|
||||
/**
|
||||
* Removes the specified FontFace from the mUnavailableFaces array. This
|
||||
* is called when a FontFace object is about be destroyed.
|
||||
*/
|
||||
void RemoveUnavailableFontFace(FontFace* aFontFace);
|
||||
|
||||
// -- Web IDL --------------------------------------------------------------
|
||||
|
||||
IMPL_EVENT_HANDLER(loading)
|
||||
@ -193,6 +205,10 @@ private:
|
||||
|
||||
// The CSS-connected FontFace objects in the FontFaceSet.
|
||||
nsTArray<FontFaceRecord> mConnectedFaces;
|
||||
|
||||
// The unconnected FontFace objects that have not been added to
|
||||
// this FontFaceSet.
|
||||
nsTArray<FontFace*> mUnavailableFaces;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -280,6 +280,9 @@ public:
|
||||
mozilla::dom::FontFace* GetFontFace() const { return mFontFace; }
|
||||
void SetFontFace(mozilla::dom::FontFace* aFontFace) { mFontFace = aFontFace; }
|
||||
|
||||
void GetDescriptors(mozilla::CSSFontFaceDescriptors& aDescriptors) const
|
||||
{ aDescriptors = mDecl.mDescriptors; }
|
||||
|
||||
protected:
|
||||
~nsCSSFontFaceRule() {}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user