зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset e85cb54e5944 (bug 1546046
) complementary backout after 1470880 was backed out CLOSED TREE
This commit is contained in:
Родитель
a0ccfdb583
Коммит
ec489aa170
|
@ -609,6 +609,8 @@ JSObject* Element::WrapObject(JSContext* aCx,
|
|||
nsCOMPtr<nsIPrincipal> principal = bindingURL->ExtraData()->Principal();
|
||||
|
||||
// We have a binding that must be installed.
|
||||
bool dummy;
|
||||
|
||||
nsXBLService* xblService = nsXBLService::GetInstance();
|
||||
if (!xblService) {
|
||||
dom::Throw(aCx, NS_ERROR_NOT_AVAILABLE);
|
||||
|
@ -616,7 +618,8 @@ JSObject* Element::WrapObject(JSContext* aCx,
|
|||
}
|
||||
|
||||
RefPtr<nsXBLBinding> binding;
|
||||
xblService->LoadBindings(this, uri, principal, getter_AddRefs(binding));
|
||||
xblService->LoadBindings(this, uri, principal, getter_AddRefs(binding),
|
||||
&dummy);
|
||||
|
||||
if (binding) {
|
||||
if (nsContentUtils::IsSafeToRunScript()) {
|
||||
|
|
|
@ -33,6 +33,8 @@ UNIFIED_SOURCES += [
|
|||
'nsXBLProtoImplProperty.cpp',
|
||||
'nsXBLPrototypeBinding.cpp',
|
||||
'nsXBLPrototypeHandler.cpp',
|
||||
'nsXBLPrototypeResources.cpp',
|
||||
'nsXBLResourceLoader.cpp',
|
||||
'nsXBLSerialize.cpp',
|
||||
'nsXBLService.cpp',
|
||||
'nsXBLWindowKeyHandler.cpp',
|
||||
|
|
|
@ -585,6 +585,40 @@ nsresult nsBindingManager::GetBindingImplementation(nsIContent* aContent,
|
|||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
bool nsBindingManager::EnumerateBoundContentProtoBindings(
|
||||
const BoundContentProtoBindingCallback& aCallback) const {
|
||||
if (!mBoundContentSet) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsTHashtable<nsPtrHashKey<nsXBLPrototypeBinding>> bindings;
|
||||
for (auto iter = mBoundContentSet->Iter(); !iter.Done(); iter.Next()) {
|
||||
nsIContent* boundContent = iter.Get()->GetKey();
|
||||
for (nsXBLBinding* binding = boundContent->GetXBLBinding(); binding;
|
||||
binding = binding->GetBaseBinding()) {
|
||||
nsXBLPrototypeBinding* proto = binding->PrototypeBinding();
|
||||
// If we have already invoked the callback with a binding, we
|
||||
// should have also invoked it for all its base bindings, so we
|
||||
// don't need to continue this loop anymore.
|
||||
if (!bindings.EnsureInserted(proto)) {
|
||||
break;
|
||||
}
|
||||
if (!aCallback(proto)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void nsBindingManager::AppendAllSheets(nsTArray<StyleSheet*>& aArray) {
|
||||
EnumerateBoundContentProtoBindings([&aArray](nsXBLPrototypeBinding* aProto) {
|
||||
aProto->AppendStyleSheetsTo(aArray);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
static void InsertAppendedContent(XBLChildrenElement* aPoint,
|
||||
nsIContent* aFirstNewContent) {
|
||||
int32_t insertionIndex;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/MediaFeatureChange.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
|
||||
struct ElementDependentRuleProcessorData;
|
||||
|
@ -116,6 +117,8 @@ class nsBindingManager final : public nsStubMutationObserver {
|
|||
nsresult GetBindingImplementation(nsIContent* aContent, REFNSIID aIID,
|
||||
void** aResult);
|
||||
|
||||
void AppendAllSheets(nsTArray<mozilla::StyleSheet*>& aArray);
|
||||
|
||||
void Traverse(nsIContent* aContent, nsCycleCollectionTraversalCallback& cb);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(nsBindingManager)
|
||||
|
@ -145,6 +148,14 @@ class nsBindingManager final : public nsStubMutationObserver {
|
|||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
// Enumerate each bound content's bindings (including its base bindings)
|
||||
// in mBoundContentSet. Return false from the callback to stop enumeration.
|
||||
using BoundContentProtoBindingCallback =
|
||||
std::function<bool(nsXBLPrototypeBinding*)>;
|
||||
|
||||
bool EnumerateBoundContentProtoBindings(
|
||||
const BoundContentProtoBindingCallback&) const;
|
||||
|
||||
protected:
|
||||
nsIXPConnectWrappedJS* GetWrappedJS(nsIContent* aContent);
|
||||
nsresult SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult);
|
||||
|
|
|
@ -210,6 +210,14 @@ void nsXBLBinding::SetBoundElement(Element* aElement) {
|
|||
if (mNextBinding) mNextBinding->SetBoundElement(aElement);
|
||||
}
|
||||
|
||||
bool nsXBLBinding::HasStyleSheets() const {
|
||||
// Find out if we need to re-resolve style. We'll need to do this
|
||||
// if we have additional stylesheets in our binding document.
|
||||
if (mPrototypeBinding->HasStyleSheets()) return true;
|
||||
|
||||
return mNextBinding ? mNextBinding->HasStyleSheets() : false;
|
||||
}
|
||||
|
||||
void nsXBLBinding::GenerateAnonymousContent() {
|
||||
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
|
||||
"Someone forgot a script blocker");
|
||||
|
@ -683,6 +691,24 @@ void nsXBLBinding::ChangeDocument(Document* aOldDocument,
|
|||
}
|
||||
}
|
||||
|
||||
bool nsXBLBinding::InheritsStyle() const {
|
||||
// XXX Will have to change if we ever allow multiple bindings to contribute
|
||||
// anonymous content. Most derived binding with anonymous content determines
|
||||
// style inheritance for now.
|
||||
|
||||
// XXX What about bindings with <content> but no kids, e.g., my treecell-text
|
||||
// binding?
|
||||
if (mContent) return mPrototypeBinding->InheritsStyle();
|
||||
|
||||
if (mNextBinding) return mNextBinding->InheritsStyle();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const RawServoAuthorStyles* nsXBLBinding::GetServoStyles() const {
|
||||
return mPrototypeBinding->GetServoStyles();
|
||||
}
|
||||
|
||||
// Internal helper methods /////////////////////////////////////////////////////
|
||||
|
||||
// Get or create a WeakMap object on a given XBL-hosting global.
|
||||
|
|
|
@ -92,6 +92,8 @@ class nsXBLBinding final {
|
|||
void MarkForDeath();
|
||||
bool MarkedForDeath() const { return mMarkedForDeath; }
|
||||
|
||||
bool HasStyleSheets() const;
|
||||
bool InheritsStyle() const;
|
||||
bool ImplementsInterface(REFNSIID aIID) const;
|
||||
|
||||
void GenerateAnonymousContent();
|
||||
|
|
|
@ -255,6 +255,9 @@ nsXBLContentSink::HandleEndElement(const char16_t* aName) {
|
|||
} else if (localName == nsGkAtoms::handler)
|
||||
mSecondaryState = eXBL_None;
|
||||
return NS_OK;
|
||||
} else if (mState == eXBL_InResources) {
|
||||
if (localName == nsGkAtoms::resources) mState = eXBL_InBinding;
|
||||
return NS_OK;
|
||||
} else if (mState == eXBL_InImplementation) {
|
||||
if (localName == nsGkAtoms::implementation)
|
||||
mState = eXBL_InBinding;
|
||||
|
@ -368,6 +371,16 @@ bool nsXBLContentSink::OnOpenContainer(const char16_t** aAtts,
|
|||
mSecondaryState = eXBL_InHandler;
|
||||
ConstructHandler(aAtts, aLineNumber);
|
||||
ret = false;
|
||||
} else if (aTagName == nsGkAtoms::resources) {
|
||||
ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding);
|
||||
mState = eXBL_InResources;
|
||||
// Note that this mState will cause us to return false, so no need
|
||||
// to set ret to false.
|
||||
} else if (aTagName == nsGkAtoms::stylesheet ||
|
||||
aTagName == nsGkAtoms::image) {
|
||||
ENSURE_XBL_STATE(mState == eXBL_InResources);
|
||||
NS_ASSERTION(mBinding, "Must have binding here");
|
||||
ConstructResource(aAtts, aTagName);
|
||||
} else if (aTagName == nsGkAtoms::implementation) {
|
||||
ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding);
|
||||
mState = eXBL_InImplementation;
|
||||
|
@ -449,7 +462,7 @@ bool nsXBLContentSink::OnOpenContainer(const char16_t** aAtts,
|
|||
mSecondaryState = eXBL_InBody;
|
||||
}
|
||||
|
||||
return ret && mState != eXBL_InImplementation;
|
||||
return ret && mState != eXBL_InResources && mState != eXBL_InImplementation;
|
||||
}
|
||||
|
||||
#undef ENSURE_XBL_STATE
|
||||
|
@ -591,6 +604,16 @@ void nsXBLContentSink::ConstructHandler(const char16_t** aAtts,
|
|||
mHandler = newHandler;
|
||||
}
|
||||
|
||||
void nsXBLContentSink::ConstructResource(const char16_t** aAtts,
|
||||
nsAtom* aResourceType) {
|
||||
if (!mBinding) return;
|
||||
|
||||
const char16_t* src = nullptr;
|
||||
if (FindValue(aAtts, nsGkAtoms::src, &src)) {
|
||||
mBinding->AddResource(aResourceType, nsDependentString(src));
|
||||
}
|
||||
}
|
||||
|
||||
void nsXBLContentSink::ConstructImplementation(const char16_t** aAtts) {
|
||||
mImplementation = nullptr;
|
||||
mImplMember = nullptr;
|
||||
|
|
|
@ -21,6 +21,7 @@ typedef enum {
|
|||
eXBL_InDocument, /* outside any bindings */
|
||||
eXBL_InBindings, /* Inside a <bindings> element */
|
||||
eXBL_InBinding, /* Inside a <binding> */
|
||||
eXBL_InResources, /* Inside a <resources> */
|
||||
eXBL_InImplementation, /* Inside a <implementation> */
|
||||
eXBL_InHandlers, /* Inside a <handlers> */
|
||||
eXBL_Error /* An error has occurred. Suspend binding construction */
|
||||
|
@ -88,8 +89,7 @@ class nsXBLContentSink : public nsXMLContentSink {
|
|||
nsIContent** aResult, bool* aAppendContent,
|
||||
mozilla::dom::FromParser aFromParser) override;
|
||||
|
||||
nsresult AddAttributes(const char16_t** aAtts,
|
||||
mozilla::dom::Element* aElement) override;
|
||||
nsresult AddAttributes(const char16_t** aAtts, Element* aElement) override;
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
nsresult AddAttributesToXULPrototype(const char16_t** aAtts,
|
||||
|
@ -100,6 +100,7 @@ class nsXBLContentSink : public nsXMLContentSink {
|
|||
// Our own helpers for constructing XBL prototype objects.
|
||||
nsresult ConstructBinding(uint32_t aLineNumber);
|
||||
void ConstructHandler(const char16_t** aAtts, uint32_t aLineNumber);
|
||||
void ConstructResource(const char16_t** aAtts, nsAtom* aResourceType);
|
||||
void ConstructImplementation(const char16_t** aAtts);
|
||||
void ConstructProperty(const char16_t** aAtts, uint32_t aLineNumber);
|
||||
void ConstructMethod(const char16_t** aAtts);
|
||||
|
|
|
@ -285,6 +285,14 @@ void nsXBLDocumentInfo::SetFirstPrototypeBinding(
|
|||
mFirstBinding = aBinding;
|
||||
}
|
||||
|
||||
void nsXBLDocumentInfo::FlushSkinStylesheets() {
|
||||
if (mBindingTable) {
|
||||
for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.UserData()->FlushSkinSheets();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void AssertInCompilationScope() {
|
||||
AutoJSContext cx;
|
||||
|
|
|
@ -40,6 +40,8 @@ class nsXBLDocumentInfo final : public nsSupportsWeakReference {
|
|||
|
||||
void SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding);
|
||||
|
||||
void FlushSkinStylesheets();
|
||||
|
||||
bool IsChrome() { return mIsChrome; }
|
||||
|
||||
void MarkInCCGeneration(uint32_t aGeneration);
|
||||
|
|
|
@ -37,10 +37,13 @@
|
|||
#include "nsTextNode.h"
|
||||
#include "nsIScriptError.h"
|
||||
|
||||
#include "nsXBLResourceLoader.h"
|
||||
#include "mozilla/dom/CDATASection.h"
|
||||
#include "mozilla/dom/CharacterData.h"
|
||||
#include "mozilla/dom/Comment.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
# include "nsXULElement.h"
|
||||
|
@ -107,10 +110,12 @@ size_t nsXBLAttributeEntry::SizeOfIncludingThis(
|
|||
nsXBLPrototypeBinding::nsXBLPrototypeBinding()
|
||||
: mImplementation(nullptr),
|
||||
mBaseBinding(nullptr),
|
||||
mInheritStyle(true),
|
||||
mCheckedBaseProto(false),
|
||||
mKeyHandlersRegistered(false),
|
||||
mBindToUntrustedContent(false),
|
||||
mSimpleScopeChain(false),
|
||||
mResources(nullptr),
|
||||
mXBLDocInfoWeak(nullptr) {
|
||||
MOZ_COUNT_CTOR(nsXBLPrototypeBinding);
|
||||
}
|
||||
|
@ -155,6 +160,9 @@ void nsXBLPrototypeBinding::Traverse(
|
|||
nsCycleCollectionTraversalCallback& cb) const {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "proto mBinding");
|
||||
cb.NoteXPCOMChild(mBinding);
|
||||
if (mResources) {
|
||||
mResources->Traverse(cb);
|
||||
}
|
||||
ImplCycleCollectionTraverse(cb, mInterfaceTable, "proto mInterfaceTable");
|
||||
}
|
||||
|
||||
|
@ -162,6 +170,10 @@ void nsXBLPrototypeBinding::Unlink() {
|
|||
if (mImplementation) {
|
||||
mImplementation->UnlinkJSObjects();
|
||||
}
|
||||
|
||||
if (mResources) {
|
||||
mResources->Unlink();
|
||||
}
|
||||
}
|
||||
|
||||
void nsXBLPrototypeBinding::Trace(const TraceCallbacks& aCallbacks,
|
||||
|
@ -193,6 +205,9 @@ void nsXBLPrototypeBinding::SetBasePrototype(nsXBLPrototypeBinding* aBinding) {
|
|||
|
||||
void nsXBLPrototypeBinding::SetBindingElement(Element* aElement) {
|
||||
mBinding = aElement;
|
||||
if (mBinding->AttrValueIs(kNameSpaceID_None, nsGkAtoms::inheritstyle,
|
||||
nsGkAtoms::_false, eCaseMatters))
|
||||
mInheritStyle = false;
|
||||
|
||||
mBindToUntrustedContent = mBinding->AttrValueIs(
|
||||
kNameSpaceID_None, nsGkAtoms::bindToUntrustedContent, nsGkAtoms::_true,
|
||||
|
@ -208,6 +223,27 @@ bool nsXBLPrototypeBinding::GetAllowScripts() const {
|
|||
return mXBLDocInfoWeak->GetScriptAccess();
|
||||
}
|
||||
|
||||
bool nsXBLPrototypeBinding::LoadResources(nsIContent* aBoundElement) {
|
||||
if (mResources) {
|
||||
return mResources->LoadResources(aBoundElement);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult nsXBLPrototypeBinding::AddResource(nsAtom* aResourceType,
|
||||
const nsAString& aSrc) {
|
||||
EnsureResources();
|
||||
|
||||
mResources->AddResource(aResourceType, aSrc);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsXBLPrototypeBinding::FlushSkinSheets() {
|
||||
if (mResources) return mResources->FlushSkinSheets();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsXBLPrototypeBinding::BindingAttached(nsIContent* aBoundElement) {
|
||||
if (mImplementation && mImplementation->CompiledMembers() &&
|
||||
mImplementation->mConstructor)
|
||||
|
@ -605,6 +641,15 @@ nsresult nsXBLPrototypeBinding::ConstructInterfaceTable(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsXBLPrototypeBinding::AddResourceListener(nsIContent* aBoundElement) {
|
||||
if (!mResources)
|
||||
return NS_ERROR_FAILURE; // Makes no sense to add a listener when the
|
||||
// binding has no resources.
|
||||
|
||||
mResources->AddResourceListener(aBoundElement);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsXBLPrototypeBinding::CreateKeyHandlers() {
|
||||
nsXBLPrototypeHandler* curr = mPrototypeHandler;
|
||||
while (curr) {
|
||||
|
@ -656,6 +701,7 @@ class XBLPrototypeSetupCleanup {
|
|||
nsresult nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream,
|
||||
nsXBLDocumentInfo* aDocInfo,
|
||||
Document* aDocument, uint8_t aFlags) {
|
||||
mInheritStyle = (aFlags & XBLBinding_Serialize_InheritStyle) ? true : false;
|
||||
mBindToUntrustedContent =
|
||||
(aFlags & XBLBinding_Serialize_BindToUntrustedContent) ? true : false;
|
||||
mSimpleScopeChain =
|
||||
|
@ -798,6 +844,28 @@ nsresult nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream,
|
|||
}
|
||||
}
|
||||
|
||||
// Finally, read in the resources.
|
||||
while (true) {
|
||||
XBLBindingSerializeDetails type;
|
||||
rv = aStream->Read8(&type);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (type == XBLBinding_Serialize_NoMoreItems) break;
|
||||
|
||||
NS_ASSERTION(
|
||||
(type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Stylesheet ||
|
||||
(type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Image,
|
||||
"invalid resource type");
|
||||
|
||||
nsAutoString src;
|
||||
rv = aStream->ReadString(src);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
AddResource(type == XBLBinding_Serialize_Stylesheet ? nsGkAtoms::stylesheet
|
||||
: nsGkAtoms::image,
|
||||
src);
|
||||
}
|
||||
|
||||
if (isFirstBinding) {
|
||||
aDocInfo->SetFirstPrototypeBinding(this);
|
||||
}
|
||||
|
@ -833,7 +901,7 @@ nsresult nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream) {
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
uint8_t flags = 0;
|
||||
uint8_t flags = mInheritStyle ? XBLBinding_Serialize_InheritStyle : 0;
|
||||
|
||||
// mAlternateBindingURI is only set on the first binding.
|
||||
if (mAlternateBindingURI) {
|
||||
|
@ -942,6 +1010,15 @@ nsresult nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream) {
|
|||
}
|
||||
}
|
||||
|
||||
aStream->Write8(XBLBinding_Serialize_NoMoreItems);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Write out the resources
|
||||
if (mResources) {
|
||||
rv = mResources->Write(aStream);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Write out an end mark at the end.
|
||||
return aStream->Write8(XBLBinding_Serialize_NoMoreItems);
|
||||
}
|
||||
|
@ -1310,11 +1387,57 @@ nsresult nsXBLPrototypeBinding::ResolveBaseBinding() {
|
|||
doc->GetDocumentCharacterSet(), doc->GetDocBaseURI());
|
||||
}
|
||||
|
||||
void nsXBLPrototypeBinding::EnsureResources() {
|
||||
if (!mResources) {
|
||||
mResources = new nsXBLPrototypeResources(this);
|
||||
}
|
||||
}
|
||||
|
||||
void nsXBLPrototypeBinding::AppendStyleSheet(StyleSheet* aSheet) {
|
||||
EnsureResources();
|
||||
mResources->AppendStyleSheet(aSheet);
|
||||
}
|
||||
|
||||
void nsXBLPrototypeBinding::RemoveStyleSheet(StyleSheet* aSheet) {
|
||||
if (!mResources) {
|
||||
MOZ_ASSERT(false, "Trying to remove a sheet that does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
mResources->RemoveStyleSheet(aSheet);
|
||||
}
|
||||
void nsXBLPrototypeBinding::InsertStyleSheetAt(size_t aIndex,
|
||||
StyleSheet* aSheet) {
|
||||
EnsureResources();
|
||||
mResources->InsertStyleSheetAt(aIndex, aSheet);
|
||||
}
|
||||
|
||||
StyleSheet* nsXBLPrototypeBinding::StyleSheetAt(size_t aIndex) const {
|
||||
MOZ_ASSERT(mResources);
|
||||
return mResources->StyleSheetAt(aIndex);
|
||||
}
|
||||
|
||||
size_t nsXBLPrototypeBinding::SheetCount() const {
|
||||
return mResources ? mResources->SheetCount() : 0;
|
||||
}
|
||||
|
||||
bool nsXBLPrototypeBinding::HasStyleSheets() const {
|
||||
return mResources && mResources->HasStyleSheets();
|
||||
}
|
||||
|
||||
void nsXBLPrototypeBinding::AppendStyleSheetsTo(
|
||||
nsTArray<StyleSheet*>& aResult) const {
|
||||
if (mResources) {
|
||||
mResources->AppendStyleSheetsTo(aResult);
|
||||
}
|
||||
}
|
||||
|
||||
size_t nsXBLPrototypeBinding::SizeOfIncludingThis(
|
||||
MallocSizeOf aMallocSizeOf) const {
|
||||
size_t n = aMallocSizeOf(this);
|
||||
n += mPrototypeHandler ? mPrototypeHandler->SizeOfIncludingThis(aMallocSizeOf)
|
||||
: 0;
|
||||
n += mResources ? mResources->SizeOfIncludingThis(aMallocSizeOf) : 0;
|
||||
|
||||
if (mAttributeTable) {
|
||||
n += mAttributeTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
#include "nsXBLProtoImpl.h"
|
||||
#include "nsXBLProtoImplMethod.h"
|
||||
#include "nsXBLPrototypeHandler.h"
|
||||
#include "nsXBLPrototypeResources.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
|
||||
class nsAtom;
|
||||
class nsIContent;
|
||||
|
@ -55,6 +57,14 @@ class nsXBLPrototypeBinding final
|
|||
nsresult BindingAttached(nsIContent* aBoundElement);
|
||||
nsresult BindingDetached(nsIContent* aBoundElement);
|
||||
|
||||
// aBoundElement is passed in here because we need to get owner document
|
||||
// and PresContext in nsXBLResourceLoader::LoadResources().
|
||||
bool LoadResources(nsIContent* aBoundElement);
|
||||
nsresult AddResource(nsAtom* aResourceType, const nsAString& aSrc);
|
||||
|
||||
bool InheritsStyle() const { return mInheritStyle; }
|
||||
void SetInheritsStyle(bool aInheritStyle) { mInheritStyle = aInheritStyle; }
|
||||
|
||||
nsXBLPrototypeHandler* GetPrototypeHandlers() { return mPrototypeHandler; }
|
||||
void SetPrototypeHandlers(nsXBLPrototypeHandler* aHandler) {
|
||||
mPrototypeHandler = aHandler;
|
||||
|
@ -112,11 +122,42 @@ class nsXBLPrototypeBinding final
|
|||
void SetInitialAttributes(mozilla::dom::Element* aBoundElement,
|
||||
nsIContent* aAnonymousContent);
|
||||
|
||||
void AppendStyleSheet(mozilla::StyleSheet* aSheet);
|
||||
void RemoveStyleSheet(mozilla::StyleSheet* aSheet);
|
||||
void InsertStyleSheetAt(size_t aIndex, mozilla::StyleSheet* aSheet);
|
||||
mozilla::StyleSheet* StyleSheetAt(size_t aIndex) const;
|
||||
size_t SheetCount() const;
|
||||
bool HasStyleSheets() const;
|
||||
void AppendStyleSheetsTo(nsTArray<mozilla::StyleSheet*>& aResult) const;
|
||||
|
||||
const RawServoAuthorStyles* GetServoStyles() const {
|
||||
return mResources ? mResources->GetServoStyles() : nullptr;
|
||||
}
|
||||
|
||||
void SyncServoStyles() {
|
||||
MOZ_ASSERT(mResources);
|
||||
mResources->SyncServoStyles();
|
||||
}
|
||||
|
||||
RawServoAuthorStyles* GetServoStyles() {
|
||||
return mResources
|
||||
? const_cast<RawServoAuthorStyles*>(mResources->GetServoStyles())
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
mozilla::ServoStyleRuleMap* GetServoStyleRuleMap() {
|
||||
return mResources ? mResources->GetServoStyleRuleMap() : nullptr;
|
||||
}
|
||||
|
||||
nsresult FlushSkinSheets();
|
||||
|
||||
nsAtom* GetBaseTag(int32_t* aNamespaceID);
|
||||
void SetBaseTag(int32_t aNamespaceID, nsAtom* aTag);
|
||||
|
||||
bool ImplementsInterface(REFNSIID aIID) const;
|
||||
|
||||
nsresult AddResourceListener(nsIContent* aBoundElement);
|
||||
|
||||
void Initialize();
|
||||
|
||||
nsresult ResolveBaseBinding();
|
||||
|
@ -247,6 +288,9 @@ class nsXBLPrototypeBinding final
|
|||
void ConstructAttributeTable(mozilla::dom::Element* aElement);
|
||||
void CreateKeyHandlers();
|
||||
|
||||
private:
|
||||
void EnsureResources();
|
||||
|
||||
// MEMBER VARIABLES
|
||||
protected:
|
||||
nsCOMPtr<nsIURI> mBindingURI;
|
||||
|
@ -267,6 +311,8 @@ class nsXBLPrototypeBinding final
|
|||
|
||||
// Weak. The docinfo will own our base binding.
|
||||
mozilla::WeakPtr<nsXBLPrototypeBinding> mBaseBinding;
|
||||
// FIXME(emilio): This is dead code now.
|
||||
bool mInheritStyle;
|
||||
bool mCheckedBaseProto;
|
||||
bool mKeyHandlersRegistered;
|
||||
// FIXME(emilio): This is dead code now.
|
||||
|
@ -276,6 +322,9 @@ class nsXBLPrototypeBinding final
|
|||
// FIXME(emilio): This is dead code now.
|
||||
bool mSimpleScopeChain;
|
||||
|
||||
nsAutoPtr<nsXBLPrototypeResources>
|
||||
mResources; // If we have any resources, this will be non-null.
|
||||
|
||||
nsXBLDocumentInfo* mXBLDocInfoWeak; // A pointer back to our doc info. Weak,
|
||||
// since it owns us.
|
||||
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/dom/Document.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIPresShellInlines.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsXBLResourceLoader.h"
|
||||
#include "nsXBLPrototypeResources.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "nsIDocumentObserver.h"
|
||||
#include "mozilla/css/Loader.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsLayoutCID.h"
|
||||
#include "mozilla/dom/URL.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/ServoBindings.h"
|
||||
#include "mozilla/ServoStyleRuleMap.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using mozilla::dom::IsChromeURI;
|
||||
|
||||
nsXBLPrototypeResources::nsXBLPrototypeResources(
|
||||
nsXBLPrototypeBinding* aBinding) {
|
||||
MOZ_COUNT_CTOR(nsXBLPrototypeResources);
|
||||
|
||||
mLoader = new nsXBLResourceLoader(aBinding, this);
|
||||
}
|
||||
|
||||
nsXBLPrototypeResources::~nsXBLPrototypeResources() {
|
||||
MOZ_COUNT_DTOR(nsXBLPrototypeResources);
|
||||
if (mLoader) {
|
||||
mLoader->mResources = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void nsXBLPrototypeResources::AddResource(nsAtom* aResourceType,
|
||||
const nsAString& aSrc) {
|
||||
if (mLoader) mLoader->AddResource(aResourceType, aSrc);
|
||||
}
|
||||
|
||||
bool nsXBLPrototypeResources::LoadResources(nsIContent* aBoundElement) {
|
||||
if (mLoader) {
|
||||
return mLoader->LoadResources(aBoundElement);
|
||||
}
|
||||
|
||||
return true; // All resources loaded.
|
||||
}
|
||||
|
||||
void nsXBLPrototypeResources::AddResourceListener(nsIContent* aBoundElement) {
|
||||
if (mLoader) mLoader->AddResourceListener(aBoundElement);
|
||||
}
|
||||
|
||||
nsresult nsXBLPrototypeResources::FlushSkinSheets() {
|
||||
if (mStyleSheetList.Length() == 0) return NS_OK;
|
||||
|
||||
nsCOMPtr<Document> doc = mLoader->mBinding->XBLDocumentInfo()->GetDocument();
|
||||
|
||||
// If doc is null, we're in the process of tearing things down, so just
|
||||
// return without rebuilding anything.
|
||||
if (!doc) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We have scoped stylesheets. Reload any chrome stylesheets we
|
||||
// encounter. (If they aren't skin sheets, it doesn't matter, since
|
||||
// they'll still be in the chrome cache. Skip inline sheets, which
|
||||
// skin sheets can't be, and which in any case don't have a usable
|
||||
// URL to reload.)
|
||||
|
||||
nsTArray<RefPtr<StyleSheet>> oldSheets;
|
||||
|
||||
oldSheets.SwapElements(mStyleSheetList);
|
||||
|
||||
mozilla::css::Loader* cssLoader = doc->CSSLoader();
|
||||
|
||||
for (size_t i = 0, count = oldSheets.Length(); i < count; ++i) {
|
||||
StyleSheet* oldSheet = oldSheets[i];
|
||||
|
||||
nsIURI* uri = oldSheet->GetSheetURI();
|
||||
|
||||
RefPtr<StyleSheet> newSheet;
|
||||
if (!oldSheet->IsInline() && IsChromeURI(uri)) {
|
||||
if (NS_FAILED(cssLoader->LoadSheetSync(uri, &newSheet))) continue;
|
||||
} else {
|
||||
newSheet = oldSheet;
|
||||
}
|
||||
|
||||
mStyleSheetList.AppendElement(newSheet);
|
||||
}
|
||||
|
||||
// There may be no shell during unlink.
|
||||
if (PresShell* presShell = doc->GetPresShell()) {
|
||||
MOZ_ASSERT(presShell->GetPresContext());
|
||||
ComputeServoStyles(*presShell->StyleSet());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsXBLPrototypeResources::Write(nsIObjectOutputStream* aStream) {
|
||||
if (mLoader) return mLoader->Write(aStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsXBLPrototypeResources::Traverse(nsCycleCollectionTraversalCallback& cb) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "proto mResources mLoader");
|
||||
cb.NoteXPCOMChild(mLoader);
|
||||
|
||||
ImplCycleCollectionTraverse(cb, mStyleSheetList, "mStyleSheetList");
|
||||
}
|
||||
|
||||
void nsXBLPrototypeResources::Unlink() { mStyleSheetList.Clear(); }
|
||||
|
||||
void nsXBLPrototypeResources::ClearLoader() { mLoader = nullptr; }
|
||||
|
||||
void nsXBLPrototypeResources::SyncServoStyles() {
|
||||
mStyleRuleMap.reset(nullptr);
|
||||
mServoStyles = Servo_AuthorStyles_Create().Consume();
|
||||
for (auto& sheet : mStyleSheetList) {
|
||||
Servo_AuthorStyles_AppendStyleSheet(mServoStyles.get(), sheet);
|
||||
}
|
||||
}
|
||||
|
||||
void nsXBLPrototypeResources::ComputeServoStyles(
|
||||
const ServoStyleSet& aMasterStyleSet) {
|
||||
SyncServoStyles();
|
||||
Servo_AuthorStyles_Flush(mServoStyles.get(), aMasterStyleSet.RawSet());
|
||||
}
|
||||
|
||||
ServoStyleRuleMap* nsXBLPrototypeResources::GetServoStyleRuleMap() {
|
||||
if (!HasStyleSheets() || !mServoStyles) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mStyleRuleMap) {
|
||||
mStyleRuleMap = MakeUnique<ServoStyleRuleMap>();
|
||||
}
|
||||
|
||||
mStyleRuleMap->EnsureTable(*this);
|
||||
return mStyleRuleMap.get();
|
||||
}
|
||||
|
||||
void nsXBLPrototypeResources::AppendStyleSheet(StyleSheet* aSheet) {
|
||||
mStyleSheetList.AppendElement(aSheet);
|
||||
}
|
||||
|
||||
void nsXBLPrototypeResources::RemoveStyleSheet(StyleSheet* aSheet) {
|
||||
mStyleSheetList.RemoveElement(aSheet);
|
||||
}
|
||||
|
||||
void nsXBLPrototypeResources::InsertStyleSheetAt(size_t aIndex,
|
||||
StyleSheet* aSheet) {
|
||||
mStyleSheetList.InsertElementAt(aIndex, aSheet);
|
||||
}
|
||||
|
||||
void nsXBLPrototypeResources::AppendStyleSheetsTo(
|
||||
nsTArray<StyleSheet*>& aResult) const {
|
||||
aResult.AppendElements(mStyleSheetList);
|
||||
}
|
||||
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(ServoAuthorStylesMallocSizeOf)
|
||||
MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoAuthorStylesMallocEnclosingSizeOf)
|
||||
|
||||
size_t nsXBLPrototypeResources::SizeOfIncludingThis(
|
||||
MallocSizeOf aMallocSizeOf) const {
|
||||
size_t n = aMallocSizeOf(this);
|
||||
n += mStyleSheetList.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (const auto& sheet : mStyleSheetList) {
|
||||
n += sheet->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
n += mServoStyles
|
||||
? Servo_AuthorStyles_SizeOfIncludingThis(
|
||||
ServoAuthorStylesMallocSizeOf,
|
||||
ServoAuthorStylesMallocEnclosingSizeOf, mServoStyles.get())
|
||||
: 0;
|
||||
n += mStyleRuleMap ? mStyleRuleMap->SizeOfIncludingThis(aMallocSizeOf) : 0;
|
||||
|
||||
// Measurement of the following members may be added later if DMD finds it
|
||||
// is worthwhile:
|
||||
// - mLoader
|
||||
|
||||
return n;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsXBLPrototypeResources_h__
|
||||
#define nsXBLPrototypeResources_h__
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "nsICSSLoaderObserver.h"
|
||||
|
||||
class nsAtom;
|
||||
class nsIContent;
|
||||
class nsXBLPrototypeBinding;
|
||||
class nsXBLResourceLoader;
|
||||
struct RawServoAuthorStyles;
|
||||
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
class ServoStyleSet;
|
||||
class ServoStyleRuleMap;
|
||||
} // namespace mozilla
|
||||
|
||||
// *********************************************************************/
|
||||
// The XBLPrototypeResources class
|
||||
|
||||
class nsXBLPrototypeResources {
|
||||
public:
|
||||
explicit nsXBLPrototypeResources(nsXBLPrototypeBinding* aBinding);
|
||||
~nsXBLPrototypeResources();
|
||||
|
||||
bool LoadResources(nsIContent* aBoundElement);
|
||||
void AddResource(nsAtom* aResourceType, const nsAString& aSrc);
|
||||
void AddResourceListener(nsIContent* aElement);
|
||||
nsresult FlushSkinSheets();
|
||||
|
||||
nsresult Write(nsIObjectOutputStream* aStream);
|
||||
|
||||
void Traverse(nsCycleCollectionTraversalCallback& cb);
|
||||
void Unlink();
|
||||
|
||||
void ClearLoader();
|
||||
|
||||
void AppendStyleSheet(mozilla::StyleSheet* aSheet);
|
||||
void RemoveStyleSheet(mozilla::StyleSheet* aSheet);
|
||||
void InsertStyleSheetAt(size_t aIndex, mozilla::StyleSheet* aSheet);
|
||||
|
||||
mozilla::StyleSheet* StyleSheetAt(size_t aIndex) const {
|
||||
return mStyleSheetList[aIndex];
|
||||
}
|
||||
|
||||
size_t SheetCount() const { return mStyleSheetList.Length(); }
|
||||
|
||||
bool HasStyleSheets() const { return !mStyleSheetList.IsEmpty(); }
|
||||
|
||||
void AppendStyleSheetsTo(nsTArray<mozilla::StyleSheet*>& aResult) const;
|
||||
|
||||
const RawServoAuthorStyles* GetServoStyles() const {
|
||||
return mServoStyles.get();
|
||||
}
|
||||
|
||||
void SyncServoStyles();
|
||||
|
||||
mozilla::ServoStyleRuleMap* GetServoStyleRuleMap();
|
||||
|
||||
// Updates the ServoStyleSet object that holds the result of cascading the
|
||||
// sheets in mStyleSheetList. Equivalent to GatherRuleProcessor(), but for
|
||||
// the Servo style backend.
|
||||
void ComputeServoStyles(const mozilla::ServoStyleSet& aMasterStyleSet);
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
private:
|
||||
// A loader object. Exists only long enough to load resources, and then it
|
||||
// dies.
|
||||
RefPtr<nsXBLResourceLoader> mLoader;
|
||||
|
||||
// A list of loaded stylesheets for this binding.
|
||||
//
|
||||
// FIXME(emilio): Remove when the old style system is gone, defer to
|
||||
// mServoStyles.
|
||||
nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheetList;
|
||||
|
||||
// The result of cascading the XBL style sheets like mRuleProcessor, but
|
||||
// for the Servo style backend.
|
||||
mozilla::UniquePtr<RawServoAuthorStyles> mServoStyles;
|
||||
mozilla::UniquePtr<mozilla::ServoStyleRuleMap> mStyleRuleMap;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,251 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsTArray.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIPresShellInlines.h"
|
||||
#include "nsXBLService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsXBLResourceLoader.h"
|
||||
#include "nsXBLPrototypeResources.h"
|
||||
#include "nsIDocumentObserver.h"
|
||||
#include "imgILoader.h"
|
||||
#include "imgRequestProxy.h"
|
||||
#include "mozilla/ComputedStyle.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
#include "mozilla/css/Loader.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(nsXBLResourceLoader, mBoundElements)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXBLResourceLoader)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXBLResourceLoader)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXBLResourceLoader)
|
||||
|
||||
struct nsXBLResource {
|
||||
nsXBLResource* mNext;
|
||||
nsAtom* mType;
|
||||
nsString mSrc;
|
||||
|
||||
nsXBLResource(nsAtom* aType, const nsAString& aSrc) {
|
||||
MOZ_COUNT_CTOR(nsXBLResource);
|
||||
mNext = nullptr;
|
||||
mType = aType;
|
||||
mSrc = aSrc;
|
||||
}
|
||||
|
||||
~nsXBLResource() {
|
||||
MOZ_COUNT_DTOR(nsXBLResource);
|
||||
NS_CONTENT_DELETE_LIST_MEMBER(nsXBLResource, this, mNext);
|
||||
}
|
||||
};
|
||||
|
||||
nsXBLResourceLoader::nsXBLResourceLoader(nsXBLPrototypeBinding* aBinding,
|
||||
nsXBLPrototypeResources* aResources)
|
||||
: mBinding(aBinding),
|
||||
mResources(aResources),
|
||||
mResourceList(nullptr),
|
||||
mLastResource(nullptr),
|
||||
mLoadingResources(false),
|
||||
mInLoadResourcesFunc(false),
|
||||
mPendingSheets(0),
|
||||
mBoundDocument(nullptr) {}
|
||||
|
||||
nsXBLResourceLoader::~nsXBLResourceLoader() { delete mResourceList; }
|
||||
|
||||
bool nsXBLResourceLoader::LoadResources(nsIContent* aBoundElement) {
|
||||
mInLoadResourcesFunc = true;
|
||||
|
||||
if (mLoadingResources) {
|
||||
mInLoadResourcesFunc = false;
|
||||
return mPendingSheets == 0;
|
||||
}
|
||||
|
||||
mLoadingResources = true;
|
||||
|
||||
// Declare our loaders.
|
||||
nsCOMPtr<Document> doc = mBinding->XBLDocumentInfo()->GetDocument();
|
||||
mBoundDocument = aBoundElement->OwnerDoc();
|
||||
|
||||
mozilla::css::Loader* cssLoader = doc->CSSLoader();
|
||||
MOZ_ASSERT(cssLoader->GetDocument(), "Loader must have document");
|
||||
|
||||
nsIURI* docURL = doc->GetDocumentURI();
|
||||
nsIPrincipal* docPrincipal = doc->NodePrincipal();
|
||||
|
||||
nsCOMPtr<nsIURI> url;
|
||||
|
||||
for (nsXBLResource* curr = mResourceList; curr; curr = curr->mNext) {
|
||||
if (curr->mSrc.IsEmpty()) continue;
|
||||
|
||||
if (NS_FAILED(NS_NewURI(getter_AddRefs(url), curr->mSrc,
|
||||
doc->GetDocumentCharacterSet(), docURL)))
|
||||
continue;
|
||||
|
||||
if (curr->mType == nsGkAtoms::image) {
|
||||
// Now kick off the image load...
|
||||
// Passing nullptr for pretty much everything -- cause we don't care!
|
||||
// XXX: initialDocumentURI is nullptr!
|
||||
RefPtr<imgRequestProxy> req;
|
||||
nsContentUtils::LoadImage(url, doc, doc, docPrincipal, 0, docURL,
|
||||
doc->GetReferrerPolicy(), nullptr,
|
||||
nsIRequest::LOAD_BACKGROUND, EmptyString(),
|
||||
getter_AddRefs(req));
|
||||
} else if (curr->mType == nsGkAtoms::stylesheet) {
|
||||
// Kick off the load of the stylesheet.
|
||||
|
||||
// Always load chrome synchronously
|
||||
// XXXbz should that still do a content policy check?
|
||||
bool chrome;
|
||||
nsresult rv;
|
||||
if (NS_SUCCEEDED(url->SchemeIs("chrome", &chrome)) && chrome) {
|
||||
rv = nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
|
||||
docPrincipal, url, nsIScriptSecurityManager::ALLOW_CHROME);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
RefPtr<StyleSheet> sheet;
|
||||
rv = cssLoader->LoadSheetSync(url, &sheet);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Load failed!!!");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = StyleSheetLoaded(sheet, false, NS_OK);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Processing the style sheet failed!!!");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rv = cssLoader->LoadSheet(url, false, docPrincipal, nullptr, this);
|
||||
if (NS_SUCCEEDED(rv)) ++mPendingSheets;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mInLoadResourcesFunc = false;
|
||||
|
||||
// Destroy our resource list.
|
||||
delete mResourceList;
|
||||
mResourceList = nullptr;
|
||||
|
||||
return mPendingSheets == 0;
|
||||
}
|
||||
|
||||
// nsICSSLoaderObserver
|
||||
NS_IMETHODIMP
|
||||
nsXBLResourceLoader::StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
|
||||
nsresult aStatus) {
|
||||
if (!mResources) {
|
||||
// Our resources got destroyed -- just bail out
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mResources->AppendStyleSheet(aSheet);
|
||||
|
||||
if (!mInLoadResourcesFunc) mPendingSheets--;
|
||||
|
||||
if (mPendingSheets == 0) {
|
||||
// All stylesheets are loaded.
|
||||
|
||||
// Our document might have been undisplayed after this sheet load
|
||||
// was started, so check before building the XBL cascade data.
|
||||
if (PresShell* presShell = mBoundDocument->GetPresShell()) {
|
||||
mResources->ComputeServoStyles(*presShell->StyleSet());
|
||||
}
|
||||
|
||||
// XXX Check for mPendingScripts when scripts also come online.
|
||||
if (!mInLoadResourcesFunc) NotifyBoundElements();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsXBLResourceLoader::AddResource(nsAtom* aResourceType,
|
||||
const nsAString& aSrc) {
|
||||
nsXBLResource* res = new nsXBLResource(aResourceType, aSrc);
|
||||
if (!mResourceList)
|
||||
mResourceList = res;
|
||||
else
|
||||
mLastResource->mNext = res;
|
||||
|
||||
mLastResource = res;
|
||||
}
|
||||
|
||||
void nsXBLResourceLoader::AddResourceListener(nsIContent* aBoundElement) {
|
||||
if (aBoundElement) {
|
||||
mBoundElements.AppendObject(aBoundElement);
|
||||
aBoundElement->OwnerDoc()->BlockOnload();
|
||||
}
|
||||
}
|
||||
|
||||
void nsXBLResourceLoader::NotifyBoundElements() {
|
||||
nsXBLService* xblService = nsXBLService::GetInstance();
|
||||
if (!xblService) return;
|
||||
|
||||
nsIURI* bindingURI = mBinding->BindingURI();
|
||||
|
||||
uint32_t eltCount = mBoundElements.Count();
|
||||
for (uint32_t j = 0; j < eltCount; j++) {
|
||||
nsCOMPtr<nsIContent> content = mBoundElements.ObjectAt(j);
|
||||
MOZ_ASSERT(content->IsElement());
|
||||
content->OwnerDoc()->UnblockOnload(/* aFireSync = */ false);
|
||||
|
||||
bool ready = false;
|
||||
xblService->BindingReady(content, bindingURI, &ready);
|
||||
|
||||
if (!ready) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Document* doc = content->GetUncomposedDoc();
|
||||
if (!doc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PresShell* presShell = doc->GetPresShell();
|
||||
if (!presShell) {
|
||||
continue;
|
||||
}
|
||||
|
||||
presShell->PostRecreateFramesFor(content->AsElement());
|
||||
}
|
||||
|
||||
// Clear out the whole array.
|
||||
mBoundElements.Clear();
|
||||
|
||||
// Delete ourselves.
|
||||
mResources->ClearLoader();
|
||||
}
|
||||
|
||||
nsresult nsXBLResourceLoader::Write(nsIObjectOutputStream* aStream) {
|
||||
nsresult rv;
|
||||
|
||||
for (nsXBLResource* curr = mResourceList; curr; curr = curr->mNext) {
|
||||
if (curr->mType == nsGkAtoms::image)
|
||||
rv = aStream->Write8(XBLBinding_Serialize_Image);
|
||||
else if (curr->mType == nsGkAtoms::stylesheet)
|
||||
rv = aStream->Write8(XBLBinding_Serialize_Stylesheet);
|
||||
else
|
||||
continue;
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aStream->WriteWStringZ(curr->mSrc.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsXBLResourceLoader_h
|
||||
#define nsXBLResourceLoader_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsICSSLoaderObserver.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsAtom;
|
||||
class nsXBLPrototypeResources;
|
||||
class nsXBLPrototypeBinding;
|
||||
struct nsXBLResource;
|
||||
class nsIObjectOutputStream;
|
||||
|
||||
// *********************************************************************/
|
||||
// The XBLResourceLoader class
|
||||
|
||||
class nsXBLResourceLoader : public nsICSSLoaderObserver {
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(nsXBLResourceLoader)
|
||||
|
||||
// nsICSSLoaderObserver
|
||||
NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet, bool aWasAlternate,
|
||||
nsresult aStatus) override;
|
||||
|
||||
bool LoadResources(nsIContent* aBoundElement);
|
||||
void AddResource(nsAtom* aResourceType, const nsAString& aSrc);
|
||||
void AddResourceListener(nsIContent* aElement);
|
||||
|
||||
nsXBLResourceLoader(nsXBLPrototypeBinding* aBinding,
|
||||
nsXBLPrototypeResources* aResources);
|
||||
|
||||
void NotifyBoundElements();
|
||||
|
||||
nsresult Write(nsIObjectOutputStream* aStream);
|
||||
|
||||
// MEMBER VARIABLES
|
||||
nsXBLPrototypeBinding* mBinding; // A pointer back to our binding.
|
||||
nsXBLPrototypeResources* mResources; // A pointer back to our resources
|
||||
// information. May be null if the
|
||||
// resources have already been
|
||||
// destroyed.
|
||||
|
||||
nsXBLResource* mResourceList; // The list of resources we need to load.
|
||||
nsXBLResource* mLastResource;
|
||||
|
||||
bool mLoadingResources;
|
||||
// We need mInLoadResourcesFunc because we do a mixture of sync and
|
||||
// async loads.
|
||||
bool mInLoadResourcesFunc;
|
||||
int16_t mPendingSheets; // The number of stylesheets that have yet to load.
|
||||
|
||||
// Bound elements that are waiting on the stylesheets and scripts.
|
||||
nsCOMArray<nsIContent> mBoundElements;
|
||||
|
||||
protected:
|
||||
virtual ~nsXBLResourceLoader();
|
||||
|
||||
private:
|
||||
// The bound document is needed in StyleSheetLoaded() for servo style
|
||||
// backend, which will be set in LoadResources().
|
||||
dom::Document* MOZ_NON_OWNING_REF mBoundDocument;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -16,11 +16,14 @@ typedef uint8_t XBLBindingSerializeDetails;
|
|||
|
||||
// A version number to ensure we don't load cached data in a different
|
||||
// file format.
|
||||
#define XBLBinding_Serialize_Version 0x00000007
|
||||
#define XBLBinding_Serialize_Version 0x00000006
|
||||
|
||||
// Set for the first binding in a document
|
||||
#define XBLBinding_Serialize_IsFirstBinding (1 << 0)
|
||||
|
||||
// Set to indicate that nsXBLPrototypeBinding::mInheritStyle should be true
|
||||
#define XBLBinding_Serialize_InheritStyle (1 << 1)
|
||||
|
||||
// Set to indicate that nsXBLPrototypeBinding::mBindToUntrustedContent should be
|
||||
// true
|
||||
#define XBLBinding_Serialize_BindToUntrustedContent (1 << 3)
|
||||
|
@ -46,6 +49,8 @@ typedef uint8_t XBLBindingSerializeDetails;
|
|||
#define XBLBinding_Serialize_Constructor 6
|
||||
#define XBLBinding_Serialize_Destructor 7
|
||||
#define XBLBinding_Serialize_Handler 8
|
||||
#define XBLBinding_Serialize_Image 9
|
||||
#define XBLBinding_Serialize_Stylesheet 10
|
||||
#define XBLBinding_Serialize_Attribute 0xA
|
||||
#define XBLBinding_Serialize_Mask 0x0F
|
||||
#define XBLBinding_Serialize_ReadOnly 0x80
|
||||
|
|
|
@ -399,8 +399,11 @@ class MOZ_RAII AutoEnsureSubtreeStyled {
|
|||
// RAII class to restyle the XBL bound element when it shuffles the flat tree.
|
||||
class MOZ_RAII AutoStyleElement {
|
||||
public:
|
||||
explicit AutoStyleElement(Element* aElement)
|
||||
: mElement(aElement), mHadData(aElement->HasServoData()) {
|
||||
AutoStyleElement(Element* aElement, bool* aResolveStyle)
|
||||
: mElement(aElement),
|
||||
mHadData(aElement->HasServoData()),
|
||||
mResolveStyle(aResolveStyle) {
|
||||
MOZ_ASSERT(mResolveStyle);
|
||||
if (mHadData) {
|
||||
RestyleManager::ClearServoDataFromSubtree(
|
||||
mElement, RestyleManager::IncludeRoot::No);
|
||||
|
@ -412,11 +415,19 @@ class MOZ_RAII AutoStyleElement {
|
|||
if (!mHadData || !presShell || !presShell->DidInitialize()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (*mResolveStyle) {
|
||||
mElement->ClearServoData();
|
||||
|
||||
ServoStyleSet* servoSet = presShell->StyleSet();
|
||||
servoSet->StyleNewSubtree(mElement);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Element* mElement;
|
||||
bool mHadData;
|
||||
bool* mResolveStyle;
|
||||
};
|
||||
|
||||
static bool IsSystemOrChromeURLPrincipal(nsIPrincipal* aPrincipal) {
|
||||
|
@ -436,10 +447,12 @@ static bool IsSystemOrChromeURLPrincipal(nsIPrincipal* aPrincipal) {
|
|||
// onto the element.
|
||||
nsresult nsXBLService::LoadBindings(Element* aElement, nsIURI* aURL,
|
||||
nsIPrincipal* aOriginPrincipal,
|
||||
nsXBLBinding** aBinding) {
|
||||
nsXBLBinding** aBinding,
|
||||
bool* aResolveStyle) {
|
||||
MOZ_ASSERT(aOriginPrincipal, "Must have an origin principal");
|
||||
|
||||
*aBinding = nullptr;
|
||||
*aResolveStyle = false;
|
||||
|
||||
AutoEnsureSubtreeStyled subtreeStyled(aElement);
|
||||
|
||||
|
@ -483,7 +496,7 @@ nsresult nsXBLService::LoadBindings(Element* aElement, nsIURI* aURL,
|
|||
return rv;
|
||||
}
|
||||
|
||||
AutoStyleElement styleElement(aElement);
|
||||
AutoStyleElement styleElement(aElement, aResolveStyle);
|
||||
|
||||
if (binding) {
|
||||
FlushStyleBindings(aElement);
|
||||
|
@ -534,6 +547,9 @@ nsresult nsXBLService::LoadBindings(Element* aElement, nsIURI* aURL,
|
|||
rv = newBinding->InstallImplementation();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Figure out if we have any scoped sheets. If so, we do a second resolve.
|
||||
*aResolveStyle = newBinding->HasStyleSheets();
|
||||
|
||||
newBinding.forget(aBinding);
|
||||
}
|
||||
|
||||
|
@ -755,6 +771,15 @@ nsresult nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
|
|||
aDontExtendURIs.AppendElement(altBindingURI);
|
||||
}
|
||||
|
||||
// Our prototype binding must have all its resources loaded.
|
||||
bool ready = protoBinding->LoadResources(aBoundElement);
|
||||
if (!ready) {
|
||||
// Add our bound element to the protos list of elts that should
|
||||
// be notified when the stylesheets and scripts finish loading.
|
||||
protoBinding->AddResourceListener(aBoundElement);
|
||||
return NS_ERROR_FAILURE; // The binding isn't ready yet.
|
||||
}
|
||||
|
||||
rv = protoBinding->ResolveBaseBinding();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ class nsIPrincipal;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Document;
|
||||
class Element;
|
||||
class EventTarget;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -45,8 +44,8 @@ class nsXBLService final : public nsSupportsWeakReference {
|
|||
// This function loads a particular XBL file and installs all of the bindings
|
||||
// onto the element. aOriginPrincipal must not be null here.
|
||||
nsresult LoadBindings(mozilla::dom::Element* aElement, nsIURI* aURL,
|
||||
nsIPrincipal* aOriginPrincipal,
|
||||
nsXBLBinding** aBinding);
|
||||
nsIPrincipal* aOriginPrincipal, nsXBLBinding** aBinding,
|
||||
bool* aResolveStyle);
|
||||
|
||||
// Indicates whether or not a binding is fully loaded.
|
||||
nsresult BindingReady(nsIContent* aBoundElement, nsIURI* aURI,
|
||||
|
|
|
@ -229,6 +229,13 @@ void nsXULPrototypeCache::FlushSkinFiles() {
|
|||
iter.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over all the remaining XBL and make sure cached
|
||||
// scoped skin stylesheets are flushed and refetched by the
|
||||
// prototype bindings.
|
||||
for (auto iter = mXBLDocTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.Data()->FlushSkinStylesheets();
|
||||
}
|
||||
}
|
||||
|
||||
void nsXULPrototypeCache::FlushScripts() { mScriptTable.Clear(); }
|
||||
|
|
|
@ -2252,6 +2252,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
|
|||
if (display->mBinding) {
|
||||
// Get the XBL loader.
|
||||
nsresult rv;
|
||||
bool resolveStyle;
|
||||
|
||||
nsXBLService* xblService = nsXBLService::GetInstance();
|
||||
if (!xblService) {
|
||||
|
@ -2261,7 +2262,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
|
|||
RefPtr<nsXBLBinding> binding;
|
||||
rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(),
|
||||
display->mBinding->ExtraData()->Principal(),
|
||||
getter_AddRefs(binding));
|
||||
getter_AddRefs(binding), &resolveStyle);
|
||||
if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED) {
|
||||
// Binding will load asynchronously.
|
||||
return nullptr;
|
||||
|
@ -2273,6 +2274,11 @@ nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
|
|||
// manager about it right now.
|
||||
mDocument->BindingManager()->AddToAttachedQueue(binding);
|
||||
}
|
||||
|
||||
if (resolveStyle) {
|
||||
computedStyle = mPresShell->StyleSet()->ResolveServoStyle(*aDocElement);
|
||||
display = computedStyle->StyleDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
// --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
|
||||
|
@ -5298,21 +5304,28 @@ nsCSSFrameConstructor::FindElementTagData(const Element& aElement,
|
|||
}
|
||||
|
||||
nsCSSFrameConstructor::XBLBindingLoadInfo::XBLBindingLoadInfo(
|
||||
already_AddRefed<ComputedStyle>&& aStyle,
|
||||
UniquePtr<PendingBinding> aPendingBinding)
|
||||
: mPendingBinding(std::move(aPendingBinding)), mSuccess(true) {}
|
||||
: mStyle(std::move(aStyle)), mPendingBinding(std::move(aPendingBinding)) {
|
||||
MOZ_ASSERT(mStyle);
|
||||
}
|
||||
|
||||
nsCSSFrameConstructor::XBLBindingLoadInfo::XBLBindingLoadInfo(
|
||||
nsIContent& aContent, ComputedStyle& aStyle)
|
||||
: mStyle(&aStyle), mPendingBinding(nullptr) {}
|
||||
|
||||
nsCSSFrameConstructor::XBLBindingLoadInfo::XBLBindingLoadInfo() = default;
|
||||
|
||||
nsCSSFrameConstructor::XBLBindingLoadInfo
|
||||
nsCSSFrameConstructor::LoadXBLBindingIfNeeded(nsIContent& aContent,
|
||||
const ComputedStyle& aStyle,
|
||||
ComputedStyle& aStyle,
|
||||
uint32_t aFlags) {
|
||||
if (!(aFlags & ITEM_ALLOW_XBL_BASE)) {
|
||||
return XBLBindingLoadInfo(nullptr);
|
||||
return {aContent, aStyle};
|
||||
}
|
||||
css::URLValue* binding = aStyle.StyleDisplay()->mBinding;
|
||||
if (!binding) {
|
||||
return XBLBindingLoadInfo(nullptr);
|
||||
return {aContent, aStyle};
|
||||
}
|
||||
|
||||
nsXBLService* xblService = nsXBLService::GetInstance();
|
||||
|
@ -5322,18 +5335,24 @@ nsCSSFrameConstructor::LoadXBLBindingIfNeeded(nsIContent& aContent,
|
|||
|
||||
auto newPendingBinding = MakeUnique<PendingBinding>();
|
||||
|
||||
nsresult rv =
|
||||
xblService->LoadBindings(aContent.AsElement(), binding->GetURI(),
|
||||
binding->ExtraData()->Principal(),
|
||||
getter_AddRefs(newPendingBinding->mBinding));
|
||||
bool resolveStyle;
|
||||
nsresult rv = xblService->LoadBindings(
|
||||
aContent.AsElement(), binding->GetURI(),
|
||||
binding->ExtraData()->Principal(),
|
||||
getter_AddRefs(newPendingBinding->mBinding), &resolveStyle);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (rv == NS_ERROR_XBL_BLOCKED) {
|
||||
return XBLBindingLoadInfo(nullptr);
|
||||
return {aContent, aStyle};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
return XBLBindingLoadInfo(std::move(newPendingBinding));
|
||||
RefPtr<ComputedStyle> style =
|
||||
resolveStyle
|
||||
? mPresShell->StyleSet()->ResolveServoStyle(*aContent.AsElement())
|
||||
: do_AddRef(&aStyle);
|
||||
|
||||
return {style.forget(), std::move(newPendingBinding)};
|
||||
}
|
||||
|
||||
void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
|
||||
|
@ -5348,10 +5367,11 @@ void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
|
|||
aContent->NodeInfo()->NameAtom() == nsGkAtoms::area);
|
||||
|
||||
PendingBinding* pendingBinding = nullptr;
|
||||
RefPtr<ComputedStyle> style;
|
||||
{
|
||||
XBLBindingLoadInfo xblInfo =
|
||||
LoadXBLBindingIfNeeded(*aContent, *aComputedStyle, aFlags);
|
||||
if (!xblInfo.mSuccess) {
|
||||
if (!xblInfo.mStyle) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5359,10 +5379,13 @@ void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
|
|||
pendingBinding = xblInfo.mPendingBinding.get();
|
||||
aState.AddPendingBinding(std::move(xblInfo.mPendingBinding));
|
||||
}
|
||||
|
||||
style = xblInfo.mStyle.forget();
|
||||
aComputedStyle = style.get();
|
||||
}
|
||||
|
||||
const bool isGeneratedContent = !!(aFlags & ITEM_IS_GENERATED_CONTENT);
|
||||
MOZ_ASSERT(!isGeneratedContent || aComputedStyle->IsPseudoElement(),
|
||||
MOZ_ASSERT(!isGeneratedContent || style->IsPseudoElement(),
|
||||
"Generated content should be a pseudo-element");
|
||||
|
||||
FrameConstructionItem* item = nullptr;
|
||||
|
@ -5375,7 +5398,7 @@ void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
|
|||
}
|
||||
});
|
||||
|
||||
const nsStyleDisplay& display = *aComputedStyle->StyleDisplay();
|
||||
const nsStyleDisplay& display = *style->StyleDisplay();
|
||||
|
||||
// Pre-check for display "none" - if we find that, don't create
|
||||
// any frame at all
|
||||
|
@ -5385,8 +5408,7 @@ void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
|
|||
|
||||
if (display.mDisplay == StyleDisplay::Contents) {
|
||||
CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
|
||||
*aComputedStyle, PseudoStyleType::before,
|
||||
aItems);
|
||||
*style, PseudoStyleType::before, aItems);
|
||||
|
||||
FlattenedChildIterator iter(aContent);
|
||||
InsertionPoint insertion(aParentFrame, aContent);
|
||||
|
@ -5398,7 +5420,7 @@ void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
|
|||
aItems.SetParentHasNoXBLChildren(!iter.XBLInvolved());
|
||||
|
||||
CreateGeneratedContentItem(aState, aParentFrame, *aContent->AsElement(),
|
||||
*aComputedStyle, PseudoStyleType::after, aItems);
|
||||
*style, PseudoStyleType::after, aItems);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5418,7 +5440,7 @@ void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
|
|||
}
|
||||
|
||||
const FrameConstructionData* data =
|
||||
FindDataForContent(*aContent, *aComputedStyle, aParentFrame, aFlags);
|
||||
FindDataForContent(*aContent, *style, aParentFrame, aFlags);
|
||||
if (!data || data->mBits & FCDATA_SUPPRESS_FRAME) {
|
||||
return;
|
||||
}
|
||||
|
@ -5460,16 +5482,15 @@ void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
|
|||
if (summary && summary->IsMainSummary()) {
|
||||
// If details is open, the main summary needs to be rendered as if it is
|
||||
// the first child, so add the item to the front of the item list.
|
||||
item = aItems.PrependItem(this, data, aContent, pendingBinding,
|
||||
do_AddRef(aComputedStyle),
|
||||
aSuppressWhiteSpaceOptimizations);
|
||||
item =
|
||||
aItems.PrependItem(this, data, aContent, pendingBinding,
|
||||
style.forget(), aSuppressWhiteSpaceOptimizations);
|
||||
}
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
item = aItems.AppendItem(this, data, aContent, pendingBinding,
|
||||
do_AddRef(aComputedStyle),
|
||||
aSuppressWhiteSpaceOptimizations);
|
||||
style.forget(), aSuppressWhiteSpaceOptimizations);
|
||||
}
|
||||
item->mIsText = !aContent->IsElement();
|
||||
item->mIsGeneratedContent = isGeneratedContent;
|
||||
|
|
|
@ -770,16 +770,22 @@ class nsCSSFrameConstructor final : public nsFrameManager {
|
|||
// This is expected to just be used temporarily to aggregate the different
|
||||
// objects that LoadXBLBindingIfNeeded returns.
|
||||
struct MOZ_STACK_CLASS XBLBindingLoadInfo {
|
||||
RefPtr<ComputedStyle> mStyle;
|
||||
mozilla::UniquePtr<PendingBinding> mPendingBinding;
|
||||
bool mSuccess = false;
|
||||
|
||||
// For the 'no binding loaded' case.
|
||||
XBLBindingLoadInfo(nsIContent&, ComputedStyle&);
|
||||
|
||||
// For the case we actually load an XBL binding.
|
||||
XBLBindingLoadInfo(already_AddRefed<ComputedStyle>&& aStyle,
|
||||
mozilla::UniquePtr<PendingBinding> aPendingBinding);
|
||||
|
||||
// For the error case.
|
||||
XBLBindingLoadInfo();
|
||||
explicit XBLBindingLoadInfo(mozilla::UniquePtr<PendingBinding>);
|
||||
};
|
||||
|
||||
// Returns null mStyle member to signal an error.
|
||||
XBLBindingLoadInfo LoadXBLBindingIfNeeded(nsIContent&, const ComputedStyle&,
|
||||
XBLBindingLoadInfo LoadXBLBindingIfNeeded(nsIContent&, ComputedStyle&,
|
||||
uint32_t aFlags);
|
||||
|
||||
const FrameConstructionData* FindDataForContent(nsIContent&, ComputedStyle&,
|
||||
|
|
|
@ -184,6 +184,22 @@ void InspectorUtils::GetCSSStyleRules(
|
|||
maps.AppendElement(map);
|
||||
}
|
||||
|
||||
// Collect style rule maps for bindings.
|
||||
for (nsIContent* bindingContent = &aElement; bindingContent;
|
||||
bindingContent = bindingContent->GetBindingParent()) {
|
||||
for (nsXBLBinding* binding = bindingContent->GetXBLBinding(); binding;
|
||||
binding = binding->GetBaseBinding()) {
|
||||
if (auto* map = binding->PrototypeBinding()->GetServoStyleRuleMap()) {
|
||||
maps.AppendElement(map);
|
||||
}
|
||||
}
|
||||
// Note that we intentionally don't cut off here, unlike when we
|
||||
// do styling, because even if style rules from parent binding
|
||||
// do not apply to the element directly in those cases, their
|
||||
// rules may still show up in the list we get above due to the
|
||||
// inheritance in cascading.
|
||||
}
|
||||
|
||||
// Now shadow DOM stuff...
|
||||
if (auto* shadow = aElement.GetShadowRoot()) {
|
||||
maps.AppendElement(&shadow->ServoStyleRuleMap());
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "mozilla/ServoStyleSet.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
#include "nsStyleSheetService.h"
|
||||
#include "nsXBLPrototypeResources.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
|
@ -29,6 +30,15 @@ void ServoStyleRuleMap::EnsureTable(ServoStyleSet& aStyleSet) {
|
|||
[&](StyleSheet& aSheet) { FillTableFromStyleSheet(aSheet); });
|
||||
}
|
||||
|
||||
void ServoStyleRuleMap::EnsureTable(nsXBLPrototypeResources& aXBLResources) {
|
||||
if (!IsEmpty() || !aXBLResources.GetServoStyles()) {
|
||||
return;
|
||||
}
|
||||
for (auto index : IntegerRange(aXBLResources.SheetCount())) {
|
||||
FillTableFromStyleSheet(*aXBLResources.StyleSheetAt(index));
|
||||
}
|
||||
}
|
||||
|
||||
void ServoStyleRuleMap::EnsureTable(ShadowRoot& aShadowRoot) {
|
||||
if (!IsEmpty()) {
|
||||
return;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "nsDataHashtable.h"
|
||||
|
||||
struct RawServoStyleRule;
|
||||
class nsXBLPrototypeResources;
|
||||
|
||||
namespace mozilla {
|
||||
class ServoCSSRuleList;
|
||||
|
@ -28,6 +29,7 @@ class ServoStyleRuleMap {
|
|||
ServoStyleRuleMap() = default;
|
||||
|
||||
void EnsureTable(ServoStyleSet&);
|
||||
void EnsureTable(nsXBLPrototypeResources&);
|
||||
void EnsureTable(dom::ShadowRoot&);
|
||||
|
||||
dom::CSSStyleRule* Lookup(const RawServoStyleRule* aRawRule) const {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference for bug 1375513</title>
|
||||
<style type="text/css">
|
||||
input[type=range] {
|
||||
width: 200px;
|
||||
height: 20px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
input[type=range]::-moz-range-progress {
|
||||
height: 10px;
|
||||
background-color: lime;
|
||||
}
|
||||
|
||||
input[type=range]::-moz-range-track,
|
||||
input[type=range]::-moz-range-thumb {
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<input type="range">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
input[type=range] {
|
||||
width: 200px;
|
||||
height: 20px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
input[type=range]::-moz-range-progress {
|
||||
height: 10px;
|
||||
background-color: lime;
|
||||
}
|
||||
|
||||
input[type=range]::-moz-range-track,
|
||||
input[type=range]::-moz-range-thumb {
|
||||
visibility: hidden;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for bug 1375513</title>
|
||||
<style type="text/css">
|
||||
#input {
|
||||
-moz-binding: url(1375513.xml#createInputRange);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="input"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0"?>
|
||||
<bindings xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
<binding id="createInputRange">
|
||||
<resources>
|
||||
<stylesheet src="1375513.css"/>
|
||||
</resources>
|
||||
<content><html:input type="range"/></content>
|
||||
</binding>
|
||||
</bindings>
|
|
@ -2054,6 +2054,7 @@ skip-if(isDebugBuild&&winWidget) == 1330051.svg 1330051-ref.svg
|
|||
== 1375315-11.html 1375315-11-ref.html
|
||||
== 1375315-12.html 1375315-12-ref.html
|
||||
== 1374062.html 1374062-ref.html
|
||||
== 1375513.html 1375513-ref.html
|
||||
== 1375674.html 1375674-ref.html
|
||||
== 1372041.html 1372041-ref.html
|
||||
== 1376092.html 1376092-ref.html
|
||||
|
|
|
@ -62,6 +62,8 @@ fuzzy-if(skiaContent,0-1,0-60) fuzzy-if(cocoaWidget&&browserIsRemote&&!skiaConte
|
|||
== object-position-png-001.xul object-position-png-001-ref.html
|
||||
== object-position-png-002.xul object-position-png-002-ref.html
|
||||
|
||||
== root-binding-style.xul green-ref.xul
|
||||
|
||||
== stack-sizing-1.xul stack-sizing-1-ref.xul
|
||||
== stack-sizing-2.xul stack-sizing-2-ref.xul
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
|
||||
test {
|
||||
background-color: green;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0"?>
|
||||
<test xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" style="-moz-binding: url(xbl_bindings.xml#root_binding_style)">
|
||||
</test>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0"?>
|
||||
<bindings xmlns="http://www.mozilla.org/xbl">
|
||||
<binding id="root_binding_style">
|
||||
<resources>
|
||||
<stylesheet src="root-binding-style-xbl.css"/>
|
||||
</resources>
|
||||
</binding>
|
||||
</bindings>
|
|
@ -1957,6 +1957,15 @@ const Element* Gecko_GetBindingParent(const Element* aElement) {
|
|||
return parent ? parent->AsElement() : nullptr;
|
||||
}
|
||||
|
||||
const RawServoAuthorStyles* Gecko_XBLBinding_GetRawServoStyles(
|
||||
const nsXBLBinding* aXBLBinding) {
|
||||
return aXBLBinding->GetServoStyles();
|
||||
}
|
||||
|
||||
bool Gecko_XBLBinding_InheritsStyle(const nsXBLBinding* aXBLBinding) {
|
||||
return aXBLBinding->InheritsStyle();
|
||||
}
|
||||
|
||||
static StaticRefPtr<UACacheReporter> gUACacheReporter;
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -695,6 +695,10 @@ mozilla::FontSizePrefs Gecko_GetBaseSize(nsAtom* lang);
|
|||
const mozilla::dom::Element* Gecko_GetBindingParent(
|
||||
const mozilla::dom::Element*);
|
||||
|
||||
const RawServoAuthorStyles* Gecko_XBLBinding_GetRawServoStyles(
|
||||
const nsXBLBinding*);
|
||||
bool Gecko_XBLBinding_InheritsStyle(const nsXBLBinding* aXBLBinding);
|
||||
|
||||
struct GeckoFontMetrics {
|
||||
nscoord mChSize; // -1.0 indicates not found
|
||||
nscoord mXSize;
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "mozilla/dom/DocumentInlines.h"
|
||||
#include "nsMediaFeatures.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
#include "nsBindingManager.h"
|
||||
#include "nsWindowSizes.h"
|
||||
|
@ -140,7 +141,7 @@ void ServoStyleSet::ShellDetachedFromDocument() {
|
|||
void ServoStyleSet::RecordShadowStyleChange(ShadowRoot& aShadowRoot) {
|
||||
// TODO(emilio): We could keep track of the actual shadow roots that need
|
||||
// their styles recomputed.
|
||||
SetStylistShadowDOMStyleSheetsDirty();
|
||||
SetStylistXBLStyleSheetsDirty();
|
||||
|
||||
// FIXME(emilio): This should be done using stylesheet invalidation instead.
|
||||
if (nsPresContext* pc = GetPresContext()) {
|
||||
|
@ -165,8 +166,9 @@ void ServoStyleSet::InvalidateStyleForDocumentStateChanges(
|
|||
}
|
||||
|
||||
// TODO(emilio): It may be nicer to just invalidate stuff in a given subtree
|
||||
// for Shadow DOM. Consider just enumerating shadow roots instead and run
|
||||
// invalidation individually, passing mRawSet for the UA / User sheets.
|
||||
// for XBL sheets / Shadow DOM. Consider just enumerating bound content
|
||||
// instead and run invalidation individually, passing mRawSet for the UA /
|
||||
// User sheets.
|
||||
AutoTArray<const RawServoAuthorStyles*, 20> nonDocumentStyles;
|
||||
|
||||
EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
|
||||
|
@ -175,6 +177,14 @@ void ServoStyleSet::InvalidateStyleForDocumentStateChanges(
|
|||
}
|
||||
});
|
||||
|
||||
mDocument->BindingManager()->EnumerateBoundContentProtoBindings(
|
||||
[&](nsXBLPrototypeBinding* aProto) {
|
||||
if (auto* authorStyles = aProto->GetServoStyles()) {
|
||||
nonDocumentStyles.AppendElement(authorStyles);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
Servo_InvalidateStyleForDocStateChanges(
|
||||
root, mRawSet.get(), &nonDocumentStyles, aStatesChanged.ServoValue());
|
||||
}
|
||||
|
@ -198,6 +208,15 @@ RestyleHint ServoStyleSet::MediumFeaturesChanged(
|
|||
}
|
||||
});
|
||||
|
||||
// FIXME(emilio): This is broken for XBL. See bug 1406875.
|
||||
mDocument->BindingManager()->EnumerateBoundContentProtoBindings(
|
||||
[&](nsXBLPrototypeBinding* aProto) {
|
||||
if (auto* authorStyles = aProto->GetServoStyles()) {
|
||||
nonDocumentStyles.AppendElement(authorStyles);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
bool mayAffectDefaultStyle =
|
||||
bool(aReason & kMediaFeaturesAffectingDefaultStyle);
|
||||
|
||||
|
@ -213,7 +232,7 @@ RestyleHint ServoStyleSet::MediumFeaturesChanged(
|
|||
}
|
||||
|
||||
if (result.mAffectsNonDocumentRules) {
|
||||
SetStylistShadowDOMStyleSheetsDirty();
|
||||
SetStylistXBLStyleSheetsDirty();
|
||||
}
|
||||
|
||||
if (rulesChanged) {
|
||||
|
@ -643,11 +662,14 @@ StyleSheet* ServoStyleSet::SheetAt(Origin aOrigin, size_t aIndex) const {
|
|||
|
||||
void ServoStyleSet::AppendAllNonDocumentAuthorSheets(
|
||||
nsTArray<StyleSheet*>& aArray) const {
|
||||
EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
|
||||
for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
|
||||
aArray.AppendElement(aShadowRoot.SheetAt(index));
|
||||
}
|
||||
});
|
||||
if (mDocument) {
|
||||
mDocument->BindingManager()->AppendAllSheets(aArray);
|
||||
EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
|
||||
for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
|
||||
aArray.AppendElement(aShadowRoot.SheetAt(index));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ServoStyleSet::AddDocStyleSheet(StyleSheet* aSheet) {
|
||||
|
@ -871,8 +893,8 @@ void ServoStyleSet::SetStylistStyleSheetsDirty() {
|
|||
}
|
||||
}
|
||||
|
||||
void ServoStyleSet::SetStylistShadowDOMStyleSheetsDirty() {
|
||||
mStylistState |= StylistState::ShadowDOMStyleSheetsDirty;
|
||||
void ServoStyleSet::SetStylistXBLStyleSheetsDirty() {
|
||||
mStylistState |= StylistState::XBLStyleSheetsDirty;
|
||||
if (nsPresContext* presContext = GetPresContext()) {
|
||||
presContext->RestyleManager()->IncrementUndisplayedRestyleGeneration();
|
||||
}
|
||||
|
@ -982,7 +1004,8 @@ already_AddRefed<RawServoAnimationValue> ServoStyleSet::ComputeAnimationValue(
|
|||
}
|
||||
|
||||
bool ServoStyleSet::EnsureUniqueInnerOnCSSSheets() {
|
||||
using SheetOwner = Variant<ServoStyleSet*, ShadowRoot*>;
|
||||
using SheetOwner =
|
||||
Variant<ServoStyleSet*, nsXBLPrototypeBinding*, ShadowRoot*>;
|
||||
|
||||
AutoTArray<Pair<StyleSheet*, SheetOwner>, 32> queue;
|
||||
EnumerateStyleSheets([&](StyleSheet& aSheet) {
|
||||
|
@ -996,6 +1019,16 @@ bool ServoStyleSet::EnsureUniqueInnerOnCSSSheets() {
|
|||
}
|
||||
});
|
||||
|
||||
mDocument->BindingManager()->EnumerateBoundContentProtoBindings(
|
||||
[&](nsXBLPrototypeBinding* aProto) {
|
||||
AutoTArray<StyleSheet*, 3> sheets;
|
||||
aProto->AppendStyleSheetsTo(sheets);
|
||||
for (auto* sheet : sheets) {
|
||||
queue.AppendElement(MakePair(sheet, SheetOwner{aProto}));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
bool anyNonDocStyleChanged = false;
|
||||
while (!queue.IsEmpty()) {
|
||||
uint32_t idx = queue.Length() - 1;
|
||||
|
@ -1003,9 +1036,13 @@ bool ServoStyleSet::EnsureUniqueInnerOnCSSSheets() {
|
|||
SheetOwner owner = queue[idx].second();
|
||||
queue.RemoveElementAt(idx);
|
||||
|
||||
if (!sheet->HasUniqueInner() && owner.is<ShadowRoot*>()) {
|
||||
RawServoAuthorStyles* authorStyles =
|
||||
owner.as<ShadowRoot*>()->GetServoStyles();
|
||||
if (!sheet->HasUniqueInner()) {
|
||||
RawServoAuthorStyles* authorStyles = nullptr;
|
||||
if (owner.is<ShadowRoot*>()) {
|
||||
authorStyles = owner.as<ShadowRoot*>()->GetServoStyles();
|
||||
} else if (owner.is<nsXBLPrototypeBinding*>()) {
|
||||
authorStyles = owner.as<nsXBLPrototypeBinding*>()->GetServoStyles();
|
||||
}
|
||||
|
||||
if (authorStyles) {
|
||||
Servo_AuthorStyles_ForceDirty(authorStyles);
|
||||
|
@ -1033,7 +1070,7 @@ bool ServoStyleSet::EnsureUniqueInnerOnCSSSheets() {
|
|||
}
|
||||
|
||||
if (anyNonDocStyleChanged) {
|
||||
SetStylistShadowDOMStyleSheetsDirty();
|
||||
SetStylistXBLStyleSheetsDirty();
|
||||
}
|
||||
|
||||
if (mNeedsRestyleAfterEnsureUniqueInner) {
|
||||
|
@ -1063,7 +1100,7 @@ void ServoStyleSet::CompatibilityModeChanged() {
|
|||
}
|
||||
});
|
||||
if (anyShadow) {
|
||||
SetStylistShadowDOMStyleSheetsDirty();
|
||||
SetStylistXBLStyleSheetsDirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1153,6 +1190,9 @@ void ServoStyleSet::UpdateStylist() {
|
|||
MOZ_ASSERT(StylistNeedsUpdate());
|
||||
|
||||
if (mStylistState & StylistState::StyleSheetsDirty) {
|
||||
// There's no need to compute invalidations and such for an XBL styleset,
|
||||
// since they are loaded and unloaded synchronously, and they don't have to
|
||||
// deal with dynamic content changes.
|
||||
Element* root = mDocument->GetRootElement();
|
||||
const ServoElementSnapshotTable* snapshots = nullptr;
|
||||
if (nsPresContext* pc = GetPresContext()) {
|
||||
|
@ -1161,12 +1201,20 @@ void ServoStyleSet::UpdateStylist() {
|
|||
Servo_StyleSet_FlushStyleSheets(mRawSet.get(), root, snapshots);
|
||||
}
|
||||
|
||||
if (MOZ_UNLIKELY(mStylistState & StylistState::ShadowDOMStyleSheetsDirty)) {
|
||||
if (MOZ_UNLIKELY(mStylistState & StylistState::XBLStyleSheetsDirty)) {
|
||||
EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
|
||||
if (auto* authorStyles = aShadowRoot.GetServoStyles()) {
|
||||
Servo_AuthorStyles_Flush(authorStyles, mRawSet.get());
|
||||
}
|
||||
});
|
||||
|
||||
mDocument->BindingManager()->EnumerateBoundContentProtoBindings(
|
||||
[&](nsXBLPrototypeBinding* aProto) {
|
||||
if (auto* authorStyles = aProto->GetServoStyles()) {
|
||||
Servo_AuthorStyles_Flush(authorStyles, mRawSet.get());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
mStylistState = StylistState::NotDirty;
|
||||
|
|
|
@ -57,9 +57,9 @@ enum class StylistState : uint8_t {
|
|||
// The style sheets have changed, so we need to update the style data.
|
||||
StyleSheetsDirty = 1 << 0,
|
||||
|
||||
// Some of the style sheets of the shadow trees in the document have
|
||||
// changed.
|
||||
ShadowDOMStyleSheetsDirty = 1 << 1,
|
||||
// Some of the style sheets of the bound elements in binding manager have
|
||||
// changed, so we need to tell the binding manager to update style data.
|
||||
XBLStyleSheetsDirty = 1 << 1,
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(StylistState)
|
||||
|
@ -480,7 +480,7 @@ class ServoStyleSet {
|
|||
*/
|
||||
void SetStylistStyleSheetsDirty();
|
||||
|
||||
void SetStylistShadowDOMStyleSheetsDirty();
|
||||
void SetStylistXBLStyleSheetsDirty();
|
||||
|
||||
bool StylistNeedsUpdate() const {
|
||||
return mStylistState != StylistState::NotDirty;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0"?>
|
||||
<bindings xmlns="http://www.mozilla.org/xbl">
|
||||
<binding id="binding">
|
||||
<resources>
|
||||
<stylesheet src="media_queries_dynamic_xbl_style.css" />
|
||||
</resources>
|
||||
<content>
|
||||
<html:div xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
<children/>
|
||||
</html:div>
|
||||
</content>
|
||||
</binding>
|
||||
</bindings>
|
|
@ -0,0 +1,5 @@
|
|||
<!DOCTYPE HTML>
|
||||
<style type="text/css">
|
||||
body { -moz-binding: url(media_queries_dynamic_xbl_binding.xml#binding); }
|
||||
</style>
|
||||
<p id="para">Hello</p>
|
|
@ -0,0 +1,6 @@
|
|||
@media (orientation: portrait) {
|
||||
div { color: purple; }
|
||||
}
|
||||
@media (orientation: landscape) {
|
||||
div { color: blue; }
|
||||
}
|
|
@ -21,6 +21,9 @@ support-files =
|
|||
empty.html
|
||||
file_computed_style_bfcache_display_none.html
|
||||
file_computed_style_bfcache_display_none2.html
|
||||
media_queries_dynamic_xbl_binding.xml
|
||||
media_queries_dynamic_xbl_iframe.html
|
||||
media_queries_dynamic_xbl_style.css
|
||||
media_queries_iframe.html
|
||||
neverending_font_load.sjs
|
||||
neverending_stylesheet_load.sjs
|
||||
|
@ -262,6 +265,7 @@ support-files = slow_broken_sheet.sjs slow_ok_sheet.sjs
|
|||
# debug-only failure; timed out #Android 4.3 aws only; bug 1030419
|
||||
skip-if = (verify || android_version == '18')
|
||||
[test_media_queries_dynamic.html]
|
||||
[test_media_queries_dynamic_xbl.html]
|
||||
[test_media_query_list.html]
|
||||
[test_media_query_serialization.html]
|
||||
[test_mq_any_hover_and_any_pointer.html]
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=156716
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 156716</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="run()">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=156716">Mozilla Bug 156716</a>
|
||||
<iframe id="display" src="media_queries_dynamic_xbl_iframe.html"></iframe>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 156716 **/
|
||||
|
||||
function run() {
|
||||
var iframe = document.getElementById("display");
|
||||
|
||||
var subdoc = iframe.contentDocument;
|
||||
var subwin = iframe.contentWindow;
|
||||
var p = subdoc.getElementById("para");
|
||||
|
||||
iframe.setAttribute("style", "height: 300px; width: 100px");
|
||||
is(subwin.getComputedStyle(p).color, "rgb(128, 0, 128)",
|
||||
"should be purple when portait");
|
||||
iframe.setAttribute("style", "height: 100px; width: 300px");
|
||||
is(subwin.getComputedStyle(p).color, "rgb(0, 0, 255)",
|
||||
"should be blue when landscape");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -279,13 +279,13 @@ where
|
|||
/// Runs F with a given shadow host which is the root of the tree whose
|
||||
/// rules we're matching.
|
||||
#[inline]
|
||||
pub fn with_shadow_host<F, E, R>(&mut self, host: E, f: F) -> R
|
||||
pub fn with_shadow_host<F, E, R>(&mut self, host: Option<E>, f: F) -> R
|
||||
where
|
||||
E: Element,
|
||||
F: FnOnce(&mut Self) -> R,
|
||||
{
|
||||
let original_host = self.current_host.take();
|
||||
self.current_host = Some(host.opaque());
|
||||
self.current_host = host.map(|h| h.opaque());
|
||||
let result = f(self);
|
||||
self.current_host = original_host;
|
||||
result
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! A set of author stylesheets and their computed representation, such as the
|
||||
//! ones used for ShadowRoot.
|
||||
//! ones used for ShadowRoot and XBL.
|
||||
|
||||
use crate::context::QuirksMode;
|
||||
use crate::dom::TElement;
|
||||
|
@ -17,7 +17,7 @@ use crate::stylesheets::StylesheetInDocument;
|
|||
use crate::stylist::CascadeData;
|
||||
|
||||
/// A set of author stylesheets and their computed representation, such as the
|
||||
/// ones used for ShadowRoot.
|
||||
/// ones used for ShadowRoot and XBL.
|
||||
pub struct AuthorStyles<S>
|
||||
where
|
||||
S: StylesheetInDocument + PartialEq + 'static,
|
||||
|
@ -27,6 +27,9 @@ where
|
|||
pub stylesheets: AuthorStylesheetSet<S>,
|
||||
/// The actual cascade data computed from the stylesheets.
|
||||
pub data: CascadeData,
|
||||
/// The quirks mode of the last stylesheet flush, used because XBL sucks and
|
||||
/// we should really fix it, see bug 1406875.
|
||||
pub quirks_mode: QuirksMode,
|
||||
}
|
||||
|
||||
impl<S> AuthorStyles<S>
|
||||
|
@ -39,6 +42,7 @@ where
|
|||
Self {
|
||||
stylesheets: AuthorStylesheetSet::new(),
|
||||
data: CascadeData::new(),
|
||||
quirks_mode: QuirksMode::NoQuirks,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,6 +64,10 @@ where
|
|||
.stylesheets
|
||||
.flush::<E>(/* host = */ None, /* snapshot_map = */ None);
|
||||
|
||||
if flusher.sheets.dirty() {
|
||||
self.quirks_mode = quirks_mode;
|
||||
}
|
||||
|
||||
// Ignore OOM.
|
||||
let _ = self
|
||||
.data
|
||||
|
|
|
@ -761,7 +761,7 @@ pub trait TElement:
|
|||
/// Returns the anonymous content for the current element's XBL binding,
|
||||
/// given if any.
|
||||
///
|
||||
/// This is used in Gecko for XBL.
|
||||
/// This is used in Gecko for XBL and shadow DOM.
|
||||
fn xbl_binding_anonymous_content(&self) -> Option<Self::ConcreteNode> {
|
||||
None
|
||||
}
|
||||
|
@ -772,6 +772,11 @@ pub trait TElement:
|
|||
/// The shadow root which roots the subtree this element is contained in.
|
||||
fn containing_shadow(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;
|
||||
|
||||
/// XBL hack for style sharing. :(
|
||||
fn has_same_xbl_proto_binding_as(&self, _other: Self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Return the element which we can use to look up rules in the selector
|
||||
/// maps.
|
||||
///
|
||||
|
@ -787,34 +792,56 @@ pub trait TElement:
|
|||
}
|
||||
}
|
||||
|
||||
/// Implements Gecko's `nsBindingManager::WalkRules`.
|
||||
///
|
||||
/// Returns whether to cut off the binding inheritance, that is, whether
|
||||
/// document rules should _not_ apply.
|
||||
fn each_xbl_cascade_data<'a, F>(&self, _: F) -> bool
|
||||
where
|
||||
Self: 'a,
|
||||
F: FnMut(&'a CascadeData, QuirksMode),
|
||||
{
|
||||
false
|
||||
}
|
||||
|
||||
/// Executes the callback for each applicable style rule data which isn't
|
||||
/// the main document's data (which stores UA / author rules).
|
||||
///
|
||||
/// The element passed to the callback is the containing shadow host for the
|
||||
/// data if it comes from Shadow DOM.
|
||||
/// data if it comes from Shadow DOM, None if it comes from XBL.
|
||||
///
|
||||
/// Returns whether normal document author rules should apply.
|
||||
fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool
|
||||
where
|
||||
Self: 'a,
|
||||
F: FnMut(&'a CascadeData, Self),
|
||||
F: FnMut(&'a CascadeData, QuirksMode, Option<Self>),
|
||||
{
|
||||
use rule_collector::containing_shadow_ignoring_svg_use;
|
||||
|
||||
let mut doc_rules_apply = self.matches_user_and_author_rules();
|
||||
let mut doc_rules_apply = !self.each_xbl_cascade_data(|data, quirks_mode| {
|
||||
f(data, quirks_mode, None);
|
||||
});
|
||||
|
||||
// Use the same rules to look for the containing host as we do for rule
|
||||
// collection.
|
||||
if let Some(shadow) = containing_shadow_ignoring_svg_use(*self) {
|
||||
doc_rules_apply = false;
|
||||
if let Some(data) = shadow.style_data() {
|
||||
f(data, shadow.host());
|
||||
f(
|
||||
data,
|
||||
self.as_node().owner_doc().quirks_mode(),
|
||||
Some(shadow.host()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(shadow) = self.shadow_root() {
|
||||
if let Some(data) = shadow.style_data() {
|
||||
f(data, shadow.host());
|
||||
f(
|
||||
data,
|
||||
self.as_node().owner_doc().quirks_mode(),
|
||||
Some(shadow.host()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -823,7 +850,11 @@ pub trait TElement:
|
|||
// Slots can only have assigned nodes when in a shadow tree.
|
||||
let shadow = slot.containing_shadow().unwrap();
|
||||
if let Some(data) = shadow.style_data() {
|
||||
f(data, shadow.host());
|
||||
f(
|
||||
data,
|
||||
self.as_node().owner_doc().quirks_mode(),
|
||||
Some(shadow.host()),
|
||||
);
|
||||
}
|
||||
current = slot.assigned_slot();
|
||||
}
|
||||
|
|
|
@ -145,6 +145,11 @@ impl PerDocumentStyleData {
|
|||
/// Create a `PerDocumentStyleData`.
|
||||
pub fn new(document: *const structs::Document) -> Self {
|
||||
let device = Device::new(document);
|
||||
|
||||
// FIXME(emilio, tlin): How is this supposed to work with XBL? This is
|
||||
// right now not always honored, see bug 1405543...
|
||||
//
|
||||
// Should we just force XBL Stylists to be NoQuirks?
|
||||
let quirks_mode = device.document().mCompatMode;
|
||||
|
||||
PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
|
||||
|
|
|
@ -172,7 +172,15 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
|
|||
Self: 'a,
|
||||
{
|
||||
let author_styles = unsafe { self.0.mServoStyles.mPtr.as_ref()? };
|
||||
|
||||
let author_styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
|
||||
|
||||
debug_assert!(
|
||||
author_styles.quirks_mode == self.as_node().owner_doc().quirks_mode() ||
|
||||
author_styles.stylesheets.is_empty() ||
|
||||
author_styles.stylesheets.dirty()
|
||||
);
|
||||
|
||||
Some(&author_styles.data)
|
||||
}
|
||||
|
||||
|
@ -528,6 +536,11 @@ impl<'lb> GeckoXBLBinding<'lb> {
|
|||
self.0.mContent.raw::<nsIContent>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inherits_style(&self) -> bool {
|
||||
unsafe { bindings::Gecko_XBLBinding_InheritsStyle(self.0) }
|
||||
}
|
||||
|
||||
// This duplicates the logic in Gecko's
|
||||
// nsBindingManager::GetBindingWithContent.
|
||||
fn binding_with_content(&self) -> Option<Self> {
|
||||
|
@ -539,6 +552,22 @@ impl<'lb> GeckoXBLBinding<'lb> {
|
|||
binding = binding.base_binding()?;
|
||||
}
|
||||
}
|
||||
|
||||
fn each_xbl_cascade_data<F>(&self, f: &mut F)
|
||||
where
|
||||
F: FnMut(&'lb CascadeData, QuirksMode),
|
||||
{
|
||||
if let Some(base) = self.base_binding() {
|
||||
base.each_xbl_cascade_data(f);
|
||||
}
|
||||
|
||||
let data = unsafe { bindings::Gecko_XBLBinding_GetRawServoStyles(self.0).as_ref() };
|
||||
|
||||
if let Some(data) = data {
|
||||
let data: &'lb _ = AuthorStyles::<GeckoStyleSheet>::from_ffi(data);
|
||||
f(&data.data, data.quirks_mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple wrapper over a non-null Gecko `Element` pointer.
|
||||
|
@ -1221,6 +1250,14 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
}
|
||||
}
|
||||
|
||||
fn has_same_xbl_proto_binding_as(&self, other: Self) -> bool {
|
||||
match (self.xbl_binding(), other.xbl_binding()) {
|
||||
(None, None) => true,
|
||||
(Some(a), Some(b)) => a.0.mPrototypeBinding == b.0.mPrototypeBinding,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn each_anonymous_content_child<F>(&self, mut f: F)
|
||||
where
|
||||
F: FnMut(Self),
|
||||
|
@ -1399,7 +1436,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
|
||||
#[inline]
|
||||
fn matches_user_and_author_rules(&self) -> bool {
|
||||
!self.rule_hash_target().is_in_native_anonymous_subtree()
|
||||
!self.is_in_native_anonymous_subtree()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -1562,6 +1599,43 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
self.may_have_animations() && unsafe { Gecko_ElementHasCSSTransitions(self.0) }
|
||||
}
|
||||
|
||||
fn each_xbl_cascade_data<'a, F>(&self, mut f: F) -> bool
|
||||
where
|
||||
'le: 'a,
|
||||
F: FnMut(&'a CascadeData, QuirksMode),
|
||||
{
|
||||
// Walk the binding scope chain, starting with the binding attached to
|
||||
// our content, up till we run out of scopes or we get cut off.
|
||||
//
|
||||
// If we are a NAC pseudo-element, we want to get rules from our
|
||||
// rule_hash_target, that is, our originating element.
|
||||
let mut current = Some(self.rule_hash_target());
|
||||
while let Some(element) = current {
|
||||
if let Some(binding) = element.xbl_binding() {
|
||||
binding.each_xbl_cascade_data(&mut f);
|
||||
|
||||
// If we're not looking at our original element, allow the
|
||||
// binding to cut off style inheritance.
|
||||
if element != *self && !binding.inherits_style() {
|
||||
// Go no further; we're not inheriting style from
|
||||
// anything above here.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if element.is_root_of_native_anonymous_subtree() {
|
||||
// Deliberately cut off style inheritance here.
|
||||
break;
|
||||
}
|
||||
|
||||
current = element.xbl_binding_parent();
|
||||
}
|
||||
|
||||
// If current has something, this means we cut off inheritance at some
|
||||
// point in the loop.
|
||||
current.is_some()
|
||||
}
|
||||
|
||||
fn xbl_binding_anonymous_content(&self) -> Option<GeckoNode<'le>> {
|
||||
self.xbl_binding_with_content()
|
||||
.map(|b| unsafe { GeckoNode::from_content(&*b.anon_content()) })
|
||||
|
|
|
@ -224,8 +224,8 @@ where
|
|||
|
||||
let mut shadow_rule_datas = SmallVec::<[_; 3]>::new();
|
||||
let matches_document_author_rules =
|
||||
element.each_applicable_non_document_style_rule_data(|data, host| {
|
||||
shadow_rule_datas.push((data, host.opaque()))
|
||||
element.each_applicable_non_document_style_rule_data(|data, quirks_mode, host| {
|
||||
shadow_rule_datas.push((data, quirks_mode, host.map(|h| h.opaque())))
|
||||
});
|
||||
|
||||
let invalidated_self = {
|
||||
|
@ -258,8 +258,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
for &(ref data, ref host) in &shadow_rule_datas {
|
||||
collector.matching_context.current_host = Some(host.clone());
|
||||
for &(ref data, quirks_mode, ref host) in &shadow_rule_datas {
|
||||
// FIXME(emilio): Replace with assert / remove when we figure
|
||||
// out what to do with the quirks mode mismatches
|
||||
// (that is, when bug 1406875 is properly fixed).
|
||||
collector.matching_context.set_quirks_mode(quirks_mode);
|
||||
collector.matching_context.current_host = host.clone();
|
||||
collector.collect_dependencies_in_invalidation_map(data.invalidation_map());
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ where
|
|||
flags_setter: &'a mut F,
|
||||
) -> Self {
|
||||
let rule_hash_target = element.rule_hash_target();
|
||||
let matches_user_and_author_rules = element.matches_user_and_author_rules();
|
||||
let matches_user_and_author_rules = rule_hash_target.matches_user_and_author_rules();
|
||||
|
||||
// Gecko definitely has pseudo-elements with style attributes, like
|
||||
// ::-moz-color-swatch.
|
||||
|
@ -198,7 +198,7 @@ where
|
|||
let rules = &mut self.rules;
|
||||
let flags_setter = &mut self.flags_setter;
|
||||
let shadow_cascade_order = self.shadow_cascade_order;
|
||||
self.context.with_shadow_host(shadow_host, |context| {
|
||||
self.context.with_shadow_host(Some(shadow_host), |context| {
|
||||
map.get_all_matching_rules(
|
||||
element,
|
||||
rule_hash_target,
|
||||
|
@ -303,6 +303,42 @@ where
|
|||
self.collect_stylist_rules(Origin::Author);
|
||||
}
|
||||
|
||||
fn collect_xbl_rules(&mut self) {
|
||||
let element = self.element;
|
||||
let cut_xbl_binding_inheritance =
|
||||
element.each_xbl_cascade_data(|cascade_data, quirks_mode| {
|
||||
let map = match cascade_data.normal_rules(self.pseudo_element) {
|
||||
Some(m) => m,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// NOTE(emilio): This is needed because the XBL stylist may
|
||||
// think it has a different quirks mode than the document.
|
||||
let mut matching_context = MatchingContext::new(
|
||||
self.context.matching_mode(),
|
||||
self.context.bloom_filter,
|
||||
self.context.nth_index_cache.as_mut().map(|s| &mut **s),
|
||||
quirks_mode,
|
||||
);
|
||||
matching_context.pseudo_element_matching_fn =
|
||||
self.context.pseudo_element_matching_fn;
|
||||
|
||||
// SameTreeAuthorNormal instead of InnerShadowNormal to
|
||||
// preserve behavior, though that's kinda fishy...
|
||||
map.get_all_matching_rules(
|
||||
self.element,
|
||||
self.rule_hash_target,
|
||||
self.rules,
|
||||
&mut matching_context,
|
||||
self.flags_setter,
|
||||
CascadeLevel::SameTreeAuthorNormal,
|
||||
self.shadow_cascade_order,
|
||||
);
|
||||
});
|
||||
|
||||
self.matches_document_author_rules &= !cut_xbl_binding_inheritance;
|
||||
}
|
||||
|
||||
fn collect_style_attribute_and_animation_rules(&mut self) {
|
||||
if let Some(sa) = self.style_attribute {
|
||||
self.rules
|
||||
|
@ -360,6 +396,7 @@ where
|
|||
self.collect_host_rules();
|
||||
self.collect_slotted_rules();
|
||||
self.collect_normal_rules_from_containing_shadow_tree();
|
||||
self.collect_xbl_rules();
|
||||
self.collect_document_author_rules();
|
||||
self.collect_style_attribute_and_animation_rules();
|
||||
}
|
||||
|
|
|
@ -727,6 +727,27 @@ impl<E: TElement> StyleSharingCache<E> {
|
|||
return None;
|
||||
}
|
||||
|
||||
// Note that in theory we shouldn't need this XBL check. However, XBL is
|
||||
// absolutely broken in all sorts of ways.
|
||||
//
|
||||
// A style change that changes which XBL binding applies to an element
|
||||
// arrives there, with the element still having the old prototype
|
||||
// binding attached. And thus we try to match revalidation selectors
|
||||
// with the old XBL binding, because we can't look at the new ones of
|
||||
// course. And that causes us to revalidate with the wrong selectors and
|
||||
// hit assertions.
|
||||
//
|
||||
// Other than this, we don't need anything else like the containing XBL
|
||||
// binding parent or what not, since two elements with different XBL
|
||||
// bindings will necessarily end up with different style.
|
||||
if !target
|
||||
.element
|
||||
.has_same_xbl_proto_binding_as(candidate.element)
|
||||
{
|
||||
trace!("Miss: Different proto bindings");
|
||||
return None;
|
||||
}
|
||||
|
||||
// If the elements are not assigned to the same slot they could match
|
||||
// different ::slotted() rules in the slot scope.
|
||||
//
|
||||
|
|
|
@ -546,7 +546,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// The set of stylesheets effective for a given Shadow Root.
|
||||
/// The set of stylesheets effective for a given XBL binding or Shadow Root.
|
||||
#[derive(MallocSizeOf)]
|
||||
pub struct AuthorStylesheetSet<S>
|
||||
where
|
||||
|
|
|
@ -636,7 +636,7 @@ impl Stylist {
|
|||
let mut maybe = false;
|
||||
|
||||
let doc_author_rules_apply =
|
||||
element.each_applicable_non_document_style_rule_data(|data, _| {
|
||||
element.each_applicable_non_document_style_rule_data(|data, _, _| {
|
||||
maybe = maybe || f(&*data);
|
||||
});
|
||||
|
||||
|
@ -1072,6 +1072,12 @@ impl Stylist {
|
|||
/// Returns whether, given a media feature change, any previously-applicable
|
||||
/// style has become non-applicable, or vice-versa for each origin, using
|
||||
/// `device`.
|
||||
///
|
||||
/// Passing `device` is needed because this is used for XBL in Gecko, which
|
||||
/// can be stale in various ways, so we need to pass the device of the
|
||||
/// document itself, which is what is kept up-to-date.
|
||||
///
|
||||
/// Arguably XBL should use something more lightweight than a Stylist.
|
||||
pub fn media_features_change_changed_style(
|
||||
&self,
|
||||
guards: &StylesheetGuards,
|
||||
|
@ -1255,11 +1261,11 @@ impl Stylist {
|
|||
let mut results = SmallBitVec::new();
|
||||
|
||||
let matches_document_rules =
|
||||
element.each_applicable_non_document_style_rule_data(|data, host| {
|
||||
element.each_applicable_non_document_style_rule_data(|data, quirks_mode, host| {
|
||||
matching_context.with_shadow_host(host, |matching_context| {
|
||||
data.selectors_for_cache_revalidation.lookup(
|
||||
element,
|
||||
self.quirks_mode,
|
||||
quirks_mode,
|
||||
|selector_and_hashes| {
|
||||
results.push(matches_selector(
|
||||
&selector_and_hashes.selector,
|
||||
|
|
Загрузка…
Ссылка в новой задаче