Backed out changeset e85cb54e5944 (bug 1546046) complementary backout after 1470880 was backed out CLOSED TREE

This commit is contained in:
Bogdan Tara 2019-04-23 06:55:29 +03:00
Родитель a0ccfdb583
Коммит ec489aa170
53 изменённых файлов: 1468 добавлений и 83 удалений

Просмотреть файл

@ -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,