mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-24 05:44:10 +00:00
Bug 929885 - Implement web components ShadowRoot style sheet behavior. r=mrbkap
This commit is contained in:
parent
b92be20c45
commit
ad649152bc
@ -745,14 +745,19 @@ Element::CreateShadowRoot(ErrorResult& aError)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Unlike for XBL, false is the default for inheriting style.
|
||||
protoBinding->SetInheritsStyle(false);
|
||||
|
||||
// Calling SetPrototypeBinding takes ownership of protoBinding.
|
||||
docInfo->SetPrototypeBinding(NS_LITERAL_CSTRING("shadowroot"), protoBinding);
|
||||
|
||||
nsRefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget());
|
||||
nsRefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
|
||||
protoBinding);
|
||||
SetShadowRoot(shadowRoot);
|
||||
|
||||
// xblBinding takes ownership of docInfo.
|
||||
nsRefPtr<nsXBLBinding> xblBinding = new nsXBLBinding(shadowRoot, protoBinding);
|
||||
shadowRoot->SetAssociatedBinding(xblBinding);
|
||||
xblBinding->SetBoundElement(this);
|
||||
|
||||
SetXBLBinding(xblBinding);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsIStyleSheetLinkingElement.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLContentElement.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
@ -32,6 +33,8 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
|
||||
DocumentFragment)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHost)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
|
||||
tmp->mIdentifierMap.EnumerateEntries(IdentifierMapEntryTraverse, &cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
@ -41,6 +44,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ShadowRoot,
|
||||
tmp->mHost->RemoveMutationObserver(tmp);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHost)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
|
||||
tmp->mIdentifierMap.Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
@ -55,9 +60,10 @@ NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
|
||||
NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
|
||||
|
||||
ShadowRoot::ShadowRoot(nsIContent* aContent,
|
||||
already_AddRefed<nsINodeInfo> aNodeInfo)
|
||||
already_AddRefed<nsINodeInfo> aNodeInfo,
|
||||
nsXBLPrototypeBinding* aProtoBinding)
|
||||
: DocumentFragment(aNodeInfo), mHost(aContent),
|
||||
mInsertionPointChanged(false)
|
||||
mProtoBinding(aProtoBinding), mInsertionPointChanged(false)
|
||||
{
|
||||
SetHost(aContent);
|
||||
SetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||
@ -101,6 +107,66 @@ ShadowRoot::FromNode(nsINode* aNode)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::Restyle()
|
||||
{
|
||||
mProtoBinding->FlushSkinSheets();
|
||||
|
||||
nsIPresShell* shell = OwnerDoc()->GetShell();
|
||||
if (shell) {
|
||||
OwnerDoc()->BeginUpdate(UPDATE_STYLE);
|
||||
shell->RestyleShadowRoot(this);
|
||||
OwnerDoc()->EndUpdate(UPDATE_STYLE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::InsertSheet(nsCSSStyleSheet* aSheet,
|
||||
nsIContent* aLinkingContent)
|
||||
{
|
||||
nsCOMPtr<nsIStyleSheetLinkingElement>
|
||||
linkingElement = do_QueryInterface(aLinkingContent);
|
||||
MOZ_ASSERT(linkingElement, "The only styles in a ShadowRoot should come "
|
||||
"from <style>.");
|
||||
|
||||
linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
|
||||
|
||||
nsTArray<nsRefPtr<nsCSSStyleSheet> >* sheets =
|
||||
mProtoBinding->GetOrCreateStyleSheets();
|
||||
MOZ_ASSERT(sheets, "Style sheets array should never be null.");
|
||||
|
||||
// Find the correct position to insert into the style sheet list (must
|
||||
// be in tree order).
|
||||
for (uint32_t i = 0; i <= sheets->Length(); i++) {
|
||||
if (i == sheets->Length()) {
|
||||
sheets->AppendElement(aSheet);
|
||||
break;
|
||||
}
|
||||
|
||||
nsINode* sheetOwnerNode = sheets->ElementAt(i)->GetOwnerNode();
|
||||
if (nsContentUtils::PositionIsBefore(aLinkingContent, sheetOwnerNode)) {
|
||||
sheets->InsertElementAt(i, aSheet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Restyle();
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::RemoveSheet(nsCSSStyleSheet* aSheet)
|
||||
{
|
||||
nsTArray<nsRefPtr<nsCSSStyleSheet> >* sheets =
|
||||
mProtoBinding->GetOrCreateStyleSheets();
|
||||
MOZ_ASSERT(sheets, "Style sheets array should never be null.");
|
||||
|
||||
DebugOnly<bool> found = sheets->RemoveElement(aSheet);
|
||||
MOZ_ASSERT(found, "Trying to remove a sheet from a ShadowRoot "
|
||||
"that does not exist.");
|
||||
|
||||
Restyle();
|
||||
}
|
||||
|
||||
Element*
|
||||
ShadowRoot::GetElementById(const nsAString& aElementId)
|
||||
{
|
||||
@ -332,6 +398,35 @@ ShadowRoot::SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError)
|
||||
SetInnerHTMLInternal(aInnerHTML, aError);
|
||||
}
|
||||
|
||||
bool
|
||||
ShadowRoot::ApplyAuthorStyles()
|
||||
{
|
||||
return mProtoBinding->InheritsStyle();
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::SetApplyAuthorStyles(bool aApplyAuthorStyles)
|
||||
{
|
||||
mProtoBinding->SetInheritsStyle(aApplyAuthorStyles);
|
||||
|
||||
nsIPresShell* shell = OwnerDoc()->GetShell();
|
||||
if (shell) {
|
||||
OwnerDoc()->BeginUpdate(UPDATE_STYLE);
|
||||
shell->RestyleShadowRoot(this);
|
||||
OwnerDoc()->EndUpdate(UPDATE_STYLE);
|
||||
}
|
||||
}
|
||||
|
||||
nsIDOMStyleSheetList*
|
||||
ShadowRoot::StyleSheets()
|
||||
{
|
||||
if (!mStyleSheetList) {
|
||||
mStyleSheetList = new ShadowRootStyleSheetList(this);
|
||||
}
|
||||
|
||||
return mStyleSheetList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the web components pool population algorithm
|
||||
* on the host would contain |aContent|. This function ignores
|
||||
@ -441,3 +536,55 @@ ShadowRoot::ContentRemoved(nsIDocument* aDocument,
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_1(ShadowRootStyleSheetList, mShadowRoot)
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD(ShadowRootStyleSheetList)
|
||||
NS_INTERFACE_TABLE1(ShadowRootStyleSheetList, nsIDOMStyleSheetList)
|
||||
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(ShadowRootStyleSheetList)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StyleSheetList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ShadowRootStyleSheetList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ShadowRootStyleSheetList)
|
||||
|
||||
ShadowRootStyleSheetList::ShadowRootStyleSheetList(ShadowRoot* aShadowRoot)
|
||||
: mShadowRoot(aShadowRoot)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ShadowRootStyleSheetList);
|
||||
}
|
||||
|
||||
ShadowRootStyleSheetList::~ShadowRootStyleSheetList()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ShadowRootStyleSheetList);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ShadowRootStyleSheetList::Item(uint32_t aIndex, nsIDOMStyleSheet** aReturn)
|
||||
{
|
||||
nsTArray<nsRefPtr<nsCSSStyleSheet> >* sheets =
|
||||
mShadowRoot->mProtoBinding->GetStyleSheets();
|
||||
|
||||
if (sheets) {
|
||||
NS_IF_ADDREF(*aReturn = sheets->SafeElementAt(aIndex));
|
||||
} else {
|
||||
*aReturn = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ShadowRootStyleSheetList::GetLength(uint32_t* aLength)
|
||||
{
|
||||
nsTArray<nsRefPtr<nsCSSStyleSheet> >* sheets =
|
||||
mShadowRoot->mProtoBinding->GetStyleSheets();
|
||||
|
||||
if (sheets) {
|
||||
*aLength = sheets->Length();
|
||||
} else {
|
||||
*aLength = 0;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,12 @@ namespace dom {
|
||||
|
||||
class Element;
|
||||
class HTMLContentElement;
|
||||
class ShadowRootStyleSheetList;
|
||||
|
||||
class ShadowRoot : public DocumentFragment,
|
||||
public nsStubMutationObserver
|
||||
{
|
||||
friend class ShadowRootStyleSheetList;
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot,
|
||||
DocumentFragment)
|
||||
@ -39,12 +41,18 @@ public:
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
|
||||
ShadowRoot(nsIContent* aContent, already_AddRefed<nsINodeInfo> aNodeInfo);
|
||||
ShadowRoot(nsIContent* aContent, already_AddRefed<nsINodeInfo> aNodeInfo,
|
||||
nsXBLPrototypeBinding* aProtoBinding);
|
||||
virtual ~ShadowRoot();
|
||||
|
||||
void AddToIdTable(Element* aElement, nsIAtom* aId);
|
||||
void RemoveFromIdTable(Element* aElement, nsIAtom* aId);
|
||||
static bool PrefEnabled();
|
||||
void InsertSheet(nsCSSStyleSheet* aSheet, nsIContent* aLinkingContent);
|
||||
void RemoveSheet(nsCSSStyleSheet* aSheet);
|
||||
bool ApplyAuthorStyles();
|
||||
void SetApplyAuthorStyles(bool aApplyAuthorStyles);
|
||||
nsIDOMStyleSheetList* StyleSheets();
|
||||
|
||||
/**
|
||||
* Distributes a single explicit child of the host to the content
|
||||
@ -69,6 +77,11 @@ public:
|
||||
|
||||
void SetInsertionPointChanged() { mInsertionPointChanged = true; }
|
||||
|
||||
void SetAssociatedBinding(nsXBLBinding* aBinding)
|
||||
{
|
||||
mAssociatedBinding = aBinding;
|
||||
}
|
||||
|
||||
nsISupports* GetParentObject() const
|
||||
{
|
||||
return mHost;
|
||||
@ -92,6 +105,8 @@ public:
|
||||
void GetInnerHTML(nsAString& aInnerHTML);
|
||||
void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
|
||||
protected:
|
||||
void Restyle();
|
||||
|
||||
nsCOMPtr<nsIContent> mHost;
|
||||
|
||||
// An array of content insertion points that are a descendant of the ShadowRoot
|
||||
@ -102,6 +117,14 @@ protected:
|
||||
nsTArray<HTMLContentElement*> mInsertionPoints;
|
||||
|
||||
nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
|
||||
nsXBLPrototypeBinding* mProtoBinding;
|
||||
|
||||
// It is necessary to hold a reference to the associated nsXBLBinding
|
||||
// because the binding holds a reference on the nsXBLDocumentInfo that
|
||||
// owns |mProtoBinding|.
|
||||
nsRefPtr<nsXBLBinding> mAssociatedBinding;
|
||||
|
||||
nsRefPtr<ShadowRootStyleSheetList> mStyleSheetList;
|
||||
|
||||
// A boolean that indicates that an insertion point was added or removed
|
||||
// from this ShadowRoot and that the nodes need to be redistributed into
|
||||
@ -110,6 +133,22 @@ protected:
|
||||
bool mInsertionPointChanged;
|
||||
};
|
||||
|
||||
class ShadowRootStyleSheetList : public nsIDOMStyleSheetList
|
||||
{
|
||||
public:
|
||||
ShadowRootStyleSheetList(ShadowRoot* aShadowRoot);
|
||||
virtual ~ShadowRootStyleSheetList();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(ShadowRootStyleSheetList)
|
||||
|
||||
// nsIDOMStyleSheetList
|
||||
NS_DECL_NSIDOMSTYLESHEETLIST
|
||||
|
||||
protected:
|
||||
nsRefPtr<ShadowRoot> mShadowRoot;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -279,22 +279,6 @@ public:
|
||||
|
||||
nsIStyleSheet* GetItemAt(uint32_t aIndex);
|
||||
|
||||
static nsDOMStyleSheetList* FromSupports(nsISupports* aSupports)
|
||||
{
|
||||
nsIDOMStyleSheetList* list = static_cast<nsIDOMStyleSheetList*>(aSupports);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsIDOMStyleSheetList> list_qi = do_QueryInterface(aSupports);
|
||||
|
||||
// If this assertion fires the QI implementation for the object in
|
||||
// question doesn't use the nsIDOMStyleSheetList pointer as the
|
||||
// nsISupports pointer. That must be fixed, or we'll crash...
|
||||
NS_ASSERTION(list_qi == list, "Uh, fix QI!");
|
||||
}
|
||||
#endif
|
||||
return static_cast<nsDOMStyleSheetList*>(list);
|
||||
}
|
||||
|
||||
protected:
|
||||
int32_t mLength;
|
||||
nsIDocument* mDocument;
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "mozilla/css/Loader.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "nsCSSStyleSheet.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
@ -176,17 +177,18 @@ nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
|
||||
bool* aWillNotify,
|
||||
bool* aIsAlternate)
|
||||
{
|
||||
return DoUpdateStyleSheet(nullptr, aObserver, aWillNotify, aIsAlternate,
|
||||
false);
|
||||
return DoUpdateStyleSheet(nullptr, nullptr, aObserver, aWillNotify,
|
||||
aIsAlternate, false);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument *aOldDocument,
|
||||
ShadowRoot *aOldShadowRoot,
|
||||
bool aForceUpdate)
|
||||
{
|
||||
bool notify, alternate;
|
||||
return DoUpdateStyleSheet(aOldDocument, nullptr, ¬ify, &alternate,
|
||||
aForceUpdate);
|
||||
return DoUpdateStyleSheet(aOldDocument, aOldShadowRoot, nullptr, ¬ify,
|
||||
&alternate, aForceUpdate);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -272,7 +274,8 @@ GetScopeElement(nsIStyleSheet* aSheet)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument *aOldDocument,
|
||||
nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
|
||||
ShadowRoot* aOldShadowRoot,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
bool* aWillNotify,
|
||||
bool* aIsAlternate,
|
||||
@ -283,6 +286,17 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument *aOldDocument,
|
||||
nsCOMPtr<nsIContent> thisContent;
|
||||
CallQueryInterface(this, getter_AddRefs(thisContent));
|
||||
|
||||
// All instances of nsStyleLinkElement should implement nsIContent.
|
||||
NS_ENSURE_TRUE(thisContent, NS_ERROR_FAILURE);
|
||||
|
||||
// Check for a ShadowRoot because link elements are inert in a
|
||||
// ShadowRoot.
|
||||
ShadowRoot* containingShadow = thisContent->GetContainingShadow();
|
||||
if (thisContent->IsHTML(nsGkAtoms::link) &&
|
||||
(aOldShadowRoot || containingShadow)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Element* oldScopeElement = GetScopeElement(mStyleSheet);
|
||||
|
||||
if (mStyleSheet && aOldDocument) {
|
||||
@ -290,17 +304,20 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument *aOldDocument,
|
||||
// stylesheet. We want to do this even if updates are disabled, since
|
||||
// otherwise a sheet with a stale linking element pointer will be hanging
|
||||
// around -- not good!
|
||||
aOldDocument->BeginUpdate(UPDATE_STYLE);
|
||||
aOldDocument->RemoveStyleSheet(mStyleSheet);
|
||||
aOldDocument->EndUpdate(UPDATE_STYLE);
|
||||
if (aOldShadowRoot) {
|
||||
aOldShadowRoot->RemoveSheet(mStyleSheet);
|
||||
} else {
|
||||
aOldDocument->BeginUpdate(UPDATE_STYLE);
|
||||
aOldDocument->RemoveStyleSheet(mStyleSheet);
|
||||
aOldDocument->EndUpdate(UPDATE_STYLE);
|
||||
}
|
||||
|
||||
nsStyleLinkElement::SetStyleSheet(nullptr);
|
||||
if (oldScopeElement) {
|
||||
UpdateIsElementInStyleScopeFlagOnSubtree(oldScopeElement);
|
||||
}
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(thisContent, NS_ERROR_FAILURE);
|
||||
|
||||
// When static documents are created, stylesheets are cloned manually.
|
||||
if (mDontLoadStyle || !mUpdatesEnabled ||
|
||||
thisContent->OwnerDoc()->IsStaticDocument()) {
|
||||
@ -328,9 +345,15 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument *aOldDocument,
|
||||
}
|
||||
|
||||
if (mStyleSheet) {
|
||||
doc->BeginUpdate(UPDATE_STYLE);
|
||||
doc->RemoveStyleSheet(mStyleSheet);
|
||||
doc->EndUpdate(UPDATE_STYLE);
|
||||
if (thisContent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
|
||||
ShadowRoot* containingShadow = thisContent->GetContainingShadow();
|
||||
containingShadow->RemoveSheet(mStyleSheet);
|
||||
} else {
|
||||
doc->BeginUpdate(UPDATE_STYLE);
|
||||
doc->RemoveStyleSheet(mStyleSheet);
|
||||
doc->EndUpdate(UPDATE_STYLE);
|
||||
}
|
||||
|
||||
nsStyleLinkElement::SetStyleSheet(nullptr);
|
||||
}
|
||||
|
||||
@ -420,13 +443,22 @@ nsStyleLinkElement::UpdateStyleSheetScopedness(bool aIsNowScoped)
|
||||
|
||||
nsIDocument* document = thisContent->GetOwnerDocument();
|
||||
|
||||
document->BeginUpdate(UPDATE_STYLE);
|
||||
document->RemoveStyleSheet(mStyleSheet);
|
||||
if (thisContent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
|
||||
ShadowRoot* containingShadow = thisContent->GetContainingShadow();
|
||||
containingShadow->RemoveSheet(mStyleSheet);
|
||||
|
||||
mStyleSheet->SetScopeElement(newScopeElement);
|
||||
mStyleSheet->SetScopeElement(newScopeElement);
|
||||
|
||||
document->AddStyleSheet(mStyleSheet);
|
||||
document->EndUpdate(UPDATE_STYLE);
|
||||
containingShadow->InsertSheet(mStyleSheet, thisContent);
|
||||
} else {
|
||||
document->BeginUpdate(UPDATE_STYLE);
|
||||
document->RemoveStyleSheet(mStyleSheet);
|
||||
|
||||
mStyleSheet->SetScopeElement(newScopeElement);
|
||||
|
||||
document->AddStyleSheet(mStyleSheet);
|
||||
document->EndUpdate(UPDATE_STYLE);
|
||||
}
|
||||
|
||||
if (oldScopeElement) {
|
||||
UpdateIsElementInStyleScopeFlagOnSubtree(oldScopeElement);
|
||||
|
@ -29,6 +29,12 @@
|
||||
class nsIDocument;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ShadowRoot;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
class nsStyleLinkElement : public nsIStyleSheetLinkingElement
|
||||
{
|
||||
public:
|
||||
@ -53,8 +59,11 @@ public:
|
||||
virtual void SetLineNumber(uint32_t aLineNumber) MOZ_OVERRIDE;
|
||||
|
||||
static uint32_t ParseLinkTypes(const nsAString& aTypes);
|
||||
|
||||
void UpdateStyleSheetInternal() { UpdateStyleSheetInternal(nullptr); }
|
||||
|
||||
void UpdateStyleSheetInternal()
|
||||
{
|
||||
UpdateStyleSheetInternal(nullptr, nullptr);
|
||||
}
|
||||
protected:
|
||||
/**
|
||||
* @param aOldDocument should be non-null only if we're updating because we
|
||||
@ -65,6 +74,7 @@ protected:
|
||||
* changed but the URI may not have changed.
|
||||
*/
|
||||
nsresult UpdateStyleSheetInternal(nsIDocument *aOldDocument,
|
||||
mozilla::dom::ShadowRoot *aOldShadowRoot,
|
||||
bool aForceUpdate = false);
|
||||
|
||||
void UpdateStyleSheetScopedness(bool aIsNowScoped);
|
||||
@ -90,12 +100,17 @@ private:
|
||||
/**
|
||||
* @param aOldDocument should be non-null only if we're updating because we
|
||||
* removed the node from the document.
|
||||
* @param aOldShadowRoot The ShadowRoot that used to contain the style.
|
||||
* Passed as a parameter because on an update, the node
|
||||
* is removed from the tree before the sheet is removed
|
||||
* from the ShadowRoot.
|
||||
* @param aForceUpdate true will force the update even if the URI has not
|
||||
* changed. This should be used in cases when something
|
||||
* about the content that affects the resulting sheet
|
||||
* changed but the URI may not have changed.
|
||||
*/
|
||||
nsresult DoUpdateStyleSheet(nsIDocument *aOldDocument,
|
||||
nsresult DoUpdateStyleSheet(nsIDocument* aOldDocument,
|
||||
mozilla::dom::ShadowRoot* aOldShadowRoot,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
bool* aWillNotify,
|
||||
bool* aIsAlternate,
|
||||
|
@ -131,8 +131,9 @@ HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aDocument) {
|
||||
|
||||
// Link must be inert in ShadowRoot.
|
||||
if (aDocument && !GetContainingShadow()) {
|
||||
aDocument->RegisterPendingLinkUpdate(this);
|
||||
}
|
||||
|
||||
@ -166,12 +167,19 @@ HTMLLinkElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
// Once we have XPCOMGC we shouldn't need to call UnbindFromTree during Unlink
|
||||
// and so this messy event dispatch can go away.
|
||||
nsCOMPtr<nsIDocument> oldDoc = GetCurrentDoc();
|
||||
if (oldDoc) {
|
||||
|
||||
// Check for a ShadowRoot because link elements are inert in a
|
||||
// ShadowRoot.
|
||||
ShadowRoot* oldShadowRoot = GetBindingParent() ?
|
||||
GetBindingParent()->GetShadowRoot() : nullptr;
|
||||
|
||||
if (oldDoc && !oldShadowRoot) {
|
||||
oldDoc->UnregisterPendingLinkUpdate(this);
|
||||
}
|
||||
CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved"));
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
UpdateStyleSheetInternal(oldDoc);
|
||||
|
||||
UpdateStyleSheetInternal(oldDoc, oldShadowRoot);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -248,7 +256,7 @@ HTMLLinkElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
dropSheet = !(linkTypes & STYLESHEET);
|
||||
}
|
||||
|
||||
UpdateStyleSheetInternal(nullptr,
|
||||
UpdateStyleSheetInternal(nullptr, nullptr,
|
||||
dropSheet ||
|
||||
(aName == nsGkAtoms::title ||
|
||||
aName == nsGkAtoms::media ||
|
||||
@ -272,7 +280,7 @@ HTMLLinkElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
aAttribute == nsGkAtoms::title ||
|
||||
aAttribute == nsGkAtoms::media ||
|
||||
aAttribute == nsGkAtoms::type)) {
|
||||
UpdateStyleSheetInternal(nullptr, true);
|
||||
UpdateStyleSheetInternal(nullptr, nullptr, true);
|
||||
}
|
||||
|
||||
// The ordering of the parent class's UnsetAttr call and Link::ResetLinkState
|
||||
|
@ -133,7 +133,7 @@ void
|
||||
HTMLStyleElement::ContentChanged(nsIContent* aContent)
|
||||
{
|
||||
if (nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
|
||||
UpdateStyleSheetInternal(nullptr);
|
||||
UpdateStyleSheetInternal(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,9 +157,9 @@ void
|
||||
HTMLStyleElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> oldDoc = GetCurrentDoc();
|
||||
|
||||
ShadowRoot* oldShadow = GetContainingShadow();
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
UpdateStyleSheetInternal(oldDoc);
|
||||
UpdateStyleSheetInternal(oldDoc, oldShadow);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -173,7 +173,7 @@ HTMLStyleElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
if (aName == nsGkAtoms::title ||
|
||||
aName == nsGkAtoms::media ||
|
||||
aName == nsGkAtoms::type) {
|
||||
UpdateStyleSheetInternal(nullptr, true);
|
||||
UpdateStyleSheetInternal(nullptr, nullptr, true);
|
||||
} else if (aName == nsGkAtoms::scoped) {
|
||||
UpdateStyleSheetScopedness(true);
|
||||
}
|
||||
@ -192,7 +192,7 @@ HTMLStyleElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
if (aAttribute == nsGkAtoms::title ||
|
||||
aAttribute == nsGkAtoms::media ||
|
||||
aAttribute == nsGkAtoms::type) {
|
||||
UpdateStyleSheetInternal(nullptr, true);
|
||||
UpdateStyleSheetInternal(nullptr, nullptr, true);
|
||||
} else if (aAttribute == nsGkAtoms::scoped) {
|
||||
UpdateStyleSheetScopedness(false);
|
||||
}
|
||||
@ -218,7 +218,7 @@ HTMLStyleElement::SetInnerHTML(const nsAString& aInnerHTML,
|
||||
|
||||
SetEnableUpdates(true);
|
||||
|
||||
UpdateStyleSheetInternal(nullptr);
|
||||
UpdateStyleSheetInternal(nullptr, nullptr);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
|
@ -83,9 +83,9 @@ void
|
||||
SVGStyleElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> oldDoc = GetCurrentDoc();
|
||||
|
||||
ShadowRoot* oldShadow = GetShadowRoot();
|
||||
SVGStyleElementBase::UnbindFromTree(aDeep, aNullParent);
|
||||
UpdateStyleSheetInternal(oldDoc);
|
||||
UpdateStyleSheetInternal(oldDoc, oldShadow);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -99,7 +99,7 @@ SVGStyleElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
if (aName == nsGkAtoms::title ||
|
||||
aName == nsGkAtoms::media ||
|
||||
aName == nsGkAtoms::type) {
|
||||
UpdateStyleSheetInternal(nullptr, true);
|
||||
UpdateStyleSheetInternal(nullptr, nullptr, true);
|
||||
} else if (aName == nsGkAtoms::scoped) {
|
||||
UpdateStyleSheetScopedness(true);
|
||||
}
|
||||
@ -118,7 +118,7 @@ SVGStyleElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
if (aAttribute == nsGkAtoms::title ||
|
||||
aAttribute == nsGkAtoms::media ||
|
||||
aAttribute == nsGkAtoms::type) {
|
||||
UpdateStyleSheetInternal(nullptr, true);
|
||||
UpdateStyleSheetInternal(nullptr, nullptr, true);
|
||||
} else if (aAttribute == nsGkAtoms::scoped) {
|
||||
UpdateStyleSheetScopedness(false);
|
||||
}
|
||||
@ -186,7 +186,7 @@ void
|
||||
SVGStyleElement::ContentChanged(nsIContent* aContent)
|
||||
{
|
||||
if (nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
|
||||
UpdateStyleSheetInternal(nullptr);
|
||||
UpdateStyleSheetInternal(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -596,6 +596,16 @@ nsXBLPrototypeBinding::GetRuleProcessor()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsXBLPrototypeResources::sheet_array_type*
|
||||
nsXBLPrototypeBinding::GetOrCreateStyleSheets()
|
||||
{
|
||||
if (!mResources) {
|
||||
mResources = new nsXBLPrototypeResources(this);
|
||||
}
|
||||
|
||||
return &mResources->mStyleSheetList;
|
||||
}
|
||||
|
||||
nsXBLPrototypeResources::sheet_array_type*
|
||||
nsXBLPrototypeBinding::GetStyleSheets()
|
||||
{
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
nsresult AddResource(nsIAtom* 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; }
|
||||
@ -116,6 +117,7 @@ public:
|
||||
void SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent);
|
||||
|
||||
nsIStyleRuleProcessor* GetRuleProcessor();
|
||||
nsXBLPrototypeResources::sheet_array_type* GetOrCreateStyleSheets();
|
||||
nsXBLPrototypeResources::sheet_array_type* GetStyleSheets();
|
||||
|
||||
bool HasStyleSheets() {
|
||||
|
@ -72,7 +72,7 @@ XMLStylesheetProcessingInstruction::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
nsCOMPtr<nsIDocument> oldDoc = GetCurrentDoc();
|
||||
|
||||
ProcessingInstruction::UnbindFromTree(aDeep, aNullParent);
|
||||
UpdateStyleSheetInternal(oldDoc);
|
||||
UpdateStyleSheetInternal(oldDoc, nullptr);
|
||||
}
|
||||
|
||||
// nsIDOMNode
|
||||
@ -83,7 +83,7 @@ XMLStylesheetProcessingInstruction::SetNodeValueInternal(const nsAString& aNodeV
|
||||
{
|
||||
nsGenericDOMDataNode::SetNodeValueInternal(aNodeValue, aError);
|
||||
if (!aError.Failed()) {
|
||||
UpdateStyleSheetInternal(nullptr, true);
|
||||
UpdateStyleSheetInternal(nullptr, nullptr, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
if (rv.Failed()) {
|
||||
return;
|
||||
}
|
||||
UpdateStyleSheetInternal(nullptr, true);
|
||||
UpdateStyleSheetInternal(nullptr, nullptr, true);
|
||||
}
|
||||
using ProcessingInstruction::SetData; // Prevent hiding overloaded virtual function.
|
||||
|
||||
|
@ -4278,9 +4278,10 @@ nsISupports*
|
||||
nsStyleSheetListSH::GetItemAt(nsISupports *aNative, uint32_t aIndex,
|
||||
nsWrapperCache **aCache, nsresult *rv)
|
||||
{
|
||||
nsDOMStyleSheetList* list = nsDOMStyleSheetList::FromSupports(aNative);
|
||||
|
||||
return list->GetItemAt(aIndex);
|
||||
nsIDOMStyleSheetList* list = static_cast<nsIDOMStyleSheetList*>(aNative);
|
||||
nsCOMPtr<nsIDOMStyleSheet> sheet;
|
||||
list->Item(aIndex, getter_AddRefs(sheet));
|
||||
return sheet;
|
||||
}
|
||||
|
||||
|
||||
|
@ -964,6 +964,12 @@ DOMInterfaces = {
|
||||
'nativeType': 'nsDOMScrollAreaEvent',
|
||||
},
|
||||
|
||||
'ShadowRoot': {
|
||||
'resultNotAddRefed': [
|
||||
'styleSheets'
|
||||
]
|
||||
},
|
||||
|
||||
'SharedWorker': {
|
||||
'nativeType': 'mozilla::dom::workers::SharedWorker',
|
||||
'headerFile': 'mozilla/dom/workers/bindings/SharedWorker.h',
|
||||
|
10
dom/tests/mochitest/webcomponents/inert_style.css
Normal file
10
dom/tests/mochitest/webcomponents/inert_style.css
Normal file
@ -0,0 +1,10 @@
|
||||
/* 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/. */
|
||||
|
||||
/* This style is linked in test_shadowroot_inert_link to ensure
|
||||
that link element in ShadowRoot is inert. */
|
||||
span {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
@ -8,3 +8,9 @@
|
||||
[test_document_register_lifecycle.html]
|
||||
[test_template.html]
|
||||
[test_shadow_root.html]
|
||||
[test_shadow_root_inert_element.html]
|
||||
[inert_style.css]
|
||||
[test_shadow_root_style.html]
|
||||
[test_shadow_root_style_multiple_shadow.html]
|
||||
[test_shadow_root_style_order.html]
|
||||
[test_style_fallback_content.html]
|
||||
|
@ -0,0 +1,44 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=806506
|
||||
-->
|
||||
<head>
|
||||
<title>Test for inert elements in ShadowRoot</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="runChecks();">
|
||||
<div id="grabme"></div>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
|
||||
<script>
|
||||
|
||||
var element = document.getElementById("grabme");
|
||||
var shadow = element.createShadowRoot();
|
||||
|
||||
// Check that <base> is inert.
|
||||
shadow.innerHTML = '<base href="http://www.example.org/" />';
|
||||
isnot(document.baseURI, "http://www.example.org/", "Base element should be inert in ShadowRoot.");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Check that <link> is inert.
|
||||
var numStyleBeforeLoad = document.styleSheets.length;
|
||||
|
||||
shadow.innerHTML = '<link id="shadowlink" rel="stylesheet" type="text/css" href="inert_style.css" /><span id="shadowspan"></span>';
|
||||
shadow.applyAuthorStyles = true;
|
||||
var shadowSpan = shadow.getElementById("shadowspan");
|
||||
var shadowStyle = shadow.getElementById("shadowlink");
|
||||
|
||||
function runChecks() {
|
||||
isnot(getComputedStyle(shadowSpan, null).getPropertyValue("padding-top"), "10px", "Link element should be inert.");
|
||||
is(document.styleSheets.length, numStyleBeforeLoad, "Document style count should remain the same because the style should not be in the doucment.");
|
||||
is(shadow.styleSheets.length, 0, "Inert link should not add style to ShadowRoot.");
|
||||
// Remove link to make sure we don't get assertions.
|
||||
shadow.removeChild(shadowStyle);
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
80
dom/tests/mochitest/webcomponents/test_shadowroot_style.html
Normal file
80
dom/tests/mochitest/webcomponents/test_shadowroot_style.html
Normal file
@ -0,0 +1,80 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=806506
|
||||
-->
|
||||
<head>
|
||||
<title>Test for ShadowRoot styling</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="tall" id="bodydiv"></div>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
|
||||
<script>
|
||||
// Create ShadowRoot.
|
||||
var elem = document.createElement("div");
|
||||
var root = elem.createShadowRoot();
|
||||
|
||||
// A style element that will be appended into the ShadowRoot.
|
||||
var shadowStyle = document.createElement("style");
|
||||
shadowStyle.innerHTML = ".tall { height: 100px; } .fat { padding-left: inherit; }";
|
||||
|
||||
root.innerHTML = '<div id="divtostyle" class="tall fat"></div>';
|
||||
var divToStyle = root.getElementById("divtostyle");
|
||||
|
||||
// Make sure styleSheet counts are correct after appending a style to the ShadowRoot.
|
||||
is(document.styleSheets.length, 1, "There should only be one style sheet on the document from the test style sheet.");
|
||||
is(root.styleSheets.length, 0, "The ShadowRoot should have no style sheets.");
|
||||
root.appendChild(shadowStyle);
|
||||
is(document.styleSheets.length, 1, "Styles in the ShadowRoot element should not be accessible from the document.");
|
||||
is(root.styleSheets.length, 1, "ShadowRoot should have one style sheet from the appened style.");
|
||||
is(root.styleSheets[0].ownerNode, shadowStyle, "First style in ShadowRoot should match the style that was just appended.");
|
||||
|
||||
var dummyStyle = document.createElement("style");
|
||||
root.appendChild(dummyStyle);
|
||||
is(root.styleSheets.length, 2, "ShadowRoot should have an additional style from appending dummyStyle.");
|
||||
is(root.styleSheets[1].ownerNode, dummyStyle, "Second style in ShadowRoot should be the dummyStyle.");
|
||||
root.removeChild(dummyStyle);
|
||||
is(root.styleSheets.length, 1, "Removing dummyStyle should remove it from the ShadowRoot style sheets.");
|
||||
is(root.styleSheets[0].ownerNode, shadowStyle, "The style sheet remaining in the ShadowRoot should be shadowStyle.");
|
||||
|
||||
// Make sure that elements outside of the ShadowRoot are not affected by the ShadowRoot style.
|
||||
isnot(getComputedStyle(document.getElementById("bodydiv"), null).getPropertyValue("height"), "100px", "Style sheets in ShadowRoot should not apply to elements no in the ShadowRoot.");
|
||||
|
||||
// Make sure that elements in the ShadowRoot are styled according to the ShadowRoot style.
|
||||
is(getComputedStyle(divToStyle, null).getPropertyValue("height"), "100px", "ShadowRoot style sheets should apply to elements in ShadowRoot.");
|
||||
|
||||
// Tests for applyAuthorStyles.
|
||||
var authorStyle = document.createElement("style");
|
||||
authorStyle.innerHTML = ".fat { padding-right: 20px; padding-left: 30px; }";
|
||||
document.body.appendChild(authorStyle);
|
||||
|
||||
is(root.applyAuthorStyles, false, "applyAuthorStyles defaults to false.");
|
||||
isnot(getComputedStyle(divToStyle, null).getPropertyValue("padding-right"), "20px", "Author styles should not apply to ShadowRoot when ShadowRoot.applyAuthorStyles is false.");
|
||||
root.applyAuthorStyles = true;
|
||||
is(root.applyAuthorStyles, true, "applyAuthorStyles was set to true.");
|
||||
is(getComputedStyle(divToStyle, null).getPropertyValue("padding-right"), "20px", "Author styles should apply to ShadowRoot when ShadowRoot.applyAuthorStyles is true.");
|
||||
root.applyAuthorStyles = false;
|
||||
is(root.applyAuthorStyles, false, "applyAuthorStyles was set to false.");
|
||||
isnot(getComputedStyle(divToStyle, null).getPropertyValue("padding-right"), "20px", "Author styles should not apply to ShadowRoot when ShadowRoot.applyAuthorStyles is false.");
|
||||
|
||||
// Test dynamic changes to style in ShadowRoot.
|
||||
root.innerHTML = '<div id="divtostyle" class="dummy"></div>';
|
||||
divToStyle = root.getElementById("divtostyle");
|
||||
var dummyShadowStyle = document.createElement("style");
|
||||
dummyShadowStyle.innerHTML = ".dummy { height: 300px; }";
|
||||
root.appendChild(dummyShadowStyle);
|
||||
is(getComputedStyle(divToStyle, null).getPropertyValue("height"), "300px", "Dummy element in ShadowRoot should be styled by style in ShadowRoot.");
|
||||
dummyShadowStyle.innerHTML = ".dummy { height: 200px; }";
|
||||
is(getComputedStyle(divToStyle, null).getPropertyValue("height"), "200px", "Dynamic changes to styles in ShadowRoot should change style of affected elements.");
|
||||
|
||||
// Test id selector in ShadowRoot style.
|
||||
root.innerHTML = '<style>#divtostyle { padding-top: 10px; }</style><div id="divtostyle"></div>';
|
||||
divToStyle = root.getElementById("divtostyle");
|
||||
is(getComputedStyle(divToStyle, null).getPropertyValue("padding-top"), "10px", "ID selector in style selector should match element.");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -0,0 +1,54 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=806506
|
||||
-->
|
||||
<head>
|
||||
<title>Test for ShadowRoot styles with multiple ShadowRoot on host.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="tall" id="bodydiv"></div>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
|
||||
<script>
|
||||
// Create ShadowRoot.
|
||||
var elem = document.createElement("div");
|
||||
var firstRoot = elem.createShadowRoot();
|
||||
var secondRoot = elem.createShadowRoot();
|
||||
var thirdRoot = elem.createShadowRoot();
|
||||
|
||||
// A style element that will be appended into the ShadowRoot.
|
||||
var firstStyle = document.createElement("style");
|
||||
firstRoot.appendChild(firstStyle);
|
||||
is(firstRoot.styleSheets.length, 1, "firstStyle should be the only style in firstRoot.");
|
||||
is(firstRoot.styleSheets[0].ownerNode, firstStyle, "firstStyle should in the ShadowRoot styleSheets.");
|
||||
|
||||
var secondStyle = document.createElement("style");
|
||||
secondRoot.appendChild(secondStyle);
|
||||
is(secondRoot.styleSheets.length, 1, "secondStyle should be the only style in secondRoot.");
|
||||
is(secondRoot.styleSheets[0].ownerNode, secondStyle, "secondStyle should in the ShadowRoot styleSheets.");
|
||||
|
||||
var thirdStyle = document.createElement("style");
|
||||
thirdRoot.appendChild(thirdStyle);
|
||||
is(thirdRoot.styleSheets.length, 1, "thirdStyle should be the only style in thirdRoot.");
|
||||
is(thirdRoot.styleSheets[0].ownerNode, thirdStyle, "thirdStyle should in the ShadowRoot styleSheets.");
|
||||
|
||||
// Check the stylesheet counts again to make sure that none of the style sheets leaked into the older ShadowRoots.
|
||||
is(firstRoot.styleSheets.length, 1, "Adding a stylesheet to a younger ShadowRoot should not affect stylesheets in the older ShadowRoot.");
|
||||
is(secondRoot.styleSheets.length, 1, "Adding a stylesheet to a younger ShadowRoot should not affect stylesheets in the older ShadowRoot.");
|
||||
|
||||
// Remove styles and make sure they are removed from the correct ShadowRoot.
|
||||
firstRoot.removeChild(firstStyle);
|
||||
is(firstRoot.styleSheets.length, 0, "firstRoot should no longer have any styles.");
|
||||
|
||||
thirdRoot.removeChild(thirdStyle);
|
||||
is(thirdRoot.styleSheets.length, 0, "thirdRoot should no longer have any styles.");
|
||||
|
||||
secondRoot.removeChild(secondStyle);
|
||||
is(secondRoot.styleSheets.length, 0, "secondRoot should no longer have any styles.");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -0,0 +1,39 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=806506
|
||||
-->
|
||||
<head>
|
||||
<title>Test for ShadowRoot style order</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
|
||||
<script>
|
||||
// Create ShadowRoot.
|
||||
var elem = document.createElement("div");
|
||||
var root = elem.createShadowRoot();
|
||||
|
||||
// Style elements that will be appended into the ShadowRoot.
|
||||
var tallShadowStyle = document.createElement("style");
|
||||
tallShadowStyle.innerHTML = ".tall { height: 100px; }";
|
||||
|
||||
var veryTallShadowStyle = document.createElement("style");
|
||||
veryTallShadowStyle.innerHTML = ".tall { height: 200px; }";
|
||||
|
||||
var divToStyle = document.createElement("div");
|
||||
divToStyle.setAttribute("class", "tall");
|
||||
root.appendChild(divToStyle);
|
||||
|
||||
// Make sure the styles are applied in tree order.
|
||||
root.appendChild(tallShadowStyle);
|
||||
is(root.styleSheets.length, 1, "ShadowRoot should have one style sheet.");
|
||||
is(window.getComputedStyle(divToStyle, null).getPropertyValue("height"), "100px", "Style in ShadowRoot should apply to elements in ShadowRoot.");
|
||||
root.appendChild(veryTallShadowStyle);
|
||||
is(root.styleSheets.length, 2, "ShadowRoot should have two style sheets.");
|
||||
is(window.getComputedStyle(divToStyle, null).getPropertyValue("height"), "200px", "Style in ShadowRoot should apply to elements in ShadowRoot in tree order.");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,28 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=806506
|
||||
-->
|
||||
<head>
|
||||
<title>Test for styling fallback content</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="grabme"></div>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
|
||||
<script>
|
||||
var host = document.getElementById("grabme");
|
||||
var shadow = host.createShadowRoot();
|
||||
shadow.innerHTML = '<style id="innerstyle"></style><span id="container"><content><span id="innerspan">Hello</span></content></span>';
|
||||
var innerStyle = shadow.getElementById("innerstyle");
|
||||
|
||||
innerStyle.innerHTML = '#innerspan { margin-top: 10px; }';
|
||||
var innerSpan = shadow.getElementById("innerspan");
|
||||
is(getComputedStyle(innerSpan, null).getPropertyValue("margin-top"), "10px", "Default content should be style by id selector.");
|
||||
|
||||
innerStyle.innerHTML = '#container > content > #innerspan { margin-top: 30px; }';
|
||||
is(getComputedStyle(innerSpan, null).getPropertyValue("margin-top"), "30px", "Default content should be style by child combinators.");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -19,5 +19,7 @@ interface ShadowRoot : DocumentFragment
|
||||
HTMLCollection getElementsByClassName(DOMString classNames);
|
||||
[SetterThrows,TreatNullAs=EmptyString]
|
||||
attribute DOMString innerHTML;
|
||||
attribute boolean applyAuthorStyles;
|
||||
readonly attribute StyleSheetList styleSheets;
|
||||
};
|
||||
|
||||
|
@ -2577,7 +2577,7 @@ ElementRestyler::RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint)
|
||||
// not have a frame and would not otherwise be pushed as an ancestor.
|
||||
nsIContent* parent = undisplayed->mContent->GetParent();
|
||||
TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
|
||||
if (parent && parent->IsActiveChildrenElement()) {
|
||||
if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
|
||||
insertionPointPusher.PushAncestorAndStyleScope(parent);
|
||||
}
|
||||
|
||||
@ -2748,7 +2748,7 @@ ElementRestyler::RestyleContentChildren(nsIFrame* aParent,
|
||||
// nsPageFrame that does not have a content.
|
||||
nsIContent* parent = child->GetContent() ? child->GetContent()->GetParent() : nullptr;
|
||||
TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
|
||||
if (parent && parent->IsActiveChildrenElement()) {
|
||||
if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
|
||||
insertionPointPusher.PushAncestorAndStyleScope(parent);
|
||||
}
|
||||
|
||||
|
@ -3540,7 +3540,7 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt
|
||||
nsIContent* parent = content->GetParent();
|
||||
TreeMatchContext::AutoAncestorPusher
|
||||
insertionPointPusher(aState.mTreeMatchContext);
|
||||
if (parent && parent->IsActiveChildrenElement()) {
|
||||
if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
|
||||
if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
|
||||
insertionPointPusher.PushAncestorAndStyleScope(parent);
|
||||
} else {
|
||||
|
@ -611,7 +611,7 @@ nsFrameManagerBase::UndisplayedMap::GetEntryFor(nsIContent** aParentContent)
|
||||
// be a <xbl:children> element) but the parent in the frame tree would be the
|
||||
// insertion parent (parent of the <xbl:children> element). Here the children
|
||||
// elements are normalized to the insertion parent to correct for the mismatch.
|
||||
if (parentContent && parentContent->IsActiveChildrenElement()) {
|
||||
if (parentContent && nsContentUtils::IsContentInsertionPoint(parentContent)) {
|
||||
parentContent = parentContent->GetParent();
|
||||
// Change the caller's pointer for the parent content to be the insertion parent.
|
||||
*aParentContent = parentContent;
|
||||
|
@ -98,6 +98,7 @@ class Selection;
|
||||
namespace dom {
|
||||
class Element;
|
||||
class Touch;
|
||||
class ShadowRoot;
|
||||
} // namespace dom
|
||||
|
||||
namespace layers{
|
||||
@ -527,6 +528,11 @@ public:
|
||||
void RestyleForAnimation(mozilla::dom::Element* aElement,
|
||||
nsRestyleHint aHint);
|
||||
|
||||
// ShadowRoot has APIs that can change styles so we only
|
||||
// want to restyle elements in the ShadowRoot and not the whole
|
||||
// document.
|
||||
virtual void RestyleShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot) = 0;
|
||||
|
||||
/**
|
||||
* Determine if it is safe to flush all pending notifications
|
||||
* @param aIsSafeToFlush true if it is safe, false otherwise.
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIContent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsCSSStyleSheet.h"
|
||||
#include "nsAnimationManager.h"
|
||||
@ -159,6 +160,7 @@
|
||||
#include "nsIScreenManager.h"
|
||||
#include "nsPlaceholderFrame.h"
|
||||
#include "nsTransitionManager.h"
|
||||
#include "ChildIterator.h"
|
||||
#include "RestyleManager.h"
|
||||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsIDragSession.h"
|
||||
@ -5733,6 +5735,22 @@ private:
|
||||
nsIFrame* mFrame;
|
||||
};
|
||||
|
||||
void
|
||||
PresShell::RestyleShadowRoot(ShadowRoot* aShadowRoot)
|
||||
{
|
||||
// Mark the children of the ShadowRoot as style changed but not
|
||||
// the ShadowRoot itself because it is a document fragment and does not
|
||||
// have a frame.
|
||||
ExplicitChildIterator iterator(aShadowRoot);
|
||||
for (nsIContent* child = iterator.GetNextChild();
|
||||
child;
|
||||
child = iterator.GetNextChild()) {
|
||||
if (child->IsElement()) {
|
||||
mChangedScopeStyleRoots.AppendElement(child->AsElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::Paint(nsView* aViewToPaint,
|
||||
const nsRegion& aDirtyRegion,
|
||||
|
@ -348,6 +348,8 @@ public:
|
||||
|
||||
virtual bool AssumeAllImagesVisible() MOZ_OVERRIDE;
|
||||
|
||||
virtual void RestyleShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot);
|
||||
|
||||
protected:
|
||||
virtual ~PresShell();
|
||||
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "nsIThreadInternal.h"
|
||||
#include "nsCrossSiteListenerProxy.h"
|
||||
#include "nsINetworkSeer.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/dom/URL.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
@ -1878,8 +1879,14 @@ Loader::LoadInlineStyle(nsIContent* aElement,
|
||||
|
||||
PrepareSheet(sheet, aTitle, aMedia, nullptr, aScopeElement, *aIsAlternate);
|
||||
|
||||
rv = InsertSheetInDoc(sheet, aElement, mDocument);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aElement->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
|
||||
ShadowRoot* containingShadow = aElement->GetContainingShadow();
|
||||
MOZ_ASSERT(containingShadow);
|
||||
containingShadow->InsertSheet(sheet, aElement);
|
||||
} else {
|
||||
rv = InsertSheetInDoc(sheet, aElement, mDocument);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
SheetLoadData* data = new SheetLoadData(this, aTitle, nullptr, sheet,
|
||||
owningElement, *aIsAlternate,
|
||||
|
Loading…
x
Reference in New Issue
Block a user