summaryrefslogtreecommitdiffstats
path: root/dom/html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/html')
-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
85 files changed, 1634 insertions, 2456 deletions
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>