summaryrefslogtreecommitdiffstats
path: root/dom
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2020-04-17 16:02:56 +0200
committerGitHub <noreply@github.com>2020-04-17 16:02:56 +0200
commitd5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf (patch)
tree2bfef192cbb748b675ce8308c242a376798e265d /dom
parent5caf99795aa81e1fc145b8e937b1ee8197ed2486 (diff)
parentf35aa3e15fedf3cd4ad163d60ab74a9537ca5c82 (diff)
downloadUXP-d5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf.tar
UXP-d5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf.tar.gz
UXP-d5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf.tar.lz
UXP-d5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf.tar.xz
UXP-d5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf.zip
Merge pull request #1518 from MoonchildProductions/shadowdom-merge
Incremental shadowdom-merge
Diffstat (limited to 'dom')
-rw-r--r--dom/animation/EffectCompositor.cpp22
-rw-r--r--dom/animation/KeyframeEffectReadOnly.cpp12
-rw-r--r--dom/archivereader/ArchiveRequest.cpp4
-rw-r--r--dom/archivereader/ArchiveRequest.h3
-rw-r--r--dom/base/AnonymousContent.cpp27
-rw-r--r--dom/base/AnonymousContent.h5
-rw-r--r--dom/base/Attr.cpp2
-rw-r--r--dom/base/Attr.h2
-rw-r--r--dom/base/BlobSet.h3
-rw-r--r--dom/base/CORSMode.h2
-rw-r--r--dom/base/ChildIterator.cpp301
-rw-r--r--dom/base/ChildIterator.h77
-rw-r--r--dom/base/ChromeUtils.cpp1
-rw-r--r--dom/base/ChromeUtils.h1
-rw-r--r--dom/base/CustomElementRegistry.cpp40
-rw-r--r--dom/base/CustomElementRegistry.h13
-rw-r--r--dom/base/DirectionalityUtils.cpp4
-rw-r--r--dom/base/DocGroup.cpp26
-rw-r--r--dom/base/DocGroup.h19
-rw-r--r--dom/base/DocumentFragment.cpp2
-rw-r--r--dom/base/DocumentFragment.h13
-rw-r--r--dom/base/Element.cpp562
-rw-r--r--dom/base/Element.h252
-rw-r--r--dom/base/ElementInlines.h11
-rw-r--r--dom/base/FragmentOrElement.cpp207
-rw-r--r--dom/base/FragmentOrElement.h10
-rw-r--r--dom/base/GroupedSHistory.h2
-rw-r--r--dom/base/ImageTracker.cpp2
-rw-r--r--dom/base/ImageTracker.h1
-rw-r--r--dom/base/MutableBlobStorage.h3
-rw-r--r--dom/base/MutableBlobStreamListener.cpp1
-rw-r--r--dom/base/NodeInfo.cpp1
-rw-r--r--dom/base/Pose.h1
-rw-r--r--dom/base/ShadowRoot.cpp747
-rw-r--r--dom/base/ShadowRoot.h155
-rw-r--r--dom/base/StyleScope.cpp27
-rw-r--r--dom/base/StyleScope.h81
-rw-r--r--dom/base/StyleSheetList.cpp23
-rw-r--r--dom/base/StyleSheetList.h44
-rw-r--r--dom/base/TabGroup.h2
-rw-r--r--dom/base/ThirdPartyUtil.cpp1
-rw-r--r--dom/base/TimeoutHandler.cpp1
-rw-r--r--dom/base/TimeoutHandler.h2
-rwxr-xr-xdom/base/TimerClamping.h2
-rw-r--r--dom/base/crashtests/1419799.html17
-rw-r--r--dom/base/crashtests/1422931.html6
-rw-r--r--dom/base/crashtests/crashtests.list6
-rwxr-xr-xdom/base/moz.build6
-rw-r--r--dom/base/nsAttrAndChildArray.cpp34
-rw-r--r--dom/base/nsAttrAndChildArray.h24
-rw-r--r--dom/base/nsAttrValueOrString.h30
-rw-r--r--dom/base/nsContentUtils.cpp131
-rw-r--r--dom/base/nsContentUtils.h42
-rw-r--r--dom/base/nsDOMAttributeMap.cpp6
-rw-r--r--dom/base/nsDOMAttributeMap.h7
-rw-r--r--dom/base/nsDOMMutationObserver.cpp50
-rw-r--r--dom/base/nsDOMMutationObserver.h9
-rw-r--r--dom/base/nsDOMTokenList.cpp6
-rw-r--r--dom/base/nsDOMTokenList.h7
-rw-r--r--dom/base/nsDOMWindowUtils.cpp8
-rw-r--r--dom/base/nsDocument.cpp524
-rw-r--r--dom/base/nsDocument.h71
-rw-r--r--dom/base/nsDocumentEncoder.cpp39
-rw-r--r--dom/base/nsFocusManager.cpp8
-rw-r--r--dom/base/nsFrameLoader.cpp3
-rw-r--r--dom/base/nsGenConImageContent.cpp4
-rw-r--r--dom/base/nsGenericDOMDataNode.cpp24
-rw-r--r--dom/base/nsGenericDOMDataNode.h14
-rw-r--r--dom/base/nsGkAtomList.h5
-rw-r--r--dom/base/nsGlobalWindow.cpp9
-rw-r--r--dom/base/nsHTMLContentSerializer.cpp22
-rw-r--r--dom/base/nsIContent.h68
-rw-r--r--dom/base/nsIContentInlines.h47
-rw-r--r--dom/base/nsIDocument.h64
-rw-r--r--dom/base/nsIDocumentInlines.h25
-rw-r--r--dom/base/nsINode.cpp9
-rw-r--r--dom/base/nsINode.h98
-rw-r--r--dom/base/nsInProcessTabChildGlobal.cpp12
-rw-r--r--dom/base/nsInProcessTabChildGlobal.h4
-rw-r--r--dom/base/nsJSEnvironment.cpp1
-rw-r--r--dom/base/nsJSUtils.cpp1
-rw-r--r--dom/base/nsMappedAttributeElement.cpp14
-rw-r--r--dom/base/nsMappedAttributeElement.h9
-rw-r--r--dom/base/nsMappedAttributes.cpp19
-rw-r--r--dom/base/nsMappedAttributes.h3
-rw-r--r--dom/base/nsNodeUtils.cpp4
-rw-r--r--dom/base/nsRange.cpp438
-rw-r--r--dom/base/nsRange.h116
-rw-r--r--dom/base/nsStyledElement.cpp31
-rw-r--r--dom/base/nsStyledElement.h4
-rw-r--r--dom/base/nsTextNode.cpp7
-rw-r--r--dom/base/nsTextNode.h4
-rw-r--r--dom/base/nsWindowRoot.cpp4
-rwxr-xr-xdom/base/nsXHTMLContentSerializer.cpp35
-rw-r--r--dom/base/nsXMLContentSerializer.cpp13
-rw-r--r--dom/base/test/chrome/chrome.ini8
-rw-r--r--dom/base/test/chrome/registerElement_ep.js8
-rw-r--r--dom/base/test/chrome/test_registerElement_content.xul52
-rw-r--r--dom/base/test/chrome/test_registerElement_ep.xul44
-rw-r--r--dom/base/test/mochitest.ini2
-rw-r--r--dom/base/test/test_document_register.html6
-rw-r--r--dom/base/test/test_mutationobservers.html28
-rw-r--r--dom/bindings/BindingUtils.cpp32
-rw-r--r--dom/bindings/BindingUtils.h6
-rw-r--r--dom/bindings/Codegen.py46
-rw-r--r--dom/bindings/Configuration.py3
-rw-r--r--dom/bindings/test/TestBindingHeader.h7
-rw-r--r--dom/events/ContentEventHandler.cpp9
-rw-r--r--dom/events/DOMEventTargetHelper.cpp4
-rw-r--r--dom/events/DOMEventTargetHelper.h4
-rwxr-xr-xdom/events/Event.cpp34
-rwxr-xr-xdom/events/Event.h2
-rw-r--r--dom/events/EventDispatcher.cpp363
-rw-r--r--dom/events/EventDispatcher.h72
-rw-r--r--dom/events/EventStateManager.cpp37
-rw-r--r--dom/events/EventStates.h40
-rw-r--r--dom/events/MouseEvent.cpp5
-rw-r--r--dom/events/test/mochitest.ini1
-rw-r--r--dom/events/test/test_bug1305458.html50
-rw-r--r--dom/html/HTMLAnchorElement.cpp90
-rw-r--r--dom/html/HTMLAnchorElement.h24
-rw-r--r--dom/html/HTMLAreaElement.cpp52
-rw-r--r--dom/html/HTMLAreaElement.h18
-rw-r--r--dom/html/HTMLBodyElement.cpp238
-rw-r--r--dom/html/HTMLBodyElement.h38
-rw-r--r--dom/html/HTMLButtonElement.cpp13
-rw-r--r--dom/html/HTMLButtonElement.h11
-rw-r--r--dom/html/HTMLCanvasElement.cpp53
-rw-r--r--dom/html/HTMLCanvasElement.h37
-rw-r--r--dom/html/HTMLContentElement.cpp393
-rw-r--r--dom/html/HTMLContentElement.h135
-rw-r--r--dom/html/HTMLDetailsElement.cpp2
-rw-r--r--dom/html/HTMLDetailsElement.h3
-rw-r--r--dom/html/HTMLFieldSetElement.cpp9
-rw-r--r--dom/html/HTMLFieldSetElement.h7
-rw-r--r--dom/html/HTMLFormElement.cpp52
-rw-r--r--dom/html/HTMLFormElement.h18
-rw-r--r--dom/html/HTMLFrameSetElement.cpp61
-rw-r--r--dom/html/HTMLFrameSetElement.h15
-rw-r--r--dom/html/HTMLIFrameElement.cpp71
-rw-r--r--dom/html/HTMLIFrameElement.h33
-rw-r--r--dom/html/HTMLImageElement.cpp169
-rw-r--r--dom/html/HTMLImageElement.h54
-rw-r--r--dom/html/HTMLInputElement.cpp264
-rw-r--r--dom/html/HTMLInputElement.h14
-rw-r--r--dom/html/HTMLLegendElement.cpp15
-rw-r--r--dom/html/HTMLLegendElement.h10
-rw-r--r--dom/html/HTMLLinkElement.cpp11
-rw-r--r--dom/html/HTMLLinkElement.h6
-rw-r--r--dom/html/HTMLMediaElement.cpp115
-rw-r--r--dom/html/HTMLMediaElement.h34
-rw-r--r--dom/html/HTMLMenuItemElement.cpp9
-rw-r--r--dom/html/HTMLMenuItemElement.h7
-rw-r--r--dom/html/HTMLMetaElement.cpp5
-rw-r--r--dom/html/HTMLMetaElement.h4
-rw-r--r--dom/html/HTMLObjectElement.cpp56
-rw-r--r--dom/html/HTMLObjectElement.h26
-rw-r--r--dom/html/HTMLOptGroupElement.cpp9
-rw-r--r--dom/html/HTMLOptGroupElement.h7
-rw-r--r--dom/html/HTMLOptionElement.cpp7
-rw-r--r--dom/html/HTMLOptionElement.h6
-rw-r--r--dom/html/HTMLOptionsCollection.cpp6
-rw-r--r--dom/html/HTMLOptionsCollection.h2
-rw-r--r--dom/html/HTMLScriptElement.cpp5
-rw-r--r--dom/html/HTMLScriptElement.h4
-rw-r--r--dom/html/HTMLSelectElement.cpp70
-rw-r--r--dom/html/HTMLSelectElement.h11
-rw-r--r--dom/html/HTMLShadowElement.cpp373
-rw-r--r--dom/html/HTMLShadowElement.h96
-rw-r--r--dom/html/HTMLSharedElement.cpp62
-rw-r--r--dom/html/HTMLSharedElement.h16
-rw-r--r--dom/html/HTMLSharedObjectElement.cpp58
-rw-r--r--dom/html/HTMLSharedObjectElement.h24
-rw-r--r--dom/html/HTMLSlotElement.cpp235
-rw-r--r--dom/html/HTMLSlotElement.h79
-rw-r--r--dom/html/HTMLSourceElement.cpp5
-rw-r--r--dom/html/HTMLSourceElement.h1
-rw-r--r--dom/html/HTMLStyleElement.cpp5
-rw-r--r--dom/html/HTMLStyleElement.h1
-rw-r--r--dom/html/HTMLTableCellElement.cpp14
-rw-r--r--dom/html/HTMLTableCellElement.h2
-rw-r--r--dom/html/HTMLTableElement.cpp37
-rw-r--r--dom/html/HTMLTableElement.h10
-rw-r--r--dom/html/HTMLTextAreaElement.cpp26
-rw-r--r--dom/html/HTMLTextAreaElement.h10
-rw-r--r--dom/html/HTMLUnknownElement.h3
-rw-r--r--dom/html/moz.build6
-rw-r--r--dom/html/nsDOMStringMap.cpp6
-rw-r--r--dom/html/nsDOMStringMap.h5
-rw-r--r--dom/html/nsGenericHTMLElement.cpp237
-rw-r--r--dom/html/nsGenericHTMLElement.h35
-rw-r--r--dom/html/nsGenericHTMLFrameElement.cpp180
-rw-r--r--dom/html/nsGenericHTMLFrameElement.h36
-rw-r--r--dom/html/nsHTMLContentSink.cpp10
-rw-r--r--dom/html/nsTextEditorState.cpp17
-rw-r--r--dom/html/nsTextEditorState.h5
-rw-r--r--dom/html/reftests/body-frame-margin-remove-other-pres-hint-ref.html14
-rw-r--r--dom/html/reftests/body-frame-margin-remove-other-pres-hint.html16
-rw-r--r--dom/html/reftests/body-topmargin-dynamic.html12
-rw-r--r--dom/html/reftests/body-topmargin-ref.html7
-rw-r--r--dom/html/reftests/reftest-stylo.list7
-rw-r--r--dom/html/reftests/reftest.list7
-rw-r--r--dom/html/test/mochitest.ini1
-rw-r--r--dom/html/test/test_bug1081037.html133
-rw-r--r--dom/indexedDB/IDBFileHandle.cpp4
-rw-r--r--dom/indexedDB/IDBFileHandle.h2
-rw-r--r--dom/indexedDB/IDBFileRequest.cpp4
-rw-r--r--dom/indexedDB/IDBFileRequest.h2
-rw-r--r--dom/indexedDB/IDBRequest.cpp4
-rw-r--r--dom/indexedDB/IDBRequest.h2
-rw-r--r--dom/indexedDB/IDBTransaction.cpp4
-rw-r--r--dom/indexedDB/IDBTransaction.h2
-rw-r--r--dom/interfaces/events/nsIDOMEventTarget.idl15
-rw-r--r--dom/interfaces/range/nsIDOMRange.idl12
-rw-r--r--dom/ipc/TabChild.h2
-rw-r--r--dom/mathml/nsMathMLElement.cpp51
-rw-r--r--dom/mathml/nsMathMLElement.h17
-rw-r--r--dom/svg/SVGAElement.cpp6
-rw-r--r--dom/svg/SVGAElement.h3
-rw-r--r--dom/svg/SVGAnimationElement.cpp5
-rw-r--r--dom/svg/SVGAnimationElement.h4
-rw-r--r--dom/svg/SVGFEImageElement.cpp5
-rw-r--r--dom/svg/SVGFEImageElement.h4
-rw-r--r--dom/svg/SVGImageElement.cpp5
-rw-r--r--dom/svg/SVGImageElement.h4
-rw-r--r--dom/svg/SVGSVGElement.cpp4
-rw-r--r--dom/svg/SVGSVGElement.h3
-rw-r--r--dom/svg/SVGScriptElement.cpp5
-rw-r--r--dom/svg/SVGScriptElement.h4
-rw-r--r--dom/svg/nsSVGClass.cpp4
-rw-r--r--dom/svg/nsSVGElement.cpp62
-rw-r--r--dom/svg/nsSVGElement.h6
-rw-r--r--dom/svg/nsSVGPathGeometryElement.cpp5
-rw-r--r--dom/svg/nsSVGPathGeometryElement.h4
-rw-r--r--dom/tests/mochitest/webcomponents/mochitest.ini15
-rw-r--r--dom/tests/mochitest/webcomponents/test_bug1276240.html2
-rw-r--r--dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html26
-rw-r--r--dom/tests/mochitest/webcomponents/test_custom_element_register_invalid_callbacks.html69
-rw-r--r--dom/tests/mochitest/webcomponents/test_dest_insertion_points.html73
-rw-r--r--dom/tests/mochitest/webcomponents/test_dest_insertion_points_shadow.html68
-rw-r--r--dom/tests/mochitest/webcomponents/test_document_register_parser.html47
-rw-r--r--dom/tests/mochitest/webcomponents/test_document_shared_registry.html46
-rw-r--r--dom/tests/mochitest/webcomponents/test_dynamic_content_element_matching.html50
-rw-r--r--dom/tests/mochitest/webcomponents/test_event_dispatch.html458
-rw-r--r--dom/tests/mochitest/webcomponents/test_fallback_dest_insertion_points.html71
-rw-r--r--dom/tests/mochitest/webcomponents/test_nested_content_element.html127
-rw-r--r--dom/tests/mochitest/webcomponents/test_shadowroot_host.html41
-rw-r--r--dom/tests/mochitest/webcomponents/test_shadowroot_style_multiple_shadow.html57
-rw-r--r--dom/tests/mochitest/webcomponents/test_shadowroot_youngershadowroot.html41
-rw-r--r--dom/tests/mochitest/webcomponents/test_template_custom_elements.html32
-rw-r--r--dom/tests/mochitest/webcomponents/test_unresolved_pseudo_class.html99
-rw-r--r--dom/webidl/AnonymousContent.webidl8
-rw-r--r--dom/webidl/Document.webidl10
-rw-r--r--dom/webidl/Element.webidl24
-rw-r--r--dom/webidl/Event.webidl2
-rw-r--r--dom/webidl/HTMLContentElement.webidl20
-rw-r--r--dom/webidl/HTMLSlotElement.webidl (renamed from dom/webidl/HTMLShadowElement.webidl)13
-rw-r--r--dom/webidl/ShadowRoot.webidl14
-rw-r--r--dom/webidl/Text.webidl5
-rw-r--r--dom/webidl/WebComponents.webidl5
-rw-r--r--dom/webidl/moz.build3
-rw-r--r--dom/workers/SharedWorker.cpp6
-rw-r--r--dom/workers/SharedWorker.h2
-rw-r--r--dom/xbl/XBLChildrenElement.cpp39
-rw-r--r--dom/xbl/XBLChildrenElement.h12
-rw-r--r--dom/xbl/nsXBLService.cpp38
-rw-r--r--dom/xml/nsXMLElement.cpp23
-rw-r--r--dom/xml/nsXMLElement.h3
-rw-r--r--dom/xslt/xslt/txMozillaXSLTProcessor.cpp5
-rw-r--r--dom/xslt/xslt/txMozillaXSLTProcessor.h3
-rw-r--r--dom/xul/XULDocument.cpp1
-rw-r--r--dom/xul/nsXULElement.cpp150
-rw-r--r--dom/xul/nsXULElement.h16
273 files changed, 5130 insertions, 6660 deletions
diff --git a/dom/animation/EffectCompositor.cpp b/dom/animation/EffectCompositor.cpp
index c88cabe90..49da3c033 100644
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -356,24 +356,16 @@ EffectCompositor::GetElementToRestyle(dom::Element* aElement,
return aElement;
}
- nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
- if (!primaryFrame) {
- return nullptr;
- }
- nsIFrame* pseudoFrame;
if (aPseudoType == CSSPseudoElementType::before) {
- pseudoFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame);
- } else if (aPseudoType == CSSPseudoElementType::after) {
- pseudoFrame = nsLayoutUtils::GetAfterFrame(primaryFrame);
- } else {
- NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
- "other that :before or :after");
- return nullptr;
+ return nsLayoutUtils::GetBeforePseudo(aElement);
}
- if (!pseudoFrame) {
- return nullptr;
+ if (aPseudoType == CSSPseudoElementType::after) {
+ return nsLayoutUtils::GetAfterPseudo(aElement);
}
- return pseudoFrame->GetContent()->AsElement();
+
+ NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
+ "other that :before or :after");
+ return nullptr;
}
bool
diff --git a/dom/animation/KeyframeEffectReadOnly.cpp b/dom/animation/KeyframeEffectReadOnly.cpp
index 639e0b2b0..164ee0292 100644
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -1105,19 +1105,17 @@ KeyframeEffectReadOnly::GetAnimationFrame() const
return nullptr;
}
- nsIFrame* frame = mTarget->mElement->GetPrimaryFrame();
- if (!frame) {
- return nullptr;
- }
-
+ nsIFrame* frame;
if (mTarget->mPseudoType == CSSPseudoElementType::before) {
- frame = nsLayoutUtils::GetBeforeFrame(frame);
+ frame = nsLayoutUtils::GetBeforeFrame(mTarget->mElement);
} else if (mTarget->mPseudoType == CSSPseudoElementType::after) {
- frame = nsLayoutUtils::GetAfterFrame(frame);
+ frame = nsLayoutUtils::GetAfterFrame(mTarget->mElement);
} else {
+ frame = mTarget->mElement->GetPrimaryFrame();
MOZ_ASSERT(mTarget->mPseudoType == CSSPseudoElementType::NotPseudo,
"unknown mTarget->mPseudoType");
}
+
if (!frame) {
return nullptr;
}
diff --git a/dom/archivereader/ArchiveRequest.cpp b/dom/archivereader/ArchiveRequest.cpp
index ec1686804..832dec3fa 100644
--- a/dom/archivereader/ArchiveRequest.cpp
+++ b/dom/archivereader/ArchiveRequest.cpp
@@ -69,10 +69,10 @@ ArchiveRequest::~ArchiveRequest()
}
nsresult
-ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
+ArchiveRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
- aVisitor.mParentTarget = nullptr;
+ aVisitor.SetParentTarget(nullptr, false);
return NS_OK;
}
diff --git a/dom/archivereader/ArchiveRequest.h b/dom/archivereader/ArchiveRequest.h
index 3988f1aa1..3081a3e42 100644
--- a/dom/archivereader/ArchiveRequest.h
+++ b/dom/archivereader/ArchiveRequest.h
@@ -38,7 +38,8 @@ public:
ArchiveReader* aReader);
// nsIDOMEventTarget
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
public:
// This is called by the DOMArchiveRequestEvent
diff --git a/dom/base/AnonymousContent.cpp b/dom/base/AnonymousContent.cpp
index 1df36b048..aea923f2b 100644
--- a/dom/base/AnonymousContent.cpp
+++ b/dom/base/AnonymousContent.cpp
@@ -7,6 +7,7 @@
#include "AnonymousContent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/AnonymousContentBinding.h"
+#include "nsComputedDOMStyle.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDocument.h"
#include "nsIDOMHTMLCollection.h"
@@ -208,5 +209,31 @@ AnonymousContent::WrapObject(JSContext* aCx,
return AnonymousContentBinding::Wrap(aCx, this, aGivenProto, aReflector);
}
+void
+AnonymousContent::GetComputedStylePropertyValue(const nsAString& aElementId,
+ const nsAString& aPropertyName,
+ DOMString& aResult,
+ ErrorResult& aRv)
+{
+ Element* element = GetElementById(aElementId);
+ if (!element) {
+ aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+ return;
+ }
+
+ nsIPresShell* shell = element->OwnerDoc()->GetShell();
+ if (!shell) {
+ aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+ return;
+ }
+
+ RefPtr<nsComputedDOMStyle> cs =
+ new nsComputedDOMStyle(element,
+ NS_LITERAL_STRING(""),
+ element->OwnerDoc(),
+ nsComputedDOMStyle::eAll);
+ aRv = cs->GetPropertyValue(aPropertyName, aResult);
+}
+
} // namespace dom
} // namespace mozilla
diff --git a/dom/base/AnonymousContent.h b/dom/base/AnonymousContent.h
index fd3b59c44..b56c14595 100644
--- a/dom/base/AnonymousContent.h
+++ b/dom/base/AnonymousContent.h
@@ -68,6 +68,11 @@ public:
const Sequence<OwningNonNull<DOMRect>>& aRects,
ErrorResult& aError);
+ void GetComputedStylePropertyValue(const nsAString& aElementId,
+ const nsAString& aPropertyName,
+ DOMString& aResult,
+ ErrorResult& aRv);
+
private:
~AnonymousContent();
nsCOMPtr<Element> mContentNode;
diff --git a/dom/base/Attr.cpp b/dom/base/Attr.cpp
index 71b559392..df05ef5cb 100644
--- a/dom/base/Attr.cpp
+++ b/dom/base/Attr.cpp
@@ -344,7 +344,7 @@ Attr::RemoveChildAt(uint32_t aIndex, bool aNotify)
}
nsresult
-Attr::PreHandleEvent(EventChainPreVisitor& aVisitor)
+Attr::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
return NS_OK;
diff --git a/dom/base/Attr.h b/dom/base/Attr.h
index 3f80030d2..39ac8b195 100644
--- a/dom/base/Attr.h
+++ b/dom/base/Attr.h
@@ -54,7 +54,7 @@ public:
// nsIDOMAttr interface
NS_DECL_NSIDOMATTR
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
// nsIAttribute interface
void SetMap(nsDOMAttributeMap *aMap) override;
diff --git a/dom/base/BlobSet.h b/dom/base/BlobSet.h
index 3e22955dd..bf98cb023 100644
--- a/dom/base/BlobSet.h
+++ b/dom/base/BlobSet.h
@@ -8,6 +8,9 @@
#define mozilla_dom_BlobSet_h
#include "mozilla/RefPtr.h"
+#include "jsfriendapi.h"
+#include "nsString.h"
+#include "nsTArray.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/CORSMode.h b/dom/base/CORSMode.h
index 82f2f570d..7a2b4c579 100644
--- a/dom/base/CORSMode.h
+++ b/dom/base/CORSMode.h
@@ -4,6 +4,8 @@
* 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 <stdint.h>
+
#ifndef CORSMode_h_
#define CORSMode_h_
diff --git a/dom/base/ChildIterator.cpp b/dom/base/ChildIterator.cpp
index d8c454ae8..19156aff7 100644
--- a/dom/base/ChildIterator.cpp
+++ b/dom/base/ChildIterator.cpp
@@ -6,61 +6,27 @@
#include "ChildIterator.h"
#include "nsContentUtils.h"
+#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/XBLChildrenElement.h"
-#include "mozilla/dom/HTMLContentElement.h"
-#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/ShadowRoot.h"
#include "nsIAnonymousContentCreator.h"
#include "nsIFrame.h"
#include "nsCSSAnonBoxes.h"
+#include "nsDocument.h"
namespace mozilla {
namespace dom {
-class MatchedNodes {
-public:
- explicit MatchedNodes(HTMLContentElement* aInsertionPoint)
- : mIsContentElement(true), mContentElement(aInsertionPoint) {}
-
- explicit MatchedNodes(XBLChildrenElement* aInsertionPoint)
- : mIsContentElement(false), mChildrenElement(aInsertionPoint) {}
-
- uint32_t Length() const
- {
- return mIsContentElement ? mContentElement->MatchedNodes().Length()
- : mChildrenElement->InsertedChildrenLength();
- }
-
- nsIContent* operator[](int32_t aIndex) const
- {
- return mIsContentElement ? mContentElement->MatchedNodes()[aIndex]
- : mChildrenElement->InsertedChild(aIndex);
- }
-
- bool IsEmpty() const
- {
- return mIsContentElement ? mContentElement->MatchedNodes().IsEmpty()
- : !mChildrenElement->HasInsertedChildren();
- }
-protected:
- bool mIsContentElement;
- union {
- HTMLContentElement* mContentElement;
- XBLChildrenElement* mChildrenElement;
- };
-};
-
-static inline MatchedNodes
-GetMatchedNodesForPoint(nsIContent* aContent)
+ExplicitChildIterator::ExplicitChildIterator(const nsIContent* aParent,
+ bool aStartAtBeginning)
+ : mParent(aParent),
+ mChild(nullptr),
+ mDefaultChild(nullptr),
+ mIsFirst(aStartAtBeginning),
+ mIndexInInserted(0)
{
- if (aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
- // XBL case
- return MatchedNodes(static_cast<XBLChildrenElement*>(aContent));
- }
-
- // Web components case
- MOZ_ASSERT(aContent->IsHTMLElement(nsGkAtoms::content));
- return MatchedNodes(HTMLContentElement::FromContent(aContent));
+ mParentAsSlot = nsDocument::IsWebComponentsEnabled(mParent) ?
+ HTMLSlotElement::FromContent(mParent) : nullptr;
}
nsIContent*
@@ -69,30 +35,29 @@ ExplicitChildIterator::GetNextChild()
// If we're already in the inserted-children array, look there first
if (mIndexInInserted) {
MOZ_ASSERT(mChild);
- MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
MOZ_ASSERT(!mDefaultChild);
- MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
- if (mIndexInInserted < assignedChildren.Length()) {
- return assignedChildren[mIndexInInserted++];
- }
- mIndexInInserted = 0;
- mChild = mChild->GetNextSibling();
- } else if (mShadowIterator) {
- // If we're inside of a <shadow> element, look through the
- // explicit children of the projected ShadowRoot via
- // the mShadowIterator.
- nsIContent* nextChild = mShadowIterator->GetNextChild();
- if (nextChild) {
- return nextChild;
+ if (mParentAsSlot) {
+ const nsTArray<RefPtr<nsINode>>& assignedNodes =
+ mParentAsSlot->AssignedNodes();
+
+ mChild = (mIndexInInserted < assignedNodes.Length()) ?
+ assignedNodes[mIndexInInserted++]->AsContent() : nullptr;
+ return mChild;
}
- mShadowIterator = nullptr;
+ MOZ_ASSERT(mChild->IsActiveChildrenElement());
+ auto* childrenElement =
+ static_cast<XBLChildrenElement*>(mChild);
+ if (mIndexInInserted < childrenElement->InsertedChildrenLength()) {
+ return childrenElement->InsertedChild(mIndexInInserted++);
+ }
+ mIndexInInserted = 0;
mChild = mChild->GetNextSibling();
} else if (mDefaultChild) {
// If we're already in default content, check if there are more nodes there
MOZ_ASSERT(mChild);
- MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
+ MOZ_ASSERT(mChild->IsActiveChildrenElement());
mDefaultChild = mDefaultChild->GetNextSibling();
if (mDefaultChild) {
@@ -101,6 +66,19 @@ ExplicitChildIterator::GetNextChild()
mChild = mChild->GetNextSibling();
} else if (mIsFirst) { // at the beginning of the child list
+ // For slot parent, iterate over assigned nodes if not empty, otherwise
+ // fall through and iterate over direct children (fallback content).
+ if (mParentAsSlot) {
+ const nsTArray<RefPtr<nsINode>>& assignedNodes =
+ mParentAsSlot->AssignedNodes();
+ if (!assignedNodes.IsEmpty()) {
+ mIndexInInserted = 1;
+ mChild = assignedNodes[0]->AsContent();
+ mIsFirst = false;
+ return mChild;
+ }
+ }
+
mChild = mParent->GetFirstChild();
mIsFirst = false;
} else if (mChild) { // in the middle of the child list
@@ -110,31 +88,16 @@ ExplicitChildIterator::GetNextChild()
// Iterate until we find a non-insertion point, or an insertion point with
// content.
while (mChild) {
- // If the current child being iterated is a shadow insertion point then
- // the iterator needs to go into the projected ShadowRoot.
- if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
- // Look for the next child in the projected ShadowRoot for the <shadow>
- // element.
- HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
- ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
- if (projectedShadow) {
- mShadowIterator = new ExplicitChildIterator(projectedShadow);
- nsIContent* nextChild = mShadowIterator->GetNextChild();
- if (nextChild) {
- return nextChild;
- }
- mShadowIterator = nullptr;
- }
- mChild = mChild->GetNextSibling();
- } else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
+ if (mChild->IsActiveChildrenElement()) {
// If the current child being iterated is a content insertion point
// then the iterator needs to return the nodes distributed into
// the content insertion point.
- MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
- if (!assignedChildren.IsEmpty()) {
+ auto* childrenElement =
+ static_cast<XBLChildrenElement*>(mChild);
+ if (childrenElement->HasInsertedChildren()) {
// Iterate through elements projected on insertion point.
mIndexInInserted = 1;
- return assignedChildren[0];
+ return childrenElement->InsertedChild(0);
}
// Insertion points inside fallback/default content
@@ -192,19 +155,17 @@ FlattenedChildIterator::Init(bool aIgnoreXBL)
}
bool
-ExplicitChildIterator::Seek(nsIContent* aChildToFind)
+ExplicitChildIterator::Seek(const nsIContent* aChildToFind)
{
if (aChildToFind->GetParent() == mParent &&
!aChildToFind->IsRootOfAnonymousSubtree()) {
// Fast path: just point ourselves to aChildToFind, which is a
// normal DOM child of ours.
- MOZ_ASSERT(!ShadowRoot::IsShadowInsertionPoint(aChildToFind));
- MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(aChildToFind));
- mChild = aChildToFind;
+ mChild = const_cast<nsIContent*>(aChildToFind);
mIndexInInserted = 0;
- mShadowIterator = nullptr;
mDefaultChild = nullptr;
mIsFirst = false;
+ MOZ_ASSERT(!mChild->IsActiveChildrenElement());
return true;
}
@@ -220,12 +181,18 @@ ExplicitChildIterator::Get() const
{
MOZ_ASSERT(!mIsFirst);
+ // When mParentAsSlot is set, mChild is always set to the current child. It
+ // does not matter whether mChild is an assigned node or a fallback content.
+ if (mParentAsSlot) {
+ return mChild;
+ }
+
if (mIndexInInserted) {
- MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
- return assignedChildren[mIndexInInserted - 1];
- } else if (mShadowIterator) {
- return mShadowIterator->Get();
+ MOZ_ASSERT(mChild->IsActiveChildrenElement());
+ auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
+ return childrenElement->InsertedChild(mIndexInInserted - 1);
}
+
return mDefaultChild ? mDefaultChild : mChild;
}
@@ -234,20 +201,28 @@ ExplicitChildIterator::GetPreviousChild()
{
// If we're already in the inserted-children array, look there first
if (mIndexInInserted) {
+
+ if (mParentAsSlot) {
+ const nsTArray<RefPtr<nsINode>>& assignedNodes =
+ mParentAsSlot->AssignedNodes();
+
+ mChild = (--mIndexInInserted) ?
+ assignedNodes[mIndexInInserted - 1]->AsContent() : nullptr;
+
+ if (!mChild) {
+ mIsFirst = true;
+ }
+ return mChild;
+ }
+
// NB: mIndexInInserted points one past the last returned child so we need
// to look *two* indices back in order to return the previous child.
- MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
+ MOZ_ASSERT(mChild->IsActiveChildrenElement());
+ auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
if (--mIndexInInserted) {
- return assignedChildren[mIndexInInserted - 1];
+ return childrenElement->InsertedChild(mIndexInInserted - 1);
}
mChild = mChild->GetPreviousSibling();
- } else if (mShadowIterator) {
- nsIContent* previousChild = mShadowIterator->GetPreviousChild();
- if (previousChild) {
- return previousChild;
- }
- mShadowIterator = nullptr;
- mChild = mChild->GetPreviousSibling();
} else if (mDefaultChild) {
// If we're already in default content, check if there are more nodes there
mDefaultChild = mDefaultChild->GetPreviousSibling();
@@ -261,35 +236,32 @@ ExplicitChildIterator::GetPreviousChild()
} else if (mChild) { // in the middle of the child list
mChild = mChild->GetPreviousSibling();
} else { // at the end of the child list
+ // For slot parent, iterate over assigned nodes if not empty, otherwise
+ // fall through and iterate over direct children (fallback content).
+ if (mParentAsSlot) {
+ const nsTArray<RefPtr<nsINode>>& assignedNodes =
+ mParentAsSlot->AssignedNodes();
+ if (!assignedNodes.IsEmpty()) {
+ mIndexInInserted = assignedNodes.Length();
+ mChild = assignedNodes[mIndexInInserted - 1]->AsContent();
+ return mChild;
+ }
+ }
+
mChild = mParent->GetLastChild();
}
// Iterate until we find a non-insertion point, or an insertion point with
// content.
while (mChild) {
- if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
- // If the current child being iterated is a shadow insertion point then
- // the iterator needs to go into the projected ShadowRoot.
- HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
- ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
- if (projectedShadow) {
- // Create a ExplicitChildIterator that begins iterating from the end.
- mShadowIterator = new ExplicitChildIterator(projectedShadow, false);
- nsIContent* previousChild = mShadowIterator->GetPreviousChild();
- if (previousChild) {
- return previousChild;
- }
- mShadowIterator = nullptr;
- }
- mChild = mChild->GetPreviousSibling();
- } else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
+ if (mChild->IsActiveChildrenElement()) {
// If the current child being iterated is a content insertion point
// then the iterator needs to return the nodes distributed into
// the content insertion point.
- MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
- if (!assignedChildren.IsEmpty()) {
- mIndexInInserted = assignedChildren.Length();
- return assignedChildren[mIndexInInserted - 1];
+ auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
+ if (childrenElement->HasInsertedChildren()) {
+ mIndexInInserted = childrenElement->InsertedChildrenLength();
+ return childrenElement->InsertedChild(mIndexInInserted - 1);
}
mDefaultChild = mChild->GetLastChild();
@@ -317,11 +289,9 @@ AllChildrenIterator::Get() const
{
switch (mPhase) {
case eAtBeforeKid: {
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- MOZ_ASSERT(frame, "No frame at eAtBeforeKid phase");
- nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
- MOZ_ASSERT(beforeFrame, "No content before frame at eAtBeforeKid phase");
- return beforeFrame->GetContent();
+ Element* before = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
+ MOZ_ASSERT(before, "No content before frame at eAtBeforeKid phase");
+ return before;
}
case eAtExplicitKids:
@@ -331,11 +301,9 @@ AllChildrenIterator::Get() const
return mAnonKids[mAnonKidsIdx];
case eAtAfterKid: {
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- MOZ_ASSERT(frame, "No frame at eAtAfterKid phase");
- nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
- MOZ_ASSERT(afterFrame, "No content before frame at eAtBeforeKid phase");
- return afterFrame->GetContent();
+ Element* after = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
+ MOZ_ASSERT(after, "No content after frame at eAtAfterKid phase");
+ return after;
}
default:
@@ -345,19 +313,14 @@ AllChildrenIterator::Get() const
bool
-AllChildrenIterator::Seek(nsIContent* aChildToFind)
+AllChildrenIterator::Seek(const nsIContent* aChildToFind)
{
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
mPhase = eAtExplicitKids;
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- if (frame) {
- nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
- if (beforeFrame) {
- if (beforeFrame->GetContent() == aChildToFind) {
- mPhase = eAtBeforeKid;
- return true;
- }
- }
+ Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
+ if (beforePseudo && beforePseudo == aChildToFind) {
+ mPhase = eAtBeforeKid;
+ return true;
}
}
@@ -383,12 +346,10 @@ AllChildrenIterator::AppendNativeAnonymousChildren()
// The root scroll frame is not the primary frame of the root element.
// Detect and handle this case.
- if (mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
- nsIPresShell* presShell = mOriginalContent->OwnerDoc()->GetShell();
- nsIFrame* scrollFrame = presShell ? presShell->GetRootScrollFrame() : nullptr;
- if (scrollFrame) {
- AppendNativeAnonymousChildrenFromFrame(scrollFrame);
- }
+ if (!(mFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) &&
+ mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
+ nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
+ mOriginalContent->OwnerDoc(), mAnonKids);
}
}
@@ -406,13 +367,10 @@ AllChildrenIterator::GetNextChild()
{
if (mPhase == eAtBegin) {
mPhase = eAtExplicitKids;
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- if (frame) {
- nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
- if (beforeFrame) {
- mPhase = eAtBeforeKid;
- return beforeFrame->GetContent();
- }
+ Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
+ if (beforeContent) {
+ mPhase = eAtBeforeKid;
+ return beforeContent;
}
}
@@ -448,13 +406,10 @@ AllChildrenIterator::GetNextChild()
return mAnonKids[mAnonKidsIdx];
}
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- if (frame) {
- nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
- if (afterFrame) {
- mPhase = eAtAfterKid;
- return afterFrame->GetContent();
- }
+ Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
+ if (afterContent) {
+ mPhase = eAtAfterKid;
+ return afterContent;
}
}
@@ -468,13 +423,10 @@ AllChildrenIterator::GetPreviousChild()
if (mPhase == eAtEnd) {
MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length());
mPhase = eAtAnonKids;
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- if (frame) {
- nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
- if (afterFrame) {
- mPhase = eAtAfterKid;
- return afterFrame->GetContent();
- }
+ Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
+ if (afterContent) {
+ mPhase = eAtAfterKid;
+ return afterContent;
}
}
@@ -503,13 +455,10 @@ AllChildrenIterator::GetPreviousChild()
return kid;
}
- nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
- if (frame) {
- nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
- if (beforeFrame) {
- mPhase = eAtBeforeKid;
- return beforeFrame->GetContent();
- }
+ Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
+ if (beforeContent) {
+ mPhase = eAtBeforeKid;
+ return beforeContent;
}
}
@@ -585,12 +534,6 @@ StyleChildrenIterator::IsNeeded(const Element* aElement)
return true;
}
- // The root element has a scroll frame that is not the primary frame, so we
- // need to do special checking for that case.
- if (aElement == aElement->OwnerDoc()->GetRootElement()) {
- return true;
- }
-
return false;
}
diff --git a/dom/base/ChildIterator.h b/dom/base/ChildIterator.h
index ffff8dce5..78acdc146 100644
--- a/dom/base/ChildIterator.h
+++ b/dom/base/ChildIterator.h
@@ -36,27 +36,20 @@ class ExplicitChildIterator
{
public:
explicit ExplicitChildIterator(const nsIContent* aParent,
- bool aStartAtBeginning = true)
- : mParent(aParent),
- mChild(nullptr),
- mDefaultChild(nullptr),
- mIndexInInserted(0),
- mIsFirst(aStartAtBeginning)
- {
- }
+ bool aStartAtBeginning = true);
ExplicitChildIterator(const ExplicitChildIterator& aOther)
- : mParent(aOther.mParent), mChild(aOther.mChild),
+ : mParent(aOther.mParent),
+ mParentAsSlot(aOther.mParentAsSlot),
+ mChild(aOther.mChild),
mDefaultChild(aOther.mDefaultChild),
- mShadowIterator(aOther.mShadowIterator ?
- new ExplicitChildIterator(*aOther.mShadowIterator) :
- nullptr),
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
ExplicitChildIterator(ExplicitChildIterator&& aOther)
- : mParent(aOther.mParent), mChild(aOther.mChild),
+ : mParent(aOther.mParent),
+ mParentAsSlot(aOther.mParentAsSlot),
+ mChild(aOther.mChild),
mDefaultChild(aOther.mDefaultChild),
- mShadowIterator(Move(aOther.mShadowIterator)),
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
nsIContent* GetNextChild();
@@ -65,13 +58,13 @@ public:
// found. This version can take shortcuts that the two-argument version
// can't, so can be faster (and in fact can be O(1) instead of O(N) in many
// cases).
- bool Seek(nsIContent* aChildToFind);
+ bool Seek(const nsIContent* aChildToFind);
// Looks for aChildToFind respecting insertion points until aChildToFind is found.
// or aBound is found. If aBound is nullptr then the seek is unbounded. Returns
// whether aChildToFind was found as an explicit child prior to encountering
// aBound.
- bool Seek(nsIContent* aChildToFind, nsIContent* aBound)
+ bool Seek(const nsIContent* aChildToFind, nsIContent* aBound)
{
// It would be nice to assert that we find aChildToFind, but bz thinks that
// we might not find aChildToFind when called from ContentInserted
@@ -102,6 +95,10 @@ protected:
// the <xbl:content> element for the binding.
const nsIContent* mParent;
+ // If parent is a slot element, this points to the parent as HTMLSlotElement,
+ // otherwise, it's null.
+ const HTMLSlotElement* mParentAsSlot;
+
// The current child. When we encounter an insertion point,
// mChild remains as the insertion point whose content we're iterating (and
// our state is controled by mDefaultChild or mIndexInInserted depending on
@@ -114,11 +111,6 @@ protected:
// to null, we continue iterating at mChild's next sibling.
nsIContent* mDefaultChild;
- // If non-null, this points to an iterator of the explicit children of
- // the ShadowRoot projected by the current shadow element that we're
- // iterating.
- nsAutoPtr<ExplicitChildIterator> mShadowIterator;
-
// If not zero, we're iterating inserted children for an insertion point. This
// is an index into mChild's inserted children array (mChild must be an
// nsXBLChildrenElement). The index is one past the "current" child (as
@@ -139,19 +131,29 @@ class FlattenedChildIterator : public ExplicitChildIterator
public:
explicit FlattenedChildIterator(const nsIContent* aParent,
bool aStartAtBeginning = true)
- : ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
+ : ExplicitChildIterator(aParent, aStartAtBeginning)
+ , mXBLInvolved(false)
+ , mOriginalContent(aParent)
{
Init(false);
}
FlattenedChildIterator(FlattenedChildIterator&& aOther)
- : ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {}
+ : ExplicitChildIterator(Move(aOther))
+ , mXBLInvolved(aOther.mXBLInvolved)
+ , mOriginalContent(aOther.mOriginalContent)
+ {}
FlattenedChildIterator(const FlattenedChildIterator& aOther)
- : ExplicitChildIterator(aOther), mXBLInvolved(aOther.mXBLInvolved) {}
+ : ExplicitChildIterator(aOther)
+ , mXBLInvolved(aOther.mXBLInvolved)
+ , mOriginalContent(aOther.mOriginalContent)
+ {}
bool XBLInvolved() { return mXBLInvolved; }
+ const nsIContent* Parent() const { return mOriginalContent; }
+
protected:
/**
* This constructor is a hack to help AllChildrenIterator which sometimes
@@ -159,7 +161,9 @@ protected:
*/
FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
bool aStartAtBeginning = true)
- : ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
+ : ExplicitChildIterator(aParent, aStartAtBeginning)
+ , mXBLInvolved(false)
+ , mOriginalContent(aParent)
{
bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
Init(ignoreXBL);
@@ -170,6 +174,8 @@ protected:
// For certain optimizations, nsCSSFrameConstructor needs to know if the
// child list of the element that we're iterating matches its .childNodes.
bool mXBLInvolved;
+
+ const nsIContent* mOriginalContent;
};
/**
@@ -187,12 +193,11 @@ public:
AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
bool aStartAtBeginning = true) :
FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
- mOriginalContent(aNode), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
+ mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
AllChildrenIterator(AllChildrenIterator&& aOther)
: FlattenedChildIterator(Move(aOther)),
- mOriginalContent(aOther.mOriginalContent),
mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
mFlags(aOther.mFlags), mPhase(aOther.mPhase)
#ifdef DEBUG
@@ -211,11 +216,10 @@ public:
// Seeks the given node in children of a parent element, starting from
// the current iterator's position, and sets the iterator at the given child
// node if it was found.
- bool Seek(nsIContent* aChildToFind);
+ bool Seek(const nsIContent* aChildToFind);
nsIContent* GetNextChild();
nsIContent* GetPreviousChild();
- const nsIContent* Parent() const { return mOriginalContent; }
enum IteratorPhase
{
@@ -233,8 +237,6 @@ private:
void AppendNativeAnonymousChildren();
void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame);
- const nsIContent* mOriginalContent;
-
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
// in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
// eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
@@ -256,10 +258,11 @@ private:
/**
* StyleChildrenIterator traverses the children of the element from the
* perspective of the style system, particularly the children we need to traverse
- * during restyle. This is identical to AllChildrenIterator with eAllChildren,
- * _except_ that we detect and skip any native anonymous children that are used
- * to implement pseudo-elements (since the style system needs to cascade those
- * using different algorithms).
+ * during restyle. This is identical to AllChildrenIterator with
+ * (eAllChildren | eSkipDocumentLevelNativeAnonymousContent), _except_ that we
+ * detect and skip any native anonymous children that are used to implement
+ * pseudo-elements (since the style system needs to cascade those using
+ * different algorithms).
*
* Note: it assumes that no mutation of the DOM or frame tree takes place during
* iteration, and will break horribly if that is not true.
@@ -267,7 +270,9 @@ private:
class StyleChildrenIterator : private AllChildrenIterator {
public:
explicit StyleChildrenIterator(const nsIContent* aContent)
- : AllChildrenIterator(aContent, nsIContent::eAllChildren)
+ : AllChildrenIterator(aContent,
+ nsIContent::eAllChildren |
+ nsIContent::eSkipDocumentLevelNativeAnonymousContent)
{
MOZ_COUNT_CTOR(StyleChildrenIterator);
}
diff --git a/dom/base/ChromeUtils.cpp b/dom/base/ChromeUtils.cpp
index 3cde261f0..b25f0b76b 100644
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -7,6 +7,7 @@
#include "mozilla/Base64.h"
#include "mozilla/BasePrincipal.h"
+#include "jsfriendapi.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/ChromeUtils.h b/dom/base/ChromeUtils.h
index 051217c84..58a67b4f2 100644
--- a/dom/base/ChromeUtils.h
+++ b/dom/base/ChromeUtils.h
@@ -10,6 +10,7 @@
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ChromeUtilsBinding.h"
#include "mozilla/dom/ThreadSafeChromeUtilsBinding.h"
+#include "mozilla/dom/UnionTypes.h"
#include "mozilla/ErrorResult.h"
namespace mozilla {
diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp
index 99452df65..2bf969d38 100644
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -11,7 +11,9 @@
#include "mozilla/dom/HTMLElementBinding.h"
#include "mozilla/dom/WebComponentsBinding.h"
#include "mozilla/dom/DocGroup.h"
-#include "nsIParserService.h"
+#include "mozilla/dom/Promise.h"
+#include "nsContentUtils.h"
+#include "nsHTMLTags.h"
#include "jsapi.h"
namespace mozilla {
@@ -291,7 +293,6 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy
nsTArray<nsWeakPtr>* unresolved = mCandidatesMap.LookupOrAdd(typeName);
nsWeakPtr* elem = unresolved->AppendElement();
*elem = do_GetWeakReference(aElement);
- aElement->AddStates(NS_EVENT_STATE_UNRESOLVED);
return;
}
@@ -415,19 +416,6 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
}
void
-CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom,
- JS::MutableHandle<JSObject*> aPrototype)
-{
- mozilla::dom::CustomElementDefinition* definition =
- mCustomDefinitions.GetWeak(aAtom);
- if (definition) {
- aPrototype.set(definition->mPrototype);
- } else {
- aPrototype.set(nullptr);
- }
-}
-
-void
CustomElementRegistry::UpgradeCandidates(nsIAtom* aKey,
CustomElementDefinition* aDefinition,
ErrorResult& aRv)
@@ -466,6 +454,12 @@ nsISupports* CustomElementRegistry::GetParentObject() const
return mWindow;
}
+DocGroup*
+CustomElementRegistry::GetDocGroup() const
+{
+ return mWindow ? mWindow->GetDocGroup() : nullptr;
+}
+
static const char* kLifeCycleCallbackNames[] = {
"connectedCallback",
"disconnectedCallback",
@@ -588,14 +582,8 @@ CustomElementRegistry::Define(const nsAString& aName,
return;
}
- nsIParserService* ps = nsContentUtils::GetParserService();
- if (!ps) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
-
// bgsound and multicol are unknown html element.
- int32_t tag = ps->HTMLCaseSensitiveAtomTagToId(extendsAtom);
+ int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(extendsAtom);
if (tag == eHTMLTag_userdefined ||
tag == eHTMLTag_bgsound ||
tag == eHTMLTag_multicol) {
@@ -630,9 +618,9 @@ CustomElementRegistry::Define(const nsAString& aName,
*/
JSAutoCompartment ac(cx, constructor);
JS::Rooted<JS::Value> prototypev(cx);
- // The .prototype on the constructor passed from document.registerElement
- // is the "expando" of a wrapper. So we should get it from wrapper instead
- // instead of underlying object.
+ // The .prototype on the constructor passed could be an "expando" of a
+ // wrapper. So we should get it from wrapper instead of the underlying
+ // object.
if (!JS_GetProperty(cx, constructor, "prototype", &prototypev)) {
aRv.StealExceptionFromJSContext(cx);
return;
@@ -878,8 +866,6 @@ CustomElementRegistry::Upgrade(Element* aElement,
CustomElementDefinition* aDefinition,
ErrorResult& aRv)
{
- aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
-
RefPtr<CustomElementData> data = aElement->GetCustomElementData();
MOZ_ASSERT(data, "CustomElementData should exist");
diff --git a/dom/base/CustomElementRegistry.h b/dom/base/CustomElementRegistry.h
index c416e5043..eacf568c9 100644
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -27,6 +27,7 @@ struct CustomElementData;
struct ElementDefinitionOptions;
class CallbackFunction;
class CustomElementReaction;
+class DocGroup;
class Function;
class Promise;
@@ -423,9 +424,6 @@ public:
LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
CustomElementDefinition* aDefinition);
- void GetCustomPrototype(nsIAtom* aAtom,
- JS::MutableHandle<JSObject*> aPrototype);
-
/**
* Upgrade an element.
* https://html.spec.whatwg.org/multipage/scripting.html#upgrades
@@ -434,8 +432,7 @@ public:
/**
* Registers an unresolved custom element that is a candidate for
- * upgrade when the definition is registered via registerElement.
- * |aTypeName| is the name of the custom element type, if it is not
+ * upgrade. |aTypeName| is the name of the custom element type, if it is not
* provided, then element name is used. |aTypeName| should be provided
* when registering a custom element that extends an existing
* element. e.g. <button is="x-button">.
@@ -472,8 +469,8 @@ private:
js::SystemAllocPolicy> ConstructorMap;
// Hashtable for custom element definitions in web components.
- // Custom prototypes are stored in the compartment where
- // registerElement was called.
+ // Custom prototypes are stored in the compartment where definition was
+ // defined.
DefinitionMap mCustomDefinitions;
// Hashtable for looking up definitions by using constructor as key.
@@ -517,6 +514,8 @@ private:
public:
nsISupports* GetParentObject() const;
+ DocGroup* GetDocGroup() const;
+
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void Define(const nsAString& aName, Function& aFunctionConstructor,
diff --git a/dom/base/DirectionalityUtils.cpp b/dom/base/DirectionalityUtils.cpp
index d9a6c4524..632abb2c8 100644
--- a/dom/base/DirectionalityUtils.cpp
+++ b/dom/base/DirectionalityUtils.cpp
@@ -728,7 +728,7 @@ WalkDescendantsResetAutoDirection(Element* aElement)
{
nsIContent* child = aElement->GetFirstChild();
while (child) {
- if (child->HasDirAuto()) {
+ if (child->IsElement() && child->AsElement()->HasDirAuto()) {
child = child->GetNextNonChildNode(aElement);
continue;
}
@@ -791,7 +791,7 @@ WalkDescendantsClearAncestorDirAuto(Element* aElement)
{
nsIContent* child = aElement->GetFirstChild();
while (child) {
- if (child->HasDirAuto()) {
+ if (child->IsElement() && child->AsElement()->HasDirAuto()) {
child = child->GetNextNonChildNode(aElement);
continue;
}
diff --git a/dom/base/DocGroup.cpp b/dom/base/DocGroup.cpp
index 30c058f0c..5d7db1fb6 100644
--- a/dom/base/DocGroup.cpp
+++ b/dom/base/DocGroup.cpp
@@ -1,3 +1,7 @@
+/* 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/DocGroup.h"
#include "mozilla/dom/TabGroup.h"
#include "mozilla/Telemetry.h"
@@ -6,10 +10,14 @@
#include "mozilla/StaticPtr.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsIDocShell.h"
+#include "nsDOMMutationObserver.h"
+#include "nsNetCID.h"
namespace mozilla {
namespace dom {
+AutoTArray<RefPtr<DocGroup>, 2>* DocGroup::sPendingDocGroups = nullptr;
+
/* static */ void
DocGroup::GetKey(nsIPrincipal* aPrincipal, nsACString& aKey)
{
@@ -54,5 +62,23 @@ DocGroup::~DocGroup()
NS_IMPL_ISUPPORTS(DocGroup, nsISupports)
+void
+DocGroup::SignalSlotChange(const HTMLSlotElement* aSlot)
+{
+ if (mSignalSlotList.Contains(aSlot)) {
+ return;
+ }
+
+ mSignalSlotList.AppendElement(const_cast<HTMLSlotElement*>(aSlot));
+
+ if (!sPendingDocGroups) {
+ // Queue a mutation observer compound microtask.
+ nsDOMMutationObserver::QueueMutationObserverMicroTask();
+ sPendingDocGroups = new AutoTArray<RefPtr<DocGroup>, 2>;
+ }
+
+ sPendingDocGroups->AppendElement(this);
+}
+
}
}
diff --git a/dom/base/DocGroup.h b/dom/base/DocGroup.h
index 5b8f627cc..7a5a99dce 100644
--- a/dom/base/DocGroup.h
+++ b/dom/base/DocGroup.h
@@ -15,6 +15,7 @@
#include "mozilla/RefPtr.h"
#include "mozilla/dom/CustomElementRegistry.h"
+#include "mozilla/dom/HTMLSlotElement.h"
namespace mozilla {
namespace dom {
@@ -73,6 +74,23 @@ public:
return mDocuments.end();
}
+ // Append aSlot to the list of signal slot list, if it's not in it already
+ // list, and queue a mutation observer microtask.
+ void SignalSlotChange(const mozilla::dom::HTMLSlotElement* aSlot);
+
+ const nsTArray<RefPtr<HTMLSlotElement>>& SignalSlotList() const
+ {
+ return mSignalSlotList;
+ }
+
+ void ClearSignalSlotList()
+ {
+ mSignalSlotList.Clear();
+ }
+
+ // List of DocGroups that has non-empty signal slot list.
+ static AutoTArray<RefPtr<DocGroup>, 2>* sPendingDocGroups;
+
private:
DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
~DocGroup();
@@ -81,6 +99,7 @@ private:
RefPtr<TabGroup> mTabGroup;
nsTArray<nsIDocument*> mDocuments;
RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
+ nsTArray<RefPtr<HTMLSlotElement>> mSignalSlotList;
};
} // namespace dom
diff --git a/dom/base/DocumentFragment.cpp b/dom/base/DocumentFragment.cpp
index 3eb2a0790..3e1e2c81b 100644
--- a/dom/base/DocumentFragment.cpp
+++ b/dom/base/DocumentFragment.cpp
@@ -125,6 +125,8 @@ DocumentFragment::Constructor(const GlobalObject& aGlobal,
return window->GetDoc()->CreateDocumentFragment();
}
+NS_IMPL_CYCLE_COLLECTION_INHERITED(DocumentFragment, FragmentOrElement, mHost)
+
// QueryInterface implementation for DocumentFragment
NS_INTERFACE_MAP_BEGIN(DocumentFragment)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
diff --git a/dom/base/DocumentFragment.h b/dom/base/DocumentFragment.h
index 68a7f0ff4..ccc233ff1 100644
--- a/dom/base/DocumentFragment.h
+++ b/dom/base/DocumentFragment.h
@@ -43,6 +43,7 @@ public:
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocumentFragment, FragmentOrElement)
// interface nsIDOMNode
NS_FORWARD_NSIDOMNODE_TO_NSINODE
@@ -121,15 +122,9 @@ public:
return nullptr;
}
- nsIContent* GetHost() const
- {
- return mHost;
- }
+ Element* GetHost() const { return mHost; }
- void SetHost(nsIContent* aHost)
- {
- mHost = aHost;
- }
+ void SetHost(Element* aHost) { mHost = aHost; }
static already_AddRefed<DocumentFragment>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
@@ -145,7 +140,7 @@ protected:
}
nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
- nsIContent* mHost; // Weak
+ nsCOMPtr<Element> mHost;
};
} // namespace dom
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp
index c8467e036..8e9225a64 100644
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -166,8 +166,7 @@ nsIContent::DoGetID() const
const nsAttrValue*
Element::DoGetClasses() const
{
- MOZ_ASSERT(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call");
-
+ MOZ_ASSERT(MayHaveClass(), "Unexpected call");
if (IsSVGElement()) {
const nsAttrValue* animClass =
static_cast<const nsSVGElement*>(this)->GetAnimatedClassName();
@@ -470,50 +469,11 @@ Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
JSObject*
Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
- JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
- JS::Rooted<JSObject*> customProto(aCx);
-
- if (!givenProto) {
- // Custom element prototype swizzling.
- CustomElementData* data = GetCustomElementData();
- if (data) {
- // If this is a registered custom element then fix the prototype.
- nsContentUtils::GetCustomPrototype(OwnerDoc(), NodeInfo()->NamespaceID(),
- data->GetCustomElementType(), &customProto);
- if (customProto &&
- NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(customProto))) {
- // The custom element prototype could be in different compartment.
- if (!JS_WrapObject(aCx, &customProto)) {
- return nullptr;
- }
- // Just go ahead and create with the right proto up front. Set
- // customProto to null to flag that we don't need to do any post-facto
- // proto fixups here.
- givenProto = customProto;
- customProto = nullptr;
- }
- }
- }
-
- JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, givenProto));
+ JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, aGivenProto));
if (!obj) {
return nullptr;
}
- if (customProto) {
- // We want to set the custom prototype in the compartment where it was
- // registered. In the case that |obj| and |prototype| are in different
- // compartments, this will set the prototype on the |obj|'s wrapper and
- // thus only visible in the wrapper's compartment, since we know obj's
- // principal does not subsume customProto's in this case.
- JSAutoCompartment ac(aCx, customProto);
- JS::Rooted<JSObject*> wrappedObj(aCx, obj);
- if (!JS_WrapObject(aCx, &wrappedObj) ||
- !JS_SetPrototype(aCx, wrappedObj, customProto)) {
- return nullptr;
- }
- }
-
nsIDocument* doc;
if (HasFlag(NODE_FORCE_XBL_BINDINGS)) {
doc = OwnerDoc();
@@ -1093,9 +1053,102 @@ Element::RemoveFromIdTable()
}
}
+void
+Element::SetSlot(const nsAString& aName, ErrorResult& aError)
+{
+ aError = SetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName, true);
+}
+
+void
+Element::GetSlot(nsAString& aName)
+{
+ GetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName);
+}
+
+// https://dom.spec.whatwg.org/#dom-element-shadowroot
+ShadowRoot*
+Element::GetShadowRootByMode() const
+{
+ /**
+ * 1. Let shadow be context object’s shadow root.
+ * 2. If shadow is null or its mode is "closed", then return null.
+ */
+ ShadowRoot* shadowRoot = GetShadowRoot();
+ if (!shadowRoot || shadowRoot->IsClosed()) {
+ return nullptr;
+ }
+
+ /**
+ * 3. Return shadow.
+ */
+ return shadowRoot;
+}
+
+// https://dom.spec.whatwg.org/#dom-element-attachshadow
+already_AddRefed<ShadowRoot>
+Element::AttachShadow(const ShadowRootInit& aInit, ErrorResult& aError)
+{
+ /**
+ * 1. If context object’s namespace is not the HTML namespace,
+ * then throw a "NotSupportedError" DOMException.
+ */
+ if (!IsHTMLElement()) {
+ aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+ return nullptr;
+ }
+
+ /**
+ * 2. If context object’s local name is not
+ * a valid custom element name, "article", "aside", "blockquote",
+ * "body", "div", "footer", "h1", "h2", "h3", "h4", "h5", "h6",
+ * "header", "main" "nav", "p", "section", or "span",
+ * then throw a "NotSupportedError" DOMException.
+ */
+ nsIAtom* nameAtom = NodeInfo()->NameAtom();
+ if (!(nsContentUtils::IsCustomElementName(nameAtom) ||
+ nameAtom == nsGkAtoms::article ||
+ nameAtom == nsGkAtoms::aside ||
+ nameAtom == nsGkAtoms::blockquote ||
+ nameAtom == nsGkAtoms::body ||
+ nameAtom == nsGkAtoms::div ||
+ nameAtom == nsGkAtoms::footer ||
+ nameAtom == nsGkAtoms::h1 ||
+ nameAtom == nsGkAtoms::h2 ||
+ nameAtom == nsGkAtoms::h3 ||
+ nameAtom == nsGkAtoms::h4 ||
+ nameAtom == nsGkAtoms::h5 ||
+ nameAtom == nsGkAtoms::h6 ||
+ nameAtom == nsGkAtoms::header ||
+ nameAtom == nsGkAtoms::main ||
+ nameAtom == nsGkAtoms::nav ||
+ nameAtom == nsGkAtoms::p ||
+ nameAtom == nsGkAtoms::section ||
+ nameAtom == nsGkAtoms::span)) {
+ aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+ return nullptr;
+ }
+
+ return AttachShadowInternal(aInit.mMode == ShadowRootMode::Closed, aError);
+}
+
already_AddRefed<ShadowRoot>
Element::CreateShadowRoot(ErrorResult& aError)
{
+ return AttachShadowInternal(false, aError);
+}
+
+already_AddRefed<ShadowRoot>
+Element::AttachShadowInternal(bool aClosed, ErrorResult& aError)
+{
+ /**
+ * 3. If context object is a shadow host, then throw
+ * an "InvalidStateError" DOMException.
+ */
+ if (GetShadowRoot()) {
+ aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return nullptr;
+ }
+
nsAutoScriptBlocker scriptBlocker;
RefPtr<mozilla::dom::NodeInfo> nodeInfo;
@@ -1113,12 +1166,9 @@ Element::CreateShadowRoot(ErrorResult& aError)
return nullptr;
}
- nsIDocument* doc = GetComposedDoc();
- nsIContent* destroyedFramesFor = nullptr;
- if (doc) {
- nsIPresShell* shell = doc->GetShell();
- if (shell) {
- shell->DestroyFramesFor(this, &destroyedFramesFor);
+ if (nsIDocument* doc = GetComposedDoc()) {
+ if (nsIPresShell* shell = doc->GetShell()) {
+ shell->DestroyFramesForAndRestyle(this);
MOZ_ASSERT(!shell->FrameManager()->GetDisplayContentsStyleFor(this));
}
}
@@ -1130,29 +1180,20 @@ Element::CreateShadowRoot(ErrorResult& aError)
// Calling SetPrototypeBinding takes ownership of protoBinding.
docInfo->SetPrototypeBinding(NS_LITERAL_CSTRING("shadowroot"), protoBinding);
- RefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
- protoBinding);
+ /**
+ * 4. Let shadow be a new shadow root whose node document is
+ * context object’s node document, host is context object,
+ * and mode is init’s mode.
+ */
+ RefPtr<ShadowRoot> shadowRoot =
+ new ShadowRoot(this, aClosed, nodeInfo.forget(), protoBinding);
shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
- // Replace the old ShadowRoot with the new one and let the old
- // ShadowRoot know about the younger ShadowRoot because the old
- // ShadowRoot is projected into the younger ShadowRoot's shadow
- // insertion point (if it exists).
- ShadowRoot* olderShadow = GetShadowRoot();
+ /**
+ * 5. Set context object’s shadow root to shadow.
+ */
SetShadowRoot(shadowRoot);
- if (olderShadow) {
- olderShadow->SetYoungerShadow(shadowRoot);
-
- // Unbind children of older shadow root because they
- // are no longer in the composed tree.
- for (nsIContent* child = olderShadow->GetFirstChild(); child;
- child = child->GetNextSibling()) {
- child->UnbindFromTree(true, false);
- }
-
- olderShadow->SetIsComposedDocParticipant(false);
- }
// xblBinding takes ownership of docInfo.
RefPtr<nsXBLBinding> xblBinding = new nsXBLBinding(shadowRoot, protoBinding);
@@ -1161,96 +1202,12 @@ Element::CreateShadowRoot(ErrorResult& aError)
SetXBLBinding(xblBinding);
- // Recreate the frame for the bound content because binding a ShadowRoot
- // changes how things are rendered.
- if (doc) {
- MOZ_ASSERT(doc == GetComposedDoc());
- nsIPresShell* shell = doc->GetShell();
- if (shell) {
- shell->CreateFramesFor(destroyedFramesFor);
- }
- }
-
+ /**
+ * 6. Return shadow.
+ */
return shadowRoot.forget();
}
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DestinationInsertionPointList, mParent,
- mDestinationPoints)
-
-NS_INTERFACE_TABLE_HEAD(DestinationInsertionPointList)
- NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
- NS_INTERFACE_TABLE(DestinationInsertionPointList, nsINodeList, nsIDOMNodeList)
- NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(DestinationInsertionPointList)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(DestinationInsertionPointList)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(DestinationInsertionPointList)
-
-DestinationInsertionPointList::DestinationInsertionPointList(Element* aElement)
- : mParent(aElement)
-{
- nsTArray<nsIContent*>* destPoints = aElement->GetExistingDestInsertionPoints();
- if (destPoints) {
- for (uint32_t i = 0; i < destPoints->Length(); i++) {
- mDestinationPoints.AppendElement(destPoints->ElementAt(i));
- }
- }
-}
-
-DestinationInsertionPointList::~DestinationInsertionPointList()
-{
-}
-
-nsIContent*
-DestinationInsertionPointList::Item(uint32_t aIndex)
-{
- return mDestinationPoints.SafeElementAt(aIndex);
-}
-
-NS_IMETHODIMP
-DestinationInsertionPointList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
-{
- nsIContent* item = Item(aIndex);
- if (!item) {
- return NS_ERROR_FAILURE;
- }
-
- return CallQueryInterface(item, aReturn);
-}
-
-uint32_t
-DestinationInsertionPointList::Length() const
-{
- return mDestinationPoints.Length();
-}
-
-NS_IMETHODIMP
-DestinationInsertionPointList::GetLength(uint32_t* aLength)
-{
- *aLength = Length();
- return NS_OK;
-}
-
-int32_t
-DestinationInsertionPointList::IndexOf(nsIContent* aContent)
-{
- return mDestinationPoints.IndexOf(aContent);
-}
-
-JSObject*
-DestinationInsertionPointList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
- return NodeListBinding::Wrap(aCx, this, aGivenProto);
-}
-
-already_AddRefed<DestinationInsertionPointList>
-Element::GetDestinationInsertionPoints()
-{
- RefPtr<DestinationInsertionPointList> list =
- new DestinationInsertionPointList(this);
- return list.forget();
-}
-
void
Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
{
@@ -2383,7 +2340,8 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
bool aNotify,
nsAttrValue& aOldValue,
uint8_t* aModType,
- bool* aHasListeners)
+ bool* aHasListeners,
+ bool* aOldValueSet)
{
bool modification = false;
*aHasListeners = aNotify &&
@@ -2391,6 +2349,8 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
+ *aOldValueSet = false;
+
// If we have no listeners and aNotify is false, we are almost certainly
// coming from the content sink and will almost certainly have no previous
// value. Even if we do, setting the value is cheap when we have no
@@ -2414,6 +2374,7 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
// We have to serialize the value anyway in order to create the
// mutation event so there's no cost in doing it now.
aOldValue.SetToSerialized(*info.mValue);
+ *aOldValueSet = true;
}
bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
if (valueMatches && aPrefix == info.mName->GetPrefix()) {
@@ -2433,10 +2394,12 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
- uint8_t* aModType, bool* aHasListeners)
+ uint8_t* aModType, bool* aHasListeners,
+ bool* aOldValueSet)
{
if (!MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
- aOldValue, aModType, aHasListeners)) {
+ aOldValue, aModType, aHasListeners,
+ aOldValueSet)) {
return false;
}
@@ -2446,11 +2409,44 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
}
nsresult
+Element::SetSingleClassFromParser(nsIAtom* aSingleClassName)
+{
+ // Keep this in sync with SetAttr and SetParsedAttr below.
+
+ if (!mAttrsAndChildren.CanFitMoreAttrs()) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsAttrValue value(aSingleClassName);
+
+ nsIDocument* document = GetComposedDoc();
+ mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, false);
+
+ // In principle, BeforeSetAttr should be called here if a node type
+ // existed that wanted to do something special for class, but there
+ // is no such node type, so calling SetMayHaveClass() directly.
+ SetMayHaveClass();
+
+ return SetAttrAndNotify(kNameSpaceID_None,
+ nsGkAtoms::_class,
+ nullptr, // prefix
+ nullptr, // old value
+ value,
+ static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION),
+ false, // hasListeners
+ false, // notify
+ kCallAfterSetAttr,
+ document,
+ updateBatch);
+}
+
+nsresult
Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify)
{
- // Keep this in sync with SetParsedAttr below
+ // Keep this in sync with SetParsedAttr below and SetSingleClassFromParser
+ // above.
NS_ENSURE_ARG_POINTER(aName);
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
@@ -2462,17 +2458,27 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
uint8_t modType;
bool hasListeners;
+ // We don't want to spend time preparsing class attributes if the value is not
+ // changing, so just init our nsAttrValueOrString with aValue for the
+ // OnlyNotifySameValueSet call.
nsAttrValueOrString value(aValue);
nsAttrValue oldValue;
+ bool oldValueSet;
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
- oldValue, &modType, &hasListeners)) {
- return NS_OK;
+ oldValue, &modType, &hasListeners, &oldValueSet)) {
+ return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
}
- nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
- nsAttrValue* preparsedAttrValue = value.GetStoredAttrValue();
+ nsAttrValue attrValue;
+ nsAttrValue* preparsedAttrValue;
+ if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::_class) {
+ attrValue.ParseAtomArray(aValue);
+ value.ResetToAttrValue(attrValue);
+ preparsedAttrValue = &attrValue;
+ } else {
+ preparsedAttrValue = nullptr;
+ }
if (aNotify) {
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
@@ -2481,21 +2487,23 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
// Hold a script blocker while calling ParseAttribute since that can call
// out to id-observers
- nsAutoScriptBlocker scriptBlocker;
+ nsIDocument* document = GetComposedDoc();
+ mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
- nsAttrValue attrValue;
- if (preparsedAttrValue) {
- attrValue.SwapValueWith(*preparsedAttrValue);
- }
- // Even the value was pre-parsed in BeforeSetAttr, we still need to call
- // ParseAttribute because it can have side effects.
- if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
+ nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!preparsedAttrValue &&
+ !ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
attrValue.SetTo(aValue);
}
- return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
+ PreIdMaybeChange(aNamespaceID, aName, &value);
+
+ return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
+ oldValueSet ? &oldValue : nullptr,
attrValue, modType, hasListeners, aNotify,
- kCallAfterSetAttr);
+ kCallAfterSetAttr, document, updateBatch);
}
nsresult
@@ -2503,7 +2511,7 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix, nsAttrValue& aParsedValue,
bool aNotify)
{
- // Keep this in sync with SetAttr above
+ // Keep this in sync with SetAttr and SetSingleClassFromParser above
NS_ENSURE_ARG_POINTER(aName);
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
@@ -2518,41 +2526,46 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
bool hasListeners;
nsAttrValueOrString value(aParsedValue);
nsAttrValue oldValue;
+ bool oldValueSet;
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
- oldValue, &modType, &hasListeners)) {
- return NS_OK;
+ oldValue, &modType, &hasListeners, &oldValueSet)) {
+ return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
}
- nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
if (aNotify) {
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
&aParsedValue);
}
- return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
+ nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PreIdMaybeChange(aNamespaceID, aName, &value);
+
+ nsIDocument* document = GetComposedDoc();
+ mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
+ return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
+ oldValueSet ? &oldValue : nullptr,
aParsedValue, modType, hasListeners, aNotify,
- kCallAfterSetAttr);
+ kCallAfterSetAttr, document, updateBatch);
}
nsresult
Element::SetAttrAndNotify(int32_t aNamespaceID,
nsIAtom* aName,
nsIAtom* aPrefix,
- const nsAttrValue& aOldValue,
+ const nsAttrValue* aOldValue,
nsAttrValue& aParsedValue,
uint8_t aModType,
bool aFireMutation,
bool aNotify,
- bool aCallAfterSetAttr)
+ bool aCallAfterSetAttr,
+ nsIDocument* aComposedDocument,
+ const mozAutoDocUpdate&)
{
nsresult rv;
- nsIDocument* document = GetComposedDoc();
- mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
-
nsMutationGuard::DidMutate();
// Copy aParsedValue for later use since it will be lost when we call
@@ -2564,6 +2577,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
bool hadValidDir = false;
bool hadDirAuto = false;
+ bool oldValueSet;
if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::dir) {
@@ -2574,8 +2588,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
// XXXbz Perhaps we should push up the attribute mapping function
// stuff to Element?
if (!IsAttributeMapped(aName) ||
- !SetMappedAttribute(document, aName, aParsedValue, &rv)) {
- rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue);
+ !SetAndSwapMappedAttribute(aComposedDocument, aName, aParsedValue, &oldValueSet, &rv)) {
+ rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue, &oldValueSet);
}
}
else {
@@ -2584,24 +2598,34 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
aNamespaceID,
nsIDOMNode::ATTRIBUTE_NODE);
- rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue);
+ rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue, &oldValueSet);
}
+ NS_ENSURE_SUCCESS(rv, rv);
- // If the old value owns its own data, we know it is OK to keep using it.
- const nsAttrValue* oldValue =
- aParsedValue.StoresOwnData() ? &aParsedValue : &aOldValue;
+ PostIdMaybeChange(aNamespaceID, aName, &valueForAfterSetAttr);
- NS_ENSURE_SUCCESS(rv, rv);
+ // If the old value owns its own data, we know it is OK to keep using it.
+ // oldValue will be null if there was no previously set value
+ const nsAttrValue* oldValue;
+ if (aParsedValue.StoresOwnData()) {
+ if (oldValueSet) {
+ oldValue = &aParsedValue;
+ } else {
+ oldValue = nullptr;
+ }
+ } else {
+ // No need to conditionally assign null here. If there was no previously
+ // set value for the attribute, aOldValue will already be null.
+ oldValue = aOldValue;
+ }
- if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
+ if (aComposedDocument || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
RefPtr<nsXBLBinding> binding = GetXBLBinding();
if (binding) {
binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
}
}
- UpdateState(aNotify);
-
if (CustomElementRegistry::IsCustomElementEnabled()) {
if (CustomElementData* data = GetCustomElementData()) {
if (CustomElementDefinition* definition =
@@ -2611,7 +2635,14 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
MOZ_ASSERT(data->mState == CustomElementData::State::eCustom,
"AttributeChanged callback should fire only if "
"custom element state is custom");
- nsCOMPtr<nsIAtom> oldValueAtom = oldValue->GetAsAtom();
+ nsCOMPtr<nsIAtom> oldValueAtom;
+ if (oldValue) {
+ oldValueAtom = oldValue->GetAsAtom();
+ } else {
+ // If there is no old value, get the value of the uninitialized attribute
+ // that was swapped with aParsedValue.
+ oldValueAtom = aParsedValue.GetAsAtom();
+ }
nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
nsAutoString ns;
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
@@ -2631,7 +2662,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
}
if (aCallAfterSetAttr) {
- rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, aNotify);
+ rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, oldValue,
+ aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
@@ -2640,12 +2672,14 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
}
}
+ UpdateState(aNotify);
+
if (aNotify) {
// Don't pass aOldValue to AttributeChanged since it may not be reliable.
// Callers only compute aOldValue under certain conditions which may not
// be triggered by all nsIMutationObservers.
nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType,
- oldValue == &aParsedValue ? &aParsedValue : nullptr);
+ aParsedValue.StoresOwnData() ? &aParsedValue : nullptr);
}
if (aFireMutation) {
@@ -2663,7 +2697,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
if (!newValue.IsEmpty()) {
mutation.mNewAttrValue = NS_Atomize(newValue);
}
- if (!oldValue->IsEmptyString()) {
+ if (oldValue && !oldValue->IsEmptyString()) {
mutation.mPrevAttrValue = oldValue->GetAsAtom();
}
mutation.mAttrChange = aModType;
@@ -2675,25 +2709,6 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
return NS_OK;
}
-nsresult
-Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue, bool aNotify)
-{
- if (aNamespaceID == kNameSpaceID_None) {
- if (aName == nsGkAtoms::_class) {
- // aValue->GetAttrValue will only be non-null here when this is called
- // via Element::SetParsedAttr. This shouldn't happen for "class", but
- // this will handle it.
- if (aValue && !aValue->GetAttrValue()) {
- nsAttrValue attr;
- attr.ParseAtomArray(aValue->String());
- aValue->TakeParsedValue(attr);
- }
- }
- }
- return NS_OK;
-}
-
bool
Element::ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
@@ -2701,22 +2716,16 @@ Element::ParseAttribute(int32_t aNamespaceID,
nsAttrValue& aResult)
{
if (aNamespaceID == kNameSpaceID_None) {
- if (aAttribute == nsGkAtoms::_class) {
- SetFlags(NODE_MAY_HAVE_CLASS);
- // Result should have been preparsed above.
- return true;
- }
+ MOZ_ASSERT(aAttribute != nsGkAtoms::_class,
+ "The class attribute should be preparsed and therefore should "
+ "never be passed to Element::ParseAttribute");
if (aAttribute == nsGkAtoms::id) {
// Store id as an atom. id="" means that the element has no id,
// not that it has an emptystring as the id.
- RemoveFromIdTable();
if (aValue.IsEmpty()) {
- ClearHasID();
return false;
}
aResult.ParseAtom(aValue);
- SetHasID();
- AddToIdTable(aResult.GetAtomValue());
return true;
}
}
@@ -2725,15 +2734,71 @@ Element::ParseAttribute(int32_t aNamespaceID,
}
bool
-Element::SetMappedAttribute(nsIDocument* aDocument,
- nsIAtom* aName,
- nsAttrValue& aValue,
- nsresult* aRetval)
+Element::SetAndSwapMappedAttribute(nsIDocument* aDocument,
+ nsIAtom* aName,
+ nsAttrValue& aValue,
+ bool* aValueWasSet,
+ nsresult* aRetval)
{
*aRetval = NS_OK;
return false;
}
+nsresult
+Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue, bool aNotify)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::_class) {
+ if (aValue) {
+ // Note: This flag is asymmetrical. It is never unset and isn't exact.
+ // If it is ever made to be exact, we probably need to handle this
+ // similarly to how ids are handled in PreIdMaybeChange and
+ // PostIdMaybeChange.
+ // Note that SetSingleClassFromParser inlines BeforeSetAttr and
+ // calls SetMayHaveClass directly. Making a subclass take action
+ // on the class attribute in a BeforeSetAttr override would
+ // require revising SetSingleClassFromParser.
+ SetMayHaveClass();
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+void
+Element::PreIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue)
+{
+ if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::id) {
+ return;
+ }
+ RemoveFromIdTable();
+
+ return;
+}
+
+void
+Element::PostIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue)
+{
+ if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::id) {
+ return;
+ }
+
+ // id="" means that the element has no id, not that it has an empty
+ // string as the id.
+ if (aValue && !aValue->IsEmptyString()) {
+ SetHasID();
+ AddToIdTable(aValue->GetAtomValue());
+ } else {
+ ClearHasID();
+ }
+
+ return;
+}
+
EventListenerManager*
Element::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
bool* aDefer)
@@ -2810,9 +2875,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
return NS_OK;
}
- nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
nsIDocument *document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
@@ -2822,11 +2884,16 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nullptr);
}
+ nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify);
+ NS_ENSURE_SUCCESS(rv, rv);
+
bool hasMutationListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
+ PreIdMaybeChange(aNameSpaceID, aName, nullptr);
+
// Grab the attr node if needed before we remove it from the attr map
RefPtr<Attr> attrNode;
if (hasMutationListeners) {
@@ -2845,12 +2912,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
// react to unexpected attribute changes.
nsMutationGuard::DidMutate();
- if (aName == nsGkAtoms::id && aNameSpaceID == kNameSpaceID_None) {
- // Have to do this before clearing flag. See RemoveFromIdTable
- RemoveFromIdTable();
- ClearHasID();
- }
-
bool hadValidDir = false;
bool hadDirAuto = false;
@@ -2863,6 +2924,8 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue);
NS_ENSURE_SUCCESS(rv, rv);
+ PostIdMaybeChange(aNameSpaceID, aName, nullptr);
+
if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
RefPtr<nsXBLBinding> binding = GetXBLBinding();
if (binding) {
@@ -2870,8 +2933,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
}
- UpdateState(aNotify);
-
if (CustomElementRegistry::IsCustomElementEnabled()) {
if (CustomElementData* data = GetCustomElementData()) {
if (CustomElementDefinition* definition =
@@ -2898,6 +2959,11 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
}
+ rv = AfterSetAttr(aNameSpaceID, aName, nullptr, &oldValue, aNotify);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ UpdateState(aNotify);
+
if (aNotify) {
// We can always pass oldValue here since there is no new value which could
// have corrupted it.
@@ -2905,9 +2971,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsIDOMMutationEvent::REMOVAL, &oldValue);
}
- rv = AfterSetAttr(aNameSpaceID, aName, nullptr, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
OnSetDirAttr(this, nullptr, hadValidDir, hadDirAuto, aNotify);
}
@@ -3129,7 +3192,7 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
}
nsresult
-Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
+Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor)
{
// Optimisation: return early if this event doesn't interest us.
// IMPORTANT: this switch and the switch below it must be kept in sync!
@@ -3151,8 +3214,9 @@ Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
nsresult rv = NS_OK;
- // We do the status bar updates in PreHandleEvent so that the status bar gets
- // updated even if the event is consumed before we have a chance to set it.
+ // We do the status bar updates in GetEventTargetParent so that the status bar
+ // gets updated even if the event is consumed before we have a chance to set
+ // it.
switch (aVisitor.mEvent->mMessage) {
// Set the status bar similarly for mouseover and focus
case eMouseOver:
diff --git a/dom/base/Element.h b/dom/base/Element.h
index 782004703..3d9b80a98 100644
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -41,6 +41,7 @@
#include "Units.h"
#include "DOMIntersectionObserver.h"
+class mozAutoDocUpdate;
class nsIFrame;
class nsIDOMMozNamedAttrMap;
class nsIURI;
@@ -143,7 +144,6 @@ class CustomElementRegistry;
class Link;
class DOMRect;
class DOMRectList;
-class DestinationInsertionPointList;
class Grid;
// IID for the dom::Element interface
@@ -255,6 +255,23 @@ public:
void ClearStyleStateLocks();
/**
+ * Accessors for the state of our dir attribute.
+ */
+ bool HasDirAuto() const
+ {
+ return State().HasState(NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO);
+ }
+
+ /**
+ * Elements with dir="rtl" or dir="ltr".
+ */
+ bool HasFixedDir() const
+ {
+ return State().HasAtLeastOneOfStates(NS_EVENT_STATE_DIR_ATTR_LTR |
+ NS_EVENT_STATE_DIR_ATTR_RTL);
+ }
+
+ /**
* Get the inline style declaration, if any, for this element.
*/
virtual DeclarationBlock* GetInlineStyleDeclaration();
@@ -379,17 +396,10 @@ public:
bool GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult);
- // The bdi element defaults to dir=auto if it has no dir attribute set.
- // Other elements will only have dir=auto if they have an explicit dir=auto,
- // which will mean that HasValidDir() returns true but HasFixedDir() returns
- // false
- inline bool HasDirAuto() const {
- return (!HasFixedDir() &&
- (HasValidDir() || IsHTMLElement(nsGkAtoms::bdi)));
- }
-
Directionality GetComputedDirectionality() const;
+ inline Element* GetFlattenedTreeParentElementForStyle() const;
+
/**
* Gets the custom element data used by web components custom element.
* Custom element data is created at the first attempt to enqueue a callback.
@@ -460,6 +470,9 @@ protected:
mState &= ~aStates;
}
+ already_AddRefed<ShadowRoot> AttachShadowInternal(bool aClosed,
+ ErrorResult& aError);
+
private:
// Need to allow the ESM, nsGlobalWindow, and the focus manager to
// set our state
@@ -498,6 +511,16 @@ protected:
RemoveStatesSilently(aStates);
NotifyStateChange(aStates);
}
+ virtual void ToggleStates(EventStates aStates, bool aNotify)
+ {
+ NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
+ "Should only be removing externally-managed states here");
+ mState ^= aStates;
+ if (aNotify) {
+ NotifyStateChange(aStates);
+ }
+ }
+
public:
virtual void UpdateEditableState(bool aNotify) override;
@@ -520,6 +543,7 @@ public:
already_AddRefed<mozilla::dom::NodeInfo>
GetExistingAttrNameFromQName(const nsAString& aStr) const;
+ MOZ_ALWAYS_INLINE // Avoid a crashy hook from Avast 10 Beta (Bug 1058131)
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAString& aValue, bool aNotify)
{
@@ -534,25 +558,57 @@ public:
* values will not actually be compared if we aren't notifying and we don't
* have mutation listeners (in which case it's cheap to just return false
* and let the caller go ahead and set the value).
- * @param aOldValue Set to the old value of the attribute, but only if there
- * are event listeners. If set, the type of aOldValue will be either
+ * @param aOldValue [out] Set to the old value of the attribute, but only if
+ * there are event listeners. If set, the type of aOldValue will be either
* nsAttrValue::eString or nsAttrValue::eAtom.
- * @param aModType Set to nsIDOMMutationEvent::MODIFICATION or to
+ * @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
* nsIDOMMutationEvent::ADDITION, but only if this helper returns true
- * @param aHasListeners Set to true if there are mutation event listeners
- * listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
+ * @param aHasListeners [out] Set to true if there are mutation event
+ * listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
+ * @param aOldValueSet [out] Indicates whether an old attribute value has been
+ * stored in aOldValue. The bool will be set to true if a value was stored.
*/
bool MaybeCheckSameAttrVal(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
- uint8_t* aModType, bool* aHasListeners);
+ uint8_t* aModType, bool* aHasListeners,
+ bool* aOldValueSet);
+
+ /**
+ * Notifies mutation listeners if aNotify is true, there are mutation
+ * listeners, and the attribute value is changing.
+ *
+ * @param aNamespaceID The namespace of the attribute
+ * @param aName The local name of the attribute
+ * @param aPrefix The prefix of the attribute
+ * @param aValue The value that the attribute is being changed to
+ * @param aNotify If true, mutation listeners will be notified if they exist
+ * and the attribute value is changing
+ * @param aOldValue [out] Set to the old value of the attribute, but only if
+ * there are event listeners. If set, the type of aOldValue will be either
+ * nsAttrValue::eString or nsAttrValue::eAtom.
+ * @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
+ * nsIDOMMutationEvent::ADDITION, but only if this helper returns true
+ * @param aHasListeners [out] Set to true if there are mutation event
+ * listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
+ * @param aOldValueSet [out] Indicates whether an old attribute value has been
+ * stored in aOldValue. The bool will be set to true if a value was stored.
+ */
bool OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
- uint8_t* aModType, bool* aHasListeners);
+ uint8_t* aModType, bool* aHasListeners,
+ bool* aOldValueSet);
+
+ /**
+ * Sets the class attribute to a value that contains no whitespace.
+ * Assumes that we are not notifying and that the attribute hasn't been
+ * set previously.
+ */
+ nsresult SetSingleClassFromParser(nsIAtom* aSingleClassName);
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
const nsAString& aValue, bool aNotify) override;
@@ -589,7 +645,7 @@ public:
* guaranteed (e.g. we could have class="").
*/
const nsAttrValue* GetClasses() const {
- if (HasFlag(NODE_MAY_HAVE_CLASS)) {
+ if (MayHaveClass()) {
return DoGetClasses();
}
return nullptr;
@@ -761,6 +817,25 @@ public:
already_AddRefed<nsIHTMLCollection>
GetElementsByClassName(const nsAString& aClassNames);
+ CSSPseudoElementType GetPseudoElementType() const {
+ if (!HasProperties()) {
+ return CSSPseudoElementType::NotPseudo;
+ }
+ nsresult rv = NS_OK;
+ auto raw = GetProperty(nsGkAtoms::pseudoProperty, &rv);
+ if (rv == NS_PROPTABLE_PROP_NOT_THERE) {
+ return CSSPseudoElementType::NotPseudo;
+ }
+ return CSSPseudoElementType(reinterpret_cast<uintptr_t>(raw));
+ }
+
+ void SetPseudoElementType(CSSPseudoElementType aPseudo) {
+ static_assert(sizeof(CSSPseudoElementType) <= sizeof(uintptr_t),
+ "Need to be able to store this in a void*");
+ MOZ_ASSERT(aPseudo != CSSPseudoElementType::NotPseudo);
+ SetProperty(nsGkAtoms::pseudoProperty, reinterpret_cast<void*>(aPseudo));
+ }
+
private:
/**
* Implement the algorithm specified at
@@ -848,8 +923,15 @@ public:
already_AddRefed<DOMRectList> GetClientRects();
already_AddRefed<DOMRect> GetBoundingClientRect();
+ // Shadow DOM v1
+ already_AddRefed<ShadowRoot> AttachShadow(const ShadowRootInit& aInit,
+ ErrorResult& aError);
+ ShadowRoot* GetShadowRootByMode() const;
+ void SetSlot(const nsAString& aName, ErrorResult& aError);
+ void GetSlot(nsAString& aName);
+
+ // [deprecated] Shadow DOM v0
already_AddRefed<ShadowRoot> CreateShadowRoot(ErrorResult& aError);
- already_AddRefed<DestinationInsertionPointList> GetDestinationInsertionPoints();
ShadowRoot *FastGetShadowRoot() const
{
@@ -1239,7 +1321,10 @@ protected:
* its current value) is !StoresOwnData() --- in which
* case the current value is probably already useless.
* If the current value is StoresOwnData() (or absent),
- * aOldValue will not be used.
+ * aOldValue will not be used. aOldValue will only be set
+ * in certain circumstances (there are mutation
+ * listeners, element is a custom element, attribute was
+ * not previously unset). Otherwise it will be null.
* @param aParsedValue parsed new value of attribute. Replaced by the
* old value of the attribute. This old value is only
* useful if either it or the new value is StoresOwnData.
@@ -1248,16 +1333,19 @@ protected:
* @param aFireMutation should mutation-events be fired?
* @param aNotify should we notify document-observers?
* @param aCallAfterSetAttr should we call AfterSetAttr?
+ * @param aComposedDocument The current composed document of the element.
*/
nsresult SetAttrAndNotify(int32_t aNamespaceID,
nsIAtom* aName,
nsIAtom* aPrefix,
- const nsAttrValue& aOldValue,
+ const nsAttrValue* aOldValue,
nsAttrValue& aParsedValue,
uint8_t aModType,
bool aFireMutation,
bool aNotify,
- bool aCallAfterSetAttr);
+ bool aCallAfterSetAttr,
+ nsIDocument* aComposedDocument,
+ const mozAutoDocUpdate& aGuard);
/**
* Scroll to a new position using behavior evaluated from CSS and
@@ -1295,14 +1383,21 @@ protected:
*
* @param aDocument the current document of this node (an optimization)
* @param aName the name of the attribute
- * @param aValue the nsAttrValue to set
+ * @param aValue the nsAttrValue to set. Will be swapped with the existing
+ * value of the attribute if the attribute already exists.
+ * @param [out] aValueWasSet If the attribute was not set previously,
+ * aValue will be swapped with an empty attribute
+ * and aValueWasSet will be set to false. Otherwise,
+ * aValueWasSet will be set to true and aValue will
+ * contain the previous value set.
* @param [out] aRetval the nsresult status of the operation, if any.
* @return true if the setting was attempted, false otherwise.
*/
- virtual bool SetMappedAttribute(nsIDocument* aDocument,
- nsIAtom* aName,
- nsAttrValue& aValue,
- nsresult* aRetval);
+ virtual bool SetAndSwapMappedAttribute(nsIDocument* aDocument,
+ nsIAtom* aName,
+ nsAttrValue& aValue,
+ bool* aValueWasSet,
+ nsresult* aRetval);
/**
* Hook that is called by Element::SetAttr to allow subclasses to
@@ -1315,33 +1410,92 @@ protected:
* @param aName the localname of the attribute being set
* @param aValue the value it's being set to represented as either a string or
* a parsed nsAttrValue. Alternatively, if the attr is being removed it
- * will be null. BeforeSetAttr is allowed to modify aValue by parsing
- * the string to an nsAttrValue (to avoid having to reparse it in
- * ParseAttribute).
+ * will be null.
* @param aNotify Whether we plan to notify document observers.
*/
- // Note that this is inlined so that when subclasses call it it gets
- // inlined. Those calls don't go through a vtable.
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify);
/**
* Hook that is called by Element::SetAttr to allow subclasses to
* deal with attribute sets. This will only be called after we have called
- * SetAndTakeAttr and AttributeChanged (that is, after we have actually set
- * the attr). It will always be called under a scriptblocker.
+ * SetAndSwapAttr (that is, after we have actually set the attr). It will
+ * always be called under a scriptblocker.
*
* @param aNamespaceID the namespace of the attr being set
* @param aName the localname of the attribute being set
* @param aValue the value it's being set to. If null, the attr is being
* removed.
+ * @param aOldValue the value that the attribute had previously. If null,
+ * the attr was not previously set. This argument may not have the
+ * correct value for SVG elements, or other cases in which the
+ * attribute value doesn't store its own data
* @param aNotify Whether we plan to notify document observers.
*/
// Note that this is inlined so that when subclasses call it it gets
// inlined. Those calls don't go through a vtable.
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
+ {
+ return NS_OK;
+ }
+
+ /**
+ * This function shall be called just before the id attribute changes. It will
+ * be called after BeforeSetAttr. If the attribute being changed is not the id
+ * attribute, this function does nothing. Otherwise, it will remove the old id
+ * from the document's id cache.
+ *
+ * This must happen after BeforeSetAttr (rather than during) because the
+ * the subclasses' calls to BeforeSetAttr may notify on state changes. If they
+ * incorrectly determine whether the element had an id, the element may not be
+ * restyled properly.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aValue the new id value. Will be null if the id is being unset.
+ */
+ void PreIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue);
+
+ /**
+ * This function shall be called just after the id attribute changes. It will
+ * be called before AfterSetAttr. If the attribute being changed is not the id
+ * attribute, this function does nothing. Otherwise, it will add the new id to
+ * the document's id cache and properly set the ElementHasID flag.
+ *
+ * This must happen before AfterSetAttr (rather than during) because the
+ * the subclasses' calls to AfterSetAttr may notify on state changes. If they
+ * incorrectly determine whether the element now has an id, the element may
+ * not be restyled properly.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aValue the new id value. Will be null if the id is being unset.
+ */
+ void PostIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue);
+
+ /**
+ * Usually, setting an attribute to the value that it already has results in
+ * no action. However, in some cases, setting an attribute to its current
+ * value should have the effect of, for example, forcing a reload of
+ * network data. To address that, this function will be called in this
+ * situation to allow the handling of such a case.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aValue the value it's being set to represented as either a string or
+ * a parsed nsAttrValue.
+ * @param aNotify Whether we plan to notify document observers.
+ */
+ // Note that this is inlined so that when subclasses call it it gets
+ // inlined. Those calls don't go through a vtable.
+ virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify)
{
return NS_OK;
}
@@ -1400,7 +1554,7 @@ protected:
/**
* Handle status bar updates before they can be cancelled.
*/
- nsresult PreHandleEventForLinks(EventChainPreVisitor& aVisitor);
+ nsresult GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor);
/**
* Handle default actions for link event if the event isn't consumed yet.
@@ -1460,30 +1614,6 @@ private:
nsCOMPtr<nsIDocument> mDoc;
};
-class DestinationInsertionPointList : public nsINodeList
-{
-public:
- explicit DestinationInsertionPointList(Element* aElement);
-
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DestinationInsertionPointList)
-
- // nsIDOMNodeList
- NS_DECL_NSIDOMNODELIST
-
- // nsINodeList
- virtual nsIContent* Item(uint32_t aIndex) override;
- virtual int32_t IndexOf(nsIContent* aContent) override;
- virtual nsINode* GetParentObject() override { return mParent; }
- virtual uint32_t Length() const;
- virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-protected:
- virtual ~DestinationInsertionPointList();
-
- RefPtr<Element> mParent;
- nsCOMArray<nsIContent> mDestinationPoints;
-};
-
NS_DEFINE_STATIC_IID_ACCESSOR(Element, NS_ELEMENT_IID)
inline bool
diff --git a/dom/base/ElementInlines.h b/dom/base/ElementInlines.h
index c68bd012e..df2cc2e24 100644
--- a/dom/base/ElementInlines.h
+++ b/dom/base/ElementInlines.h
@@ -25,6 +25,17 @@ Element::UnregisterActivityObserver()
OwnerDoc()->UnregisterActivityObserver(this);
}
+inline Element*
+Element::GetFlattenedTreeParentElementForStyle() const
+{
+ nsINode* parentNode = GetFlattenedTreeParentNodeForStyle();
+ if MOZ_LIKELY(parentNode && parentNode->IsElement()) {
+ return parentNode->AsElement();
+ }
+
+ return nullptr;
+}
+
} // namespace dom
} // namespace mozilla
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
index 526c3c9d4..6fbe04d25 100644
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -123,6 +123,7 @@
#include "mozilla/CORSMode.h"
#include "mozilla/dom/ShadowRoot.h"
+#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "nsStyledElement.h"
@@ -151,8 +152,56 @@ nsIContent::FindFirstNonChromeOnlyAccessContent() const
return nullptr;
}
+// https://dom.spec.whatwg.org/#dom-slotable-assignedslot
+HTMLSlotElement*
+nsIContent::GetAssignedSlotByMode() const
+{
+ /**
+ * Get slotable's assigned slot for the result of
+ * find a slot with open flag UNSET [1].
+ *
+ * [1] https://dom.spec.whatwg.org/#assign-a-slot
+ */
+ HTMLSlotElement* slot = GetAssignedSlot();
+ if (!slot) {
+ return nullptr;
+ }
+
+ MOZ_ASSERT(GetParent());
+ MOZ_ASSERT(GetParent()->GetShadowRoot());
+
+ /**
+ * Additional check for open flag SET:
+ * If slotable’s parent’s shadow root's mode is not "open",
+ * then return null.
+ */
+ if (GetParent()->GetShadowRoot()->IsClosed()) {
+ return nullptr;
+ }
+
+ return slot;
+}
+
+nsINode*
+nsIContent::GetFlattenedTreeParentForMaybeAssignedNode() const
+{
+ if (HTMLSlotElement* assignedSlot = GetAssignedSlot()) {
+ return assignedSlot;
+ }
+
+ HTMLSlotElement* parentSlot = HTMLSlotElement::FromContent(GetParent());
+ if (!parentSlot) {
+ return nullptr;
+ }
+
+ // If this is not an unassigned node, then it must be a fallback content.
+ MOZ_ASSERT(parentSlot->AssignedNodes().IsEmpty());
+
+ return parentSlot;
+}
+
nsINode*
-nsIContent::GetFlattenedTreeParentNodeInternal() const
+nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const
{
nsINode* parentNode = GetParentNode();
if (!parentNode || !parentNode->IsContent()) {
@@ -161,18 +210,51 @@ nsIContent::GetFlattenedTreeParentNodeInternal() const
}
nsIContent* parent = parentNode->AsContent();
+ if (aType == eForStyle &&
+ IsRootOfNativeAnonymousSubtree() &&
+ OwnerDoc()->GetRootElement() == parent) {
+ // When getting the flattened tree parent for style, we return null
+ // for any "document level" native anonymous content subtree root.
+ // This is NAC generated by an ancestor frame of the document element's
+ // primary frame, and includes scrollbar elements created by the root
+ // scroll frame, and the "custom content container" and accessible caret
+ // generated by the nsCanvasFrame. We distinguish document level NAC
+ // from NAC generated by the root element's primary frame below.
+ nsIFrame* parentFrame = parent->GetPrimaryFrame();
+ if (!parentFrame) {
+ // If the root element has no primary frame, it means it can't have
+ // generated any NAC itself. Thus any NAC we have here must have
+ // been generated by an ancestor frame.
+ //
+ // If we are in here, then either the root element is display:none, or
+ // we are in the middle of constructing the root of the frame tree and
+ // we are trying to eagerly restyle document level NAC in
+ // nsCSSFrameConstructor::GetAnonymousContent before the root
+ // element's frame has been constructed.
+ return nullptr;
+ }
+ nsIAnonymousContentCreator* creator = do_QueryFrame(parentFrame);
+ if (!creator) {
+ // If the root element does have a frame, but does not implement
+ // nsIAnonymousContentCreator, then this must be document level NAC.
+ return nullptr;
+ }
+ AutoTArray<nsIContent*, 8> elements;
+ creator->AppendAnonymousContentTo(elements, 0);
+ if (!elements.Contains(this)) {
+ // If the root element does have a frame, and also does implement
+ // nsIAnonymousContentCreator, but didn't create this node, then
+ // it must be document level NAC.
+ return nullptr;
+ }
+ }
+
if (parent && nsContentUtils::HasDistributedChildren(parent) &&
nsContentUtils::IsInSameAnonymousTree(parent, this)) {
- // This node is distributed to insertion points, thus we
- // need to consult the destination insertion points list to
- // figure out where this node was inserted in the flattened tree.
- // It may be the case that |parent| distributes its children
- // but the child does not match any insertion points, thus
- // the flattened tree parent is nullptr.
- nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints();
- parent = destInsertionPoints && !destInsertionPoints->IsEmpty() ?
- destInsertionPoints->LastElement()->GetParent() : nullptr;
- } else if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
+ return GetFlattenedTreeParentForMaybeAssignedNode();
+ }
+
+ if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
nsIContent* insertionParent = GetXBLInsertionParent();
if (insertionParent) {
parent = insertionParent;
@@ -575,6 +657,9 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mContainingShadow");
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mContainingShadow));
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mAssignedSlot");
+ cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mAssignedSlot.get()));
+
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mXBLBinding");
cb.NoteNativeChild(mExtendedSlots->mXBLBinding,
NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding));
@@ -618,6 +703,7 @@ FragmentOrElement::nsDOMSlots::Unlink()
mExtendedSlots->mLabelsList = nullptr;
mExtendedSlots->mShadowRoot = nullptr;
mExtendedSlots->mContainingShadow = nullptr;
+ mExtendedSlots->mAssignedSlot = nullptr;
MOZ_ASSERT(!(mExtendedSlots->mXBLBinding));
mExtendedSlots->mXBLInsertionParent = nullptr;
if (mExtendedSlots->mCustomElementData) {
@@ -718,7 +804,7 @@ FindChromeAccessOnlySubtreeOwner(nsIContent* aContent)
}
nsresult
-nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
//FIXME! Document how this event retargeting works, Bug 329124.
aVisitor.mCanHandle = true;
@@ -727,6 +813,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
// Don't propagate mouseover and mouseout events when mouse is moving
// inside chrome access only content.
bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();
+ aVisitor.mRootOfClosedTree = isAnonForEvents;
if ((aVisitor.mEvent->mMessage == eMouseOver ||
aVisitor.mEvent->mMessage == eMouseOut ||
aVisitor.mEvent->mMessage == ePointerOver ||
@@ -738,7 +825,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
((this == aVisitor.mEvent->mOriginalTarget &&
!ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) {
nsCOMPtr<nsIContent> relatedTarget =
- do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->relatedTarget);
+ do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->mRelatedTarget);
if (relatedTarget &&
relatedTarget->OwnerDoc() == OwnerDoc()) {
@@ -748,7 +835,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
nsIContent* adjustedTarget =
Event::GetShadowRelatedTarget(this, relatedTarget);
if (this == adjustedTarget) {
- aVisitor.mParentTarget = nullptr;
+ aVisitor.SetParentTarget(nullptr, false);
aVisitor.mCanHandle = false;
return NS_OK;
}
@@ -805,7 +892,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
originalTarget->FindFirstNonChromeOnlyAccessContent())
? "" : "Wrong event propagation!?!\n");
#endif
- aVisitor.mParentTarget = nullptr;
+ aVisitor.SetParentTarget(nullptr, false);
// Event should not propagate to non-anon content.
aVisitor.mCanHandle = isAnonForEvents;
return NS_OK;
@@ -816,58 +903,10 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
- nsIContent* parent = GetParent();
-
- // Web components have a special event chain that need to account
- // for destination insertion points where nodes have been distributed.
- nsTArray<nsIContent*>* destPoints = GetExistingDestInsertionPoints();
- if (destPoints && !destPoints->IsEmpty()) {
- // Push destination insertion points to aVisitor.mDestInsertionPoints
- // excluding shadow insertion points.
- bool didPushNonShadowInsertionPoint = false;
- for (uint32_t i = 0; i < destPoints->Length(); i++) {
- nsIContent* point = destPoints->ElementAt(i);
- if (!ShadowRoot::IsShadowInsertionPoint(point)) {
- aVisitor.mDestInsertionPoints.AppendElement(point);
- didPushNonShadowInsertionPoint = true;
- }
- }
-
- // Next node in the event path is the final destination
- // (non-shadow) insertion point that was pushed.
- if (didPushNonShadowInsertionPoint) {
- parent = aVisitor.mDestInsertionPoints.LastElement();
- aVisitor.mDestInsertionPoints.SetLength(
- aVisitor.mDestInsertionPoints.Length() - 1);
- }
- }
-
- ShadowRoot* thisShadowRoot = ShadowRoot::FromNode(this);
- if (thisShadowRoot) {
- if (!aVisitor.mEvent->mFlags.mComposed) {
- // If we do stop propagation, we still want to propagate
- // the event to chrome (nsPIDOMWindow::GetParentTarget()).
- // The load event is special in that we don't ever propagate it
- // to chrome.
- nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
- EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
- ? win->GetParentTarget() : nullptr;
-
- aVisitor.mParentTarget = parentTarget;
- return NS_OK;
- }
-
- if (!aVisitor.mDestInsertionPoints.IsEmpty()) {
- parent = aVisitor.mDestInsertionPoints.LastElement();
- aVisitor.mDestInsertionPoints.SetLength(
- aVisitor.mDestInsertionPoints.Length() - 1);
- } else {
- // The pool host for the youngest shadow root is shadow DOM host,
- // for older shadow roots, it is the shadow insertion point
- // where the shadow root is projected, nullptr if none exists.
- parent = thisShadowRoot->GetPoolHost();
- }
- }
+ // Event parent is the assigned slot, if node is assigned, or node's parent
+ // otherwise.
+ HTMLSlotElement* slot = GetAssignedSlot();
+ nsIContent* parent = slot ? slot : GetParent();
// Event may need to be retargeted if this is the root of a native
// anonymous content subtree or event is dispatched somewhere inside XBL.
@@ -905,11 +944,17 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
if (!aVisitor.mEvent->mFlags.mComposedInNativeAnonymousContent &&
IsRootOfNativeAnonymousSubtree() && OwnerDoc() &&
OwnerDoc()->GetWindow()) {
- aVisitor.mParentTarget = OwnerDoc()->GetWindow()->GetParentTarget();
+ aVisitor.SetParentTarget(OwnerDoc()->GetWindow()->GetParentTarget(), true);
} else if (parent) {
- aVisitor.mParentTarget = parent;
+ aVisitor.SetParentTarget(parent, false);
+ if (slot) {
+ ShadowRoot* root = slot->GetContainingShadow();
+ if (root && root->IsClosed()) {
+ aVisitor.mParentIsSlotInClosedTree = true;
+ }
+ }
} else {
- aVisitor.mParentTarget = GetComposedDoc();
+ aVisitor.SetParentTarget(GetComposedDoc(), false);
}
return NS_OK;
}
@@ -1086,21 +1131,18 @@ FragmentOrElement::SetShadowRoot(ShadowRoot* aShadowRoot)
slots->mShadowRoot = aShadowRoot;
}
-nsTArray<nsIContent*>&
-FragmentOrElement::DestInsertionPoints()
+HTMLSlotElement*
+FragmentOrElement::GetAssignedSlot() const
{
- nsExtendedDOMSlots* slots = ExtendedDOMSlots();
- return slots->mDestInsertionPoints;
+ nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
+ return slots ? slots->mAssignedSlot.get() : nullptr;
}
-nsTArray<nsIContent*>*
-FragmentOrElement::GetExistingDestInsertionPoints() const
+void
+FragmentOrElement::SetAssignedSlot(HTMLSlotElement* aSlot)
{
- nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
- if (slots) {
- return &slots->mDestInsertionPoints;
- }
- return nullptr;
+ nsExtendedDOMSlots* slots = ExtendedDOMSlots();
+ slots->mAssignedSlot = aSlot;
}
void
@@ -2368,9 +2410,8 @@ FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
NS_ASSERTION(IsElement(), "calling SetIsElementInStyleScopeFlagOnShadowTree "
"on a non-Element is useless");
ShadowRoot* shadowRoot = GetShadowRoot();
- while (shadowRoot) {
+ if (shadowRoot) {
shadowRoot->SetIsElementInStyleScopeFlagOnSubtree(aInStyleScope);
- shadowRoot = shadowRoot->GetOlderShadowRoot();
}
}
diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h
index 4edd88908..f1fa046ee 100644
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -62,6 +62,7 @@ public:
// nsIWeakReference
NS_DECL_NSIWEAKREFERENCE
virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+ virtual bool IsAlive() const override { return mNode != nullptr; }
void NoticeNodeDestruction()
{
@@ -154,9 +155,9 @@ public:
virtual void SetXBLBinding(nsXBLBinding* aBinding,
nsBindingManager* aOldBindingManager = nullptr) override;
virtual ShadowRoot *GetContainingShadow() const override;
- virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
- virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
virtual void SetShadowRoot(ShadowRoot* aBinding) override;
+ virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const override;
+ virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) override;
virtual nsIContent *GetXBLInsertionParent() const override;
virtual void SetXBLInsertionParent(nsIContent* aContent) override;
virtual bool IsLink(nsIURI** aURI) const override;
@@ -294,10 +295,9 @@ public:
RefPtr<ShadowRoot> mContainingShadow;
/**
- * An array of web component insertion points to which this element
- * is distributed.
+ * The assigned slot associated with this element.
*/
- nsTArray<nsIContent*> mDestInsertionPoints;
+ RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot;
/**
* XBL binding installed on the element.
diff --git a/dom/base/GroupedSHistory.h b/dom/base/GroupedSHistory.h
index 8c88a0aaf..c5e75d639 100644
--- a/dom/base/GroupedSHistory.h
+++ b/dom/base/GroupedSHistory.h
@@ -7,6 +7,8 @@
#ifndef GroupedSHistory_h
#define GroupedSHistory_h
+#include "nsCOMArray.h"
+#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
#include "nsIFrameLoader.h"
#include "nsIGroupedSHistory.h"
#include "nsIPartialSHistory.h"
diff --git a/dom/base/ImageTracker.cpp b/dom/base/ImageTracker.cpp
index 9fef059bc..d0c231981 100644
--- a/dom/base/ImageTracker.cpp
+++ b/dom/base/ImageTracker.cpp
@@ -8,6 +8,8 @@
* animating */
#include "ImageTracker.h"
+#include "mozilla/Preferences.h"
+#include "nsAppRunner.h" // for XRE_IsContentProcess
namespace mozilla {
namespace dom {
diff --git a/dom/base/ImageTracker.h b/dom/base/ImageTracker.h
index d33dc55f8..f16461192 100644
--- a/dom/base/ImageTracker.h
+++ b/dom/base/ImageTracker.h
@@ -10,6 +10,7 @@
#ifndef mozilla_dom_ImageTracker
#define mozilla_dom_ImageTracker
+#include "imgIRequest.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
diff --git a/dom/base/MutableBlobStorage.h b/dom/base/MutableBlobStorage.h
index fad391b16..ed368e5e6 100644
--- a/dom/base/MutableBlobStorage.h
+++ b/dom/base/MutableBlobStorage.h
@@ -7,6 +7,9 @@
#ifndef mozilla_dom_MutableBlobStorage_h
#define mozilla_dom_MutableBlobStorage_h
+#include "nsCycleCollectionParticipant.h"
+#include "nsThreadUtils.h"
+#include "nsProxyRelease.h"
#include "mozilla/RefPtr.h"
#include "prio.h"
diff --git a/dom/base/MutableBlobStreamListener.cpp b/dom/base/MutableBlobStreamListener.cpp
index 6769ad3e6..afcc04d9f 100644
--- a/dom/base/MutableBlobStreamListener.cpp
+++ b/dom/base/MutableBlobStreamListener.cpp
@@ -5,6 +5,7 @@
#include "MutableBlobStreamListener.h"
#include "MutableBlobStorage.h"
+#include "nsIInputStream.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/NodeInfo.cpp b/dom/base/NodeInfo.cpp
index d32a00fd3..f055dfc75 100644
--- a/dom/base/NodeInfo.cpp
+++ b/dom/base/NodeInfo.cpp
@@ -15,6 +15,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Likely.h"
+#include "mozilla/Unused.h"
#include "nsNodeInfoManager.h"
#include "nsCOMPtr.h"
diff --git a/dom/base/Pose.h b/dom/base/Pose.h
index c7ef1b381..0817c8c96 100644
--- a/dom/base/Pose.h
+++ b/dom/base/Pose.h
@@ -8,6 +8,7 @@
#define mozilla_dom_Pose_h
#include "nsWrapperCache.h"
+#include "mozilla/ErrorResult.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/ShadowRoot.cpp b/dom/base/ShadowRoot.cpp
index 831987a96..c4e56f3fb 100644
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -14,9 +14,9 @@
#include "nsIDOMHTMLElement.h"
#include "nsIStyleSheetLinkingElement.h"
#include "mozilla/dom/Element.h"
-#include "mozilla/dom/HTMLContentElement.h"
-#include "mozilla/dom/HTMLShadowElement.h"
+#include "mozilla/dom/HTMLSlotElement.h"
#include "nsXBLPrototypeBinding.h"
+#include "mozilla/EventDispatcher.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
@@ -27,10 +27,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
DocumentFragment)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPoolHost)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOlderShadow)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mYoungerShadow)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
iter.Next()) {
@@ -38,18 +35,14 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ShadowRoot,
- DocumentFragment)
- if (tmp->mPoolHost) {
- tmp->mPoolHost->RemoveMutationObserver(tmp);
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
+ if (tmp->GetHost()) {
+ tmp->GetHost()->RemoveMutationObserver(tmp);
}
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mPoolHost)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mOlderShadow)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mYoungerShadow)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
tmp->mIdentifierMap.Clear();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRoot)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
@@ -59,14 +52,16 @@ NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
-ShadowRoot::ShadowRoot(nsIContent* aContent,
+ShadowRoot::ShadowRoot(Element* aElement, bool aClosed,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
nsXBLPrototypeBinding* aProtoBinding)
- : DocumentFragment(aNodeInfo), mPoolHost(aContent),
- mProtoBinding(aProtoBinding), mShadowElement(nullptr),
- mInsertionPointChanged(false), mIsComposedDocParticipant(false)
+ : DocumentFragment(aNodeInfo)
+ , mProtoBinding(aProtoBinding)
+ , mInsertionPointChanged(false)
+ , mIsComposedDocParticipant(false)
{
- SetHost(aContent);
+ SetHost(aElement);
+ mMode = aClosed ? ShadowRootMode::Closed : ShadowRootMode::Open;
// Nodes in a shadow tree should never store a value
// in the subtree root pointer, nodes in the shadow tree
@@ -75,29 +70,27 @@ ShadowRoot::ShadowRoot(nsIContent* aContent,
SetFlags(NODE_IS_IN_SHADOW_TREE);
- ExtendedDOMSlots()->mBindingParent = aContent;
+ ExtendedDOMSlots()->mBindingParent = aElement;
ExtendedDOMSlots()->mContainingShadow = this;
// Add the ShadowRoot as a mutation observer on the host to watch
// for mutations because the insertion points in this ShadowRoot
// may need to be updated when the host children are modified.
- mPoolHost->AddMutationObserver(this);
+ GetHost()->AddMutationObserver(this);
}
ShadowRoot::~ShadowRoot()
{
- if (mPoolHost) {
- // mPoolHost may have been unlinked or a new ShadowRoot may have been
- // creating, making this one obsolete.
- mPoolHost->RemoveMutationObserver(this);
+ if (auto* host = GetHost()) {
+ // mHost may have been unlinked or a new ShadowRoot may have been
+ // created, making this one obsolete.
+ host->RemoveMutationObserver(this);
}
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
// nsINode destructor expects mSubtreeRoot == this.
SetSubtreeRootPointer(this);
-
- SetHost(nullptr);
}
JSObject*
@@ -119,12 +112,115 @@ ShadowRoot::FromNode(nsINode* aNode)
}
void
+ShadowRoot::AddSlot(HTMLSlotElement* aSlot)
+{
+ MOZ_ASSERT(aSlot);
+
+ // Note that if name attribute missing, the slot is a default slot.
+ nsAutoString name;
+ aSlot->GetName(name);
+
+ nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.LookupOrAdd(name);
+ MOZ_ASSERT(currentSlots);
+
+ HTMLSlotElement* oldSlot = currentSlots->IsEmpty() ?
+ nullptr : currentSlots->ElementAt(0);
+
+ TreeOrderComparator comparator;
+ currentSlots->InsertElementSorted(aSlot, comparator);
+
+ HTMLSlotElement* currentSlot = currentSlots->ElementAt(0);
+ if (currentSlot != aSlot) {
+ return;
+ }
+
+ bool doEnqueueSlotChange = false;
+ if (oldSlot && oldSlot != currentSlot) {
+ // Move assigned nodes from old slot to new slot.
+ const nsTArray<RefPtr<nsINode>>& assignedNodes = oldSlot->AssignedNodes();
+ while (assignedNodes.Length() > 0) {
+ nsINode* assignedNode = assignedNodes[0];
+
+ oldSlot->RemoveAssignedNode(assignedNode);
+ currentSlot->AppendAssignedNode(assignedNode);
+ doEnqueueSlotChange = true;
+ }
+
+ if (doEnqueueSlotChange) {
+ oldSlot->EnqueueSlotChangeEvent();
+ currentSlot->EnqueueSlotChangeEvent();
+ }
+ } else {
+ // Otherwise add appropriate nodes to this slot from the host.
+ for (nsIContent* child = GetHost()->GetFirstChild();
+ child;
+ child = child->GetNextSibling()) {
+ nsAutoString slotName;
+ child->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
+ if (child->IsSlotable() && slotName.Equals(name)) {
+ currentSlot->AppendAssignedNode(child);
+ doEnqueueSlotChange = true;
+ }
+ }
+
+ if (doEnqueueSlotChange) {
+ currentSlot->EnqueueSlotChangeEvent();
+ }
+ }
+}
+
+void
+ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot)
+{
+ MOZ_ASSERT(aSlot);
+
+ nsAutoString name;
+ aSlot->GetName(name);
+
+ nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.Get(name);
+
+ if (currentSlots) {
+ if (currentSlots->Length() == 1) {
+ MOZ_ASSERT(currentSlots->ElementAt(0) == aSlot);
+ mSlotMap.Remove(name);
+
+ if (aSlot->AssignedNodes().Length() > 0) {
+ aSlot->ClearAssignedNodes();
+ aSlot->EnqueueSlotChangeEvent();
+ }
+ } else {
+ bool doEnqueueSlotChange = false;
+ bool doReplaceSlot = currentSlots->ElementAt(0) == aSlot;
+ currentSlots->RemoveElement(aSlot);
+ HTMLSlotElement* replacementSlot = currentSlots->ElementAt(0);
+
+ // Move assigned nodes from removed slot to the next slot in
+ // tree order with the same name.
+ if (doReplaceSlot) {
+ const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
+ while (assignedNodes.Length() > 0) {
+ nsINode* assignedNode = assignedNodes[0];
+
+ aSlot->RemoveAssignedNode(assignedNode);
+ replacementSlot->AppendAssignedNode(assignedNode);
+ doEnqueueSlotChange = true;
+ }
+
+ if (doEnqueueSlotChange) {
+ aSlot->EnqueueSlotChangeEvent();
+ replacementSlot->EnqueueSlotChangeEvent();
+ }
+ }
+ }
+ }
+}
+
+void
ShadowRoot::StyleSheetChanged()
{
mProtoBinding->FlushSkinSheets();
- nsIPresShell* shell = OwnerDoc()->GetShell();
- if (shell) {
+ if (nsIPresShell* shell = OwnerDoc()->GetShell()) {
OwnerDoc()->BeginUpdate(UPDATE_STYLE);
shell->RecordShadowStyleChange(this);
OwnerDoc()->EndUpdate(UPDATE_STYLE);
@@ -142,16 +238,30 @@ ShadowRoot::InsertSheet(StyleSheet* aSheet,
linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
+ MOZ_DIAGNOSTIC_ASSERT(mProtoBinding->SheetCount() == StyleScope::SheetCount());
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+ // FIXME(emilio, bug 1425759): For now we keep them duplicated, the proto
+ // binding will disappear soon (tm).
+ {
+ size_t i = 0;
+ for (RefPtr<StyleSheet>& sheet : mStyleSheets) {
+ MOZ_DIAGNOSTIC_ASSERT(sheet.get() == mProtoBinding->StyleSheetAt(i++));
+ }
+ }
+#endif
+
// Find the correct position to insert into the style sheet list (must
// be in tree order).
- for (size_t i = 0; i <= mProtoBinding->SheetCount(); i++) {
- if (i == mProtoBinding->SheetCount()) {
+ for (size_t i = 0; i <= SheetCount(); i++) {
+ if (i == SheetCount()) {
+ AppendStyleSheet(*aSheet);
mProtoBinding->AppendStyleSheet(aSheet);
break;
}
- nsINode* sheetOwningNode = mProtoBinding->StyleSheetAt(i)->GetOwnerNode();
+ nsINode* sheetOwningNode = SheetAt(i)->GetOwnerNode();
if (nsContentUtils::PositionIsBefore(aLinkingContent, sheetOwningNode)) {
+ InsertSheetAt(i, *aSheet);
mProtoBinding->InsertStyleSheetAt(i, aSheet);
break;
}
@@ -166,6 +276,7 @@ void
ShadowRoot::RemoveSheet(StyleSheet* aSheet)
{
mProtoBinding->RemoveStyleSheet(aSheet);
+ StyleScope::RemoveSheet(*aSheet);
if (aSheet->IsApplicable()) {
StyleSheetChanged();
@@ -232,238 +343,158 @@ ShadowRoot::GetElementsByClassName(const nsAString& aClasses)
return nsContentUtils::GetElementsByClassName(this, aClasses);
}
-void
-ShadowRoot::AddInsertionPoint(HTMLContentElement* aInsertionPoint)
-{
- TreeOrderComparator comparator;
- mInsertionPoints.InsertElementSorted(aInsertionPoint, comparator);
-}
-
-void
-ShadowRoot::RemoveInsertionPoint(HTMLContentElement* aInsertionPoint)
-{
- mInsertionPoints.RemoveElement(aInsertionPoint);
-}
-
-void
-ShadowRoot::SetYoungerShadow(ShadowRoot* aYoungerShadow)
-{
- mYoungerShadow = aYoungerShadow;
- mYoungerShadow->mOlderShadow = this;
+nsresult
+ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
+{
+ aVisitor.mCanHandle = true;
+ aVisitor.mRootOfClosedTree = IsClosed();
+
+ // https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
+ if (!aVisitor.mEvent->mFlags.mComposed) {
+ nsCOMPtr<nsIContent> originalTarget =
+ do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
+ if (originalTarget->GetContainingShadow() == this) {
+ // If we do stop propagation, we still want to propagate
+ // the event to chrome (nsPIDOMWindow::GetParentTarget()).
+ // The load event is special in that we don't ever propagate it
+ // to chrome.
+ nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
+ EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
+ ? win->GetParentTarget() : nullptr;
+
+ aVisitor.SetParentTarget(parentTarget, true);
+ return NS_OK;
+ }
+ }
- ChangePoolHost(mYoungerShadow->GetShadowElement());
-}
+ nsIContent* shadowHost = GetHost();
+ aVisitor.SetParentTarget(shadowHost, false);
-void
-ShadowRoot::RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
- nsTArray<nsIContent*>& aDestInsertionPoints)
-{
- // Remove the insertion point from the destination insertion points.
- // Also remove all succeeding insertion points because it is no longer
- // possible for the content to be distributed into deeper node trees.
- int32_t index = aDestInsertionPoints.IndexOf(aInsertionPoint);
+ if (aVisitor.mOriginalTargetIsInAnon) {
+ nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
+ if (content && content->GetBindingParent() == shadowHost) {
+ aVisitor.mEventTargetAtParent = shadowHost;
+ }
+ }
- // It's possible that we already removed the insertion point while processing
- // other insertion point removals.
- if (index >= 0) {
- aDestInsertionPoints.SetLength(index);
- }
+ return NS_OK;
}
-void
-ShadowRoot::DistributeSingleNode(nsIContent* aContent)
+const HTMLSlotElement*
+ShadowRoot::AssignSlotFor(nsIContent* aContent)
{
- // Find the insertion point to which the content belongs.
- HTMLContentElement* insertionPoint = nullptr;
- for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
- if (mInsertionPoints[i]->Match(aContent)) {
- if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
- // Node is already matched into the insertion point. We are done.
- return;
- }
-
- // Matching may cause the insertion point to drop fallback content.
- if (mInsertionPoints[i]->MatchedNodes().IsEmpty() &&
- static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
- // This match will cause the insertion point to drop all fallback
- // content and used matched nodes instead. Give up on the optimization
- // and just distribute all nodes.
- DistributeAllNodes();
- return;
- }
- insertionPoint = mInsertionPoints[i];
- break;
- }
+ nsAutoString slotName;
+ // Note that if slot attribute is missing, assign it to the first default
+ // slot, if exists.
+ aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
+ nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(slotName);
+ if (!slots) {
+ return nullptr;
}
- // Find the index into the insertion point.
- if (insertionPoint) {
- nsCOMArray<nsIContent>& matchedNodes = insertionPoint->MatchedNodes();
- // Find the appropriate position in the matched node list for the
- // newly distributed content.
- bool isIndexFound = false;
- MOZ_ASSERT(mPoolHost, "Where did the content come from if there is no pool host?");
- ExplicitChildIterator childIterator(mPoolHost);
- for (uint32_t i = 0; i < matchedNodes.Length(); i++) {
- // Seek through the host's explicit children until the inserted content
- // is found or when the current matched node is reached.
- if (childIterator.Seek(aContent, matchedNodes[i])) {
- // aContent was found before the current matched node.
- insertionPoint->InsertMatchedNode(i, aContent);
- isIndexFound = true;
- break;
+ HTMLSlotElement* slot = slots->ElementAt(0);
+ MOZ_ASSERT(slot);
+
+ // Find the appropriate position in the assigned node list for the
+ // newly assigned content.
+ const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
+ nsIContent* currentContent = GetHost()->GetFirstChild();
+ bool indexFound = false;
+ uint32_t insertionIndex;
+ for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
+ // Seek through the host's explicit children until the
+ // assigned content is found.
+ while (currentContent && currentContent != assignedNodes[i]) {
+ if (currentContent == aContent) {
+ indexFound = true;
+ insertionIndex = i;
}
- }
-
- if (!isIndexFound) {
- // We have still not found an index in the insertion point,
- // thus it must be at the end.
- MOZ_ASSERT(childIterator.Seek(aContent, nullptr),
- "Trying to match a node that is not a candidate to be matched");
- insertionPoint->AppendMatchedNode(aContent);
- }
- // Handle the case where the parent of the insertion point is a ShadowRoot
- // that is projected into the younger ShadowRoot's shadow insertion point.
- // The node distributed into the insertion point must be reprojected
- // to the shadow insertion point.
- if (insertionPoint->GetParent() == this &&
- mYoungerShadow && mYoungerShadow->GetShadowElement()) {
- mYoungerShadow->GetShadowElement()->DistributeSingleNode(aContent);
+ currentContent = currentContent->GetNextSibling();
}
- // Handle the case where the parent of the insertion point has a ShadowRoot.
- // The node distributed into the insertion point must be reprojected to the
- // insertion points of the parent's ShadowRoot.
- ShadowRoot* parentShadow = insertionPoint->GetParent()->GetShadowRoot();
- if (parentShadow) {
- parentShadow->DistributeSingleNode(aContent);
+ if (indexFound) {
+ break;
}
+ }
- // Handle the case where the parent of the insertion point is the <shadow>
- // element. The node distributed into the insertion point must be reprojected
- // into the older ShadowRoot's insertion points.
- if (mShadowElement && mShadowElement == insertionPoint->GetParent()) {
- ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
- if (olderShadow) {
- olderShadow->DistributeSingleNode(aContent);
- }
- }
+ if (indexFound) {
+ slot->InsertAssignedNode(insertionIndex, aContent);
+ } else {
+ slot->AppendAssignedNode(aContent);
}
+
+ return slot;
}
-void
-ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
+const HTMLSlotElement*
+ShadowRoot::UnassignSlotFor(nsIContent* aNode, const nsAString& aSlotName)
{
- // Find insertion point containing the content and remove the node.
- for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
- if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
- // Removing the matched node may cause the insertion point to use
- // fallback content.
- if (mInsertionPoints[i]->MatchedNodes().Length() == 1 &&
- static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
- // Removing the matched node will cause fallback content to be
- // used instead. Give up optimization and distribute all nodes.
- DistributeAllNodes();
- return;
- }
+ // Find the insertion point to which the content belongs. Note that if slot
+ // attribute is missing, unassign it from the first default slot, if exists.
+ nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(aSlotName);
+ if (!slots) {
+ return nullptr;
+ }
- mInsertionPoints[i]->RemoveMatchedNode(aContent);
+ HTMLSlotElement* slot = slots->ElementAt(0);
+ MOZ_ASSERT(slot);
- // Handle the case where the parent of the insertion point is a ShadowRoot
- // that is projected into the younger ShadowRoot's shadow insertion point.
- // The removed node needs to be removed from the shadow insertion point.
- if (mInsertionPoints[i]->GetParent() == this) {
- if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
- mYoungerShadow->GetShadowElement()->RemoveDistributedNode(aContent);
- }
- }
+ if (!slot->AssignedNodes().Contains(aNode)) {
+ return nullptr;
+ }
- // Handle the case where the parent of the insertion point has a ShadowRoot.
- // The removed node needs to be removed from the insertion points of the
- // parent's ShadowRoot.
- ShadowRoot* parentShadow = mInsertionPoints[i]->GetParent()->GetShadowRoot();
- if (parentShadow) {
- parentShadow->RemoveDistributedNode(aContent);
- }
+ slot->RemoveAssignedNode(aNode);
+ return slot;
+}
- // Handle the case where the parent of the insertion point is the <shadow>
- // element. The removed node must be removed from the older ShadowRoot's
- // insertion points.
- if (mShadowElement && mShadowElement == mInsertionPoints[i]->GetParent()) {
- ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
- if (olderShadow) {
- olderShadow->RemoveDistributedNode(aContent);
- }
+bool
+ShadowRoot::MaybeReassignElement(Element* aElement,
+ const nsAttrValue* aOldValue)
+{
+ nsIContent* parent = aElement->GetParent();
+ if (parent && parent == GetHost()) {
+ const HTMLSlotElement* oldSlot = UnassignSlotFor(aElement,
+ aOldValue ? aOldValue->GetStringValue() : EmptyString());
+ const HTMLSlotElement* newSlot = AssignSlotFor(aElement);
+
+ if (oldSlot != newSlot) {
+ if (oldSlot) {
+ oldSlot->EnqueueSlotChangeEvent();
}
-
- break;
+ if (newSlot) {
+ newSlot->EnqueueSlotChangeEvent();
+ }
+ return true;
}
}
+
+ return false;
}
void
-ShadowRoot::DistributeAllNodes()
+ShadowRoot::DistributionChanged()
{
- // Create node pool.
- nsTArray<nsIContent*> nodePool;
-
- // Make sure there is a pool host, an older shadow may not have
- // one if the younger shadow does not have a <shadow> element.
- if (mPoolHost) {
- ExplicitChildIterator childIterator(mPoolHost);
- for (nsIContent* content = childIterator.GetNextChild();
- content;
- content = childIterator.GetNextChild()) {
- nodePool.AppendElement(content);
- }
+ // FIXME(emilio): We could be more granular in a bunch of cases.
+ auto* host = GetHost();
+ if (!host || !host->IsInComposedDoc()) {
+ return;
}
- nsTArray<ShadowRoot*> shadowsToUpdate;
-
- for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
- mInsertionPoints[i]->ClearMatchedNodes();
- // Assign matching nodes from node pool.
- for (uint32_t j = 0; j < nodePool.Length(); j++) {
- if (mInsertionPoints[i]->Match(nodePool[j])) {
- mInsertionPoints[i]->AppendMatchedNode(nodePool[j]);
- nodePool.RemoveElementAt(j--);
- }
- }
-
- // Keep track of instances where the content insertion point is distributed
- // (parent of insertion point has a ShadowRoot).
- nsIContent* insertionParent = mInsertionPoints[i]->GetParent();
- MOZ_ASSERT(insertionParent, "The only way for an insertion point to be in the"
- "mInsertionPoints array is to be a descendant of a"
- "ShadowRoot, in which case, it should have a parent");
-
- // If the parent of the insertion point has a ShadowRoot, the nodes distributed
- // to the insertion point must be reprojected to the insertion points of the
- // parent's ShadowRoot.
- ShadowRoot* parentShadow = insertionParent->GetShadowRoot();
- if (parentShadow && !shadowsToUpdate.Contains(parentShadow)) {
- shadowsToUpdate.AppendElement(parentShadow);
- }
+ auto* shell = OwnerDoc()->GetShell();
+ if (!shell) {
+ return;
}
- // If there is a shadow insertion point in this ShadowRoot, the children
- // of the shadow insertion point needs to be distributed into the insertion
- // points of the older ShadowRoot.
- if (mShadowElement && mOlderShadow) {
- mOlderShadow->DistributeAllNodes();
- }
+ shell->DestroyFramesForAndRestyle(host);
+}
- // If there is a younger ShadowRoot with a shadow insertion point,
- // then the children of this ShadowRoot needs to be distributed to
- // the younger ShadowRoot's shadow insertion point.
- if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
- mYoungerShadow->GetShadowElement()->DistributeAllNodes();
- }
+void
+ShadowRoot::DistributeAllNodes()
+{
+ //XXX Handle <slot>.
- for (uint32_t i = 0; i < shadowsToUpdate.Length(); i++) {
- shadowsToUpdate[i]->DistributeAllNodes();
- }
+ DistributionChanged();
}
void
@@ -507,105 +538,6 @@ ShadowRoot::SetApplyAuthorStyles(bool aApplyAuthorStyles)
}
}
-StyleSheetList*
-ShadowRoot::StyleSheets()
-{
- if (!mStyleSheetList) {
- mStyleSheetList = new ShadowRootStyleSheetList(this);
- }
-
- return mStyleSheetList;
-}
-
-void
-ShadowRoot::SetShadowElement(HTMLShadowElement* aShadowElement)
-{
- // If there is already a shadow element point, remove
- // the projected shadow because it is no longer an insertion
- // point.
- if (mShadowElement) {
- mShadowElement->SetProjectedShadow(nullptr);
- }
-
- if (mOlderShadow) {
- // Nodes for distribution will come from the new shadow element.
- mOlderShadow->ChangePoolHost(aShadowElement);
- }
-
- // Set the new shadow element to project the older ShadowRoot because
- // it is the current shadow insertion point.
- mShadowElement = aShadowElement;
- if (mShadowElement) {
- mShadowElement->SetProjectedShadow(mOlderShadow);
- }
-}
-
-void
-ShadowRoot::ChangePoolHost(nsIContent* aNewHost)
-{
- if (mPoolHost) {
- mPoolHost->RemoveMutationObserver(this);
- }
-
- // Clear the nodes matched to content insertion points
- // because it is no longer relevant.
- for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
- mInsertionPoints[i]->ClearMatchedNodes();
- }
-
- mPoolHost = aNewHost;
- if (mPoolHost) {
- mPoolHost->AddMutationObserver(this);
- }
-}
-
-bool
-ShadowRoot::IsShadowInsertionPoint(nsIContent* aContent)
-{
- if (!aContent) {
- return false;
- }
-
- HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(aContent);
- return shadowElem && shadowElem->IsInsertionPoint();
-}
-
-/**
- * Returns whether the web components pool population algorithm
- * on the host would contain |aContent|. This function ignores
- * insertion points in the pool, thus should only be used to
- * test nodes that have not yet been distributed.
- */
-bool
-ShadowRoot::IsPooledNode(nsIContent* aContent, nsIContent* aContainer,
- nsIContent* aHost)
-{
- if (nsContentUtils::IsContentInsertionPoint(aContent) ||
- IsShadowInsertionPoint(aContent)) {
- // Insertion points never end up in the pool.
- return false;
- }
-
- if (aContainer == aHost &&
- nsContentUtils::IsInSameAnonymousTree(aContainer, aContent)) {
- // Children of the host will end up in the pool. We check to ensure
- // that the content is in the same anonymous tree as the container
- // because anonymous content may report its container as the host
- // but it may not be in the host's child list.
- return true;
- }
-
- if (aContainer) {
- // Fallback content will end up in pool if its parent is a child of the host.
- HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
- return content && content->IsInsertionPoint() &&
- content->MatchedNodes().IsEmpty() &&
- aContainer->GetParentNode() == aHost;
- }
-
- return false;
-}
-
void
ShadowRoot::AttributeChanged(nsIDocument* aDocument,
Element* aElement,
@@ -614,13 +546,26 @@ ShadowRoot::AttributeChanged(nsIDocument* aDocument,
int32_t aModType,
const nsAttrValue* aOldValue)
{
- if (!IsPooledNode(aElement, aElement->GetParent(), mPoolHost)) {
+ if (aNameSpaceID != kNameSpaceID_None || aAttribute != nsGkAtoms::slot) {
return;
}
// Attributes may change insertion point matching, find its new distribution.
- RemoveDistributedNode(aElement);
- DistributeSingleNode(aElement);
+ if (!MaybeReassignElement(aElement, aOldValue)) {
+ return;
+ }
+
+ if (!aElement->IsInComposedDoc()) {
+ return;
+ }
+
+ auto* shell = OwnerDoc()->GetShell();
+ if (!shell) {
+ return;
+ }
+
+ //XXX optimize this!
+ shell->DestroyFramesForAndRestyle(aElement);
}
void
@@ -629,29 +574,10 @@ ShadowRoot::ContentAppended(nsIDocument* aDocument,
nsIContent* aFirstNewContent,
int32_t aNewIndexInContainer)
{
- if (mInsertionPointChanged) {
- DistributeAllNodes();
- mInsertionPointChanged = false;
- return;
- }
-
- // Watch for new nodes added to the pool because the node
- // may need to be added to an insertion point.
- nsIContent* currentChild = aFirstNewContent;
- while (currentChild) {
- // Add insertion point to destination insertion points of fallback content.
- if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
- HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
- if (content->MatchedNodes().IsEmpty()) {
- currentChild->DestInsertionPoints().AppendElement(aContainer);
- }
- }
-
- if (IsPooledNode(currentChild, aContainer, mPoolHost)) {
- DistributeSingleNode(currentChild);
- }
-
- currentChild = currentChild->GetNextSibling();
+ for (nsIContent* content = aFirstNewContent;
+ content;
+ content = content->GetNextSibling()) {
+ ContentInserted(aDocument, aContainer, aFirstNewContent, aNewIndexInContainer);
}
}
@@ -661,24 +587,30 @@ ShadowRoot::ContentInserted(nsIDocument* aDocument,
nsIContent* aChild,
int32_t aIndexInContainer)
{
- if (mInsertionPointChanged) {
- DistributeAllNodes();
- mInsertionPointChanged = false;
+ // Check to ensure that the content is in the same anonymous tree
+ // as the container because anonymous content may report its container
+ // as the host but it may not be in the host's child list.
+ if (!nsContentUtils::IsInSameAnonymousTree(aContainer, aChild)) {
return;
}
- // Watch for new nodes added to the pool because the node
- // may need to be added to an insertion point.
- if (IsPooledNode(aChild, aContainer, mPoolHost)) {
- // Add insertion point to destination insertion points of fallback content.
- if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
- HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
- if (content->MatchedNodes().IsEmpty()) {
- aChild->DestInsertionPoints().AppendElement(aContainer);
- }
+ if (!aChild->IsSlotable()) {
+ return;
+ }
+
+ if (aContainer && aContainer == GetHost()) {
+ if (const HTMLSlotElement* slot = AssignSlotFor(aChild)) {
+ slot->EnqueueSlotChangeEvent();
}
+ return;
+ }
- DistributeSingleNode(aChild);
+ // If parent's root is a shadow root, and parent is a slot whose assigned
+ // nodes is the empty list, then run signal a slot change for parent.
+ HTMLSlotElement* slot = HTMLSlotElement::FromContentOrNull(aContainer);
+ if (slot && slot->GetContainingShadow() == this &&
+ slot->AssignedNodes().IsEmpty()) {
+ slot->EnqueueSlotChangeEvent();
}
}
@@ -689,25 +621,32 @@ ShadowRoot::ContentRemoved(nsIDocument* aDocument,
int32_t aIndexInContainer,
nsIContent* aPreviousSibling)
{
- if (mInsertionPointChanged) {
- DistributeAllNodes();
- mInsertionPointChanged = false;
+ // Check to ensure that the content is in the same anonymous tree
+ // as the container because anonymous content may report its container
+ // as the host but it may not be in the host's child list.
+ if (!nsContentUtils::IsInSameAnonymousTree(aContainer, aChild)) {
+ return;
+ }
+
+ if (!aChild->IsSlotable()) {
return;
}
- // Clear destination insertion points for removed
- // fallback content.
- if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
- HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
- if (content->MatchedNodes().IsEmpty()) {
- aChild->DestInsertionPoints().Clear();
+ if (aContainer && aContainer == GetHost()) {
+ nsAutoString slotName;
+ aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
+ if (const HTMLSlotElement* slot = UnassignSlotFor(aChild, slotName)) {
+ slot->EnqueueSlotChangeEvent();
}
+ return;
}
- // Watch for node that is removed from the pool because
- // it may need to be removed from an insertion point.
- if (IsPooledNode(aChild, aContainer, mPoolHost)) {
- RemoveDistributedNode(aChild);
+ // If parent's root is a shadow root, and parent is a slot whose assigned
+ // nodes is the empty list, then run signal a slot change for parent.
+ HTMLSlotElement* slot = HTMLSlotElement::FromContentOrNull(aContainer);
+ if (slot && slot->GetContainingShadow() == this &&
+ slot->AssignedNodes().IsEmpty()) {
+ slot->EnqueueSlotChangeEvent();
}
}
@@ -717,49 +656,3 @@ ShadowRoot::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
*aResult = nullptr;
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
-
-void
-ShadowRoot::DestroyContent()
-{
- if (mOlderShadow) {
- mOlderShadow->DestroyContent();
- }
- DocumentFragment::DestroyContent();
-}
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList, StyleSheetList,
- mShadowRoot)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList)
-NS_INTERFACE_MAP_END_INHERITING(StyleSheetList)
-
-NS_IMPL_ADDREF_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
-NS_IMPL_RELEASE_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
-
-ShadowRootStyleSheetList::ShadowRootStyleSheetList(ShadowRoot* aShadowRoot)
- : mShadowRoot(aShadowRoot)
-{
- MOZ_COUNT_CTOR(ShadowRootStyleSheetList);
-}
-
-ShadowRootStyleSheetList::~ShadowRootStyleSheetList()
-{
- MOZ_COUNT_DTOR(ShadowRootStyleSheetList);
-}
-
-StyleSheet*
-ShadowRootStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
-{
- aFound = aIndex < mShadowRoot->mProtoBinding->SheetCount();
- if (!aFound) {
- return nullptr;
- }
- return mShadowRoot->mProtoBinding->StyleSheetAt(aIndex);
-}
-
-uint32_t
-ShadowRootStyleSheetList::Length()
-{
- return mShadowRoot->mProtoBinding->SheetCount();
-}
-
diff --git a/dom/base/ShadowRoot.h b/dom/base/ShadowRoot.h
index f84078134..a24c8138e 100644
--- a/dom/base/ShadowRoot.h
+++ b/dom/base/ShadowRoot.h
@@ -8,8 +8,7 @@
#define mozilla_dom_shadowroot_h__
#include "mozilla/dom/DocumentFragment.h"
-#include "mozilla/dom/StyleSheetList.h"
-#include "mozilla/StyleSheet.h"
+#include "mozilla/dom/StyleScope.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIContentInlines.h"
@@ -21,17 +20,17 @@ class nsIContent;
class nsXBLPrototypeBinding;
namespace mozilla {
+
+class EventChainPreVisitor;
+
namespace dom {
class Element;
-class HTMLContentElement;
-class HTMLShadowElement;
-class ShadowRootStyleSheetList;
class ShadowRoot final : public DocumentFragment,
+ public StyleScope,
public nsStubMutationObserver
{
- friend class ShadowRootStyleSheetList;
public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot,
DocumentFragment)
@@ -42,76 +41,86 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
- ShadowRoot(nsIContent* aContent, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
+ ShadowRoot(Element* aElement, bool aClosed,
+ already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
nsXBLPrototypeBinding* aProtoBinding);
+ // Shadow DOM v1
+ Element* Host();
+ ShadowRootMode Mode() const
+ {
+ return mMode;
+ }
+ bool IsClosed() const
+ {
+ return mMode == ShadowRootMode::Closed;
+ }
+
+ // StyleScope.
+ nsINode& AsNode() final
+ {
+ return *this;
+ }
+
+ // [deprecated] Shadow DOM v0
void AddToIdTable(Element* aElement, nsIAtom* aId);
void RemoveFromIdTable(Element* aElement, nsIAtom* aId);
void InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent);
void RemoveSheet(StyleSheet* aSheet);
bool ApplyAuthorStyles();
void SetApplyAuthorStyles(bool aApplyAuthorStyles);
- StyleSheetList* StyleSheets();
- HTMLShadowElement* GetShadowElement() { return mShadowElement; }
+ StyleSheetList* StyleSheets()
+ {
+ return &StyleScope::EnsureDOMStyleSheets();
+ }
/**
- * Sets the current shadow insertion point where the older
- * ShadowRoot will be projected.
+ * Distributes all the explicit children of the pool host to the content
+ * insertion points in this ShadowRoot.
*/
- void SetShadowElement(HTMLShadowElement* aShadowElement);
+ void DistributeAllNodes();
+private:
/**
- * Change the node that populates the distribution pool with
- * its children. This is distinct from the ShadowRoot host described
- * in the specifications. The ShadowRoot host is the element
- * which created this ShadowRoot and does not change. The pool host
- * is the same as the ShadowRoot host if this is the youngest
- * ShadowRoot. If this is an older ShadowRoot, the pool host is
- * the <shadow> element in the younger ShadowRoot (if it exists).
+ * Try to reassign an element to a slot and returns whether the assignment
+ * changed.
*/
- void ChangePoolHost(nsIContent* aNewHost);
+ bool MaybeReassignElement(Element* aElement, const nsAttrValue* aOldValue);
/**
- * Distributes a single explicit child of the pool host to the content
- * insertion points in this ShadowRoot.
+ * Try to assign aContent to a slot in the shadow tree, returns the assigned
+ * slot if found.
*/
- void DistributeSingleNode(nsIContent* aContent);
+ const HTMLSlotElement* AssignSlotFor(nsIContent* aContent);
/**
- * Removes a single explicit child of the pool host from the content
- * insertion points in this ShadowRoot.
+ * Unassign aContent from the assigned slot in the shadow tree, returns the
+ * assigned slot if found.
+ *
+ * Note: slot attribute of aContent may have changed already, so pass slot
+ * name explicity here.
*/
- void RemoveDistributedNode(nsIContent* aContent);
+ const HTMLSlotElement* UnassignSlotFor(nsIContent* aContent,
+ const nsAString& aSlotName);
/**
- * Distributes all the explicit children of the pool host to the content
- * insertion points in this ShadowRoot.
+ * Called when we redistribute content after insertion points have changed.
*/
- void DistributeAllNodes();
+ void DistributionChanged();
- void AddInsertionPoint(HTMLContentElement* aInsertionPoint);
- void RemoveInsertionPoint(HTMLContentElement* aInsertionPoint);
+ bool IsPooledNode(nsIContent* aChild) const;
+
+public:
+ void AddSlot(HTMLSlotElement* aSlot);
+ void RemoveSlot(HTMLSlotElement* aSlot);
- void SetYoungerShadow(ShadowRoot* aYoungerShadow);
- ShadowRoot* GetYoungerShadowRoot() { return mYoungerShadow; }
void SetInsertionPointChanged() { mInsertionPointChanged = true; }
void SetAssociatedBinding(nsXBLBinding* aBinding) { mAssociatedBinding = aBinding; }
- nsISupports* GetParentObject() const { return mPoolHost; }
-
- nsIContent* GetPoolHost() { return mPoolHost; }
- nsTArray<HTMLShadowElement*>& ShadowDescendants() { return mShadowDescendants; }
-
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
- static bool IsPooledNode(nsIContent* aChild, nsIContent* aContainer,
- nsIContent* aHost);
static ShadowRoot* FromNode(nsINode* aNode);
- static bool IsShadowInsertionPoint(nsIContent* aContent);
-
- static void RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
- nsTArray<nsIContent*>& aDestInsertionPoints);
// WebIDL methods.
Element* GetElementById(const nsAString& aElementId);
@@ -124,8 +133,6 @@ public:
GetElementsByClassName(const nsAString& aClasses);
void GetInnerHTML(nsAString& aInnerHTML);
void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
- Element* Host();
- ShadowRoot* GetOlderShadowRoot() { return mOlderShadow; }
void StyleSheetChanged();
bool IsComposedDocParticipant() { return mIsComposedDocParticipant; }
@@ -134,24 +141,17 @@ public:
mIsComposedDocParticipant = aIsComposedDocParticipant;
}
- virtual void DestroyContent() override;
+ nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
+
protected:
virtual ~ShadowRoot();
- // The pool host is the parent of the nodes that will be distributed
- // into the insertion points in this ShadowRoot. See |ChangeShadowRoot|.
- nsCOMPtr<nsIContent> mPoolHost;
-
- // An array of content insertion points that are a descendant of the ShadowRoot
- // sorted in tree order. Insertion points are responsible for notifying
- // the ShadowRoot when they are removed or added as a descendant. The insertion
- // points are kept alive by the parent node, thus weak references are held
- // by the array.
- nsTArray<HTMLContentElement*> mInsertionPoints;
+ ShadowRootMode mMode;
- // An array of the <shadow> elements that are descendant of the ShadowRoot
- // sorted in tree order. Only the first may be a shadow insertion point.
- nsTArray<HTMLShadowElement*> mShadowDescendants;
+ // Map from name of slot to an array of all slots in the shadow DOM with with
+ // the given name. The slots are stored as a weak pointer because the elements
+ // are in the shadow tree and should be kept alive by its parent.
+ nsClassHashtable<nsStringHashKey, nsTArray<mozilla::dom::HTMLSlotElement*>> mSlotMap;
nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
nsXBLPrototypeBinding* mProtoBinding;
@@ -161,19 +161,6 @@ protected:
// owns |mProtoBinding|.
RefPtr<nsXBLBinding> mAssociatedBinding;
- RefPtr<ShadowRootStyleSheetList> mStyleSheetList;
-
- // The current shadow insertion point of this ShadowRoot.
- HTMLShadowElement* mShadowElement;
-
- // The ShadowRoot that was created by the host element before
- // this ShadowRoot was created.
- RefPtr<ShadowRoot> mOlderShadow;
-
- // The ShadowRoot that was created by the host element after
- // this ShadowRoot was created.
- RefPtr<ShadowRoot> mYoungerShadow;
-
// A boolean that indicates that an insertion point was added or removed
// from this ShadowRoot and that the nodes need to be redistributed into
// the insertion points. After this flag is set, nodes will be distributed
@@ -189,28 +176,6 @@ protected:
nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
};
-class ShadowRootStyleSheetList : public StyleSheetList
-{
-public:
- explicit ShadowRootStyleSheetList(ShadowRoot* aShadowRoot);
-
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
-
- virtual nsINode* GetParentObject() const override
- {
- return mShadowRoot;
- }
-
- uint32_t Length() override;
- StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
-
-protected:
- virtual ~ShadowRootStyleSheetList();
-
- RefPtr<ShadowRoot> mShadowRoot;
-};
-
} // namespace dom
} // namespace mozilla
diff --git a/dom/base/StyleScope.cpp b/dom/base/StyleScope.cpp
new file mode 100644
index 000000000..6c708a8ba
--- /dev/null
+++ b/dom/base/StyleScope.cpp
@@ -0,0 +1,27 @@
+/* -*- 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 "StyleScope.h"
+#include "mozilla/dom/StyleSheetList.h"
+
+namespace mozilla {
+namespace dom {
+
+StyleScope::~StyleScope()
+{
+}
+
+StyleSheetList&
+StyleScope::EnsureDOMStyleSheets()
+{
+ if (!mDOMStyleSheets) {
+ mDOMStyleSheets = new StyleSheetList(*this);
+ }
+ return *mDOMStyleSheets;
+}
+
+}
+}
diff --git a/dom/base/StyleScope.h b/dom/base/StyleScope.h
new file mode 100644
index 000000000..c8957b069
--- /dev/null
+++ b/dom/base/StyleScope.h
@@ -0,0 +1,81 @@
+/* -*- 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 mozilla_dom_StyleScope_h__
+#define mozilla_dom_StyleScope_h__
+
+#include "nsTArray.h"
+
+class nsINode;
+
+namespace mozilla {
+class StyleSheet;
+
+namespace dom {
+
+class StyleSheetList;
+
+/**
+ * A class meant to be shared by ShadowRoot and Document, that holds a list of
+ * stylesheets.
+ *
+ * TODO(emilio, bug 1418159): In the future this should hold most of the
+ * relevant style state, this should allow us to fix bug 548397.
+ */
+class StyleScope
+{
+public:
+ virtual nsINode& AsNode() = 0;
+
+ const nsINode& AsNode() const
+ {
+ return const_cast<StyleScope&>(*this).AsNode();
+ }
+
+ StyleSheet* SheetAt(size_t aIndex) const
+ {
+ return mStyleSheets.SafeElementAt(aIndex);
+ }
+
+ size_t SheetCount() const
+ {
+ return mStyleSheets.Length();
+ }
+
+ int32_t IndexOfSheet(const StyleSheet& aSheet) const
+ {
+ return mStyleSheets.IndexOf(&aSheet);
+ }
+
+ void InsertSheetAt(size_t aIndex, StyleSheet& aSheet)
+ {
+ mStyleSheets.InsertElementAt(aIndex, &aSheet);
+ }
+
+ void RemoveSheet(StyleSheet& aSheet)
+ {
+ mStyleSheets.RemoveElement(&aSheet);
+ }
+
+ void AppendStyleSheet(StyleSheet& aSheet)
+ {
+ mStyleSheets.AppendElement(&aSheet);
+ }
+
+ StyleSheetList& EnsureDOMStyleSheets();
+
+ ~StyleScope();
+
+protected:
+ nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
+ RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
+};
+
+}
+
+}
+
+#endif
diff --git a/dom/base/StyleSheetList.cpp b/dom/base/StyleSheetList.cpp
index 7274b5ea5..42db3179d 100644
--- a/dom/base/StyleSheetList.cpp
+++ b/dom/base/StyleSheetList.cpp
@@ -8,6 +8,7 @@
#include "mozilla/CSSStyleSheet.h"
#include "mozilla/dom/StyleSheetListBinding.h"
+#include "nsStubDocumentObserver.h"
namespace mozilla {
namespace dom {
@@ -17,7 +18,8 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(StyleSheetList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheetList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheetList)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
+ NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStyleSheetList)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheetList)
@@ -43,5 +45,24 @@ StyleSheetList::SlowItem(uint32_t aIndex, nsIDOMStyleSheet** aItem)
return NS_OK;
}
+void
+StyleSheetList::NodeWillBeDestroyed(const nsINode* aNode)
+{
+ mStyleScope = nullptr;
+}
+
+StyleSheetList::StyleSheetList(StyleScope& aScope)
+ : mStyleScope(&aScope)
+{
+ mStyleScope->AsNode().AddMutationObserver(this);
+}
+
+StyleSheetList::~StyleSheetList()
+{
+ if (mStyleScope) {
+ mStyleScope->AsNode().RemoveMutationObserver(this);
+ }
+}
+
} // namespace dom
} // namespace mozilla
diff --git a/dom/base/StyleSheetList.h b/dom/base/StyleSheetList.h
index dfedc2214..ea5c33a98 100644
--- a/dom/base/StyleSheetList.h
+++ b/dom/base/StyleSheetList.h
@@ -7,8 +7,10 @@
#ifndef mozilla_dom_StyleSheetList_h
#define mozilla_dom_StyleSheetList_h
+#include "mozilla/dom/StyleScope.h"
#include "nsIDOMStyleSheetList.h"
#include "nsWrapperCache.h"
+#include "nsStubDocumentObserver.h"
class nsINode;
@@ -17,28 +19,54 @@ class StyleSheet;
namespace dom {
-class StyleSheetList : public nsIDOMStyleSheetList
- , public nsWrapperCache
+class StyleSheetList final : public nsIDOMStyleSheetList
+ , public nsWrapperCache
+ , public nsStubDocumentObserver
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheetList)
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(StyleSheetList, nsIDOMStyleSheetList)
+
NS_DECL_NSIDOMSTYLESHEETLIST
+ NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
+
+ explicit StyleSheetList(StyleScope& aScope);
+
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override final;
- virtual nsINode* GetParentObject() const = 0;
+ nsINode* GetParentObject() const
+ {
+ return mStyleScope ? &mStyleScope->AsNode() : nullptr;
+ }
- virtual uint32_t Length() = 0;
- virtual StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
- StyleSheet* Item(uint32_t aIndex)
+ uint32_t Length() const
+ {
+ return mStyleScope ? mStyleScope->SheetCount() : 0;
+ }
+
+ StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) const
+ {
+ if (!mStyleScope) {
+ aFound = false;
+ return nullptr;
+ }
+
+ StyleSheet* sheet = mStyleScope->SheetAt(aIndex);
+ aFound = !!sheet;
+ return sheet;
+ }
+
+ StyleSheet* Item(uint32_t aIndex) const
{
bool dummy = false;
return IndexedGetter(aIndex, dummy);
}
protected:
- virtual ~StyleSheetList() {}
+ virtual ~StyleSheetList();
+
+ StyleScope* mStyleScope; // Weak, cleared on "NodeWillBeDestroyed".
};
} // namespace dom
diff --git a/dom/base/TabGroup.h b/dom/base/TabGroup.h
index f9fa9eec5..c436ce98d 100644
--- a/dom/base/TabGroup.h
+++ b/dom/base/TabGroup.h
@@ -7,10 +7,12 @@
#ifndef TabGroup_h
#define TabGroup_h
+#include "nsIDocument.h"
#include "nsISupports.h"
#include "nsISupportsImpl.h"
#include "nsIPrincipal.h"
#include "nsTHashtable.h"
+#include "nsHashKeys.h"
#include "nsString.h"
#include "mozilla/RefPtr.h"
diff --git a/dom/base/ThirdPartyUtil.cpp b/dom/base/ThirdPartyUtil.cpp
index 61d97f634..37d326dbc 100644
--- a/dom/base/ThirdPartyUtil.cpp
+++ b/dom/base/ThirdPartyUtil.cpp
@@ -10,6 +10,7 @@
#include "nsIChannel.h"
#include "nsIServiceManager.h"
#include "nsIHttpChannelInternal.h"
+#include "nsPIDOMWindow.h"
#include "nsIDOMWindow.h"
#include "nsILoadContext.h"
#include "nsIPrincipal.h"
diff --git a/dom/base/TimeoutHandler.cpp b/dom/base/TimeoutHandler.cpp
index 78c3f16dd..f34275840 100644
--- a/dom/base/TimeoutHandler.cpp
+++ b/dom/base/TimeoutHandler.cpp
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TimeoutHandler.h"
+#include "nsJSUtils.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/TimeoutHandler.h b/dom/base/TimeoutHandler.h
index cb0a0ce94..a80dc2995 100644
--- a/dom/base/TimeoutHandler.h
+++ b/dom/base/TimeoutHandler.h
@@ -7,9 +7,11 @@
#ifndef mozilla_dom_timeout_handler_h
#define mozilla_dom_timeout_handler_h
+#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
#include "nsCOMPtr.h"
#include "nsISupports.h"
#include "nsITimeoutHandler.h"
+#include "nsString.h"
namespace mozilla {
namespace dom {
diff --git a/dom/base/TimerClamping.h b/dom/base/TimerClamping.h
index 2ffd6add5..2bd1f019c 100755
--- a/dom/base/TimerClamping.h
+++ b/dom/base/TimerClamping.h
@@ -7,6 +7,8 @@
#ifndef TimerClamping_h___
#define TimerClamping_h___
+#include <math.h>
+
namespace mozilla {
class TimerClamping
diff --git a/dom/base/crashtests/1419799.html b/dom/base/crashtests/1419799.html
new file mode 100644
index 000000000..b6d34a1a9
--- /dev/null
+++ b/dom/base/crashtests/1419799.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <script>
+ try { o1 = document.createElement('textarea') } catch(e) { }
+ try { o2 = document.createElement('div') } catch(e) { }
+ try { o3 = document.createElement('map') } catch(e) { }
+ try { document.documentElement.appendChild(o2) } catch(e) { }
+ try { o2.appendChild(o1) } catch(e) { }
+ try { document.documentElement.getClientRects() } catch(e) { }
+ try { o4 = o2.attachShadow({ mode: "open" }); } catch(e) { }
+ try { o1.appendChild(o3) } catch(e) { }
+ try { o5 = o3.parentElement } catch(e) { }
+ try { o3.outerHTML = "\n" } catch(e) { }
+ try { o4.prepend("", o5, "") } catch(e) { }
+ </script>
+ </head>
+</html>
diff --git a/dom/base/crashtests/1422931.html b/dom/base/crashtests/1422931.html
new file mode 100644
index 000000000..9f09f41ef
--- /dev/null
+++ b/dom/base/crashtests/1422931.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+<!-- Testing slot element with "dom.webcomponents.enabled" set to false -->
+<slot><div></div></slot>
+</html>
diff --git a/dom/base/crashtests/crashtests.list b/dom/base/crashtests/crashtests.list
index 0fb597b30..40d358b38 100644
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -193,7 +193,7 @@ load 930250.html
load 942979.html
load 973401.html
load 978646.html
-pref(dom.webcomponents.enabled,true) load 1024428-1.html
+pref(dom.webcomponents.enabled,true) load 1024428-1.html # bug 1340009
load 1026714.html
pref(dom.webcomponents.enabled,true) load 1027461-1.html
pref(dom.webcomponents.enabled,true) load 1029710.html
@@ -209,4 +209,6 @@ load 1230422.html
load 1251361.html
load 1304437.html
pref(clipboard.autocopy,true) load 1385272-1.html
-pref(dom.webcomponents.customelements.enabled,true) load 1341693.html
+pref(dom.webcomponents.enabled,true) load 1341693.html
+pref(dom.webcomponents.enabled,true) load 1419799.html
+pref(dom.webcomponents.enabled,false) load 1422931.html
diff --git a/dom/base/moz.build b/dom/base/moz.build
index 75ddefded..5acb49d4e 100755
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -213,6 +213,7 @@ EXPORTS.mozilla.dom += [
'SimpleTreeIterator.h',
'StructuredCloneHolder.h',
'StructuredCloneTags.h',
+ 'StyleScope.h',
'StyleSheetList.h',
'SubtleCrypto.h',
'TabGroup.h',
@@ -225,7 +226,7 @@ EXPORTS.mozilla.dom += [
'WindowOrientationObserver.h',
]
-UNIFIED_SOURCES += [
+SOURCES += [
'AnonymousContent.cpp',
'Attr.cpp',
'BarProps.cpp',
@@ -359,6 +360,7 @@ UNIFIED_SOURCES += [
'ScriptSettings.cpp',
'ShadowRoot.cpp',
'StructuredCloneHolder.cpp',
+ 'StyleScope.cpp',
'StyleSheetList.cpp',
'SubtleCrypto.cpp',
'TabGroup.cpp',
@@ -376,7 +378,7 @@ UNIFIED_SOURCES += [
]
if CONFIG['MOZ_WEBRTC']:
- UNIFIED_SOURCES += [
+ SOURCES += [
'nsDOMDataChannel.cpp',
]
diff --git a/dom/base/nsAttrAndChildArray.cpp b/dom/base/nsAttrAndChildArray.cpp
index 9fd27262b..f8e4c3f18 100644
--- a/dom/base/nsAttrAndChildArray.cpp
+++ b/dom/base/nsAttrAndChildArray.cpp
@@ -382,12 +382,15 @@ nsAttrAndChildArray::AttrAt(uint32_t aPos) const
}
nsresult
-nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
+nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
+ bool* aHadValue)
{
+ *aHadValue = false;
uint32_t i, slotCount = AttrSlotCount();
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
+ *aHadValue = true;
return NS_OK;
}
}
@@ -407,21 +410,22 @@ nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
}
nsresult
-nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue)
+nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName,
+ nsAttrValue& aValue, bool* aHadValue)
{
int32_t namespaceID = aName->NamespaceID();
nsIAtom* localName = aName->NameAtom();
if (namespaceID == kNameSpaceID_None) {
- return SetAndSwapAttr(localName, aValue);
+ return SetAndSwapAttr(localName, aValue, aHadValue);
}
+ *aHadValue = false;
uint32_t i, slotCount = AttrSlotCount();
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
if (ATTRS(mImpl)[i].mName.Equals(localName, namespaceID)) {
ATTRS(mImpl)[i].mName.SetTo(aName);
- ATTRS(mImpl)[i].mValue.Reset();
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
-
+ *aHadValue = true;
return NS_OK;
}
}
@@ -576,10 +580,11 @@ nsAttrAndChildArray::IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID) cons
}
nsresult
-nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
+nsAttrAndChildArray::SetAndSwapMappedAttr(nsIAtom* aLocalName,
nsAttrValue& aValue,
nsMappedAttributeElement* aContent,
- nsHTMLStyleSheet* aSheet)
+ nsHTMLStyleSheet* aSheet,
+ bool* aHadValue)
{
bool willAdd = true;
if (mImpl && mImpl->mMappedAttrs) {
@@ -589,7 +594,7 @@ nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
RefPtr<nsMappedAttributes> mapped =
GetModifiableMapped(aContent, aSheet, willAdd);
- mapped->SetAndTakeAttr(aLocalName, aValue);
+ mapped->SetAndSwapAttr(aLocalName, aValue, aHadValue);
return MakeMappedUnique(mapped);
}
@@ -714,10 +719,19 @@ nsAttrAndChildArray::MappedAttrCount() const
return mImpl && mImpl->mMappedAttrs ? (uint32_t)mImpl->mMappedAttrs->Count() : 0;
}
+nsresult
+nsAttrAndChildArray::ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument)
+{
+ nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet();
+ RefPtr<nsMappedAttributes> mapped = GetModifiableMapped(aContent, sheet, false, 0);
+ return MakeMappedUnique(mapped);
+}
+
nsMappedAttributes*
nsAttrAndChildArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
nsHTMLStyleSheet* aSheet,
- bool aWillAddAttr)
+ bool aWillAddAttr,
+ int32_t aAttrCount)
{
if (mImpl && mImpl->mMappedAttrs) {
return mImpl->mMappedAttrs->Clone(aWillAddAttr);
@@ -727,7 +741,7 @@ nsAttrAndChildArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
nsMapRuleToAttributesFunc mapRuleFunc =
aContent->GetAttributeMappingFunction();
- return new nsMappedAttributes(aSheet, mapRuleFunc);
+ return new (aAttrCount) nsMappedAttributes(aSheet, mapRuleFunc);
}
nsresult
diff --git a/dom/base/nsAttrAndChildArray.h b/dom/base/nsAttrAndChildArray.h
index f34370c43..0ce51c52e 100644
--- a/dom/base/nsAttrAndChildArray.h
+++ b/dom/base/nsAttrAndChildArray.h
@@ -91,8 +91,13 @@ public:
nsCaseTreatment aCaseSensitive) const;
const nsAttrValue* AttrAt(uint32_t aPos) const;
// SetAndSwapAttr swaps the current attribute value with aValue.
- nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
- nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue);
+ // If the attribute was unset, an empty value will be swapped into aValue
+ // and aHadValue will be set to false. Otherwise, aHadValue will be set to
+ // true.
+ nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
+ bool* aHadValue);
+ nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue,
+ bool* aHadValue);
// Remove the attr at position aPos. The value of the attr is placed in
// aValue; any value that was already in aValue is destroyed.
@@ -110,9 +115,14 @@ public:
const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
int32_t IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID = kNameSpaceID_None) const;
- nsresult SetAndTakeMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
+ // SetAndSwapMappedAttr swaps the current attribute value with aValue.
+ // If the attribute was unset, an empty value will be swapped into aValue
+ // and aHadValue will be set to false. Otherwise, aHadValue will be set to
+ // true.
+ nsresult SetAndSwapMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
nsMappedAttributeElement* aContent,
- nsHTMLStyleSheet* aSheet);
+ nsHTMLStyleSheet* aSheet,
+ bool* aHadValue);
nsresult SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet) {
if (!mImpl || !mImpl->mMappedAttrs) {
return NS_OK;
@@ -135,6 +145,9 @@ public:
return MappedAttrCount();
}
+ // Force this to have mapped attributes, even if those attributes are empty.
+ nsresult ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument);
+
private:
nsAttrAndChildArray(const nsAttrAndChildArray& aOther) = delete;
nsAttrAndChildArray& operator=(const nsAttrAndChildArray& aOther) = delete;
@@ -148,7 +161,8 @@ private:
nsMappedAttributes*
GetModifiableMapped(nsMappedAttributeElement* aContent,
nsHTMLStyleSheet* aSheet,
- bool aWillAddAttr);
+ bool aWillAddAttr,
+ int32_t aAttrCount = 1);
nsresult MakeMappedUnique(nsMappedAttributes* aAttributes);
uint32_t AttrSlotsSize() const
diff --git a/dom/base/nsAttrValueOrString.h b/dom/base/nsAttrValueOrString.h
index df0dac17d..1a62a8428 100644
--- a/dom/base/nsAttrValueOrString.h
+++ b/dom/base/nsAttrValueOrString.h
@@ -49,20 +49,13 @@ public:
, mCheapString(nullptr)
{ }
- void TakeParsedValue(nsAttrValue& aValue)
+ void ResetToAttrValue(const nsAttrValue& aValue)
{
- mStoredAttrValue.SwapValueWith(aValue);
- mAttrValue = &mStoredAttrValue;
+ mAttrValue = &aValue;
mStringPtr = nullptr;
+ // No need to touch mCheapString here. If we need to use it, we will reset
+ // it to the rigthe value anyway.
}
- /**
- * If TakeParsedValue has been called, returns the value that it set.
- */
- nsAttrValue* GetStoredAttrValue()
- {
- return mAttrValue == &mStoredAttrValue ? &mStoredAttrValue : nullptr;
- }
- const nsAttrValue* GetAttrValue() { return mAttrValue; }
/**
* Returns a reference to the string value of the contents of this object.
@@ -85,11 +78,24 @@ public:
return aOther.EqualsAsStrings(*mAttrValue);
}
+ /*
+ * Returns true if the value stored is empty
+ */
+ bool IsEmpty() const
+ {
+ if (mStringPtr) {
+ return mStringPtr->IsEmpty();
+ }
+ if (mAttrValue) {
+ return mAttrValue->IsEmptyString();
+ }
+ return true;
+ }
+
protected:
const nsAttrValue* mAttrValue;
mutable const nsAString* mStringPtr;
mutable nsCheapString mCheapString;
- nsAttrValue mStoredAttrValue;
};
#endif // nsAttrValueOrString_h___
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 4f7b71b19..c0d81a41e 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -44,9 +44,8 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/FileSystemSecurity.h"
#include "mozilla/dom/HTMLMediaElement.h"
+#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
-#include "mozilla/dom/HTMLContentElement.h"
-#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/BlobParent.h"
#include "mozilla/dom/Promise.h"
@@ -102,7 +101,9 @@
#include "nsHostObjectProtocolHandler.h"
#include "nsHtml5Module.h"
#include "nsHtml5StringParser.h"
+#include "nsHTMLTags.h"
#include "nsIAddonPolicyService.h"
+#include "nsIAnonymousContentCreator.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsICategoryManager.h"
#include "nsIChannelEventSink.h"
@@ -500,6 +501,8 @@ nsContentUtils::Init()
return NS_OK;
}
+ nsHTMLTags::AddRefTable();
+
sNameSpaceManager = nsNameSpaceManager::GetInstance();
NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY);
@@ -590,7 +593,7 @@ nsContentUtils::Init()
"dom.webcomponents.enabled", false);
Preferences::AddBoolVarCache(&sIsCustomElementsEnabled,
- "dom.webcomponents.customelements.enabled", false);
+ "dom.webcomponents.enabled", false);
Preferences::AddBoolVarCache(&sEncodeDecodeURLHash,
"dom.url.encode_decode_hash", false);
@@ -1926,6 +1929,8 @@ nsContentUtils::Shutdown()
{
sInitialized = false;
+ nsHTMLTags::ReleaseTable();
+
NS_IF_RELEASE(sContentPolicyService);
sTriedToGetContentPolicy = false;
uint32_t i;
@@ -2390,6 +2395,9 @@ nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
bool* aDisconnected)
{
if (aParent1 == aParent2) {
+ // XXX This is odd. aOffset1 and/or aOffset2 may be -1, e.g., it's result
+ // of nsINode::IndexOf(), but this compares such invalid offset with
+ // valid offset.
return aOffset1 < aOffset2 ? -1 :
aOffset1 > aOffset2 ? 1 :
0;
@@ -2440,10 +2448,14 @@ nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
if (!pos1) {
nsINode* child2 = parents2.ElementAt(--pos2);
+ // XXX aOffset1 may be -1 as mentioned above. So, why does this return
+ // it's *before* of the valid DOM point?
return aOffset1 <= parent->IndexOf(child2) ? -1 : 1;
}
nsINode* child1 = parents1.ElementAt(--pos1);
+ // XXX aOffset2 may be -1 as mentioned above. So, why does this return it's
+ // *after* of the valid DOM point?
return parent->IndexOf(child1) < aOffset2 ? -1 : 1;
}
@@ -4943,17 +4955,7 @@ nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode,
return aContent->GetBindingParent() == nullptr;
}
- const nsIContent* nodeAsContent = static_cast<const nsIContent*>(aNode);
-
- // For nodes in a shadow tree, it is insufficient to simply compare
- // the binding parent because a node may host multiple ShadowRoots,
- // thus nodes in different shadow tree may have the same binding parent.
- if (aNode->IsInShadowTree()) {
- return nodeAsContent->GetContainingShadow() ==
- aContent->GetContainingShadow();
- }
-
- return nodeAsContent->GetBindingParent() == aContent->GetBindingParent();
+ return aNode->AsContent()->GetBindingParent() == aContent->GetBindingParent();
}
class AnonymousContentDestroyer : public Runnable {
@@ -7015,25 +7017,11 @@ nsContentUtils::GetHTMLEditor(nsPresContext* aPresContext)
return editor;
}
-bool
-nsContentUtils::IsContentInsertionPoint(nsIContent* aContent)
-{
- // Check if the content is a XBL insertion point.
- if (aContent->IsActiveChildrenElement()) {
- return true;
- }
-
- // Check if the content is a web components content insertion point.
- HTMLContentElement* contentElement =
- HTMLContentElement::FromContent(aContent);
- return contentElement && contentElement->IsInsertionPoint();
-}
-
// static
bool
nsContentUtils::HasDistributedChildren(nsIContent* aContent)
{
- if (!aContent) {
+ if (!aContent || !nsDocument::IsWebComponentsEnabled(aContent)) {
return false;
}
@@ -7043,26 +7031,11 @@ nsContentUtils::HasDistributedChildren(nsIContent* aContent)
return true;
}
- ShadowRoot* shadow = ShadowRoot::FromNode(aContent);
- if (shadow) {
- // Children of a shadow root are distributed to
- // the shadow insertion point of the younger shadow root.
- return shadow->GetYoungerShadowRoot();
- }
-
- HTMLShadowElement* shadowEl = HTMLShadowElement::FromContent(aContent);
- if (shadowEl && shadowEl->IsInsertionPoint()) {
- // Children of a shadow insertion points are distributed
- // to the insertion points in the older shadow root.
- return shadowEl->GetOlderShadowRoot();
- }
-
- HTMLContentElement* contentEl = HTMLContentElement::FromContent(aContent);
- if (contentEl && contentEl->IsInsertionPoint()) {
- // Children of a content insertion point are distributed to the
- // content insertion point if the content insertion point does
- // not match any nodes (fallback content).
- return contentEl->MatchedNodes().IsEmpty();
+ HTMLSlotElement* slotEl = HTMLSlotElement::FromContent(aContent);
+ if (slotEl && slotEl->GetContainingShadow()) {
+ // Children of a slot are rendered if the slot does not have any assigned
+ // nodes (fallback content).
+ return slotEl->AssignedNodes().IsEmpty();
}
return false;
@@ -9675,35 +9648,6 @@ nsContentUtils::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
aDefinition);
}
-/* static */ void
-nsContentUtils::GetCustomPrototype(nsIDocument* aDoc,
- int32_t aNamespaceID,
- nsIAtom* aAtom,
- JS::MutableHandle<JSObject*> aPrototype)
-{
- MOZ_ASSERT(aDoc);
-
- // To support imported document.
- nsCOMPtr<nsIDocument> doc = aDoc->MasterDocument();
-
- if (aNamespaceID != kNameSpaceID_XHTML ||
- !doc->GetDocShell()) {
- return;
- }
-
- nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow());
- if (!window) {
- return;
- }
-
- RefPtr<CustomElementRegistry> registry(window->CustomElements());
- if (!registry) {
- return;
- }
-
- return registry->GetCustomPrototype(aAtom, aPrototype);
-}
-
/* static */ bool
nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel)
{
@@ -9837,6 +9781,24 @@ nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel)
return reloadSucceeded;
}
+/* static */ void
+nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
+ nsIDocument* aDocument,
+ nsTArray<nsIContent*>& aElements)
+{
+ MOZ_ASSERT(aDocument);
+
+ // XXXheycam This probably needs to find the nsCanvasFrame's NAC too.
+ if (nsIPresShell* presShell = aDocument->GetShell()) {
+ if (nsIFrame* scrollFrame = presShell->GetRootScrollFrame()) {
+ nsIAnonymousContentCreator* creator = do_QueryFrame(scrollFrame);
+ MOZ_ASSERT(creator,
+ "scroll frame should always implement nsIAnonymousContentCreator");
+ creator->AppendAnonymousContentTo(aElements, 0);
+ }
+ }
+}
+
/* static */ bool
nsContentUtils::IsLocalRefURL(const nsString& aString)
{
@@ -9852,3 +9814,16 @@ nsContentUtils::IsLocalRefURL(const nsString& aString)
return false;
}
+
+/* static */ Element*
+nsContentUtils::GetClosestNonNativeAnonymousAncestor(Element* aElement)
+{
+ MOZ_ASSERT(aElement);
+ MOZ_ASSERT(aElement->IsNativeAnonymous());
+
+ Element* e = aElement;
+ while (e && e->IsNativeAnonymous()) {
+ e = e->GetParentElement();
+ }
+ return e;
+}
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 64f7485cb..b58b0e0e3 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -339,6 +339,13 @@ public:
* NOTE! If the two nodes aren't in the same connected subtree,
* the result is 1, and the optional aDisconnected parameter
* is set to true.
+ *
+ * XXX aOffset1 and aOffset2 should be uint32_t since valid offset value is
+ * between 0 - UINT32_MAX. However, these methods work even with
+ * negative offset values! E.g., when aOffset1 is -1 and aOffset is 0,
+ * these methods return -1. Some root callers depend on this behavior.
+ * On the other hand, nsINode can have ATTRCHILD_ARRAY_MAX_CHILD_COUN
+ * (0x3FFFFF) at most. Therefore, they can be int32_t for now.
*/
static int32_t ComparePoints(nsINode* aParent1, int32_t aOffset1,
nsINode* aParent2, int32_t aOffset2,
@@ -582,7 +589,7 @@ public:
/**
* Returns true if |aName| is a valid name to be registered via
- * document.registerElement.
+ * customElements.define.
*/
static bool IsCustomElementName(nsIAtom* aName);
@@ -2408,18 +2415,6 @@ public:
static mozilla::LogModule* DOMDumpLog();
/**
- * Returns whether a content is an insertion point for XBL
- * bindings or web components ShadowRoot. In web components,
- * this corresponds to a <content> element that participates
- * in node distribution. In XBL this corresponds to an
- * <xbl:children> element in anonymous content.
- *
- * @param aContent The content to test for being an insertion point.
- */
- static bool IsContentInsertionPoint(nsIContent* aContent);
-
-
- /**
* Returns whether the children of the provided content are
* nodes that are distributed to Shadow DOM insertion points.
*/
@@ -2735,14 +2730,19 @@ public:
mozilla::dom::LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs = nullptr,
mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
- static void GetCustomPrototype(nsIDocument* aDoc,
- int32_t aNamespaceID,
- nsIAtom* aAtom,
- JS::MutableHandle<JSObject*> prototype);
-
static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel);
/**
+ * Appends all "document level" native anonymous content subtree roots for
+ * aDocument to aElements. Document level NAC subtrees are those created
+ * by ancestor frames of the document element's primary frame, such as
+ * the scrollbar elements created by the root scroll frame.
+ */
+ static void AppendDocumentLevelNativeAnonymousContentTo(
+ nsIDocument* aDocument,
+ nsTArray<nsIContent*>& aElements);
+
+ /**
* Detect whether a string is a (CSS) local-url.
* https://drafts.csswg.org/css-values/#local-urls
*/
@@ -2752,6 +2752,12 @@ public:
static bool
IsWebComponentsEnabled() { return sIsWebComponentsEnabled; }
+ /**
+ * Walks up the tree from aElement until it finds an element that is
+ * not native anonymous content. aElement must be NAC itself.
+ */
+ static Element* GetClosestNonNativeAnonymousAncestor(Element* aElement);
+
static bool
IsCustomElementsEnabled() { return sIsCustomElementsEnabled; }
diff --git a/dom/base/nsDOMAttributeMap.cpp b/dom/base/nsDOMAttributeMap.cpp
index 2a90df7e4..29a4a6349 100644
--- a/dom/base/nsDOMAttributeMap.cpp
+++ b/dom/base/nsDOMAttributeMap.cpp
@@ -524,3 +524,9 @@ nsDOMAttributeMap::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return NamedNodeMapBinding::Wrap(aCx, this, aGivenProto);
}
+
+DocGroup*
+nsDOMAttributeMap::GetDocGroup() const
+{
+ return mContent ? mContent->OwnerDoc()->GetDocGroup() : nullptr;
+}
diff --git a/dom/base/nsDOMAttributeMap.h b/dom/base/nsDOMAttributeMap.h
index 31eb701e3..d73d1c3b6 100644
--- a/dom/base/nsDOMAttributeMap.h
+++ b/dom/base/nsDOMAttributeMap.h
@@ -22,6 +22,11 @@
class nsIAtom;
class nsIDocument;
+namespace mozilla {
+namespace dom {
+class DocGroup;
+} // namespace dom
+} // namespace mozilla
/**
* Structure used as a key for caching Attrs in nsDOMAttributeMap's mAttributeCache.
@@ -87,6 +92,7 @@ class nsDOMAttributeMap final : public nsIDOMMozNamedAttrMap
{
public:
typedef mozilla::dom::Attr Attr;
+ typedef mozilla::dom::DocGroup DocGroup;
typedef mozilla::dom::Element Element;
typedef mozilla::ErrorResult ErrorResult;
@@ -135,6 +141,7 @@ public:
return mContent;
}
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+ DocGroup* GetDocGroup() const;
// WebIDL
Attr* GetNamedItem(const nsAString& aAttrName);
diff --git a/dom/base/nsDOMMutationObserver.cpp b/dom/base/nsDOMMutationObserver.cpp
index 4c4731c11..1f8e8f6a8 100644
--- a/dom/base/nsDOMMutationObserver.cpp
+++ b/dom/base/nsDOMMutationObserver.cpp
@@ -7,11 +7,13 @@
#include "nsDOMMutationObserver.h"
#include "mozilla/AnimationTarget.h"
+#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/Maybe.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/KeyframeEffectReadOnly.h"
+#include "mozilla/dom/DocGroup.h"
#include "nsContentUtils.h"
#include "nsCSSPseudoElements.h"
@@ -29,6 +31,9 @@ using mozilla::dom::TreeOrderComparator;
using mozilla::dom::Animation;
using mozilla::dom::Element;
+using namespace mozilla;
+using namespace mozilla::dom;
+
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>*
nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
@@ -609,6 +614,28 @@ public:
}
};
+/* static */ void
+nsDOMMutationObserver::QueueMutationObserverMicroTask()
+{
+ CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
+ if (!ccjs) {
+ return;
+ }
+
+ RefPtr<MutationObserverMicroTask> momt =
+ new MutationObserverMicroTask();
+ ccjs->DispatchMicroTaskRunnable(momt.forget());
+}
+
+void
+nsDOMMutationObserver::HandleMutations(mozilla::AutoSlowOperation& aAso)
+{
+ if (sScheduledMutationObservers ||
+ mozilla::dom::DocGroup::sPendingDocGroups) {
+ HandleMutationsInternal(aAso);
+ }
+}
+
void
nsDOMMutationObserver::RescheduleForRun()
{
@@ -887,7 +914,23 @@ nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso)
{
nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
- while (sScheduledMutationObservers) {
+ // Let signalList be a copy of unit of related similar-origin browsing
+ // contexts' signal slot list.
+ nsTArray<RefPtr<HTMLSlotElement>> signalList;
+ if (DocGroup::sPendingDocGroups) {
+ for (uint32_t i = 0; i < DocGroup::sPendingDocGroups->Length(); ++i) {
+ DocGroup* docGroup = DocGroup::sPendingDocGroups->ElementAt(i);
+ signalList.AppendElements(docGroup->SignalSlotList());
+
+ // Empty unit of related similar-origin browsing contexts' signal slot
+ // list.
+ docGroup->ClearSignalSlotList();
+ }
+ delete DocGroup::sPendingDocGroups;
+ DocGroup::sPendingDocGroups = nullptr;
+ }
+
+ if (sScheduledMutationObservers) {
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* observers =
sScheduledMutationObservers;
sScheduledMutationObservers = nullptr;
@@ -917,6 +960,11 @@ nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso)
delete suppressedObservers;
suppressedObservers = nullptr;
}
+
+ // Fire slotchange event for each slot in signalList.
+ for (uint32_t i = 0; i < signalList.Length(); ++i) {
+ signalList[i]->FireSlotChangeEvent();
+ }
}
nsDOMMutationRecord*
diff --git a/dom/base/nsDOMMutationObserver.h b/dom/base/nsDOMMutationObserver.h
index a8babc603..d6bdfb3e0 100644
--- a/dom/base/nsDOMMutationObserver.h
+++ b/dom/base/nsDOMMutationObserver.h
@@ -552,12 +552,9 @@ public:
}
// static methods
- static void HandleMutations(mozilla::AutoSlowOperation& aAso)
- {
- if (sScheduledMutationObservers) {
- HandleMutationsInternal(aAso);
- }
- }
+ static void QueueMutationObserverMicroTask();
+
+ static void HandleMutations(mozilla::AutoSlowOperation& aAso);
static bool AllScheduledMutationObserversAreSuppressed()
{
diff --git a/dom/base/nsDOMTokenList.cpp b/dom/base/nsDOMTokenList.cpp
index 39ff60e12..961beb50e 100644
--- a/dom/base/nsDOMTokenList.cpp
+++ b/dom/base/nsDOMTokenList.cpp
@@ -366,6 +366,12 @@ nsDOMTokenList::Stringify(nsAString& aResult)
mElement->GetAttr(kNameSpaceID_None, mAttrAtom, aResult);
}
+DocGroup*
+nsDOMTokenList::GetDocGroup() const
+{
+ return mElement ? mElement->OwnerDoc()->GetDocGroup() : nullptr;
+}
+
JSObject*
nsDOMTokenList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
{
diff --git a/dom/base/nsDOMTokenList.h b/dom/base/nsDOMTokenList.h
index e44e042d5..0b3f70319 100644
--- a/dom/base/nsDOMTokenList.h
+++ b/dom/base/nsDOMTokenList.h
@@ -22,7 +22,9 @@
namespace mozilla {
class ErrorResult;
-
+namespace dom {
+class DocGroup;
+} // namespace dom
} // namespace mozilla
class nsAttrValue;
@@ -35,6 +37,7 @@ class nsDOMTokenList : public nsISupports,
{
protected:
typedef mozilla::dom::Element Element;
+ typedef mozilla::dom::DocGroup DocGroup;
typedef nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace>
WhitespaceTokenizer;
@@ -52,6 +55,8 @@ public:
return mElement;
}
+ DocGroup* GetDocGroup() const;
+
uint32_t Length();
void Item(uint32_t aIndex, nsAString& aResult)
{
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp
index 2ab5937ac..a923e8f70 100644
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3473,7 +3473,7 @@ nsDOMWindowUtils::AddSheet(nsIDOMStyleSheet *aSheet, uint32_t aSheetType)
nsIDocument::additionalSheetType type = convertSheetType(aSheetType);
RefPtr<CSSStyleSheet> sheet = do_QueryObject(aSheet);
NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
- if (sheet->GetOwningDocument()) {
+ if (sheet->GetAssociatedDocument()) {
return NS_ERROR_INVALID_ARG;
}
return doc->AddAdditionalStyleSheet(type, sheet);
@@ -3657,11 +3657,11 @@ nsDOMWindowUtils::GetOMTAStyle(nsIDOMElement* aElement,
RefPtr<nsROCSSPrimitiveValue> cssValue = nullptr;
nsIFrame* frame = element->GetPrimaryFrame();
- if (frame && !aPseudoElement.IsEmpty()) {
+ if (!aPseudoElement.IsEmpty()) {
if (aPseudoElement.EqualsLiteral("::before")) {
- frame = nsLayoutUtils::GetBeforeFrame(frame);
+ frame = nsLayoutUtils::GetBeforeFrame(element);
} else if (aPseudoElement.EqualsLiteral("::after")) {
- frame = nsLayoutUtils::GetAfterFrame(frame);
+ frame = nsLayoutUtils::GetAfterFrame(element);
} else {
return NS_ERROR_INVALID_ARG;
}
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index b05bf827b..7b280a188 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -116,7 +116,6 @@
#include "nsBidiUtils.h"
-#include "nsIParserService.h"
#include "nsContentCreatorFunctions.h"
#include "nsIScriptContext.h"
@@ -571,78 +570,6 @@ struct nsRadioGroupStruct
bool mGroupSuffersFromValueMissing;
};
-
-nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument *aDocument)
-{
- mLength = -1;
- // Not reference counted to avoid circular references.
- // The document will tell us when its going away.
- mDocument = aDocument;
- mDocument->AddObserver(this);
-}
-
-nsDOMStyleSheetList::~nsDOMStyleSheetList()
-{
- if (mDocument) {
- mDocument->RemoveObserver(this);
- }
-}
-
-NS_IMPL_ISUPPORTS_INHERITED(nsDOMStyleSheetList, StyleSheetList,
- nsIDocumentObserver,
- nsIMutationObserver)
-
-uint32_t
-nsDOMStyleSheetList::Length()
-{
- if (!mDocument) {
- return 0;
- }
-
- // XXX Find the number and then cache it. We'll use the
- // observer notification to figure out if new ones have
- // been added or removed.
- if (-1 == mLength) {
- mLength = mDocument->GetNumberOfStyleSheets();
- }
- return mLength;
-}
-
-StyleSheet*
-nsDOMStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
-{
- if (!mDocument || aIndex >= (uint32_t)mDocument->GetNumberOfStyleSheets()) {
- aFound = false;
- return nullptr;
- }
- aFound = true;
- return mDocument->GetStyleSheetAt(aIndex);
-}
-
-void
-nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode)
-{
- mDocument = nullptr;
-}
-
-void
-nsDOMStyleSheetList::StyleSheetAdded(StyleSheet* aStyleSheet,
- bool aDocumentSheet)
-{
- if (aDocumentSheet && -1 != mLength) {
- mLength++;
- }
-}
-
-void
-nsDOMStyleSheetList::StyleSheetRemoved(StyleSheet* aStyleSheet,
- bool aDocumentSheet)
-{
- if (aDocumentSheet && -1 != mLength) {
- mLength--;
- }
-}
-
// nsOnloadBlocker implementation
NS_IMPL_ISUPPORTS(nsOnloadBlocker, nsIRequest)
@@ -1200,10 +1127,10 @@ nsDOMStyleSheetSetList::EnsureFresh()
// no document, for sure
}
- int32_t count = mDocument->GetNumberOfStyleSheets();
+ size_t count = mDocument->SheetCount();
nsAutoString title;
- for (int32_t index = 0; index < count; index++) {
- StyleSheet* sheet = mDocument->GetStyleSheetAt(index);
+ for (size_t index = 0; index < count; index++) {
+ StyleSheet* sheet = mDocument->SheetAt(index);
NS_ASSERTION(sheet, "Null sheet in sheet list!");
// XXXheycam ServoStyleSheets don't expose their title yet.
if (sheet->IsServo()) {
@@ -1333,6 +1260,10 @@ nsIDocument::nsIDocument()
{
SetIsInDocument();
+ // Set this when document is created and value stays the same for the lifetime
+ // of the document.
+ mIsWebComponentsEnabled = nsContentUtils::IsWebComponentsEnabled();
+
PR_INIT_CLIST(&mDOMMediaQueryLists);
}
@@ -1452,11 +1383,11 @@ nsDocument::~nsDocument()
// Let the stylesheets know we're going away
for (StyleSheet* sheet : mStyleSheets) {
- sheet->SetOwningDocument(nullptr);
+ sheet->ClearAssociatedDocument();
}
for (auto& sheets : mAdditionalSheets) {
for (StyleSheet* sheet : sheets) {
- sheet->SetOwningDocument(nullptr);
+ sheet->ClearAssociatedDocument();
}
}
if (mAttrStyleSheet) {
@@ -2113,7 +2044,7 @@ nsDocument::RemoveDocStyleSheetsFromStyleSets()
{
// The stylesheets should forget us
for (StyleSheet* sheet : Reversed(mStyleSheets)) {
- sheet->SetOwningDocument(nullptr);
+ sheet->ClearAssociatedDocument();
if (sheet->IsApplicable()) {
nsCOMPtr<nsIPresShell> shell = GetShell();
@@ -2132,7 +2063,7 @@ nsDocument::RemoveStyleSheetsFromStyleSets(
{
// The stylesheets should forget us
for (StyleSheet* sheet : Reversed(aSheets)) {
- sheet->SetOwningDocument(nullptr);
+ sheet->ClearAssociatedDocument();
if (sheet->IsApplicable()) {
nsCOMPtr<nsIPresShell> shell = GetShell();
@@ -2311,6 +2242,29 @@ WarnIfSandboxIneffective(nsIDocShell* aDocShell,
}
}
+bool
+nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
+{
+ if (!nsContentUtils::IsWebComponentsEnabled()) {
+ return false;
+ }
+
+ JS::Rooted<JSObject*> obj(aCx, aObject);
+
+ JSAutoCompartment ac(aCx, obj);
+ JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
+ nsCOMPtr<nsPIDOMWindowInner> window =
+ do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
+
+ nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
+ if (doc && doc->IsStyledByServo()) {
+ NS_WARNING("stylo: Web Components not supported yet");
+ return false;
+ }
+
+ return true;
+}
+
nsresult
nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
nsILoadGroup* aLoadGroup,
@@ -3927,24 +3881,6 @@ nsDocument::AddOnDemandBuiltInUASheet(StyleSheet* aSheet)
NotifyStyleSheetAdded(aSheet, false);
}
-int32_t
-nsDocument::GetNumberOfStyleSheets() const
-{
- return mStyleSheets.Length();
-}
-
-StyleSheet*
-nsDocument::GetStyleSheetAt(int32_t aIndex) const
-{
- return mStyleSheets.SafeElementAt(aIndex, nullptr);
-}
-
-int32_t
-nsDocument::GetIndexOfStyleSheet(const StyleSheet* aSheet) const
-{
- return mStyleSheets.IndexOf(aSheet);
-}
-
void
nsDocument::AddStyleSheetToStyleSets(StyleSheet* aSheet)
{
@@ -4007,7 +3943,7 @@ nsDocument::AddStyleSheet(StyleSheet* aSheet)
{
NS_PRECONDITION(aSheet, "null arg");
mStyleSheets.AppendElement(aSheet);
- aSheet->SetOwningDocument(this);
+ aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
if (aSheet->IsApplicable()) {
AddStyleSheetToStyleSets(aSheet);
@@ -4044,7 +3980,7 @@ nsDocument::RemoveStyleSheet(StyleSheet* aSheet)
NotifyStyleSheetRemoved(aSheet, true);
}
- aSheet->SetOwningDocument(nullptr);
+ aSheet->ClearAssociatedDocument();
}
void
@@ -4072,7 +4008,7 @@ nsDocument::UpdateStyleSheets(nsTArray<RefPtr<StyleSheet>>& aOldSheets,
StyleSheet* newSheet = aNewSheets[i];
if (newSheet) {
mStyleSheets.InsertElementAt(oldIndex, newSheet);
- newSheet->SetOwningDocument(this);
+ newSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
if (newSheet->IsApplicable()) {
AddStyleSheetToStyleSets(newSheet);
}
@@ -4085,13 +4021,13 @@ nsDocument::UpdateStyleSheets(nsTArray<RefPtr<StyleSheet>>& aOldSheets,
}
void
-nsDocument::InsertStyleSheetAt(StyleSheet* aSheet, int32_t aIndex)
+nsDocument::InsertStyleSheetAt(StyleSheet* aSheet, size_t aIndex)
{
- NS_PRECONDITION(aSheet, "null ptr");
+ MOZ_ASSERT(aSheet);
mStyleSheets.InsertElementAt(aIndex, aSheet);
- aSheet->SetOwningDocument(this);
+ aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
if (aSheet->IsApplicable()) {
AddStyleSheetToStyleSets(aSheet);
@@ -4216,7 +4152,7 @@ nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType,
nsresult rv = loader->LoadSheetSync(aSheetURI, parsingMode, true, &sheet);
NS_ENSURE_SUCCESS(rv, rv);
- sheet->SetOwningDocument(this);
+ sheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
MOZ_ASSERT(sheet->IsApplicable());
return AddAdditionalStyleSheet(aType, sheet);
@@ -4274,7 +4210,7 @@ nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheet
NotifyStyleSheetRemoved(sheetRef, false);
EndUpdate(UPDATE_STYLE);
- sheetRef->SetOwningDocument(nullptr);
+ sheetRef->ClearAssociatedDocument();
}
}
@@ -5353,29 +5289,18 @@ bool IsLowercaseASCII(const nsAString& aValue)
return true;
}
-already_AddRefed<mozilla::dom::CustomElementRegistry>
-nsDocument::GetCustomElementRegistry()
+// We only support pseudo-elements with two colons in this function.
+static CSSPseudoElementType
+GetPseudoElementType(const nsString& aString, ErrorResult& aRv)
{
- nsAutoString contentType;
- GetContentType(contentType);
- if (!IsHTMLDocument() &&
- !contentType.EqualsLiteral("application/xhtml+xml")) {
- return nullptr;
+ MOZ_ASSERT(!aString.IsEmpty(), "GetPseudoElementType aString should be non-null");
+ if (aString.Length() <= 2 || aString[0] != ':' || aString[1] != ':') {
+ aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+ return CSSPseudoElementType::NotPseudo;
}
-
- nsCOMPtr<nsPIDOMWindowInner> window(
- do_QueryInterface(mScriptGlobalObject ? mScriptGlobalObject
- : GetScopeObject()));
- if (!window) {
- return nullptr;
- }
-
- RefPtr<CustomElementRegistry> registry = window->CustomElements();
- if (!registry) {
- return nullptr;
- }
-
- return registry.forget();
+ nsCOMPtr<nsIAtom> pseudo = NS_Atomize(Substring(aString, 1));
+ return nsCSSPseudoElements::GetPseudoType(pseudo,
+ nsCSSProps::EnabledState::eInUASheets);
}
already_AddRefed<Element>
@@ -5395,10 +5320,36 @@ nsDocument::CreateElement(const nsAString& aTagName,
}
const nsString* is = nullptr;
+ CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo;
+ if (aOptions.IsElementCreationOptions()) {
+ const ElementCreationOptions& options =
+ aOptions.GetAsElementCreationOptions();
+
+ if (CustomElementRegistry::IsCustomElementEnabled() &&
+ options.mIs.WasPassed()) {
+ is = &options.mIs.Value();
+ }
+
+ // Check 'pseudo' and throw an exception if it's not one allowed
+ // with CSS_PSEUDO_ELEMENT_IS_JS_CREATED_NAC.
+ if (options.mPseudo.WasPassed()) {
+ pseudoType = GetPseudoElementType(options.mPseudo.Value(), rv);
+ if (rv.Failed() ||
+ pseudoType == CSSPseudoElementType::NotPseudo ||
+ !nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(pseudoType)) {
+ rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+ return nullptr;
+ }
+ }
+ }
RefPtr<Element> elem = CreateElem(
needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is);
+ if (pseudoType != CSSPseudoElementType::NotPseudo) {
+ elem->SetPseudoElementType(pseudoType);
+ }
+
if (is) {
elem->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true);
}
@@ -5413,8 +5364,8 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
{
*aReturn = nullptr;
ElementCreationOptionsOrString options;
- options.SetAsString();
+ options.SetAsString();
ErrorResult rv;
nsCOMPtr<Element> element =
CreateElementNS(aNamespaceURI, aQualifiedName, options, rv);
@@ -5439,6 +5390,13 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
}
const nsString* is = nullptr;
+ if (CustomElementRegistry::IsCustomElementEnabled() &&
+ aOptions.IsElementCreationOptions()) {
+ const ElementCreationOptions& options = aOptions.GetAsElementCreationOptions();
+ if (options.mIs.WasPassed()) {
+ is = &options.mIs.Value();
+ }
+ }
nsCOMPtr<Element> element;
rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
@@ -5647,278 +5605,9 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
}
bool
-nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
+nsDocument::IsWebComponentsEnabled(const nsINode* aNode)
{
- JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
-
- JS::Rooted<JSObject*> global(aCx,
- JS_GetGlobalForObject(aCx, &args.callee()));
- RefPtr<nsGlobalWindow> window;
- UNWRAP_OBJECT(Window, global, window);
- MOZ_ASSERT(window, "Should have a non-null window");
-
- nsDocument* document = static_cast<nsDocument*>(window->GetDoc());
-
- // Function name is the type of the custom element.
- JSString* jsFunName =
- JS_GetFunctionId(JS_ValueToFunction(aCx, args.calleev()));
- nsAutoJSString elemName;
- if (!elemName.init(aCx, jsFunName)) {
- return true;
- }
-
- RefPtr<mozilla::dom::CustomElementRegistry> registry = window->CustomElements();
- if (!registry) {
- return true;
- }
-
- nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(elemName));
- CustomElementDefinition* definition =
- registry->mCustomDefinitions.GetWeak(typeAtom);
- if (!definition) {
- return true;
- }
-
- RefPtr<Element> element;
-
- // We integrate with construction stack and do prototype swizzling here, so
- // that old upgrade behavior could also share the new upgrade steps.
- // And this old upgrade will be remove at some point (when everything is
- // switched to latest custom element spec).
- nsTArray<RefPtr<nsGenericHTMLElement>>& constructionStack =
- definition->mConstructionStack;
- if (constructionStack.Length()) {
- element = constructionStack.LastElement();
- NS_ENSURE_TRUE(element != ALEADY_CONSTRUCTED_MARKER, false);
-
- // Do prototype swizzling if dom reflector exists.
- JS::Rooted<JSObject*> reflector(aCx, element->GetWrapper());
- if (reflector) {
- Maybe<JSAutoCompartment> ac;
- JS::Rooted<JSObject*> prototype(aCx, definition->mPrototype);
- if (element->NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(prototype))) {
- ac.emplace(aCx, reflector);
- if (!JS_WrapObject(aCx, &prototype) ||
- !JS_SetPrototype(aCx, reflector, prototype)) {
- return false;
- }
- } else {
- // We want to set the custom prototype in the compartment where it was
- // registered. We store the prototype from define() without unwrapped,
- // hence the prototype's compartment is the compartment where it was
- // registered.
- // In the case that |reflector| and |prototype| are in different
- // compartments, this will set the prototype on the |reflector|'s wrapper
- // and thus only visible in the wrapper's compartment, since we know
- // reflector's principal does not subsume prototype's in this case.
- ac.emplace(aCx, prototype);
- if (!JS_WrapObject(aCx, &reflector) ||
- !JS_SetPrototype(aCx, reflector, prototype)) {
- return false;
- }
- }
-
- // Wrap into current context.
- if (!JS_WrapObject(aCx, &reflector)) {
- return false;
- }
-
- args.rval().setObject(*reflector);
- return true;
- }
- } else {
- nsDependentAtomString localName(definition->mLocalName);
- element =
- document->CreateElem(localName, nullptr, kNameSpaceID_XHTML,
- (definition->mLocalName != typeAtom) ? &elemName
- : nullptr);
- NS_ENSURE_TRUE(element, false);
- }
-
- // The prototype setup happens in Element::WrapObject().
-
- nsresult rv = nsContentUtils::WrapNative(aCx, element, element, args.rval());
- NS_ENSURE_SUCCESS(rv, true);
-
- return true;
-}
-
-bool
-nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
-{
- JS::Rooted<JSObject*> obj(aCx, aObject);
-
- if (nsContentUtils::IsWebComponentsEnabled()) {
- return true;
- }
-
- // Check for the webcomponents permission. See Bug 1181555.
- JSAutoCompartment ac(aCx, obj);
- JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
- nsCOMPtr<nsPIDOMWindowInner> window =
- do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
-
- return IsWebComponentsEnabled(window);
-}
-
-bool
-nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo)
-{
- if (nsContentUtils::IsWebComponentsEnabled()) {
- return true;
- }
-
- nsIDocument* doc = aNodeInfo->GetDocument();
- // Use GetScopeObject() here so that data documents work the same way as the
- // main document they're associated with.
- nsCOMPtr<nsPIDOMWindowInner> window =
- do_QueryInterface(doc->GetScopeObject());
- return IsWebComponentsEnabled(window);
-}
-
-bool
-nsDocument::IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow)
-{
- if (aWindow) {
- nsresult rv;
- nsCOMPtr<nsIPermissionManager> permMgr =
- do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, false);
-
- uint32_t perm;
- rv = permMgr->TestPermissionFromWindow(
- aWindow, "moz-extremely-unstable-and-will-change-webcomponents", &perm);
- NS_ENSURE_SUCCESS(rv, false);
-
- return perm == nsIPermissionManager::ALLOW_ACTION;
- }
-
- return false;
-}
-
-void
-nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
- const ElementRegistrationOptions& aOptions,
- JS::MutableHandle<JSObject*> aRetval,
- ErrorResult& rv)
-{
- RefPtr<CustomElementRegistry> registry(GetCustomElementRegistry());
- if (!registry) {
- rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
- return;
- }
-
- AutoCEReaction ceReaction(this->GetDocGroup()->CustomElementReactionsStack(),
- aCx);
- // Unconditionally convert TYPE to lowercase.
- nsAutoString lcType;
- nsContentUtils::ASCIIToLower(aType, lcType);
-
- nsIGlobalObject* sgo = GetScopeObject();
- if (!sgo) {
- rv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
-
- JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject());
- JS::Rooted<JSObject*> protoObject(aCx);
-
- if (!aOptions.mPrototype) {
- JS::Rooted<JSObject*> htmlProto(aCx);
- htmlProto = HTMLElementBinding::GetProtoObjectHandle(aCx);
- if (!htmlProto) {
- rv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return;
- }
-
- protoObject = JS_NewObjectWithGivenProto(aCx, nullptr, htmlProto);
- if (!protoObject) {
- rv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
- } else {
- protoObject = aOptions.mPrototype;
-
- // Get the unwrapped prototype to do some checks.
- JS::Rooted<JSObject*> protoObjectUnwrapped(aCx, js::CheckedUnwrap(protoObject));
- if (!protoObjectUnwrapped) {
- // If the caller's compartment does not have permission to access the
- // unwrapped prototype then throw.
- rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
- return;
- }
-
- // If PROTOTYPE is already an interface prototype object for any interface
- // object or PROTOTYPE has a non-configurable property named constructor,
- // throw a NotSupportedError and stop.
- const js::Class* clasp = js::GetObjectClass(protoObjectUnwrapped);
- if (IsDOMIfaceAndProtoClass(clasp)) {
- rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
- return;
- }
-
- JS::Rooted<JS::PropertyDescriptor> descRoot(aCx);
- JS::MutableHandle<JS::PropertyDescriptor> desc(&descRoot);
- // This check may go through a wrapper, but as we checked above
- // it should be transparent or an xray. This should be fine for now,
- // until the spec is sorted out.
- if (!JS_GetPropertyDescriptor(aCx, protoObject, "constructor", desc)) {
- rv.Throw(NS_ERROR_UNEXPECTED);
- return;
- }
-
- if (!desc.configurable()) {
- rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
- return;
- }
- }
-
- JS::Rooted<JSFunction*> constructor(aCx);
- {
- // Go into the document's global compartment when creating the constructor
- // function because we want to get the correct document (where the
- // definition is registered) when it is called.
- JSAutoCompartment ac(aCx, global);
-
- // Create constructor to return. Store the name of the custom element as the
- // name of the function.
- constructor = JS_NewFunction(aCx, nsDocument::CustomElementConstructor, 0,
- JSFUN_CONSTRUCTOR,
- NS_ConvertUTF16toUTF8(lcType).get());
- if (!constructor) {
- rv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return;
- }
- }
-
- JS::Rooted<JSObject*> wrappedConstructor(aCx);
- wrappedConstructor = JS_GetFunctionObject(constructor);
- if (!JS_WrapObject(aCx, &wrappedConstructor)) {
- rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
- return;
- }
-
- if (!JS_LinkConstructorAndPrototype(aCx, wrappedConstructor, protoObject)) {
- rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
- return;
- }
-
- ElementDefinitionOptions options;
- if (!aOptions.mExtends.IsVoid()) {
- // Only convert NAME to lowercase in HTML documents.
- nsAutoString lcName;
- IsHTMLDocument() ? nsContentUtils::ASCIIToLower(aOptions.mExtends, lcName)
- : lcName.Assign(aOptions.mExtends);
-
- options.mExtends.Construct(lcName);
- }
-
- RootedCallback<OwningNonNull<binding_detail::FastFunction>> functionConstructor(aCx);
- functionConstructor = new binding_detail::FastFunction(aCx, wrappedConstructor, sgo);
-
- registry->Define(lcType, functionConstructor, options, rv);
-
- aRetval.set(wrappedConstructor);
+ return aNode->OwnerDoc()->IsWebComponentsEnabled();
}
NS_IMETHODIMP
@@ -6006,15 +5695,6 @@ nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets)
return NS_OK;
}
-StyleSheetList*
-nsDocument::StyleSheets()
-{
- if (!mDOMStyleSheets) {
- mDOMStyleSheets = new nsDOMStyleSheetList(this);
- }
- return mDOMStyleSheets;
-}
-
NS_IMETHODIMP
nsDocument::GetMozSelectedStyleSheetSet(nsAString& aSheetSet)
{
@@ -6028,10 +5708,10 @@ nsIDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet)
aSheetSet.Truncate();
// Look through our sheets, find the selected set title
- int32_t count = GetNumberOfStyleSheets();
+ size_t count = SheetCount();
nsAutoString title;
- for (int32_t index = 0; index < count; index++) {
- StyleSheet* sheet = GetStyleSheetAt(index);
+ for (size_t index = 0; index < count; index++) {
+ StyleSheet* sheet = SheetAt(index);
NS_ASSERTION(sheet, "Null sheet in sheet list!");
// XXXheycam Make this work with ServoStyleSheets.
@@ -6148,10 +5828,10 @@ nsDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
bool aUpdateCSSLoader)
{
BeginUpdate(UPDATE_STYLE);
- int32_t count = GetNumberOfStyleSheets();
+ size_t count = SheetCount();
nsAutoString title;
- for (int32_t index = 0; index < count; index++) {
- StyleSheet* sheet = GetStyleSheetAt(index);
+ for (size_t index = 0; index < count; index++) {
+ StyleSheet* sheet = SheetAt(index);
NS_ASSERTION(sheet, "Null sheet in sheet list!");
// XXXheycam Make this work with ServoStyleSheets.
@@ -6421,7 +6101,7 @@ already_AddRefed<nsRange>
nsIDocument::CreateRange(ErrorResult& rv)
{
RefPtr<nsRange> range = new nsRange(this);
- nsresult res = range->Set(this, 0, this, 0);
+ nsresult res = range->CollapseTo(this, 0);
if (NS_FAILED(res)) {
rv.Throw(res);
return nullptr;
@@ -7712,7 +7392,7 @@ nsDocument::GetExistingListenerManager() const
}
nsresult
-nsDocument::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsDocument::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
// FIXME! This is a hack to make middle mouse paste working also in Editor.
@@ -7722,8 +7402,8 @@ nsDocument::PreHandleEvent(EventChainPreVisitor& aVisitor)
// Load events must not propagate to |window| object, see bug 335251.
if (aVisitor.mEvent->mMessage != eLoad) {
nsGlobalWindow* window = nsGlobalWindow::Cast(GetWindow());
- aVisitor.mParentTarget =
- window ? window->GetTargetForEventTargetChain() : nullptr;
+ aVisitor.SetParentTarget(
+ window ? window->GetTargetForEventTargetChain() : nullptr, false);
}
return NS_OK;
}
@@ -9859,9 +9539,9 @@ nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
clonedDoc->mOriginalDocument->mStaticCloneCount++;
- int32_t sheetsCount = GetNumberOfStyleSheets();
- for (int32_t i = 0; i < sheetsCount; ++i) {
- RefPtr<StyleSheet> sheet = GetStyleSheetAt(i);
+ size_t sheetsCount = SheetCount();
+ for (size_t i = 0; i < sheetsCount; ++i) {
+ RefPtr<StyleSheet> sheet = SheetAt(i);
if (sheet) {
if (sheet->IsApplicable()) {
// XXXheycam Need to make ServoStyleSheet cloning work.
@@ -12079,7 +11759,7 @@ SizeOfOwnedSheetArrayExcludingThis(const nsTArray<RefPtr<StyleSheet>>& aSheets,
size_t n = 0;
n += aSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (StyleSheet* sheet : aSheets) {
- if (!sheet->GetOwningDocument()) {
+ if (!sheet->GetAssociatedDocument()) {
// Avoid over-reporting shared sheets.
continue;
}
diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h
index 90e511dcb..6520d905d 100644
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -293,36 +293,6 @@ public:
nsDocHeaderData* mNext;
};
-class nsDOMStyleSheetList : public mozilla::dom::StyleSheetList,
- public nsStubDocumentObserver
-{
-public:
- explicit nsDOMStyleSheetList(nsIDocument* aDocument);
-
- NS_DECL_ISUPPORTS_INHERITED
-
- // nsIDocumentObserver
- NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED
- NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED
-
- // nsIMutationObserver
- NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
-
- virtual nsINode* GetParentObject() const override
- {
- return mDocument;
- }
-
- uint32_t Length() override;
- mozilla::StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
-
-protected:
- virtual ~nsDOMStyleSheetList();
-
- int32_t mLength;
- nsIDocument* mDocument;
-};
-
class nsOnloadBlocker final : public nsIRequest
{
public:
@@ -624,14 +594,6 @@ public:
virtual void EnsureOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet) override;
- /**
- * Get the (document) style sheets owned by this document.
- * These are ordered, highest priority last
- */
- virtual int32_t GetNumberOfStyleSheets() const override;
- virtual mozilla::StyleSheet* GetStyleSheetAt(int32_t aIndex) const override;
- virtual int32_t GetIndexOfStyleSheet(
- const mozilla::StyleSheet* aSheet) const override;
virtual void AddStyleSheet(mozilla::StyleSheet* aSheet) override;
virtual void RemoveStyleSheet(mozilla::StyleSheet* aSheet) override;
@@ -642,7 +604,7 @@ public:
virtual void RemoveStyleSheetFromStyleSets(mozilla::StyleSheet* aSheet);
virtual void InsertStyleSheetAt(mozilla::StyleSheet* aSheet,
- int32_t aIndex) override;
+ size_t aIndex) override;
virtual void SetStyleSheetApplicableState(mozilla::StyleSheet* aSheet,
bool aApplicable) override;
@@ -793,7 +755,11 @@ public:
virtual void NotifyLayerManagerRecreated() override;
-
+ // Check whether web components are enabled for the global of aObject.
+ static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
+ // Check whether web components are enabled for the document this node belongs
+ // to.
+ static bool IsWebComponentsEnabled(const nsINode* aNode);
private:
void AddOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet);
nsRadioGroupStruct* GetRadioGroupInternal(const nsAString& aName) const;
@@ -810,7 +776,7 @@ public:
NS_DECL_NSIDOMDOCUMENTXBL
// nsIDOMEventTarget
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
virtual mozilla::EventListenerManager*
GetOrCreateListenerManager() override;
@@ -1129,12 +1095,7 @@ public:
// WebIDL bits
virtual mozilla::dom::DOMImplementation*
GetImplementation(mozilla::ErrorResult& rv) override;
- virtual void
- RegisterElement(JSContext* aCx, const nsAString& aName,
- const mozilla::dom::ElementRegistrationOptions& aOptions,
- JS::MutableHandle<JSObject*> aRetval,
- mozilla::ErrorResult& rv) override;
- virtual mozilla::dom::StyleSheetList* StyleSheets() override;
+
virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) override;
virtual void GetLastStyleSheetSet(nsString& aSheetSet) override;
virtual mozilla::dom::DOMStringList* StyleSheetSets() override;
@@ -1356,7 +1317,6 @@ protected:
// EndLoad() has already happened.
nsWeakPtr mWeakSink;
- nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
nsTArray<RefPtr<mozilla::StyleSheet>> mOnDemandBuiltInUASheets;
nsTArray<RefPtr<mozilla::StyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount];
@@ -1385,23 +1345,8 @@ protected:
// non-null when this document is in fullscreen mode.
nsWeakPtr mFullscreenRoot;
-private:
- static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
-
public:
- virtual already_AddRefed<mozilla::dom::CustomElementRegistry>
- GetCustomElementRegistry() override;
-
- // Check whether web components are enabled for the global of aObject.
- static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
- // Check whether web components are enabled for the global of the document
- // this nodeinfo comes from.
- static bool IsWebComponentsEnabled(mozilla::dom::NodeInfo* aNodeInfo);
- // Check whether web components are enabled for the given window.
- static bool IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow);
-
RefPtr<mozilla::EventListenerManager> mListenerManager;
- RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
RefPtr<nsScriptLoader> mScriptLoader;
nsDocHeaderData* mHeaderData;
diff --git a/dom/base/nsDocumentEncoder.cpp b/dom/base/nsDocumentEncoder.cpp
index 34eb6ed38..2f5c3dc0a 100644
--- a/dom/base/nsDocumentEncoder.cpp
+++ b/dom/base/nsDocumentEncoder.cpp
@@ -32,7 +32,6 @@
#include "nsIDOMDocument.h"
#include "nsGkAtoms.h"
#include "nsIContent.h"
-#include "nsIParserService.h"
#include "nsIScriptContext.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptSecurityManager.h"
@@ -40,6 +39,7 @@
#include "nsISelectionPrivate.h"
#include "nsITransferable.h" // for kUnicodeMime
#include "nsContentUtils.h"
+#include "nsElementTable.h"
#include "nsNodeUtils.h"
#include "nsUnicharUtils.h"
#include "nsReadableUtils.h"
@@ -1588,10 +1588,13 @@ nsHTMLCopyEncoder::IncludeInContext(nsINode *aNode)
nsresult
nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
{
- if (!inRange) return NS_ERROR_NULL_POINTER;
+ RefPtr<nsRange> range = static_cast<nsRange*>(inRange);
+ if (!range) {
+ return NS_ERROR_NULL_POINTER;
+ }
nsresult rv;
nsCOMPtr<nsIDOMNode> startNode, endNode, common;
- int32_t startOffset, endOffset;
+ uint32_t startOffset, endOffset;
rv = inRange->GetCommonAncestorContainer(getter_AddRefs(common));
NS_ENSURE_SUCCESS(rv, rv);
@@ -1609,9 +1612,11 @@ nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
int32_t opStartOffset, opEndOffset;
// examine range endpoints.
- rv = GetPromotedPoint( kStart, startNode, startOffset, address_of(opStartNode), &opStartOffset, common);
+ rv = GetPromotedPoint(kStart, startNode, static_cast<int32_t>(startOffset),
+ address_of(opStartNode), &opStartOffset, common);
NS_ENSURE_SUCCESS(rv, rv);
- rv = GetPromotedPoint( kEnd, endNode, endOffset, address_of(opEndNode), &opEndOffset, common);
+ rv = GetPromotedPoint(kEnd, endNode, static_cast<int32_t>(endOffset),
+ address_of(opEndNode), &opEndOffset, common);
NS_ENSURE_SUCCESS(rv, rv);
// if both range endpoints are at the common ancestor, check for possible inclusion of ancestors
@@ -1623,9 +1628,9 @@ nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
}
// set the range to the new values
- rv = inRange->SetStart(opStartNode, opStartOffset);
+ rv = inRange->SetStart(opStartNode, static_cast<uint32_t>(opStartOffset));
NS_ENSURE_SUCCESS(rv, rv);
- rv = inRange->SetEnd(opEndNode, opEndOffset);
+ rv = inRange->SetEnd(opEndNode, static_cast<uint32_t>(opEndOffset));
return rv;
}
@@ -1736,9 +1741,6 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
rv = GetNodeLocation(node, address_of(parent), &offset);
NS_ENSURE_SUCCESS(rv, rv);
if (offset == -1) return NS_OK; // we hit generated content; STOP
- nsIParserService *parserService = nsContentUtils::GetParserService();
- if (!parserService)
- return NS_ERROR_OUT_OF_MEMORY;
while ((IsFirstNode(node)) && (!IsRoot(parent)) && (parent != common))
{
if (bResetPromotion)
@@ -1746,11 +1748,8 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
nsCOMPtr<nsIContent> content = do_QueryInterface(parent);
if (content && content->IsHTMLElement())
{
- bool isBlock = false;
- parserService->IsBlock(parserService->HTMLAtomTagToId(
- content->NodeInfo()->NameAtom()), isBlock);
- if (isBlock)
- {
+ if (nsHTMLElement::IsBlock(nsHTMLTags::AtomTagToId(
+ content->NodeInfo()->NameAtom()))) {
bResetPromotion = false;
}
}
@@ -1819,9 +1818,6 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
rv = GetNodeLocation(node, address_of(parent), &offset);
NS_ENSURE_SUCCESS(rv, rv);
if (offset == -1) return NS_OK; // we hit generated content; STOP
- nsIParserService *parserService = nsContentUtils::GetParserService();
- if (!parserService)
- return NS_ERROR_OUT_OF_MEMORY;
while ((IsLastNode(node)) && (!IsRoot(parent)) && (parent != common))
{
if (bResetPromotion)
@@ -1829,11 +1825,8 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
nsCOMPtr<nsIContent> content = do_QueryInterface(parent);
if (content && content->IsHTMLElement())
{
- bool isBlock = false;
- parserService->IsBlock(parserService->HTMLAtomTagToId(
- content->NodeInfo()->NameAtom()), isBlock);
- if (isBlock)
- {
+ if (nsHTMLElement::IsBlock(nsHTMLTags::AtomTagToId(
+ content->NodeInfo()->NameAtom()))) {
bResetPromotion = false;
}
}
diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp
index 01c1944be..c14087c8a 100644
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -2457,7 +2457,7 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
nsCOMPtr<nsIDOMNode> startNode, endNode;
bool isCollapsed = false;
nsCOMPtr<nsIContent> startContent, endContent;
- int32_t startOffset = 0;
+ uint32_t startOffset = 0;
if (domSelection) {
domSelection->GetIsCollapsed(&isCollapsed);
nsCOMPtr<nsIDOMRange> domRange;
@@ -2471,7 +2471,6 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
startContent = do_QueryInterface(startNode);
if (startContent && startContent->IsElement()) {
- NS_ASSERTION(startOffset >= 0, "Start offset cannot be negative");
childContent = startContent->GetChildAt(startOffset);
if (childContent) {
startContent = childContent;
@@ -2480,9 +2479,8 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
endContent = do_QueryInterface(endNode);
if (endContent && endContent->IsElement()) {
- int32_t endOffset = 0;
+ uint32_t endOffset = 0;
domRange->GetEndOffset(&endOffset);
- NS_ASSERTION(endOffset >= 0, "End offset cannot be negative");
childContent = endContent->GetChildAt(endOffset);
if (childContent) {
endContent = childContent;
@@ -2510,7 +2508,7 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
bool isFormControl =
startContent->IsNodeOfType(nsINode::eHTML_FORM_CONTROL);
- if (nodeValue.Length() == (uint32_t)startOffset && !isFormControl &&
+ if (nodeValue.Length() == startOffset && !isFormControl &&
startContent != aDocument->GetRootElement()) {
// Yes, indeed we were at the end of the last node
nsCOMPtr<nsIFrameEnumerator> frameTraversal;
diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp
index 2804f2d4c..942a84102 100644
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -57,6 +57,7 @@
#include "nsGlobalWindow.h"
#include "nsPIWindowRoot.h"
#include "nsLayoutUtils.h"
+#include "nsMappedAttributes.h"
#include "nsView.h"
#include "GroupedSHistory.h"
#include "PartialSHistory.h"
@@ -936,6 +937,8 @@ nsFrameLoader::MarginsChanged(uint32_t aMarginWidth,
RefPtr<nsPresContext> presContext;
mDocShell->GetPresContext(getter_AddRefs(presContext));
if (presContext)
+ // rebuild, because now the same nsMappedAttributes* will produce
+ // a different style
presContext->RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
}
diff --git a/dom/base/nsGenConImageContent.cpp b/dom/base/nsGenConImageContent.cpp
index e1b1f5a17..af3b186bd 100644
--- a/dom/base/nsGenConImageContent.cpp
+++ b/dom/base/nsGenConImageContent.cpp
@@ -46,7 +46,7 @@ public:
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
virtual EventStates IntrinsicState() const override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override
+ virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override
{
MOZ_ASSERT(IsInNativeAnonymousSubtree());
if (aVisitor.mEvent->mMessage == eLoad ||
@@ -54,7 +54,7 @@ public:
// Don't propagate the events to the parent.
return NS_OK;
}
- return nsXMLElement::PreHandleEvent(aVisitor);
+ return nsXMLElement::GetEventTargetParent(aVisitor);
}
private:
diff --git a/dom/base/nsGenericDOMDataNode.cpp b/dom/base/nsGenericDOMDataNode.cpp
index 73463ea5e..d23783368 100644
--- a/dom/base/nsGenericDOMDataNode.cpp
+++ b/dom/base/nsGenericDOMDataNode.cpp
@@ -15,6 +15,7 @@
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/Element.h"
+#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/ShadowRoot.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
@@ -736,21 +737,18 @@ nsGenericDOMDataNode::SetShadowRoot(ShadowRoot* aShadowRoot)
{
}
-nsTArray<nsIContent*>&
-nsGenericDOMDataNode::DestInsertionPoints()
+HTMLSlotElement*
+nsGenericDOMDataNode::GetAssignedSlot() const
{
- nsDataSlots *slots = DataSlots();
- return slots->mDestInsertionPoints;
+ nsDataSlots *slots = GetExistingDataSlots();
+ return slots ? slots->mAssignedSlot.get() : nullptr;
}
-nsTArray<nsIContent*>*
-nsGenericDOMDataNode::GetExistingDestInsertionPoints() const
+void
+nsGenericDOMDataNode::SetAssignedSlot(HTMLSlotElement* aSlot)
{
- nsDataSlots *slots = GetExistingDataSlots();
- if (slots) {
- return &slots->mDestInsertionPoints;
- }
- return nullptr;
+ nsDataSlots *slots = DataSlots();
+ slots->mAssignedSlot = aSlot;
}
nsXBLBinding *
@@ -843,6 +841,9 @@ nsGenericDOMDataNode::nsDataSlots::Traverse(nsCycleCollectionTraversalCallback &
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mContainingShadow");
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow));
+
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAssignedSlot");
+ cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mAssignedSlot.get()));
}
void
@@ -850,6 +851,7 @@ nsGenericDOMDataNode::nsDataSlots::Unlink()
{
mXBLInsertionParent = nullptr;
mContainingShadow = nullptr;
+ mAssignedSlot = nullptr;
}
//----------------------------------------------------------------------
diff --git a/dom/base/nsGenericDOMDataNode.h b/dom/base/nsGenericDOMDataNode.h
index e8818b518..4d0114cb1 100644
--- a/dom/base/nsGenericDOMDataNode.h
+++ b/dom/base/nsGenericDOMDataNode.h
@@ -26,6 +26,12 @@
class nsIDocument;
class nsIDOMText;
+namespace mozilla {
+namespace dom {
+class HTMLSlotElement;
+} // namespace dom
+} // namespace mozilla
+
#define DATA_NODE_FLAG_BIT(n_) NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
// Data node specific flags
@@ -154,9 +160,9 @@ public:
virtual void SetXBLBinding(nsXBLBinding* aBinding,
nsBindingManager* aOldBindingManager = nullptr) override;
virtual mozilla::dom::ShadowRoot *GetContainingShadow() const override;
- virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
- virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
virtual void SetShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot) override;
+ virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const override;
+ virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) override;
virtual nsIContent *GetXBLInsertionParent() const override;
virtual void SetXBLInsertionParent(nsIContent* aContent) override;
virtual bool IsNodeOfType(uint32_t aFlags) const override;
@@ -261,9 +267,9 @@ protected:
RefPtr<mozilla::dom::ShadowRoot> mContainingShadow;
/**
- * @see nsIContent::GetDestInsertionPoints
+ * @see nsIContent::GetAssignedSlot
*/
- nsTArray<nsIContent*> mDestInsertionPoints;
+ RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot;
};
// Override from nsINode
diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h
index 73a3a02b1..35963afd7 100644
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -1560,11 +1560,11 @@ GK_ATOM(saturate, "saturate")
GK_ATOM(saturation, "saturation")
GK_ATOM(set, "set")
GK_ATOM(seed, "seed")
-GK_ATOM(shadow, "shadow")
GK_ATOM(shape_rendering, "shape-rendering")
GK_ATOM(skewX, "skewX")
GK_ATOM(skewY, "skewY")
GK_ATOM(slope, "slope")
+GK_ATOM(slot, "slot")
GK_ATOM(softLight, "soft-light")
GK_ATOM(spacing, "spacing")
GK_ATOM(spacingAndGlyphs, "spacingAndGlyphs")
@@ -2144,12 +2144,14 @@ GK_ATOM(ongamepaddisconnected, "ongamepaddisconnected")
#endif
// Content property names
+GK_ATOM(afterPseudoProperty, "afterPseudoProperty") // nsXMLElement*
GK_ATOM(animationsProperty, "AnimationsProperty") // FrameAnimations*
GK_ATOM(animationsOfBeforeProperty, "AnimationsOfBeforeProperty") // FrameAnimations*
GK_ATOM(animationsOfAfterProperty, "AnimationsOfAfterProperty") // FrameAnimations*
GK_ATOM(animationEffectsProperty, "AnimationEffectsProperty") // EffectSet*
GK_ATOM(animationEffectsForBeforeProperty, "AnimationsEffectsForBeforeProperty") // EffectSet*
GK_ATOM(animationEffectsForAfterProperty, "AnimationsEffectsForAfterProperty") // EffectSet*
+GK_ATOM(beforePseudoProperty, "beforePseudoProperty") // nsXMLElement*
GK_ATOM(cssPseudoElementBeforeProperty, "CSSPseudoElementBeforeProperty") // CSSPseudoElement*
GK_ATOM(cssPseudoElementAfterProperty, "CSSPseudoElementAfterProperty") // CSSPseudoElement*
GK_ATOM(transitionsProperty, "TransitionsProperty") // FrameTransitions*
@@ -2162,6 +2164,7 @@ GK_ATOM(lockedStyleStates, "lockedStyleStates")
GK_ATOM(apzCallbackTransform, "apzCallbackTransform")
GK_ATOM(restylableAnonymousNode, "restylableAnonymousNode")
GK_ATOM(paintRequestTime, "PaintRequestTime")
+GK_ATOM(pseudoProperty, "PseudoProperty") // CSSPseudoElementType
// Languages for lang-specific transforms
GK_ATOM(Japanese, "ja")
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index c965d5b97..69643762c 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3577,9 +3577,10 @@ nsGlobalWindow::WillHandleEvent(EventChainPostVisitor& aVisitor)
}
nsresult
-nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsGlobalWindow::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
+ NS_PRECONDITION(IsInnerWindow(),
+ "GetEventTargetParent is used on outer window!?");
EventMessage msg = aVisitor.mEvent->mMessage;
aVisitor.mCanHandle = true;
@@ -3607,7 +3608,7 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
- aVisitor.mParentTarget = GetParentTarget();
+ aVisitor.SetParentTarget(GetParentTarget(), true);
// Handle 'active' event.
if (!mIdleObservers.IsEmpty() &&
@@ -3812,7 +3813,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
} else if (aVisitor.mEvent->mMessage == eLoad &&
aVisitor.mEvent->IsTrusted()) {
// This is page load event since load events don't propagate to |window|.
- // @see nsDocument::PreHandleEvent.
+ // @see nsDocument::GetEventTargetParent.
mIsDocumentLoaded = true;
nsCOMPtr<Element> element = GetOuterWindow()->GetFrameElementInternal();
diff --git a/dom/base/nsHTMLContentSerializer.cpp b/dom/base/nsHTMLContentSerializer.cpp
index c135c4cf8..ea9c5a66f 100644
--- a/dom/base/nsHTMLContentSerializer.cpp
+++ b/dom/base/nsHTMLContentSerializer.cpp
@@ -15,6 +15,7 @@
#include "nsIDOMElement.h"
#include "nsIContent.h"
#include "nsIDocument.h"
+#include "nsElementTable.h"
#include "nsNameSpaceManager.h"
#include "nsString.h"
#include "nsUnicharUtils.h"
@@ -347,20 +348,13 @@ nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
}
if (ns == kNameSpaceID_XHTML) {
- nsIParserService* parserService = nsContentUtils::GetParserService();
-
- if (parserService) {
- bool isContainer;
-
- parserService->
- IsContainer(parserService->HTMLCaseSensitiveAtomTagToId(name),
- isContainer);
- if (!isContainer) {
- // Keep this in sync with the cleanup at the end of this method.
- MOZ_ASSERT(name != nsGkAtoms::body);
- MaybeLeaveFromPreContent(content);
- return NS_OK;
- }
+ bool isContainer =
+ nsHTMLElement::IsContainer(nsHTMLTags::CaseSensitiveAtomTagToId(name));
+ if (!isContainer) {
+ // Keep this in sync with the cleanup at the end of this method.
+ MOZ_ASSERT(name != nsGkAtoms::body);
+ MaybeLeaveFromPreContent(content);
+ return NS_OK;
}
}
diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h
index dcdc632b4..ce0a4e596 100644
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -26,6 +26,7 @@ namespace mozilla {
class EventChainPreVisitor;
namespace dom {
class ShadowRoot;
+class HTMLSlotElement;
} // namespace dom
namespace widget {
struct IMEState;
@@ -144,7 +145,14 @@ public:
* Skip native anonymous content created for placeholder of HTML input,
* used in conjunction with eAllChildren or eAllButXBL.
*/
- eSkipPlaceholderContent = 2
+ eSkipPlaceholderContent = 2,
+
+ /**
+ * Skip native anonymous content created by ancestor frames of the root
+ * element's primary frame, such as scrollbar elements created by the root
+ * scroll frame.
+ */
+ eSkipDocumentLevelNativeAnonymousContent = 4,
};
/**
@@ -186,7 +194,7 @@ public:
void SetIsNativeAnonymousRoot()
{
SetFlags(NODE_IS_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
- NODE_IS_NATIVE_ANONYMOUS_ROOT);
+ NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_NATIVE_ANONYMOUS);
}
/**
@@ -689,18 +697,27 @@ public:
virtual mozilla::dom::ShadowRoot *GetContainingShadow() const = 0;
/**
- * Gets an array of destination insertion points where this content
- * is distributed by web component distribution algorithms.
- * The array is created if it does not already exist.
+ * Gets the assigned slot associated with this content.
+ *
+ * @return The assigned slot element or null.
*/
- virtual nsTArray<nsIContent*> &DestInsertionPoints() = 0;
+ virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const = 0;
/**
- * Same as DestInsertionPoints except that this method will return
- * null if the array of destination insertion points does not already
- * exist.
+ * Sets the assigned slot associated with this content.
+ *
+ * @param aSlot The assigned slot.
*/
- virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const = 0;
+ virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) = 0;
+
+ /**
+ * Gets the assigned slot associated with this content based on parent's
+ * shadow root mode. Returns null if parent's shadow root is "closed".
+ * https://dom.spec.whatwg.org/#dom-slotable-assignedslot
+ *
+ * @return The assigned slot element or null.
+ */
+ mozilla::dom::HTMLSlotElement* GetAssignedSlotByMode() const;
/**
* Gets the insertion parent element of the XBL binding.
@@ -723,10 +740,9 @@ public:
*/
inline nsIContent *GetFlattenedTreeParent() const;
- /**
- * Helper method, which we leave public so that it's accessible from nsINode.
- */
- nsINode *GetFlattenedTreeParentNodeInternal() const;
+ // Helper method, which we leave public so that it's accessible from nsINode.
+ enum FlattenedParentType { eNotForStyle, eForStyle };
+ nsINode* GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const;
/**
* API to check if this is a link that's traversed in response to user input
@@ -944,10 +960,18 @@ public:
return false;
}
+ // Returns true if this element is native-anonymous scrollbar content.
+ bool IsNativeScrollbarContent() const {
+ return IsNativeAnonymous() &&
+ IsAnyOfXULElements(nsGkAtoms::scrollbar,
+ nsGkAtoms::resizer,
+ nsGkAtoms::scrollcorner);
+ }
+
// Overloaded from nsINode
virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override;
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
virtual bool IsPurple() = 0;
@@ -961,6 +985,12 @@ protected:
*/
nsIAtom* DoGetID() const;
+ /**
+ * Returns the assigned slot, if it exists, or the direct parent, if it's a
+ * fallback content of a slot.
+ */
+ nsINode* GetFlattenedTreeParentForMaybeAssignedNode() const;
+
public:
#ifdef DEBUG
/**
@@ -1014,9 +1044,17 @@ inline nsIContent* nsINode::AsContent()
{ \
return aContent->_check ? static_cast<_class*>(aContent) : nullptr; \
} \
+ static const _class* FromContent(const nsIContent* aContent) \
+ { \
+ return aContent->_check ? static_cast<const _class*>(aContent) : nullptr; \
+ } \
static _class* FromContentOrNull(nsIContent* aContent) \
{ \
return aContent ? FromContent(aContent) : nullptr; \
+ } \
+ static const _class* FromContentOrNull(const nsIContent* aContent) \
+ { \
+ return aContent ? FromContent(aContent) : nullptr; \
}
#define NS_IMPL_FROMCONTENT(_class, _nsid) \
diff --git a/dom/base/nsIContentInlines.h b/dom/base/nsIContentInlines.h
index 368a0422b..6a9bd7afa 100644
--- a/dom/base/nsIContentInlines.h
+++ b/dom/base/nsIContentInlines.h
@@ -33,14 +33,15 @@ inline mozilla::dom::ShadowRoot* nsIContent::GetShadowRoot() const
return AsElement()->FastGetShadowRoot();
}
-inline nsINode* nsINode::GetFlattenedTreeParentNode() const
+template<nsIContent::FlattenedParentType Type>
+static inline nsINode*
+GetFlattenedTreeParentNode(const nsINode* aNode)
{
- nsINode* parent = GetParentNode();
-
+ nsINode* parent = aNode->GetParentNode();
// Try to short-circuit past the complicated and not-exactly-fast logic for
// computing the flattened parent.
//
- // There are three cases where we need might something other than parentNode:
+ // There are four cases where we need might something other than parentNode:
// (1) The node is an explicit child of an XBL-bound element, re-bound
// to an XBL insertion point.
// (2) The node is a top-level element in a shadow tree, whose flattened
@@ -48,18 +49,31 @@ inline nsINode* nsINode::GetFlattenedTreeParentNode() const
// is the shadow root).
// (3) The node is an explicit child of an element with a shadow root,
// re-bound to an insertion point.
- bool needSlowCall = HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
- IsInShadowTree() ||
- (parent && parent->IsContent() &&
- parent->AsContent()->GetShadowRoot());
+ // (4) We want the flattened parent for style, and the node is the root
+ // of a native anonymous content subtree parented to the document's
+ // root element.
+ bool needSlowCall = aNode->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
+ aNode->IsInShadowTree() ||
+ (parent &&
+ parent->IsContent() &&
+ parent->AsContent()->GetShadowRoot()) ||
+ (Type == nsIContent::eForStyle &&
+ aNode->IsContent() &&
+ aNode->AsContent()->IsRootOfNativeAnonymousSubtree() &&
+ aNode->OwnerDoc()->GetRootElement() == parent);
if (MOZ_UNLIKELY(needSlowCall)) {
- MOZ_ASSERT(IsContent());
- return AsContent()->GetFlattenedTreeParentNodeInternal();
+ MOZ_ASSERT(aNode->IsContent());
+ return aNode->AsContent()->GetFlattenedTreeParentNodeInternal(Type);
}
-
return parent;
}
+inline nsINode*
+nsINode::GetFlattenedTreeParentNode() const
+{
+ return ::GetFlattenedTreeParentNode<nsIContent::eNotForStyle>(this);
+}
+
inline nsIContent*
nsIContent::GetFlattenedTreeParent() const
{
@@ -67,5 +81,16 @@ nsIContent::GetFlattenedTreeParent() const
return (parent && parent->IsContent()) ? parent->AsContent() : nullptr;
}
+inline nsINode*
+nsINode::GetFlattenedTreeParentNodeForStyle() const
+{
+ return ::GetFlattenedTreeParentNode<nsIContent::eForStyle>(this);
+}
+
+inline bool
+nsINode::NodeOrAncestorHasDirAuto() const
+{
+ return AncestorHasDirAuto() || (IsElement() && AsElement()->HasDirAuto());
+}
#endif // nsIContentInlines_h
diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
index 125816c95..b4fda21c1 100644
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -34,6 +34,7 @@
#include "prclist.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/CORSMode.h"
+#include "mozilla/dom/StyleScope.h"
#include "mozilla/LinkedList.h"
#include "mozilla/StyleBackendType.h"
#include "mozilla/StyleSheet.h"
@@ -133,7 +134,6 @@ class DOMIntersectionObserver;
class DOMStringList;
class Element;
struct ElementCreationOptions;
-struct ElementRegistrationOptions;
class Event;
class EventTarget;
class FontFaceSet;
@@ -197,7 +197,8 @@ class nsContentList;
// Document interface. This is implemented by all document objects in
// Gecko.
-class nsIDocument : public nsINode
+class nsIDocument : public nsINode,
+ public mozilla::dom::StyleScope
{
typedef mozilla::dom::GlobalObject GlobalObject;
@@ -1070,40 +1071,24 @@ public:
*/
virtual void EnsureOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet) = 0;
- /**
- * Get the number of (document) stylesheets
- *
- * @return the number of stylesheets
- * @throws no exceptions
- */
- virtual int32_t GetNumberOfStyleSheets() const = 0;
+ nsINode& AsNode() final
+ {
+ return *this;
+ }
- /**
- * Get a particular stylesheet
- * @param aIndex the index the stylesheet lives at. This is zero-based
- * @return the stylesheet at aIndex. Null if aIndex is out of range.
- * @throws no exceptions
- */
- virtual mozilla::StyleSheet* GetStyleSheetAt(int32_t aIndex) const = 0;
+ mozilla::dom::StyleSheetList* StyleSheets()
+ {
+ return &StyleScope::EnsureDOMStyleSheets();
+ }
/**
* Insert a sheet at a particular spot in the stylesheet list (zero-based)
* @param aSheet the sheet to insert
- * @param aIndex the index to insert at. This index will be
- * adjusted for the "special" sheets.
+ * @param aIndex the index to insert at.
* @throws no exceptions
*/
virtual void InsertStyleSheetAt(mozilla::StyleSheet* aSheet,
- int32_t aIndex) = 0;
-
- /**
- * Get the index of a particular stylesheet. This will _always_
- * consider the "special" sheets as part of the sheet list.
- * @param aSheet the sheet to get the index of
- * @return aIndex the index of the sheet in the full list
- */
- virtual int32_t GetIndexOfStyleSheet(
- const mozilla::StyleSheet* aSheet) const = 0;
+ size_t aIndex) = 0;
/**
* Replace the stylesheets in aOldSheets with the stylesheets in
@@ -1154,11 +1139,13 @@ public:
* sheets for this document, returns the index that aSheet should
* be inserted at to maintain document ordering.
*
+ * Type T has to cast to StyleSheet*.
+ *
* Defined in nsIDocumentInlines.h.
*/
template<typename T>
- size_t FindDocStyleSheetInsertionPoint(const nsTArray<RefPtr<T>>& aDocSheets,
- T* aSheet);
+ size_t FindDocStyleSheetInsertionPoint(const nsTArray<T>& aDocSheets,
+ const mozilla::StyleSheet& aSheet);
/**
* Get this document's CSSLoader. This is guaranteed to not return null.
@@ -2587,14 +2574,6 @@ public:
nsIDocument* GetTopLevelContentDocument();
- virtual void
- RegisterElement(JSContext* aCx, const nsAString& aName,
- const mozilla::dom::ElementRegistrationOptions& aOptions,
- JS::MutableHandle<JSObject*> aRetval,
- mozilla::ErrorResult& rv) = 0;
- virtual already_AddRefed<mozilla::dom::CustomElementRegistry>
- GetCustomElementRegistry() = 0;
-
already_AddRefed<nsContentList>
GetElementsByTagName(const nsAString& aTagName)
{
@@ -2706,7 +2685,6 @@ public:
return mVisibilityState;
}
#endif
- virtual mozilla::dom::StyleSheetList* StyleSheets() = 0;
void GetSelectedStyleSheetSet(nsAString& aSheetSet);
virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) = 0;
virtual void GetLastStyleSheetSet(nsString& aSheetSet) = 0;
@@ -2894,6 +2872,11 @@ public:
--mThrowOnDynamicMarkupInsertionCounter;
}
+ bool IsWebComponentsEnabled() const
+ {
+ return mIsWebComponentsEnabled;
+ }
+
protected:
bool GetUseCounter(mozilla::UseCounter aUseCounter)
{
@@ -3037,6 +3020,9 @@ protected:
// container for per-context fonts (downloadable, SVG, etc.)
RefPtr<mozilla::dom::FontFaceSet> mFontFaceSet;
+ // True if dom.webcomponents.enabled pref is set when document is created.
+ bool mIsWebComponentsEnabled : 1;
+
// Compatibility mode
nsCompatibility mCompatMode;
diff --git a/dom/base/nsIDocumentInlines.h b/dom/base/nsIDocumentInlines.h
index 4ba21dfe6..5b95a1bd3 100644
--- a/dom/base/nsIDocumentInlines.h
+++ b/dom/base/nsIDocumentInlines.h
@@ -19,24 +19,23 @@ nsIDocument::GetBodyElement()
template<typename T>
size_t
nsIDocument::FindDocStyleSheetInsertionPoint(
- const nsTArray<RefPtr<T>>& aDocSheets,
- T* aSheet)
+ const nsTArray<T>& aDocSheets,
+ const mozilla::StyleSheet& aSheet)
{
nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
// lowest index first
- int32_t newDocIndex = GetIndexOfStyleSheet(aSheet);
-
- int32_t count = aDocSheets.Length();
- int32_t index;
- for (index = 0; index < count; index++) {
- T* sheet = aDocSheets[index];
- int32_t sheetDocIndex = GetIndexOfStyleSheet(sheet);
+ int32_t newDocIndex = IndexOfSheet(aSheet);
+
+ size_t count = aDocSheets.Length();
+ size_t index = 0;
+ for (; index < count; index++) {
+ auto* sheet = static_cast<mozilla::StyleSheet*>(aDocSheets[index]);
+ MOZ_ASSERT(sheet);
+ int32_t sheetDocIndex = IndexOfSheet(*sheet);
if (sheetDocIndex > newDocIndex)
break;
- mozilla::StyleSheet* sheetHandle = sheet;
-
// If the sheet is not owned by the document it can be an author
// sheet registered at nsStyleSheetService or an additional author
// sheet on the document, which means the new
@@ -44,11 +43,11 @@ nsIDocument::FindDocStyleSheetInsertionPoint(
if (sheetDocIndex < 0) {
if (sheetService) {
auto& authorSheets = *sheetService->AuthorStyleSheets();
- if (authorSheets.IndexOf(sheetHandle) != authorSheets.NoIndex) {
+ if (authorSheets.IndexOf(sheet) != authorSheets.NoIndex) {
break;
}
}
- if (sheetHandle == GetFirstAdditionalAuthorSheet()) {
+ if (sheet == GetFirstAdditionalAuthorSheet()) {
break;
}
}
diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp
index 212110b72..d0cbdb454 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1243,7 +1243,7 @@ nsINode::RemoveEventListener(const nsAString& aType,
NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode)
nsresult
-nsINode::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsINode::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
// This is only here so that we can use the NS_DECL_NSIDOMTARGET macro
NS_ABORT();
@@ -1515,7 +1515,6 @@ nsINode::SetExplicitBaseURI(nsIURI* aURI)
{
nsresult rv = SetProperty(nsGkAtoms::baseURIProperty, aURI, ReleaseURI);
if (NS_SUCCEEDED(rv)) {
- SetHasExplicitBaseURI();
NS_ADDREF(aURI);
}
return rv;
@@ -3133,3 +3132,9 @@ nsINode::IsStyledByServo() const
return OwnerDoc()->IsStyledByServo();
}
#endif
+
+DocGroup*
+nsINode::GetDocGroup() const
+{
+ return OwnerDoc()->GetDocGroup();
+}
diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h
index d82f5f899..7fb535701 100644
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -72,6 +72,7 @@ inline bool IsSpaceCharacter(char aChar) {
class AccessibleNode;
struct BoxQuadOptions;
struct ConvertCoordinateOptions;
+class DocGroup;
class DOMPoint;
class DOMQuad;
class DOMRectReadOnly;
@@ -126,9 +127,28 @@ enum {
NODE_IS_EDITABLE = NODE_FLAG_BIT(7),
- // For all Element nodes, NODE_MAY_HAVE_CLASS is guaranteed to be set if the
- // node in fact has a class, but may be set even if it doesn't.
- NODE_MAY_HAVE_CLASS = NODE_FLAG_BIT(8),
+ // This node was created by layout as native anonymous content. This
+ // generally corresponds to things created by nsIAnonymousContentCreator,
+ // though there are exceptions (svg:use content does not have this flag
+ // set, and any non-nsIAnonymousContentCreator callers of
+ // SetIsNativeAnonymousRoot also get this flag).
+ //
+ // One very important aspect here is that this node is not transitive over
+ // the subtree (if you want that, use NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE).
+ // If Gecko code somewhere attaches children to a node with this bit set,
+ // the children will not have the bit themselves unless the calling code sets
+ // it explicitly. This means that XBL content bound to NAC doesn't get this
+ // bit, nor do nodes inserted by editor.
+ //
+ // For now, this bit exists primarily to control style inheritance behavior,
+ // since the nodes for which we set it are often used to implement pseudo-
+ // elements, which need to inherit style from a script-visible element.
+ //
+ // A more general principle for this bit might be this: If the node is entirely
+ // a detail of layout, is not script-observable in any way, and other engines
+ // might accomplish the same task with a nodeless layout frame, then the node
+ // should have this bit set.
+ NODE_IS_NATIVE_ANONYMOUS = NODE_FLAG_BIT(8),
// Whether the node participates in a shadow tree.
NODE_IS_IN_SHADOW_TREE = NODE_FLAG_BIT(9),
@@ -280,6 +300,7 @@ class nsINode : public mozilla::dom::EventTarget
public:
typedef mozilla::dom::BoxQuadOptions BoxQuadOptions;
typedef mozilla::dom::ConvertCoordinateOptions ConvertCoordinateOptions;
+ typedef mozilla::dom::DocGroup DocGroup;
typedef mozilla::dom::DOMPoint DOMPoint;
typedef mozilla::dom::DOMPointInit DOMPointInit;
typedef mozilla::dom::DOMQuad DOMQuad;
@@ -389,6 +410,12 @@ public:
*/
virtual bool IsNodeOfType(uint32_t aFlags) const = 0;
+ bool
+ IsSlotable() const
+ {
+ return IsElement() || IsNodeOfType(eTEXT);
+ }
+
virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
/**
@@ -589,6 +616,11 @@ public:
}
/**
+ * Returns the DocGroup of the "node document" of this node.
+ */
+ DocGroup* GetDocGroup() const;
+
+ /**
* Print a debugger friendly descriptor of this element. This will describe
* the position of this element in the document.
*/
@@ -921,6 +953,14 @@ public:
inline nsINode* GetFlattenedTreeParentNode() const;
/**
+ * Like GetFlattenedTreeParentNode, but returns null for any native
+ * anonymous content that was generated for ancestor frames of the
+ * root element's primary frame, such as scrollbar elements created
+ * by the root scroll frame.
+ */
+ inline nsINode* GetFlattenedTreeParentNodeForStyle() const;
+
+ /**
* Get the parent nsINode for this node if it is an Element.
* @return the parent node
*/
@@ -1204,6 +1244,15 @@ public:
}
/**
+ * Returns true if |this| is native anonymous (i.e. created by
+ * nsIAnonymousContentCreator);
+ */
+ bool IsNativeAnonymous() const
+ {
+ return HasFlag(NODE_IS_NATIVE_ANONYMOUS);
+ }
+
+ /**
* Returns true if |this| or any of its ancestors is native anonymous.
*/
bool IsInNativeAnonymousSubtree() const
@@ -1335,10 +1384,11 @@ public:
protected:
nsIURI* GetExplicitBaseURI() const {
- if (HasExplicitBaseURI()) {
- return static_cast<nsIURI*>(GetProperty(nsGkAtoms::baseURIProperty));
+ if (!HasProperties()) {
+ return nullptr;
}
- return nullptr;
+
+ return static_cast<nsIURI*>(GetProperty(nsGkAtoms::baseURIProperty));
}
public:
@@ -1541,6 +1591,8 @@ private:
// cases lie for nsXMLElement, such as when the node has been moved between
// documents with different id mappings.
ElementHasID,
+ // Set if the element might have a class.
+ ElementMayHaveClass,
// Set if the element might have inline style.
ElementMayHaveStyle,
// Set if the element has a name attribute set.
@@ -1559,8 +1611,6 @@ private:
// Maybe set if the node is a root of a subtree
// which needs to be kept in the purple buffer.
NodeIsPurpleRoot,
- // Set if the node has an explicit base URI stored
- NodeHasExplicitBaseURI,
// Set if the element has some style states locked
ElementHasLockedStyleStates,
// Set if element has pointer locked
@@ -1571,10 +1621,11 @@ private:
NodeIsContent,
// Set if the node has animations or transitions
ElementHasAnimations,
- // Set if node has a dir attribute with a valid value (ltr, rtl, or auto)
+ // Set if node has a dir attribute with a valid value (ltr, rtl, or auto).
+ // Note that we cannot compute this from the dir attribute event state
+ // flags, because we can't use those to distinguish
+ // <bdi dir="some-invalid-value"> and <bdi dir="auto">.
NodeHasValidDirAttribute,
- // Set if node has a dir attribute with a fixed value (ltr or rtl, NOT auto)
- NodeHasFixedDir,
// Set if the node has dir=auto and has a property pointing to the text
// node that determines its direction
NodeHasDirAutoSet,
@@ -1582,8 +1633,6 @@ private:
// and has a TextNodeDirectionalityMap property listing the elements whose
// direction it determines.
NodeHasTextNodeDirectionalityMap,
- // Set if the node has dir=auto.
- NodeHasDirAuto,
// Set if a node in the node's parent chain has dir=auto.
NodeAncestorHasDirAuto,
// Set if the element is in the scope of a scoped style sheet; this flag is
@@ -1637,6 +1686,8 @@ public:
{ SetBoolFlag(NodeHasRenderingObservers, aValue); }
bool IsContent() const { return GetBoolFlag(NodeIsContent); }
bool HasID() const { return GetBoolFlag(ElementHasID); }
+ bool MayHaveClass() const { return GetBoolFlag(ElementMayHaveClass); }
+ void SetMayHaveClass() { SetBoolFlag(ElementMayHaveClass); }
bool MayHaveStyle() const { return GetBoolFlag(ElementMayHaveStyle); }
bool HasName() const { return GetBoolFlag(ElementHasName); }
bool MayHaveContentEditableAttr() const
@@ -1676,17 +1727,6 @@ public:
void SetHasValidDir() { SetBoolFlag(NodeHasValidDirAttribute); }
void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); }
bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); }
- void SetHasFixedDir() {
- MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
- "SetHasFixedDir on text node");
- SetBoolFlag(NodeHasFixedDir);
- }
- void ClearHasFixedDir() {
- MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
- "ClearHasFixedDir on text node");
- ClearBoolFlag(NodeHasFixedDir);
- }
- bool HasFixedDir() const { return GetBoolFlag(NodeHasFixedDir); }
void SetHasDirAutoSet() {
MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
"SetHasDirAutoSet on text node");
@@ -1715,16 +1755,12 @@ public:
return GetBoolFlag(NodeHasTextNodeDirectionalityMap);
}
- void SetHasDirAuto() { SetBoolFlag(NodeHasDirAuto); }
- void ClearHasDirAuto() { ClearBoolFlag(NodeHasDirAuto); }
- bool HasDirAuto() const { return GetBoolFlag(NodeHasDirAuto); }
-
void SetAncestorHasDirAuto() { SetBoolFlag(NodeAncestorHasDirAuto); }
void ClearAncestorHasDirAuto() { ClearBoolFlag(NodeAncestorHasDirAuto); }
bool AncestorHasDirAuto() const { return GetBoolFlag(NodeAncestorHasDirAuto); }
- bool NodeOrAncestorHasDirAuto() const
- { return HasDirAuto() || AncestorHasDirAuto(); }
+ // Implemented in nsIContentInlines.h.
+ inline bool NodeOrAncestorHasDirAuto() const;
void SetIsElementInStyleScope(bool aValue) {
MOZ_ASSERT(IsElement(), "SetIsInStyleScope on a non-Element node");
@@ -1766,8 +1802,6 @@ protected:
void ClearHasName() { ClearBoolFlag(ElementHasName); }
void SetMayHaveContentEditableAttr()
{ SetBoolFlag(ElementMayHaveContentEditableAttr); }
- bool HasExplicitBaseURI() const { return GetBoolFlag(NodeHasExplicitBaseURI); }
- void SetHasExplicitBaseURI() { SetBoolFlag(NodeHasExplicitBaseURI); }
void SetHasLockedStyleStates() { SetBoolFlag(ElementHasLockedStyleStates); }
void ClearHasLockedStyleStates() { ClearBoolFlag(ElementHasLockedStyleStates); }
bool HasLockedStyleStates() const
diff --git a/dom/base/nsInProcessTabChildGlobal.cpp b/dom/base/nsInProcessTabChildGlobal.cpp
index 10ccf4aec..9885b41a8 100644
--- a/dom/base/nsInProcessTabChildGlobal.cpp
+++ b/dom/base/nsInProcessTabChildGlobal.cpp
@@ -97,7 +97,7 @@ nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
mozilla::HoldJSObjects(this);
// If owner corresponds to an <iframe mozbrowser> or <iframe mozapp>, we'll
- // have to tweak our PreHandleEvent implementation.
+ // GetEventTargetParent implementation.
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
if (browserFrame) {
mIsBrowserOrAppFrame = browserFrame->GetReallyIsBrowserOrApp();
@@ -251,7 +251,7 @@ nsInProcessTabChildGlobal::GetOwnerContent()
}
nsresult
-nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsInProcessTabChildGlobal::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mForceContentDispatch = true;
aVisitor.mCanHandle = true;
@@ -270,7 +270,7 @@ nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
#endif
if (mPreventEventsEscaping) {
- aVisitor.mParentTarget = nullptr;
+ aVisitor.SetParentTarget(nullptr, false);
return NS_OK;
}
@@ -278,11 +278,13 @@ nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
(!mOwner || !nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))) {
if (mOwner) {
if (nsPIDOMWindowInner* innerWindow = mOwner->OwnerDoc()->GetInnerWindow()) {
- aVisitor.mParentTarget = innerWindow->GetParentTarget();
+ // 'this' is already a "chrome handler", so we consider window's
+ // parent target to be part of that same part of the event path.
+ aVisitor.SetParentTarget(innerWindow->GetParentTarget(), false);
}
}
} else {
- aVisitor.mParentTarget = mOwner;
+ aVisitor.SetParentTarget(mOwner, false);
}
return NS_OK;
diff --git a/dom/base/nsInProcessTabChildGlobal.h b/dom/base/nsInProcessTabChildGlobal.h
index e7dd9cb5a..55ffc5965 100644
--- a/dom/base/nsInProcessTabChildGlobal.h
+++ b/dom/base/nsInProcessTabChildGlobal.h
@@ -96,7 +96,7 @@ public:
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal) override;
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
NS_IMETHOD AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
@@ -168,7 +168,7 @@ protected:
// Is this the message manager for an in-process <iframe mozbrowser> or
// <iframe mozapp>? This affects where events get sent, so it affects
- // PreHandleEvent.
+ // GetEventTargetParent.
bool mIsBrowserOrAppFrame;
bool mPreventEventsEscaping;
diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp
index dfd380fc2..efea3ee40 100644
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -57,6 +57,7 @@
#include "mozilla/dom/ErrorEvent.h"
#include "nsAXPCNativeCallContext.h"
#include "mozilla/CycleCollectedJSContext.h"
+#include "mozilla/Telemetry.h"
#include "nsJSPrincipals.h"
diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp
index b6c843065..c24adc739 100644
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -31,6 +31,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ScriptSettings.h"
+using namespace mozilla;
using namespace mozilla::dom;
bool
diff --git a/dom/base/nsMappedAttributeElement.cpp b/dom/base/nsMappedAttributeElement.cpp
index 1c1f8838f..d06cbf2bc 100644
--- a/dom/base/nsMappedAttributeElement.cpp
+++ b/dom/base/nsMappedAttributeElement.cpp
@@ -15,17 +15,19 @@ nsMappedAttributeElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
}
bool
-nsMappedAttributeElement::SetMappedAttribute(nsIDocument* aDocument,
- nsIAtom* aName,
- nsAttrValue& aValue,
- nsresult* aRetval)
+nsMappedAttributeElement::SetAndSwapMappedAttribute(nsIDocument* aDocument,
+ nsIAtom* aName,
+ nsAttrValue& aValue,
+ bool* aValueWasSet,
+ nsresult* aRetval)
+
{
NS_PRECONDITION(aDocument == GetComposedDoc(), "Unexpected document");
nsHTMLStyleSheet* sheet = aDocument ?
aDocument->GetAttributeStyleSheet() : nullptr;
- *aRetval = mAttrsAndChildren.SetAndTakeMappedAttr(aName, aValue,
- this, sheet);
+ *aRetval = mAttrsAndChildren.SetAndSwapMappedAttr(aName, aValue,
+ this, sheet, aValueWasSet);
return true;
}
diff --git a/dom/base/nsMappedAttributeElement.h b/dom/base/nsMappedAttributeElement.h
index 4668b36a1..a37af85ca 100644
--- a/dom/base/nsMappedAttributeElement.h
+++ b/dom/base/nsMappedAttributeElement.h
@@ -39,10 +39,11 @@ public:
nsRuleData* aRuleData);
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
- virtual bool SetMappedAttribute(nsIDocument* aDocument,
- nsIAtom* aName,
- nsAttrValue& aValue,
- nsresult* aRetval) override;
+ virtual bool SetAndSwapMappedAttribute(nsIDocument* aDocument,
+ nsIAtom* aName,
+ nsAttrValue& aValue,
+ bool* aValueWasSet,
+ nsresult* aRetval) override;
};
#endif // NS_MAPPEDATTRIBUTEELEMENT_H_
diff --git a/dom/base/nsMappedAttributes.cpp b/dom/base/nsMappedAttributes.cpp
index a3accd2a7..05ad42310 100644
--- a/dom/base/nsMappedAttributes.cpp
+++ b/dom/base/nsMappedAttributes.cpp
@@ -62,11 +62,17 @@ nsMappedAttributes::Clone(bool aWillAddAttr)
void* nsMappedAttributes::operator new(size_t aSize, uint32_t aAttrCount) CPP_THROW_NEW
{
- NS_ASSERTION(aAttrCount > 0, "zero-attribute nsMappedAttributes requested");
+ size_t size = aSize + aAttrCount * sizeof(InternalAttr);
// aSize will include the mAttrs buffer so subtract that.
- void* newAttrs = ::operator new(aSize - sizeof(void*[1]) +
- aAttrCount * sizeof(InternalAttr));
+ // We don't want to under-allocate, however, so do not subtract
+ // if we have zero attributes. The zero attribute case only happens
+ // for <body>'s mapped attributes
+ if (aAttrCount != 0) {
+ size -= sizeof(void*[1]);
+ }
+
+ void* newAttrs = ::operator new(size);
#ifdef DEBUG
static_cast<nsMappedAttributes*>(newAttrs)->mBufferSize = aAttrCount;
@@ -79,15 +85,16 @@ NS_IMPL_ISUPPORTS(nsMappedAttributes,
nsIStyleRule)
void
-nsMappedAttributes::SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue)
+nsMappedAttributes::SetAndSwapAttr(nsIAtom* aAttrName, nsAttrValue& aValue,
+ bool* aValueWasSet)
{
NS_PRECONDITION(aAttrName, "null name");
-
+ *aValueWasSet = false;
uint32_t i;
for (i = 0; i < mAttrCount && !Attrs()[i].mName.IsSmaller(aAttrName); ++i) {
if (Attrs()[i].mName.Equals(aAttrName)) {
- Attrs()[i].mValue.Reset();
Attrs()[i].mValue.SwapValueWith(aValue);
+ *aValueWasSet = true;
return;
}
}
diff --git a/dom/base/nsMappedAttributes.h b/dom/base/nsMappedAttributes.h
index f00b888b9..0c24fd973 100644
--- a/dom/base/nsMappedAttributes.h
+++ b/dom/base/nsMappedAttributes.h
@@ -33,7 +33,8 @@ public:
NS_DECL_ISUPPORTS
- void SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue);
+ void SetAndSwapAttr(nsIAtom* aAttrName, nsAttrValue& aValue,
+ bool* aValueWasSet);
const nsAttrValue* GetAttr(nsIAtom* aAttrName) const;
const nsAttrValue* GetAttr(const nsAString& aAttrName) const;
diff --git a/dom/base/nsNodeUtils.cpp b/dom/base/nsNodeUtils.cpp
index 384e56cde..5fdd24e43 100644
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -65,7 +65,7 @@ using mozilla::AutoJSContext;
} \
ShadowRoot* shadow = ShadowRoot::FromNode(node); \
if (shadow) { \
- node = shadow->GetPoolHost(); \
+ node = shadow->GetHost(); \
} else { \
node = node->GetParentNode(); \
} \
@@ -93,7 +93,7 @@ using mozilla::AutoJSContext;
} \
ShadowRoot* shadow = ShadowRoot::FromNode(node); \
if (shadow) { \
- node = shadow->GetPoolHost(); \
+ node = shadow->GetHost(); \
} else { \
node = node->GetParentNode(); \
} \
diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp
index d45a2c975..82e28f645 100644
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -49,6 +49,12 @@ nsRange::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return RangeBinding::Wrap(aCx, this, aGivenProto);
}
+DocGroup*
+nsRange::GetDocGroup() const
+{
+ return mOwner ? mOwner->GetDocGroup() : nullptr;
+}
+
/******************************************************
* stack based utilty class for managing monitor
******************************************************/
@@ -111,31 +117,37 @@ nsRange::CompareNodeToRange(nsINode* aNode, nsRange* aRange,
// so instead represent it by (node,0) and (node,numChildren)
parent = aNode;
nodeStart = 0;
- nodeEnd = aNode->GetChildCount();
+ uint32_t childCount = aNode->GetChildCount();
+ MOZ_ASSERT(childCount <= INT32_MAX,
+ "There shouldn't be over INT32_MAX children");
+ nodeEnd = static_cast<int32_t>(childCount);
}
else {
nodeStart = parent->IndexOf(aNode);
nodeEnd = nodeStart + 1;
+ MOZ_ASSERT(nodeStart < nodeEnd, "nodeStart shouldn't be INT32_MAX");
}
nsINode* rangeStartParent = aRange->GetStartParent();
nsINode* rangeEndParent = aRange->GetEndParent();
- int32_t rangeStartOffset = aRange->StartOffset();
- int32_t rangeEndOffset = aRange->EndOffset();
+ uint32_t rangeStartOffset = aRange->StartOffset();
+ uint32_t rangeEndOffset = aRange->EndOffset();
// is RANGE(start) <= NODE(start) ?
bool disconnected = false;
- *outNodeBefore = nsContentUtils::ComparePoints(rangeStartParent,
- rangeStartOffset,
- parent, nodeStart,
- &disconnected) > 0;
+ *outNodeBefore =
+ nsContentUtils::ComparePoints(rangeStartParent,
+ static_cast<int32_t>(rangeStartOffset),
+ parent, nodeStart,
+ &disconnected) > 0;
NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
// is RANGE(end) >= NODE(end) ?
- *outNodeAfter = nsContentUtils::ComparePoints(rangeEndParent,
- rangeEndOffset,
- parent, nodeEnd,
- &disconnected) < 0;
+ *outNodeAfter =
+ nsContentUtils::ComparePoints(rangeEndParent,
+ static_cast<int32_t>(rangeEndOffset),
+ parent, nodeEnd,
+ &disconnected) < 0;
NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
return NS_OK;
}
@@ -164,13 +176,17 @@ struct IsItemInRangeComparator
int operator()(const nsRange* const aRange) const
{
- int32_t cmp = nsContentUtils::ComparePoints(mNode, mEndOffset,
- aRange->GetStartParent(),
- aRange->StartOffset());
+ int32_t cmp =
+ nsContentUtils::ComparePoints(
+ mNode, static_cast<int32_t>(mEndOffset),
+ aRange->GetStartParent(),
+ static_cast<int32_t>(aRange->StartOffset()));
if (cmp == 1) {
- cmp = nsContentUtils::ComparePoints(mNode, mStartOffset,
- aRange->GetEndParent(),
- aRange->EndOffset());
+ cmp =
+ nsContentUtils::ComparePoints(
+ mNode, static_cast<int32_t>(mStartOffset),
+ aRange->GetEndParent(),
+ static_cast<int32_t>(aRange->EndOffset()));
if (cmp == -1) {
return 0;
}
@@ -266,48 +282,38 @@ nsRange::nsRange(nsINode* aNode)
/* static */
nsresult
-nsRange::CreateRange(nsINode* aStartParent, int32_t aStartOffset,
- nsINode* aEndParent, int32_t aEndOffset,
+nsRange::CreateRange(nsINode* aStartParent, uint32_t aStartOffset,
+ nsINode* aEndParent, uint32_t aEndOffset,
nsRange** aRange)
{
- nsCOMPtr<nsIDOMNode> startDomNode = do_QueryInterface(aStartParent);
- nsCOMPtr<nsIDOMNode> endDomNode = do_QueryInterface(aEndParent);
-
- nsresult rv = CreateRange(startDomNode, aStartOffset, endDomNode, aEndOffset,
- aRange);
-
- return rv;
+ MOZ_ASSERT(aRange);
+ *aRange = nullptr;
+ RefPtr<nsRange> range = new nsRange(aStartParent);
+ nsresult rv = range->SetStartAndEnd(aStartParent, aStartOffset,
+ aEndParent, aEndOffset);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ range.forget(aRange);
+ return NS_OK;
}
/* static */
nsresult
-nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
- nsIDOMNode* aEndParent, int32_t aEndOffset,
+nsRange::CreateRange(nsIDOMNode* aStartParent, uint32_t aStartOffset,
+ nsIDOMNode* aEndParent, uint32_t aEndOffset,
nsRange** aRange)
{
- MOZ_ASSERT(aRange);
- *aRange = nullptr;
-
nsCOMPtr<nsINode> startParent = do_QueryInterface(aStartParent);
- NS_ENSURE_ARG_POINTER(startParent);
-
- RefPtr<nsRange> range = new nsRange(startParent);
-
- nsresult rv = range->SetStart(startParent, aStartOffset);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = range->SetEnd(aEndParent, aEndOffset);
- NS_ENSURE_SUCCESS(rv, rv);
-
- range.forget(aRange);
- return NS_OK;
+ nsCOMPtr<nsINode> endParent = do_QueryInterface(aEndParent);
+ return CreateRange(startParent, aStartOffset, endParent, aEndOffset, aRange);
}
/* static */
nsresult
-nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
- nsIDOMNode* aEndParent, int32_t aEndOffset,
+nsRange::CreateRange(nsIDOMNode* aStartParent, uint32_t aStartOffset,
+ nsIDOMNode* aEndParent, uint32_t aEndOffset,
nsIDOMRange** aRange)
{
RefPtr<nsRange> range;
@@ -465,15 +471,27 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
// again (when the new text node is notified).
nsINode* parentNode = aContent->GetParentNode();
int32_t index = -1;
- if (parentNode == mEndParent && mEndOffset > 0 &&
- (index = parentNode->IndexOf(aContent)) + 1 == mEndOffset) {
- ++mEndOffset;
- mEndOffsetWasIncremented = true;
+ if (parentNode == mEndParent && mEndOffset > 0) {
+ index = parentNode->IndexOf(aContent);
+ NS_WARNING_ASSERTION(index >= 0,
+ "Shouldn't be called during removing the node or something");
+ if (static_cast<uint32_t>(index + 1) == mEndOffset) {
+ newEndNode = mEndParent;
+ newEndOffset = mEndOffset + 1;
+ MOZ_ASSERT(IsValidOffset(newEndOffset));
+ mEndOffsetWasIncremented = true;
+ }
}
- if (parentNode == mStartParent && mStartOffset > 0 &&
- (index != -1 ? index : parentNode->IndexOf(aContent)) + 1 == mStartOffset) {
- ++mStartOffset;
- mStartOffsetWasIncremented = true;
+ if (parentNode == mStartParent && mStartOffset > 0) {
+ if (index <= 0) {
+ index = parentNode->IndexOf(aContent);
+ }
+ if (static_cast<uint32_t>(index + 1) == mStartOffset) {
+ newStartNode = mStartParent;
+ newStartOffset = mStartOffset + 1;
+ MOZ_ASSERT(IsValidOffset(newStartOffset));
+ mStartOffsetWasIncremented = true;
+ }
}
#ifdef DEBUG
if (mStartOffsetWasIncremented || mEndOffsetWasIncremented) {
@@ -486,16 +504,15 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
// If the changed node contains our start boundary and the change starts
// before the boundary we'll need to adjust the offset.
- if (aContent == mStartParent &&
- aInfo->mChangeStart < static_cast<uint32_t>(mStartOffset)) {
+ if (aContent == mStartParent && aInfo->mChangeStart < mStartOffset) {
if (aInfo->mDetails) {
// splitText(), aInfo->mDetails->mNextSibling is the new text node
NS_ASSERTION(aInfo->mDetails->mType ==
CharacterDataChangeInfo::Details::eSplit,
"only a split can start before the end");
- NS_ASSERTION(static_cast<uint32_t>(mStartOffset) <= aInfo->mChangeEnd + 1,
+ NS_ASSERTION(mStartOffset <= aInfo->mChangeEnd + 1,
"mStartOffset is beyond the end of this node");
- newStartOffset = static_cast<uint32_t>(mStartOffset) - aInfo->mChangeStart;
+ newStartOffset = mStartOffset - aInfo->mChangeStart;
newStartNode = aInfo->mDetails->mNextSibling;
if (MOZ_UNLIKELY(aContent == mRoot)) {
newRoot = IsValidBoundary(newStartNode);
@@ -512,7 +529,7 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
} else {
// If boundary is inside changed text, position it before change
// else adjust start offset for the change in length.
- mStartOffset = static_cast<uint32_t>(mStartOffset) <= aInfo->mChangeEnd ?
+ mStartOffset = mStartOffset <= aInfo->mChangeEnd ?
aInfo->mChangeStart :
mStartOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
aInfo->mReplaceLength;
@@ -522,16 +539,15 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
// Do the same thing for the end boundary, except for splitText of a node
// with no parent then only switch to the new node if the start boundary
// did so too (otherwise the range would end up with disconnected nodes).
- if (aContent == mEndParent &&
- aInfo->mChangeStart < static_cast<uint32_t>(mEndOffset)) {
+ if (aContent == mEndParent && aInfo->mChangeStart < mEndOffset) {
if (aInfo->mDetails && (aContent->GetParentNode() || newStartNode)) {
// splitText(), aInfo->mDetails->mNextSibling is the new text node
NS_ASSERTION(aInfo->mDetails->mType ==
CharacterDataChangeInfo::Details::eSplit,
"only a split can start before the end");
- NS_ASSERTION(static_cast<uint32_t>(mEndOffset) <= aInfo->mChangeEnd + 1,
+ NS_ASSERTION(mEndOffset <= aInfo->mChangeEnd + 1,
"mEndOffset is beyond the end of this node");
- newEndOffset = static_cast<uint32_t>(mEndOffset) - aInfo->mChangeStart;
+ newEndOffset = mEndOffset - aInfo->mChangeStart;
newEndNode = aInfo->mDetails->mNextSibling;
bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
@@ -544,7 +560,7 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
}
} else {
- mEndOffset = static_cast<uint32_t>(mEndOffset) <= aInfo->mChangeEnd ?
+ mEndOffset = mEndOffset <= aInfo->mChangeEnd ?
aInfo->mChangeStart :
mEndOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
aInfo->mReplaceLength;
@@ -557,14 +573,14 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
// that will be removed
nsIContent* removed = aInfo->mDetails->mNextSibling;
if (removed == mStartParent) {
- newStartOffset = static_cast<uint32_t>(mStartOffset) + aInfo->mChangeStart;
+ newStartOffset = mStartOffset + aInfo->mChangeStart;
newStartNode = aContent;
if (MOZ_UNLIKELY(removed == mRoot)) {
newRoot = IsValidBoundary(newStartNode);
}
}
if (removed == mEndParent) {
- newEndOffset = static_cast<uint32_t>(mEndOffset) + aInfo->mChangeStart;
+ newEndOffset = mEndOffset + aInfo->mChangeStart;
newEndNode = aContent;
if (MOZ_UNLIKELY(removed == mRoot)) {
newRoot = IsValidBoundary(newEndNode);
@@ -578,13 +594,13 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
// point before the first child is never affected by normalize().)
nsINode* parentNode = aContent->GetParentNode();
if (parentNode == mStartParent && mStartOffset > 0 &&
- uint32_t(mStartOffset) < parentNode->GetChildCount() &&
+ mStartOffset < parentNode->GetChildCount() &&
removed == parentNode->GetChildAt(mStartOffset)) {
newStartNode = aContent;
newStartOffset = aInfo->mChangeStart;
}
if (parentNode == mEndParent && mEndOffset > 0 &&
- uint32_t(mEndOffset) < parentNode->GetChildCount() &&
+ mEndOffset < parentNode->GetChildCount() &&
removed == parentNode->GetChildAt(mEndOffset)) {
newEndNode = aContent;
newEndOffset = aInfo->mChangeEnd;
@@ -649,13 +665,19 @@ nsRange::ContentInserted(nsIDocument* aDocument,
nsINode* container = NODE_FROM(aContainer, aDocument);
// Adjust position if a sibling was inserted.
- if (container == mStartParent && aIndexInContainer < mStartOffset &&
+ if (container == mStartParent &&
+ (NS_WARN_IF(aIndexInContainer < 0) ||
+ static_cast<uint32_t>(aIndexInContainer) < mStartOffset) &&
!mStartOffsetWasIncremented) {
++mStartOffset;
+ MOZ_ASSERT(IsValidOffset(mStartOffset));
}
- if (container == mEndParent && aIndexInContainer < mEndOffset &&
+ if (container == mEndParent &&
+ (NS_WARN_IF(aIndexInContainer < 0) ||
+ static_cast<uint32_t>(aIndexInContainer) < mEndOffset) &&
!mEndOffsetWasIncremented) {
++mEndOffset;
+ MOZ_ASSERT(IsValidOffset(mEndOffset));
}
if (container->IsSelectionDescendant() &&
!aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
@@ -694,7 +716,7 @@ nsRange::ContentRemoved(nsIDocument* aDocument,
// Adjust position if a sibling was removed...
if (container == mStartParent) {
- if (aIndexInContainer < mStartOffset) {
+ if (aIndexInContainer < static_cast<int32_t>(mStartOffset)) {
--mStartOffset;
}
} else { // ...or gravitate if an ancestor was removed.
@@ -704,7 +726,7 @@ nsRange::ContentRemoved(nsIDocument* aDocument,
// Do same thing for end boundry.
if (container == mEndParent) {
- if (aIndexInContainer < mEndOffset) {
+ if (aIndexInContainer < static_cast<int32_t>(mEndOffset)) {
--mEndOffset;
}
} else if (didCheckStartParentDescendant && mStartParent == mEndParent) {
@@ -763,12 +785,15 @@ nsRange::ParentChainChanged(nsIContent *aContent)
* Utilities for comparing points: API from nsIDOMRange
******************************************************/
NS_IMETHODIMP
-nsRange::IsPointInRange(nsIDOMNode* aParent, int32_t aOffset, bool* aResult)
+nsRange::IsPointInRange(nsIDOMNode* aParent, uint32_t aOffset, bool* aResult)
{
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
if (!parent) {
return NS_ERROR_DOM_NOT_OBJECT_ERR;
}
+ if (NS_WARN_IF(!IsValidOffset(aOffset))) {
+ return NS_ERROR_DOM_INDEX_SIZE_ERR;
+ }
ErrorResult rv;
*aResult = IsPointInRange(*parent, aOffset, rv);
@@ -791,7 +816,7 @@ nsRange::IsPointInRange(nsINode& aParent, uint32_t aOffset, ErrorResult& aRv)
// returns -1 if point is before range, 0 if point is in range,
// 1 if point is after range.
NS_IMETHODIMP
-nsRange::ComparePoint(nsIDOMNode* aParent, int32_t aOffset, int16_t* aResult)
+nsRange::ComparePoint(nsIDOMNode* aParent, uint32_t aOffset, int16_t* aResult)
{
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
NS_ENSURE_TRUE(parent, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
@@ -825,14 +850,18 @@ nsRange::ComparePoint(nsINode& aParent, uint32_t aOffset, ErrorResult& aRv)
return 0;
}
- int32_t cmp;
- if ((cmp = nsContentUtils::ComparePoints(&aParent, aOffset,
- mStartParent, mStartOffset)) <= 0) {
-
+ int32_t cmp =
+ nsContentUtils::ComparePoints(&aParent,
+ static_cast<int32_t>(aOffset),
+ mStartParent,
+ static_cast<int32_t>(mStartOffset));
+ if (cmp <= 0) {
return cmp;
}
- if (nsContentUtils::ComparePoints(mEndParent, mEndOffset,
- &aParent, aOffset) == -1) {
+ if (nsContentUtils::ComparePoints(mEndParent,
+ static_cast<int32_t>(mEndOffset),
+ &aParent,
+ static_cast<int32_t>(aOffset)) == -1) {
return 1;
}
@@ -875,12 +904,15 @@ nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv)
// Steps 6-7.
// Note: if disconnected is true, ComparePoints returns 1.
bool disconnected = false;
- bool result = nsContentUtils::ComparePoints(mStartParent, mStartOffset,
- parent, nodeIndex + 1,
- &disconnected) < 0 &&
- nsContentUtils::ComparePoints(parent, nodeIndex,
- mEndParent, mEndOffset,
- &disconnected) < 0;
+ bool result =
+ nsContentUtils::ComparePoints(mStartParent,
+ static_cast<int32_t>(mStartOffset),
+ parent, nodeIndex + 1,
+ &disconnected) < 0 &&
+ nsContentUtils::ComparePoints(parent, nodeIndex,
+ mEndParent,
+ static_cast<int32_t>(mEndOffset),
+ &disconnected) < 0;
// Step 2.
if (disconnected) {
@@ -899,8 +931,8 @@ nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv)
// Calling DoSetRange with either parent argument null will collapse
// the range to have both endpoints point to the other node
void
-nsRange::DoSetRange(nsINode* aStartN, int32_t aStartOffset,
- nsINode* aEndN, int32_t aEndOffset,
+nsRange::DoSetRange(nsINode* aStartN, uint32_t aStartOffset,
+ nsINode* aEndN, uint32_t aEndOffset,
nsINode* aRoot, bool aNotInsertedYet)
{
NS_PRECONDITION((aStartN && aEndN && aRoot) ||
@@ -926,6 +958,8 @@ nsRange::DoSetRange(nsINode* aStartN, int32_t aStartOffset,
/*For backward compatibility*/
aRoot->IsNodeOfType(nsINode::eCONTENT))),
"Bad root");
+ MOZ_ASSERT(IsValidOffset(aStartOffset));
+ MOZ_ASSERT(IsValidOffset(aEndOffset));
if (mRoot != aRoot) {
if (mRoot) {
@@ -1038,7 +1072,7 @@ nsRange::GetStartContainer(ErrorResult& aRv) const
}
NS_IMETHODIMP
-nsRange::GetStartOffset(int32_t* aStartOffset)
+nsRange::GetStartOffset(uint32_t* aStartOffset)
{
if (!mIsPositioned)
return NS_ERROR_NOT_INITIALIZED;
@@ -1080,7 +1114,7 @@ nsRange::GetEndContainer(ErrorResult& aRv) const
}
NS_IMETHODIMP
-nsRange::GetEndOffset(int32_t* aEndOffset)
+nsRange::GetEndOffset(uint32_t* aEndOffset)
{
if (!mIsPositioned)
return NS_ERROR_NOT_INITIALIZED;
@@ -1137,6 +1171,15 @@ nsRange::GetCommonAncestorContainer(nsIDOMNode** aCommonParent)
return rv.StealNSResult();
}
+/* static */
+bool
+nsRange::IsValidOffset(nsINode* aNode, uint32_t aOffset)
+{
+ return aNode &&
+ IsValidOffset(aOffset) &&
+ static_cast<size_t>(aOffset) <= aNode->Length();
+}
+
nsINode*
nsRange::IsValidBoundary(nsINode* aNode)
{
@@ -1197,7 +1240,7 @@ nsRange::SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
}
NS_IMETHODIMP
-nsRange::SetStart(nsIDOMNode* aParent, int32_t aOffset)
+nsRange::SetStart(nsIDOMNode* aParent, uint32_t aOffset)
{
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
if (!parent) {
@@ -1210,22 +1253,24 @@ nsRange::SetStart(nsIDOMNode* aParent, int32_t aOffset)
}
/* virtual */ nsresult
-nsRange::SetStart(nsINode* aParent, int32_t aOffset)
+nsRange::SetStart(nsINode* aParent, uint32_t aOffset)
{
nsINode* newRoot = IsValidBoundary(aParent);
if (!newRoot) {
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
}
- if (aOffset < 0 || uint32_t(aOffset) > aParent->Length()) {
+ if (!IsValidOffset(aParent, aOffset)) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
// Collapse if not positioned yet, if positioned in another doc or
// if the new start is after end.
if (!mIsPositioned || newRoot != mRoot ||
- nsContentUtils::ComparePoints(aParent, aOffset,
- mEndParent, mEndOffset) == 1) {
+ nsContentUtils::ComparePoints(aParent,
+ static_cast<int32_t>(aOffset),
+ mEndParent,
+ static_cast<int32_t>(mEndOffset)) == 1) {
DoSetRange(aParent, aOffset, aParent, aOffset, newRoot);
return NS_OK;
@@ -1246,7 +1291,12 @@ nsRange::SetStartBefore(nsINode& aNode, ErrorResult& aRv)
}
AutoInvalidateSelection atEndOfBlock(this);
- aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode));
+ // If the node is being removed from its parent, GetContainerAndOffsetBefore()
+ // returns nullptr. Then, SetStart() will throw
+ // NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
+ uint32_t offset = UINT32_MAX;
+ nsINode* parent = GetParentAndOffsetBefore(&aNode, &offset);
+ aRv = SetStart(parent, offset);
}
NS_IMETHODIMP
@@ -1272,7 +1322,12 @@ nsRange::SetStartAfter(nsINode& aNode, ErrorResult& aRv)
}
AutoInvalidateSelection atEndOfBlock(this);
- aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode) + 1);
+ // If the node is being removed from its parent, GetContainerAndOffsetAfter()
+ // returns nullptr. Then, SetStart() will throw
+ // NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
+ uint32_t offset = UINT32_MAX;
+ nsINode* parent = GetParentAndOffsetAfter(&aNode, &offset);
+ aRv = SetStart(parent, offset);
}
NS_IMETHODIMP
@@ -1301,7 +1356,7 @@ nsRange::SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
}
NS_IMETHODIMP
-nsRange::SetEnd(nsIDOMNode* aParent, int32_t aOffset)
+nsRange::SetEnd(nsIDOMNode* aParent, uint32_t aOffset)
{
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
if (!parent) {
@@ -1314,22 +1369,24 @@ nsRange::SetEnd(nsIDOMNode* aParent, int32_t aOffset)
}
/* virtual */ nsresult
-nsRange::SetEnd(nsINode* aParent, int32_t aOffset)
+nsRange::SetEnd(nsINode* aParent, uint32_t aOffset)
{
nsINode* newRoot = IsValidBoundary(aParent);
if (!newRoot) {
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
}
- if (aOffset < 0 || uint32_t(aOffset) > aParent->Length()) {
+ if (!IsValidOffset(aParent, aOffset)) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
// Collapse if not positioned yet, if positioned in another doc or
// if the new end is before start.
if (!mIsPositioned || newRoot != mRoot ||
- nsContentUtils::ComparePoints(mStartParent, mStartOffset,
- aParent, aOffset) == 1) {
+ nsContentUtils::ComparePoints(mStartParent,
+ static_cast<int32_t>(mStartOffset),
+ aParent,
+ static_cast<int32_t>(aOffset)) == 1) {
DoSetRange(aParent, aOffset, aParent, aOffset, newRoot);
return NS_OK;
@@ -1340,6 +1397,66 @@ nsRange::SetEnd(nsINode* aParent, int32_t aOffset)
return NS_OK;
}
+nsresult
+nsRange::SetStartAndEnd(nsINode* aStartParent, uint32_t aStartOffset,
+ nsINode* aEndParent, uint32_t aEndOffset)
+{
+ if (NS_WARN_IF(!aStartParent) || NS_WARN_IF(!aEndParent)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ nsINode* newStartRoot = IsValidBoundary(aStartParent);
+ if (!newStartRoot) {
+ return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
+ }
+ if (!IsValidOffset(aStartParent, aStartOffset)) {
+ return NS_ERROR_DOM_INDEX_SIZE_ERR;
+ }
+
+ if (aStartParent == aEndParent) {
+ if (!IsValidOffset(aEndParent, aEndOffset)) {
+ return NS_ERROR_DOM_INDEX_SIZE_ERR;
+ }
+ // If the end offset is less than the start offset, this should be
+ // collapsed at the end offset.
+ if (aStartOffset > aEndOffset) {
+ DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newStartRoot);
+ } else {
+ DoSetRange(aStartParent, aStartOffset,
+ aEndParent, aEndOffset, newStartRoot);
+ }
+ return NS_OK;
+ }
+
+ nsINode* newEndRoot = IsValidBoundary(aEndParent);
+ if (!newEndRoot) {
+ return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
+ }
+ if (!IsValidOffset(aEndParent, aEndOffset)) {
+ return NS_ERROR_DOM_INDEX_SIZE_ERR;
+ }
+
+ // If they have different root, this should be collapsed at the end point.
+ if (newStartRoot != newEndRoot) {
+ DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newEndRoot);
+ return NS_OK;
+ }
+
+ // If the end point is before the start point, this should be collapsed at
+ // the end point.
+ if (nsContentUtils::ComparePoints(aStartParent,
+ static_cast<int32_t>(aStartOffset),
+ aEndParent,
+ static_cast<int32_t>(aEndOffset)) == 1) {
+ DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newEndRoot);
+ return NS_OK;
+ }
+
+ // Otherwise, set the range as specified.
+ DoSetRange(aStartParent, aStartOffset, aEndParent, aEndOffset, newStartRoot);
+ return NS_OK;
+}
+
void
nsRange::SetEndBefore(nsINode& aNode, ErrorResult& aRv)
{
@@ -1350,7 +1467,12 @@ nsRange::SetEndBefore(nsINode& aNode, ErrorResult& aRv)
}
AutoInvalidateSelection atEndOfBlock(this);
- aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode));
+ // If the node is being removed from its parent, GetContainerAndOffsetBefore()
+ // returns nullptr. Then, SetEnd() will throw
+ // NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
+ uint32_t offset = UINT32_MAX;
+ nsINode* parent = GetParentAndOffsetBefore(&aNode, &offset);
+ aRv = SetEnd(parent, offset);
}
NS_IMETHODIMP
@@ -1376,7 +1498,12 @@ nsRange::SetEndAfter(nsINode& aNode, ErrorResult& aRv)
}
AutoInvalidateSelection atEndOfBlock(this);
- aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode) + 1);
+ // If the node is being removed from its parent, GetContainerAndOffsetAfter()
+ // returns nullptr. Then, SetEnd() will throw
+ // NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
+ uint32_t offset = UINT32_MAX;
+ nsINode* parent = GetParentAndOffsetAfter(&aNode, &offset);
+ aRv = SetEnd(parent, offset);
}
NS_IMETHODIMP
@@ -1435,7 +1562,9 @@ nsRange::SelectNode(nsINode& aNode, ErrorResult& aRv)
}
int32_t index = parent->IndexOf(&aNode);
- if (index < 0) {
+ if (NS_WARN_IF(index < 0) ||
+ !IsValidOffset(static_cast<uint32_t>(index)) ||
+ !IsValidOffset(static_cast<uint32_t>(index) + 1)) {
aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
return;
}
@@ -1884,9 +2013,9 @@ nsRange::CutContents(DocumentFragment** aFragment)
// of Range gravity during our edits!
nsCOMPtr<nsINode> startContainer = mStartParent;
- int32_t startOffset = mStartOffset;
+ uint32_t startOffset = mStartOffset;
nsCOMPtr<nsINode> endContainer = mEndParent;
- int32_t endOffset = mEndOffset;
+ uint32_t endOffset = mEndOffset;
if (retval) {
// For extractContents(), abort early if there's a doctype (bug 719533).
@@ -1897,10 +2026,12 @@ nsRange::CutContents(DocumentFragment** aFragment)
RefPtr<DocumentType> doctype = commonAncestorDocument->GetDoctype();
if (doctype &&
- nsContentUtils::ComparePoints(startContainer, startOffset,
+ nsContentUtils::ComparePoints(startContainer,
+ static_cast<int32_t>(startOffset),
doctype, 0) < 0 &&
nsContentUtils::ComparePoints(doctype, 0,
- endContainer, endOffset) < 0) {
+ endContainer,
+ static_cast<int32_t>(endOffset)) < 0) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
}
@@ -1995,8 +2126,7 @@ nsRange::CutContents(DocumentFragment** aFragment)
rv = charData->GetLength(&dataLength);
NS_ENSURE_SUCCESS(rv, rv);
- if (dataLength >= (uint32_t)startOffset)
- {
+ if (dataLength >= startOffset) {
nsMutationGuard guard;
nsCOMPtr<nsIDOMCharacterData> cutNode;
rv = SplitDataNode(charData, startOffset, getter_AddRefs(cutNode));
@@ -2012,22 +2142,17 @@ nsRange::CutContents(DocumentFragment** aFragment)
else if (node == endContainer)
{
// Delete or extract everything before endOffset.
-
- if (endOffset >= 0)
- {
- nsMutationGuard guard;
- nsCOMPtr<nsIDOMCharacterData> cutNode;
- /* The Range spec clearly states clones get cut and original nodes
- remain behind, so use false as the last parameter.
- */
- rv = SplitDataNode(charData, endOffset, getter_AddRefs(cutNode),
- false);
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ENSURE_STATE(!guard.Mutated(1) ||
- ValidateCurrentNode(this, iter));
- nodeToResult = do_QueryInterface(cutNode);
- }
-
+ nsMutationGuard guard;
+ nsCOMPtr<nsIDOMCharacterData> cutNode;
+ /* The Range spec clearly states clones get cut and original nodes
+ remain behind, so use false as the last parameter.
+ */
+ rv = SplitDataNode(charData, endOffset, getter_AddRefs(cutNode),
+ false);
+ NS_ENSURE_SUCCESS(rv, rv);
+ NS_ENSURE_STATE(!guard.Mutated(1) ||
+ ValidateCurrentNode(this, iter));
+ nodeToResult = do_QueryInterface(cutNode);
handled = true;
}
}
@@ -2037,8 +2162,7 @@ nsRange::CutContents(DocumentFragment** aFragment)
if (node && node->IsElement() &&
((node == endContainer && endOffset == 0) ||
(node == startContainer &&
- int32_t(node->AsElement()->GetChildCount()) == startOffset)))
- {
+ node->AsElement()->GetChildCount() == startOffset))) {
if (retval) {
ErrorResult rv;
nodeToResult = node->CloneNode(false, rv);
@@ -2183,7 +2307,7 @@ nsRange::CompareBoundaryPoints(uint16_t aHow, nsRange& aOtherRange,
}
nsINode *ourNode, *otherNode;
- int32_t ourOffset, otherOffset;
+ uint32_t ourOffset, otherOffset;
switch (aHow) {
case nsIDOMRange::START_TO_START:
@@ -2221,8 +2345,10 @@ nsRange::CompareBoundaryPoints(uint16_t aHow, nsRange& aOtherRange,
return 0;
}
- return nsContentUtils::ComparePoints(ourNode, ourOffset,
- otherNode, otherOffset);
+ return nsContentUtils::ComparePoints(ourNode,
+ static_cast<int32_t>(ourOffset),
+ otherNode,
+ static_cast<int32_t>(otherOffset));
}
/* static */ nsresult
@@ -2339,8 +2465,7 @@ nsRange::CloneContents(ErrorResult& aRv)
bool deepClone = !node->IsElement() ||
(!(node == mEndParent && mEndOffset == 0) &&
!(node == mStartParent &&
- mStartOffset ==
- int32_t(node->AsElement()->GetChildCount())));
+ mStartOffset == node->AsElement()->GetChildCount()));
// Clone the current subtree!
@@ -2370,7 +2495,7 @@ nsRange::CloneContents(ErrorResult& aRv)
return nullptr;
}
- if (dataLength > (uint32_t)mEndOffset)
+ if (dataLength > mEndOffset)
{
aRv = charData->DeleteData(mEndOffset, dataLength - mEndOffset);
if (aRv.Failed()) {
@@ -2528,7 +2653,7 @@ nsRange::InsertNode(nsINode& aNode, ErrorResult& aRv)
return;
}
- int32_t tStartOffset = StartOffset();
+ uint32_t tStartOffset = StartOffset();
nsCOMPtr<nsINode> tStartContainer = GetStartContainer(aRv);
if (aRv.Failed()) {
@@ -2589,18 +2714,20 @@ nsRange::InsertNode(nsINode& aNode, ErrorResult& aRv)
// We might need to update the end to include the new node (bug 433662).
// Ideally we'd only do this if needed, but it's tricky to know when it's
// needed in advance (bug 765799).
- int32_t newOffset;
+ uint32_t newOffset;
if (referenceNode) {
- newOffset = IndexOf(referenceNode);
+ int32_t indexInParent = IndexOf(referenceNode);
+ if (NS_WARN_IF(indexInParent < 0)) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return;
+ }
+ newOffset = static_cast<uint32_t>(indexInParent);
} else {
- uint32_t length;
- aRv = tChildList->GetLength(&length);
+ aRv = tChildList->GetLength(&newOffset);
if (aRv.Failed()) {
return;
}
-
- newOffset = length;
}
if (aNode.NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
@@ -2956,10 +3083,15 @@ static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
nsRange::CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
mozilla::dom::DOMStringList* aTextList,
nsRange* aRange,
- nsINode* aStartParent, int32_t aStartOffset,
- nsINode* aEndParent, int32_t aEndOffset,
+ nsINode* aStartParent, uint32_t aStartOffset,
+ nsINode* aEndParent, uint32_t aEndOffset,
bool aClampToEdge, bool aFlushLayout)
{
+ // Currently, this method is called with start of end offset of nsRange.
+ // So, they must be between 0 - INT32_MAX.
+ MOZ_ASSERT(IsValidOffset(aStartOffset));
+ MOZ_ASSERT(IsValidOffset(aEndOffset));
+
// Hold strong pointers across the flush
nsCOMPtr<nsINode> startContainer = aStartParent;
nsCOMPtr<nsINode> endContainer = aEndParent;
@@ -2990,13 +3122,15 @@ nsRange::CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
if (textFrame) {
int32_t outOffset;
nsIFrame* outFrame;
- textFrame->GetChildFrameContainingOffset(aStartOffset, false,
- &outOffset, &outFrame);
+ textFrame->GetChildFrameContainingOffset(
+ static_cast<int32_t>(aStartOffset), false,
+ &outOffset, &outFrame);
if (outFrame) {
nsIFrame* relativeTo =
nsLayoutUtils::GetContainingBlockForClientRect(outFrame);
nsRect r = outFrame->GetRectRelativeToSelf();
- ExtractRectFromOffset(outFrame, aStartOffset, &r, false, aClampToEdge);
+ ExtractRectFromOffset(outFrame, static_cast<int32_t>(aStartOffset),
+ &r, false, aClampToEdge);
r.width = 0;
r = nsLayoutUtils::TransformFrameRectToAncestor(outFrame, r, relativeTo);
aCollector->AddRect(r);
@@ -3015,12 +3149,14 @@ nsRange::CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
if (content->IsNodeOfType(nsINode::eTEXT)) {
if (node == startContainer) {
int32_t offset = startContainer == endContainer ?
- aEndOffset : content->GetText()->GetLength();
- GetPartialTextRect(aCollector, aTextList, content, aStartOffset, offset,
+ static_cast<int32_t>(aEndOffset) : content->GetText()->GetLength();
+ GetPartialTextRect(aCollector, aTextList, content,
+ static_cast<int32_t>(aStartOffset), offset,
aClampToEdge, aFlushLayout);
continue;
} else if (node == endContainer) {
- GetPartialTextRect(aCollector, aTextList, content, 0, aEndOffset,
+ GetPartialTextRect(aCollector, aTextList, content,
+ 0, static_cast<int32_t>(aEndOffset),
aClampToEdge, aFlushLayout);
continue;
}
@@ -3397,7 +3533,7 @@ ElementIsVisibleNoFlush(Element* aElement)
static void
AppendTransformedText(InnerTextAccumulator& aResult,
nsGenericDOMDataNode* aTextNode,
- int32_t aStart, int32_t aEnd)
+ uint32_t aStart, uint32_t aEnd)
{
nsIFrame* frame = aTextNode->GetPrimaryFrame();
if (!IsVisibleAndNotInReplacedElement(frame)) {
@@ -3506,7 +3642,7 @@ nsRange::GetInnerTextNoFlush(DOMString& aValue, ErrorResult& aError,
if (aEndParent->IsNodeOfType(nsINode::eTEXT)) {
endState = AT_NODE;
} else {
- if (uint32_t(aEndOffset) < aEndParent->GetChildCount()) {
+ if (aEndOffset < aEndParent->GetChildCount()) {
endNode = aEndParent->GetChildAt(aEndOffset);
endState = AT_NODE;
}
diff --git a/dom/base/nsRange.h b/dom/base/nsRange.h
index 4b35c749a..2c0c19edc 100644
--- a/dom/base/nsRange.h
+++ b/dom/base/nsRange.h
@@ -26,6 +26,7 @@ namespace mozilla {
class ErrorResult;
namespace dom {
struct ClientRectsAndTexts;
+class DocGroup;
class DocumentFragment;
class DOMRect;
class DOMRectList;
@@ -38,6 +39,7 @@ class nsRange final : public nsIDOMRange,
public nsWrapperCache
{
typedef mozilla::ErrorResult ErrorResult;
+ typedef mozilla::dom::DocGroup DocGroup;
typedef mozilla::dom::DOMRect DOMRect;
typedef mozilla::dom::DOMRectList DOMRectList;
@@ -46,14 +48,14 @@ class nsRange final : public nsIDOMRange,
public:
explicit nsRange(nsINode* aNode);
- static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
- nsIDOMNode* aEndParent, int32_t aEndOffset,
+ static nsresult CreateRange(nsIDOMNode* aStartParent, uint32_t aStartOffset,
+ nsIDOMNode* aEndParent, uint32_t aEndOffset,
nsRange** aRange);
- static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
- nsIDOMNode* aEndParent, int32_t aEndOffset,
+ static nsresult CreateRange(nsIDOMNode* aStartParent, uint32_t aStartOffset,
+ nsIDOMNode* aEndParent, uint32_t aEndOffset,
nsIDOMRange** aRange);
- static nsresult CreateRange(nsINode* aStartParent, int32_t aStartOffset,
- nsINode* aEndParent, int32_t aEndOffset,
+ static nsresult CreateRange(nsINode* aStartParent, uint32_t aStartOffset,
+ nsINode* aEndParent, uint32_t aEndOffset,
nsRange** aRange);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -91,12 +93,12 @@ public:
return mEndParent;
}
- int32_t StartOffset() const
+ uint32_t StartOffset() const
{
return mStartOffset;
}
- int32_t EndOffset() const
+ uint32_t EndOffset() const
{
return mEndOffset;
}
@@ -148,19 +150,74 @@ public:
nsINode* GetCommonAncestor() const;
void Reset();
- nsresult SetStart(nsINode* aParent, int32_t aOffset);
- nsresult SetEnd(nsINode* aParent, int32_t aOffset);
+
+ /**
+ * SetStart() and SetEnd() sets start point or end point separately.
+ * However, this is expensive especially when it's a range of Selection.
+ * When you set both start and end of a range, you should use
+ * SetStartAndEnd() instead.
+ */
+ nsresult SetStart(nsINode* aParent, uint32_t aOffset);
+ nsresult SetEnd(nsINode* aParent, uint32_t aOffset);
+
already_AddRefed<nsRange> CloneRange() const;
- nsresult Set(nsINode* aStartParent, int32_t aStartOffset,
- nsINode* aEndParent, int32_t aEndOffset)
+ /**
+ * SetStartAndEnd() works similar to call both SetStart() and SetEnd().
+ * Different from calls them separately, this does nothing if either
+ * the start point or the end point is invalid point.
+ * If the specified start point is after the end point, the range will be
+ * collapsed at the end point. Similarly, if they are in different root,
+ * the range will be collapsed at the end point.
+ */
+ nsresult SetStartAndEnd(nsINode* aStartParent, uint32_t aStartOffset,
+ nsINode* aEndParent, uint32_t aEndOffset);
+
+ /**
+ * CollapseTo() works similar to call both SetStart() and SetEnd() with
+ * same node and offset. This just calls SetStartAndParent() to set
+ * collapsed range at aParent and aOffset.
+ */
+ nsresult CollapseTo(nsINode* aParent, uint32_t aOffset)
{
- // If this starts being hot, we may be able to optimize this a bit,
- // but for now just set start and end separately.
- nsresult rv = SetStart(aStartParent, aStartOffset);
- NS_ENSURE_SUCCESS(rv, rv);
+ return SetStartAndEnd(aParent, aOffset, aParent, aOffset);
+ }
- return SetEnd(aEndParent, aEndOffset);
+ /**
+ * Retrieves node and offset for setting start or end of a range to
+ * before or after aNode.
+ */
+ static nsINode* GetParentAndOffsetAfter(nsINode* aNode, uint32_t* aOffset)
+ {
+ MOZ_ASSERT(aNode);
+ MOZ_ASSERT(aOffset);
+ *aOffset = 0;
+ nsINode* parentNode = aNode->GetParentNode();
+ if (!parentNode) {
+ return nullptr;
+ }
+ int32_t indexInParent = parentNode->IndexOf(aNode);
+ if (NS_WARN_IF(indexInParent < 0)) {
+ return nullptr;
+ }
+ *aOffset = static_cast<uint32_t>(indexInParent) + 1;
+ return parentNode;
+ }
+ static nsINode* GetParentAndOffsetBefore(nsINode* aNode, uint32_t* aOffset)
+ {
+ MOZ_ASSERT(aNode);
+ MOZ_ASSERT(aOffset);
+ *aOffset = 0;
+ nsINode* parentNode = aNode->GetParentNode();
+ if (!parentNode) {
+ return nullptr;
+ }
+ int32_t indexInParent = parentNode->IndexOf(aNode);
+ if (NS_WARN_IF(indexInParent < 0)) {
+ return nullptr;
+ }
+ *aOffset = static_cast<uint32_t>(indexInParent);
+ return parentNode;
}
NS_IMETHOD GetUsedFontFaces(nsIDOMFontFaceList** aResult);
@@ -225,6 +282,7 @@ public:
nsINode* GetParentObject() const { return mOwner; }
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override final;
+ DocGroup* GetDocGroup() const;
private:
// no copy's or assigns
@@ -274,8 +332,8 @@ public:
static void CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
mozilla::dom::DOMStringList* aTextList,
nsRange* aRange,
- nsINode* aStartParent, int32_t aStartOffset,
- nsINode* aEndParent, int32_t aEndOffset,
+ nsINode* aStartParent, uint32_t aStartOffset,
+ nsINode* aEndParent, uint32_t aEndOffset,
bool aClampToEdge, bool aFlushLayout);
/**
@@ -297,12 +355,24 @@ protected:
void UnregisterCommonAncestor(nsINode* aNode);
nsINode* IsValidBoundary(nsINode* aNode);
+ /**
+ * XXX nsRange should accept 0 - UINT32_MAX as offset. However, users of
+ * nsRange treat offset as int32_t. Additionally, some other internal
+ * APIs like nsINode::IndexOf() use int32_t. Therefore, nsRange should
+ * accept only 0 - INT32_MAX as valid offset for now.
+ */
+ static bool IsValidOffset(uint32_t aOffset)
+ {
+ return aOffset <= INT32_MAX;
+ }
+ static bool IsValidOffset(nsINode* aNode, uint32_t aOffset);
+
// CharacterDataChanged set aNotInsertedYet to true to disable an assertion
// and suppress re-registering a range common ancestor node since
// the new text node of a splitText hasn't been inserted yet.
// CharacterDataChanged does the re-registering when needed.
- void DoSetRange(nsINode* aStartN, int32_t aStartOffset,
- nsINode* aEndN, int32_t aEndOffset,
+ void DoSetRange(nsINode* aStartN, uint32_t aStartOffset,
+ nsINode* aEndN, uint32_t aEndOffset,
nsINode* aRoot, bool aNotInsertedYet = false);
/**
@@ -350,8 +420,8 @@ protected:
nsCOMPtr<nsINode> mStartParent;
nsCOMPtr<nsINode> mEndParent;
RefPtr<mozilla::dom::Selection> mSelection;
- int32_t mStartOffset;
- int32_t mEndOffset;
+ uint32_t mStartOffset;
+ uint32_t mEndOffset;
bool mIsPositioned : 1;
bool mMaySpanAnonymousSubtrees : 1;
diff --git a/dom/base/nsStyledElement.cpp b/dom/base/nsStyledElement.cpp
index 03d1187ab..8cd448d47 100644
--- a/dom/base/nsStyledElement.cpp
+++ b/dom/base/nsStyledElement.cpp
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsStyledElement.h"
+#include "mozAutoDocUpdate.h"
#include "nsGkAtoms.h"
#include "nsAttrValue.h"
#include "nsAttrValueInlines.h"
@@ -39,7 +40,6 @@ nsStyledElement::ParseAttribute(int32_t aNamespaceID,
nsAttrValue& aResult)
{
if (aAttribute == nsGkAtoms::style && aNamespaceID == kNameSpaceID_None) {
- SetMayHaveStyle();
ParseStyleAttribute(aValue, aResult, false);
return true;
}
@@ -49,6 +49,22 @@ nsStyledElement::ParseAttribute(int32_t aNamespaceID,
}
nsresult
+nsStyledElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue, bool aNotify)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::style) {
+ if (aValue) {
+ SetMayHaveStyle();
+ }
+ }
+ }
+
+ return nsStyledElementBase::BeforeSetAttr(aNamespaceID, aName, aValue,
+ aNotify);
+}
+
+nsresult
nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
const nsAString* aSerialized,
bool aNotify)
@@ -56,6 +72,7 @@ nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
SetMayHaveStyle();
bool modification = false;
nsAttrValue oldValue;
+ bool oldValueSet = false;
bool hasListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
@@ -75,6 +92,7 @@ nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
oldValueStr);
if (modification) {
oldValue.SetTo(oldValueStr);
+ oldValueSet = true;
}
}
else if (aNotify && IsInUncomposedDoc()) {
@@ -88,9 +106,12 @@ nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION) :
static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION);
+ nsIDocument* document = GetComposedDoc();
+ mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nullptr,
- oldValue, attrValue, modType, hasListeners,
- aNotify, kDontCallAfterSetAttr);
+ oldValueSet ? &oldValue : nullptr, attrValue, modType,
+ hasListeners, aNotify, kDontCallAfterSetAttr,
+ document, updateBatch);
}
DeclarationBlock*
@@ -141,7 +162,9 @@ nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc)
ParseStyleAttribute(stringValue, attrValue, aForceInDataDoc);
// Don't bother going through SetInlineStyleDeclaration; we don't
// want to fire off mutation events or document notifications anyway
- nsresult rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue);
+ bool oldValueSet;
+ nsresult rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue,
+ &oldValueSet);
NS_ENSURE_SUCCESS(rv, rv);
}
diff --git a/dom/base/nsStyledElement.h b/dom/base/nsStyledElement.h
index c4894d87f..cb6dfd54b 100644
--- a/dom/base/nsStyledElement.h
+++ b/dom/base/nsStyledElement.h
@@ -80,6 +80,10 @@ protected:
* document.
*/
nsresult ReparseStyleAttribute(bool aForceInDataDoc);
+
+ virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify) override;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsStyledElement, NS_STYLED_ELEMENT_IID)
diff --git a/dom/base/nsTextNode.cpp b/dom/base/nsTextNode.cpp
index 25c2d3525..b488c85b7 100644
--- a/dom/base/nsTextNode.cpp
+++ b/dom/base/nsTextNode.cpp
@@ -21,6 +21,7 @@
#ifdef DEBUG
#include "nsRange.h"
#endif
+#include "nsDocument.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -155,6 +156,12 @@ void nsTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
nsGenericDOMDataNode::UnbindFromTree(aDeep, aNullParent);
}
+bool
+nsTextNode::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
+{
+ return nsDocument::IsWebComponentsEnabled(aCx, aObject);
+}
+
#ifdef DEBUG
void
nsTextNode::List(FILE* out, int32_t aIndent) const
diff --git a/dom/base/nsTextNode.h b/dom/base/nsTextNode.h
index 488540a82..94b8dbd1d 100644
--- a/dom/base/nsTextNode.h
+++ b/dom/base/nsTextNode.h
@@ -75,6 +75,10 @@ public:
virtual nsIDOMNode* AsDOMNode() override { return this; }
+ // Need to have a copy here because including nsDocument.h in this file will
+ // fail to build on Windows.
+ static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
+
#ifdef DEBUG
virtual void List(FILE* out, int32_t aIndent) const override;
virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const override;
diff --git a/dom/base/nsWindowRoot.cpp b/dom/base/nsWindowRoot.cpp
index b839a0ee5..710ecd88f 100644
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -180,13 +180,13 @@ nsWindowRoot::GetContextForEventHandlers(nsresult* aRv)
}
nsresult
-nsWindowRoot::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsWindowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
// To keep mWindow alive
aVisitor.mItemData = static_cast<nsISupports *>(mWindow);
- aVisitor.mParentTarget = mParent;
+ aVisitor.SetParentTarget(mParent, false);
return NS_OK;
}
diff --git a/dom/base/nsXHTMLContentSerializer.cpp b/dom/base/nsXHTMLContentSerializer.cpp
index 0a39ef663..42874f02b 100755
--- a/dom/base/nsXHTMLContentSerializer.cpp
+++ b/dom/base/nsXHTMLContentSerializer.cpp
@@ -15,6 +15,7 @@
#include "nsIDOMElement.h"
#include "nsIContent.h"
#include "nsIDocument.h"
+#include "nsElementTable.h"
#include "nsNameSpaceManager.h"
#include "nsString.h"
#include "nsUnicharUtils.h"
@@ -27,7 +28,6 @@
#include "nsEscape.h"
#include "nsITextToSubURI.h"
#include "nsCRT.h"
-#include "nsIParserService.h"
#include "nsContentUtils.h"
#include "nsLWBrkCIID.h"
#include "nsIScriptElement.h"
@@ -667,18 +667,7 @@ nsXHTMLContentSerializer::LineBreakBeforeOpen(int32_t aNamespaceID, nsIAtom* aNa
aName == nsGkAtoms::html) {
return true;
}
- else {
- nsIParserService* parserService = nsContentUtils::GetParserService();
-
- if (parserService) {
- bool res;
- parserService->
- IsBlock(parserService->HTMLCaseSensitiveAtomTagToId(aName), res);
- return res;
- }
- }
-
- return mAddSpace;
+ return nsHTMLElement::IsBlock(nsHTMLTags::CaseSensitiveAtomTagToId(aName));
}
bool
@@ -748,31 +737,15 @@ nsXHTMLContentSerializer::LineBreakAfterClose(int32_t aNamespaceID, nsIAtom* aNa
(aName == nsGkAtoms::tr) ||
(aName == nsGkAtoms::th) ||
(aName == nsGkAtoms::td) ||
- (aName == nsGkAtoms::pre) ||
(aName == nsGkAtoms::title) ||
- (aName == nsGkAtoms::li) ||
(aName == nsGkAtoms::dt) ||
(aName == nsGkAtoms::dd) ||
- (aName == nsGkAtoms::blockquote) ||
(aName == nsGkAtoms::select) ||
(aName == nsGkAtoms::option) ||
- (aName == nsGkAtoms::p) ||
- (aName == nsGkAtoms::map) ||
- (aName == nsGkAtoms::div)) {
+ (aName == nsGkAtoms::map)) {
return true;
}
- else {
- nsIParserService* parserService = nsContentUtils::GetParserService();
-
- if (parserService) {
- bool res;
- parserService->
- IsBlock(parserService->HTMLCaseSensitiveAtomTagToId(aName), res);
- return res;
- }
- }
-
- return false;
+ return nsHTMLElement::IsBlock(nsHTMLTags::CaseSensitiveAtomTagToId(aName));
}
diff --git a/dom/base/nsXMLContentSerializer.cpp b/dom/base/nsXMLContentSerializer.cpp
index f12bb8fdc..71a675e11 100644
--- a/dom/base/nsXMLContentSerializer.cpp
+++ b/dom/base/nsXMLContentSerializer.cpp
@@ -19,7 +19,7 @@
#include "nsIContent.h"
#include "nsIDocument.h"
#include "nsIDocumentEncoder.h"
-#include "nsIParserService.h"
+#include "nsElementTable.h"
#include "nsNameSpaceManager.h"
#include "nsTextFragment.h"
#include "nsString.h"
@@ -994,14 +994,9 @@ ElementNeedsSeparateEndTag(Element* aElement, Element* aOriginalElement)
// HTML container tags should have a separate end tag even if empty, per spec.
// See
// https://w3c.github.io/DOM-Parsing/#dfn-concept-xml-serialization-algorithm
- bool isHTMLContainer = true; // Default in case we get no parser service.
- nsIParserService* parserService = nsContentUtils::GetParserService();
- if (parserService) {
- nsIAtom* localName = aElement->NodeInfo()->NameAtom();
- parserService->IsContainer(
- parserService->HTMLCaseSensitiveAtomTagToId(localName),
- isHTMLContainer);
- }
+ nsIAtom* localName = aElement->NodeInfo()->NameAtom();
+ bool isHTMLContainer =
+ nsHTMLElement::IsContainer(nsHTMLTags::CaseSensitiveAtomTagToId(localName));
return isHTMLContainer;
}
diff --git a/dom/base/test/chrome/chrome.ini b/dom/base/test/chrome/chrome.ini
index 765bbd2df..c6ee42391 100644
--- a/dom/base/test/chrome/chrome.ini
+++ b/dom/base/test/chrome/chrome.ini
@@ -18,8 +18,8 @@ support-files =
file_bug1209621.xul
fileconstructor_file.png
frame_bug814638.xul
- frame_registerElement_content.html
- registerElement_ep.js
+ frame_custom_element_content.html
+ custom_element_ep.js
host_bug814638.xul
window_nsITextInputProcessor.xul
title_window.xul
@@ -62,8 +62,8 @@ support-files = ../file_bug357450.js
[test_bug1139964.xul]
[test_bug1209621.xul]
[test_cpows.xul]
-[test_registerElement_content.xul]
-[test_registerElement_ep.xul]
+[test_custom_element_content.xul]
+[test_custom_element_ep.xul]
[test_domparsing.xul]
[test_fileconstructor.xul]
[test_fileconstructor_tempfile.xul]
diff --git a/dom/base/test/chrome/registerElement_ep.js b/dom/base/test/chrome/registerElement_ep.js
deleted file mode 100644
index 9189593c0..000000000
--- a/dom/base/test/chrome/registerElement_ep.js
+++ /dev/null
@@ -1,8 +0,0 @@
-var proto = Object.create(HTMLElement.prototype);
-proto.magicNumber = 42;
-proto.connectedCallback = function() {
- finishTest(this.magicNumber === 42);
-};
-document.registerElement("x-foo", { prototype: proto });
-
-document.firstChild.appendChild(document.createElement("x-foo"));
diff --git a/dom/base/test/chrome/test_registerElement_content.xul b/dom/base/test/chrome/test_registerElement_content.xul
deleted file mode 100644
index bf00ed53d..000000000
--- a/dom/base/test/chrome/test_registerElement_content.xul
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
- type="text/css"?>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
--->
-<window title="Mozilla Bug 1130028"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
- <script type="application/javascript"
- src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-
- <!-- test results are displayed in the html:body -->
- <body xmlns="http://www.w3.org/1999/xhtml">
- <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1130028"
- target="_blank">Mozilla Bug 1130028</a>
- <iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_registerElement_content.html"></iframe>
- </body>
-
- <!-- test code goes here -->
- <script type="application/javascript"><![CDATA[
-
- /** Test for Bug 1130028 **/
- var connectedCallbackCount = 0;
-
- // Callback should be called only once by element created in content.
- function connectedCallbackCalled() {
- connectedCallbackCount++;
- is(connectedCallbackCount, 1, "Connected callback called, should be called once in test.");
- is(this.magicNumber, 42, "Callback should be able to see the custom prototype.");
- }
-
- function startTests() {
- var frame = $("frame");
-
- var c = frame.contentDocument.registerElement("x-foo");
- var elem = new c();
- is(elem.tagName, "X-FOO", "Constructor should create an x-foo element.");
-
- var proto = Object.create(frame.contentWindow.HTMLElement.prototype);
- proto.magicNumber = 42;
- proto.connectedCallback = connectedCallbackCalled;
-
- frame.contentDocument.registerElement("x-bar", { prototype: proto });
- is(connectedCallbackCount, 1, "Connected callback should be called by element created in content.");
-
- var element = frame.contentDocument.createElement("x-bar");
- is(element.magicNumber, 42, "Should be able to see the custom prototype on created element.");
- }
-
- ]]></script>
-</window>
diff --git a/dom/base/test/chrome/test_registerElement_ep.xul b/dom/base/test/chrome/test_registerElement_ep.xul
deleted file mode 100644
index b6a160c2e..000000000
--- a/dom/base/test/chrome/test_registerElement_ep.xul
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
- type="text/css"?>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
--->
-<window title="Mozilla Bug 1130028"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
- <script type="application/javascript"
- src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-
- <!-- test results are displayed in the html:body -->
- <body xmlns="http://www.w3.org/1999/xhtml">
- <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1130028"
- target="_blank">Mozilla Bug 1130028</a>
- <iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_registerElement_content.html"></iframe>
- </body>
-
- <!-- test code goes here -->
- <script type="application/javascript"><![CDATA[
-
- Components.utils.import("resource://gre/modules/Services.jsm");
-
- /** Test for Bug 1130028 **/
- SimpleTest.waitForExplicitFinish();
-
- function finishTest(canSeePrototype) {
- ok(true, "connectedCallback called when reigsterElement was called with an extended principal.");
- ok(canSeePrototype, "connectedCallback should be able to see custom prototype.");
- SimpleTest.finish();
- }
-
- function startTests() {
- var frame = $("frame");
-
- // Create a sandbox with an extended principal then run a script that registers a custom element in the sandbox.
- var sandbox = Components.utils.Sandbox([frame.contentWindow], { sandboxPrototype: frame.contentWindow });
- sandbox.finishTest = finishTest;
- Services.scriptloader.loadSubScript("chrome://mochitests/content/chrome/dom/base/test/chrome/registerElement_ep.js", sandbox);
- }
-
- ]]></script>
-</window>
diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini
index 3dfd666f8..928727f81 100644
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -630,7 +630,7 @@ skip-if = toolkit == 'android' #bug 904183
[test_document.all_unqualified.html]
[test_document_constructor.html]
[test_document_importNode_document.html]
-[test_document_register.html]
+[test_custom_element.html]
[test_domcursor.html]
[test_domparser_null_char.html]
[test_domparsing.html]
diff --git a/dom/base/test/test_document_register.html b/dom/base/test/test_document_register.html
index 6cf15a52f..7de235108 100644
--- a/dom/base/test/test_document_register.html
+++ b/dom/base/test/test_document_register.html
@@ -13,8 +13,10 @@
SimpleTest.waitForExplicitFinish();
function startTests() {
- var c = document.getElementById("fooframe").contentDocument.registerElement("x-foo");
- var elem = new c();
+ var frame = document.getElementById("fooframe");
+ class XFoo extends frame.contentWindow.HTMLElement {};
+ frame.contentWindow.customElements.define("x-foo", XFoo);
+ var elem = new XFoo();
is(elem.tagName, "X-FOO", "Constructor should create an x-foo element.");
var anotherElem = $("fooframe").contentDocument.createElement("x-foo");
diff --git a/dom/base/test/test_mutationobservers.html b/dom/base/test/test_mutationobservers.html
index 7e4c99423..021bedf1c 100644
--- a/dom/base/test/test_mutationobservers.html
+++ b/dom/base/test/test_mutationobservers.html
@@ -612,7 +612,7 @@ function testOutsideShadowDOM() {
is(records.length, 1);
is(records[0].type, "attributes", "Should have got attributes");
observer.disconnect();
- then(testInsideShadowDOM);
+ then(testMarquee);
});
m.observe(div, {
attributes: true,
@@ -628,32 +628,6 @@ function testOutsideShadowDOM() {
div.setAttribute("foo", "bar");
}
-function testInsideShadowDOM() {
- var m = new M(function(records, observer) {
- is(records.length, 4);
- is(records[0].type, "childList");
- is(records[1].type, "attributes");
- is(records[2].type, "characterData");
- is(records[3].type, "childList");
- observer.disconnect();
- then(testMarquee);
- });
- var sr = div.createShadowRoot();
- m.observe(sr, {
- attributes: true,
- childList: true,
- characterData: true,
- subtree: true
- });
-
- sr.innerHTML = "<div" + ">text</" + "div>";
- sr.firstChild.setAttribute("foo", "bar");
- sr.firstChild.firstChild.data = "text2";
- sr.firstChild.appendChild(document.createElement("div"));
- div.setAttribute("foo", "bar2");
-
-}
-
function testMarquee() {
var m = new M(function(records, observer) {
is(records.length, 1);
diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
index f76f14d95..ee321772e 100644
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -23,9 +23,9 @@
#include "nsContentCreatorFunctions.h"
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
+#include "nsHTMLTags.h"
#include "nsIDocShell.h"
#include "nsIDOMGlobalPropertyInitializer.h"
-#include "nsIParserService.h"
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
#include "nsIXPConnect.h"
@@ -3406,28 +3406,6 @@ GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
return true;
}
-CustomElementReactionsStack*
-GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj)
-{
- // This might not be the right object, if there are wrappers. Unwrap if we can.
- JSObject* obj = js::CheckedUnwrap(aObj);
- if (!obj) {
- return nullptr;
- }
-
- nsGlobalWindow* window = xpc::WindowGlobalOrNull(obj);
- if (!window) {
- return nullptr;
- }
-
- DocGroup* docGroup = window->AsInner()->GetDocGroup();
- if (!docGroup) {
- return nullptr;
- }
-
- return docGroup->CustomElementReactionsStack();
-}
-
// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
already_AddRefed<nsGenericHTMLElement>
CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
@@ -3493,13 +3471,7 @@ CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
// Step 5.
// If the definition is for a customized built-in element, the localName
// should be defined in the specification.
- nsIParserService* parserService = nsContentUtils::GetParserService();
- if (!parserService) {
- aRv.Throw(NS_ERROR_UNEXPECTED);
- return nullptr;
- }
-
- tag = parserService->HTMLCaseSensitiveAtomTagToId(definition->mLocalName);
+ tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
if (tag == eHTMLTag_userdefined) {
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
return nullptr;
diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h
index e583d0e06..356d3aa00 100644
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3422,12 +3422,6 @@ bool
GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
JS::MutableHandle<JSObject*> aDesiredProto);
-// Get the CustomElementReactionsStack for the docgroup of the global
-// of the underlying object of aObj. This can be null if aObj can't
-// be CheckUnwrapped, or if the global of the result has no docgroup
-// (e.g. because it's not a Window global).
-CustomElementReactionsStack*
-GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj);
// This function is expected to be called from the constructor function for an
// HTML element interface; the global/callargs need to be whatever was passed to
// that constructor function.
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index 8985863e8..c9a5e9f41 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -7680,14 +7680,14 @@ class CGPerSignatureCall(CGThing):
if (idlNode.getExtendedAttribute('CEReactions') is not None and
not getter):
- cgThings.append(CGGeneric(fill(
+ cgThings.append(CGGeneric(dedent(
"""
- CustomElementReactionsStack* reactionsStack = GetCustomElementReactionsStack(${obj});
- Maybe<AutoCEReaction> ceReaction;
- if (reactionsStack) {
- ceReaction.emplace(reactionsStack, cx);
+ Maybe<AutoCEReaction> ceReaction;
+ DocGroup* docGroup = self->GetDocGroup();
+ if (docGroup) {
+ ceReaction.emplace(docGroup->CustomElementReactionsStack(), cx);
}
- """, obj=objectName)))
+ """)))
# If this is a method that was generated by a maplike/setlike
# interface, use the maplike/setlike generator to fill in the body.
@@ -13786,6 +13786,8 @@ class CGForwardDeclarations(CGWrapper):
builder.add(d.nativeType + "Atoms", isStruct=True)
for t in getTypesFromDescriptor(d):
builder.forwardDeclareForType(t, config)
+ if d.hasCEReactions():
+ builder.addInMozillaDom("DocGroup")
for d in dictionaries:
if len(d.members) > 0:
@@ -13857,18 +13859,15 @@ class CGBindingRoot(CGThing):
iface = desc.interface
return any(m.getExtendedAttribute("Deprecated") for m in iface.members + [iface])
- def descriptorHasCEReactions(desc):
- iface = desc.interface
- return any(m.getExtendedAttribute("CEReactions") for m in iface.members + [iface])
-
bindingHeaders["nsIDocument.h"] = any(
descriptorDeprecated(d) for d in descriptors)
bindingHeaders["mozilla/Preferences.h"] = any(
descriptorRequiresPreferences(d) for d in descriptors)
bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any(
d.concrete and d.proxy for d in descriptors)
- bindingHeaders["mozilla/dom/CustomElementRegistry.h"] = any(
- descriptorHasCEReactions(d) for d in descriptors)
+ hasCEReactions = any(d.hasCEReactions() for d in descriptors)
+ bindingHeaders["mozilla/dom/CustomElementRegistry.h"] = hasCEReactions
+ bindingHeaders["mozilla/dom/DocGroup.h"] = hasCEReactions
def descriptorHasChromeOnly(desc):
ctor = desc.interface.ctor()
@@ -14704,6 +14703,12 @@ class CGBindingImplClass(CGClass):
breakAfterReturnDecl=" ",
override=descriptor.wrapperCache,
body=self.getWrapObjectBody()))
+ if descriptor.hasCEReactions():
+ self.methodDecls.insert(0,
+ ClassMethod("GetDocGroup", "DocGroup*", [],
+ const=True,
+ breakAfterReturnDecl=" ",
+ body=self.getGetDocGroupBody()))
if wantGetParent:
self.methodDecls.insert(0,
ClassMethod("GetParentObject",
@@ -14724,6 +14729,9 @@ class CGBindingImplClass(CGClass):
def getGetParentObjectBody(self):
return None
+ def getGetDocGroupBody(self):
+ return None
+
def deps(self):
return self._deps
@@ -14863,6 +14871,8 @@ class CGExampleRoot(CGThing):
self.root = CGNamespace.build(["mozilla", "dom"], self.root)
builder = ForwardDeclarationBuilder()
+ if descriptor.hasCEReactions():
+ builder.addInMozillaDom("DocGroup")
for member in descriptor.interface.members:
if not member.isAttr() and not member.isMethod():
continue
@@ -15174,7 +15184,7 @@ class CGJSImplClass(CGBindingImplClass):
private:
RefPtr<${jsImplName}> mImpl;
- nsCOMPtr<nsISupports> mParent;
+ nsCOMPtr<nsIGlobalObject> mParent;
""",
isupportsDecl=isupportsDecl,
@@ -15253,6 +15263,16 @@ class CGJSImplClass(CGBindingImplClass):
def getGetParentObjectBody(self):
return "return mParent;\n"
+ def getGetDocGroupBody(self):
+ return dedent(
+ """
+ nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
+ if (!window) {
+ return nullptr;
+ }
+ return window->GetDocGroup();
+ """)
+
def getCreateFromExistingBody(self):
# XXXbz we could try to get parts of this (e.g. the argument
# conversions) auto-generated by somehow creating an IDLMethod and
diff --git a/dom/bindings/Configuration.py b/dom/bindings/Configuration.py
index a56f2f2fd..2669e3e4c 100644
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -631,6 +631,9 @@ class Descriptor(DescriptorProvider):
not self.interface.isExposedInWindow()) or
self.interface.isExposedInSomeButNotAllWorkers())
+ def hasCEReactions(self):
+ return any(m.getExtendedAttribute("CEReactions") for m in self.interface.members)
+
def isExposedConditionally(self):
return (self.interface.isExposedConditionally() or
self.interface.isExposedInSomeButNotAllWorkers())
diff --git a/dom/bindings/test/TestBindingHeader.h b/dom/bindings/test/TestBindingHeader.h
index 7d9963700..4e2e10e43 100644
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -21,6 +21,7 @@
// this one for it, for ParentDict. Hopefully it won't begin to rely on it in more fundamental ways.
namespace mozilla {
namespace dom {
+class DocGroup;
class TestExternalInterface;
class Promise;
} // namespace dom
@@ -46,8 +47,9 @@ public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_RENAMED_INTERFACE_IID)
NS_DECL_ISUPPORTS
- // We need a GetParentObject to make binding codegen happy
+ // We need a GetParentObject and GetDocGroup to make binding codegen happy
virtual nsISupports* GetParentObject();
+ DocGroup* GetDocGroup() const;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsRenamedInterface, NS_RENAMED_INTERFACE_IID)
@@ -64,8 +66,9 @@ public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INDIRECTLY_IMPLEMENTED_INTERFACE_IID)
NS_DECL_ISUPPORTS
- // We need a GetParentObject to make binding codegen happy
+ // We need a GetParentObject and GetDocGroup to make binding codegen happy
virtual nsISupports* GetParentObject();
+ DocGroup* GetDocGroup() const;
bool IndirectlyImplementedProperty();
void IndirectlyImplementedProperty(bool);
diff --git a/dom/events/ContentEventHandler.cpp b/dom/events/ContentEventHandler.cpp
index 935ade23f..df54a4d44 100644
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -980,11 +980,7 @@ ContentEventHandler::SetRangeFromFlatTextOffset(nsRange* aRange,
// Special case like <br contenteditable>
if (!mRootContent->HasChildren()) {
- nsresult rv = aRange->SetStart(mRootContent, 0);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- rv = aRange->SetEnd(mRootContent, 0);
+ nsresult rv = aRange->CollapseTo(mRootContent, 0);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -2880,8 +2876,7 @@ ContentEventHandler::AdjustCollapsedRangeMaybeIntoTextNode(nsRange* aRange)
return NS_OK;
}
- nsresult rv = aRange->Set(childNode, offsetInChildNode,
- childNode, offsetInChildNode);
+ nsresult rv = aRange->CollapseTo(childNode, offsetInChildNode);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
diff --git a/dom/events/DOMEventTargetHelper.cpp b/dom/events/DOMEventTargetHelper.cpp
index dd9a01d8d..90ee61059 100644
--- a/dom/events/DOMEventTargetHelper.cpp
+++ b/dom/events/DOMEventTargetHelper.cpp
@@ -328,10 +328,10 @@ DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
}
nsresult
-DOMEventTargetHelper::PreHandleEvent(EventChainPreVisitor& aVisitor)
+DOMEventTargetHelper::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
- aVisitor.mParentTarget = nullptr;
+ aVisitor.SetParentTarget(nullptr, false);
return NS_OK;
}
diff --git a/dom/events/DOMEventTargetHelper.h b/dom/events/DOMEventTargetHelper.h
index c5a0611c9..b14f05428 100644
--- a/dom/events/DOMEventTargetHelper.h
+++ b/dom/events/DOMEventTargetHelper.h
@@ -248,10 +248,10 @@ NS_DEFINE_STATIC_IID_ACCESSOR(DOMEventTargetHelper,
/* Use this macro to declare functions that forward the behavior of this
* interface to another object.
- * This macro doesn't forward PreHandleEvent because sometimes subclasses
+ * This macro doesn't forward GetEventTargetParent because sometimes subclasses
* want to override it.
*/
-#define NS_FORWARD_NSIDOMEVENTTARGET_NOPREHANDLEEVENT(_to) \
+#define NS_FORWARD_NSIDOMEVENTTARGET_NOGETEVENTTARGETPARENT(_to) \
NS_IMETHOD AddEventListener(const nsAString & type, nsIDOMEventListener *listener, bool useCapture, bool wantsUntrusted, uint8_t _argc) { \
return _to AddEventListener(type, listener, useCapture, wantsUntrusted, _argc); \
} \
diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp
index 280e40ad5..aff65b40f 100755
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -11,6 +11,7 @@
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/ContentEvents.h"
#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/EventDispatcher.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/InternalMutationEvent.h"
#include "mozilla/dom/Performance.h"
@@ -157,18 +158,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
tmp->mEvent->mTarget = nullptr;
tmp->mEvent->mCurrentTarget = nullptr;
tmp->mEvent->mOriginalTarget = nullptr;
+ tmp->mEvent->mRelatedTarget = nullptr;
switch (tmp->mEvent->mClass) {
- case eMouseEventClass:
- case eMouseScrollEventClass:
- case eWheelEventClass:
- case eSimpleGestureEventClass:
- case ePointerEventClass:
- tmp->mEvent->AsMouseEventBase()->relatedTarget = nullptr;
- break;
case eDragEventClass: {
WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
dragEvent->mDataTransfer = nullptr;
- dragEvent->relatedTarget = nullptr;
break;
}
case eClipboardEventClass:
@@ -177,9 +171,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
case eMutationEventClass:
tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
break;
- case eFocusEventClass:
- tmp->mEvent->AsFocusEvent()->mRelatedTarget = nullptr;
- break;
default:
break;
}
@@ -195,21 +186,12 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mCurrentTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalTarget)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mRelatedTarget)
switch (tmp->mEvent->mClass) {
- case eMouseEventClass:
- case eMouseScrollEventClass:
- case eWheelEventClass:
- case eSimpleGestureEventClass:
- case ePointerEventClass:
- NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
- cb.NoteXPCOMChild(tmp->mEvent->AsMouseEventBase()->relatedTarget);
- break;
case eDragEventClass: {
WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mDataTransfer");
cb.NoteXPCOMChild(dragEvent->mDataTransfer);
- NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
- cb.NoteXPCOMChild(dragEvent->relatedTarget);
break;
}
case eClipboardEventClass:
@@ -220,10 +202,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
break;
- case eFocusEventClass:
- NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedTarget");
- cb.NoteXPCOMChild(tmp->mEvent->AsFocusEvent()->mRelatedTarget);
- break;
default:
break;
}
@@ -298,6 +276,12 @@ Event::GetCurrentTarget() const
return mEvent->GetCurrentDOMEventTarget();
}
+void
+Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath)
+{
+ EventDispatcher::GetComposedPathFor(mEvent, aPath);
+}
+
NS_IMETHODIMP
Event::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget)
{
diff --git a/dom/events/Event.h b/dom/events/Event.h
index 0817aa809..4f1fcc827 100755
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -157,6 +157,8 @@ public:
EventTarget* GetTarget() const;
EventTarget* GetCurrentTarget() const;
+ void ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath);
+
uint16_t EventPhase() const;
// xpidl implementation
diff --git a/dom/events/EventDispatcher.cpp b/dom/events/EventDispatcher.cpp
index 1d4dfd7d9..1094c08c2 100644
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -130,13 +130,6 @@ static bool IsEventTargetChrome(EventTarget* aEventTarget,
return isChrome;
}
-
-#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
-#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
-#define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2)
-#define NS_TARGET_CHAIN_CHECKED_IF_CHROME (1 << 3)
-#define NS_TARGET_CHAIN_IS_CHROME_CONTENT (1 << 4)
-
// EventTargetChainItem represents a single item in the event target chain.
class EventTargetChainItem
{
@@ -144,8 +137,7 @@ private:
explicit EventTargetChainItem(EventTarget* aTarget);
public:
EventTargetChainItem()
- : mFlags(0)
- , mItemFlags(0)
+ : mItemFlags(0)
{
}
@@ -153,7 +145,8 @@ public:
EventTarget* aTarget,
EventTargetChainItem* aChild = nullptr)
{
- MOZ_ASSERT(!aChild || &aChain.ElementAt(aChain.Length() - 1) == aChild);
+ // The last item which can handle the event must be aChild.
+ MOZ_ASSERT(GetLastCanHandleEventTarget(aChain) == aChild);
return new (aChain.AppendElement()) EventTargetChainItem(aTarget);
}
@@ -165,6 +158,38 @@ public:
aChain.RemoveElementAt(lastIndex);
}
+ static EventTargetChainItem* GetFirstCanHandleEventTarget(
+ nsTArray<EventTargetChainItem>& aChain)
+ {
+ return &aChain[GetFirstCanHandleEventTargetIdx(aChain)];
+ }
+
+ static uint32_t GetFirstCanHandleEventTargetIdx(nsTArray<EventTargetChainItem>& aChain)
+ {
+ // aChain[i].PreHandleEventOnly() = true only when the target element wants
+ // PreHandleEvent and set mCanHandle=false. So we find the first element
+ // which can handle the event.
+ for (uint32_t i = 0; i < aChain.Length(); ++i) {
+ if (!aChain[i].PreHandleEventOnly()) {
+ return i;
+ }
+ }
+ MOZ_ASSERT(false);
+ return 0;
+ }
+
+ static EventTargetChainItem* GetLastCanHandleEventTarget(
+ nsTArray<EventTargetChainItem>& aChain)
+ {
+ // Fine the last item which can handle the event.
+ for (int32_t i = aChain.Length() - 1; i >= 0; --i) {
+ if (!aChain[i].PreHandleEventOnly()) {
+ return &aChain[i];
+ }
+ }
+ return nullptr;
+ }
+
bool IsValid()
{
NS_WARNING_ASSERTION(!!(mTarget), "Event target is not valid!");
@@ -183,44 +208,82 @@ public:
void SetForceContentDispatch(bool aForce)
{
- if (aForce) {
- mFlags |= NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
- } else {
- mFlags &= ~NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
- }
+ mFlags.mForceContentDispatch = aForce;
}
bool ForceContentDispatch()
{
- return !!(mFlags & NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH);
+ return mFlags.mForceContentDispatch;
}
void SetWantsWillHandleEvent(bool aWants)
{
- if (aWants) {
- mFlags |= NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
- } else {
- mFlags &= ~NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
- }
+ mFlags.mWantsWillHandleEvent = aWants;
}
bool WantsWillHandleEvent()
{
- return !!(mFlags & NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT);
+ return mFlags.mWantsWillHandleEvent;
+ }
+
+ void SetWantsPreHandleEvent(bool aWants)
+ {
+ mFlags.mWantsPreHandleEvent = aWants;
+ }
+
+ bool WantsPreHandleEvent()
+ {
+ return mFlags.mWantsPreHandleEvent;
+ }
+
+ void SetPreHandleEventOnly(bool aWants)
+ {
+ mFlags.mPreHandleEventOnly = aWants;
+ }
+
+ bool PreHandleEventOnly()
+ {
+ return mFlags.mPreHandleEventOnly;
+ }
+
+ void SetRootOfClosedTree(bool aSet)
+ {
+ mFlags.mRootOfClosedTree = aSet;
+ }
+
+ bool IsRootOfClosedTree()
+ {
+ return mFlags.mRootOfClosedTree;
+ }
+
+ void SetIsSlotInClosedTree(bool aSet)
+ {
+ mFlags.mIsSlotInClosedTree = aSet;
+ }
+
+ bool IsSlotInClosedTree()
+ {
+ return mFlags.mIsSlotInClosedTree;
+ }
+
+ void SetIsChromeHandler(bool aSet)
+ {
+ mFlags.mIsChromeHandler = aSet;
+ }
+
+ bool IsChromeHandler()
+ {
+ return mFlags.mIsChromeHandler;
}
void SetMayHaveListenerManager(bool aMayHave)
{
- if (aMayHave) {
- mFlags |= NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
- } else {
- mFlags &= ~NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
- }
+ mFlags.mMayHaveManager = aMayHave;
}
bool MayHaveListenerManager()
{
- return !!(mFlags & NS_TARGET_CHAIN_MAY_HAVE_MANAGER);
+ return mFlags.mMayHaveManager;
}
EventTarget* CurrentTarget()
@@ -240,10 +303,15 @@ public:
ELMCreationDetector& aCd);
/**
- * Resets aVisitor object and calls PreHandleEvent.
+ * Resets aVisitor object and calls GetEventTargetParent.
* Copies mItemFlags and mItemData to the current EventTargetChainItem.
*/
- void PreHandleEvent(EventChainPreVisitor& aVisitor);
+ void GetEventTargetParent(EventChainPreVisitor& aVisitor);
+
+ /**
+ * Calls PreHandleEvent for those items which called SetWantsPreHandleEvent.
+ */
+ void PreHandleEvent(EventChainVisitor& aVisitor);
/**
* If the current item in the event target chain has an event listener
@@ -288,7 +356,37 @@ public:
private:
nsCOMPtr<EventTarget> mTarget;
- uint16_t mFlags;
+
+ class EventTargetChainFlags
+ {
+ public:
+ explicit EventTargetChainFlags()
+ {
+ SetRawFlags(0);
+ }
+ // Cached flags for each EventTargetChainItem which are set when calling
+ // GetEventTargetParent to create event target chain. They are used to
+ // manage or speedup event dispatching.
+ bool mForceContentDispatch : 1;
+ bool mWantsWillHandleEvent : 1;
+ bool mMayHaveManager : 1;
+ bool mChechedIfChrome : 1;
+ bool mIsChromeContent : 1;
+ bool mWantsPreHandleEvent : 1;
+ bool mPreHandleEventOnly : 1;
+ bool mRootOfClosedTree : 1;
+ bool mIsSlotInClosedTree : 1;
+ bool mIsChromeHandler : 1;
+ private:
+ typedef uint32_t RawFlags;
+ void SetRawFlags(RawFlags aRawFlags)
+ {
+ static_assert(sizeof(EventTargetChainFlags) <= sizeof(RawFlags),
+ "EventTargetChainFlags must not be bigger than the RawFlags");
+ memcpy(this, &aRawFlags, sizeof(EventTargetChainFlags));
+ }
+ } mFlags;
+
uint16_t mItemFlags;
nsCOMPtr<nsISupports> mItemData;
// Event retargeting must happen whenever mNewTarget is non-null.
@@ -298,37 +396,50 @@ private:
bool IsCurrentTargetChrome()
{
- if (!(mFlags & NS_TARGET_CHAIN_CHECKED_IF_CHROME)) {
- mFlags |= NS_TARGET_CHAIN_CHECKED_IF_CHROME;
+ if (!mFlags.mChechedIfChrome) {
+ mFlags.mChechedIfChrome = true;
if (IsEventTargetChrome(mTarget)) {
- mFlags |= NS_TARGET_CHAIN_IS_CHROME_CONTENT;
+ mFlags.mIsChromeContent = true;
}
}
- return !!(mFlags & NS_TARGET_CHAIN_IS_CHROME_CONTENT);
+ return mFlags.mIsChromeContent;
}
};
EventTargetChainItem::EventTargetChainItem(EventTarget* aTarget)
: mTarget(aTarget)
- , mFlags(0)
, mItemFlags(0)
{
MOZ_ASSERT(!aTarget || mTarget == aTarget->GetTargetForEventTargetChain());
}
void
-EventTargetChainItem::PreHandleEvent(EventChainPreVisitor& aVisitor)
+EventTargetChainItem::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.Reset();
- Unused << mTarget->PreHandleEvent(aVisitor);
+ Unused << mTarget->GetEventTargetParent(aVisitor);
SetForceContentDispatch(aVisitor.mForceContentDispatch);
SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent);
SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager);
+ SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent);
+ SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle);
+ SetRootOfClosedTree(aVisitor.mRootOfClosedTree);
mItemFlags = aVisitor.mItemFlags;
mItemData = aVisitor.mItemData;
}
void
+EventTargetChainItem::PreHandleEvent(EventChainVisitor& aVisitor)
+{
+ if (!WantsPreHandleEvent()) {
+ return;
+ }
+ aVisitor.mItemFlags = mItemFlags;
+ aVisitor.mItemData = mItemData;
+ Unused << mTarget->PreHandleEvent(aVisitor);
+}
+
+void
EventTargetChainItem::PostHandleEvent(EventChainPostVisitor& aVisitor)
{
aVisitor.mItemFlags = mItemFlags;
@@ -346,12 +457,17 @@ EventTargetChainItem::HandleEventTargetChain(
// Save the target so that it can be restored later.
nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->mTarget;
uint32_t chainLength = aChain.Length();
+ uint32_t firstCanHandleEventTargetIdx =
+ EventTargetChainItem::GetFirstCanHandleEventTargetIdx(aChain);
// Capture
aVisitor.mEvent->mFlags.mInCapturePhase = true;
aVisitor.mEvent->mFlags.mInBubblingPhase = false;
- for (uint32_t i = chainLength - 1; i > 0; --i) {
+ for (uint32_t i = chainLength - 1; i > firstCanHandleEventTargetIdx; --i) {
EventTargetChainItem& item = aChain[i];
+ if (item.PreHandleEventOnly()) {
+ continue;
+ }
if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
item.ForceContentDispatch()) &&
!aVisitor.mEvent->PropagationStopped()) {
@@ -373,7 +489,7 @@ EventTargetChainItem::HandleEventTargetChain(
// Target
aVisitor.mEvent->mFlags.mInBubblingPhase = true;
- EventTargetChainItem& targetItem = aChain[0];
+ EventTargetChainItem& targetItem = aChain[firstCanHandleEventTargetIdx];
if (!aVisitor.mEvent->PropagationStopped() &&
(!aVisitor.mEvent->mFlags.mNoContentDispatch ||
targetItem.ForceContentDispatch())) {
@@ -385,8 +501,11 @@ EventTargetChainItem::HandleEventTargetChain(
// Bubble
aVisitor.mEvent->mFlags.mInCapturePhase = false;
- for (uint32_t i = 1; i < chainLength; ++i) {
+ for (uint32_t i = firstCanHandleEventTargetIdx + 1; i < chainLength; ++i) {
EventTargetChainItem& item = aChain[i];
+ if (item.PreHandleEventOnly()) {
+ continue;
+ }
EventTarget* newTarget = item.GetNewTarget();
if (newTarget) {
// Item is at anonymous boundary. Need to retarget for the current item
@@ -471,6 +590,28 @@ EventTargetChainItemForChromeTarget(nsTArray<EventTargetChainItem>& aChain,
return etci;
}
+/* static */ EventTargetChainItem*
+MayRetargetToChromeIfCanNotHandleEvent(
+ nsTArray<EventTargetChainItem>& aChain, EventChainPreVisitor& aPreVisitor,
+ EventTargetChainItem* aTargetEtci, EventTargetChainItem* aChildEtci,
+ nsINode* aContent)
+{
+ if (!aPreVisitor.mWantsPreHandleEvent) {
+ // Keep EventTargetChainItem if we need to call PreHandleEvent on it.
+ EventTargetChainItem::DestroyLast(aChain, aTargetEtci);
+ }
+ if (aPreVisitor.mAutomaticChromeDispatch && aContent) {
+ // Event target couldn't handle the event. Try to propagate to chrome.
+ EventTargetChainItem* chromeTargetEtci =
+ EventTargetChainItemForChromeTarget(aChain, aContent, aChildEtci);
+ if (chromeTargetEtci) {
+ chromeTargetEtci->GetEventTargetParent(aPreVisitor);
+ return chromeTargetEtci;
+ }
+ }
+ return nullptr;
+}
+
/* static */ nsresult
EventDispatcher::Dispatch(nsISupports* aTarget,
nsPresContext* aPresContext,
@@ -593,7 +734,6 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
// Create the event target chain item for the event target.
EventTargetChainItem* targetEtci =
EventTargetChainItem::Create(chain, target->GetTargetForEventTargetChain());
- MOZ_ASSERT(&chain[0] == targetEtci);
if (!targetEtci->IsValid()) {
EventTargetChainItem::DestroyLast(chain, targetEtci);
return NS_ERROR_FAILURE;
@@ -631,37 +771,43 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
aEvent->mFlags.mIsBeingDispatched = true;
// Create visitor object and start event dispatching.
- // PreHandleEvent for the original target.
+ // GetEventTargetParent for the original target.
nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore;
EventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
isInAnon);
- targetEtci->PreHandleEvent(preVisitor);
-
- if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) {
- // Event target couldn't handle the event. Try to propagate to chrome.
- EventTargetChainItem::DestroyLast(chain, targetEtci);
- targetEtci = EventTargetChainItemForChromeTarget(chain, content);
- NS_ENSURE_STATE(targetEtci);
- MOZ_ASSERT(&chain[0] == targetEtci);
- targetEtci->PreHandleEvent(preVisitor);
- }
- if (preVisitor.mCanHandle) {
+ targetEtci->GetEventTargetParent(preVisitor);
+
+ if (!preVisitor.mCanHandle) {
+ targetEtci = MayRetargetToChromeIfCanNotHandleEvent(chain, preVisitor,
+ targetEtci, nullptr,
+ content);
+ }
+ if (!preVisitor.mCanHandle) {
+ // The original target and chrome target (mAutomaticChromeDispatch=true)
+ // can not handle the event but we still have to call their PreHandleEvent.
+ for (uint32_t i = 0; i < chain.Length(); ++i) {
+ chain[i].PreHandleEvent(preVisitor);
+ }
+ } else {
// At least the original target can handle the event.
// Setting the retarget to the |target| simplifies retargeting code.
nsCOMPtr<EventTarget> t = do_QueryInterface(aEvent->mTarget);
targetEtci->SetNewTarget(t);
EventTargetChainItem* topEtci = targetEtci;
targetEtci = nullptr;
- while (preVisitor.mParentTarget) {
- EventTarget* parentTarget = preVisitor.mParentTarget;
+ while (preVisitor.GetParentTarget()) {
+ EventTarget* parentTarget = preVisitor.GetParentTarget();
EventTargetChainItem* parentEtci =
- EventTargetChainItem::Create(chain, preVisitor.mParentTarget, topEtci);
+ EventTargetChainItem::Create(chain, parentTarget, topEtci);
if (!parentEtci->IsValid()) {
EventTargetChainItem::DestroyLast(chain, parentEtci);
rv = NS_ERROR_FAILURE;
break;
}
+ parentEtci->SetIsSlotInClosedTree(preVisitor.mParentIsSlotInClosedTree);
+ parentEtci->SetIsChromeHandler(preVisitor.mParentIsChromeHandler);
+
// Item needs event retargetting.
if (preVisitor.mEventTargetAtParent) {
// Need to set the target of the event
@@ -670,29 +816,22 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent);
}
- parentEtci->PreHandleEvent(preVisitor);
+ parentEtci->GetEventTargetParent(preVisitor);
if (preVisitor.mCanHandle) {
topEtci = parentEtci;
} else {
- EventTargetChainItem::DestroyLast(chain, parentEtci);
- parentEtci = nullptr;
- if (preVisitor.mAutomaticChromeDispatch && content) {
- // Even if the current target can't handle the event, try to
- // propagate to chrome.
- nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
- if (disabledTarget) {
- parentEtci = EventTargetChainItemForChromeTarget(chain,
- disabledTarget,
- topEtci);
- if (parentEtci) {
- parentEtci->PreHandleEvent(preVisitor);
- if (preVisitor.mCanHandle) {
- chain[0].SetNewTarget(parentTarget);
- topEtci = parentEtci;
- continue;
- }
- }
- }
+ nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
+ parentEtci = MayRetargetToChromeIfCanNotHandleEvent(chain,
+ preVisitor,
+ parentEtci,
+ topEtci,
+ disabledTarget);
+ if (parentEtci && preVisitor.mCanHandle) {
+ EventTargetChainItem* item =
+ EventTargetChainItem::GetFirstCanHandleEventTarget(chain);
+ item->SetNewTarget(parentTarget);
+ topEtci = parentEtci;
+ continue;
}
break;
}
@@ -706,11 +845,19 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
targets[i] = chain[i].CurrentTarget()->GetTargetForDOMEvent();
}
} else {
- // Event target chain is created. Handle the chain.
+ // Event target chain is created. PreHandle the chain.
+ for (uint32_t i = 0; i < chain.Length(); ++i) {
+ chain[i].PreHandleEvent(preVisitor);
+ }
+ // Handle the chain.
EventChainPostVisitor postVisitor(preVisitor);
+ MOZ_RELEASE_ASSERT(!aEvent->mPath);
+ aEvent->mPath = &chain;
EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
aCallback, cd);
+ aEvent->mPath = nullptr;
+
preVisitor.mEventStatus = postVisitor.mEventStatus;
// If the DOM event was created during event flow.
if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
@@ -1022,4 +1169,64 @@ EventDispatcher::CreateEvent(EventTarget* aOwner,
return nullptr;
}
+// static
+void
+EventDispatcher::GetComposedPathFor(WidgetEvent* aEvent,
+ nsTArray<RefPtr<EventTarget>>& aPath)
+{
+ nsTArray<EventTargetChainItem>* path = aEvent->mPath;
+ if (!path || path->IsEmpty() || !aEvent->mCurrentTarget) {
+ return;
+ }
+
+ EventTarget* currentTarget =
+ aEvent->mCurrentTarget->GetTargetForEventTargetChain();
+ if (!currentTarget) {
+ return;
+ }
+
+ AutoTArray<EventTarget*, 128> reversedComposedPath;
+ bool hasSeenCurrentTarget = false;
+ uint32_t hiddenSubtreeLevel = 0;
+ for (uint32_t i = path->Length(); i; ) {
+ --i;
+
+ EventTargetChainItem& item = path->ElementAt(i);
+ if (item.PreHandleEventOnly()) {
+ continue;
+ }
+
+ if (!hasSeenCurrentTarget && currentTarget == item.CurrentTarget()) {
+ hasSeenCurrentTarget = true;
+ } else if (hasSeenCurrentTarget && item.IsRootOfClosedTree()) {
+ ++hiddenSubtreeLevel;
+ }
+
+ if (hiddenSubtreeLevel == 0) {
+ reversedComposedPath.AppendElement(item.CurrentTarget());
+ }
+
+ if (item.IsSlotInClosedTree() && hiddenSubtreeLevel > 0) {
+ --hiddenSubtreeLevel;
+ }
+
+ if (item.IsChromeHandler()) {
+ if (hasSeenCurrentTarget) {
+ // The current behavior is to include only EventTargets from
+ // either chrome side of event path or content side, not from both.
+ break;
+ }
+
+ // Need to start all over to collect the composed path on content side.
+ reversedComposedPath.Clear();
+ }
+ }
+
+ aPath.SetCapacity(reversedComposedPath.Length());
+ for (uint32_t i = reversedComposedPath.Length(); i; ) {
+ --i;
+ aPath.AppendElement(reversedComposedPath[i]->GetTargetForDOMEvent());
+ }
+}
+
} // namespace mozilla
diff --git a/dom/events/EventDispatcher.h b/dom/events/EventDispatcher.h
index 3c754033d..8a34e6bf7 100644
--- a/dom/events/EventDispatcher.h
+++ b/dom/events/EventDispatcher.h
@@ -31,14 +31,14 @@ class EventTarget;
* About event dispatching:
* When either EventDispatcher::Dispatch or
* EventDispatcher::DispatchDOMEvent is called an event target chain is
- * created. EventDispatcher creates the chain by calling PreHandleEvent
+ * created. EventDispatcher creates the chain by calling GetEventTargetParent
* on each event target and the creation continues until either the mCanHandle
* member of the EventChainPreVisitor object is false or the mParentTarget
* does not point to a new target. The event target chain is created in the
* heap.
*
* If the event needs retargeting, mEventTargetAtParent must be set in
- * PreHandleEvent.
+ * GetEventTargetParent.
*
* The capture, target and bubble phases of the event dispatch are handled
* by iterating through the event target chain. Iteration happens twice,
@@ -86,7 +86,7 @@ public:
/**
* Bits for items in the event target chain.
- * Set in PreHandleEvent() and used in PostHandleEvent().
+ * Set in GetEventTargetParent() and used in PostHandleEvent().
*
* @note These bits are different for each item in the event target chain.
* It is up to the Pre/PostHandleEvent implementation to decide how to
@@ -98,7 +98,7 @@ public:
/**
* Data for items in the event target chain.
- * Set in PreHandleEvent() and used in PostHandleEvent().
+ * Set in GetEventTargetParent() and used in PostHandleEvent().
*
* @note This data is different for each item in the event target chain.
* It is up to the Pre/PostHandleEvent implementation to decide how to
@@ -123,6 +123,10 @@ public:
, mOriginalTargetIsInAnon(aIsInAnon)
, mWantsWillHandleEvent(false)
, mMayHaveListenerManager(true)
+ , mWantsPreHandleEvent(false)
+ , mRootOfClosedTree(false)
+ , mParentIsSlotInClosedTree(false)
+ , mParentIsChromeHandler(false)
, mParentTarget(nullptr)
, mEventTargetAtParent(nullptr)
{
@@ -137,13 +141,30 @@ public:
mForceContentDispatch = false;
mWantsWillHandleEvent = false;
mMayHaveListenerManager = true;
+ mWantsPreHandleEvent = false;
+ mRootOfClosedTree = false;
+ mParentIsSlotInClosedTree = false;
+ mParentIsChromeHandler = false;
mParentTarget = nullptr;
mEventTargetAtParent = nullptr;
}
+ dom::EventTarget* GetParentTarget()
+ {
+ return mParentTarget;
+ }
+
+ void SetParentTarget(dom::EventTarget* aParentTarget, bool aIsChromeHandler)
+ {
+ mParentTarget = aParentTarget;
+ if (mParentTarget) {
+ mParentIsChromeHandler = aIsChromeHandler;
+ }
+ }
+
/**
- * Member that must be set in PreHandleEvent by event targets. If set to false,
- * indicates that this event target will not be handling the event and
+ * Member that must be set in GetEventTargetParent by event targets. If set to
+ * false, indicates that this event target will not be handling the event and
* construction of the event target chain is complete. The target that sets
* mCanHandle to false is NOT included in the event target chain.
*/
@@ -170,7 +191,7 @@ public:
/**
* true if the original target of the event is inside anonymous content.
- * This is set before calling PreHandleEvent on event targets.
+ * This is set before calling GetEventTargetParent on event targets.
*/
bool mOriginalTargetIsInAnon;
@@ -182,27 +203,45 @@ public:
/**
* If it is known that the current target doesn't have a listener manager
- * when PreHandleEvent is called, set this to false.
+ * when GetEventTargetParent is called, set this to false.
*/
bool mMayHaveListenerManager;
/**
+ * Whether or not nsIDOMEventTarget::PreHandleEvent will be called. Default is
+ * false;
+ */
+ bool mWantsPreHandleEvent;
+
+ /**
+ * True if the current target is either closed ShadowRoot or root of
+ * chrome only access tree (for example native anonymous content).
+ */
+ bool mRootOfClosedTree;
+
+ /**
+ * True if mParentTarget is HTMLSlotElement in a closed shadow tree and the
+ * current target is assigned to that slot.
+ */
+ bool mParentIsSlotInClosedTree;
+
+ /**
+ * True if mParentTarget is a chrome handler in the event path.
+ */
+ bool mParentIsChromeHandler;
+
+private:
+ /**
* Parent item in the event target chain.
*/
dom::EventTarget* mParentTarget;
+public:
/**
* If the event needs to be retargeted, this is the event target,
* which should be used when the event is handled at mParentTarget.
*/
dom::EventTarget* mEventTargetAtParent;
-
- /**
- * An array of destination insertion points that need to be inserted
- * into the event path of nodes that are distributed by the
- * web components distribution algorithm.
- */
- nsTArray<nsIContent*> mDestInsertionPoints;
};
class EventChainPostVisitor : public mozilla::EventChainVisitor
@@ -280,6 +319,9 @@ public:
WidgetEvent* aEvent,
const nsAString& aEventType);
+ static void GetComposedPathFor(WidgetEvent* aEvent,
+ nsTArray<RefPtr<dom::EventTarget>>& aPath);
+
/**
* Called at shutting down.
*/
diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp
index e16d68c81..cc3bd3f5a 100644
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -3484,6 +3484,12 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
// make sure to fire the enter and exit_synth events after the
// eDragExit event, otherwise we'll clean up too early
GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
+ if (ContentChild* child = ContentChild::GetSingleton()) {
+ // SendUpdateDropEffect to prevent nsIDragService from waiting for
+ // response of forwarded dragexit event.
+ child->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
+ nsIDragService::DRAGDROP_ACTION_NONE);
+ }
break;
case eBeforeKeyUp:
@@ -3900,13 +3906,13 @@ CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
newPointerEvent->mWidth = sourcePointer->mWidth;
newPointerEvent->mHeight = sourcePointer->mHeight;
newPointerEvent->inputSource = sourcePointer->inputSource;
- newPointerEvent->relatedTarget = aRelatedContent;
+ newPointerEvent->mRelatedTarget = aRelatedContent;
aNewEvent = newPointerEvent.forget();
} else {
aNewEvent =
new WidgetMouseEvent(aMouseEvent->IsTrusted(), aMessage,
aMouseEvent->mWidget, WidgetMouseEvent::eReal);
- aNewEvent->relatedTarget = aRelatedContent;
+ aNewEvent->mRelatedTarget = aRelatedContent;
}
aNewEvent->mRefPoint = aMouseEvent->mRefPoint;
aNewEvent->mModifiers = aMouseEvent->mModifiers;
@@ -4446,6 +4452,19 @@ EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
FireDragEnterOrExit(sLastDragOverFrame->PresContext(),
aDragEvent, eDragExit,
targetContent, lastContent, sLastDragOverFrame);
+ nsIContent* target = sLastDragOverFrame ? sLastDragOverFrame.GetFrame()->GetContent() : nullptr;
+ if (IsRemoteTarget(target)) {
+ // Dragging something and moving from web content to chrome only
+ // fires dragexit and dragleave to xul:browser. We have to forward
+ // dragexit to sLastDragOverFrame when its content is a remote
+ // target. We don't forward dragleave since it's generated from
+ // dragexit.
+ WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), eDragExit,
+ aDragEvent->mWidget);
+ remoteEvent.AssignDragEventData(*aDragEvent, true);
+ nsEventStatus remoteStatus = nsEventStatus_eIgnore;
+ HandleCrossProcessEvent(&remoteEvent, &remoteStatus);
+ }
}
FireDragEnterOrExit(aPresContext, aDragEvent, eDragEnter,
@@ -4502,14 +4521,11 @@ EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
nsIContent* aTargetContent,
nsWeakFrame& aTargetFrame)
{
+ MOZ_ASSERT(aMessage == eDragLeave || aMessage == eDragExit ||
+ aMessage == eDragEnter);
nsEventStatus status = nsEventStatus_eIgnore;
WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->mWidget);
- event.mRefPoint = aDragEvent->mRefPoint;
- event.mModifiers = aDragEvent->mModifiers;
- event.buttons = aDragEvent->buttons;
- event.relatedTarget = aRelatedTarget;
- event.inputSource = aDragEvent->inputSource;
-
+ event.AssignDragEventData(*aDragEvent, true);
mCurrentTargetContent = aTargetContent;
if (aTargetContent != aRelatedTarget) {
@@ -4527,10 +4543,7 @@ EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
// collect any changes to moz cursor settings stored in the event's
// data transfer.
- if (aMessage == eDragLeave || aMessage == eDragExit ||
- aMessage == eDragEnter) {
- UpdateDragDataTransfer(&event);
- }
+ UpdateDragDataTransfer(&event);
}
// Finally dispatch the event to the frame
diff --git a/dom/events/EventStates.h b/dom/events/EventStates.h
index 2672d2897..3397110ba 100644
--- a/dom/events/EventStates.h
+++ b/dom/events/EventStates.h
@@ -292,14 +292,39 @@ private:
#define NS_EVENT_STATE_RTL NS_DEFINE_EVENT_STATE_MACRO(43)
// Element is highlighted (devtools inspector)
#define NS_EVENT_STATE_DEVTOOLS_HIGHLIGHTED NS_DEFINE_EVENT_STATE_MACRO(45)
-// Element is an unresolved custom element candidate
-#define NS_EVENT_STATE_UNRESOLVED NS_DEFINE_EVENT_STATE_MACRO(46)
+// States for tracking the state of the "dir" attribute for HTML elements. We
+// use these to avoid having to get "dir" attributes all the time during
+// selector matching for some parts of the UA stylesheet.
+//
+// These states are externally managed, because we also don't want to keep
+// getting "dir" attributes in IntrinsicState.
+//
+// Element is HTML and has a "dir" attibute. This state might go away depending
+// on how https://github.com/whatwg/html/issues/2769 gets resolved. The value
+// could be anything.
+#define NS_EVENT_STATE_HAS_DIR_ATTR NS_DEFINE_EVENT_STATE_MACRO(46)
+// Element is HTML, has a "dir" attribute, and the attribute's value is
+// case-insensitively equal to "ltr".
+#define NS_EVENT_STATE_DIR_ATTR_LTR NS_DEFINE_EVENT_STATE_MACRO(47)
+// Element is HTML, has a "dir" attribute, and the attribute's value is
+// case-insensitively equal to "rtl".
+#define NS_EVENT_STATE_DIR_ATTR_RTL NS_DEFINE_EVENT_STATE_MACRO(48)
+// Element is HTML, and is either a <bdi> element with no valid-valued "dir"
+// attribute or any HTML element which has a "dir" attribute whose value is
+// "auto".
+#define NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO NS_DEFINE_EVENT_STATE_MACRO(49)
+// Free bit NS_DEFINE_EVENT_STATE_MACRO(50)
// Element is transitioning for rules changed by style editor
-#define NS_EVENT_STATE_STYLEEDITOR_TRANSITIONING NS_DEFINE_EVENT_STATE_MACRO(47)
+#define NS_EVENT_STATE_STYLEEDITOR_TRANSITIONING NS_DEFINE_EVENT_STATE_MACRO(51)
// Content shows its placeholder
-#define NS_EVENT_STATE_PLACEHOLDERSHOWN NS_DEFINE_EVENT_STATE_MACRO(48)
+#define NS_EVENT_STATE_PLACEHOLDERSHOWN NS_DEFINE_EVENT_STATE_MACRO(52)
// Element has focus-within.
-#define NS_EVENT_STATE_FOCUS_WITHIN NS_DEFINE_EVENT_STATE_MACRO(49)
+#define NS_EVENT_STATE_FOCUS_WITHIN NS_DEFINE_EVENT_STATE_MACRO(53)
+
+#define DIR_ATTR_STATES (NS_EVENT_STATE_HAS_DIR_ATTR | \
+ NS_EVENT_STATE_DIR_ATTR_LTR | \
+ NS_EVENT_STATE_DIR_ATTR_RTL | \
+ NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO)
// Event state that is used for values that need to be parsed but do nothing.
#define NS_EVENT_STATE_IGNORE NS_DEFINE_EVENT_STATE_MACRO(63)
@@ -310,11 +335,10 @@ private:
#define DIRECTION_STATES (NS_EVENT_STATE_LTR | NS_EVENT_STATE_RTL)
-#define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \
+#define ESM_MANAGED_STATES (DIR_ATTR_STATES | NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \
NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER | \
NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
- NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_UNRESOLVED | \
- NS_EVENT_STATE_FOCUS_WITHIN)
+ NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_FOCUS_WITHIN)
#define INTRINSIC_STATES (~ESM_MANAGED_STATES)
diff --git a/dom/events/MouseEvent.cpp b/dom/events/MouseEvent.cpp
index 5e540ac5b..415e626c5 100644
--- a/dom/events/MouseEvent.cpp
+++ b/dom/events/MouseEvent.cpp
@@ -79,7 +79,7 @@ MouseEvent::InitMouseEvent(const nsAString& aType,
case ePointerEventClass:
case eSimpleGestureEventClass: {
WidgetMouseEventBase* mouseEventBase = mEvent->AsMouseEventBase();
- mouseEventBase->relatedTarget = aRelatedTarget;
+ mouseEventBase->mRelatedTarget = aRelatedTarget;
mouseEventBase->button = aButton;
mouseEventBase->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
mClientPoint.x = aClientX;
@@ -295,8 +295,7 @@ MouseEvent::GetRelatedTarget()
case eDragEventClass:
case ePointerEventClass:
case eSimpleGestureEventClass:
- relatedTarget =
- do_QueryInterface(mEvent->AsMouseEventBase()->relatedTarget);
+ relatedTarget = mEvent->AsMouseEventBase()->mRelatedTarget;
break;
default:
break;
diff --git a/dom/events/test/mochitest.ini b/dom/events/test/mochitest.ini
index 0397487bb..27e8e7150 100644
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -185,3 +185,4 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_bug687787.html]
[test_bug1298970.html]
[test_bug1304044.html]
+[test_bug1305458.html]
diff --git a/dom/events/test/test_bug1305458.html b/dom/events/test/test_bug1305458.html
new file mode 100644
index 000000000..df65959a9
--- /dev/null
+++ b/dom/events/test/test_bug1305458.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1305458
+-->
+<head>
+ <title>Test for Bug 1305458</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ input[type=number] {
+ -moz-appearance: textfield;
+ }
+ input[type=number]:focus,
+ input[type=number]:hover {
+ -moz-appearance: number-input;
+ }
+ </style>
+</head>
+<body onload="doTest()">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1305458">Mozilla Bug 1305458</a>
+ <input id="test_input" type="number">
+ <div id="test_div">bar</div>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ var change_count = 0;
+ function doTest() {
+ let input = document.getElementById("test_input");
+ let div = document.getElementById("test_div");
+ input.addEventListener("change", () => {
+ ++change_count;
+ }, false);
+ // mouse hover
+ input.focus();
+ synthesizeMouse(input, 1, 1, {type: "mousemove"});
+ synthesizeKey("1", {});
+ input.blur();
+ is(change_count, 1, "input should fire change when blur");
+
+ input.focus();
+ synthesizeMouse(div, 1, 1, {type: "mousemove"});
+ synthesizeKey("1", {});
+ input.blur();
+ is(change_count, 2, "input should fire change when blur");
+ SimpleTest.finish();
+ }
+ </script>
+</body>
+</html>
diff --git a/dom/html/HTMLAnchorElement.cpp b/dom/html/HTMLAnchorElement.cpp
index a6cfacc53..0759af339 100644
--- a/dom/html/HTMLAnchorElement.cpp
+++ b/dom/html/HTMLAnchorElement.cpp
@@ -14,6 +14,7 @@
#include "nsContentUtils.h"
#include "nsGkAtoms.h"
#include "nsHTMLDNSPrefetch.h"
+#include "nsAttrValueOrString.h"
#include "nsIDocument.h"
#include "nsIPresShell.h"
#include "nsPresContext.h"
@@ -252,9 +253,9 @@ HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse,
}
nsresult
-HTMLAnchorElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLAnchorElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- return PreHandleEventForAnchors(aVisitor);
+ return GetEventTargetParentForAnchors(aVisitor);
}
nsresult
@@ -372,84 +373,37 @@ HTMLAnchorElement::GetHrefURI() const
}
nsresult
-HTMLAnchorElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
+HTMLAnchorElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify)
{
- bool reset = false;
- if (aName == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
- // If we do not have a cached URI, we have some value here so we must reset
- // our link state after calling the parent.
- if (!Link::HasCachedURI()) {
- reset = true;
- }
- // However, if we have a cached URI, we'll want to see if the value changed.
- else {
- nsAutoString val;
- GetHref(val);
- if (!val.Equals(aValue)) {
- reset = true;
- }
- }
- if (reset) {
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::href) {
CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
}
}
- nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
- aValue, aNotify);
-
- // The ordering of the parent class's SetAttr call and Link::ResetLinkState
- // is important here! The attribute is not set until SetAttr returns, and
- // we will need the updated attribute value because notifying the document
- // that content states have changed will call IntrinsicState, which will try
- // to get updated information about the visitedness from Link.
- if (reset) {
- Link::ResetLinkState(!!aNotify, true);
- if (IsInComposedDoc()) {
- TryDNSPrefetch();
- }
- }
-
- return rv;
+ return nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName, aValue,
+ aNotify);
}
nsresult
-HTMLAnchorElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify)
+HTMLAnchorElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
- bool href =
- (aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID);
-
- if (href) {
- CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
- HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
- }
-
- nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
- aNotify);
-
- // The ordering of the parent class's UnsetAttr call and Link::ResetLinkState
- // is important here! The attribute is not unset until UnsetAttr returns, and
- // we will need the updated attribute value because notifying the document
- // that content states have changed will call IntrinsicState, which will try
- // to get updated information about the visitedness from Link.
- if (href) {
- Link::ResetLinkState(!!aNotify, false);
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::href) {
+ Link::ResetLinkState(aNotify, !!aValue);
+ if (aValue && IsInComposedDoc()) {
+ TryDNSPrefetch();
+ }
+ }
}
- return rv;
-}
-
-bool
-HTMLAnchorElement::ParseAttribute(int32_t aNamespaceID,
- nsIAtom* aAttribute,
- const nsAString& aValue,
- nsAttrValue& aResult)
-{
- return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
- aResult);
+ return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName,
+ aValue, aOldValue, aNotify);
}
EventStates
diff --git a/dom/html/HTMLAnchorElement.h b/dom/html/HTMLAnchorElement.h
index 2cb04ad93..087555964 100644
--- a/dom/html/HTMLAnchorElement.h
+++ b/dom/html/HTMLAnchorElement.h
@@ -58,27 +58,21 @@ public:
bool aNullParent = true) override;
virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
virtual bool IsLink(nsIURI** aURI) const override;
virtual void GetLinkTarget(nsAString& aTarget) override;
virtual already_AddRefed<nsIURI> GetHrefURI() const override;
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify) override;
- virtual bool ParseAttribute(int32_t aNamespaceID,
- nsIAtom* aAttribute,
- const nsAString& aValue,
- nsAttrValue& aResult) override;
+ virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify) override;
+ virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
diff --git a/dom/html/HTMLAreaElement.cpp b/dom/html/HTMLAreaElement.cpp
index 098081b8b..4c85774f4 100644
--- a/dom/html/HTMLAreaElement.cpp
+++ b/dom/html/HTMLAreaElement.cpp
@@ -81,9 +81,9 @@ HTMLAreaElement::SetTarget(const nsAString& aValue)
}
nsresult
-HTMLAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLAreaElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- return PreHandleEventForAnchors(aVisitor);
+ return GetEventTargetParentForAnchors(aVisitor);
}
nsresult
@@ -153,42 +153,22 @@ HTMLAreaElement::UnbindFromTree(bool aDeep, bool aNullParent)
}
nsresult
-HTMLAreaElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
-{
- nsresult rv =
- nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue, aNotify);
-
- // The ordering of the parent class's SetAttr call and Link::ResetLinkState
- // is important here! The attribute is not set until SetAttr returns, and
- // we will need the updated attribute value because notifying the document
- // that content states have changed will call IntrinsicState, which will try
- // to get updated information about the visitedness from Link.
- if (aName == nsGkAtoms::href && aNameSpaceID == kNameSpaceID_None) {
- Link::ResetLinkState(!!aNotify, true);
+HTMLAreaElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ // This must happen after the attribute is set. We will need the updated
+ // attribute value because notifying the document that content states have
+ // changed will call IntrinsicState, which will try to get updated
+ // information about the visitedness from Link.
+ if (aName == nsGkAtoms::href) {
+ Link::ResetLinkState(aNotify, !!aValue);
+ }
}
- return rv;
-}
-
-nsresult
-HTMLAreaElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify)
-{
- nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
- aNotify);
-
- // The ordering of the parent class's UnsetAttr call and Link::ResetLinkState
- // is important here! The attribute is not unset until UnsetAttr returns, and
- // we will need the updated attribute value because notifying the document
- // that content states have changed will call IntrinsicState, which will try
- // to get updated information about the visitedness from Link.
- if (aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
- Link::ResetLinkState(!!aNotify, false);
- }
-
- return rv;
+ return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
+ aOldValue, aNotify);
}
#define IMPL_URI_PART(_part) \
diff --git a/dom/html/HTMLAreaElement.h b/dom/html/HTMLAreaElement.h
index 650c0fd8f..d408934c9 100644
--- a/dom/html/HTMLAreaElement.h
+++ b/dom/html/HTMLAreaElement.h
@@ -44,7 +44,8 @@ public:
// nsIDOMHTMLAreaElement
NS_DECL_NSIDOMHTMLAREAELEMENT
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
virtual bool IsLink(nsIURI** aURI) const override;
virtual void GetLinkTarget(nsAString& aTarget) override;
@@ -55,16 +56,6 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
@@ -185,6 +176,11 @@ protected:
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+ virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
+
RefPtr<nsDOMTokenList > mRelList;
};
diff --git a/dom/html/HTMLBodyElement.cpp b/dom/html/HTMLBodyElement.cpp
index 6230cb6ca..112d48dd1 100644
--- a/dom/html/HTMLBodyElement.cpp
+++ b/dom/html/HTMLBodyElement.cpp
@@ -27,180 +27,8 @@ namespace dom {
//----------------------------------------------------------------------
-BodyRule::BodyRule(HTMLBodyElement* aPart)
- : mPart(aPart)
-{
-}
-
-BodyRule::~BodyRule()
-{
-}
-
-NS_IMPL_ISUPPORTS(BodyRule, nsIStyleRule)
-
-/* virtual */ void
-BodyRule::MapRuleInfoInto(nsRuleData* aData)
-{
- if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)) || !mPart)
- return; // We only care about margins.
-
- int32_t bodyMarginWidth = -1;
- int32_t bodyMarginHeight = -1;
- int32_t bodyTopMargin = -1;
- int32_t bodyBottomMargin = -1;
- int32_t bodyLeftMargin = -1;
- int32_t bodyRightMargin = -1;
-
- // check the mode (fortunately, the ruleData has a presContext for us to use!)
- NS_ASSERTION(aData->mPresContext, "null presContext in ruleNode was unexpected");
- nsCompatibility mode = aData->mPresContext->CompatibilityMode();
-
-
- const nsAttrValue* value;
- if (mPart->GetAttrCount() > 0) {
- // if marginwidth/marginheight are set, reflect them as 'margin'
- value = mPart->GetParsedAttr(nsGkAtoms::marginwidth);
- if (value && value->Type() == nsAttrValue::eInteger) {
- bodyMarginWidth = value->GetIntegerValue();
- if (bodyMarginWidth < 0) bodyMarginWidth = 0;
- nsCSSValue* marginLeft = aData->ValueForMarginLeft();
- if (marginLeft->GetUnit() == eCSSUnit_Null)
- marginLeft->SetFloatValue((float)bodyMarginWidth, eCSSUnit_Pixel);
- nsCSSValue* marginRight = aData->ValueForMarginRight();
- if (marginRight->GetUnit() == eCSSUnit_Null)
- marginRight->SetFloatValue((float)bodyMarginWidth, eCSSUnit_Pixel);
- }
-
- value = mPart->GetParsedAttr(nsGkAtoms::marginheight);
- if (value && value->Type() == nsAttrValue::eInteger) {
- bodyMarginHeight = value->GetIntegerValue();
- if (bodyMarginHeight < 0) bodyMarginHeight = 0;
- nsCSSValue* marginTop = aData->ValueForMarginTop();
- if (marginTop->GetUnit() == eCSSUnit_Null)
- marginTop->SetFloatValue((float)bodyMarginHeight, eCSSUnit_Pixel);
- nsCSSValue* marginBottom = aData->ValueForMarginBottom();
- if (marginBottom->GetUnit() == eCSSUnit_Null)
- marginBottom->SetFloatValue((float)bodyMarginHeight, eCSSUnit_Pixel);
- }
-
- // topmargin (IE-attribute)
- value = mPart->GetParsedAttr(nsGkAtoms::topmargin);
- if (value && value->Type() == nsAttrValue::eInteger) {
- bodyTopMargin = value->GetIntegerValue();
- if (bodyTopMargin < 0) bodyTopMargin = 0;
- nsCSSValue* marginTop = aData->ValueForMarginTop();
- if (marginTop->GetUnit() == eCSSUnit_Null)
- marginTop->SetFloatValue((float)bodyTopMargin, eCSSUnit_Pixel);
- }
-
- // bottommargin (IE-attribute)
- value = mPart->GetParsedAttr(nsGkAtoms::bottommargin);
- if (value && value->Type() == nsAttrValue::eInteger) {
- bodyBottomMargin = value->GetIntegerValue();
- if (bodyBottomMargin < 0) bodyBottomMargin = 0;
- nsCSSValue* marginBottom = aData->ValueForMarginBottom();
- if (marginBottom->GetUnit() == eCSSUnit_Null)
- marginBottom->SetFloatValue((float)bodyBottomMargin, eCSSUnit_Pixel);
- }
-
- // leftmargin (IE-attribute)
- value = mPart->GetParsedAttr(nsGkAtoms::leftmargin);
- if (value && value->Type() == nsAttrValue::eInteger) {
- bodyLeftMargin = value->GetIntegerValue();
- if (bodyLeftMargin < 0) bodyLeftMargin = 0;
- nsCSSValue* marginLeft = aData->ValueForMarginLeft();
- if (marginLeft->GetUnit() == eCSSUnit_Null)
- marginLeft->SetFloatValue((float)bodyLeftMargin, eCSSUnit_Pixel);
- }
-
- // rightmargin (IE-attribute)
- value = mPart->GetParsedAttr(nsGkAtoms::rightmargin);
- if (value && value->Type() == nsAttrValue::eInteger) {
- bodyRightMargin = value->GetIntegerValue();
- if (bodyRightMargin < 0) bodyRightMargin = 0;
- nsCSSValue* marginRight = aData->ValueForMarginRight();
- if (marginRight->GetUnit() == eCSSUnit_Null)
- marginRight->SetFloatValue((float)bodyRightMargin, eCSSUnit_Pixel);
- }
-
- }
-
- // if marginwidth or marginheight is set in the <frame> and not set in the <body>
- // reflect them as margin in the <body>
- if (bodyMarginWidth == -1 || bodyMarginHeight == -1) {
- nsCOMPtr<nsIDocShell> docShell(aData->mPresContext->GetDocShell());
- if (docShell) {
- nscoord frameMarginWidth=-1; // default value
- nscoord frameMarginHeight=-1; // default value
- docShell->GetMarginWidth(&frameMarginWidth); // -1 indicates not set
- docShell->GetMarginHeight(&frameMarginHeight);
- if ((frameMarginWidth >= 0) && (bodyMarginWidth == -1)) { // set in <frame> & not in <body>
- if (eCompatibility_NavQuirks == mode) {
- if ((bodyMarginHeight == -1) && (0 > frameMarginHeight)) // nav quirk
- frameMarginHeight = 0;
- }
- }
- if ((frameMarginHeight >= 0) && (bodyMarginHeight == -1)) { // set in <frame> & not in <body>
- if (eCompatibility_NavQuirks == mode) {
- if ((bodyMarginWidth == -1) && (0 > frameMarginWidth)) // nav quirk
- frameMarginWidth = 0;
- }
- }
-
- if ((bodyMarginWidth == -1) && (frameMarginWidth >= 0)) {
- nsCSSValue* marginLeft = aData->ValueForMarginLeft();
- if (marginLeft->GetUnit() == eCSSUnit_Null)
- marginLeft->SetFloatValue((float)frameMarginWidth, eCSSUnit_Pixel);
- nsCSSValue* marginRight = aData->ValueForMarginRight();
- if (marginRight->GetUnit() == eCSSUnit_Null)
- marginRight->SetFloatValue((float)frameMarginWidth, eCSSUnit_Pixel);
- }
-
- if ((bodyMarginHeight == -1) && (frameMarginHeight >= 0)) {
- nsCSSValue* marginTop = aData->ValueForMarginTop();
- if (marginTop->GetUnit() == eCSSUnit_Null)
- marginTop->SetFloatValue((float)frameMarginHeight, eCSSUnit_Pixel);
- nsCSSValue* marginBottom = aData->ValueForMarginBottom();
- if (marginBottom->GetUnit() == eCSSUnit_Null)
- marginBottom->SetFloatValue((float)frameMarginHeight, eCSSUnit_Pixel);
- }
- }
- }
-}
-
-/* virtual */ bool
-BodyRule::MightMapInheritedStyleData()
-{
- return false;
-}
-
-/* virtual */ bool
-BodyRule::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
- nsCSSValue* aValue)
-{
- MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
- return false;
-}
-
-#ifdef DEBUG
-/* virtual */ void
-BodyRule::List(FILE* out, int32_t aIndent) const
-{
- nsAutoCString indent;
- for (int32_t index = aIndent; --index >= 0; ) {
- indent.AppendLiteral(" ");
- }
- fprintf_stderr(out, "%s[body rule] {}\n", indent.get());
-}
-#endif
-
-//----------------------------------------------------------------------
-
HTMLBodyElement::~HTMLBodyElement()
{
- if (mContentStyleRule) {
- mContentStyleRule->mPart = nullptr;
- }
}
JSObject*
@@ -348,17 +176,6 @@ HTMLBodyElement::ParseAttribute(int32_t aNamespaceID,
}
void
-HTMLBodyElement::UnbindFromTree(bool aDeep, bool aNullParent)
-{
- if (mContentStyleRule) {
- mContentStyleRule->mPart = nullptr;
- mContentStyleRule = nullptr;
- }
-
- nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
-}
-
-void
HTMLBodyElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
nsRuleData* aData)
{
@@ -413,22 +230,6 @@ HTMLBodyElement::GetAttributeMappingFunction() const
return &MapAttributesIntoRule;
}
-NS_IMETHODIMP
-HTMLBodyElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
-{
- nsGenericHTMLElement::WalkContentStyleRules(aRuleWalker);
-
- if (!mContentStyleRule && IsInUncomposedDoc()) {
- // XXXbz should this use OwnerDoc() or GetComposedDoc()?
- // sXBL/XBL2 issue!
- mContentStyleRule = new BodyRule(this);
- }
- if (aRuleWalker && mContentStyleRule) {
- aRuleWalker->Forward(mContentStyleRule);
- }
- return NS_OK;
-}
-
NS_IMETHODIMP_(bool)
HTMLBodyElement::IsAttributeMapped(const nsIAtom* aAttribute) const
{
@@ -437,12 +238,12 @@ HTMLBodyElement::IsAttributeMapped(const nsIAtom* aAttribute) const
{ &nsGkAtoms::vlink },
{ &nsGkAtoms::alink },
{ &nsGkAtoms::text },
- // These aren't mapped through attribute mapping, but they are
- // mapped through a style rule, so it is attribute dependent style.
- // XXXldb But we don't actually replace the body rule when we have
- // dynamic changes...
{ &nsGkAtoms::marginwidth },
{ &nsGkAtoms::marginheight },
+ { &nsGkAtoms::topmargin },
+ { &nsGkAtoms::rightmargin },
+ { &nsGkAtoms::bottommargin },
+ { &nsGkAtoms::leftmargin },
{ nullptr },
};
@@ -491,6 +292,37 @@ HTMLBodyElement::IsEventAttributeName(nsIAtom *aName)
EventNameType_HTMLBodyOrFramesetOnly);
}
+nsresult
+HTMLBodyElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+ nsIContent* aBindingParent,
+ bool aCompileEventHandlers)
+{
+ nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
+ aBindingParent,
+ aCompileEventHandlers);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return mAttrsAndChildren.ForceMapped(this, OwnerDoc());
+}
+
+nsresult
+HTMLBodyElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
+{
+ nsresult rv = nsGenericHTMLElement::AfterSetAttr(aNameSpaceID,
+ aName, aValue, aOldValue,
+ aNotify);
+ NS_ENSURE_SUCCESS(rv, rv);
+ // if the last mapped attribute was removed, don't clear the
+ // nsMappedAttributes, our style can still depend on the containing frame element
+ if (!aValue && IsAttributeMapped(aName)) {
+ nsresult rv = mAttrsAndChildren.ForceMapped(this, OwnerDoc());
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+}
+
#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the superclass */
// nsGenericHTMLElement::GetOnError returns
// already_AddRefed<EventHandlerNonNull> while other getters return
diff --git a/dom/html/HTMLBodyElement.h b/dom/html/HTMLBodyElement.h
index 436dc4cba..6a888c71b 100644
--- a/dom/html/HTMLBodyElement.h
+++ b/dom/html/HTMLBodyElement.h
@@ -15,28 +15,6 @@ namespace mozilla {
namespace dom {
class OnBeforeUnloadEventHandlerNonNull;
-class HTMLBodyElement;
-
-class BodyRule: public nsIStyleRule
-{
- virtual ~BodyRule();
-
-public:
- explicit BodyRule(HTMLBodyElement* aPart);
-
- NS_DECL_ISUPPORTS
-
- // nsIStyleRule interface
- virtual void MapRuleInfoInto(nsRuleData* aRuleData) override;
- virtual bool MightMapInheritedStyleData() override;
- virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
- nsCSSValue* aValue) override;
-#ifdef DEBUG
- virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
-#endif
-
- HTMLBodyElement* mPart; // not ref-counted, cleared by content
-};
class HTMLBodyElement final : public nsGenericHTMLElement,
public nsIDOMHTMLBodyElement
@@ -125,23 +103,29 @@ public:
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult) override;
- virtual void UnbindFromTree(bool aDeep = true,
- bool aNullParent = true) override;
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
- NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
virtual already_AddRefed<nsIEditor> GetAssociatedEditor() override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
virtual bool IsEventAttributeName(nsIAtom* aName) override;
+ virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+ nsIContent* aBindingParent,
+ bool aCompileEventHandlers) override;
+ /**
+ * Called when an attribute has just been changed
+ */
+ virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
+
protected:
virtual ~HTMLBodyElement();
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
- RefPtr<BodyRule> mContentStyleRule;
-
private:
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
nsRuleData* aData);
diff --git a/dom/html/HTMLButtonElement.cpp b/dom/html/HTMLButtonElement.cpp
index 435aa9f7f..1a76aac10 100644
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -207,7 +207,7 @@ HTMLButtonElement::IsDisabledForEvents(EventMessage aMessage)
}
nsresult
-HTMLButtonElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLButtonElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = false;
if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
@@ -235,7 +235,7 @@ HTMLButtonElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
nsresult
@@ -423,7 +423,7 @@ HTMLButtonElement::DoneCreatingElement()
nsresult
HTMLButtonElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify)
{
if (aNotify && aName == nsGkAtoms::disabled &&
@@ -437,7 +437,8 @@ HTMLButtonElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsresult
HTMLButtonElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::type) {
@@ -448,12 +449,12 @@ HTMLButtonElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
if (aName == nsGkAtoms::type || aName == nsGkAtoms::disabled) {
UpdateBarredFromConstraintValidation();
- UpdateState(aNotify);
}
}
return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue,
+ aNotify);
}
NS_IMETHODIMP
diff --git a/dom/html/HTMLButtonElement.h b/dom/html/HTMLButtonElement.h
index ecd9e03d7..8bab9fd48 100644
--- a/dom/html/HTMLButtonElement.h
+++ b/dom/html/HTMLButtonElement.h
@@ -57,7 +57,8 @@ public:
virtual void FieldSetDisabledChanged(bool aNotify) override;
// nsIDOMEventTarget
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
@@ -80,13 +81,15 @@ public:
* Called when an attribute is about to be changed
*/
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify) override;
/**
* Called when an attribute has just been changed
*/
- nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual bool ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp
index 4b5deab18..ba1fbedbb 100644
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -446,38 +446,37 @@ NS_IMPL_UINT_ATTR_DEFAULT_VALUE(HTMLCanvasElement, Height, height, DEFAULT_CANVA
NS_IMPL_BOOL_ATTR(HTMLCanvasElement, MozOpaque, moz_opaque)
nsresult
-HTMLCanvasElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
-{
- nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
- aNotify);
- if (NS_SUCCEEDED(rv) && mCurrentContext &&
- aNameSpaceID == kNameSpaceID_None &&
- (aName == nsGkAtoms::width || aName == nsGkAtoms::height || aName == nsGkAtoms::moz_opaque))
- {
- ErrorResult dummy;
- rv = UpdateContext(nullptr, JS::NullHandleValue, dummy);
- NS_ENSURE_SUCCESS(rv, rv);
- }
+HTMLCanvasElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
+{
+ AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
- return rv;
+ return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
+ aOldValue, aNotify);
}
nsresult
-HTMLCanvasElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- bool aNotify)
+HTMLCanvasElement::OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify)
{
- nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aName, aNotify);
- if (NS_SUCCEEDED(rv) && mCurrentContext &&
- aNameSpaceID == kNameSpaceID_None &&
- (aName == nsGkAtoms::width || aName == nsGkAtoms::height || aName == nsGkAtoms::moz_opaque))
- {
+ AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
+
+ return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
+ aValue, aNotify);
+}
+
+void
+HTMLCanvasElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
+ bool aNotify)
+{
+ if (mCurrentContext && aNamespaceID == kNameSpaceID_None &&
+ (aName == nsGkAtoms::width || aName == nsGkAtoms::height ||
+ aName == nsGkAtoms::moz_opaque)) {
ErrorResult dummy;
- rv = UpdateContext(nullptr, JS::NullHandleValue, dummy);
- NS_ENSURE_SUCCESS(rv, rv);
+ UpdateContext(nullptr, JS::NullHandleValue, dummy);
}
- return rv;
}
void
@@ -574,7 +573,7 @@ HTMLCanvasElement::CopyInnerTo(Element* aDest)
return rv;
}
-nsresult HTMLCanvasElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsresult HTMLCanvasElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
if (aVisitor.mEvent->mClass == eMouseEventClass) {
WidgetMouseEventBase* evt = (WidgetMouseEventBase*)aVisitor.mEvent;
@@ -592,7 +591,7 @@ nsresult HTMLCanvasElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
aVisitor.mCanHandle = true;
}
}
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
nsChangeHint
diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h
index e77db6ff1..822f05397 100644
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -295,24 +295,11 @@ public:
nsAttrValue& aResult) override;
nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, int32_t aModType) const override;
- // SetAttr override. C++ is stupid, so have to override both
- // overloaded methods.
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
-
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- bool aNotify) override;
-
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
nsresult CopyInnerTo(mozilla::dom::Element* aDest);
- virtual nsresult PreHandleEvent(mozilla::EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ mozilla::EventChainPreVisitor& aVisitor) override;
/*
* Helpers called by various users of Canvas
@@ -372,6 +359,14 @@ protected:
nsISupports** aResult);
void CallPrintCallback();
+ virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
+ virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify) override;
+
AsyncCanvasRenderer* GetAsyncCanvasRenderer();
bool mResetLayer;
@@ -405,6 +400,18 @@ public:
CanvasContextType GetCurrentContextType() {
return mCurrentContextType;
}
+
+private:
+ /**
+ * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
+ * This function will be called by AfterSetAttr whether the attribute is being
+ * set or unset.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aNotify Whether we plan to notify document observers.
+ */
+ void AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName, bool aNotify);
};
class HTMLCanvasPrintState final : public nsWrapperCache
diff --git a/dom/html/HTMLContentElement.cpp b/dom/html/HTMLContentElement.cpp
deleted file mode 100644
index 01c0158a0..000000000
--- a/dom/html/HTMLContentElement.cpp
+++ /dev/null
@@ -1,393 +0,0 @@
-/* -*- 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/HTMLContentElement.h"
-#include "mozilla/dom/HTMLContentElementBinding.h"
-#include "mozilla/dom/HTMLUnknownElement.h"
-#include "mozilla/dom/NodeListBinding.h"
-#include "mozilla/dom/ShadowRoot.h"
-#include "mozilla/css/StyleRule.h"
-#include "nsGkAtoms.h"
-#include "nsStyleConsts.h"
-#include "nsIAtom.h"
-#include "nsCSSRuleProcessor.h"
-#include "nsRuleData.h"
-#include "nsRuleProcessorData.h"
-#include "nsRuleWalker.h"
-#include "nsCSSParser.h"
-#include "nsDocument.h"
-
-// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Content) to add check for web components
-// being enabled.
-nsGenericHTMLElement*
-NS_NewHTMLContentElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
- mozilla::dom::FromParser aFromParser)
-{
- // When this check is removed, remove the nsDocument.h and
- // HTMLUnknownElement.h includes. Also remove nsINode::IsHTMLContentElement.
- //
- // We have to jump through some hoops to be able to produce both NodeInfo* and
- // already_AddRefed<NodeInfo>& for our callees.
- RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
- if (!nsDocument::IsWebComponentsEnabled(nodeInfo)) {
- already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
- return new mozilla::dom::HTMLUnknownElement(nodeInfoArg);
- }
-
- already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
- return new mozilla::dom::HTMLContentElement(nodeInfoArg);
-}
-
-using namespace mozilla::dom;
-
-HTMLContentElement::HTMLContentElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
- : nsGenericHTMLElement(aNodeInfo), mValidSelector(true), mIsInsertionPoint(false)
-{
-}
-
-HTMLContentElement::~HTMLContentElement()
-{
-}
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLContentElement,
- nsGenericHTMLElement,
- mMatchedNodes)
-
-NS_IMPL_ADDREF_INHERITED(HTMLContentElement, Element)
-NS_IMPL_RELEASE_INHERITED(HTMLContentElement, Element)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLContentElement)
-NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
-
-NS_IMPL_ELEMENT_CLONE(HTMLContentElement)
-
-JSObject*
-HTMLContentElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
-{
- return HTMLContentElementBinding::Wrap(aCx, this, aGivenProto);
-}
-
-nsresult
-HTMLContentElement::BindToTree(nsIDocument* aDocument,
- nsIContent* aParent,
- nsIContent* aBindingParent,
- bool aCompileEventHandlers)
-{
- RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
-
- nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
- aBindingParent,
- aCompileEventHandlers);
- NS_ENSURE_SUCCESS(rv, rv);
-
- ShadowRoot* containingShadow = GetContainingShadow();
- if (containingShadow && !oldContainingShadow) {
- nsINode* parentNode = nsINode::GetParentNode();
- while (parentNode && parentNode != containingShadow) {
- if (parentNode->IsHTMLContentElement()) {
- // Content element in fallback content is not an insertion point.
- return NS_OK;
- }
- parentNode = parentNode->GetParentNode();
- }
-
- // If the content element is being inserted into a ShadowRoot,
- // add this element to the list of insertion points.
- mIsInsertionPoint = true;
- containingShadow->AddInsertionPoint(this);
- containingShadow->SetInsertionPointChanged();
- }
-
- return NS_OK;
-}
-
-void
-HTMLContentElement::UnbindFromTree(bool aDeep, bool aNullParent)
-{
- RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
-
- nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
-
- if (oldContainingShadow && !GetContainingShadow() && mIsInsertionPoint) {
- oldContainingShadow->RemoveInsertionPoint(this);
-
- // Remove all the matched nodes now that the
- // insertion point is no longer an insertion point.
- ClearMatchedNodes();
- oldContainingShadow->SetInsertionPointChanged();
-
- mIsInsertionPoint = false;
- }
-}
-
-void
-HTMLContentElement::AppendMatchedNode(nsIContent* aContent)
-{
- mMatchedNodes.AppendElement(aContent);
- nsTArray<nsIContent*>& destInsertionPoint = aContent->DestInsertionPoints();
- destInsertionPoint.AppendElement(this);
-
- if (mMatchedNodes.Length() == 1) {
- // Fallback content gets dropped so we need to updated fallback
- // content distribution.
- UpdateFallbackDistribution();
- }
-}
-
-void
-HTMLContentElement::UpdateFallbackDistribution()
-{
- for (nsIContent* child = nsINode::GetFirstChild();
- child;
- child = child->GetNextSibling()) {
- nsTArray<nsIContent*>& destInsertionPoint = child->DestInsertionPoints();
- destInsertionPoint.Clear();
- if (mMatchedNodes.IsEmpty()) {
- destInsertionPoint.AppendElement(this);
- }
- }
-}
-
-void
-HTMLContentElement::RemoveMatchedNode(nsIContent* aContent)
-{
- mMatchedNodes.RemoveElement(aContent);
- ShadowRoot::RemoveDestInsertionPoint(this, aContent->DestInsertionPoints());
-
- if (mMatchedNodes.IsEmpty()) {
- // Fallback content is activated so we need to update fallback
- // content distribution.
- UpdateFallbackDistribution();
- }
-}
-
-void
-HTMLContentElement::InsertMatchedNode(uint32_t aIndex, nsIContent* aContent)
-{
- mMatchedNodes.InsertElementAt(aIndex, aContent);
- nsTArray<nsIContent*>& destInsertionPoint = aContent->DestInsertionPoints();
- destInsertionPoint.AppendElement(this);
-
- if (mMatchedNodes.Length() == 1) {
- // Fallback content gets dropped so we need to updated fallback
- // content distribution.
- UpdateFallbackDistribution();
- }
-}
-
-void
-HTMLContentElement::ClearMatchedNodes()
-{
- for (uint32_t i = 0; i < mMatchedNodes.Length(); i++) {
- ShadowRoot::RemoveDestInsertionPoint(this, mMatchedNodes[i]->DestInsertionPoints());
- }
-
- mMatchedNodes.Clear();
-
- UpdateFallbackDistribution();
-}
-
-static bool
-IsValidContentSelectors(nsCSSSelector* aSelector)
-{
- nsCSSSelector* currentSelector = aSelector;
- while (currentSelector) {
- // Blacklist invalid selector fragments.
- if (currentSelector->IsPseudoElement() ||
- currentSelector->mPseudoClassList ||
- currentSelector->mNegations ||
- currentSelector->mOperator) {
- return false;
- }
-
- currentSelector = currentSelector->mNext;
- }
-
- return true;
-}
-
-nsresult
-HTMLContentElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
-{
- nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
- aValue, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::select) {
- // Select attribute was updated, the insertion point may match different
- // elements.
- nsIDocument* doc = OwnerDoc();
- nsCSSParser parser(doc->CSSLoader());
-
- mValidSelector = true;
- mSelectorList = nullptr;
-
- nsresult rv = parser.ParseSelectorString(aValue,
- doc->GetDocumentURI(),
- // Bug 11240
- 0, // XXX get the line number!
- getter_Transfers(mSelectorList));
-
- // We don't want to return an exception if parsing failed because
- // the spec does not define it as an exception case.
- if (NS_SUCCEEDED(rv)) {
- // Ensure that all the selectors are valid
- nsCSSSelectorList* selectors = mSelectorList;
- while (selectors) {
- if (!IsValidContentSelectors(selectors->mSelectors)) {
- // If we have an invalid selector, we can not match anything.
- mValidSelector = false;
- mSelectorList = nullptr;
- break;
- }
- selectors = selectors->mNext;
- }
- }
-
- ShadowRoot* containingShadow = GetContainingShadow();
- if (containingShadow) {
- containingShadow->DistributeAllNodes();
- }
- }
-
- return NS_OK;
-}
-
-nsresult
-HTMLContentElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify)
-{
- nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID,
- aAttribute, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::select) {
- // The select attribute was removed. This insertion point becomes
- // a universal selector.
- mValidSelector = true;
- mSelectorList = nullptr;
-
- ShadowRoot* containingShadow = GetContainingShadow();
- if (containingShadow) {
- containingShadow->DistributeAllNodes();
- }
- }
-
- return NS_OK;
-}
-
-bool
-HTMLContentElement::Match(nsIContent* aContent)
-{
- if (!mValidSelector) {
- return false;
- }
-
- if (mSelectorList) {
- nsIDocument* doc = OwnerDoc();
- ShadowRoot* containingShadow = GetContainingShadow();
- nsIContent* host = containingShadow->GetHost();
-
- TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited,
- doc, TreeMatchContext::eNeverMatchVisited);
- doc->FlushPendingLinkUpdates();
- matchingContext.SetHasSpecifiedScope();
- matchingContext.AddScopeElement(host->AsElement());
-
- if (!aContent->IsElement()) {
- return false;
- }
-
- return nsCSSRuleProcessor::SelectorListMatches(aContent->AsElement(),
- matchingContext,
- mSelectorList);
- }
-
- return true;
-}
-
-already_AddRefed<DistributedContentList>
-HTMLContentElement::GetDistributedNodes()
-{
- RefPtr<DistributedContentList> list = new DistributedContentList(this);
- return list.forget();
-}
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DistributedContentList, mParent,
- mDistributedNodes)
-
-NS_INTERFACE_TABLE_HEAD(DistributedContentList)
- NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
- NS_INTERFACE_TABLE(DistributedContentList, nsINodeList, nsIDOMNodeList)
- NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(DistributedContentList)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(DistributedContentList)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(DistributedContentList)
-
-DistributedContentList::DistributedContentList(HTMLContentElement* aHostElement)
- : mParent(aHostElement)
-{
- MOZ_COUNT_CTOR(DistributedContentList);
-
- if (aHostElement->IsInsertionPoint()) {
- if (aHostElement->MatchedNodes().IsEmpty()) {
- // Fallback content.
- nsINode* contentNode = aHostElement;
- for (nsIContent* content = contentNode->GetFirstChild();
- content;
- content = content->GetNextSibling()) {
- mDistributedNodes.AppendElement(content);
- }
- } else {
- mDistributedNodes.AppendElements(aHostElement->MatchedNodes());
- }
- }
-}
-
-DistributedContentList::~DistributedContentList()
-{
- MOZ_COUNT_DTOR(DistributedContentList);
-}
-
-nsIContent*
-DistributedContentList::Item(uint32_t aIndex)
-{
- return mDistributedNodes.SafeElementAt(aIndex);
-}
-
-NS_IMETHODIMP
-DistributedContentList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
-{
- nsIContent* item = Item(aIndex);
- if (!item) {
- return NS_ERROR_FAILURE;
- }
-
- return CallQueryInterface(item, aReturn);
-}
-
-NS_IMETHODIMP
-DistributedContentList::GetLength(uint32_t* aLength)
-{
- *aLength = mDistributedNodes.Length();
- return NS_OK;
-}
-
-int32_t
-DistributedContentList::IndexOf(nsIContent* aContent)
-{
- return mDistributedNodes.IndexOf(aContent);
-}
-
-JSObject*
-DistributedContentList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
- return NodeListBinding::Wrap(aCx, this, aGivenProto);
-}
-
diff --git a/dom/html/HTMLContentElement.h b/dom/html/HTMLContentElement.h
deleted file mode 100644
index f019e56cd..000000000
--- a/dom/html/HTMLContentElement.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/* -*- 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 mozilla_dom_HTMLContentElement_h__
-#define mozilla_dom_HTMLContentElement_h__
-
-#include "nsAutoPtr.h"
-#include "nsINodeList.h"
-#include "nsGenericHTMLElement.h"
-
-struct nsCSSSelectorList;
-
-namespace mozilla {
-namespace dom {
-
-class DistributedContentList;
-
-class HTMLContentElement final : public nsGenericHTMLElement
-{
-public:
- explicit HTMLContentElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
-
- // nsISupports
- NS_DECL_ISUPPORTS_INHERITED
-
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLContentElement,
- nsGenericHTMLElement)
-
- static HTMLContentElement* FromContent(nsIContent* aContent)
- {
- if (aContent->IsHTMLContentElement()) {
- return static_cast<HTMLContentElement*>(aContent);
- }
-
- return nullptr;
- }
-
- virtual bool IsHTMLContentElement() const override { return true; }
-
- virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
-
- virtual nsIDOMNode* AsDOMNode() override { return this; }
-
- virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
- nsIContent* aBindingParent,
- bool aCompileEventHandlers) override;
-
- virtual void UnbindFromTree(bool aDeep = true,
- bool aNullParent = true) override;
-
- /**
- * Returns whether if the selector of this insertion point
- * matches the provided content.
- */
- bool Match(nsIContent* aContent);
- bool IsInsertionPoint() const { return mIsInsertionPoint; }
- nsCOMArray<nsIContent>& MatchedNodes() { return mMatchedNodes; }
- void AppendMatchedNode(nsIContent* aContent);
- void RemoveMatchedNode(nsIContent* aContent);
- void InsertMatchedNode(uint32_t aIndex, nsIContent* aContent);
- void ClearMatchedNodes();
-
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
-
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify) override;
-
- // WebIDL methods.
- already_AddRefed<DistributedContentList> GetDistributedNodes();
- void GetSelect(nsAString& aSelect)
- {
- Element::GetAttr(kNameSpaceID_None, nsGkAtoms::select, aSelect);
- }
- void SetSelect(const nsAString& aSelect)
- {
- Element::SetAttr(kNameSpaceID_None, nsGkAtoms::select, aSelect, true);
- }
-
-protected:
- virtual ~HTMLContentElement();
-
- virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
-
- /**
- * Updates the destination insertion points of the fallback
- * content of this insertion point. If there are nodes matched
- * to this insertion point, then destination insertion points
- * of fallback are cleared, otherwise, this insertion point
- * is a destination insertion point.
- */
- void UpdateFallbackDistribution();
-
- /**
- * An array of nodes from the ShadowRoot host that match the
- * content insertion selector.
- */
- nsCOMArray<nsIContent> mMatchedNodes;
-
- nsAutoPtr<nsCSSSelectorList> mSelectorList;
- bool mValidSelector;
- bool mIsInsertionPoint;
-};
-
-class DistributedContentList : public nsINodeList
-{
-public:
- explicit DistributedContentList(HTMLContentElement* aHostElement);
-
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DistributedContentList)
-
- // nsIDOMNodeList
- NS_DECL_NSIDOMNODELIST
-
- // nsINodeList
- virtual nsIContent* Item(uint32_t aIndex) override;
- virtual int32_t IndexOf(nsIContent* aContent) override;
- virtual nsINode* GetParentObject() override { return mParent; }
- virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-protected:
- virtual ~DistributedContentList();
- RefPtr<HTMLContentElement> mParent;
- nsCOMArray<nsIContent> mDistributedNodes;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_HTMLContentElement_h__
-
diff --git a/dom/html/HTMLDetailsElement.cpp b/dom/html/HTMLDetailsElement.cpp
index 8619b1450..9d4dd89c2 100644
--- a/dom/html/HTMLDetailsElement.cpp
+++ b/dom/html/HTMLDetailsElement.cpp
@@ -45,7 +45,7 @@ HTMLDetailsElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
nsresult
HTMLDetailsElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue, bool aNotify)
+ const nsAttrValueOrString* aValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::open) {
bool setOpen = aValue != nullptr;
diff --git a/dom/html/HTMLDetailsElement.h b/dom/html/HTMLDetailsElement.h
index 6adf567bf..4575ed888 100644
--- a/dom/html/HTMLDetailsElement.h
+++ b/dom/html/HTMLDetailsElement.h
@@ -38,7 +38,8 @@ public:
int32_t aModType) const override;
nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue, bool aNotify) override;
+ const nsAttrValueOrString* aValue,
+ bool aNotify) override;
// HTMLDetailsElement WebIDL
bool Open() const { return GetBoolAttr(nsGkAtoms::open); }
diff --git a/dom/html/HTMLFieldSetElement.cpp b/dom/html/HTMLFieldSetElement.cpp
index d72fd1061..f546cad5b 100644
--- a/dom/html/HTMLFieldSetElement.cpp
+++ b/dom/html/HTMLFieldSetElement.cpp
@@ -70,7 +70,7 @@ HTMLFieldSetElement::IsDisabledForEvents(EventMessage aMessage)
// nsIContent
nsresult
-HTMLFieldSetElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLFieldSetElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
// Do not process any DOM events if the element is disabled.
aVisitor.mCanHandle = false;
@@ -78,12 +78,13 @@ HTMLFieldSetElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
return NS_OK;
}
- return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLFormElement::GetEventTargetParent(aVisitor);
}
nsresult
HTMLFieldSetElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::disabled &&
nsINode::GetFirstChild()) {
@@ -100,7 +101,7 @@ HTMLFieldSetElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
// nsIDOMHTMLFieldSetElement
diff --git a/dom/html/HTMLFieldSetElement.h b/dom/html/HTMLFieldSetElement.h
index 96fff4582..2c0e9cc14 100644
--- a/dom/html/HTMLFieldSetElement.h
+++ b/dom/html/HTMLFieldSetElement.h
@@ -40,9 +40,12 @@ public:
NS_DECL_NSIDOMHTMLFIELDSETELEMENT
// nsIContent
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual nsresult InsertChildAt(nsIContent* aChild, uint32_t aIndex,
bool aNotify) override;
diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp
index 6bea19a2b..58cba6863 100644
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -189,32 +189,37 @@ HTMLFormElement::GetElements(nsIDOMHTMLCollection** aElements)
}
nsresult
-HTMLFormElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
-{
- if ((aName == nsGkAtoms::action || aName == nsGkAtoms::target) &&
- aNameSpaceID == kNameSpaceID_None) {
- if (mPendingSubmission) {
- // aha, there is a pending submission that means we're in
- // the script and we need to flush it. let's tell it
- // that the event was ignored to force the flush.
- // the second argument is not playing a role at all.
- FlushPendingSubmission();
+HTMLFormElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue, bool aNotify)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::action || aName == nsGkAtoms::target) {
+ // This check is mostly to preserve previous behavior.
+ if (aValue) {
+ if (mPendingSubmission) {
+ // aha, there is a pending submission that means we're in
+ // the script and we need to flush it. let's tell it
+ // that the event was ignored to force the flush.
+ // the second argument is not playing a role at all.
+ FlushPendingSubmission();
+ }
+ // Don't forget we've notified the password manager already if the
+ // page sets the action/target in the during submit. (bug 343182)
+ bool notifiedObservers = mNotifiedObservers;
+ ForgetCurrentSubmission();
+ mNotifiedObservers = notifiedObservers;
+ }
}
- // Don't forget we've notified the password manager already if the
- // page sets the action/target in the during submit. (bug 343182)
- bool notifiedObservers = mNotifiedObservers;
- ForgetCurrentSubmission();
- mNotifiedObservers = notifiedObservers;
}
- return nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
- aNotify);
+
+ return nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName, aValue,
+ aNotify);
}
nsresult
HTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aName == nsGkAtoms::novalidate && aNameSpaceID == kNameSpaceID_None) {
// Update all form elements states because they might be [no longer]
@@ -230,7 +235,8 @@ HTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
}
- return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, aNotify);
+ return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
+ aOldValue, aNotify);
}
NS_IMPL_STRING_ATTR(HTMLFormElement, AcceptCharset, acceptcharset)
@@ -489,7 +495,7 @@ HTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
}
nsresult
-HTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLFormElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mWantsWillHandleEvent = true;
if (aVisitor.mEvent->mOriginalTarget == static_cast<nsIContent*>(this)) {
@@ -513,7 +519,7 @@ HTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
mGeneratingReset = true;
}
}
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
nsresult
diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h
index b3e836f5f..f06db4b51 100644
--- a/dom/html/HTMLFormElement.h
+++ b/dom/html/HTMLFormElement.h
@@ -93,7 +93,8 @@ public:
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult) override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult WillHandleEvent(
EventChainPostVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
@@ -104,16 +105,13 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
+ virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
/**
* Forget all information about the current submission (and the fact that we
diff --git a/dom/html/HTMLFrameSetElement.cpp b/dom/html/HTMLFrameSetElement.cpp
index 6d39caa19..861dbfe9f 100644
--- a/dom/html/HTMLFrameSetElement.cpp
+++ b/dom/html/HTMLFrameSetElement.cpp
@@ -9,6 +9,7 @@
#include "mozilla/dom/EventHandlerBinding.h"
#include "nsGlobalWindow.h"
#include "mozilla/UniquePtrExtensions.h"
+#include "nsAttrValueOrString.h"
NS_IMPL_NS_NEW_HTML_ELEMENT(FrameSet)
@@ -65,43 +66,45 @@ HTMLFrameSetElement::GetRows(nsAString& aRows)
}
nsresult
-HTMLFrameSetElement::SetAttr(int32_t aNameSpaceID,
- nsIAtom* aAttribute,
- nsIAtom* aPrefix,
- const nsAString& aValue,
- bool aNotify)
+HTMLFrameSetElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify)
{
- nsresult rv;
/* The main goal here is to see whether the _number_ of rows or
- * columns has changed. If it has, we need to reframe; otherwise
- * we want to reflow. So we set mCurrentRowColHint here, then call
- * nsGenericHTMLElement::SetAttr, which will end up calling
- * GetAttributeChangeHint and notifying layout with that hint.
- * Once nsGenericHTMLElement::SetAttr returns, we want to go back to our
- * normal hint, which is NS_STYLE_HINT_REFLOW.
+ * columns has changed. If it has, we need to reframe; otherwise
+ * we want to reflow.
+ * Ideally, the style hint would be changed back to reflow after the reframe
+ * has been performed. Unfortunately, however, the reframe will be performed
+ * by the call to nsNodeUtils::AttributeChanged, which occurs *after*
+ * AfterSetAttr is called, leaving us with no convenient way of changing the
+ * value back to reflow afterwards. However, nsNodeUtils::AttributeChanged is
+ * effectively the only consumer of this value, so as long as we always set
+ * the value correctly here, we should be fine.
*/
- if (aAttribute == nsGkAtoms::rows && aNameSpaceID == kNameSpaceID_None) {
- int32_t oldRows = mNumRows;
- ParseRowCol(aValue, mNumRows, &mRowSpecs);
+ mCurrentRowColHint = NS_STYLE_HINT_REFLOW;
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::rows) {
+ if (aValue) {
+ int32_t oldRows = mNumRows;
+ ParseRowCol(aValue->String(), mNumRows, &mRowSpecs);
- if (mNumRows != oldRows) {
- mCurrentRowColHint = nsChangeHint_ReconstructFrame;
- }
- } else if (aAttribute == nsGkAtoms::cols &&
- aNameSpaceID == kNameSpaceID_None) {
- int32_t oldCols = mNumCols;
- ParseRowCol(aValue, mNumCols, &mColSpecs);
+ if (mNumRows != oldRows) {
+ mCurrentRowColHint = nsChangeHint_ReconstructFrame;
+ }
+ }
+ } else if (aName == nsGkAtoms::cols) {
+ if (aValue) {
+ int32_t oldCols = mNumCols;
+ ParseRowCol(aValue->String(), mNumCols, &mColSpecs);
- if (mNumCols != oldCols) {
- mCurrentRowColHint = nsChangeHint_ReconstructFrame;
+ if (mNumCols != oldCols) {
+ mCurrentRowColHint = nsChangeHint_ReconstructFrame;
+ }
+ }
}
}
- rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aAttribute, aPrefix,
- aValue, aNotify);
- mCurrentRowColHint = NS_STYLE_HINT_REFLOW;
-
- return rv;
+ return nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName, aValue, aNotify);
}
nsresult
diff --git a/dom/html/HTMLFrameSetElement.h b/dom/html/HTMLFrameSetElement.h
index b6bbe5d95..fe3bc2341 100644
--- a/dom/html/HTMLFrameSetElement.h
+++ b/dom/html/HTMLFrameSetElement.h
@@ -100,17 +100,6 @@ public:
#undef WINDOW_EVENT_HELPER
#undef EVENT
- // These override the SetAttr methods in nsGenericHTMLElement (need
- // both here to silence compiler warnings).
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
-
/**
* GetRowSpec is used to get the "rows" spec.
* @param out int32_t aNumValues The number of row sizes specified.
@@ -143,6 +132,10 @@ protected:
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
+ virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify) override;
+
private:
nsresult ParseRowCol(const nsAString& aValue,
int32_t& aNumSpecs,
diff --git a/dom/html/HTMLIFrameElement.cpp b/dom/html/HTMLIFrameElement.cpp
index 0d5a209c0..2b66cbd26 100644
--- a/dom/html/HTMLIFrameElement.cpp
+++ b/dom/html/HTMLIFrameElement.cpp
@@ -182,54 +182,49 @@ HTMLIFrameElement::GetAttributeMappingFunction() const
}
nsresult
-HTMLIFrameElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
-{
- nsresult rv = nsGenericHTMLFrameElement::SetAttr(aNameSpaceID, aName,
- aPrefix, aValue, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::srcdoc) {
- // Don't propagate error here. The attribute was successfully set, that's
- // what we should reflect.
- LoadSrc();
- }
-
- return NS_OK;
-}
-
-nsresult
HTMLIFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
- bool aNotify)
+ const nsAttrValue* aOldValue, bool aNotify)
{
- if (aName == nsGkAtoms::sandbox &&
- aNameSpaceID == kNameSpaceID_None && mFrameLoader) {
- // If we have an nsFrameLoader, apply the new sandbox flags.
- // Since this is called after the setter, the sandbox flags have
- // alreay been updated.
- mFrameLoader->ApplySandboxFlags(GetSandboxFlags());
+ AfterMaybeChangeAttr(aNameSpaceID, aName, aNotify);
+
+ if (aNameSpaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::sandbox) {
+ if (mFrameLoader) {
+ // If we have an nsFrameLoader, apply the new sandbox flags.
+ // Since this is called after the setter, the sandbox flags have
+ // alreay been updated.
+ mFrameLoader->ApplySandboxFlags(GetSandboxFlags());
+ }
+ }
}
return nsGenericHTMLFrameElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
nsresult
-HTMLIFrameElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify)
+HTMLIFrameElement::OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify)
{
- // Invoke on the superclass.
- nsresult rv = nsGenericHTMLFrameElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (aNameSpaceID == kNameSpaceID_None &&
- aAttribute == nsGkAtoms::srcdoc) {
- // Fall back to the src attribute, if any
- LoadSrc();
- }
+ AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
+
+ return nsGenericHTMLFrameElement::OnAttrSetButNotChanged(aNamespaceID, aName,
+ aValue, aNotify);
+}
- return NS_OK;
+void
+HTMLIFrameElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
+ nsIAtom* aName,
+ bool aNotify)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::srcdoc) {
+ // Don't propagate errors from LoadSrc. The attribute was successfully
+ // set/unset, that's what we should reflect.
+ LoadSrc();
+ }
+ }
}
uint32_t
diff --git a/dom/html/HTMLIFrameElement.h b/dom/html/HTMLIFrameElement.h
index 5bfda2470..e94ae0bad 100644
--- a/dom/html/HTMLIFrameElement.h
+++ b/dom/html/HTMLIFrameElement.h
@@ -46,20 +46,6 @@ public:
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
- virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue,
- bool aNotify) override;
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify) override;
-
uint32_t GetSandboxFlags();
// Web IDL binding methods
@@ -196,11 +182,30 @@ protected:
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+ virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
+ virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify) override;
+
private:
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
nsRuleData* aData);
static const DOMTokenListSupportedToken sSupportedSandboxTokens[];
+
+ /**
+ * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
+ * This function will be called by AfterSetAttr whether the attribute is being
+ * set or unset.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aNotify Whether we plan to notify document observers.
+ */
+ void AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName, bool aNotify);
};
} // namespace dom
diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp
index fab1cdef4..444c352e2 100644
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -112,6 +112,7 @@ private:
HTMLImageElement::HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo)
, mForm(nullptr)
+ , mForceReload(false)
, mInDocResponsiveContent(false)
, mCurrentDensity(1.0)
{
@@ -369,9 +370,12 @@ HTMLImageElement::GetAttributeMappingFunction() const
nsresult
HTMLImageElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify)
{
+ if (aValue) {
+ BeforeMaybeChangeAttr(aNameSpaceID, aName, *aValue, aNotify);
+ }
if (aNameSpaceID == kNameSpaceID_None && mForm &&
(aName == nsGkAtoms::name || aName == nsGkAtoms::id)) {
@@ -391,8 +395,13 @@ HTMLImageElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsresult
HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
+ if (aValue) {
+ AfterMaybeChangeAttr(aNameSpaceID, aName, aNotify);
+ }
+
if (aNameSpaceID == kNameSpaceID_None && mForm &&
(aName == nsGkAtoms::name || aName == nsGkAtoms::id) &&
aValue && !aValue->IsEmptyString()) {
@@ -433,67 +442,26 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
nsresult
-HTMLImageElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLImageElement::OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify)
{
- // We handle image element with attribute ismap in its corresponding frame
- // element. Set mMultipleActionsPrevented here to prevent the click event
- // trigger the behaviors in Element::PostHandleEventForLinks
- WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
- if (mouseEvent && mouseEvent->IsLeftClickEvent() && IsMap()) {
- mouseEvent->mFlags.mMultipleActionsPrevented = true;
- }
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
-}
-
-bool
-HTMLImageElement::IsHTMLFocusable(bool aWithMouse,
- bool *aIsFocusable, int32_t *aTabIndex)
-{
- int32_t tabIndex = TabIndex();
-
- if (IsInUncomposedDoc()) {
- nsAutoString usemap;
- GetUseMap(usemap);
- // XXXbz which document should this be using? sXBL/XBL2 issue! I
- // think that OwnerDoc() is right, since we don't want to
- // assume stuff about the document we're bound to.
- if (OwnerDoc()->FindImageMap(usemap)) {
- if (aTabIndex) {
- // Use tab index on individual map areas
- *aTabIndex = (sTabFocusModel & eTabFocus_linksMask)? 0 : -1;
- }
- // Image map is not focusable itself, but flag as tabbable
- // so that image map areas get walked into.
- *aIsFocusable = false;
-
- return false;
- }
- }
-
- if (aTabIndex) {
- // Can be in tab order if tabindex >=0 and form controls are tabbable.
- *aTabIndex = (sTabFocusModel & eTabFocus_formElementsMask)? tabIndex : -1;
- }
+ BeforeMaybeChangeAttr(aNamespaceID, aName, aValue, aNotify);
+ AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
- *aIsFocusable =
-#ifdef XP_MACOSX
- (!aWithMouse || nsFocusManager::sMouseFocusesFormControl) &&
-#endif
- (tabIndex >= 0 || HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex));
-
- return false;
+ return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
+ aValue, aNotify);
}
-nsresult
-HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
+void
+HTMLImageElement::BeforeMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify)
{
- bool forceReload = false;
// We need to force our image to reload. This must be done here, not in
// AfterSetAttr or BeforeSetAttr, because we want to do it even if the attr is
// being set to its existing value, which is normally optimized away as a
@@ -504,16 +472,19 @@ HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
// spec.
//
// Both cases handle unsetting src in AfterSetAttr
- if (aNameSpaceID == kNameSpaceID_None &&
+ //
+ // Much of this should probably happen in AfterMaybeChangeAttr.
+ // See Bug 1370705
+ if (aNamespaceID == kNameSpaceID_None &&
aName == nsGkAtoms::src) {
if (InResponsiveMode()) {
if (mResponsiveSelector &&
mResponsiveSelector->Content() == this) {
- mResponsiveSelector->SetDefaultSource(aValue);
+ mResponsiveSelector->SetDefaultSource(aValue.String());
}
QueueImageLoadTask(true);
- } else if (aNotify) {
+ } else if (aNotify && OwnerDoc()->IsCurrentActiveDocument()) {
// If aNotify is false, we are coming from the parser or some such place;
// we'll get bound after all the attributes have been set, so we'll do the
// sync image load from BindToTree. Skip the LoadImage call in that case.
@@ -528,23 +499,23 @@ HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
// the state gets in Element's attr-setting happen around this
// LoadImage call, we could start passing false instead of aNotify
// here.
- LoadImage(aValue, true, aNotify, eImageLoadType_Normal);
+ LoadImage(aValue.String(), true, aNotify, eImageLoadType_Normal);
mNewRequestsWillNeedAnimationReset = false;
}
- } else if (aNameSpaceID == kNameSpaceID_None &&
+ } else if (aNamespaceID == kNameSpaceID_None &&
aName == nsGkAtoms::crossorigin &&
aNotify) {
nsAttrValue attrValue;
- ParseCORSValue(aValue, attrValue);
+ ParseCORSValue(aValue.String(), attrValue);
if (GetCORSMode() != AttrValueToCORSMode(&attrValue)) {
// Force a new load of the image with the new cross origin policy.
- forceReload = true;
+ mForceReload = true;
}
} else if (aName == nsGkAtoms::referrerpolicy &&
- aNameSpaceID == kNameSpaceID_None &&
+ aNamespaceID == kNameSpaceID_None &&
aNotify) {
- ReferrerPolicy referrerPolicy = AttributeReferrerPolicyFromString(aValue);
+ ReferrerPolicy referrerPolicy = AttributeReferrerPolicyFromString(aValue.String());
if (!InResponsiveMode() &&
referrerPolicy != RP_Unset &&
referrerPolicy != GetImageReferrerPolicy()) {
@@ -553,22 +524,28 @@ HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
// the attribute will neither trigger a reload nor update the referrer
// policy of the loading channel (whether it has previously completed or
// not). Force a new load of the image with the new referrerpolicy.
- forceReload = true;
+ mForceReload = true;
}
}
- nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
- aValue, aNotify);
+ return;
+}
+void
+HTMLImageElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
+ bool aNotify)
+{
// Because we load image synchronously in non-responsive-mode, we need to do
// reload after the attribute has been set if the reload is triggerred by
// cross origin changing.
- if (forceReload) {
+ if (mForceReload) {
+ mForceReload = false;
+
if (InResponsiveMode()) {
// per spec, full selection runs when this changes, even though
// it doesn't directly affect the source selection
QueueImageLoadTask(true);
- } else {
+ } else if (OwnerDoc()->IsCurrentActiveDocument()) {
// Bug 1076583 - We still use the older synchronous algorithm in
// non-responsive mode. Force a new load of the image with the
// new cross origin policy
@@ -576,7 +553,59 @@ HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
}
- return rv;
+ return;
+}
+
+nsresult
+HTMLImageElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
+{
+ // We handle image element with attribute ismap in its corresponding frame
+ // element. Set mMultipleActionsPrevented here to prevent the click event
+ // trigger the behaviors in Element::PostHandleEventForLinks
+ WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
+ if (mouseEvent && mouseEvent->IsLeftClickEvent() && IsMap()) {
+ mouseEvent->mFlags.mMultipleActionsPrevented = true;
+ }
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
+}
+
+bool
+HTMLImageElement::IsHTMLFocusable(bool aWithMouse,
+ bool *aIsFocusable, int32_t *aTabIndex)
+{
+ int32_t tabIndex = TabIndex();
+
+ if (IsInUncomposedDoc()) {
+ nsAutoString usemap;
+ GetUseMap(usemap);
+ // XXXbz which document should this be using? sXBL/XBL2 issue! I
+ // think that OwnerDoc() is right, since we don't want to
+ // assume stuff about the document we're bound to.
+ if (OwnerDoc()->FindImageMap(usemap)) {
+ if (aTabIndex) {
+ // Use tab index on individual map areas
+ *aTabIndex = (sTabFocusModel & eTabFocus_linksMask)? 0 : -1;
+ }
+ // Image map is not focusable itself, but flag as tabbable
+ // so that image map areas get walked into.
+ *aIsFocusable = false;
+
+ return false;
+ }
+ }
+
+ if (aTabIndex) {
+ // Can be in tab order if tabindex >=0 and form controls are tabbable.
+ *aTabIndex = (sTabFocusModel & eTabFocus_formElementsMask)? tabIndex : -1;
+ }
+
+ *aIsFocusable =
+#ifdef XP_MACOSX
+ (!aWithMouse || nsFocusManager::sMouseFocusesFormControl) &&
+#endif
+ (tabIndex >= 0 || HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex));
+
+ return false;
}
nsresult
diff --git a/dom/html/HTMLImageElement.h b/dom/html/HTMLImageElement.h
index 62323e801..bb4a09882 100644
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -70,21 +70,11 @@ public:
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
- // SetAttr override. C++ is stupid, so have to override both
- // overloaded methods.
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
-
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
@@ -343,11 +333,17 @@ protected:
void UpdateFormOwner();
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
+
+ virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify) override;
// This is a weak reference that this element and the HTMLFormElement
// cooperate in maintaining.
@@ -362,6 +358,36 @@ private:
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
nsRuleData* aData);
+ /**
+ * This function is called by BeforeSetAttr and OnAttrSetButNotChanged.
+ * It will not be called if the value is being unset.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aValue the value it's being set to represented as either a string or
+ * a parsed nsAttrValue.
+ * @param aNotify Whether we plan to notify document observers.
+ */
+ void BeforeMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify);
+ /**
+ * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
+ * It will not be called if the value is being unset.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aNotify Whether we plan to notify document observers.
+ */
+ void AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
+ bool aNotify);
+ /**
+ * Used by BeforeMaybeChangeAttr and AfterMaybeChangeAttr to keep track of
+ * whether a reload needs to be forced after an attribute change that is
+ * currently in progress.
+ */
+ bool mForceReload;
+
bool mInDocResponsiveContent;
RefPtr<ImageLoadTask> mPendingImageLoadTask;
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index 0b879bb9b..7708a60ac 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -147,6 +147,8 @@ namespace dom {
#define NS_CONTROL_TYPE(bits) ((bits) & ~( \
NS_OUTER_ACTIVATE_EVENT | NS_ORIGINAL_CHECKED_VALUE | NS_NO_CONTENT_DISPATCH | \
NS_ORIGINAL_INDETERMINATE_VALUE))
+#define NS_PRE_HANDLE_BLUR_EVENT (1 << 13)
+#define NS_PRE_HANDLE_INPUT_EVENT (1 << 14)
// whether textfields should be selected once focused:
// -1: no, 1: yes, 0: uninitialized
@@ -172,15 +174,18 @@ static const nsAttrValue::EnumTable kInputTypeTable[] = {
{ "search", NS_FORM_INPUT_SEARCH },
{ "submit", NS_FORM_INPUT_SUBMIT },
{ "tel", NS_FORM_INPUT_TEL },
- { "text", NS_FORM_INPUT_TEXT },
{ "time", NS_FORM_INPUT_TIME },
{ "url", NS_FORM_INPUT_URL },
{ "week", NS_FORM_INPUT_WEEK },
+ // "text" must be last for ParseAttribute to work right. If you add things
+ // before it, please update kInputDefaultType.
+ { "text", NS_FORM_INPUT_TEXT },
{ nullptr, 0 }
};
// Default type is 'text'.
-static const nsAttrValue::EnumTable* kInputDefaultType = &kInputTypeTable[18];
+static const nsAttrValue::EnumTable* kInputDefaultType =
+ &kInputTypeTable[ArrayLength(kInputTypeTable) - 2];
static const uint8_t NS_INPUT_INPUTMODE_AUTO = 0;
static const uint8_t NS_INPUT_INPUTMODE_NUMERIC = 1;
@@ -1235,7 +1240,7 @@ HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) co
nsresult
HTMLInputElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
@@ -1259,10 +1264,6 @@ HTMLInputElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
} else if (aNotify && aName == nsGkAtoms::disabled) {
mDisabledChanged = true;
- } else if (aName == nsGkAtoms::dir &&
- AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
- nsGkAtoms::_auto, eIgnoreCase)) {
- SetDirectionIfAuto(false, aNotify);
} else if (mType == NS_FORM_INPUT_RADIO && aName == nsGkAtoms::required) {
nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
@@ -1282,7 +1283,8 @@ HTMLInputElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsresult
HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
//
@@ -1322,36 +1324,15 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
if (aName == nsGkAtoms::type) {
+ uint8_t newType;
if (!aValue) {
- // We're now a text input. Note that we have to handle this manually,
- // since removing an attribute (which is what happened, since aValue is
- // null) doesn't call ParseAttribute.
- HandleTypeChange(kInputDefaultType->value);
- }
-
- UpdateBarredFromConstraintValidation();
-
- if (mType != NS_FORM_INPUT_IMAGE) {
- // We're no longer an image input. Cancel our image requests, if we have
- // any. Note that doing this when we already weren't an image is ok --
- // just does nothing.
- CancelImageRequests(aNotify);
- } else if (aNotify) {
- // We just got switched to be an image input; we should see
- // whether we have an image to load;
- nsAutoString src;
- if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
- LoadImage(src, false, aNotify, eImageLoadType_Normal);
- }
+ // We're now a text input.
+ newType = kInputDefaultType->value;
+ } else {
+ newType = aValue->GetEnumValue();
}
-
- if (mType == NS_FORM_INPUT_PASSWORD && IsInComposedDoc()) {
- AsyncEventDispatcher* dispatcher =
- new AsyncEventDispatcher(this,
- NS_LITERAL_STRING("DOMInputPasswordAdded"),
- true,
- true);
- dispatcher->PostDOMEvent();
+ if (newType != mType) {
+ HandleTypeChange(newType, aNotify);
}
}
@@ -1434,7 +1415,7 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
"HTML5 spec does not allow underflow for type=range");
} else if (aName == nsGkAtoms::dir &&
aValue && aValue->Equals(nsGkAtoms::_auto, eIgnoreCase)) {
- SetDirectionIfAuto(true, aNotify);
+ SetDirectionFromValue(aNotify);
} else if (aName == nsGkAtoms::lang) {
if (mType == NS_FORM_INPUT_NUMBER) {
// Update the value that is displayed to the user to the new locale:
@@ -1450,12 +1431,11 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
// Clear the cached @autocomplete attribute state.
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
}
-
- UpdateState(aNotify);
}
return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue,
+ aNotify);
}
// nsIDOMHTMLInputElement
@@ -3738,7 +3718,7 @@ HTMLInputElement::IsDisabledForEvents(EventMessage aMessage)
}
nsresult
-HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLInputElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
// Do not process any DOM events if the element is disabled
aVisitor.mCanHandle = false;
@@ -3755,7 +3735,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
//FIXME Allow submission etc. also when there is no prescontext, Bug 329509.
if (!aVisitor.mPresContext) {
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
}
//
// Web pages expect the value of a radio button or checkbox to be set
@@ -3865,23 +3845,16 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
// Fire onchange (if necessary), before we do the blur, bug 357684.
if (aVisitor.mEvent->mMessage == eBlur) {
- // Experimental mobile types rely on the system UI to prevent users to not
- // set invalid values but we have to be extra-careful. Especially if the
- // option has been enabled on desktop.
- if (IsExperimentalMobileType(mType)) {
- nsAutoString aValue;
- GetValueInternal(aValue);
- nsresult rv =
- SetValueInternal(aValue, nsTextEditorState::eSetValue_Internal);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- FireChangeEventIfNeeded();
+ // We set NS_PRE_HANDLE_BLUR_EVENT here and handle it in PreHandleEvent to
+ // prevent breaking event target chain creation.
+ aVisitor.mWantsPreHandleEvent = true;
+ aVisitor.mItemFlags |= NS_PRE_HANDLE_BLUR_EVENT;
}
if (mType == NS_FORM_INPUT_RANGE &&
(aVisitor.mEvent->mMessage == eFocus ||
aVisitor.mEvent->mMessage == eBlur)) {
- // Just as nsGenericHTMLFormElementWithState::PreHandleEvent calls
+ // Just as nsGenericHTMLFormElementWithState::GetEventTargetParent calls
// nsIFormControlFrame::SetFocus, we handle focus here.
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
@@ -3969,10 +3942,11 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
- nsresult rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
+ nsresult rv = nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
- // We do this after calling the base class' PreHandleEvent so that
- // nsIContent::PreHandleEvent doesn't reset any change we make to mCanHandle.
+ // We do this after calling the base class' GetEventTargetParent so that
+ // nsIContent::GetEventTargetParent doesn't reset any change we make to
+ // mCanHandle.
if (mType == NS_FORM_INPUT_NUMBER &&
aVisitor.mEvent->IsTrusted() &&
aVisitor.mEvent->mOriginalTarget != this) {
@@ -3987,18 +3961,10 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
if (textControl && aVisitor.mEvent->mOriginalTarget == textControl) {
if (aVisitor.mEvent->mMessage == eEditorInput) {
- // Propogate the anon text control's new value to our HTMLInputElement:
- nsAutoString value;
- numberControlFrame->GetValueOfAnonTextControl(value);
- numberControlFrame->HandlingInputEvent(true);
- nsWeakFrame weakNumberControlFrame(numberControlFrame);
- rv = SetValueInternal(value,
- nsTextEditorState::eSetValue_BySetUserInput |
- nsTextEditorState::eSetValue_Notify);
- NS_ENSURE_SUCCESS(rv, rv);
- if (weakNumberControlFrame.IsAlive()) {
- numberControlFrame->HandlingInputEvent(false);
- }
+ aVisitor.mWantsPreHandleEvent = true;
+ // We set NS_PRE_HANDLE_INPUT_EVENT here and handle it in PreHandleEvent
+ // to prevent breaking event target chain creation.
+ aVisitor.mItemFlags |= NS_PRE_HANDLE_INPUT_EVENT;
}
else if (aVisitor.mEvent->mMessage == eFormChange) {
// We cancel the DOM 'change' event that is fired for any change to our
@@ -4037,6 +4003,50 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
return rv;
}
+nsresult
+HTMLInputElement::PreHandleEvent(EventChainVisitor& aVisitor)
+{
+ if (!aVisitor.mPresContext) {
+ return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
+ }
+ nsresult rv;
+ if (aVisitor.mItemFlags & NS_PRE_HANDLE_BLUR_EVENT) {
+ MOZ_ASSERT(aVisitor.mEvent->mMessage == eBlur);
+ // Experimental mobile types rely on the system UI to prevent users to not
+ // set invalid values but we have to be extra-careful. Especially if the
+ // option has been enabled on desktop.
+ if (IsExperimentalMobileType(mType)) {
+ nsAutoString aValue;
+ GetValueInternal(aValue);
+ nsresult rv =
+ SetValueInternal(aValue, nsTextEditorState::eSetValue_Internal);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ FireChangeEventIfNeeded();
+ }
+ rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
+ if (aVisitor.mItemFlags & NS_PRE_HANDLE_INPUT_EVENT) {
+ nsNumberControlFrame* numberControlFrame = do_QueryFrame(GetPrimaryFrame());
+ MOZ_ASSERT(aVisitor.mEvent->mMessage == eEditorInput);
+ MOZ_ASSERT(numberControlFrame);
+ MOZ_ASSERT(numberControlFrame->GetAnonTextControl() ==
+ aVisitor.mEvent->mOriginalTarget);
+ // Propogate the anon text control's new value to our HTMLInputElement:
+ nsAutoString value;
+ numberControlFrame->GetValueOfAnonTextControl(value);
+ numberControlFrame->HandlingInputEvent(true);
+ nsWeakFrame weakNumberControlFrame(numberControlFrame);
+ rv = SetValueInternal(value,
+ nsTextEditorState::eSetValue_BySetUserInput |
+ nsTextEditorState::eSetValue_Notify);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (weakNumberControlFrame.IsAlive()) {
+ numberControlFrame->HandlingInputEvent(false);
+ }
+ }
+ return rv;
+}
+
void
HTMLInputElement::StartRangeThumbDrag(WidgetGUIEvent* aEvent)
{
@@ -4961,7 +4971,9 @@ HTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
}
// Set direction based on value if dir=auto
- SetDirectionIfAuto(HasDirAuto(), false);
+ if (HasDirAuto()) {
+ SetDirectionFromValue(false);
+ }
// An element can't suffer from value missing if it is not in a document.
// We have to check if we suffer from that as we are now in a document.
@@ -5015,14 +5027,23 @@ HTMLInputElement::UnbindFromTree(bool aDeep, bool aNullParent)
}
void
-HTMLInputElement::HandleTypeChange(uint8_t aNewType)
+HTMLInputElement::HandleTypeChange(uint8_t aNewType, bool aNotify)
{
- if (mType == NS_FORM_INPUT_RANGE && mIsDraggingRange) {
+ uint8_t oldType = mType;
+ MOZ_ASSERT(oldType != aNewType);
+
+ if (aNewType == NS_FORM_INPUT_FILE || oldType == NS_FORM_INPUT_FILE) {
+ // Strictly speaking, we only need to clear files on going _to_ or _from_
+ // the NS_FORM_INPUT_FILE type, not both, since we'll never confuse values
+ // and filenames. But this is safer.
+ ClearFiles(false);
+ }
+
+ if (oldType == NS_FORM_INPUT_RANGE && mIsDraggingRange) {
CancelRangeThumbDrag(false);
}
ValueModeType aOldValueMode = GetValueMode();
- uint8_t oldType = mType;
nsAutoString aOldValue;
if (aOldValueMode == VALUE_MODE_VALUE) {
@@ -5103,6 +5124,30 @@ HTMLInputElement::HandleTypeChange(uint8_t aNewType)
UpdateAllValidityStates(false);
UpdateApzAwareFlag();
+
+ UpdateBarredFromConstraintValidation();
+
+ if (oldType == NS_FORM_INPUT_IMAGE) {
+ // We're no longer an image input. Cancel our image requests, if we have
+ // any.
+ CancelImageRequests(aNotify);
+ } else if (aNotify && mType == NS_FORM_INPUT_IMAGE) {
+ // We just got switched to be an image input; we should see
+ // whether we have an image to load;
+ nsAutoString src;
+ if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
+ LoadImage(src, false, aNotify, eImageLoadType_Normal);
+ }
+ }
+
+ if (mType == NS_FORM_INPUT_PASSWORD && IsInComposedDoc()) {
+ AsyncEventDispatcher* dispatcher =
+ new AsyncEventDispatcher(this,
+ NS_LITERAL_STRING("DOMInputPasswordAdded"),
+ true,
+ true);
+ dispatcher->PostDOMEvent();
+ }
}
void
@@ -5813,42 +5858,34 @@ HTMLInputElement::ParseAttribute(int32_t aNamespaceID,
const nsAString& aValue,
nsAttrValue& aResult)
{
+ // We can't make these static_asserts because kInputDefaultType and
+ // kInputTypeTable aren't constexpr.
+ MOZ_ASSERT(kInputDefaultType->value == NS_FORM_INPUT_TEXT,
+ "Someone forgot to update kInputDefaultType when adding a new "
+ "input type.");
+ MOZ_ASSERT(kInputTypeTable[ArrayLength(kInputTypeTable) - 1].tag == nullptr,
+ "Last entry in the table must be the nullptr guard");
+ MOZ_ASSERT(kInputTypeTable[ArrayLength(kInputTypeTable) - 2].value ==
+ NS_FORM_INPUT_TEXT,
+ "Next to last entry in the table must be the \"text\" entry");
+
if (aNamespaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::type) {
- // XXX ARG!! This is major evilness. ParseAttribute
- // shouldn't set members. Override SetAttr instead
- int32_t newType;
- bool success = aResult.ParseEnumValue(aValue, kInputTypeTable, false);
- if (success) {
- newType = aResult.GetEnumValue();
- if ((newType == NS_FORM_INPUT_NUMBER && !IsInputNumberEnabled()) ||
- (newType == NS_FORM_INPUT_COLOR && !IsInputColorEnabled()) ||
- (IsDateTimeInputType(newType) && !IsDateTimeTypeSupported(newType))) {
- newType = kInputDefaultType->value;
- aResult.SetTo(newType, &aValue);
- }
- } else {
- newType = kInputDefaultType->value;
+ aResult.ParseEnumValue(aValue, kInputTypeTable, false, kInputDefaultType);
+ int32_t newType = aResult.GetEnumValue();
+ if ((IsExperimentalMobileType(newType) &&
+ !IsExperimentalFormsEnabled()) ||
+ (newType == NS_FORM_INPUT_NUMBER && !IsInputNumberEnabled()) ||
+ (newType == NS_FORM_INPUT_COLOR && !IsInputColorEnabled()) ||
+ (IsDateTimeInputType(newType) &&
+ !IsDateTimeTypeSupported(newType))) {
+ // There's no public way to set an nsAttrValue to an enum value, but we
+ // can just re-parse with a table that doesn't have any types other than
+ // "text" in it.
+ aResult.ParseEnumValue(aValue, kInputDefaultType, false, kInputDefaultType);
}
- if (newType != mType) {
- // Make sure to do the check for newType being NS_FORM_INPUT_FILE and
- // the corresponding SetValueInternal() call _before_ we set mType.
- // That way the logic in SetValueInternal() will work right (that logic
- // makes assumptions about our frame based on mType, but we won't have
- // had time to recreate frames yet -- that happens later in the
- // SetAttr() process).
- if (newType == NS_FORM_INPUT_FILE || mType == NS_FORM_INPUT_FILE) {
- // This call isn't strictly needed any more since we'll never
- // confuse values and filenames. However it's there for backwards
- // compat.
- ClearFiles(false);
- }
-
- HandleTypeChange(newType);
- }
-
- return success;
+ return true;
}
if (aAttribute == nsGkAtoms::width) {
return aResult.ParseSpecialIntValue(aValue);
@@ -6654,17 +6691,12 @@ HTMLInputElement::SetDefaultValueAsValue()
}
void
-HTMLInputElement::SetDirectionIfAuto(bool aAuto, bool aNotify)
+HTMLInputElement::SetDirectionFromValue(bool aNotify)
{
- if (aAuto) {
- SetHasDirAuto();
- if (IsSingleLineTextControl(true)) {
- nsAutoString value;
- GetValue(value);
- SetDirectionalityFromValue(this, value, aNotify);
- }
- } else {
- ClearHasDirAuto();
+ if (IsSingleLineTextControl(true)) {
+ nsAutoString value;
+ GetValue(value);
+ SetDirectionalityFromValue(this, value, aNotify);
}
}
@@ -8441,7 +8473,7 @@ HTMLInputElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
UpdateAllValidityStates(aNotify);
if (HasDirAuto()) {
- SetDirectionIfAuto(true, aNotify);
+ SetDirectionFromValue(aNotify);
}
// :placeholder-shown pseudo-class may change when the value changes.
diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h
index 98a590443..55bb59ec9 100644
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -185,7 +185,9 @@ public:
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
+ virtual nsresult PreHandleEvent(EventChainVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
void PostHandleEventForRangeThumb(EventChainPostVisitor& aVisitor);
@@ -956,13 +958,15 @@ protected:
* Called when an attribute is about to be changed
*/
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify) override;
/**
* Called when an attribute has just been changed
*/
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
/**
* Dispatch a select event. Returns true if the event was not cancelled.
@@ -1098,7 +1102,7 @@ protected:
/**
* Manages the internal data storage across type changes.
*/
- void HandleTypeChange(uint8_t aNewType);
+ void HandleTypeChange(uint8_t aNewType, bool aNotify);
/**
* Sanitize the value of the element depending of its current type.
@@ -1118,7 +1122,7 @@ protected:
*/
nsresult SetDefaultValueAsValue();
- virtual void SetDirectionIfAuto(bool aAuto, bool aNotify);
+ void SetDirectionFromValue(bool aNotify);
/**
* Return if an element should have a specific validity UI
diff --git a/dom/html/HTMLLegendElement.cpp b/dom/html/HTMLLegendElement.cpp
index 1a593d769..3f329de42 100644
--- a/dom/html/HTMLLegendElement.cpp
+++ b/dom/html/HTMLLegendElement.cpp
@@ -71,21 +71,6 @@ HTMLLegendElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
}
nsresult
-HTMLLegendElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
-{
- return nsGenericHTMLElement::SetAttr(aNameSpaceID, aAttribute,
- aPrefix, aValue, aNotify);
-}
-nsresult
-HTMLLegendElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify)
-{
- return nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
-}
-
-nsresult
HTMLLegendElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers)
diff --git a/dom/html/HTMLLegendElement.h b/dom/html/HTMLLegendElement.h
index e2d71d62d..0b476c119 100644
--- a/dom/html/HTMLLegendElement.h
+++ b/dom/html/HTMLLegendElement.h
@@ -42,16 +42,6 @@ public:
nsAttrValue& aResult) override;
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
int32_t aModType) const override;
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp
index 8afe767bd..b05b92d7a 100644
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -333,7 +333,7 @@ HTMLLinkElement::UpdateImport()
nsresult
HTMLLinkElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue, bool aNotify)
+ const nsAttrValueOrString* aValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None &&
(aName == nsGkAtoms::href || aName == nsGkAtoms::rel)) {
@@ -348,7 +348,8 @@ HTMLLinkElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsresult
HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
// It's safe to call ResetLinkState here because our new attr value has
// already been set or unset. ResetLinkState needs the updated attribute
@@ -417,13 +418,13 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
nsresult
-HTMLLinkElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLLinkElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- return PreHandleEventForAnchors(aVisitor);
+ return GetEventTargetParentForAnchors(aVisitor);
}
nsresult
diff --git a/dom/html/HTMLLinkElement.h b/dom/html/HTMLLinkElement.h
index 421b149e9..acac955cb 100644
--- a/dom/html/HTMLLinkElement.h
+++ b/dom/html/HTMLLinkElement.h
@@ -46,7 +46,8 @@ public:
void UpdateImport();
// nsIDOMEventTarget
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
@@ -61,10 +62,11 @@ public:
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
bool aNotify) override;
virtual bool IsLink(nsIURI** aURI) const override;
virtual already_AddRefed<nsIURI> GetHrefURI() const override;
diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp
index bc63eab51..cbb86edac 100644
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3726,77 +3726,74 @@ int32_t HTMLMediaElement::TabIndexDefault()
return 0;
}
-nsresult HTMLMediaElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
-{
- nsresult rv =
- nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
- aNotify);
- if (NS_FAILED(rv))
- return rv;
- if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
- DoLoad();
- }
- if (aNotify && aNameSpaceID == kNameSpaceID_None) {
- if (aName == nsGkAtoms::autoplay) {
- StopSuspendingAfterFirstFrame();
- CheckAutoplayDataReady();
- // This attribute can affect AddRemoveSelfReference
- AddRemoveSelfReference();
- UpdatePreloadAction();
+nsresult
+HTMLMediaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
+{
+ if (aNameSpaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::src) {
+ mSrcMediaSource = nullptr;
+ if (aValue) {
+ nsString srcStr = aValue->GetStringValue();
+ nsCOMPtr<nsIURI> uri;
+ NewURIFromString(srcStr, getter_AddRefs(uri));
+ if (uri && IsMediaSourceURI(uri)) {
+ nsresult rv =
+ NS_GetSourceForMediaSourceURI(uri, getter_AddRefs(mSrcMediaSource));
+ if (NS_FAILED(rv)) {
+ nsAutoString spec;
+ GetCurrentSrc(spec);
+ const char16_t* params[] = { spec.get() };
+ ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
+ }
+ }
+ }
+ } else if (aName == nsGkAtoms::autoplay) {
+ if (aNotify) {
+ if (aValue) {
+ StopSuspendingAfterFirstFrame();
+ CheckAutoplayDataReady();
+ }
+ // This attribute can affect AddRemoveSelfReference
+ AddRemoveSelfReference();
+ UpdatePreloadAction();
+ }
} else if (aName == nsGkAtoms::preload) {
UpdatePreloadAction();
}
}
- return rv;
+ // Since AfterMaybeChangeAttr may call DoLoad, make sure that it is called
+ // *after* any possible changes to mSrcMediaSource.
+ if (aValue) {
+ AfterMaybeChangeAttr(aNameSpaceID, aName, aNotify);
+ }
+
+ return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
+ aValue, aOldValue, aNotify);
}
-nsresult HTMLMediaElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
- bool aNotify)
+nsresult
+HTMLMediaElement::OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify)
{
- nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttr, aNotify);
- if (NS_FAILED(rv))
- return rv;
- if (aNotify && aNameSpaceID == kNameSpaceID_None) {
- if (aAttr == nsGkAtoms::autoplay) {
- // This attribute can affect AddRemoveSelfReference
- AddRemoveSelfReference();
- UpdatePreloadAction();
- } else if (aAttr == nsGkAtoms::preload) {
- UpdatePreloadAction();
- }
- }
+ AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
- return rv;
+ return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
+ aValue, aNotify);
}
-nsresult
-HTMLMediaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
-{
- if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
- mSrcMediaSource = nullptr;
- if (aValue) {
- nsString srcStr = aValue->GetStringValue();
- nsCOMPtr<nsIURI> uri;
- NewURIFromString(srcStr, getter_AddRefs(uri));
- if (uri && IsMediaSourceURI(uri)) {
- nsresult rv =
- NS_GetSourceForMediaSourceURI(uri, getter_AddRefs(mSrcMediaSource));
- if (NS_FAILED(rv)) {
- nsAutoString spec;
- GetCurrentSrc(spec);
- const char16_t* params[] = { spec.get() };
- ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
- }
- }
+void
+HTMLMediaElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
+ bool aNotify)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::src) {
+ DoLoad();
}
}
-
- return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
}
nsresult HTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
@@ -5634,7 +5631,7 @@ nsIContent* HTMLMediaElement::GetNextSource()
"Should only iterate over direct children");
#endif
- int32_t startOffset = 0;
+ uint32_t startOffset = 0;
rv = mSourcePointer->GetStartOffset(&startOffset);
NS_ENSURE_SUCCESS(rv, nullptr);
diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h
index 44c666f95..0d8d5d4e0 100644
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -132,21 +132,6 @@ public:
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult) override;
- // SetAttr override. C++ is stupid, so have to override both
- // overloaded methods.
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
- bool aNotify) override;
- virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue,
- bool aNotify) override;
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
@@ -1314,6 +1299,14 @@ protected:
already_AddRefed<Promise> CreateDOMPromise(ErrorResult& aRv) const;
+ virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
+ virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify) override;
+
// The current decoder. Load() has been called on this decoder.
// At most one of mDecoder and mSrcStream can be non-null.
RefPtr<MediaDecoder> mDecoder;
@@ -1716,6 +1709,17 @@ private:
// We keep track of these because the load algorithm resolves/rejects all
// already-dispatched pending play promises.
nsTArray<nsResolveOrRejectPendingPlayPromisesRunner*> mPendingPlayPromisesRunners;
+
+private:
+ /**
+ * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
+ * It will not be called if the value is being unset.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aNotify Whether we plan to notify document observers.
+ */
+ void AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName, bool aNotify);
};
} // namespace dom
diff --git a/dom/html/HTMLMenuItemElement.cpp b/dom/html/HTMLMenuItemElement.cpp
index ca8bb4feb..3245a16b1 100644
--- a/dom/html/HTMLMenuItemElement.cpp
+++ b/dom/html/HTMLMenuItemElement.cpp
@@ -252,7 +252,7 @@ HTMLMenuItemElement::SetChecked(bool aChecked)
}
nsresult
-HTMLMenuItemElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLMenuItemElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
if (aVisitor.mEvent->mMessage == eMouseClick) {
@@ -283,7 +283,7 @@ HTMLMenuItemElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
aVisitor.mItemFlags |= mType;
}
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
nsresult
@@ -380,7 +380,8 @@ HTMLMenuItemElement::GetText(nsAString& aText)
nsresult
HTMLMenuItemElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
if ((aName == nsGkAtoms::radiogroup || aName == nsGkAtoms::type) &&
@@ -404,7 +405,7 @@ HTMLMenuItemElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
void
diff --git a/dom/html/HTMLMenuItemElement.h b/dom/html/HTMLMenuItemElement.h
index 3c19b1170..cb824edcc 100644
--- a/dom/html/HTMLMenuItemElement.h
+++ b/dom/html/HTMLMenuItemElement.h
@@ -36,7 +36,8 @@ public:
// nsIDOMHTMLMenuItemElement
NS_DECL_NSIDOMHTMLMENUITEMELEMENT
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
@@ -124,7 +125,9 @@ protected:
protected:
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
void WalkRadioGroup(Visitor* aVisitor);
diff --git a/dom/html/HTMLMetaElement.cpp b/dom/html/HTMLMetaElement.cpp
index 47effa2bc..833c3177a 100644
--- a/dom/html/HTMLMetaElement.cpp
+++ b/dom/html/HTMLMetaElement.cpp
@@ -60,7 +60,8 @@ HTMLMetaElement::SetMetaReferrer(nsIDocument* aDocument)
nsresult
HTMLMetaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
nsIDocument *document = GetUncomposedDoc();
@@ -82,7 +83,7 @@ HTMLMetaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
nsresult
diff --git a/dom/html/HTMLMetaElement.h b/dom/html/HTMLMetaElement.h
index d3f05826d..0b9117e55 100644
--- a/dom/html/HTMLMetaElement.h
+++ b/dom/html/HTMLMetaElement.h
@@ -33,7 +33,9 @@ public:
bool aNullParent = true) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
void CreateAndDispatchEvent(nsIDocument* aDoc, const nsAString& aEventName);
diff --git a/dom/html/HTMLObjectElement.cpp b/dom/html/HTMLObjectElement.cpp
index 65f407889..cd2f3f37a 100644
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -298,41 +298,45 @@ HTMLObjectElement::UnbindFromTree(bool aDeep,
nsresult
-HTMLObjectElement::SetAttr(int32_t aNameSpaceID, nsIAtom *aName,
- nsIAtom *aPrefix, const nsAString &aValue,
- bool aNotify)
+HTMLObjectElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
- nsresult rv = nsGenericHTMLFormElement::SetAttr(aNameSpaceID, aName, aPrefix,
- aValue, aNotify);
+ nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
- // if aNotify is false, we are coming from the parser or some such place;
- // we'll get bound after all the attributes have been set, so we'll do the
- // object load from BindToTree/DoneAddingChildren.
- // Skip the LoadObject call in that case.
- // We also don't want to start loading the object when we're not yet in
- // a document, just in case that the caller wants to set additional
- // attributes before inserting the node into the document.
- if (aNotify && IsInComposedDoc() && mIsDoneAddingChildren &&
- aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::data) {
- return LoadObject(aNotify, true);
- }
-
- return NS_OK;
+ return nsGenericHTMLFormElement::AfterSetAttr(aNamespaceID, aName, aValue,
+ aOldValue, aNotify);
}
nsresult
-HTMLObjectElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify)
+HTMLObjectElement::OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify)
{
- nsresult rv = nsGenericHTMLFormElement::UnsetAttr(aNameSpaceID,
- aAttribute, aNotify);
+ nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
- // See comment in SetAttr
- if (aNotify && IsInComposedDoc() && mIsDoneAddingChildren &&
- aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::data) {
- return LoadObject(aNotify, true);
+ return nsGenericHTMLFormElement::OnAttrSetButNotChanged(aNamespaceID, aName,
+ aValue, aNotify);
+}
+
+nsresult
+HTMLObjectElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
+ bool aNotify)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ // if aNotify is false, we are coming from the parser or some such place;
+ // we'll get bound after all the attributes have been set, so we'll do the
+ // object load from BindToTree/DoneAddingChildren.
+ // Skip the LoadObject call in that case.
+ // We also don't want to start loading the object when we're not yet in
+ // a document, just in case that the caller wants to set additional
+ // attributes before inserting the node into the document.
+ if (aNotify && IsInComposedDoc() && mIsDoneAddingChildren &&
+ aName == nsGkAtoms::data) {
+ return LoadObject(aNotify, true);
+ }
}
return NS_OK;
diff --git a/dom/html/HTMLObjectElement.h b/dom/html/HTMLObjectElement.h
index 5226154da..6ce09e1cc 100644
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -59,11 +59,6 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom *aName,
- nsIAtom *aPrefix, const nsAString &aValue,
- bool aNotify) override;
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify) override;
virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
virtual IMEState GetDesiredIMEState() override;
@@ -245,6 +240,15 @@ public:
return GetContentDocument(aSubjectPrincipal);
}
+ protected:
+ virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
+ virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify) override;
+
private:
/**
* Calls LoadObject with the correct arguments to start the plugin load.
@@ -269,6 +273,18 @@ private:
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
nsRuleData* aData);
+ /**
+ * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
+ * This function will be called by AfterSetAttr whether the attribute is being
+ * set or unset.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aNotify Whether we plan to notify document observers.
+ */
+ nsresult AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
+ bool aNotify);
+
bool mIsDoneAddingChildren;
};
diff --git a/dom/html/HTMLOptGroupElement.cpp b/dom/html/HTMLOptGroupElement.cpp
index 9e738961d..63af4e39f 100644
--- a/dom/html/HTMLOptGroupElement.cpp
+++ b/dom/html/HTMLOptGroupElement.cpp
@@ -48,7 +48,7 @@ NS_IMPL_STRING_ATTR(HTMLOptGroupElement, Label, label)
nsresult
-HTMLOptGroupElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLOptGroupElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = false;
// Do not process any DOM events if the element is disabled
@@ -65,7 +65,7 @@ HTMLOptGroupElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
Element*
@@ -101,7 +101,8 @@ HTMLOptGroupElement::RemoveChildAt(uint32_t aIndex, bool aNotify)
nsresult
HTMLOptGroupElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::disabled) {
// All our children <option> have their :disabled state depending on our
@@ -116,7 +117,7 @@ HTMLOptGroupElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
EventStates
diff --git a/dom/html/HTMLOptGroupElement.h b/dom/html/HTMLOptGroupElement.h
index e46a6a953..6853e51ed 100644
--- a/dom/html/HTMLOptGroupElement.h
+++ b/dom/html/HTMLOptGroupElement.h
@@ -35,14 +35,17 @@ public:
virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
// nsIContent
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual EventStates IntrinsicState() const override;
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual nsIDOMNode* AsDOMNode() override { return this; }
diff --git a/dom/html/HTMLOptionElement.cpp b/dom/html/HTMLOptionElement.cpp
index 7b1e3ca2d..410c5713e 100644
--- a/dom/html/HTMLOptionElement.cpp
+++ b/dom/html/HTMLOptionElement.cpp
@@ -181,7 +181,7 @@ HTMLOptionElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
nsresult
HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify)
{
nsresult rv = nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName,
@@ -244,7 +244,8 @@ HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
nsresult
HTMLOptionElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None &&
aName == nsGkAtoms::value && Selected()) {
@@ -258,7 +259,7 @@ HTMLOptionElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
NS_IMETHODIMP
diff --git a/dom/html/HTMLOptionElement.h b/dom/html/HTMLOptionElement.h
index 4b5e192ff..965cdeb8f 100644
--- a/dom/html/HTMLOptionElement.h
+++ b/dom/html/HTMLOptionElement.h
@@ -47,10 +47,12 @@ public:
int32_t aModType) const override;
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
void SetSelectedInternal(bool aValue, bool aNotify);
diff --git a/dom/html/HTMLOptionsCollection.cpp b/dom/html/HTMLOptionsCollection.cpp
index 67de97fc4..da8a9d571 100644
--- a/dom/html/HTMLOptionsCollection.cpp
+++ b/dom/html/HTMLOptionsCollection.cpp
@@ -239,6 +239,12 @@ HTMLOptionsCollection::GetParentObject()
return mSelect;
}
+DocGroup*
+HTMLOptionsCollection::GetDocGroup() const
+{
+ return mSelect ? mSelect->GetDocGroup() : nullptr;
+}
+
NS_IMETHODIMP
HTMLOptionsCollection::NamedItem(const nsAString& aName,
nsIDOMNode** aReturn)
diff --git a/dom/html/HTMLOptionsCollection.h b/dom/html/HTMLOptionsCollection.h
index 496919555..9dd1561f6 100644
--- a/dom/html/HTMLOptionsCollection.h
+++ b/dom/html/HTMLOptionsCollection.h
@@ -23,6 +23,7 @@ class nsIDOMHTMLOptionElement;
namespace mozilla {
namespace dom {
+class DocGroup;
class HTMLElementOrLong;
class HTMLOptionElementOrHTMLOptGroupElement;
class HTMLSelectElement;
@@ -62,6 +63,7 @@ public:
virtual Element* GetElementAt(uint32_t aIndex) override;
virtual nsINode* GetParentObject() override;
+ DocGroup* GetDocGroup() const;
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(HTMLOptionsCollection,
nsIHTMLCollection)
diff --git a/dom/html/HTMLScriptElement.cpp b/dom/html/HTMLScriptElement.cpp
index 095b9b77d..a1bea94d9 100644
--- a/dom/html/HTMLScriptElement.cpp
+++ b/dom/html/HTMLScriptElement.cpp
@@ -232,13 +232,14 @@ HTMLScriptElement::SetNoModule(bool aValue, ErrorResult& aRv)
nsresult
HTMLScriptElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (nsGkAtoms::async == aName && kNameSpaceID_None == aNamespaceID) {
mForceAsync = false;
}
return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
NS_IMETHODIMP
diff --git a/dom/html/HTMLScriptElement.h b/dom/html/HTMLScriptElement.h
index 19ceb414f..bd446fa97 100644
--- a/dom/html/HTMLScriptElement.h
+++ b/dom/html/HTMLScriptElement.h
@@ -57,7 +57,9 @@ public:
// Element
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
// WebIDL
void SetText(const nsAString& aValue, ErrorResult& rv);
diff --git a/dom/html/HTMLSelectElement.cpp b/dom/html/HTMLSelectElement.cpp
index 9ba0a1efe..36dac0852 100644
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -1269,12 +1269,25 @@ HTMLSelectElement::UnbindFromTree(bool aDeep, bool aNullParent)
nsresult
HTMLSelectElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify)
{
- if (aNotify && aName == nsGkAtoms::disabled &&
- aNameSpaceID == kNameSpaceID_None) {
- mDisabledChanged = true;
+ if (aNameSpaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::disabled) {
+ if (aNotify) {
+ mDisabledChanged = true;
+ }
+ } else if (aName == nsGkAtoms::multiple) {
+ if (!aValue && aNotify && mSelectedIndex >= 0) {
+ // We're changing from being a multi-select to a single-select.
+ // Make sure we only have one option selected before we do that.
+ // Note that this needs to come before we really unset the attr,
+ // since SetOptionsSelectedByIndex does some bail-out type
+ // optimization for cases when the select is not multiple that
+ // would lead to only a single option getting deselected.
+ SetSelectedIndexInternal(mSelectedIndex, aNotify);
+ }
+ }
}
return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
@@ -1283,7 +1296,8 @@ HTMLSelectElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsresult
HTMLSelectElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::disabled) {
@@ -1293,44 +1307,18 @@ HTMLSelectElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
} else if (aName == nsGkAtoms::autocomplete) {
// Clear the cached @autocomplete attribute state
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
+ } else if (aName == nsGkAtoms::multiple) {
+ if (!aValue && aNotify) {
+ // We might have become a combobox; make sure _something_ gets
+ // selected in that case
+ CheckSelectSomething(aNotify);
+ }
}
-
- UpdateState(aNotify);
}
return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
-}
-
-nsresult
-HTMLSelectElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify)
-{
- if (aNotify && aNameSpaceID == kNameSpaceID_None &&
- aAttribute == nsGkAtoms::multiple) {
- // We're changing from being a multi-select to a single-select.
- // Make sure we only have one option selected before we do that.
- // Note that this needs to come before we really unset the attr,
- // since SetOptionsSelectedByIndex does some bail-out type
- // optimization for cases when the select is not multiple that
- // would lead to only a single option getting deselected.
- if (mSelectedIndex >= 0) {
- SetSelectedIndexInternal(mSelectedIndex, aNotify);
- }
- }
-
- nsresult rv = nsGenericHTMLFormElementWithState::UnsetAttr(aNameSpaceID, aAttribute,
- aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (aNotify && aNameSpaceID == kNameSpaceID_None &&
- aAttribute == nsGkAtoms::multiple) {
- // We might have become a combobox; make sure _something_ gets
- // selected in that case
- CheckSelectSomething(aNotify);
- }
-
- return rv;
+ aValue, aOldValue,
+ aNotify);
}
void
@@ -1442,14 +1430,14 @@ HTMLSelectElement::IsDisabledForEvents(EventMessage aMessage)
}
nsresult
-HTMLSelectElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLSelectElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = false;
if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
return NS_OK;
}
- return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
+ return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
}
nsresult
diff --git a/dom/html/HTMLSelectElement.h b/dom/html/HTMLSelectElement.h
index dc1075cd7..298b1a8d1 100644
--- a/dom/html/HTMLSelectElement.h
+++ b/dom/html/HTMLSelectElement.h
@@ -278,7 +278,8 @@ public:
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// nsIContent
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
@@ -374,12 +375,12 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual void DoneAddingChildren(bool aHaveNotified) override;
virtual bool IsDoneAddingChildren() override {
diff --git a/dom/html/HTMLShadowElement.cpp b/dom/html/HTMLShadowElement.cpp
deleted file mode 100644
index 8824c2875..000000000
--- a/dom/html/HTMLShadowElement.cpp
+++ /dev/null
@@ -1,373 +0,0 @@
-/* -*- 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/ShadowRoot.h"
-
-#include "ChildIterator.h"
-#include "nsContentUtils.h"
-#include "nsDocument.h"
-#include "mozilla/dom/HTMLShadowElement.h"
-#include "mozilla/dom/HTMLUnknownElement.h"
-#include "mozilla/dom/HTMLShadowElementBinding.h"
-
-// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Shadow) to add check for web components
-// being enabled.
-nsGenericHTMLElement*
-NS_NewHTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
- mozilla::dom::FromParser aFromParser)
-{
- // When this check is removed, remove the nsDocument.h and
- // HTMLUnknownElement.h includes. Also remove nsINode::IsHTMLShadowElement.
- //
- // We have to jump through some hoops to be able to produce both NodeInfo* and
- // already_AddRefed<NodeInfo>& for our callees.
- RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
- if (!nsDocument::IsWebComponentsEnabled(nodeInfo)) {
- already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
- return new mozilla::dom::HTMLUnknownElement(nodeInfoArg);
- }
-
- already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
- return new mozilla::dom::HTMLShadowElement(nodeInfoArg);
-}
-
-using namespace mozilla::dom;
-
-HTMLShadowElement::HTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
- : nsGenericHTMLElement(aNodeInfo), mIsInsertionPoint(false)
-{
-}
-
-HTMLShadowElement::~HTMLShadowElement()
-{
- if (mProjectedShadow) {
- mProjectedShadow->RemoveMutationObserver(this);
- }
-}
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLShadowElement)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLShadowElement,
- nsGenericHTMLElement)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProjectedShadow)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLShadowElement,
- nsGenericHTMLElement)
- if (tmp->mProjectedShadow) {
- tmp->mProjectedShadow->RemoveMutationObserver(tmp);
- tmp->mProjectedShadow = nullptr;
- }
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_ADDREF_INHERITED(HTMLShadowElement, Element)
-NS_IMPL_RELEASE_INHERITED(HTMLShadowElement, Element)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLShadowElement)
-NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
-
-NS_IMPL_ELEMENT_CLONE(HTMLShadowElement)
-
-JSObject*
-HTMLShadowElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
-{
- return HTMLShadowElementBinding::Wrap(aCx, this, aGivenProto);
-}
-
-void
-HTMLShadowElement::SetProjectedShadow(ShadowRoot* aProjectedShadow)
-{
- if (mProjectedShadow) {
- mProjectedShadow->RemoveMutationObserver(this);
-
- // The currently projected ShadowRoot is going away,
- // thus the destination insertion points need to be updated.
- ExplicitChildIterator childIterator(mProjectedShadow);
- for (nsIContent* content = childIterator.GetNextChild();
- content;
- content = childIterator.GetNextChild()) {
- ShadowRoot::RemoveDestInsertionPoint(this, content->DestInsertionPoints());
- }
- }
-
- mProjectedShadow = aProjectedShadow;
- if (mProjectedShadow) {
- // A new ShadowRoot is being projected, thus its explcit
- // children will be distributed to this shadow insertion point.
- ExplicitChildIterator childIterator(mProjectedShadow);
- for (nsIContent* content = childIterator.GetNextChild();
- content;
- content = childIterator.GetNextChild()) {
- content->DestInsertionPoints().AppendElement(this);
- }
-
- // Watch for mutations on the projected shadow because
- // it affects the nodes that are distributed to this shadow
- // insertion point.
- mProjectedShadow->AddMutationObserver(this);
- }
-}
-
-static bool
-IsInFallbackContent(nsIContent* aContent)
-{
- nsINode* parentNode = aContent->GetParentNode();
- while (parentNode) {
- if (parentNode->IsHTMLElement(nsGkAtoms::content)) {
- return true;
- }
- parentNode = parentNode->GetParentNode();
- }
-
- return false;
-}
-
-nsresult
-HTMLShadowElement::BindToTree(nsIDocument* aDocument,
- nsIContent* aParent,
- nsIContent* aBindingParent,
- bool aCompileEventHandlers)
-{
- RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
-
- nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
- aBindingParent,
- aCompileEventHandlers);
- NS_ENSURE_SUCCESS(rv, rv);
-
- ShadowRoot* containingShadow = GetContainingShadow();
- if (containingShadow && !oldContainingShadow) {
- // Keep track of all descendant <shadow> elements in tree order so
- // that when the current shadow insertion point is removed, the next
- // one can be found quickly.
- TreeOrderComparator comparator;
- containingShadow->ShadowDescendants().InsertElementSorted(this, comparator);
-
- if (containingShadow->ShadowDescendants()[0] != this) {
- // Only the first <shadow> (in tree order) of a ShadowRoot can be an insertion point.
- return NS_OK;
- }
-
- if (IsInFallbackContent(this)) {
- // If the first shadow element in tree order is invalid (in fallback content),
- // the containing ShadowRoot will not have a shadow insertion point.
- containingShadow->SetShadowElement(nullptr);
- } else {
- mIsInsertionPoint = true;
- containingShadow->SetShadowElement(this);
- }
-
- containingShadow->SetInsertionPointChanged();
- }
-
- if (mIsInsertionPoint && containingShadow) {
- // Propagate BindToTree calls to projected shadow root children.
- ShadowRoot* projectedShadow = containingShadow->GetOlderShadowRoot();
- if (projectedShadow) {
- projectedShadow->SetIsComposedDocParticipant(IsInComposedDoc());
-
- for (nsIContent* child = projectedShadow->GetFirstChild(); child;
- child = child->GetNextSibling()) {
- rv = child->BindToTree(nullptr, projectedShadow,
- projectedShadow->GetBindingParent(),
- aCompileEventHandlers);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- }
- }
-
- return NS_OK;
-}
-
-void
-HTMLShadowElement::UnbindFromTree(bool aDeep, bool aNullParent)
-{
- RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
-
- if (mIsInsertionPoint && oldContainingShadow) {
- // Propagate UnbindFromTree call to previous projected shadow
- // root children.
- ShadowRoot* projectedShadow = oldContainingShadow->GetOlderShadowRoot();
- if (projectedShadow) {
- for (nsIContent* child = projectedShadow->GetFirstChild(); child;
- child = child->GetNextSibling()) {
- child->UnbindFromTree(true, false);
- }
-
- projectedShadow->SetIsComposedDocParticipant(false);
- }
- }
-
- nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
-
- if (oldContainingShadow && !GetContainingShadow() && mIsInsertionPoint) {
- nsTArray<HTMLShadowElement*>& shadowDescendants =
- oldContainingShadow->ShadowDescendants();
- shadowDescendants.RemoveElement(this);
- oldContainingShadow->SetShadowElement(nullptr);
-
- // Find the next shadow insertion point.
- if (shadowDescendants.Length() > 0 &&
- !IsInFallbackContent(shadowDescendants[0])) {
- oldContainingShadow->SetShadowElement(shadowDescendants[0]);
- }
-
- oldContainingShadow->SetInsertionPointChanged();
-
- mIsInsertionPoint = false;
- }
-}
-
-void
-HTMLShadowElement::DistributeSingleNode(nsIContent* aContent)
-{
- if (aContent->DestInsertionPoints().Contains(this)) {
- // Node has already been distrbuted this this node,
- // we are done.
- return;
- }
-
- aContent->DestInsertionPoints().AppendElement(this);
-
- // Handle the case where the shadow element is a child of
- // a node with a ShadowRoot. The nodes that have been distributed to
- // this shadow insertion point will need to be reprojected into the
- // insertion points of the parent's ShadowRoot.
- ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
- if (parentShadowRoot) {
- parentShadowRoot->DistributeSingleNode(aContent);
- return;
- }
-
- // Handle the case where the parent of this shadow element is a ShadowRoot
- // that is projected into a shadow insertion point in the younger ShadowRoot.
- ShadowRoot* containingShadow = GetContainingShadow();
- ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
- if (youngerShadow && GetParent() == containingShadow) {
- HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
- if (youngerShadowElement) {
- youngerShadowElement->DistributeSingleNode(aContent);
- }
- }
-}
-
-void
-HTMLShadowElement::RemoveDistributedNode(nsIContent* aContent)
-{
- ShadowRoot::RemoveDestInsertionPoint(this, aContent->DestInsertionPoints());
-
- // Handle the case where the shadow element is a child of
- // a node with a ShadowRoot. The nodes that have been distributed to
- // this shadow insertion point will need to be removed from the
- // insertion points of the parent's ShadowRoot.
- ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
- if (parentShadowRoot) {
- parentShadowRoot->RemoveDistributedNode(aContent);
- return;
- }
-
- // Handle the case where the parent of this shadow element is a ShadowRoot
- // that is projected into a shadow insertion point in the younger ShadowRoot.
- ShadowRoot* containingShadow = GetContainingShadow();
- ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
- if (youngerShadow && GetParent() == containingShadow) {
- HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
- if (youngerShadowElement) {
- youngerShadowElement->RemoveDistributedNode(aContent);
- }
- }
-}
-
-void
-HTMLShadowElement::DistributeAllNodes()
-{
- // All the explicit children of the projected ShadowRoot are distributed
- // into this shadow insertion point so update the destination insertion
- // points.
- ShadowRoot* containingShadow = GetContainingShadow();
- ShadowRoot* olderShadow = containingShadow->GetOlderShadowRoot();
- if (olderShadow) {
- ExplicitChildIterator childIterator(olderShadow);
- for (nsIContent* content = childIterator.GetNextChild();
- content;
- content = childIterator.GetNextChild()) {
- ShadowRoot::RemoveDestInsertionPoint(this, content->DestInsertionPoints());
- content->DestInsertionPoints().AppendElement(this);
- }
- }
-
- // Handle the case where the shadow element is a child of
- // a node with a ShadowRoot. The nodes that have been distributed to
- // this shadow insertion point will need to be reprojected into the
- // insertion points of the parent's ShadowRoot.
- ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
- if (parentShadowRoot) {
- parentShadowRoot->DistributeAllNodes();
- return;
- }
-
- // Handle the case where the parent of this shadow element is a ShadowRoot
- // that is projected into a shadow insertion point in the younger ShadowRoot.
- ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
- if (youngerShadow && GetParent() == containingShadow) {
- HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
- if (youngerShadowElement) {
- youngerShadowElement->DistributeAllNodes();
- }
- }
-}
-
-void
-HTMLShadowElement::ContentAppended(nsIDocument* aDocument,
- nsIContent* aContainer,
- nsIContent* aFirstNewContent,
- int32_t aNewIndexInContainer)
-{
- // Watch for content appended to the projected shadow (the ShadowRoot that
- // will be rendered in place of this shadow insertion point) because the
- // nodes may need to be distributed into other insertion points.
- nsIContent* currentChild = aFirstNewContent;
- while (currentChild) {
- if (ShadowRoot::IsPooledNode(currentChild, aContainer, mProjectedShadow)) {
- DistributeSingleNode(currentChild);
- }
- currentChild = currentChild->GetNextSibling();
- }
-}
-
-void
-HTMLShadowElement::ContentInserted(nsIDocument* aDocument,
- nsIContent* aContainer,
- nsIContent* aChild,
- int32_t aIndexInContainer)
-{
- // Watch for content appended to the projected shadow (the ShadowRoot that
- // will be rendered in place of this shadow insertion point) because the
- // nodes may need to be distributed into other insertion points.
- if (!ShadowRoot::IsPooledNode(aChild, aContainer, mProjectedShadow)) {
- return;
- }
-
- DistributeSingleNode(aChild);
-}
-
-void
-HTMLShadowElement::ContentRemoved(nsIDocument* aDocument,
- nsIContent* aContainer,
- nsIContent* aChild,
- int32_t aIndexInContainer,
- nsIContent* aPreviousSibling)
-{
- // Watch for content removed from the projected shadow (the ShadowRoot that
- // will be rendered in place of this shadow insertion point) because the
- // nodes may need to be removed from other insertion points.
- if (!ShadowRoot::IsPooledNode(aChild, aContainer, mProjectedShadow)) {
- return;
- }
-
- RemoveDistributedNode(aChild);
-}
-
diff --git a/dom/html/HTMLShadowElement.h b/dom/html/HTMLShadowElement.h
deleted file mode 100644
index 95083b802..000000000
--- a/dom/html/HTMLShadowElement.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/* -*- 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 mozilla_dom_HTMLShadowElement_h__
-#define mozilla_dom_HTMLShadowElement_h__
-
-#include "nsGenericHTMLElement.h"
-
-namespace mozilla {
-namespace dom {
-
-class HTMLShadowElement final : public nsGenericHTMLElement,
- public nsStubMutationObserver
-{
-public:
- explicit HTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
-
- // nsISupports
- NS_DECL_ISUPPORTS_INHERITED
-
- NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
- NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
- NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
-
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLShadowElement,
- nsGenericHTMLElement)
-
- static HTMLShadowElement* FromContent(nsIContent* aContent)
- {
- if (aContent->IsHTMLShadowElement()) {
- return static_cast<HTMLShadowElement*>(aContent);
- }
-
- return nullptr;
- }
-
- virtual bool IsHTMLShadowElement() const override { return true; }
-
- virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
-
- virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
- nsIContent* aBindingParent,
- bool aCompileEventHandlers) override;
-
- virtual void UnbindFromTree(bool aDeep = true,
- bool aNullParent = true) override;
-
- bool IsInsertionPoint() { return mIsInsertionPoint; }
-
- /**
- * Sets the ShadowRoot that will be rendered in place of
- * this shadow insertion point.
- */
- void SetProjectedShadow(ShadowRoot* aProjectedShadow);
-
- /**
- * Distributes a single explicit child of the projected ShadowRoot
- * to relevant insertion points.
- */
- void DistributeSingleNode(nsIContent* aContent);
-
- /**
- * Removes a single explicit child of the projected ShadowRoot
- * from relevant insertion points.
- */
- void RemoveDistributedNode(nsIContent* aContent);
-
- /**
- * Distributes all the explicit children of the projected ShadowRoot
- * to the shadow insertion point in the younger ShadowRoot and
- * the content insertion point of the parent node's ShadowRoot.
- */
- void DistributeAllNodes();
-
- // WebIDL methods.
- ShadowRoot* GetOlderShadowRoot() { return mProjectedShadow; }
-
-protected:
- virtual ~HTMLShadowElement();
-
- virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
-
- // The ShadowRoot that will be rendered in place of this shadow insertion point.
- RefPtr<ShadowRoot> mProjectedShadow;
-
- bool mIsInsertionPoint;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_HTMLShadowElement_h__
-
diff --git a/dom/html/HTMLSharedElement.cpp b/dom/html/HTMLSharedElement.cpp
index bcb84d29b..a7a10b082 100644
--- a/dom/html/HTMLSharedElement.cpp
+++ b/dom/html/HTMLSharedElement.cpp
@@ -231,52 +231,32 @@ SetBaseTargetUsingFirstBaseWithTarget(nsIDocument* aDocument,
}
nsresult
-HTMLSharedElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
+HTMLSharedElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
- nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
- aValue, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // If the href attribute of a <base> tag is changing, we may need to update
- // the document's base URI, which will cause all the links on the page to be
- // re-resolved given the new base. If the target attribute is changing, we
- // similarly need to change the base target.
- if (mNodeInfo->Equals(nsGkAtoms::base) &&
- aNameSpaceID == kNameSpaceID_None &&
- IsInUncomposedDoc()) {
- if (aName == nsGkAtoms::href) {
- SetBaseURIUsingFirstBaseWithHref(GetUncomposedDoc(), this);
- } else if (aName == nsGkAtoms::target) {
- SetBaseTargetUsingFirstBaseWithTarget(GetUncomposedDoc(), this);
- }
- }
-
- return NS_OK;
-}
-
-nsresult
-HTMLSharedElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- bool aNotify)
-{
- nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aName, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // If we're the first <base> with an href and our href attribute is being
- // unset, then we're no longer the first <base> with an href, and we need to
- // find the new one. Similar for target.
- if (mNodeInfo->Equals(nsGkAtoms::base) &&
- aNameSpaceID == kNameSpaceID_None &&
- IsInUncomposedDoc()) {
+ if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::href) {
- SetBaseURIUsingFirstBaseWithHref(GetUncomposedDoc(), nullptr);
+ // If the href attribute of a <base> tag is changing, we may need to
+ // update the document's base URI, which will cause all the links on the
+ // page to be re-resolved given the new base.
+ // If the href is being unset (aValue is null), we will need to find a new
+ // <base>.
+ if (mNodeInfo->Equals(nsGkAtoms::base) && IsInUncomposedDoc()) {
+ SetBaseURIUsingFirstBaseWithHref(GetUncomposedDoc(),
+ aValue ? this : nullptr);
+ }
} else if (aName == nsGkAtoms::target) {
- SetBaseTargetUsingFirstBaseWithTarget(GetUncomposedDoc(), nullptr);
+ // The target attribute is in pretty much the same situation as the href
+ // attribute, above.
+ if (mNodeInfo->Equals(nsGkAtoms::base) && IsInUncomposedDoc()) {
+ SetBaseTargetUsingFirstBaseWithTarget(GetUncomposedDoc(),
+ aValue ? this : nullptr);
+ }
}
}
-
- return NS_OK;
+ return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
+ aOldValue, aNotify);
}
nsresult
diff --git a/dom/html/HTMLSharedElement.h b/dom/html/HTMLSharedElement.h
index 205750cf6..a12ee096d 100644
--- a/dom/html/HTMLSharedElement.h
+++ b/dom/html/HTMLSharedElement.h
@@ -59,17 +59,6 @@ public:
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult) override;
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
-
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- bool aNotify) override;
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
@@ -181,6 +170,11 @@ protected:
virtual ~HTMLSharedElement();
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+ virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
};
} // namespace dom
diff --git a/dom/html/HTMLSharedObjectElement.cpp b/dom/html/HTMLSharedObjectElement.cpp
index 889fd5aef..4f35068e1 100644
--- a/dom/html/HTMLSharedObjectElement.cpp
+++ b/dom/html/HTMLSharedObjectElement.cpp
@@ -161,27 +161,53 @@ HTMLSharedObjectElement::UnbindFromTree(bool aDeep,
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
}
+nsresult
+HTMLSharedObjectElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify)
+{
+ if (aValue) {
+ nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
+ aOldValue, aNotify);
+}
nsresult
-HTMLSharedObjectElement::SetAttr(int32_t aNameSpaceID, nsIAtom *aName,
- nsIAtom *aPrefix, const nsAString &aValue,
- bool aNotify)
+HTMLSharedObjectElement::OnAttrSetButNotChanged(int32_t aNamespaceID,
+ nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify)
{
- nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
- aValue, aNotify);
+ nsresult rv = AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
- // if aNotify is false, we are coming from the parser or some such place;
- // we'll get bound after all the attributes have been set, so we'll do the
- // object load from BindToTree/DoneAddingChildren.
- // Skip the LoadObject call in that case.
- // We also don't want to start loading the object when we're not yet in
- // a document, just in case that the caller wants to set additional
- // attributes before inserting the node into the document.
- if (aNotify && IsInComposedDoc() && mIsDoneAddingChildren &&
- aNameSpaceID == kNameSpaceID_None && aName == URIAttrName()
- && !BlockEmbedContentLoading()) {
- return LoadObject(aNotify, true);
+ return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
+ aValue, aNotify);
+}
+
+nsresult
+HTMLSharedObjectElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
+ nsIAtom* aName,
+ bool aNotify)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == URIAttrName()) {
+ // If aNotify is false, we are coming from the parser or some such place;
+ // we'll get bound after all the attributes have been set, so we'll do the
+ // object load from BindToTree/DoneAddingChildren.
+ // Skip the LoadObject call in that case.
+ // We also don't want to start loading the object when we're not yet in
+ // a document, just in case that the caller wants to set additional
+ // attributes before inserting the node into the document.
+ if (aNotify && IsInComposedDoc() && mIsDoneAddingChildren) {
+ nsresult rv = LoadObject(aNotify, true);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
}
return NS_OK;
diff --git a/dom/html/HTMLSharedObjectElement.h b/dom/html/HTMLSharedObjectElement.h
index c70ba8ebd..07cf86cb0 100644
--- a/dom/html/HTMLSharedObjectElement.h
+++ b/dom/html/HTMLSharedObjectElement.h
@@ -57,9 +57,6 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom *aName,
- nsIAtom *aPrefix, const nsAString &aValue,
- bool aNotify) override;
virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
virtual IMEState GetDesiredIMEState() override;
@@ -200,6 +197,16 @@ public:
* Calls LoadObject with the correct arguments to start the plugin load.
*/
void StartObjectLoad(bool aNotify, bool aForceLoad);
+
+protected:
+ virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
+ virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify) override;
+
private:
virtual ~HTMLSharedObjectElement();
@@ -222,6 +229,17 @@ private:
nsRuleData* aData);
/**
+ * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
+ * It will not be called if the value is being unset.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aNotify Whether we plan to notify document observers.
+ */
+ nsresult AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
+ bool aNotify);
+
+ /**
* Decides whether we should load embed node content.
*
* If this is an embed node there are cases in which we should not try to load
diff --git a/dom/html/HTMLSlotElement.cpp b/dom/html/HTMLSlotElement.cpp
new file mode 100644
index 000000000..18b8ef87b
--- /dev/null
+++ b/dom/html/HTMLSlotElement.cpp
@@ -0,0 +1,235 @@
+/* -*- 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/DocGroup.h"
+#include "mozilla/dom/HTMLSlotElement.h"
+#include "mozilla/dom/HTMLSlotElementBinding.h"
+#include "mozilla/dom/HTMLUnknownElement.h"
+#include "mozilla/dom/ShadowRoot.h"
+#include "nsGkAtoms.h"
+#include "nsDocument.h"
+
+nsGenericHTMLElement*
+NS_NewHTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
+ mozilla::dom::FromParser aFromParser)
+{
+ RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
+ if (nsDocument::IsWebComponentsEnabled(nodeInfo->GetDocument())) {
+ already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
+ return new mozilla::dom::HTMLSlotElement(nodeInfoArg);
+ }
+
+ already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
+ return new mozilla::dom::HTMLUnknownElement(nodeInfoArg);
+}
+
+namespace mozilla {
+namespace dom {
+
+HTMLSlotElement::HTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+ : nsGenericHTMLElement(aNodeInfo)
+{
+}
+
+HTMLSlotElement::~HTMLSlotElement()
+{
+}
+
+NS_IMPL_ADDREF_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
+NS_IMPL_RELEASE_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLSlotElement,
+ nsGenericHTMLElement,
+ mAssignedNodes)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLSlotElement)
+NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
+
+NS_IMPL_ELEMENT_CLONE(HTMLSlotElement)
+
+nsresult
+HTMLSlotElement::BindToTree(nsIDocument* aDocument,
+ nsIContent* aParent,
+ nsIContent* aBindingParent,
+ bool aCompileEventHandlers)
+{
+ RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
+
+ nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
+ aBindingParent,
+ aCompileEventHandlers);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ ShadowRoot* containingShadow = GetContainingShadow();
+ if (containingShadow && !oldContainingShadow) {
+ containingShadow->AddSlot(this);
+ }
+
+ return NS_OK;
+}
+
+void
+HTMLSlotElement::UnbindFromTree(bool aDeep, bool aNullParent)
+{
+ RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
+
+ nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
+
+ if (oldContainingShadow && !GetContainingShadow()) {
+ oldContainingShadow->RemoveSlot(this);
+ }
+}
+
+nsresult
+HTMLSlotElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify)
+{
+ if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::name) {
+ if (ShadowRoot* containingShadow = GetContainingShadow()) {
+ containingShadow->RemoveSlot(this);
+ }
+ }
+
+ return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName, aValue,
+ aNotify);
+}
+
+nsresult
+HTMLSlotElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify)
+{
+
+ if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::name) {
+ if (ShadowRoot* containingShadow = GetContainingShadow()) {
+ containingShadow->AddSlot(this);
+ }
+ }
+
+ return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
+ aOldValue, aNotify);
+}
+
+/**
+ * Flatten assigned nodes given a slot, as in:
+ * https://dom.spec.whatwg.org/#find-flattened-slotables
+ */
+static void
+FlattenAssignedNodes(HTMLSlotElement* aSlot, nsTArray<RefPtr<nsINode>>& aNodes)
+{
+ if (!aSlot->GetContainingShadow()) {
+ return;
+ }
+
+ const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
+
+ // If assignedNodes is empty, use children of slot as fallback content.
+ if (assignedNodes.IsEmpty()) {
+ for (nsIContent* child = aSlot->AsContent()->GetFirstChild();
+ child;
+ child = child->GetNextSibling()) {
+ if (!child->IsSlotable()) {
+ continue;
+ }
+
+ if (child->IsHTMLElement(nsGkAtoms::slot)) {
+ FlattenAssignedNodes(HTMLSlotElement::FromContent(child), aNodes);
+ } else {
+ aNodes.AppendElement(child);
+ }
+ }
+ return;
+ }
+
+ for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
+ nsINode* assignedNode = assignedNodes[i];
+ if (assignedNode->IsHTMLElement(nsGkAtoms::slot)) {
+ FlattenAssignedNodes(
+ HTMLSlotElement::FromContent(assignedNode->AsContent()), aNodes);
+ } else {
+ aNodes.AppendElement(assignedNode);
+ }
+ }
+}
+
+void
+HTMLSlotElement::AssignedNodes(const AssignedNodesOptions& aOptions,
+ nsTArray<RefPtr<nsINode>>& aNodes)
+{
+ if (aOptions.mFlatten) {
+ return FlattenAssignedNodes(this, aNodes);
+ }
+
+ aNodes = mAssignedNodes;
+}
+
+const nsTArray<RefPtr<nsINode>>&
+HTMLSlotElement::AssignedNodes() const
+{
+ return mAssignedNodes;
+}
+
+void
+HTMLSlotElement::InsertAssignedNode(uint32_t aIndex, nsINode* aNode)
+{
+ mAssignedNodes.InsertElementAt(aIndex, aNode);
+ aNode->AsContent()->SetAssignedSlot(this);
+}
+
+void
+HTMLSlotElement::AppendAssignedNode(nsINode* aNode)
+{
+ mAssignedNodes.AppendElement(aNode);
+ aNode->AsContent()->SetAssignedSlot(this);
+}
+
+void
+HTMLSlotElement::RemoveAssignedNode(nsINode* aNode)
+{
+ mAssignedNodes.RemoveElement(aNode);
+ aNode->AsContent()->SetAssignedSlot(nullptr);
+}
+
+void
+HTMLSlotElement::ClearAssignedNodes()
+{
+ for (uint32_t i = 0; i < mAssignedNodes.Length(); i++) {
+ mAssignedNodes[i]->AsContent()->SetAssignedSlot(nullptr);
+ }
+
+ mAssignedNodes.Clear();
+}
+
+void
+HTMLSlotElement::EnqueueSlotChangeEvent() const
+{
+ DocGroup* docGroup = OwnerDoc()->GetDocGroup();
+ if (!docGroup) {
+ return;
+ }
+
+ docGroup->SignalSlotChange(this);
+}
+
+void
+HTMLSlotElement::FireSlotChangeEvent()
+{
+ nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
+ static_cast<nsIContent*>(this),
+ NS_LITERAL_STRING("slotchange"), true,
+ false);
+}
+
+JSObject*
+HTMLSlotElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return HTMLSlotElementBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace dom
+} // namespace mozilla
diff --git a/dom/html/HTMLSlotElement.h b/dom/html/HTMLSlotElement.h
new file mode 100644
index 000000000..0494a654e
--- /dev/null
+++ b/dom/html/HTMLSlotElement.h
@@ -0,0 +1,79 @@
+/* -*- 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 mozilla_dom_HTMLSlotElement_h
+#define mozilla_dom_HTMLSlotElement_h
+
+#include "nsIDOMHTMLElement.h"
+#include "nsGenericHTMLElement.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+struct AssignedNodesOptions;
+
+class HTMLSlotElement final : public nsGenericHTMLElement
+{
+public:
+ explicit HTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
+ NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLSlotElement, slot)
+
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
+ virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const override;
+
+ // nsIContent
+ virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+ nsIContent* aBindingParent,
+ bool aCompileEventHandlers) override;
+ virtual void UnbindFromTree(bool aDeep = true,
+ bool aNullParent = true) override;
+
+ virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify) override;
+ virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
+
+ // WebIDL
+ void SetName(const nsAString& aName, ErrorResult& aRv)
+ {
+ SetHTMLAttr(nsGkAtoms::name, aName, aRv);
+ }
+
+ void GetName(nsAString& aName)
+ {
+ GetHTMLAttr(nsGkAtoms::name, aName);
+ }
+
+ void AssignedNodes(const AssignedNodesOptions& aOptions,
+ nsTArray<RefPtr<nsINode>>& aNodes);
+
+ // Helper methods
+ const nsTArray<RefPtr<nsINode>>& AssignedNodes() const;
+ void InsertAssignedNode(uint32_t aIndex, nsINode* aNode);
+ void AppendAssignedNode(nsINode* aNode);
+ void RemoveAssignedNode(nsINode* aNode);
+ void ClearAssignedNodes();
+
+ void EnqueueSlotChangeEvent() const;
+ void FireSlotChangeEvent();
+
+protected:
+ virtual ~HTMLSlotElement();
+ virtual JSObject*
+ WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+ nsTArray<RefPtr<nsINode>> mAssignedNodes;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_HTMLSlotElement_h
diff --git a/dom/html/HTMLSourceElement.cpp b/dom/html/HTMLSourceElement.cpp
index 73d9c9d8c..93a17ea8c 100644
--- a/dom/html/HTMLSourceElement.cpp
+++ b/dom/html/HTMLSourceElement.cpp
@@ -98,7 +98,8 @@ HTMLSourceElement::UpdateMediaList(const nsAttrValue* aValue)
nsresult
HTMLSourceElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
// If we are associated with a <picture> with a valid <img>, notify it of
// responsive parameter changes
@@ -143,7 +144,7 @@ HTMLSourceElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
nsresult
diff --git a/dom/html/HTMLSourceElement.h b/dom/html/HTMLSourceElement.h
index 595e21015..71b676c2c 100644
--- a/dom/html/HTMLSourceElement.h
+++ b/dom/html/HTMLSourceElement.h
@@ -110,6 +110,7 @@ protected:
protected:
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
bool aNotify) override;
private:
diff --git a/dom/html/HTMLStyleElement.cpp b/dom/html/HTMLStyleElement.cpp
index 329dda648..743f4addb 100644
--- a/dom/html/HTMLStyleElement.cpp
+++ b/dom/html/HTMLStyleElement.cpp
@@ -171,7 +171,8 @@ HTMLStyleElement::UnbindFromTree(bool aDeep, bool aNullParent)
nsresult
HTMLStyleElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::title ||
@@ -185,7 +186,7 @@ HTMLStyleElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
NS_IMETHODIMP
diff --git a/dom/html/HTMLStyleElement.h b/dom/html/HTMLStyleElement.h
index 6b2a12b1f..bd69a6aa1 100644
--- a/dom/html/HTMLStyleElement.h
+++ b/dom/html/HTMLStyleElement.h
@@ -48,6 +48,7 @@ public:
bool aNullParent = true) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
diff --git a/dom/html/HTMLTableCellElement.cpp b/dom/html/HTMLTableCellElement.cpp
index 1cf413413..e8b338342 100644
--- a/dom/html/HTMLTableCellElement.cpp
+++ b/dom/html/HTMLTableCellElement.cpp
@@ -107,9 +107,7 @@ HTMLTableCellElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
nsresult rv = nsGenericHTMLElement::WalkContentStyleRules(aRuleWalker);
NS_ENSURE_SUCCESS(rv, rv);
- if (HTMLTableElement* table = GetTable()) {
- nsMappedAttributes* tableInheritedAttributes =
- table->GetAttributesMappedForCell();
+ if (nsMappedAttributes* tableInheritedAttributes = GetMappedAttributesInheritedFromTable()) {
if (tableInheritedAttributes) {
aRuleWalker->Forward(tableInheritedAttributes);
}
@@ -117,6 +115,16 @@ HTMLTableCellElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
return NS_OK;
}
+nsMappedAttributes*
+HTMLTableCellElement::GetMappedAttributesInheritedFromTable() const
+{
+ if (HTMLTableElement* table = GetTable()) {
+ return table->GetAttributesMappedForCell();
+ }
+
+ return nullptr;
+}
+
NS_IMETHODIMP
HTMLTableCellElement::SetAbbr(const nsAString& aAbbr)
{
diff --git a/dom/html/HTMLTableCellElement.h b/dom/html/HTMLTableCellElement.h
index ab7a918eb..6740b870e 100644
--- a/dom/html/HTMLTableCellElement.h
+++ b/dom/html/HTMLTableCellElement.h
@@ -148,6 +148,8 @@ public:
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
+ // Get mapped attributes of ancestor table, if any
+ nsMappedAttributes* GetMappedAttributesInheritedFromTable() const;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
diff --git a/dom/html/HTMLTableElement.cpp b/dom/html/HTMLTableElement.cpp
index c5b7696cf..e6aa71e51 100644
--- a/dom/html/HTMLTableElement.cpp
+++ b/dom/html/HTMLTableElement.cpp
@@ -322,7 +322,7 @@ TableRowsCollection::ParentDestroyed()
HTMLTableElement::HTMLTableElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo),
- mTableInheritedAttributes(TABLE_ATTRS_DIRTY)
+ mTableInheritedAttributes(nullptr)
{
SetHasWeirdParserInsertionMode();
}
@@ -912,20 +912,15 @@ MapInheritedTableAttributesIntoRule(const nsMappedAttributes* aAttributes,
nsMappedAttributes*
HTMLTableElement::GetAttributesMappedForCell()
{
- if (mTableInheritedAttributes) {
- if (mTableInheritedAttributes == TABLE_ATTRS_DIRTY)
- BuildInheritedAttributes();
- if (mTableInheritedAttributes != TABLE_ATTRS_DIRTY)
- return mTableInheritedAttributes;
- }
- return nullptr;
+ return mTableInheritedAttributes;
}
void
HTMLTableElement::BuildInheritedAttributes()
{
- NS_ASSERTION(mTableInheritedAttributes == TABLE_ATTRS_DIRTY,
+ NS_ASSERTION(!mTableInheritedAttributes,
"potential leak, plus waste of work");
+ MOZ_ASSERT(NS_IsMainThread());
nsIDocument *document = GetComposedDoc();
nsHTMLStyleSheet* sheet = document ?
document->GetAttributeStyleSheet() : nullptr;
@@ -938,7 +933,9 @@ HTMLTableElement::BuildInheritedAttributes()
if (modifiableMapped) {
nsAttrValue val(*value);
- modifiableMapped->SetAndTakeAttr(nsGkAtoms::cellpadding, val);
+ bool oldValueSet;
+ modifiableMapped->SetAndSwapAttr(nsGkAtoms::cellpadding, val,
+ &oldValueSet);
}
newAttrs = sheet->UniqueMappedAttributes(modifiableMapped);
NS_ASSERTION(newAttrs, "out of memory, but handling gracefully");
@@ -960,10 +957,7 @@ HTMLTableElement::BuildInheritedAttributes()
void
HTMLTableElement::ReleaseInheritedAttributes()
{
- if (mTableInheritedAttributes &&
- mTableInheritedAttributes != TABLE_ATTRS_DIRTY)
- NS_RELEASE(mTableInheritedAttributes);
- mTableInheritedAttributes = TABLE_ATTRS_DIRTY;
+ NS_IF_RELEASE(mTableInheritedAttributes);
}
nsresult
@@ -972,9 +966,12 @@ HTMLTableElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
bool aCompileEventHandlers)
{
ReleaseInheritedAttributes();
- return nsGenericHTMLElement::BindToTree(aDocument, aParent,
- aBindingParent,
- aCompileEventHandlers);
+ nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
+ aBindingParent,
+ aCompileEventHandlers);
+ NS_ENSURE_SUCCESS(rv, rv);
+ BuildInheritedAttributes();
+ return NS_OK;
}
void
@@ -986,7 +983,7 @@ HTMLTableElement::UnbindFromTree(bool aDeep, bool aNullParent)
nsresult
HTMLTableElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify)
{
if (aName == nsGkAtoms::cellpadding && aNameSpaceID == kNameSpaceID_None) {
@@ -999,13 +996,13 @@ HTMLTableElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsresult
HTMLTableElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
- bool aNotify)
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aName == nsGkAtoms::cellpadding && aNameSpaceID == kNameSpaceID_None) {
BuildInheritedAttributes();
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
} // namespace dom
diff --git a/dom/html/HTMLTableElement.h b/dom/html/HTMLTableElement.h
index 4e172964b..ce9d224b9 100644
--- a/dom/html/HTMLTableElement.h
+++ b/dom/html/HTMLTableElement.h
@@ -14,8 +14,6 @@
namespace mozilla {
namespace dom {
-#define TABLE_ATTRS_DIRTY ((nsMappedAttributes*)0x1)
-
class TableRowsCollection;
class HTMLTableElement final : public nsGenericHTMLElement
@@ -190,13 +188,15 @@ public:
* Called when an attribute is about to be changed
*/
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify) override;
/**
* Called when an attribute has just been changed
*/
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLTableElement,
nsGenericHTMLElement)
@@ -220,8 +220,6 @@ protected:
RefPtr<nsContentList> mTBodies;
RefPtr<TableRowsCollection> mRows;
- // Sentinel value of TABLE_ATTRS_DIRTY indicates that this is dirty and needs
- // to be recalculated.
nsMappedAttributes *mTableInheritedAttributes;
void BuildInheritedAttributes();
void ReleaseInheritedAttributes();
diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp
index 42bc02435..f25241d60 100644
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -506,7 +506,7 @@ HTMLTextAreaElement::IsDisabledForEvents(EventMessage aMessage)
}
nsresult
-HTMLTextAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLTextAreaElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = false;
if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
@@ -534,11 +534,22 @@ HTMLTextAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
aVisitor.mEvent->mFlags.mNoContentDispatch = false;
}
- // Fire onchange (if necessary), before we do the blur, bug 370521.
if (aVisitor.mEvent->mMessage == eBlur) {
- FireChangeEventIfNeeded();
+ // Set mWantsPreHandleEvent and fire change event in PreHandleEvent to
+ // prevent it breaks event target chain creation.
+ aVisitor.mWantsPreHandleEvent = true;
}
+ return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
+}
+
+nsresult
+HTMLTextAreaElement::PreHandleEvent(EventChainVisitor& aVisitor)
+{
+ if (aVisitor.mEvent->mMessage == eBlur) {
+ // Fire onchange (if necessary), before we do the blur, bug 370521.
+ FireChangeEventIfNeeded();
+ }
return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
}
@@ -1275,7 +1286,7 @@ HTMLTextAreaElement::UnbindFromTree(bool aDeep, bool aNullParent)
nsresult
HTMLTextAreaElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify)
{
if (aNotify && aName == nsGkAtoms::disabled &&
@@ -1337,7 +1348,8 @@ HTMLTextAreaElement::ContentChanged(nsIContent* aContent)
nsresult
HTMLTextAreaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
@@ -1353,12 +1365,10 @@ HTMLTextAreaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
} else if (aName == nsGkAtoms::minlength) {
UpdateTooShortValidityState();
}
-
- UpdateState(aNotify);
}
return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
nsresult
diff --git a/dom/html/HTMLTextAreaElement.h b/dom/html/HTMLTextAreaElement.h
index 039082818..5ab58554e 100644
--- a/dom/html/HTMLTextAreaElement.h
+++ b/dom/html/HTMLTextAreaElement.h
@@ -125,7 +125,9 @@ public:
int32_t aModType) const override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
+ virtual nsresult PreHandleEvent(EventChainVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
@@ -142,7 +144,7 @@ public:
* Called when an attribute is about to be changed
*/
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify) override;
// nsIMutationObserver
@@ -355,7 +357,9 @@ protected:
void ContentChanged(nsIContent* aContent);
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom *aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
/**
* Return if an element should have a specific validity UI
diff --git a/dom/html/HTMLUnknownElement.h b/dom/html/HTMLUnknownElement.h
index c77fba919..6390cc576 100644
--- a/dom/html/HTMLUnknownElement.h
+++ b/dom/html/HTMLUnknownElement.h
@@ -7,6 +7,7 @@
#define mozilla_dom_HTMLUnknownElement_h
#include "mozilla/Attributes.h"
+#include "mozilla/EventStates.h"
#include "nsGenericHTMLElement.h"
namespace mozilla {
@@ -27,7 +28,7 @@ public:
: nsGenericHTMLElement(aNodeInfo)
{
if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
- SetHasDirAuto();
+ AddStatesSilently(NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO);
}
}
diff --git a/dom/html/moz.build b/dom/html/moz.build
index c86c169b5..342b027a5 100644
--- a/dom/html/moz.build
+++ b/dom/html/moz.build
@@ -52,7 +52,6 @@ EXPORTS.mozilla.dom += [
'HTMLBRElement.h',
'HTMLButtonElement.h',
'HTMLCanvasElement.h',
- 'HTMLContentElement.h',
'HTMLDataElement.h',
'HTMLDataListElement.h',
'HTMLDetailsElement.h',
@@ -92,10 +91,10 @@ EXPORTS.mozilla.dom += [
'HTMLProgressElement.h',
'HTMLScriptElement.h',
'HTMLSelectElement.h',
- 'HTMLShadowElement.h',
'HTMLSharedElement.h',
'HTMLSharedListElement.h',
'HTMLSharedObjectElement.h',
+ 'HTMLSlotElement.h',
'HTMLSourceElement.h',
'HTMLSpanElement.h',
'HTMLStyleElement.h',
@@ -131,7 +130,6 @@ UNIFIED_SOURCES += [
'HTMLBRElement.cpp',
'HTMLButtonElement.cpp',
'HTMLCanvasElement.cpp',
- 'HTMLContentElement.cpp',
'HTMLDataElement.cpp',
'HTMLDataListElement.cpp',
'HTMLDetailsElement.cpp',
@@ -172,10 +170,10 @@ UNIFIED_SOURCES += [
'HTMLProgressElement.cpp',
'HTMLScriptElement.cpp',
'HTMLSelectElement.cpp',
- 'HTMLShadowElement.cpp',
'HTMLSharedElement.cpp',
'HTMLSharedListElement.cpp',
'HTMLSharedObjectElement.cpp',
+ 'HTMLSlotElement.cpp',
'HTMLSourceElement.cpp',
'HTMLSpanElement.cpp',
'HTMLStyleElement.cpp',
diff --git a/dom/html/nsDOMStringMap.cpp b/dom/html/nsDOMStringMap.cpp
index 6d2bc424d..7e2ed0ece 100644
--- a/dom/html/nsDOMStringMap.cpp
+++ b/dom/html/nsDOMStringMap.cpp
@@ -62,6 +62,12 @@ nsDOMStringMap::~nsDOMStringMap()
}
}
+DocGroup*
+nsDOMStringMap::GetDocGroup() const
+{
+ return mElement ? mElement->GetDocGroup() : nullptr;
+}
+
/* virtual */
JSObject*
nsDOMStringMap::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
diff --git a/dom/html/nsDOMStringMap.h b/dom/html/nsDOMStringMap.h
index bf28957f7..6506f1464 100644
--- a/dom/html/nsDOMStringMap.h
+++ b/dom/html/nsDOMStringMap.h
@@ -16,6 +16,9 @@
namespace mozilla {
class ErrorResult;
+namespace dom {
+class DocGroup;
+} // namespace dom
} // namespace mozilla
class nsDOMStringMap : public nsStubMutationObserver,
@@ -32,6 +35,8 @@ public:
return mElement;
}
+ mozilla::dom::DocGroup* GetDocGroup() const;
+
explicit nsDOMStringMap(mozilla::dom::Element* aElement);
// WebIDL API
diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp
index 78e4d5b95..3cf19ea8f 100644
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -607,16 +607,16 @@ nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(
}
nsresult
-nsGenericHTMLElement::PreHandleEventForAnchors(EventChainPreVisitor& aVisitor)
+nsGenericHTMLElement::GetEventTargetParentForAnchors(EventChainPreVisitor& aVisitor)
{
- nsresult rv = nsGenericHTMLElementBase::PreHandleEvent(aVisitor);
+ nsresult rv = nsGenericHTMLElementBase::GetEventTargetParent(aVisitor);
NS_ENSURE_SUCCESS(rv, rv);
if (!CheckHandleEventForAnchorsPreconditions(aVisitor)) {
return NS_OK;
}
- return PreHandleEventForLinks(aVisitor);
+ return GetEventTargetParentForLinks(aVisitor);
}
nsresult
@@ -655,8 +655,46 @@ nsGenericHTMLElement::GetHrefURIForAnchors() const
}
nsresult
+nsGenericHTMLElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::accesskey) {
+ // Have to unregister before clearing flag. See UnregAccessKey
+ UnregAccessKey();
+ if (!aValue) {
+ UnsetFlags(NODE_HAS_ACCESSKEY);
+ }
+ } else if (aName == nsGkAtoms::name) {
+ // Have to do this before clearing flag. See RemoveFromNameTable
+ RemoveFromNameTable();
+ if (!aValue || aValue->IsEmpty()) {
+ ClearHasName();
+ }
+ } else if (aName == nsGkAtoms::contenteditable) {
+ if (aValue) {
+ // Set this before the attribute is set so that any subclass code that
+ // runs before the attribute is set won't think we're missing a
+ // contenteditable attr when we actually have one.
+ SetMayHaveContentEditableAttr();
+ }
+ }
+ if (!aValue && IsEventAttributeName(aName)) {
+ if (EventListenerManager* manager = GetExistingListenerManager()) {
+ manager->RemoveEventHandler(aName, EmptyString());
+ }
+ }
+ }
+
+ return nsGenericHTMLElementBase::BeforeSetAttr(aNamespaceID, aName, aValue,
+ aNotify);
+}
+
+nsresult
nsGenericHTMLElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNamespaceID == kNameSpaceID_None) {
if (IsEventAttributeName(aName) && aValue) {
@@ -670,34 +708,83 @@ nsGenericHTMLElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
}
else if (aName == nsGkAtoms::dir) {
Directionality dir = eDir_LTR;
+ // A boolean tracking whether we need to recompute our directionality.
+ // This needs to happen after we update our internal "dir" attribute
+ // state but before we call SetDirectionalityOnDescendants.
+ bool recomputeDirectionality = false;
+ // We don't want to have to keep getting the "dir" attribute in
+ // IntrinsicState, so we manually recompute our dir-related event states
+ // here and send the relevant update notifications.
+ EventStates dirStates;
if (aValue && aValue->Type() == nsAttrValue::eEnum) {
SetHasValidDir();
+ dirStates |= NS_EVENT_STATE_HAS_DIR_ATTR;
Directionality dirValue = (Directionality)aValue->GetEnumValue();
if (dirValue == eDir_Auto) {
- SetHasDirAuto();
- ClearHasFixedDir();
+ dirStates |= NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO;
} else {
dir = dirValue;
SetDirectionality(dir, aNotify);
- ClearHasDirAuto();
- SetHasFixedDir();
+ if (dirValue == eDir_LTR) {
+ dirStates |= NS_EVENT_STATE_DIR_ATTR_LTR;
+ } else {
+ MOZ_ASSERT(dirValue == eDir_RTL);
+ dirStates |= NS_EVENT_STATE_DIR_ATTR_RTL;
+ }
}
} else {
+ if (aValue) {
+ // We have a value, just not a valid one.
+ dirStates |= NS_EVENT_STATE_HAS_DIR_ATTR;
+ }
ClearHasValidDir();
- ClearHasFixedDir();
if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
- SetHasDirAuto();
+ dirStates |= NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO;
} else {
- ClearHasDirAuto();
- dir = RecomputeDirectionality(this, aNotify);
+ recomputeDirectionality = true;
}
}
+ // Now figure out what's changed about our dir states.
+ EventStates oldDirStates = State() & DIR_ATTR_STATES;
+ EventStates changedStates = dirStates ^ oldDirStates;
+ ToggleStates(changedStates, aNotify);
+ if (recomputeDirectionality) {
+ dir = RecomputeDirectionality(this, aNotify);
+ }
SetDirectionalityOnDescendants(this, dir, aNotify);
+ } else if (aName == nsGkAtoms::contenteditable) {
+ int32_t editableCountDelta = 0;
+ if (aOldValue &&
+ (aOldValue->Equals(NS_LITERAL_STRING("true"), eIgnoreCase) ||
+ aOldValue->Equals(EmptyString(), eIgnoreCase))) {
+ editableCountDelta = -1;
+ }
+ if (aValue && (aValue->Equals(NS_LITERAL_STRING("true"), eIgnoreCase) ||
+ aValue->Equals(EmptyString(), eIgnoreCase))) {
+ ++editableCountDelta;
+ }
+ ChangeEditableState(editableCountDelta);
+ } else if (aName == nsGkAtoms::accesskey) {
+ if (aValue && !aValue->Equals(EmptyString(), eIgnoreCase)) {
+ SetFlags(NODE_HAS_ACCESSKEY);
+ RegAccessKey();
+ }
+ } else if (aName == nsGkAtoms::name) {
+ if (aValue && !aValue->Equals(EmptyString(), eIgnoreCase) &&
+ CanHaveName(NodeInfo()->NameAtom())) {
+ // This may not be quite right because we can have subclass code run
+ // before here. But in practice subclasses don't care about this flag,
+ // and in particular selector matching does not care. Otherwise we'd
+ // want to handle it like we handle id attributes (in PreIdMaybeChange
+ // and PostIdMaybeChange).
+ SetHasName();
+ AddToNameTable(aValue->GetAtomValue());
+ }
}
}
return nsGenericHTMLElementBase::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
EventListenerManager*
@@ -818,87 +905,6 @@ nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler) \
#undef FORWARDED_EVENT
#undef EVENT
-nsresult
-nsGenericHTMLElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
-{
- bool contentEditable = aNameSpaceID == kNameSpaceID_None &&
- aName == nsGkAtoms::contenteditable;
- bool accessKey = aName == nsGkAtoms::accesskey &&
- aNameSpaceID == kNameSpaceID_None;
-
- int32_t change = 0;
- if (contentEditable) {
- change = GetContentEditableValue() == eTrue ? -1 : 0;
- SetMayHaveContentEditableAttr();
- }
-
- if (accessKey) {
- UnregAccessKey();
- }
-
- nsresult rv = nsStyledElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
- aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (contentEditable) {
- if (aValue.IsEmpty() || aValue.LowerCaseEqualsLiteral("true")) {
- change += 1;
- }
-
- ChangeEditableState(change);
- }
-
- if (accessKey && !aValue.IsEmpty()) {
- SetFlags(NODE_HAS_ACCESSKEY);
- RegAccessKey();
- }
-
- return NS_OK;
-}
-
-nsresult
-nsGenericHTMLElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify)
-{
- bool contentEditable = false;
- int32_t contentEditableChange = 0;
-
- // Check for event handlers
- if (aNameSpaceID == kNameSpaceID_None) {
- if (aAttribute == nsGkAtoms::name) {
- // Have to do this before clearing flag. See RemoveFromNameTable
- RemoveFromNameTable();
- ClearHasName();
- }
- else if (aAttribute == nsGkAtoms::contenteditable) {
- contentEditable = true;
- contentEditableChange = GetContentEditableValue() == eTrue ? -1 : 0;
- }
- else if (aAttribute == nsGkAtoms::accesskey) {
- // Have to unregister before clearing flag. See UnregAccessKey
- UnregAccessKey();
- UnsetFlags(NODE_HAS_ACCESSKEY);
- }
- else if (IsEventAttributeName(aAttribute)) {
- if (EventListenerManager* manager = GetExistingListenerManager()) {
- manager->RemoveEventHandler(aAttribute, EmptyString());
- }
- }
- }
-
- nsresult rv = nsGenericHTMLElementBase::UnsetAttr(aNameSpaceID, aAttribute,
- aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (contentEditable) {
- ChangeEditableState(contentEditableChange);
- }
-
- return NS_OK;
-}
-
void
nsGenericHTMLElement::GetBaseTarget(nsAString& aBaseTarget) const
{
@@ -928,19 +934,13 @@ nsGenericHTMLElement::ParseAttribute(int32_t aNamespaceID,
if (aAttribute == nsGkAtoms::name) {
// Store name as an atom. name="" means that the element has no name,
- // not that it has an emptystring as the name.
- RemoveFromNameTable();
+ // not that it has an empty string as the name.
if (aValue.IsEmpty()) {
ClearHasName();
return false;
}
aResult.ParseAtom(aValue);
-
- if (CanHaveName(NodeInfo()->NameAtom())) {
- SetHasName();
- AddToNameTable(aResult.GetAtomValue());
- }
return true;
}
@@ -1962,7 +1962,7 @@ nsGenericHTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
nsresult
nsGenericHTMLFormElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
@@ -1995,13 +1995,6 @@ nsGenericHTMLFormElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
mForm->RemoveElement(this, false);
-
- // Removing the element from the form can make it not be the default
- // control anymore. Go ahead and notify on that change, though we might
- // end up readding and becoming the default control again in
- // AfterSetAttr.
- // FIXME: Bug 656197
- UpdateState(aNotify);
}
if (aName == nsGkAtoms::form) {
@@ -2022,7 +2015,8 @@ nsGenericHTMLFormElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsresult
nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
// add the control to the hashtable as needed
@@ -2051,12 +2045,6 @@ nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
mForm->AddElement(this, false, aNotify);
-
- // Adding the element to the form can make it be the default control .
- // Go ahead and notify on that change.
- // Note: no need to notify on CanBeDisabled(), since type attr
- // changes can't affect that.
- UpdateState(aNotify);
}
if (aName == nsGkAtoms::form) {
@@ -2077,11 +2065,23 @@ nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
+}
+
+nsresult
+nsGenericHTMLFormElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
+{
+ if (aVisitor.mEvent->IsTrusted() && (aVisitor.mEvent->mMessage == eFocus ||
+ aVisitor.mEvent->mMessage == eBlur)) {
+ // We have to handle focus/blur event to change focus states in
+ // PreHandleEvent to prevent it breaks event target chain creation.
+ aVisitor.mWantsPreHandleEvent = true;
+ }
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
nsresult
-nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsGenericHTMLFormElement::PreHandleEvent(EventChainVisitor& aVisitor)
{
if (aVisitor.mEvent->IsTrusted()) {
switch (aVisitor.mEvent->mMessage) {
@@ -2105,7 +2105,6 @@ nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
break;
}
}
-
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
}
diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h
index 2b8b608b9..1b0977fa2 100644
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -465,17 +465,6 @@ public:
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
- MOZ_ALWAYS_INLINE // Avoid a crashy hook from Avast 10 Beta
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- bool aNotify) override;
virtual bool IsFocusableInternal(int32_t *aTabIndex, bool aWithMouse) override
{
bool isFocusable = false;
@@ -498,7 +487,8 @@ public:
*/
bool CheckHandleEventForAnchorsPreconditions(
mozilla::EventChainVisitor& aVisitor);
- nsresult PreHandleEventForAnchors(mozilla::EventChainPreVisitor& aVisitor);
+ nsresult GetEventTargetParentForAnchors(
+ mozilla::EventChainPreVisitor& aVisitor);
nsresult PostHandleEventForAnchors(mozilla::EventChainPostVisitor& aVisitor);
bool IsHTMLLink(nsIURI** aURI) const;
@@ -913,8 +903,13 @@ private:
void RegUnRegAccessKey(bool aDoReg);
protected:
+ virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual mozilla::EventListenerManager*
GetEventListenerManagerForAttr(nsIAtom* aAttrName,
@@ -1219,8 +1214,10 @@ public:
virtual IMEState GetDesiredIMEState() override;
virtual mozilla::EventStates IntrinsicState() const override;
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
+ virtual nsresult PreHandleEvent(
+ mozilla::EventChainVisitor& aVisitor) override;
/**
* This callback is called by a fieldest on all its elements whenever its
@@ -1260,11 +1257,13 @@ protected:
virtual ~nsGenericHTMLFormElement();
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
/**
* This method will update the form owner, using @form or looking to a parent.
@@ -1305,7 +1304,7 @@ protected:
static bool FormIdUpdated(Element* aOldElement, Element* aNewElement,
void* aData);
- // Returns true if the event should not be handled from PreHandleEvent
+ // Returns true if the event should not be handled from GetEventTargetParent
bool IsElementDisabledForEvents(mozilla::EventMessage aMessage,
nsIFrame* aFrame);
@@ -1701,7 +1700,7 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(Pre)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Progress)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Script)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Select)
-NS_DECLARE_NS_NEW_HTML_ELEMENT(Shadow)
+NS_DECLARE_NS_NEW_HTML_ELEMENT(Slot)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Source)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Span)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Style)
diff --git a/dom/html/nsGenericHTMLFrameElement.cpp b/dom/html/nsGenericHTMLFrameElement.cpp
index 6e50a4092..8170179e2 100644
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -27,6 +27,7 @@
#include "nsServiceManagerUtils.h"
#include "nsSubDocumentFrame.h"
#include "nsXULElement.h"
+#include "nsAttrValueOrString.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -334,55 +335,6 @@ nsGenericHTMLFrameElement::UnbindFromTree(bool aDeep, bool aNullParent)
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
}
-nsresult
-nsGenericHTMLFrameElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
-{
- nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
- aValue, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src &&
- (!IsHTMLElement(nsGkAtoms::iframe) ||
- !HasAttr(kNameSpaceID_None,nsGkAtoms::srcdoc))) {
- // Don't propagate error here. The attribute was successfully set, that's
- // what we should reflect.
- LoadSrc();
- } else if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::name) {
- // Propagate "name" to the docshell to make browsing context names live,
- // per HTML5.
- nsIDocShell *docShell = mFrameLoader ? mFrameLoader->GetExistingDocShell()
- : nullptr;
- if (docShell) {
- docShell->SetName(aValue);
- }
- }
-
- return NS_OK;
-}
-
-nsresult
-nsGenericHTMLFrameElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify)
-{
- // Invoke on the superclass.
- nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::name) {
- // Propagate "name" to the docshell to make browsing context names live,
- // per HTML5.
- nsIDocShell *docShell = mFrameLoader ? mFrameLoader->GetExistingDocShell()
- : nullptr;
- if (docShell) {
- docShell->SetName(EmptyString());
- }
- }
-
- return NS_OK;
-}
-
/* static */ int32_t
nsGenericHTMLFrameElement::MapScrollingAttribute(const nsAttrValue* aValue)
{
@@ -399,37 +351,102 @@ nsGenericHTMLFrameElement::MapScrollingAttribute(const nsAttrValue* aValue)
return mappedValue;
}
+static bool
+PrincipalAllowsBrowserFrame(nsIPrincipal* aPrincipal)
+{
+ nsCOMPtr<nsIPermissionManager> permMgr = mozilla::services::GetPermissionManager();
+ NS_ENSURE_TRUE(permMgr, false);
+ uint32_t permission = nsIPermissionManager::DENY_ACTION;
+ nsresult rv = permMgr->TestPermissionFromPrincipal(aPrincipal, "browser", &permission);
+ NS_ENSURE_SUCCESS(rv, false);
+ return permission == nsIPermissionManager::ALLOW_ACTION;
+}
+
/* virtual */ nsresult
nsGenericHTMLFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
- bool aNotify)
-{
- if (aName == nsGkAtoms::scrolling && aNameSpaceID == kNameSpaceID_None) {
- if (mFrameLoader) {
- nsIDocShell* docshell = mFrameLoader->GetExistingDocShell();
- nsCOMPtr<nsIScrollable> scrollable = do_QueryInterface(docshell);
- if (scrollable) {
- int32_t cur;
- scrollable->GetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, &cur);
- int32_t val = MapScrollingAttribute(aValue);
- if (cur != val) {
- scrollable->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, val);
- scrollable->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y, val);
- RefPtr<nsPresContext> presContext;
- docshell->GetPresContext(getter_AddRefs(presContext));
- nsIPresShell* shell = presContext ? presContext->GetPresShell() : nullptr;
- nsIFrame* rootScroll = shell ? shell->GetRootScrollFrame() : nullptr;
- if (rootScroll) {
- shell->FrameNeedsReflow(rootScroll, nsIPresShell::eStyleChange,
- NS_FRAME_IS_DIRTY);
+ const nsAttrValue* aOldValue, bool aNotify)
+{
+ if (aValue) {
+ nsAttrValueOrString value(aValue);
+ AfterMaybeChangeAttr(aNameSpaceID, aName, &value, aNotify);
+ } else {
+ AfterMaybeChangeAttr(aNameSpaceID, aName, nullptr, aNotify);
+ }
+
+ if (aNameSpaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::scrolling) {
+ if (mFrameLoader) {
+ nsIDocShell* docshell = mFrameLoader->GetExistingDocShell();
+ nsCOMPtr<nsIScrollable> scrollable = do_QueryInterface(docshell);
+ if (scrollable) {
+ int32_t cur;
+ scrollable->GetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, &cur);
+ int32_t val = MapScrollingAttribute(aValue);
+ if (cur != val) {
+ scrollable->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, val);
+ scrollable->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y, val);
+ RefPtr<nsPresContext> presContext;
+ docshell->GetPresContext(getter_AddRefs(presContext));
+ nsIPresShell* shell = presContext ? presContext->GetPresShell() : nullptr;
+ nsIFrame* rootScroll = shell ? shell->GetRootScrollFrame() : nullptr;
+ if (rootScroll) {
+ shell->FrameNeedsReflow(rootScroll, nsIPresShell::eStyleChange,
+ NS_FRAME_IS_DIRTY);
+ }
}
}
}
+ } else if (aName == nsGkAtoms::mozbrowser) {
+ mReallyIsBrowser = !!aValue && BrowserFramesEnabled() &&
+ PrincipalAllowsBrowserFrame(NodePrincipal());
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
+}
+
+nsresult
+nsGenericHTMLFrameElement::OnAttrSetButNotChanged(int32_t aNamespaceID,
+ nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify)
+{
+ AfterMaybeChangeAttr(aNamespaceID, aName, &aValue, aNotify);
+
+ return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
+ aValue, aNotify);
+}
+
+void
+nsGenericHTMLFrameElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
+ nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify)
+{
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::src) {
+ if (aValue && (!IsHTMLElement(nsGkAtoms::iframe) ||
+ !HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc))) {
+ // Don't propagate error here. The attribute was successfully set,
+ // that's what we should reflect.
+ LoadSrc();
+ }
+ } else if (aName == nsGkAtoms::name) {
+ // Propagate "name" to the docshell to make browsing context names live,
+ // per HTML5.
+ nsIDocShell* docShell = mFrameLoader ? mFrameLoader->GetExistingDocShell()
+ : nullptr;
+ if (docShell) {
+ if (aValue) {
+ docShell->SetName(aValue->String());
+ } else {
+ docShell->SetName(EmptyString());
+ }
+ }
+ }
+ }
}
void
@@ -503,28 +520,7 @@ nsGenericHTMLFrameElement::BrowserFramesEnabled()
/* [infallible] */ nsresult
nsGenericHTMLFrameElement::GetReallyIsBrowserOrApp(bool *aOut)
{
- *aOut = false;
-
- // Fail if browser frames are globally disabled.
- if (!nsGenericHTMLFrameElement::BrowserFramesEnabled()) {
- return NS_OK;
- }
-
- // Fail if this frame doesn't have the mozbrowser attribute.
- if (!GetBoolAttr(nsGkAtoms::mozbrowser)) {
- return NS_OK;
- }
-
- // Fail if the node principal isn't trusted.
- nsIPrincipal *principal = NodePrincipal();
- nsCOMPtr<nsIPermissionManager> permMgr =
- services::GetPermissionManager();
- NS_ENSURE_TRUE(permMgr, NS_OK);
-
- uint32_t permission = nsIPermissionManager::DENY_ACTION;
- nsresult rv = permMgr->TestPermissionFromPrincipal(principal, "browser", &permission);
- NS_ENSURE_SUCCESS(rv, NS_OK);
- *aOut = permission == nsIPermissionManager::ALLOW_ACTION;
+ *aOut = mReallyIsBrowser;
return NS_OK;
}
diff --git a/dom/html/nsGenericHTMLFrameElement.h b/dom/html/nsGenericHTMLFrameElement.h
index d9c2df9d5..adcd17715 100644
--- a/dom/html/nsGenericHTMLFrameElement.h
+++ b/dom/html/nsGenericHTMLFrameElement.h
@@ -36,6 +36,7 @@ public:
, mIsPrerendered(false)
, mBrowserFrameListenersRegistered(false)
, mFrameLoaderCreationDisallowed(false)
+ , mReallyIsBrowser(false)
{
}
@@ -52,19 +53,7 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify) override;
- virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue,
- bool aNotify) override;
+
virtual void DestroyContent() override;
nsresult CopyInnerTo(mozilla::dom::Element* aDest);
@@ -109,6 +98,14 @@ protected:
nsresult GetContentDocument(nsIDOMDocument** aContentDocument);
already_AddRefed<nsPIDOMWindowOuter> GetContentWindow();
+ virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
+ virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify) override;
+
RefPtr<nsFrameLoader> mFrameLoader;
nsCOMPtr<nsPIDOMWindowOuter> mOpenerWindow;
@@ -122,6 +119,7 @@ protected:
bool mIsPrerendered;
bool mBrowserFrameListenersRegistered;
bool mFrameLoaderCreationDisallowed;
+ bool mReallyIsBrowser;
// This flag is only used by <iframe>. See HTMLIFrameElement::
// FullscreenFlag() for details. It is placed here so that we
@@ -130,6 +128,18 @@ protected:
private:
void GetManifestURL(nsAString& aOut);
+
+ /**
+ * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
+ * It will be called whether the value is being set or unset.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aValue the value being set or null if the value is being unset
+ * @param aNotify Whether we plan to notify document observers.
+ */
+ void AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue, bool aNotify);
};
#endif // nsGenericHTMLFrameElement_h
diff --git a/dom/html/nsHTMLContentSink.cpp b/dom/html/nsHTMLContentSink.cpp
index 1fe5d2a86..eb22b772f 100644
--- a/dom/html/nsHTMLContentSink.cpp
+++ b/dom/html/nsHTMLContentSink.cpp
@@ -14,6 +14,7 @@
#include "nsContentSink.h"
#include "nsCOMPtr.h"
+#include "nsHTMLTags.h"
#include "nsReadableUtils.h"
#include "nsUnicharUtils.h"
#include "nsIHTMLContentSink.h"
@@ -30,6 +31,7 @@
#include "mozilla/Logging.h"
#include "nsNodeUtils.h"
#include "nsIContent.h"
+#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/Element.h"
#include "mozilla/Preferences.h"
@@ -59,8 +61,6 @@
#include "nsIScriptGlobalObject.h"
#include "nsNameSpaceManager.h"
-#include "nsIParserService.h"
-
#include "nsIStyleSheetLinkingElement.h"
#include "nsITimer.h"
#include "nsError.h"
@@ -262,10 +262,6 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
- nsIParserService* parserService = nsContentUtils::GetParserService();
- if (!parserService)
- return NS_ERROR_OUT_OF_MEMORY;
-
nsIAtom *name = nodeInfo->NameAtom();
RefPtr<nsIAtom> tagAtom = nodeInfo->NameAtom();
RefPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom;
@@ -273,7 +269,7 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
"Trying to HTML elements that don't have the XHTML namespace");
- int32_t tag = parserService->HTMLCaseSensitiveAtomTagToId(name);
+ int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(name);
bool isCustomElementName = (tag == eHTMLTag_userdefined &&
nsContentUtils::IsCustomElementName(name));
diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp
index 25be6016c..812a8d0b6 100644
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -2214,6 +2214,23 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
return true;
}
+bool
+nsTextEditorState::HasNonEmptyValue()
+{
+ if (mEditor && mBoundFrame && mEditorInitialized &&
+ !mIsCommittingComposition) {
+ bool empty;
+ nsresult rv = mEditor->GetDocumentIsEmpty(&empty);
+ if (NS_SUCCEEDED(rv)) {
+ return !empty;
+ }
+ }
+
+ nsAutoString value;
+ GetValue(value, true);
+ return !value.IsEmpty();
+}
+
void
nsTextEditorState::InitializeKeyboardEventListeners()
{
diff --git a/dom/html/nsTextEditorState.h b/dom/html/nsTextEditorState.h
index caf5e8eed..77d12e81a 100644
--- a/dom/html/nsTextEditorState.h
+++ b/dom/html/nsTextEditorState.h
@@ -157,6 +157,11 @@ public:
};
MOZ_MUST_USE bool SetValue(const nsAString& aValue, uint32_t aFlags);
void GetValue(nsAString& aValue, bool aIgnoreWrap) const;
+ bool HasNonEmptyValue();
+ // The following methods are for textarea element to use whether default
+ // value or not.
+ // XXX We might have to add assertion when it is into editable,
+ // or reconsider fixing bug 597525 to remove these.
void EmptyValue() { if (mValue) mValue->Truncate(); }
bool IsEmpty() const { return mValue ? mValue->IsEmpty() : true; }
diff --git a/dom/html/reftests/body-frame-margin-remove-other-pres-hint-ref.html b/dom/html/reftests/body-frame-margin-remove-other-pres-hint-ref.html
new file mode 100644
index 000000000..8446d7f26
--- /dev/null
+++ b/dom/html/reftests/body-frame-margin-remove-other-pres-hint-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+ <title></title>
+</head>
+<body>
+<script type="text/javascript">
+ function loadFrame() {
+ document.documentElement.className = "";
+ }
+</script>
+<iframe id=frame onload="loadFrame()" src="data:text/html,<body><span lang='en'>text</span></body>" marginwidth="100px" marginheight="100px" width=300px height=300px></iframe>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/html/reftests/body-frame-margin-remove-other-pres-hint.html b/dom/html/reftests/body-frame-margin-remove-other-pres-hint.html
new file mode 100644
index 000000000..6f4953637
--- /dev/null
+++ b/dom/html/reftests/body-frame-margin-remove-other-pres-hint.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+ <title></title>
+</head>
+<body>
+<script type="text/javascript">
+ function loadFrame() {
+ let frame = document.getElementById('frame');
+ frame.contentDocument.body.removeAttribute('lang');
+ document.documentElement.className = "";
+ }
+</script>
+<iframe id=frame onload="loadFrame()" src="data:text/html,<body lang='en'>text</body>" marginwidth="100px" marginheight="100px" width=300px height=300px></iframe>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/html/reftests/body-topmargin-dynamic.html b/dom/html/reftests/body-topmargin-dynamic.html
new file mode 100644
index 000000000..e6c8c505e
--- /dev/null
+++ b/dom/html/reftests/body-topmargin-dynamic.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<body>
+this text should have a margin of 100px on the top and left
+<p style="direction: rtl">this text should have a margin of 100px on the right</p>
+<script type="text/javascript">
+ document.body.setAttribute("topmargin", "100px");
+ document.body.setAttribute("leftmargin", "100px");
+ document.body.setAttribute("rightmargin", "100px");
+</script>
+</body>
+</html>
diff --git a/dom/html/reftests/body-topmargin-ref.html b/dom/html/reftests/body-topmargin-ref.html
new file mode 100644
index 000000000..6530a0ae4
--- /dev/null
+++ b/dom/html/reftests/body-topmargin-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body topmargin="100px" leftmargin="100px" rightmargin="100px">
+this text should have a margin of 100px on the top and left
+<p style="direction: rtl">this text should have a margin of 100px on the right</p>
+</body>
+</html>
diff --git a/dom/html/reftests/reftest-stylo.list b/dom/html/reftests/reftest-stylo.list
index dd6339edf..570c07358 100644
--- a/dom/html/reftests/reftest-stylo.list
+++ b/dom/html/reftests/reftest-stylo.list
@@ -64,3 +64,10 @@ pref(permissions.default.image,2) HTTP == bug1196784-with-srcset.html bug1196784
# Test video with rotation information can be rotated.
== bug1228601-video-rotation-90.html bug1228601-video-rotation-90.html
+
+# Test that dynamically setting body margin attributes updates style appropriately
+== body-topmargin-dynamic.html body-topmargin-dynamic.html
+
+# Test that dynamically removing a nonmargin mapped attribute does not
+# destroy margins inherited from the frame.
+== body-frame-margin-remove-other-pres-hint.html body-frame-margin-remove-other-pres-hint.html
diff --git a/dom/html/reftests/reftest.list b/dom/html/reftests/reftest.list
index 27a13e7c9..82e773abb 100644
--- a/dom/html/reftests/reftest.list
+++ b/dom/html/reftests/reftest.list
@@ -62,3 +62,10 @@ pref(permissions.default.image,2) HTTP == bug1196784-with-srcset.html bug1196784
# Test video with rotation information can be rotated.
== bug1228601-video-rotation-90.html bug1228601-video-rotated-ref.html
+
+# Test that dynamically setting body margin attributes updates style appropriately
+== body-topmargin-dynamic.html body-topmargin-ref.html
+
+# Test that dynamically removing a nonmargin mapped attribute does not
+# destroy margins inherited from the frame.
+== body-frame-margin-remove-other-pres-hint.html body-frame-margin-remove-other-pres-hint-ref.html
diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini
index 4a50a9c3f..5c9c66e61 100644
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -569,7 +569,6 @@ support-files = file_cookiemanager.js
support-files = file_bug871161-1.html file_bug871161-2.html
[test_bug1013316.html]
[test_hash_encoded.html]
-[test_bug1081037.html]
[test_window_open_close.html]
tags = openwindow
[test_viewport_resize.html]
diff --git a/dom/html/test/test_bug1081037.html b/dom/html/test/test_bug1081037.html
deleted file mode 100644
index 9d8782580..000000000
--- a/dom/html/test/test_bug1081037.html
+++ /dev/null
@@ -1,133 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1081037
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1081037</title>
- <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
- <script type="application/javascript">
-
- /** Test for Bug 1081037 **/
-
-function shouldThrow(fun, msg, ex, todo) {
- try {
- fun();
- ok(todo, msg);
- } catch (e) {
- ok(new RegExp(ex).test(e), msg + " (thrown:" + e + ")")
- }
-}
-
-var Foo = document.registerElement('x-foo', {
- prototype: {bar: 5}
-});
-
-Foo.prototype.bar = 6;
-var foo = new Foo();
-is(foo.bar, 6, "prototype of the ctor returned from registerElement works");
-
-var protoDesc = Object.getOwnPropertyDescriptor(Foo, "prototype");
-is(protoDesc.configurable, false, "proto should be non-configurable");
-is(protoDesc.enumerable, false, "proto should be non-enumerable");
-is(protoDesc.writable, false, "proto should be non-writable");
-
-// TODO: FIXME!
-shouldThrow(function() {
- document.registerElement('x-foo2', {
- prototype: Foo.prototype
- });
- },
- "if proto is an interface prototype object, registerElement should throw",
- "not supported",
- /* todo = */ true);
-
-var nonConfigReadonlyProto = Object.create(HTMLElement.prototype,
- { constructor: { configurable: false, writable: false, value: 42 } });
-
-shouldThrow(function() {
- document.registerElement('x-nonconfig-readonly', {
- prototype: nonConfigReadonlyProto
- });
- },
- "non-configurable and not-writable constructor property",
- "not supported");
-
-
-// this is not defined in current spec:
-var readonlyProto = Object.create(HTMLElement.prototype,
- { constructor: { configurable: true, writable: false, value: 42 } });
-
-var Readonly = document.registerElement('x-nonconfig-readonly', {
- prototype: readonlyProto
-});
-
-is(Readonly.prototype, readonlyProto, "configurable readonly constructor property");
-
-var handler = {
- getOwnPropertyDescriptor: function(target, name) {
- return name == "constructor" ? undefined : Object.getOwnPropertyDescriptor(target,name);
- },
- defineProperty: function(target, name, propertyDescriptor) {
- if (name == "constructor") {
- throw "spec this";
- }
-
- return Object.defineProperty(target, name, propertyDescriptor);
- },
- has: function(target, name) {
- if (name == "constructor") {
- return false;
- }
- return name in target;
- }
-};
-var proxy = new Proxy({}, handler);
-
-shouldThrow(function() {
- document.registerElement('x-proxymagic', {
- prototype: proxy
- });
- },
- "proxy magic",
- "spec this");
-
-var getOwn = 0;
-var defineProp = 0;
-var handler2 = {
- getOwnPropertyDescriptor: function(target, name) {
- if (name == "constructor") {
- getOwn++;
- }
- return Object.getOwnPropertyDescriptor(target,name);
- },
- defineProperty: function(target, name, propertyDescriptor) {
- if (name == "constructor") {
- defineProp++;
- }
- return Object.defineProperty(target, name, propertyDescriptor);
- }
-};
-var proxy2 = new Proxy({}, handler2);
-
-document.registerElement('x-proxymagic2', {
- prototype: proxy2
-});
-
-is(getOwn, 1, "number of getOwnPropertyDescriptor calls from registerElement: " + getOwn);
-is(defineProp, 1, "number of defineProperty calls from registerElement: " + defineProp);
-
- </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081037">Mozilla Bug 1081037</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/dom/indexedDB/IDBFileHandle.cpp b/dom/indexedDB/IDBFileHandle.cpp
index 8b88e1722..93e163c11 100644
--- a/dom/indexedDB/IDBFileHandle.cpp
+++ b/dom/indexedDB/IDBFileHandle.cpp
@@ -127,12 +127,12 @@ IDBFileHandle::Run()
}
nsresult
-IDBFileHandle::PreHandleEvent(EventChainPreVisitor& aVisitor)
+IDBFileHandle::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
AssertIsOnOwningThread();
aVisitor.mCanHandle = true;
- aVisitor.mParentTarget = mMutableFile;
+ aVisitor.SetParentTarget(mMutableFile, false);
return NS_OK;
}
diff --git a/dom/indexedDB/IDBFileHandle.h b/dom/indexedDB/IDBFileHandle.h
index 574524090..17206e09c 100644
--- a/dom/indexedDB/IDBFileHandle.h
+++ b/dom/indexedDB/IDBFileHandle.h
@@ -117,7 +117,7 @@ public:
// nsIDOMEventTarget
virtual nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
// WrapperCache
virtual JSObject*
diff --git a/dom/indexedDB/IDBFileRequest.cpp b/dom/indexedDB/IDBFileRequest.cpp
index 066b2b24a..1401f7c76 100644
--- a/dom/indexedDB/IDBFileRequest.cpp
+++ b/dom/indexedDB/IDBFileRequest.cpp
@@ -64,12 +64,12 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(IDBFileRequest, DOMRequest,
mFileHandle)
nsresult
-IDBFileRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
+IDBFileRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
AssertIsOnOwningThread();
aVisitor.mCanHandle = true;
- aVisitor.mParentTarget = mFileHandle;
+ aVisitor.SetParentTarget(mFileHandle, false);
return NS_OK;
}
diff --git a/dom/indexedDB/IDBFileRequest.h b/dom/indexedDB/IDBFileRequest.h
index 4f4252dc9..3d8d282fd 100644
--- a/dom/indexedDB/IDBFileRequest.h
+++ b/dom/indexedDB/IDBFileRequest.h
@@ -58,7 +58,7 @@ public:
// nsIDOMEventTarget
virtual nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
// nsWrapperCache
virtual JSObject*
diff --git a/dom/indexedDB/IDBRequest.cpp b/dom/indexedDB/IDBRequest.cpp
index e0e318059..5ce077e33 100644
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -449,12 +449,12 @@ NS_IMPL_ADDREF_INHERITED(IDBRequest, IDBWrapperCache)
NS_IMPL_RELEASE_INHERITED(IDBRequest, IDBWrapperCache)
nsresult
-IDBRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
+IDBRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
AssertIsOnOwningThread();
aVisitor.mCanHandle = true;
- aVisitor.mParentTarget = mTransaction;
+ aVisitor.SetParentTarget(mTransaction, false);
return NS_OK;
}
diff --git a/dom/indexedDB/IDBRequest.h b/dom/indexedDB/IDBRequest.h
index 1c7fca756..e6cbaab9e 100644
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -90,7 +90,7 @@ public:
// nsIDOMEventTarget
virtual nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
void
GetSource(Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const;
diff --git a/dom/indexedDB/IDBTransaction.cpp b/dom/indexedDB/IDBTransaction.cpp
index a50489898..0a10e2ca0 100644
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -996,12 +996,12 @@ IDBTransaction::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
}
nsresult
-IDBTransaction::PreHandleEvent(EventChainPreVisitor& aVisitor)
+IDBTransaction::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
AssertIsOnOwningThread();
aVisitor.mCanHandle = true;
- aVisitor.mParentTarget = mDatabase;
+ aVisitor.SetParentTarget(mDatabase, false);
return NS_OK;
}
diff --git a/dom/indexedDB/IDBTransaction.h b/dom/indexedDB/IDBTransaction.h
index 1c3e8be99..5a893ca20 100644
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -314,7 +314,7 @@ public:
// nsIDOMEventTarget
virtual nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
private:
IDBTransaction(IDBDatabase* aDatabase,
diff --git a/dom/interfaces/events/nsIDOMEventTarget.idl b/dom/interfaces/events/nsIDOMEventTarget.idl
index a7e3aae5a..9e00c598c 100644
--- a/dom/interfaces/events/nsIDOMEventTarget.idl
+++ b/dom/interfaces/events/nsIDOMEventTarget.idl
@@ -13,6 +13,7 @@
using mozilla::dom::Nullable;
namespace mozilla {
+class EventChainVisitor;
class EventChainPostVisitor;
class EventChainPreVisitor;
class EventListenerManager;
@@ -224,7 +225,19 @@ interface nsIDOMEventTarget : nsISupports
* @note Only EventDispatcher should call this method.
*/
[noscript, nostdcall]
- void PreHandleEvent(in EventChainPreVisitorRef aVisitor);
+ void GetEventTargetParent(in EventChainPreVisitorRef aVisitor);
+
+ /**
+ * Called before the capture phase of the event flow and after event target
+ * chain creation. This is used to handle those stuffs must be executed before
+ * dispatch event to DOM
+ */
+%{C++
+ virtual nsresult PreHandleEvent(mozilla::EventChainVisitor& aVisitor)
+ {
+ return NS_OK;
+ }
+%}
/**
* If EventChainPreVisitor.mWantsWillHandleEvent is set PR_TRUE,
diff --git a/dom/interfaces/range/nsIDOMRange.idl b/dom/interfaces/range/nsIDOMRange.idl
index 2dc40ac98..7c74ddaf2 100644
--- a/dom/interfaces/range/nsIDOMRange.idl
+++ b/dom/interfaces/range/nsIDOMRange.idl
@@ -16,14 +16,14 @@
interface nsIDOMRange : nsISupports
{
readonly attribute nsIDOMNode startContainer;
- readonly attribute long startOffset;
+ readonly attribute unsigned long startOffset;
readonly attribute nsIDOMNode endContainer;
- readonly attribute long endOffset;
+ readonly attribute unsigned long endOffset;
readonly attribute boolean collapsed;
readonly attribute nsIDOMNode commonAncestorContainer;
- void setStart(in nsIDOMNode refNode, in long offset);
- void setEnd(in nsIDOMNode refNode, in long offset);
+ void setStart(in nsIDOMNode refNode, in unsigned long offset);
+ void setEnd(in nsIDOMNode refNode, in unsigned long offset);
void setStartBefore(in nsIDOMNode refNode);
void setStartAfter(in nsIDOMNode refNode);
void setEndBefore(in nsIDOMNode refNode);
@@ -56,14 +56,14 @@ interface nsIDOMRange : nsISupports
// This returns true if parent+offset equals either
// of the boundary points or is between them.
boolean isPointInRange(in nsIDOMNode parent,
- in long offset);
+ in unsigned long offset);
// comparePoint returns
// -1 if point is before the start boundary point,
// 0 if point is either of the boundary points or between them,
// 1 if point is after the end boundary point.
// Sort of a strcmp for ranges.
- short comparePoint(in nsIDOMNode parent, in long offset);
+ short comparePoint(in nsIDOMNode parent, in unsigned long offset);
/**
* Returns whether the range intersects node.
diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h
index d9988a596..004067355 100644
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -135,7 +135,7 @@ public:
}
nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override
{
aVisitor.mForceContentDispatch = true;
return NS_OK;
diff --git a/dom/mathml/nsMathMLElement.cpp b/dom/mathml/nsMathMLElement.cpp
index 2be931682..a74d8168c 100644
--- a/dom/mathml/nsMathMLElement.cpp
+++ b/dom/mathml/nsMathMLElement.cpp
@@ -919,12 +919,12 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
}
nsresult
-nsMathMLElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsMathMLElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- nsresult rv = Element::PreHandleEvent(aVisitor);
+ nsresult rv = Element::GetEventTargetParent(aVisitor);
NS_ENSURE_SUCCESS(rv, rv);
- return PreHandleEventForLinks(aVisitor);
+ return GetEventTargetParentForLinks(aVisitor);
}
nsresult
@@ -1085,50 +1085,27 @@ nsMathMLElement::GetHrefURI() const
}
nsresult
-nsMathMLElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify)
+nsMathMLElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
- nsresult rv = nsMathMLElementBase::SetAttr(aNameSpaceID, aName, aPrefix,
- aValue, aNotify);
-
- // The ordering of the parent class's SetAttr call and Link::ResetLinkState
- // is important here! The attribute is not set until SetAttr returns, and
- // we will need the updated attribute value because notifying the document
+ // It is important that this be done after the attribute is set/unset.
+ // We will need the updated attribute value because notifying the document
// that content states have changed will call IntrinsicState, which will try
// to get updated information about the visitedness from Link.
if (aName == nsGkAtoms::href &&
(aNameSpaceID == kNameSpaceID_None ||
aNameSpaceID == kNameSpaceID_XLink)) {
- if (aNameSpaceID == kNameSpaceID_XLink) {
+ if (aValue && aNameSpaceID == kNameSpaceID_XLink) {
WarnDeprecated(u"xlink:href", u"href", OwnerDoc());
}
- Link::ResetLinkState(!!aNotify, true);
- }
-
- return rv;
-}
-
-nsresult
-nsMathMLElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
- bool aNotify)
-{
- nsresult rv = nsMathMLElementBase::UnsetAttr(aNameSpaceID, aAttr, aNotify);
-
- // The ordering of the parent class's UnsetAttr call and Link::ResetLinkState
- // is important here! The attribute is not unset until UnsetAttr returns, and
- // we will need the updated attribute value because notifying the document
- // that content states have changed will call IntrinsicState, which will try
- // to get updated information about the visitedness from Link.
- if (aAttr == nsGkAtoms::href &&
- (aNameSpaceID == kNameSpaceID_None ||
- aNameSpaceID == kNameSpaceID_XLink)) {
- // Note: just because we removed a single href attr doesn't mean there's no href,
- // since there are 2 possible namespaces.
- Link::ResetLinkState(!!aNotify, Link::ElementHasHref());
+ // Note: When unsetting href, there may still be another href since there
+ // are 2 possible namespaces.
+ Link::ResetLinkState(aNotify, aValue || Link::ElementHasHref());
}
- return rv;
+ return nsMathMLElementBase::AfterSetAttr(aNameSpaceID, aName, aValue,
+ aOldValue, aNotify);
}
JSObject*
diff --git a/dom/mathml/nsMathMLElement.h b/dom/mathml/nsMathMLElement.h
index 47ed8b165..0fdaf021f 100644
--- a/dom/mathml/nsMathMLElement.h
+++ b/dom/mathml/nsMathMLElement.h
@@ -74,7 +74,7 @@ public:
static void MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
nsRuleData* aRuleData);
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
mozilla::EventChainPostVisitor& aVisitor) override;
@@ -93,16 +93,6 @@ public:
virtual bool IsLink(nsIURI** aURI) const override;
virtual void GetLinkTarget(nsAString& aTarget) override;
virtual already_AddRefed<nsIURI> GetHrefURI() const override;
- nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAString& aValue, bool aNotify)
- {
- return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
- }
- virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- nsIAtom* aPrefix, const nsAString& aValue,
- bool aNotify) override;
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify) override;
virtual nsIDOMNode* AsDOMNode() override { return this; }
@@ -111,6 +101,11 @@ protected:
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
+ virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
+
private:
bool mIncrementScriptLevel;
};
diff --git a/dom/svg/SVGAElement.cpp b/dom/svg/SVGAElement.cpp
index a69c60ee4..95c3d6979 100644
--- a/dom/svg/SVGAElement.cpp
+++ b/dom/svg/SVGAElement.cpp
@@ -84,12 +84,12 @@ SVGAElement::Href()
// nsINode methods
nsresult
-SVGAElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+SVGAElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- nsresult rv = Element::PreHandleEvent(aVisitor);
+ nsresult rv = Element::GetEventTargetParent(aVisitor);
NS_ENSURE_SUCCESS(rv, rv);
- return PreHandleEventForLinks(aVisitor);
+ return GetEventTargetParentForLinks(aVisitor);
}
nsresult
diff --git a/dom/svg/SVGAElement.h b/dom/svg/SVGAElement.h
index 4f7df9e50..776c96f53 100644
--- a/dom/svg/SVGAElement.h
+++ b/dom/svg/SVGAElement.h
@@ -37,7 +37,8 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGAElement, SVGAElementBase)
// nsINode interface methods
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
diff --git a/dom/svg/SVGAnimationElement.cpp b/dom/svg/SVGAnimationElement.cpp
index d6550c96e..90c26657f 100644
--- a/dom/svg/SVGAnimationElement.cpp
+++ b/dom/svg/SVGAnimationElement.cpp
@@ -299,11 +299,12 @@ SVGAnimationElement::ParseAttribute(int32_t aNamespaceID,
nsresult
SVGAnimationElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
nsresult rv =
SVGAnimationElementBase::AfterSetAttr(aNamespaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
if (SVGTests::IsConditionalProcessingAttribute(aName)) {
bool isDisabled = !SVGTests::PassesConditionalProcessingTests();
diff --git a/dom/svg/SVGAnimationElement.h b/dom/svg/SVGAnimationElement.h
index 9bcbdf0c2..eb602c4a8 100644
--- a/dom/svg/SVGAnimationElement.h
+++ b/dom/svg/SVGAnimationElement.h
@@ -58,7 +58,9 @@ public:
const nsAString& aValue,
nsAttrValue& aResult) override;
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
const nsAttrValue* GetAnimAttr(nsIAtom* aName) const;
bool GetAnimAttr(nsIAtom* aAttName, nsAString& aResult) const;
diff --git a/dom/svg/SVGFEImageElement.cpp b/dom/svg/SVGFEImageElement.cpp
index f235d5ccb..5492f291d 100644
--- a/dom/svg/SVGFEImageElement.cpp
+++ b/dom/svg/SVGFEImageElement.cpp
@@ -119,7 +119,8 @@ SVGFEImageElement::IsAttributeMapped(const nsIAtom* name) const
nsresult
SVGFEImageElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aName == nsGkAtoms::href &&
(aNamespaceID == kNameSpaceID_XLink ||
@@ -139,7 +140,7 @@ SVGFEImageElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
}
return SVGFEImageElementBase::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
void
diff --git a/dom/svg/SVGFEImageElement.h b/dom/svg/SVGFEImageElement.h
index edf6f065d..a5b76066a 100644
--- a/dom/svg/SVGFEImageElement.h
+++ b/dom/svg/SVGFEImageElement.h
@@ -58,7 +58,9 @@ public:
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
diff --git a/dom/svg/SVGImageElement.cpp b/dom/svg/SVGImageElement.cpp
index 524485dee..e240ee416 100644
--- a/dom/svg/SVGImageElement.cpp
+++ b/dom/svg/SVGImageElement.cpp
@@ -150,7 +150,8 @@ SVGImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
nsresult
SVGImageElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aName == nsGkAtoms::href &&
(aNamespaceID == kNameSpaceID_None ||
@@ -169,7 +170,7 @@ SVGImageElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
}
}
return SVGImageElementBase::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
void
diff --git a/dom/svg/SVGImageElement.h b/dom/svg/SVGImageElement.h
index 85730212b..e8ea95499 100644
--- a/dom/svg/SVGImageElement.h
+++ b/dom/svg/SVGImageElement.h
@@ -46,7 +46,9 @@ public:
// nsIContent interface
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
diff --git a/dom/svg/SVGSVGElement.cpp b/dom/svg/SVGSVGElement.cpp
index 90c3c3fff..bb3aaccd2 100644
--- a/dom/svg/SVGSVGElement.cpp
+++ b/dom/svg/SVGSVGElement.cpp
@@ -589,7 +589,7 @@ SVGSVGElement::IsAttributeMapped(const nsIAtom* name) const
// nsIContent methods:
nsresult
-SVGSVGElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+SVGSVGElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
if (aVisitor.mEvent->mMessage == eSVGLoad) {
if (mTimedDocumentRoot) {
@@ -600,7 +600,7 @@ SVGSVGElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
AnimationNeedsResample();
}
}
- return SVGSVGElementBase::PreHandleEvent(aVisitor);
+ return SVGSVGElementBase::GetEventTargetParent(aVisitor);
}
bool
diff --git a/dom/svg/SVGSVGElement.h b/dom/svg/SVGSVGElement.h
index da08ad770..0145ae8fa 100644
--- a/dom/svg/SVGSVGElement.h
+++ b/dom/svg/SVGSVGElement.h
@@ -152,7 +152,8 @@ public:
// nsIContent interface
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual bool IsEventAttributeName(nsIAtom* aName) override;
diff --git a/dom/svg/SVGScriptElement.cpp b/dom/svg/SVGScriptElement.cpp
index ffc049c21..0cc827b9f 100644
--- a/dom/svg/SVGScriptElement.cpp
+++ b/dom/svg/SVGScriptElement.cpp
@@ -211,7 +211,8 @@ SVGScriptElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsresult
SVGScriptElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if ((aNamespaceID == kNameSpaceID_XLink ||
aNamespaceID == kNameSpaceID_None) &&
@@ -219,7 +220,7 @@ SVGScriptElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
MaybeProcessScript();
}
return SVGScriptElementBase::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
bool
diff --git a/dom/svg/SVGScriptElement.h b/dom/svg/SVGScriptElement.h
index 620a1bcde..d3a233b72 100644
--- a/dom/svg/SVGScriptElement.h
+++ b/dom/svg/SVGScriptElement.h
@@ -55,7 +55,9 @@ public:
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual bool ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
diff --git a/dom/svg/nsSVGClass.cpp b/dom/svg/nsSVGClass.cpp
index 6b64c3be7..c5a825be4 100644
--- a/dom/svg/nsSVGClass.cpp
+++ b/dom/svg/nsSVGClass.cpp
@@ -70,7 +70,7 @@ nsSVGClass::SetBaseValue(const nsAString& aValue,
{
NS_ASSERTION(aSVGElement, "Null element passed to SetBaseValue");
- aSVGElement->SetFlags(NODE_MAY_HAVE_CLASS);
+ aSVGElement->SetMayHaveClass();
if (aDoSetAttr) {
aSVGElement->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, aValue, true);
}
@@ -106,7 +106,7 @@ nsSVGClass::SetAnimValue(const nsAString& aValue, nsSVGElement *aSVGElement)
mAnimVal = new nsString();
}
*mAnimVal = aValue;
- aSVGElement->SetFlags(NODE_MAY_HAVE_CLASS);
+ aSVGElement->SetMayHaveClass();
aSVGElement->DidAnimateClass();
}
diff --git a/dom/svg/nsSVGElement.cpp b/dom/svg/nsSVGElement.cpp
index ce849acf0..25d6d944d 100644
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -18,6 +18,7 @@
#include "nsIDOMMutationEvent.h"
#include "nsSVGPathGeometryElement.h"
#include "mozilla/InternalMutationEvent.h"
+#include "mozAutoDocUpdate.h"
#include "nsError.h"
#include "nsIPresShell.h"
#include "nsGkAtoms.h"
@@ -272,7 +273,9 @@ nsSVGElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
ParseStyleAttribute(stringValue, attrValue, true);
// Don't bother going through SetInlineStyleDeclaration; we don't
// want to fire off mutation events or document notifications anyway
- rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue);
+ bool oldValueSet;
+ rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue,
+ &oldValueSet);
NS_ENSURE_SUCCESS(rv, rv);
}
@@ -281,7 +284,8 @@ nsSVGElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsresult
nsSVGElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
// We don't currently use nsMappedAttributes within SVG. If this changes, we
// need to be very careful because some nsAttrValues used by SVG point to
@@ -309,7 +313,8 @@ nsSVGElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
NS_ENSURE_SUCCESS(rv, rv);
}
- return nsSVGElementBase::AfterSetAttr(aNamespaceID, aName, aValue, aNotify);
+ return nsSVGElementBase::AfterSetAttr(aNamespaceID, aName, aValue, aOldValue,
+ aNotify);
}
bool
@@ -1441,27 +1446,16 @@ nsSVGElement::WillChangeValue(nsIAtom* aName)
// We need an empty attr value:
// a) to pass to BeforeSetAttr when GetParsedAttr returns nullptr
// b) to store the old value in the case we have mutation listeners
- // We can use the same value for both purposes since (a) happens before (b).
+ //
+ // We can use the same value for both purposes, because if GetParsedAttr
+ // returns non-null its return value is what will get passed to BeforeSetAttr,
+ // not matter what our mutation listener situation is.
+ //
// Also, we should be careful to always return this value to benefit from
// return value optimization.
nsAttrValue emptyOrOldAttrValue;
const nsAttrValue* attrValue = GetParsedAttr(aName);
- // This is not strictly correct--the attribute value parameter for
- // BeforeSetAttr should reflect the value that *will* be set but that implies
- // allocating, e.g. an extra nsSVGLength2, and isn't necessary at the moment
- // since no SVG elements overload BeforeSetAttr. For now we just pass the
- // current value.
- nsAttrValueOrString attrStringOrValue(attrValue ? *attrValue
- : emptyOrOldAttrValue);
- DebugOnly<nsresult> rv =
- BeforeSetAttr(kNameSpaceID_None, aName, &attrStringOrValue,
- kNotifyDocumentObservers);
- // SVG elements aren't expected to overload BeforeSetAttr in such a way that
- // it may fail. So long as this is the case we don't need to check and pass on
- // the return value which simplifies the calling code significantly.
- MOZ_ASSERT(NS_SUCCEEDED(rv), "Unexpected failure from BeforeSetAttr");
-
// We only need to set the old value if we have listeners since otherwise it
// isn't used.
if (attrValue &&
@@ -1477,6 +1471,21 @@ nsSVGElement::WillChangeValue(nsIAtom* aName)
nsNodeUtils::AttributeWillChange(this, kNameSpaceID_None, aName, modType,
nullptr);
+ // This is not strictly correct--the attribute value parameter for
+ // BeforeSetAttr should reflect the value that *will* be set but that implies
+ // allocating, e.g. an extra nsSVGLength2, and isn't necessary at the moment
+ // since no SVG elements overload BeforeSetAttr. For now we just pass the
+ // current value.
+ nsAttrValueOrString attrStringOrValue(attrValue ? *attrValue
+ : emptyOrOldAttrValue);
+ DebugOnly<nsresult> rv =
+ BeforeSetAttr(kNameSpaceID_None, aName, &attrStringOrValue,
+ kNotifyDocumentObservers);
+ // SVG elements aren't expected to overload BeforeSetAttr in such a way that
+ // it may fail. So long as this is the case we don't need to check and pass on
+ // the return value which simplifies the calling code significantly.
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Unexpected failure from BeforeSetAttr");
+
return emptyOrOldAttrValue;
}
@@ -1505,9 +1514,17 @@ nsSVGElement::DidChangeValue(nsIAtom* aName,
uint8_t modType = HasAttr(kNameSpaceID_None, aName)
? static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION)
: static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION);
- SetAttrAndNotify(kNameSpaceID_None, aName, nullptr, aEmptyOrOldValue,
+
+ nsIDocument* document = GetComposedDoc();
+ mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL,
+ kNotifyDocumentObservers);
+ // XXX Really, the fourth argument to SetAttrAndNotify should be null if
+ // aEmptyOrOldValue does not represent the actual previous value of the
+ // attribute, but currently SVG elements do not even use the old attribute
+ // value in |AfterSetAttr|, so this should be ok.
+ SetAttrAndNotify(kNameSpaceID_None, aName, nullptr, &aEmptyOrOldValue,
aNewValue, modType, hasListeners, kNotifyDocumentObservers,
- kCallAfterSetAttr);
+ kCallAfterSetAttr, document, updateBatch);
}
void
@@ -1527,7 +1544,8 @@ nsSVGElement::MaybeSerializeAttrBeforeRemoval(nsIAtom* aName, bool aNotify)
nsAutoString serializedValue;
attrValue->ToString(serializedValue);
nsAttrValue oldAttrValue(serializedValue);
- mAttrsAndChildren.SetAndSwapAttr(aName, oldAttrValue);
+ bool oldValueSet;
+ mAttrsAndChildren.SetAndSwapAttr(aName, oldAttrValue, &oldValueSet);
}
/* static */
diff --git a/dom/svg/nsSVGElement.h b/dom/svg/nsSVGElement.h
index 257ed7a2e..4e8c7a938 100644
--- a/dom/svg/nsSVGElement.h
+++ b/dom/svg/nsSVGElement.h
@@ -329,14 +329,16 @@ protected:
// BeforeSetAttr since it would involve allocating extra SVG value types.
// See the comment in nsSVGElement::WillChangeValue.
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify) override final
{
return nsSVGElementBase::BeforeSetAttr(aNamespaceID, aName, aValue, aNotify);
}
#endif // DEBUG
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
const nsAString& aValue, nsAttrValue& aResult) override;
static nsresult ReportAttributeParseFailure(nsIDocument* aDocument,
diff --git a/dom/svg/nsSVGPathGeometryElement.cpp b/dom/svg/nsSVGPathGeometryElement.cpp
index ea2e1c7c4..9b9e96c8f 100644
--- a/dom/svg/nsSVGPathGeometryElement.cpp
+++ b/dom/svg/nsSVGPathGeometryElement.cpp
@@ -26,7 +26,8 @@ nsSVGPathGeometryElement::nsSVGPathGeometryElement(already_AddRefed<mozilla::dom
nsresult
nsSVGPathGeometryElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (mCachedPath &&
aNamespaceID == kNameSpaceID_None &&
@@ -34,7 +35,7 @@ nsSVGPathGeometryElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
mCachedPath = nullptr;
}
return nsSVGPathGeometryElementBase::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
bool
diff --git a/dom/svg/nsSVGPathGeometryElement.h b/dom/svg/nsSVGPathGeometryElement.h
index 1091fa0dc..29e90c4e0 100644
--- a/dom/svg/nsSVGPathGeometryElement.h
+++ b/dom/svg/nsSVGPathGeometryElement.h
@@ -45,7 +45,9 @@ public:
explicit nsSVGPathGeometryElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
/**
* Causes this element to discard any Path object that GetOrBuildPath may
diff --git a/dom/tests/mochitest/webcomponents/mochitest.ini b/dom/tests/mochitest/webcomponents/mochitest.ini
index f5d0f84ea..84322d21d 100644
--- a/dom/tests/mochitest/webcomponents/mochitest.ini
+++ b/dom/tests/mochitest/webcomponents/mochitest.ini
@@ -17,18 +17,15 @@ support-files =
htmlconstructor_builtin_tests.js
[test_custom_element_in_shadow.html]
skip-if = true || stylo # disabled - See bug 1390396 and 1293844
-[test_custom_element_register_invalid_callbacks.html]
[test_custom_element_throw_on_dynamic_markup_insertion.html]
[test_custom_element_get.html]
[test_custom_element_when_defined.html]
[test_custom_element_uncatchable_exception.html]
skip-if = !debug # TestFunctions only applied in debug builds
-[test_nested_content_element.html]
-[test_dest_insertion_points.html]
-[test_dest_insertion_points_shadow.html]
-[test_fallback_dest_insertion_points.html]
+[test_custom_element_define.html]
+[test_custom_element_define_parser.html]
+[test_custom_element_template.html]
[test_detached_style.html]
-[test_dynamic_content_element_matching.html]
[test_document_adoptnode.html]
[test_document_importnode.html]
[test_document_register.html]
@@ -38,19 +35,13 @@ skip-if = true # disabled - See bug 1390396
[test_document_register_stack.html]
skip-if = true # disabled - See bug 1390396
[test_document_shared_registry.html]
-[test_event_dispatch.html]
[test_event_retarget.html]
[test_event_stopping.html]
[test_template.html]
[test_template_xhtml.html]
-[test_template_custom_elements.html]
[test_shadowroot.html]
[test_shadowroot_inert_element.html]
-[test_shadowroot_host.html]
[test_shadowroot_style.html]
-[test_shadowroot_style_multiple_shadow.html]
[test_shadowroot_style_order.html]
-[test_shadowroot_youngershadowroot.html]
[test_style_fallback_content.html]
-[test_unresolved_pseudo_class.html]
[test_link_prefetch.html]
diff --git a/dom/tests/mochitest/webcomponents/test_bug1276240.html b/dom/tests/mochitest/webcomponents/test_bug1276240.html
index ded8d8276..33e532a6a 100644
--- a/dom/tests/mochitest/webcomponents/test_bug1276240.html
+++ b/dom/tests/mochitest/webcomponents/test_bug1276240.html
@@ -47,7 +47,7 @@ test();
// test with webcomponents disabled
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv(
- { 'set': [["dom.webcomponents.customelements.enabled", false]]}, runTest);
+ { 'set': [["dom.webcomponents.enabled", false]]}, runTest);
</script>
</pre>
diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html b/dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html
index bb5008538..22d957117 100644
--- a/dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html
+++ b/dom/tests/mochitest/webcomponents/test_custom_element_callback_innerhtml.html
@@ -18,23 +18,19 @@ SimpleTest.waitForExplicitFinish();
var connectedCallbackCount = 0;
-var p = Object.create(HTMLElement.prototype);
-
-p.createdCallback = function() {
- ok(true, "createdCallback called.");
-};
-
-p.connectedCallback = function() {
- ok(true, "connectedCallback should be called when the parser creates an element in the document.");
- connectedCallbackCount++;
- // connectedCallback should be called twice, once for the element created for innerHTML and
- // once for the element created in this document.
- if (connectedCallbackCount == 2) {
- SimpleTest.finish();
+class Foo extends HTMLElement {
+ connectedCallback() {
+ ok(true, "connectedCallback should be called when the parser creates an element in the document.");
+ connectedCallbackCount++;
+ // connectedCallback should be called twice, once for the element created for innerHTML and
+ // once for the element created in this document.
+ if (connectedCallbackCount == 2) {
+ SimpleTest.finish();
+ }
}
-}
+};
-document.registerElement("x-foo", { prototype: p });
+customElements.define("x-foo", Foo);
var container = document.getElementById("container");
container.innerHTML = '<x-foo></x-foo>';
diff --git a/dom/tests/mochitest/webcomponents/test_custom_element_register_invalid_callbacks.html b/dom/tests/mochitest/webcomponents/test_custom_element_register_invalid_callbacks.html
deleted file mode 100644
index 572579ba8..000000000
--- a/dom/tests/mochitest/webcomponents/test_custom_element_register_invalid_callbacks.html
+++ /dev/null
@@ -1,69 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1275835
--->
-<head>
- <title>Test registering invalid lifecycle callbacks for custom elements.</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=1275835">Bug 1275835</a>
-<iframe id="iframe"></iframe>
-<script>
-
-// Use window from iframe to isolate the test.
-const testWindow = iframe.contentDocument.defaultView;
-
-// This is for backward compatibility.
-// We should do the same checks for the callbacks from v0 spec.
-[
- 'attributeChangedCallback',
-].forEach(callback => {
- var c = class {};
- var p = c.prototype;
-
- // Test getting callback throws exception.
- Object.defineProperty(p, callback, {
- get() {
- const e = new Error('this is rethrown');
- e.name = 'rethrown';
- throw e;
- }
- });
-
- SimpleTest.doesThrow(() => {
- testWindow.document.registerElement(`test-register-${callback}-rethrown`,
- { prototype: p });
- }, `document.registerElement should throw exception if prototype.${callback} throws`);
-
- SimpleTest.doesThrow(() => {
- testWindow.customElements.define(`test-define-${callback}-rethrown`, c);
- }, `customElements.define should throw exception if constructor.${callback} throws`);
-
- // Test callback is not callable.
- [
- { name: 'null', value: null },
- { name: 'object', value: {} },
- { name: 'integer', value: 1 },
- ].forEach(data => {
- var c = class {};
- var p = c.prototype;
-
- p[callback] = data.value;
-
- SimpleTest.doesThrow(() => {
- testWindow.document.registerElement(`test-register-${callback}-${data.name}`,
- { prototype: p });
- }, `document.registerElement should throw exception if ${callback} is ${data.name}`);
-
- SimpleTest.doesThrow(() => {
- testWindow.customElements.define(`test-define-${callback}-${data.name}`, c);
- }, `customElements.define should throw exception if ${callback} is ${data.name}`);
- });
-});
-
-</script>
-</body>
-</html>
diff --git a/dom/tests/mochitest/webcomponents/test_dest_insertion_points.html b/dom/tests/mochitest/webcomponents/test_dest_insertion_points.html
deleted file mode 100644
index 2d4a92ed2..000000000
--- a/dom/tests/mochitest/webcomponents/test_dest_insertion_points.html
+++ /dev/null
@@ -1,73 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=999999
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 999999</title>
- <script type="application/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=999999">Mozilla Bug 999999</a>
-<p id="display"></p>
-<div id="content">
-<div id="shadowhost">
-</div>
-</div>
-<pre id="test">
-</pre>
-<script type="application/javascript">
-
-/** Test for Bug 999999 **/
-var host = document.getElementById("shadowhost");
-
-// Test destination insertion points of node distributed to content element.
-var shadowRoot = host.createShadowRoot();
-shadowRoot.innerHTML = '<div id="innerhost"><content id="innercontent" select=".red"></content></div>';
-var innerContent = shadowRoot.getElementById("innercontent");
-
-var span = document.createElement("span");
-span.setAttribute("class", "red blue");
-is(host.getDestinationInsertionPoints().length, 0, "Destination insertion points should be empty when not being distributed.");
-
-host.appendChild(span);
-
-is(span.getDestinationInsertionPoints().length, 1, "Destination insertion points should only contain a single content insertion point.");
-is(span.getDestinationInsertionPoints()[0], innerContent, "Content element should contain destination insertion point.");
-
-// Test destination insertion points of redistributed node.
-var innerHost = shadowRoot.getElementById("innerhost");
-var innerShadowRoot = innerHost.createShadowRoot();
-innerShadowRoot.innerHTML = '<content id="innerinnercontent" select=".blue"></content>';
-
-var innerInnerContent = innerShadowRoot.getElementById("innerinnercontent");
-
-is(span.getDestinationInsertionPoints().length, 2, "Redistributed node should have 2 destination insertion points.");
-is(span.getDestinationInsertionPoints()[1], innerInnerContent, "Nested content insertion point should be in list of destination insertion points.");
-
-// Test destination insertion points after removing reprojection onto second content element.
-span.setAttribute("class", "red");
-is(span.getDestinationInsertionPoints().length, 1, "Destination insertion points should only contain 1 insertion point after removing reprojection.");
-is(span.getDestinationInsertionPoints()[0], innerContent, "First content element should be only insertion point after removing reprojection.");
-
-// Test destination insertion points after removing the projected content from the host.
-host.removeChild(span);
-is(span.getDestinationInsertionPoints().length, 0, "Destination insertion points should be empty after being removed from the shadow host.");
-
-// Test destination insertion points of distributed content after removing insertion point.
-var div = document.createElement("div");
-div.setAttribute("class", "red blue");
-host.appendChild(div);
-
-is(div.getDestinationInsertionPoints().length, 2, "Div should be distributed into 2 insertion points.");
-
-innerShadowRoot.removeChild(innerInnerContent);
-
-is(div.getDestinationInsertionPoints().length, 1, "Div should be distributed into insertion point in one ShadowRoot.");
-is(div.getDestinationInsertionPoints()[0], innerContent, "Destination insertion points should only contain content insertion point in first ShadowRoot.");
-
-</script>
-</body>
-</html>
diff --git a/dom/tests/mochitest/webcomponents/test_dest_insertion_points_shadow.html b/dom/tests/mochitest/webcomponents/test_dest_insertion_points_shadow.html
deleted file mode 100644
index 75286463e..000000000
--- a/dom/tests/mochitest/webcomponents/test_dest_insertion_points_shadow.html
+++ /dev/null
@@ -1,68 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=999999
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 999999</title>
- <script type="application/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=999999">Mozilla Bug 999999</a>
-<p id="display"></p>
-<div id="content">
-<div id="shadowhost"></div>
-</div>
-<pre id="test">
-</pre>
-<script type="application/javascript">
-
-/** Test for Bug 999999 **/
-var host = document.getElementById("shadowhost");
-
-// Test destination insertion points of node distributed to shadow element.
-var olderShadowRoot = host.createShadowRoot();
-var youngerShadowRoot = host.createShadowRoot();
-
-var shadowElem = document.createElement("shadow");
-youngerShadowRoot.appendChild(shadowElem);
-
-var span = document.createElement("span");
-olderShadowRoot.appendChild(span);
-
-is(span.getDestinationInsertionPoints().length, 1, "Child of ShadowRoot should be distributed to shadow insertion point.");
-is(span.getDestinationInsertionPoints()[0], shadowElem, "Shadow element should be in destination insertion point list.");
-
-// Test destination insertion points of node removed from tree.
-olderShadowRoot.removeChild(span);
-is(span.getDestinationInsertionPoints().length, 0, "Node removed from tree should no longer be distributed.");
-
-// Test destination insertion points of fallback content being reprojected into a shadow element.
-var content = document.createElement("content");
-var fallback = document.createElement("span");
-
-content.appendChild(fallback);
-olderShadowRoot.appendChild(content);
-
-is(fallback.getDestinationInsertionPoints().length, 2, "The fallback content should have 2 destination insertion points, the parent content and the shadow element to which it is reprojected.");
-is(fallback.getDestinationInsertionPoints()[0], content, "First destination of the fallback content should be the parent content element.");
-is(fallback.getDestinationInsertionPoints()[1], shadowElem, "Second destination of the fallback content should be the shadow element to which the element is reprojected.");
-
-// Test destination insertion points of fallback content being removed from tree.
-content.removeChild(fallback);
-is(fallback.getDestinationInsertionPoints().length, 0, "The content should no longer be distributed to any nodes because it is no longer fallback content.");
-
-// Test destination insertion points of distributed content after removing shadow insertion point.
-var div = document.createElement("div");
-olderShadowRoot.appendChild(div);
-is(div.getDestinationInsertionPoints().length, 1, "Children in older shadow root should be distributed to shadow insertion point.");
-is(div.getDestinationInsertionPoints()[0], shadowElem, "Destination insertion point should include shadow element.");
-
-youngerShadowRoot.removeChild(shadowElem);
-is(div.getDestinationInsertionPoints().length, 0, "Destination insertion points should be empty after removing shadow element.");
-
-</script>
-</body>
-</html>
diff --git a/dom/tests/mochitest/webcomponents/test_document_register_parser.html b/dom/tests/mochitest/webcomponents/test_document_register_parser.html
deleted file mode 100644
index a4fb63139..000000000
--- a/dom/tests/mochitest/webcomponents/test_document_register_parser.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=783129
--->
-<head>
- <title>Test for document.registerElement for elements created by the parser</title>
- <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-<script>
-
-var extendedButtonProto = Object.create(HTMLButtonElement.prototype);
-var buttonCallbackCalled = false;
-extendedButtonProto.connectedCallback = function() {
- is(buttonCallbackCalled, false, "created callback for x-button should only be called once.");
- is(this.tagName, "BUTTON", "Only the <button> element should be upgraded.");
- buttonCallbackCalled = true;
-};
-
-document.registerElement("x-button", { prototype: extendedButtonProto, extends: "button" });
-
-var divProto = Object.create(HTMLDivElement.prototype);
-var divCallbackCalled = false;
-divProto.connectedCallback = function() {
- is(divCallbackCalled, false, "created callback for x-div should only be called once.");
- is(buttonCallbackCalled, true, "crated callback should be called for x-button before x-div.");
- is(this.tagName, "X-DIV", "Only the <x-div> element should be upgraded.");
- divCallbackCalled = true;
- SimpleTest.finish();
-};
-
-document.registerElement("x-div", { prototype: divProto });
-
-SimpleTest.waitForExplicitFinish();
-</script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
-<button is="x-button"></button><!-- should be upgraded -->
-<x-button></x-button><!-- should not be upgraded -->
-<span is="x-button"></span><!-- should not be upgraded -->
-<div is="x-div"></div><!-- should not be upgraded -->
-<x-div></x-div><!-- should be upgraded -->
-<script>
-</script>
-</body>
-</html>
diff --git a/dom/tests/mochitest/webcomponents/test_document_shared_registry.html b/dom/tests/mochitest/webcomponents/test_document_shared_registry.html
deleted file mode 100644
index db72e1e6c..000000000
--- a/dom/tests/mochitest/webcomponents/test_document_shared_registry.html
+++ /dev/null
@@ -1,46 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=783129
--->
-<head>
- <title>Test shared registry for associated HTML documents.</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="container"></div>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
-<script>
-var container = document.getElementById("container");
-
-function registerNoRegistryDoc() {
- var assocDoc = document.implementation.createDocument(null, "html");
- try {
- assocDoc.registerElement("x-dummy", { prototype: Object.create(HTMLElement.prototype) });
- ok(false, "Registring element in document without registry should throw.");
- } catch (ex) {
- ok(true, "Registring element in document without registry should throw.");
- }
-
- runNextTest();
-}
-
-function runNextTest() {
- if (testFunctions.length > 0) {
- var nextTestFunction = testFunctions.shift();
- nextTestFunction();
- }
-}
-
-var testFunctions = [
- registerNoRegistryDoc,
- SimpleTest.finish
-];
-
-SimpleTest.waitForExplicitFinish();
-
-runNextTest();
-</script>
-</body>
-</html>
diff --git a/dom/tests/mochitest/webcomponents/test_dynamic_content_element_matching.html b/dom/tests/mochitest/webcomponents/test_dynamic_content_element_matching.html
deleted file mode 100644
index c9af76610..000000000
--- a/dom/tests/mochitest/webcomponents/test_dynamic_content_element_matching.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=806506
--->
-<head>
- <title>Test for dynamic changes to content matching content elements</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();
-
-var redInsertionPoint = document.createElement("content");
-redInsertionPoint.select = "*[data-color=red]";
-
-var blueInsertionPoint = document.createElement("content");
-blueInsertionPoint.select = "*[data-color=blue]";
-
-root.appendChild(redInsertionPoint);
-root.appendChild(blueInsertionPoint);
-
-is(blueInsertionPoint.getDistributedNodes().length, 0, "Blue insertion point should have no distributed nodes.");
-is(redInsertionPoint.getDistributedNodes().length, 0, "Red insertion point should have no distrubted nodes.");
-
-var matchElement = document.createElement("div");
-matchElement.setAttribute("data-color", "red");
-elem.appendChild(matchElement);
-
-is(blueInsertionPoint.getDistributedNodes().length, 0, "Blue insertion point should have no distributed nodes.");
-is(redInsertionPoint.getDistributedNodes().length, 1, "Red insertion point should match recently inserted div.");
-
-matchElement.setAttribute("data-color", "blue");
-is(blueInsertionPoint.getDistributedNodes().length, 1, "Blue insertion point should match element after changing attribute value.");
-is(redInsertionPoint.getDistributedNodes().length, 0, "Red insertion point should not match element after changing attribute value.");
-
-matchElement.removeAttribute("data-color");
-
-is(blueInsertionPoint.getDistributedNodes().length, 0, "Blue insertion point should have no distributed nodes after removing the matching attribute.");
-is(redInsertionPoint.getDistributedNodes().length, 0, "Red insertion point should have no distrubted nodes after removing the matching attribute.");
-
-</script>
-</body>
-</html>
-
diff --git a/dom/tests/mochitest/webcomponents/test_event_dispatch.html b/dom/tests/mochitest/webcomponents/test_event_dispatch.html
deleted file mode 100644
index c73bfb214..000000000
--- a/dom/tests/mochitest/webcomponents/test_event_dispatch.html
+++ /dev/null
@@ -1,458 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=887541
--->
-<head>
- <title>Test for event model in web components</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=887541">Bug 887541</a>
-<script>
-
-var els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"]
- .getService(SpecialPowers.Ci.nsIEventListenerService);
-
-function eventListener(e) {
- eventChain.push(this);
-}
-
-function isEventChain(actual, expected, msg) {
- is(actual.length, expected.length, msg);
- for (var i = 0; i < expected.length; i++) {
- is(actual[i], expected[i], msg + " at " + i);
- }
-
- // Check to make sure the event chain matches what we get back from nsIEventListenerService.getEventTargetChainFor
- if (0 < actual.length) {
- var chain = els.getEventTargetChainFor(actual[0], true); // Events should be dispatched on actual[0].
- for (var i = 0; i < expected.length; i++) {
- ok(SpecialPowers.compare(chain[i], expected[i]), msg + " at " + i + " for nsIEventListenerService");
- }
- }
-}
-
-/*
- * Test 1: Test of event dispatch through a basic ShadowRoot with content a insertion point.
- *
- * <div elemOne> ------ <shadow-root shadowOne>
- * | |
- * <div elemTwo> <span elemThree>
- * |
- * <content elemFour>
- */
-
-var elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-var elemTwo = document.createElement("div");
-elemTwo.addEventListener("custom", eventListener);
-
-var elemThree = document.createElement("span");
-elemThree.addEventListener("custom", eventListener);
-
-var elemFour = document.createElement("content");
-elemFour.addEventListener("custom", eventListener);
-
-var shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-elemThree.appendChild(elemFour);
-shadowOne.appendChild(elemThree);
-elemOne.appendChild(elemTwo);
-
-var eventChain = [];
-var customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemTwo.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemTwo, elemFour, elemThree, shadowOne, elemOne], "Event path for test 1 for event dispatched on elemTwo.");
-
-/*
- * Test 2: Test of event dispatch through a nested ShadowRoots with content insertion points.
- *
- * <div elemFive> --- <shadow-root shadowTwo>
- * | |
- * <div elemOne> <div elemFour> ----- <shadow-root shadowOne>
- * | |
- * <content elemTwo> <p elemSix>
- * |
- * <content elemThree>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("content");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("content");
-elemThree.addEventListener("custom", eventListener);
-
-var elemFour = document.createElement("div");
-elemFour.addEventListener("custom", eventListener);
-
-var elemFive = document.createElement("div");
-elemFive.addEventListener("custom", eventListener);
-
-var elemSix = document.createElement("p");
-elemSix.addEventListener("custom", eventListener);
-
-var shadowOne = elemFour.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-var shadowTwo = elemFive.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-elemFive.appendChild(elemOne);
-shadowTwo.appendChild(elemFour);
-elemFour.appendChild(elemTwo);
-shadowOne.appendChild(elemSix);
-elemSix.appendChild(elemThree);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemOne.dispatchEvent(customEvent);
-is(elemOne.getDestinationInsertionPoints().length, 2, "yes");
-isEventChain(eventChain, [elemOne, elemThree, elemSix, shadowOne, elemTwo, elemFour, shadowTwo, elemFive], "Event path for test 2 for event dispatched on elemOne.");
-
-/*
- * Test 3: Test of event dispatch through nested ShadowRoot with content insertion points.
- *
- * <div elemOne> ------- <shadow-root shadowOne>
- * | |
- * <span elemTwo> <span elemThree> ------------ <shadow-root shadowTwo>
- * | |
- * <span elemFour> <content elemSix>
- * |
- * <content elemFive>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("span");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("span");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("span");
-elemFour.addEventListener("custom", eventListener);
-
-elemFive = document.createElement("content");
-elemFive.addEventListener("custom", eventListener);
-
-elemSix = document.createElement("content");
-elemSix.addEventListener("custom", eventListener);
-
-shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-shadowTwo = elemThree.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-elemOne.appendChild(elemTwo);
-shadowOne.appendChild(elemThree);
-elemThree.appendChild(elemFour);
-elemFour.appendChild(elemFive);
-shadowTwo.appendChild(elemSix);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemTwo.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemTwo, elemFive, elemFour, elemSix, shadowTwo, elemThree, shadowOne, elemOne], "Event path for test 3 for event dispatched on elemTwo.");
-
-/*
- * Test 4: Test of event dispatch through host with multiple ShadowRoots with shadow insertion point.
- *
- * <div elemSeven> --- <shadow-root shadowTwo> (younger ShadowRoot)
- * | | |
- * <div elemOne> | <div elemSix> -------- <shadow-root shadowOne>
- * | | |
- * | <shadow elemFour> <content elemFive>
- * | |
- * | <content elemTwo>
- * |
- * --- <shadow-root shadowThree> (older ShadowRoot)
- * | |
- * | <content elemThree>
- * |
- * <div elemEight>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("content");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("content");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("shadow");
-elemFour.addEventListener("custom", eventListener);
-
-elemFive = document.createElement("content");
-elemFive.addEventListener("custom", eventListener);
-
-elemSix = document.createElement("div");
-elemSix.addEventListener("custom", eventListener);
-
-var elemSeven = document.createElement("div");
-elemSeven.addEventListener("custom", eventListener);
-
-var elemEight = document.createElement("div");
-elemEight.addEventListener("custom", eventListener);
-
-var shadowThree = elemSeven.createShadowRoot();
-shadowThree.addEventListener("custom", eventListener);
-
-shadowTwo = elemSeven.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-shadowOne = elemSix.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-elemSeven.appendChild(elemOne);
-shadowTwo.appendChild(elemSix);
-elemSix.appendChild(elemFour);
-elemFour.appendChild(elemTwo);
-shadowThree.appendChild(elemEight);
-shadowThree.appendChild(elemThree);
-shadowOne.appendChild(elemFive);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemOne.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemOne, elemFive, shadowOne, elemThree, shadowThree, elemTwo, elemFour, elemSix, shadowTwo, elemSeven], "Event path for test 4 for event dispatched on elemOne.");
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemEight.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemEight, elemFive, shadowOne, elemSix, shadowTwo, elemSeven], "Event path for test 4 for event dispatched on elemEight.");
-
-/*
- * Test 5: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
- *
- * <div elemOne> --------- <shadow-root shadowOne>
- * | | |
- * | <p elemThree> <span elemFour> ------------------------ <shadow-root shadowTwo>
- * | | | |
- * <span elemTwo> | <content select="p" elemFive> <content elemSeven>
- * |
- * <content select="span" elemSix>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("span");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("p");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("span");
-elemFour.addEventListener("custom", eventListener);
-
-elemFive = document.createElement("content");
-elemFive.select = "p";
-elemFive.addEventListener("custom", eventListener);
-
-elemSix = document.createElement("content");
-elemSix.select = "span";
-elemSix.addEventListener("custom", eventListener);
-
-elemSeven = document.createElement("content");
-elemSeven.addEventListener("custom", eventListener);
-
-shadowTwo = elemFour.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-elemOne.appendChild(elemTwo);
-elemOne.appendChild(elemThree);
-shadowOne.appendChild(elemFour);
-elemFour.appendChild(elemSix);
-elemFour.appendChild(elemFive);
-shadowTwo.appendChild(elemSeven);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemTwo.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemTwo, elemSeven, shadowTwo, elemSix, elemFour, shadowOne, elemOne], "Event path for test 5 for event dispatched on elemTwo.");
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemThree.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemThree, elemSeven, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 5 for event dispatched on elemThree.");
-
-/*
- * Test 6: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
- *
- * <div elemOne> --------- <shadow-root shadowOne>;
- * | | |
- * | <p elemThree> <span elemFour> ------ <shadow-root shadowTwo>
- * | | | |
- * <span elemTwo> <content elemFive> | <content select="p" elemSeven>
- * |
- * <content select="span" elemSix>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("span");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("p");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("span");
-elemFour.addEventListener("custom", eventListener);
-
-elemFive = document.createElement("content");
-elemFive.addEventListener("custom", eventListener);
-
-elemSix = document.createElement("content");
-elemSix.select = "span";
-elemSix.addEventListener("custom", eventListener);
-
-elemSeven = document.createElement("content");
-elemSeven.select = "p";
-elemSeven.addEventListener("custom", eventListener);
-
-shadowTwo = elemFour.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-elemOne.appendChild(elemTwo);
-elemOne.appendChild(elemThree);
-shadowOne.appendChild(elemFour);
-elemFour.appendChild(elemFive);
-shadowTwo.appendChild(elemSix);
-shadowTwo.appendChild(elemSeven);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemTwo.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemTwo, elemSix, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 6 for event dispatched on elemTwo.");
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemThree.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemThree, elemSeven, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 6 for event dispatched on elemThree.");
-
-/*
- * Test 7: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
- *
- * <div elemOne> --------- <shadow-root shadowOne>
- * | | |
- * | <p elemThree> <span elemFour> ------ <shadow-root shadowTwo>
- * | | |
- * <span elemTwo> <content elemFive> <span elemEight>
- * | |
- * | <content select="p" elemSeven>
- * |
- * <content select="span" elemSix>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("span");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("p");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("span");
-elemFour.addEventListener("custom", eventListener);
-
-elemFive = document.createElement("content");
-elemFive.addEventListener("custom", eventListener);
-
-elemSix = document.createElement("content");
-elemSix.select = "span";
-elemSix.addEventListener("custom", eventListener);
-
-elemSeven = document.createElement("content");
-elemSeven.select = "p";
-elemSeven.addEventListener("custom", eventListener);
-
-elemEight = document.createElement("span");
-elemEight.addEventListener("custom", eventListener);
-
-shadowTwo = elemFour.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-elemOne.appendChild(elemTwo);
-elemOne.appendChild(elemThree);
-shadowOne.appendChild(elemFour);
-elemFour.appendChild(elemFive);
-shadowTwo.appendChild(elemEight);
-elemEight.appendChild(elemSix);
-elemEight.appendChild(elemSeven);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemTwo.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemTwo, elemSix, elemEight, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 7 for event dispatched on elemTwo.");
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemThree.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemThree, elemSeven, elemEight, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 7 for event dispatched on elemThree.");
-
-/*
- * Test 8: Test of event dispatch through host with multiple ShadowRoots with shadow insertion point.
- *
- * <div elemOne> --- <shadow-root shadowOne> (younger ShadowRoot)
- * | |
- * | <div elemFour>
- * | |
- * | <shadow elemTwo>
- * |
- * --- <shadow-root shadowTwo> (older ShadowRoot)
- * |
- * <div elemThree>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("shadow");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("div");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("div");
-elemFour.addEventListener("custom", eventListener);
-
-shadowTwo = elemOne.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-shadowOne.appendChild(elemFour);
-elemFour.appendChild(elemTwo);
-shadowTwo.appendChild(elemThree);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemThree.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemThree, shadowTwo, elemTwo, elemFour, shadowOne, elemOne], "Event path for test 8 for event dispatched on elemThree.");
-
-</script>
-</body>
-</html>
diff --git a/dom/tests/mochitest/webcomponents/test_fallback_dest_insertion_points.html b/dom/tests/mochitest/webcomponents/test_fallback_dest_insertion_points.html
deleted file mode 100644
index 4eefa165f..000000000
--- a/dom/tests/mochitest/webcomponents/test_fallback_dest_insertion_points.html
+++ /dev/null
@@ -1,71 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=999999
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 999999</title>
- <script type="application/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=999999">Mozilla Bug 999999</a>
-<p id="display"></p>
-<div id="content">
-<div id="shadowhost"></div>
-</div>
-<pre id="test">
-</pre>
-<script type="application/javascript">
-
-/** Test for Bug 999999 **/
-var host = document.getElementById("shadowhost");
-
-// Test destination insertion points of node distributed to content element.
-var shadowRoot = host.createShadowRoot();
-shadowRoot.innerHTML = '<div id="innerhost"><content id="innercontent"></content></div>';
-
-var fallback = document.createElement("span");
-var innerContent = shadowRoot.getElementById("innercontent");
-
-innerContent.appendChild(fallback);
-
-is(fallback.getDestinationInsertionPoints().length, 1, "Active fallback content should be distributed to insertion point.");
-is(fallback.getDestinationInsertionPoints()[0], innerContent, "Insertion point should be in list of destination insertion points.");
-
-// Test destination insertion points of reprojected fallback content.
-var innerHost = shadowRoot.getElementById("innerhost");
-var innerShadowRoot = innerHost.createShadowRoot();
-innerShadowRoot.innerHTML = '<content id="innerinnercontent"></content>';
-
-var innerInnerContent = innerShadowRoot.getElementById("innerinnercontent");
-
-is(fallback.getDestinationInsertionPoints().length, 2, "Fallback content should have been distributed into parent and reprojected into another insertion point.");
-is(fallback.getDestinationInsertionPoints()[1], innerInnerContent, "Destination insertion points should contain content element to which the node was reprojected.");
-
-// Test destination insertion points of fallback content that was dropped due to content element matching a node in the host.
-var span = document.createElement("span");
-host.appendChild(span);
-
-is(fallback.getDestinationInsertionPoints().length, 0, "After dropping insertion points, fallback content should not have any nodes in destination insertion points list.");
-
-// Test destination insertion points of fallback content after reactivating by dropping matched content on host.
-host.removeChild(span);
-is(fallback.getDestinationInsertionPoints().length, 2, "Fallback content should have 2 destination insertion points after being reactivated.");
-is(fallback.getDestinationInsertionPoints()[0], innerContent, "First destination insertion point should be the parent content");
-is(fallback.getDestinationInsertionPoints()[1], innerInnerContent, "Second destination insertion point should be the content to which the node is reprojected.");
-
-// Test destination insertion points of fallback content after removed from the tree.
-innerContent.removeChild(fallback);
-is(fallback.getDestinationInsertionPoints().length, 0, "Fallback content is no longer fallback content, destination insertion points should be empty.");
-
-// Test destination insertion points of child of non-insertion point content element.
-var notInsertionPointContent = document.createElement("content");
-var notFallback = document.createElement("span");
-notInsertionPointContent.appendChild(notFallback);
-is(notFallback.getDestinationInsertionPoints().length, 0, "Child of non-insertion point content should not be distributed to any nodes.");
-
-</script>
-</body>
-</html>
diff --git a/dom/tests/mochitest/webcomponents/test_nested_content_element.html b/dom/tests/mochitest/webcomponents/test_nested_content_element.html
deleted file mode 100644
index 1d98d2996..000000000
--- a/dom/tests/mochitest/webcomponents/test_nested_content_element.html
+++ /dev/null
@@ -1,127 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=806506
--->
-<head>
- <title>Test for HTMLContent element</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>
-
-/**
- * Constructs a node with a nested ShadowRoot with the following structure:
- * <span> - - - - - - - - - - <ShadowRoot>
- * <span> <span> - - - - - - - - - - <ShadowRoot>
- * id=one id=four <span>
- * data-color=red data-color=orange id=eleven
- * <span> <span> <content>
- * id=two id=five id=twelve
- * data-color=blue data-color=purple select=secondSelect
- * <span> <content> <span>
- * id=three id=six id=thirteen
- * data-color=green select=firstSelect
- * <span>
- * id=seven
- * <content>
- * id=eight
- * <span>
- * id=nine
- * <span>
- * id=ten
- * data-color=grey
- */
-function constructTree(firstSelect, secondSelect) {
- var rootSpan = document.createElement("span");
- rootSpan.innerHTML = '<span id="one" data-color="red"></span><span id="two" data-color="blue"></span><span id="three" data-color="green"></span>';
- var firstShadow = rootSpan.createShadowRoot();
- firstShadow.innerHTML = '<span id="four" data-color="orange"><span id="five" data-color="purple"></span><content id="six" select="' + firstSelect + '"><span id="seven"></span><content id="eight"></content><span id="nine"></span></content><span id="ten"></span></span>';
- var secondShadow = firstShadow.firstChild.createShadowRoot();
- secondShadow.innerHTML = '<span id="eleven"></span><content id="twelve" select="' + secondSelect + '"></content><span id="thirteen"></span>';
- return rootSpan;
-}
-
-// Create a tree with content that matches on everything and check node distribution.
-var allSpan = constructTree("*", "*");
-var firstContent = allSpan.shadowRoot.getElementById("six");
-var firstDistNodes = firstContent.getDistributedNodes();
-is(firstDistNodes.length, 3, "Universal selector should match all nodes.");
-// Check the order of the distributed nodes.
-is(firstDistNodes.item(0).id, "one", "First distributed node should have id of 'one'");
-is(firstDistNodes.item(1).id, "two", "Second distributed node should have id of 'two'");
-is(firstDistNodes.item(2).id, "three", "Third distributed node should have id of 'three'");
-var secondContent = allSpan.shadowRoot.firstChild.shadowRoot.getElementById("twelve");
-var secondDistNodes = secondContent.getDistributedNodes();
-is(secondDistNodes.length, 5, "Universial selector should match all nodes including those distributed into content.");
-// Check the order of the distribute nodes.
-is(secondDistNodes.item(0).id, "five", "First distributed node should have id of 'five'");
-is(secondDistNodes.item(1).id, "one", "Second distributed (reprojected) node should have id of 'one'");
-is(secondDistNodes.item(2).id, "two", "Third distributed (reprojected) node should have id of 'two'");
-is(secondDistNodes.item(3).id, "three", "Fourth distributed (reprojected) node should have id of 'three'");
-is(secondDistNodes.item(4).id, "ten", "Fifth distributed node should have id of 'ten'");
-
-// Append an element after id=two and make sure that it is inserted into the corrent
-// position in the insertion points.
-var additionalSpan = document.createElement("span");
-additionalSpan.id = "additional";
-
-// Insert the additional span in the third position, before the span with id=three.
-allSpan.insertBefore(additionalSpan, allSpan.childNodes.item(2));
-firstDistNodes = firstContent.getDistributedNodes();
-secondDistNodes = secondContent.getDistributedNodes();
-is(firstDistNodes.length, 4, "First insertion point should match one more node.");
-is(firstDistNodes.item(2).id, "additional", "Additional span should have been inserted into the third position of the first insertion point.");
-
-is(secondDistNodes.length, 6, "Second insertion point should match one more node.");
-is(secondDistNodes.item(3).id, "additional", "Additional span should have been inserted into the fourth position of the second insertion point.");
-
-function nodeListDoesNotContain(nodeList, element) {
- for (var i = 0; i < nodeList.length; i++) {
- if (nodeList[i] == element) {
- return false;
- }
- }
- return true;
-}
-
-// Remove the span with id=one and check that it is removed from all insertion points.
-allSpan = constructTree("*", "*");
-var spanOne = allSpan.firstChild;
-allSpan.removeChild(spanOne);
-firstContent = allSpan.shadowRoot.getElementById("six");
-ok(nodeListDoesNotContain(firstContent.getDistributedNodes(), spanOne), "Child removed from host should not appear in insertion point node list.");
-secondContent = allSpan.shadowRoot.firstChild.shadowRoot.getElementById("twelve");
-ok(nodeListDoesNotContain(secondContent.getDistributedNodes(), spanOne), "Child removed from host should not appear in nested insertion point node list.");
-
-// Make sure <content> in fallback content is inactive.
-// First insertion point will not match anything and will use fallback content.
-allSpan = constructTree("#nomatch", "*");
-var fallbackInsertionPoint = allSpan.shadowRoot.getElementById("eight");
-is(fallbackInsertionPoint.getDistributedNodes().length, 0, "Insertion points in default content should be inactive.");
-
-// Insertion points with non-universal selectors.
-allSpan = constructTree("span[data-color=blue]", "*");
-firstContent = allSpan.shadowRoot.getElementById("six");
-is(firstContent.getDistributedNodes().length, 1, "Insertion point selector should only match one node.");
-is(firstContent.getDistributedNodes()[0].dataset.color, "blue", "Projected node should match selector.");
-secondContent = allSpan.shadowRoot.firstChild.shadowRoot.getElementById("twelve");
-is(secondContent.getDistributedNodes().length, 3, "Second insertion point should match two children and one reprojected node.");
-is(secondContent.getDistributedNodes()[1].dataset.color, "blue", "Projected node should match selector.");
-
-allSpan = constructTree("span[data-color=blue]", "span[data-color=blue]");
-firstContent = allSpan.shadowRoot.getElementById("six");
-is(firstContent.getDistributedNodes().length, 1, "Insertion point selector should only match one node.");
-is(firstContent.getDistributedNodes()[0].dataset.color, "blue", "Projected node should match selector.");
-secondContent = allSpan.shadowRoot.firstChild.shadowRoot.getElementById("twelve");
-is(secondContent.getDistributedNodes().length, 1, "Insertion point should only match reprojected node.");
-is(secondContent.getDistributedNodes()[0].dataset.color, "blue", "Projected node should match selector.");
-
-// Make sure that dynamically appended default content will get distributed.
-</script>
-</body>
-</html>
-
diff --git a/dom/tests/mochitest/webcomponents/test_shadowroot_host.html b/dom/tests/mochitest/webcomponents/test_shadowroot_host.html
deleted file mode 100644
index f48d63e87..000000000
--- a/dom/tests/mochitest/webcomponents/test_shadowroot_host.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1083587
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1083587</title>
- <script type="application/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=1083587">Mozilla Bug 1083587</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-<div id="host"></div>
-</div>
-<pre id="test">
-</pre>
-<script type="application/javascript">
-
-/** Test for Bug 1083587 **/
-var hostInDoc = document.getElementById("host");
-var shadowOne = hostInDoc.createShadowRoot();
-is(shadowOne.host, hostInDoc);
-
-var shadowTwo = hostInDoc.createShadowRoot();
-is(shadowOne.host, hostInDoc);
-is(shadowTwo.host, hostInDoc);
-
-var hostNotInDoc = document.createElement("div");
-var shadowThree = hostNotInDoc.createShadowRoot();
-is(shadowThree.host, hostNotInDoc);
-
-var shadowFour = hostNotInDoc.createShadowRoot();
-is(shadowThree.host, hostNotInDoc);
-is(shadowFour.host, hostNotInDoc);
-
-</script>
-</body>
-</html>
diff --git a/dom/tests/mochitest/webcomponents/test_shadowroot_style_multiple_shadow.html b/dom/tests/mochitest/webcomponents/test_shadowroot_style_multiple_shadow.html
deleted file mode 100644
index 7a606bcd7..000000000
--- a/dom/tests/mochitest/webcomponents/test_shadowroot_style_multiple_shadow.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!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>
-<div id="container"></div>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
-<script>
-// Create ShadowRoot.
-var container = document.getElementById("container");
-var elem = document.createElement("div");
-container.appendChild(elem); // Put ShadowRoot host in document.
-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>
-
diff --git a/dom/tests/mochitest/webcomponents/test_shadowroot_youngershadowroot.html b/dom/tests/mochitest/webcomponents/test_shadowroot_youngershadowroot.html
deleted file mode 100644
index 17743321b..000000000
--- a/dom/tests/mochitest/webcomponents/test_shadowroot_youngershadowroot.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1083587
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 1083587</title>
- <script type="application/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=1083587">Mozilla Bug 1083587</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-<div id="host"></div>
-</div>
-<pre id="test">
-</pre>
-<script type="application/javascript">
-
-/** Test for Bug 1083587 **/
-var hostInDoc = document.getElementById("host");
-var shadowOne = hostInDoc.createShadowRoot();
-is(shadowOne.olderShadowRoot, null);
-
-var shadowTwo = hostInDoc.createShadowRoot();
-is(shadowOne.olderShadowRoot, null);
-is(shadowTwo.olderShadowRoot, shadowOne);
-
-var hostNotInDoc = document.createElement("div");
-var shadowThree = hostNotInDoc.createShadowRoot();
-is(shadowThree.olderShadowRoot, null);
-
-var shadowFour = hostNotInDoc.createShadowRoot();
-is(shadowThree.olderShadowRoot, null);
-is(shadowFour.olderShadowRoot, shadowThree);
-
-</script>
-</body>
-</html>
diff --git a/dom/tests/mochitest/webcomponents/test_template_custom_elements.html b/dom/tests/mochitest/webcomponents/test_template_custom_elements.html
deleted file mode 100644
index f7f4340cf..000000000
--- a/dom/tests/mochitest/webcomponents/test_template_custom_elements.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1091425
--->
-<head>
- <title>Test for custom elements in template</title>
- <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<template>
- <x-foo></x-foo>
-</template>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1091425">Bug 1091425</a>
-<script>
-
-var p = {};
-p.createdCallback = function() {
- ok(false, "Created callback should not be called for custom elements in templates.");
-};
-
-document.registerElement("x-foo", { prototype: p });
-
-ok(true, "Created callback should not be called for custom elements in templates.");
-
-</script>
-<template>
- <x-foo></x-foo>
-</template>
-</body>
-</html>
diff --git a/dom/tests/mochitest/webcomponents/test_unresolved_pseudo_class.html b/dom/tests/mochitest/webcomponents/test_unresolved_pseudo_class.html
deleted file mode 100644
index 3e1fae8ee..000000000
--- a/dom/tests/mochitest/webcomponents/test_unresolved_pseudo_class.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1111633
--->
-<head>
- <title>Test template element in stale document.</title>
- <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
- <style>
- :unresolved {
- color: rgb(0, 0, 255);
- background-color: rgb(0, 0, 255);
- }
-
- x-foo { color: rgb(255, 0, 0); }
-
- [is="x-del"]:not(:unresolved) { color: rgb(255, 0, 0); }
-
- [is="x-bar"]:not(:unresolved) { color: rgb(255, 0, 0); }
-
- [is="x-bar"]:unresolved { background-color: rgb(255, 0, 0); }
-
- x-baz:not(:unresolved) {
- color: rgb(255, 0, 0);
- background-color: rgb(255, 0, 0);
- }
-
- span { color: rgb(0,255,0); }
-
- x-foo:unresolved + span { color: rgb(255,0,0); }
-
- </style>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1111633">Bug 1111633</a>
-<div id="container"></div>
-<x-foo id="foo"></x-foo>
-<span id="span1">This text should be green</span>
-<span id="bar" is="x-bar"></span>
-<x-baz id="baz"></x-baz>
-<span id="del" is="x-del"></span>
-<script>
-
-// Before registerElement
-var foo = document.querySelector('#foo');
-is(getComputedStyle(foo).color, "rgb(0, 0, 255)", "foo - color");
-is(getComputedStyle(foo).backgroundColor, "rgb(0, 0, 255)", "foo - backgroundColor");
-
-var bar = document.querySelector('#bar');
-is(getComputedStyle(bar).color, "rgb(0, 0, 255)", "bar - color");
-is(getComputedStyle(bar).backgroundColor, "rgb(255, 0, 0)", "bar - backgroundColor");
-
-var baz = document.querySelector('#baz');
-is(getComputedStyle(baz).color, "rgb(0, 0, 255)", "baz - color");
-is(getComputedStyle(baz).backgroundColor, "rgb(0, 0, 255)", "baz - backgroundColor");
-
-var span1 = document.querySelector('#span1');
-is(getComputedStyle(span1).color, "rgb(255, 0, 0)", "span1 - color");
-
-var Foo = document.registerElement('x-foo', { prototype: Object.create(HTMLElement.prototype) });
-
-var Bar = document.registerElement('x-bar', { extends: 'span', prototype: Object.create(HTMLSpanElement.prototype) });
-
-var Baz = document.registerElement('x-baz', { prototype: Object.create(HTMLElement.prototype) });
-
-// After registerElement
-is(getComputedStyle(foo).color, "rgb(255, 0, 0)",
- "foo - color (after registerElement)");
-
-is(getComputedStyle(bar).color,
- "rgb(255, 0, 0)", "bar - color (after registerElement)");
-
-is(getComputedStyle(baz).color,
- "rgb(255, 0, 0)", "baz - color (after registerElement)");
-is(getComputedStyle(baz).backgroundColor,
- "rgb(255, 0, 0)", "baz - backgroundColor (after registerElement)");
-
-is(getComputedStyle(span1).color, "rgb(0, 255, 0)", "span1 - color (after registerElement)");
-
-// After tree removal
-var del = document.querySelector('#del');
-is(getComputedStyle(del).color, "rgb(0, 0, 255)", "del - color");
-var par = del.parentNode;
-par.removeChild(del);
-// Changing is attribute after creation should not change the type
-// of a custom element, even if the element was removed and re-append to the tree.
-del.setAttribute("is", "foobar");
-par.appendChild(del);
-is(getComputedStyle(del).color, "rgb(0, 0, 255)", "del - color (after reappend)");
-var Del = document.registerElement('x-del', { extends: 'span', prototype: Object.create(HTMLSpanElement.prototype) });
-// [is="x-del"] will not match any longer so the rule of span will apply
-is(getComputedStyle(del).color, "rgb(0, 255, 0)", "del - color (after registerElement)");
-// but the element should have been upgraded:
-ok(del instanceof Del, "element was upgraded correctly after changing |is|");
-
-</script>
-</body>
-</html>
diff --git a/dom/webidl/AnonymousContent.webidl b/dom/webidl/AnonymousContent.webidl
index 6755fe598..8be69cd26 100644
--- a/dom/webidl/AnonymousContent.webidl
+++ b/dom/webidl/AnonymousContent.webidl
@@ -77,4 +77,12 @@ interface AnonymousContent {
[Throws]
void setCutoutRectsForElement(DOMString elementId,
sequence<DOMRect> rects);
+
+ /**
+ * Get the computed value of a property on an element inside this custom
+ * anonymous content.
+ */
+ [Throws]
+ DOMString? getComputedStylePropertyValue(DOMString elementId,
+ DOMString propertyName);
};
diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl
index b28903ae2..ba2ec17ea 100644
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -17,6 +17,9 @@ enum VisibilityState { "hidden", "visible", "prerender" };
/* https://dom.spec.whatwg.org/#dictdef-elementcreationoptions */
dictionary ElementCreationOptions {
DOMString is;
+
+ [ChromeOnly]
+ DOMString pseudo;
};
/* http://dom.spec.whatwg.org/#interface-document */
@@ -268,13 +271,6 @@ partial interface Document {
attribute EventHandler onpointerlockerror;
};
-//http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-document-register
-partial interface Document {
- // this is deprecated from CustomElements v0
- [Throws, Func="CustomElementRegistry::IsCustomElementEnabled"]
- object registerElement(DOMString name, optional ElementRegistrationOptions options);
-};
-
// https://w3c.github.io/page-visibility/#extensions-to-the-document-interface
partial interface Document {
[Pref="dom.visibilityAPI.enabled"]
diff --git a/dom/webidl/Element.webidl b/dom/webidl/Element.webidl
index a6b2bfdd5..d5cac7c64 100644
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -228,14 +228,26 @@ partial interface Element {
NodeList querySelectorAll(DOMString selectors);
};
-// http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-element-interface
+// https://dom.spec.whatwg.org/#dictdef-shadowrootinit
+dictionary ShadowRootInit {
+ required ShadowRootMode mode;
+};
+
+// https://dom.spec.whatwg.org/#element
partial interface Element {
- [Throws,Func="nsDocument::IsWebComponentsEnabled"]
- ShadowRoot createShadowRoot();
- [Func="nsDocument::IsWebComponentsEnabled"]
- NodeList getDestinationInsertionPoints();
- [Func="nsDocument::IsWebComponentsEnabled"]
+ // Shadow DOM v1
+ [Throws, Func="nsDocument::IsWebComponentsEnabled"]
+ ShadowRoot attachShadow(ShadowRootInit shadowRootInitDict);
+ [BinaryName="shadowRootByMode", Func="nsDocument::IsWebComponentsEnabled"]
readonly attribute ShadowRoot? shadowRoot;
+ [BinaryName="assignedSlotByMode", Func="nsDocument::IsWebComponentsEnabled"]
+ readonly attribute HTMLSlotElement? assignedSlot;
+ [CEReactions, Unscopable, SetterThrows, Func="nsDocument::IsWebComponentsEnabled"]
+ attribute DOMString slot;
+
+ // [deprecated] Shadow DOM v0
+ [Throws, Func="nsDocument::IsWebComponentsEnabled"]
+ ShadowRoot createShadowRoot();
};
Element implements ChildNode;
diff --git a/dom/webidl/Event.webidl b/dom/webidl/Event.webidl
index a5d7da7d4..8a8e71c43 100644
--- a/dom/webidl/Event.webidl
+++ b/dom/webidl/Event.webidl
@@ -22,6 +22,8 @@ interface Event {
[Pure]
readonly attribute EventTarget? currentTarget;
+ sequence<EventTarget> composedPath();
+
const unsigned short NONE = 0;
const unsigned short CAPTURING_PHASE = 1;
const unsigned short AT_TARGET = 2;
diff --git a/dom/webidl/HTMLContentElement.webidl b/dom/webidl/HTMLContentElement.webidl
deleted file mode 100644
index ea809f120..000000000
--- a/dom/webidl/HTMLContentElement.webidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/.
- *
- * The origin of this IDL file is
- * https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html
- *
- * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
- * Opera Software ASA. You are granted a license to use, reproduce
- * and create derivative works of this document.
- */
-
-[Func="nsDocument::IsWebComponentsEnabled"]
-interface HTMLContentElement : HTMLElement
-{
- attribute DOMString select;
- NodeList getDistributedNodes();
-};
-
diff --git a/dom/webidl/HTMLShadowElement.webidl b/dom/webidl/HTMLSlotElement.webidl
index f72cd06e1..24dfcf350 100644
--- a/dom/webidl/HTMLShadowElement.webidl
+++ b/dom/webidl/HTMLSlotElement.webidl
@@ -4,16 +4,19 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
- * https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html
+ * https://html.spec.whatwg.org/multipage/forms.html#the-dialog-element
*
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
* Opera Software ASA. You are granted a license to use, reproduce
* and create derivative works of this document.
*/
-[Func="nsDocument::IsWebComponentsEnabled"]
-interface HTMLShadowElement : HTMLElement
-{
- readonly attribute ShadowRoot? olderShadowRoot;
+[Func="nsDocument::IsWebComponentsEnabled", Exposed=Window, HTMLConstructor]
+interface HTMLSlotElement : HTMLElement {
+ [CEReactions, SetterThrows] attribute DOMString name;
+ sequence<Node> assignedNodes(optional AssignedNodesOptions options);
};
+dictionary AssignedNodesOptions {
+ boolean flatten = false;
+}; \ No newline at end of file
diff --git a/dom/webidl/ShadowRoot.webidl b/dom/webidl/ShadowRoot.webidl
index 8dd069244..47e6cf5ec 100644
--- a/dom/webidl/ShadowRoot.webidl
+++ b/dom/webidl/ShadowRoot.webidl
@@ -10,17 +10,27 @@
* liability, trademark and document use rules apply.
*/
+// https://dom.spec.whatwg.org/#enumdef-shadowrootmode
+enum ShadowRootMode {
+ "open",
+ "closed"
+};
+
+// https://dom.spec.whatwg.org/#shadowroot
[Func="nsDocument::IsWebComponentsEnabled"]
interface ShadowRoot : DocumentFragment
{
+ // Shadow DOM v1
+ readonly attribute ShadowRootMode mode;
+ readonly attribute Element host;
+
+ // [deprecated] Shadow DOM v0
Element? getElementById(DOMString elementId);
HTMLCollection getElementsByTagName(DOMString localName);
HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
HTMLCollection getElementsByClassName(DOMString classNames);
[CEReactions, SetterThrows, TreatNullAs=EmptyString]
attribute DOMString innerHTML;
- readonly attribute Element host;
- readonly attribute ShadowRoot? olderShadowRoot;
attribute boolean applyAuthorStyles;
readonly attribute StyleSheetList styleSheets;
};
diff --git a/dom/webidl/Text.webidl b/dom/webidl/Text.webidl
index dcd25cec3..fb7b5d685 100644
--- a/dom/webidl/Text.webidl
+++ b/dom/webidl/Text.webidl
@@ -18,4 +18,9 @@ interface Text : CharacterData {
readonly attribute DOMString wholeText;
};
+partial interface Text {
+ [BinaryName="assignedSlotByMode", Func="nsTextNode::IsWebComponentsEnabled"]
+ readonly attribute HTMLSlotElement? assignedSlot;
+};
+
Text implements GeometryUtils;
diff --git a/dom/webidl/WebComponents.webidl b/dom/webidl/WebComponents.webidl
index f9bb8214a..9c5e53131 100644
--- a/dom/webidl/WebComponents.webidl
+++ b/dom/webidl/WebComponents.webidl
@@ -25,8 +25,3 @@ dictionary LifecycleCallbacks {
LifecycleAdoptedCallback? adoptedCallback;
LifecycleAttributeChangedCallback? attributeChangedCallback;
};
-
-dictionary ElementRegistrationOptions {
- object? prototype = null;
- DOMString? extends = null;
-};
diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build
index 156da302d..d76a58e1f 100644
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -177,7 +177,6 @@ WEBIDL_FILES = [
'HTMLButtonElement.webidl',
'HTMLCanvasElement.webidl',
'HTMLCollection.webidl',
- 'HTMLContentElement.webidl',
'HTMLDataElement.webidl',
'HTMLDataListElement.webidl',
'HTMLDetailsElement.webidl',
@@ -226,7 +225,7 @@ WEBIDL_FILES = [
'HTMLQuoteElement.webidl',
'HTMLScriptElement.webidl',
'HTMLSelectElement.webidl',
- 'HTMLShadowElement.webidl',
+ 'HTMLSlotElement.webidl',
'HTMLSourceElement.webidl',
'HTMLSpanElement.webidl',
'HTMLStyleElement.webidl',
diff --git a/dom/workers/SharedWorker.cpp b/dom/workers/SharedWorker.cpp
index 99bb50339..71c644405 100644
--- a/dom/workers/SharedWorker.cpp
+++ b/dom/workers/SharedWorker.cpp
@@ -181,7 +181,7 @@ SharedWorker::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
}
nsresult
-SharedWorker::PreHandleEvent(EventChainPreVisitor& aVisitor)
+SharedWorker::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
AssertIsOnMainThread();
@@ -196,9 +196,9 @@ SharedWorker::PreHandleEvent(EventChainPreVisitor& aVisitor)
QueueEvent(event);
aVisitor.mCanHandle = false;
- aVisitor.mParentTarget = nullptr;
+ aVisitor.SetParentTarget(nullptr, false);
return NS_OK;
}
- return DOMEventTargetHelper::PreHandleEvent(aVisitor);
+ return DOMEventTargetHelper::GetEventTargetParent(aVisitor);
}
diff --git a/dom/workers/SharedWorker.h b/dom/workers/SharedWorker.h
index 220436e4d..4b50d39e8 100644
--- a/dom/workers/SharedWorker.h
+++ b/dom/workers/SharedWorker.h
@@ -76,7 +76,7 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
virtual nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
WorkerPrivate*
GetWorkerPrivate() const
diff --git a/dom/xbl/XBLChildrenElement.cpp b/dom/xbl/XBLChildrenElement.cpp
index e4058a789..f785a3058 100644
--- a/dom/xbl/XBLChildrenElement.cpp
+++ b/dom/xbl/XBLChildrenElement.cpp
@@ -7,6 +7,7 @@
#include "mozilla/dom/XBLChildrenElement.h"
#include "nsCharSeparatedTokenizer.h"
#include "mozilla/dom/NodeListBinding.h"
+#include "nsAttrValueOrString.h"
namespace mozilla {
namespace dom {
@@ -27,34 +28,24 @@ NS_INTERFACE_MAP_END_INHERITING(Element)
NS_IMPL_ELEMENT_CLONE(XBLChildrenElement)
nsresult
-XBLChildrenElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify)
+XBLChildrenElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify)
{
- if (aAttribute == nsGkAtoms::includes &&
- aNameSpaceID == kNameSpaceID_None) {
- mIncludes.Clear();
- }
-
- return Element::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
-}
-
-bool
-XBLChildrenElement::ParseAttribute(int32_t aNamespaceID,
- nsIAtom* aAttribute,
- const nsAString& aValue,
- nsAttrValue& aResult)
-{
- if (aAttribute == nsGkAtoms::includes &&
- aNamespaceID == kNameSpaceID_None) {
- mIncludes.Clear();
- nsCharSeparatedTokenizer tok(aValue, '|',
- nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
- while (tok.hasMoreTokens()) {
- mIncludes.AppendElement(NS_Atomize(tok.nextToken()));
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::includes) {
+ mIncludes.Clear();
+ if (aValue) {
+ nsCharSeparatedTokenizer tok(aValue->String(), '|',
+ nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
+ while (tok.hasMoreTokens()) {
+ mIncludes.AppendElement(NS_Atomize(tok.nextToken()));
+ }
+ }
}
}
- return false;
+ return nsXMLElement::BeforeSetAttr(aNamespaceID, aName, aValue, aNotify);
}
} // namespace dom
diff --git a/dom/xbl/XBLChildrenElement.h b/dom/xbl/XBLChildrenElement.h
index 4714da4a8..c01085474 100644
--- a/dom/xbl/XBLChildrenElement.h
+++ b/dom/xbl/XBLChildrenElement.h
@@ -37,14 +37,6 @@ public:
virtual nsIDOMNode* AsDOMNode() override { return this; }
- // nsIContent interface methods
- virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
- bool aNotify) override;
- virtual bool ParseAttribute(int32_t aNamespaceID,
- nsIAtom* aAttribute,
- const nsAString& aValue,
- nsAttrValue& aResult) override;
-
void AppendInsertedChild(nsIContent* aChild)
{
mInsertedChildren.AppendElement(aChild);
@@ -147,6 +139,10 @@ public:
protected:
~XBLChildrenElement();
+ virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString* aValue,
+ bool aNotify) override;
+
private:
nsTArray<nsIContent*> mInsertedChildren; // WEAK
nsTArray<nsCOMPtr<nsIAtom> > mIncludes;
diff --git a/dom/xbl/nsXBLService.cpp b/dom/xbl/nsXBLService.cpp
index 1475b1368..b50b2c6fe 100644
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -115,45 +115,19 @@ public:
if (!doc)
return;
- // Destroy the frames for mBoundElement.
- nsIContent* destroyedFramesFor = nullptr;
- nsIPresShell* shell = doc->GetShell();
- if (shell) {
- shell->DestroyFramesFor(mBoundElement, &destroyedFramesFor);
- }
- MOZ_ASSERT(!mBoundElement->GetPrimaryFrame());
-
// Get the binding.
bool ready = false;
nsXBLService::GetInstance()->BindingReady(mBoundElement, mBindingURI, &ready);
if (!ready)
return;
- // If |mBoundElement| is (in addition to having binding |mBinding|)
- // also a descendant of another element with binding |mBinding|,
- // then we might have just constructed it due to the
- // notification of its parent. (We can know about both if the
- // binding loads were triggered from the DOM rather than frame
- // construction.) So we have to check both whether the element
- // has a primary frame and whether it's in the frame manager maps
- // before sending a ContentInserted notification, or bad things
- // will happen.
- MOZ_ASSERT(shell == doc->GetShell());
- if (shell) {
- nsIFrame* childFrame = mBoundElement->GetPrimaryFrame();
- if (!childFrame) {
- // Check to see if it's in the undisplayed content map...
- nsFrameManager* fm = shell->FrameManager();
- nsStyleContext* sc = fm->GetUndisplayedContent(mBoundElement);
- if (!sc) {
- // or in the display:contents map.
- sc = fm->GetDisplayContentsStyleFor(mBoundElement);
- }
- if (!sc) {
- shell->CreateFramesFor(destroyedFramesFor);
- }
- }
+ // Destroy the frames for mBoundElement. Do this after getting the binding,
+ // since if the binding fetch fails then we don't want to destroy the
+ // frames.
+ if (nsIPresShell* shell = doc->GetShell()) {
+ shell->DestroyFramesForAndRestyle(mBoundElement->AsElement());
}
+ MOZ_ASSERT(!mBoundElement->GetPrimaryFrame());
}
nsXBLBindingRequest(nsIURI* aURI, nsIContent* aBoundElement)
diff --git a/dom/xml/nsXMLElement.cpp b/dom/xml/nsXMLElement.cpp
index 45163a1c4..ad0314f4c 100644
--- a/dom/xml/nsXMLElement.cpp
+++ b/dom/xml/nsXMLElement.cpp
@@ -9,6 +9,7 @@
#include "mozilla/dom/ElementInlines.h"
#include "nsContentUtils.h" // nsAutoScriptBlocker
+using namespace mozilla;
using namespace mozilla::dom;
nsresult
@@ -29,4 +30,26 @@ nsXMLElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
return ElementBinding::Wrap(aCx, this, aGivenProto);
}
+void
+nsXMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
+{
+ CSSPseudoElementType pseudoType = GetPseudoElementType();
+ bool isBefore = pseudoType == CSSPseudoElementType::before;
+ nsIAtom* property = isBefore
+ ? nsGkAtoms::beforePseudoProperty : nsGkAtoms::afterPseudoProperty;
+
+ switch (pseudoType) {
+ case CSSPseudoElementType::before:
+ case CSSPseudoElementType::after: {
+ MOZ_ASSERT(GetParent());
+ MOZ_ASSERT(GetParent()->IsElement());
+ GetParent()->DeleteProperty(property);
+ break;
+ }
+ default:
+ break;
+ }
+ Element::UnbindFromTree(aDeep, aNullParent);
+}
+
NS_IMPL_ELEMENT_CLONE(nsXMLElement)
diff --git a/dom/xml/nsXMLElement.h b/dom/xml/nsXMLElement.h
index d16b82f39..85f79970c 100644
--- a/dom/xml/nsXMLElement.h
+++ b/dom/xml/nsXMLElement.h
@@ -35,6 +35,9 @@ public:
virtual nsIDOMNode* AsDOMNode() override { return this; }
+ virtual void UnbindFromTree(bool aDeep = true,
+ bool aNullParent = true) override;
+
protected:
virtual ~nsXMLElement() {}
diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
index facb435b4..0a2dd9b08 100644
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
+++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
@@ -1284,6 +1284,11 @@ txMozillaXSLTProcessor::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenP
return XSLTProcessorBinding::Wrap(aCx, this, aGivenProto);
}
+DocGroup*
+txMozillaXSLTProcessor::GetDocGroup() const
+{
+ return mStylesheetDocument ? mStylesheetDocument->GetDocGroup() : nullptr;
+}
/* static */ already_AddRefed<txMozillaXSLTProcessor>
txMozillaXSLTProcessor::Constructor(const GlobalObject& aGlobal,
diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.h b/dom/xslt/xslt/txMozillaXSLTProcessor.h
index 93d3c2c30..fc76585f2 100644
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.h
+++ b/dom/xslt/xslt/txMozillaXSLTProcessor.h
@@ -29,6 +29,7 @@ class txIGlobalParameter;
namespace mozilla {
namespace dom {
+class DocGroup;
class Document;
class DocumentFragment;
class GlobalObject;
@@ -103,6 +104,8 @@ public:
return mOwner;
}
+ mozilla::dom::DocGroup* GetDocGroup() const;
+
static already_AddRefed<txMozillaXSLTProcessor>
Constructor(const mozilla::dom::GlobalObject& aGlobal,
mozilla::ErrorResult& aRv);
diff --git a/dom/xul/XULDocument.cpp b/dom/xul/XULDocument.cpp
index 1dcb55aee..929efc1af 100644
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -66,7 +66,6 @@
#include "nsContentUtils.h"
#include "nsIParser.h"
#include "nsCharsetSource.h"
-#include "nsIParserService.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/css/Loader.h"
#include "nsIScriptError.h"
diff --git a/dom/xul/nsXULElement.cpp b/dom/xul/nsXULElement.cpp
index a854f53ec..2ae03e0b1 100644
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -126,6 +126,8 @@ uint32_t nsXULPrototypeAttribute::gNumCacheSets;
uint32_t nsXULPrototypeAttribute::gNumCacheFills;
#endif
+#define NS_DISPATCH_XUL_COMMAND (1 << 0)
+
class nsXULElementTearoff final : public nsIFrameLoaderOwner
{
~nsXULElementTearoff() {}
@@ -202,7 +204,7 @@ nsXULElement::Create(nsXULPrototypeElement* aPrototype, mozilla::dom::NodeInfo *
element->SetHasID();
}
if (aPrototype->mHasClassAttribute) {
- element->SetFlags(NODE_MAY_HAVE_CLASS);
+ element->SetMayHaveClass();
}
if (aPrototype->mHasStyleAttribute) {
element->SetMayHaveStyle();
@@ -358,12 +360,15 @@ nsXULElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
attrValue.SetTo(*originalValue);
}
+ bool oldValueSet;
if (originalName->IsAtom()) {
rv = element->mAttrsAndChildren.SetAndSwapAttr(originalName->Atom(),
- attrValue);
+ attrValue,
+ &oldValueSet);
} else {
rv = element->mAttrsAndChildren.SetAndSwapAttr(originalName->NodeInfo(),
- attrValue);
+ attrValue,
+ &oldValueSet);
}
NS_ENSURE_SUCCESS(rv, rv);
element->AddListenerFor(*originalName, true);
@@ -372,7 +377,7 @@ nsXULElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
element->SetHasID();
}
if (originalName->Equals(nsGkAtoms::_class)) {
- element->SetFlags(NODE_MAY_HAVE_CLASS);
+ element->SetMayHaveClass();
}
if (originalName->Equals(nsGkAtoms::style)) {
element->SetMayHaveStyle();
@@ -1005,7 +1010,7 @@ nsXULElement::UnregisterAccessKey(const nsAString& aOldValue)
nsresult
nsXULElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue, bool aNotify)
+ const nsAttrValueOrString* aValue, bool aNotify)
{
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::accesskey &&
IsInUncomposedDoc()) {
@@ -1051,7 +1056,8 @@ nsXULElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
nsresult
nsXULElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNamespaceID == kNameSpaceID_None) {
if (aValue) {
@@ -1172,7 +1178,7 @@ nsXULElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
}
return nsStyledElement::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
bool
@@ -1236,20 +1242,68 @@ nsXULElement::List(FILE* out, int32_t aIndent) const
}
#endif
+bool
+nsXULElement::IsEventStoppedFromAnonymousScrollbar(EventMessage aMessage)
+{
+ return (IsRootOfNativeAnonymousSubtree() &&
+ IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::scrollcorner) &&
+ (aMessage == eMouseClick || aMessage == eMouseDoubleClick ||
+ aMessage == eXULCommand || aMessage == eContextMenu ||
+ aMessage == eDragStart));
+}
+
nsresult
-nsXULElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsXULElement::DispatchXULCommand(const EventChainVisitor& aVisitor,
+ nsAutoString& aCommand)
+{
+ // XXX sXBL/XBL2 issue! Owner or current document?
+ nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(GetUncomposedDoc()));
+ NS_ENSURE_STATE(domDoc);
+ nsCOMPtr<nsIDOMElement> commandElt;
+ domDoc->GetElementById(aCommand, getter_AddRefs(commandElt));
+ nsCOMPtr<nsIContent> commandContent(do_QueryInterface(commandElt));
+ if (commandContent) {
+ // Create a new command event to dispatch to the element
+ // pointed to by the command attribute. The new event's
+ // sourceEvent will be the original command event that we're
+ // handling.
+ nsCOMPtr<nsIDOMEvent> domEvent = aVisitor.mDOMEvent;
+ while (domEvent) {
+ Event* event = domEvent->InternalDOMEvent();
+ NS_ENSURE_STATE(!SameCOMIdentity(event->GetOriginalTarget(),
+ commandContent));
+ nsCOMPtr<nsIDOMXULCommandEvent> commandEvent =
+ do_QueryInterface(domEvent);
+ if (commandEvent) {
+ commandEvent->GetSourceEvent(getter_AddRefs(domEvent));
+ } else {
+ domEvent = nullptr;
+ }
+ }
+ WidgetInputEvent* orig = aVisitor.mEvent->AsInputEvent();
+ nsContentUtils::DispatchXULCommand(
+ commandContent,
+ orig->IsTrusted(),
+ aVisitor.mDOMEvent,
+ nullptr,
+ orig->IsControl(),
+ orig->IsAlt(),
+ orig->IsShift(),
+ orig->IsMeta());
+ } else {
+ NS_WARNING("A XUL element is attached to a command that doesn't exist!\n");
+ }
+ return NS_OK;
+}
+
+nsresult
+nsXULElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
- if (IsRootOfNativeAnonymousSubtree() &&
- (IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::scrollcorner)) &&
- (aVisitor.mEvent->mMessage == eMouseClick ||
- aVisitor.mEvent->mMessage == eMouseDoubleClick ||
- aVisitor.mEvent->mMessage == eXULCommand ||
- aVisitor.mEvent->mMessage == eContextMenu ||
- aVisitor.mEvent->mMessage == eDragStart)) {
+ if (IsEventStoppedFromAnonymousScrollbar(aVisitor.mEvent->mMessage)) {
// Don't propagate these events from native anonymous scrollbar.
aVisitor.mCanHandle = true;
- aVisitor.mParentTarget = nullptr;
+ aVisitor.SetParentTarget(nullptr, false);
return NS_OK;
}
if (aVisitor.mEvent->mMessage == eXULCommand &&
@@ -1263,55 +1317,33 @@ nsXULElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
// See if we have a command elt. If so, we execute on the command
// instead of on our content element.
nsAutoString command;
- if (xulEvent && GetAttr(kNameSpaceID_None, nsGkAtoms::command, command) &&
+ if (xulEvent &&
+ GetAttr(kNameSpaceID_None, nsGkAtoms::command, command) &&
!command.IsEmpty()) {
// Stop building the event target chain for the original event.
// We don't want it to propagate to any DOM nodes.
aVisitor.mCanHandle = false;
aVisitor.mAutomaticChromeDispatch = false;
-
- // XXX sXBL/XBL2 issue! Owner or current document?
- nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(GetUncomposedDoc()));
- NS_ENSURE_STATE(domDoc);
- nsCOMPtr<nsIDOMElement> commandElt;
- domDoc->GetElementById(command, getter_AddRefs(commandElt));
- nsCOMPtr<nsIContent> commandContent(do_QueryInterface(commandElt));
- if (commandContent) {
- // Create a new command event to dispatch to the element
- // pointed to by the command attribute. The new event's
- // sourceEvent will be the original command event that we're
- // handling.
- nsCOMPtr<nsIDOMEvent> domEvent = aVisitor.mDOMEvent;
- while (domEvent) {
- Event* event = domEvent->InternalDOMEvent();
- NS_ENSURE_STATE(!SameCOMIdentity(event->GetOriginalTarget(),
- commandContent));
- nsCOMPtr<nsIDOMXULCommandEvent> commandEvent =
- do_QueryInterface(domEvent);
- if (commandEvent) {
- commandEvent->GetSourceEvent(getter_AddRefs(domEvent));
- } else {
- domEvent = nullptr;
- }
- }
-
- WidgetInputEvent* orig = aVisitor.mEvent->AsInputEvent();
- nsContentUtils::DispatchXULCommand(
- commandContent,
- aVisitor.mEvent->IsTrusted(),
- aVisitor.mDOMEvent,
- nullptr,
- orig->IsControl(),
- orig->IsAlt(),
- orig->IsShift(),
- orig->IsMeta());
- } else {
- NS_WARNING("A XUL element is attached to a command that doesn't exist!\n");
- }
+ // Dispatch XUL command in PreHandleEvent to prevent it breaks event
+ // target chain creation
+ aVisitor.mWantsPreHandleEvent = true;
+ aVisitor.mItemFlags |= NS_DISPATCH_XUL_COMMAND;
return NS_OK;
}
}
+ return nsStyledElement::GetEventTargetParent(aVisitor);
+}
+
+nsresult
+nsXULElement::PreHandleEvent(EventChainVisitor& aVisitor)
+{
+ if (aVisitor.mItemFlags & NS_DISPATCH_XUL_COMMAND) {
+ nsAutoString command;
+ GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
+ MOZ_ASSERT(!command.IsEmpty());
+ return DispatchXULCommand(aVisitor, command);
+ }
return nsStyledElement::PreHandleEvent(aVisitor);
}
@@ -1880,12 +1912,14 @@ nsXULElement::MakeHeavyweight(nsXULPrototypeElement* aPrototype)
attrValue.SetTo(protoattr->mValue);
}
+ bool oldValueSet;
// XXX we might wanna have a SetAndTakeAttr that takes an nsAttrName
if (protoattr->mName.IsAtom()) {
- rv = mAttrsAndChildren.SetAndSwapAttr(protoattr->mName.Atom(), attrValue);
+ rv = mAttrsAndChildren.SetAndSwapAttr(protoattr->mName.Atom(),
+ attrValue, &oldValueSet);
} else {
rv = mAttrsAndChildren.SetAndSwapAttr(protoattr->mName.NodeInfo(),
- attrValue);
+ attrValue, &oldValueSet);
}
NS_ENSURE_SUCCESS(rv, rv);
}
diff --git a/dom/xul/nsXULElement.h b/dom/xul/nsXULElement.h
index 80424412f..a30714145 100644
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -355,9 +355,10 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULElement, nsStyledElement)
// nsINode
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
-
+ virtual nsresult PreHandleEvent(
+ mozilla::EventChainVisitor& aVisitor) override;
// nsIContent
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
@@ -623,10 +624,12 @@ protected:
nsresult MakeHeavyweight(nsXULPrototypeElement* aPrototype);
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- nsAttrValueOrString* aValue,
+ const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual void UpdateEditableState(bool aNotify) override;
@@ -689,6 +692,11 @@ protected:
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
void MaybeUpdatePrivateLifetime();
+
+ bool IsEventStoppedFromAnonymousScrollbar(mozilla::EventMessage aMessage);
+
+ nsresult DispatchXULCommand(const mozilla::EventChainVisitor& aVisitor,
+ nsAutoString& aCommand);
};
#endif // nsXULElement_h__