diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index df79f4d8d5b..bf6902642aa 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -1803,6 +1803,12 @@ Element::IsLabelable() const return false; } +bool +Element::IsInteractiveHTMLContent() const +{ + return false; +} + css::StyleRule* Element::GetInlineStyleRule() { diff --git a/dom/base/Element.h b/dom/base/Element.h index 44f24627fc5..b168e1c0174 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -284,6 +284,11 @@ public: */ virtual bool IsLabelable() const; + /** + * Returns if the element is interactive content as per HTML specification. + */ + virtual bool IsInteractiveHTMLContent() const; + /** * Is the attribute named stored in the mapped attributes? * diff --git a/dom/html/HTMLAnchorElement.h b/dom/html/HTMLAnchorElement.h index 8f66570f43d..1471fc552db 100644 --- a/dom/html/HTMLAnchorElement.h +++ b/dom/html/HTMLAnchorElement.h @@ -42,6 +42,12 @@ public: virtual int32_t TabIndexDefault() MOZ_OVERRIDE; virtual bool Draggable() const MOZ_OVERRIDE; + // Element + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE + { + return true; + } + // nsIDOMHTMLAnchorElement NS_DECL_NSIDOMHTMLANCHORELEMENT diff --git a/dom/html/HTMLAudioElement.cpp b/dom/html/HTMLAudioElement.cpp index ee8a2168a7b..39d1d5df8f6 100644 --- a/dom/html/HTMLAudioElement.cpp +++ b/dom/html/HTMLAudioElement.cpp @@ -40,6 +40,12 @@ HTMLAudioElement::~HTMLAudioElement() { } +bool +HTMLAudioElement::IsInteractiveHTMLContent() const +{ + return HasAttr(kNameSpaceID_None, nsGkAtoms::controls); +} + already_AddRefed HTMLAudioElement::Audio(const GlobalObject& aGlobal, const Optional& aSrc, diff --git a/dom/html/HTMLAudioElement.h b/dom/html/HTMLAudioElement.h index 767ce81822f..3b6ef48d351 100644 --- a/dom/html/HTMLAudioElement.h +++ b/dom/html/HTMLAudioElement.h @@ -23,6 +23,9 @@ public: explicit HTMLAudioElement(already_AddRefed& aNodeInfo); + // Element + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE; + // nsIDOMHTMLMediaElement using HTMLMediaElement::GetPaused; diff --git a/dom/html/HTMLButtonElement.h b/dom/html/HTMLButtonElement.h index 8822330a568..776eaf87d42 100644 --- a/dom/html/HTMLButtonElement.h +++ b/dom/html/HTMLButtonElement.h @@ -36,6 +36,12 @@ public: NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLButtonElement, button) + // Element + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE + { + return true; + } + // nsIDOMHTMLButtonElement NS_DECL_NSIDOMHTMLBUTTONELEMENT diff --git a/dom/html/HTMLIFrameElement.h b/dom/html/HTMLIFrameElement.h index 9ac11e8f0d6..4b3560c1162 100644 --- a/dom/html/HTMLIFrameElement.h +++ b/dom/html/HTMLIFrameElement.h @@ -26,6 +26,12 @@ public: // nsISupports NS_DECL_ISUPPORTS_INHERITED + // Element + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE + { + return true; + } + // nsIDOMHTMLIFrameElement NS_DECL_NSIDOMHTMLIFRAMEELEMENT diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index 11d27bbe192..9dbce4c5f8e 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -148,6 +148,12 @@ NS_IMPL_STRING_ATTR(HTMLImageElement, Srcset, srcset) NS_IMPL_STRING_ATTR(HTMLImageElement, UseMap, usemap) NS_IMPL_INT_ATTR(HTMLImageElement, Vspace, vspace) +bool +HTMLImageElement::IsInteractiveHTMLContent() const +{ + return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap); +} + bool HTMLImageElement::IsSrcsetEnabled() { diff --git a/dom/html/HTMLImageElement.h b/dom/html/HTMLImageElement.h index d11765600fc..768648b9df6 100644 --- a/dom/html/HTMLImageElement.h +++ b/dom/html/HTMLImageElement.h @@ -46,6 +46,9 @@ public: virtual bool Draggable() const MOZ_OVERRIDE; + // Element + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE; + // nsIDOMHTMLImageElement NS_DECL_NSIDOMHTMLIMAGEELEMENT diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 2267dc17ff0..3fc1585e852 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -3211,6 +3211,12 @@ HTMLInputElement::Focus(ErrorResult& aError) return; } +bool +HTMLInputElement::IsInteractiveHTMLContent() const +{ + return mType != NS_FORM_INPUT_HIDDEN; +} + NS_IMETHODIMP HTMLInputElement::Select() { diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index 37cb473c52f..02a9546107b 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -119,6 +119,9 @@ public: virtual void Blur(ErrorResult& aError) MOZ_OVERRIDE; virtual void Focus(ErrorResult& aError) MOZ_OVERRIDE; + // Element + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE; + // nsIDOMHTMLInputElement NS_DECL_NSIDOMHTMLINPUTELEMENT diff --git a/dom/html/HTMLLabelElement.cpp b/dom/html/HTMLLabelElement.cpp index 0509dfe1257..110a04cf3dd 100644 --- a/dom/html/HTMLLabelElement.cpp +++ b/dom/html/HTMLLabelElement.cpp @@ -83,19 +83,14 @@ HTMLLabelElement::Focus(ErrorResult& aError) } static bool -EventTargetIn(WidgetEvent* aEvent, nsIContent* aChild, nsIContent* aStop) +InInteractiveHTMLContent(nsIContent* aContent, nsIContent* aStop) { - nsCOMPtr c = do_QueryInterface(aEvent->target); - nsIContent *content = c; - while (content) { - if (content == aChild) { + nsIContent* content = aContent; + while (content && content != aStop) { + if (content->IsElement() && + content->AsElement()->IsInteractiveHTMLContent()) { return true; } - - if (content == aStop) { - break; - } - content = content->GetParent(); } return false; @@ -115,10 +110,15 @@ HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor) return NS_OK; } + nsCOMPtr target = do_QueryInterface(aVisitor.mEvent->target); + if (InInteractiveHTMLContent(target, this)) { + return NS_OK; + } + // Strong ref because event dispatch is going to happen. nsRefPtr content = GetLabeledElement(); - if (content && !EventTargetIn(aVisitor.mEvent, content, this)) { + if (content) { mHandlingEvent = true; switch (aVisitor.mEvent->message) { case NS_MOUSE_BUTTON_DOWN: diff --git a/dom/html/HTMLLabelElement.h b/dom/html/HTMLLabelElement.h index 91b1f7b38a4..9f857b56905 100644 --- a/dom/html/HTMLLabelElement.h +++ b/dom/html/HTMLLabelElement.h @@ -32,6 +32,12 @@ public: // nsISupports NS_DECL_ISUPPORTS_INHERITED + // Element + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE + { + return true; + } + // nsIDOMHTMLLabelElement NS_DECL_NSIDOMHTMLLABELELEMENT diff --git a/dom/html/HTMLObjectElement.cpp b/dom/html/HTMLObjectElement.cpp index 658c10a83ec..e08a1ca9a84 100644 --- a/dom/html/HTMLObjectElement.cpp +++ b/dom/html/HTMLObjectElement.cpp @@ -45,6 +45,12 @@ HTMLObjectElement::~HTMLObjectElement() DestroyImageLoadingContent(); } +bool +HTMLObjectElement::IsInteractiveHTMLContent() const +{ + return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap); +} + bool HTMLObjectElement::IsDoneAddingChildren() { diff --git a/dom/html/HTMLObjectElement.h b/dom/html/HTMLObjectElement.h index 6c12c51e2b8..5f074592851 100644 --- a/dom/html/HTMLObjectElement.h +++ b/dom/html/HTMLObjectElement.h @@ -30,6 +30,9 @@ public: virtual int32_t TabIndexDefault() MOZ_OVERRIDE; + // Element + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE; + // nsIDOMHTMLObjectElement NS_DECL_NSIDOMHTMLOBJECTELEMENT diff --git a/dom/html/HTMLSelectElement.h b/dom/html/HTMLSelectElement.h index d7b6006541e..c73799f3c76 100644 --- a/dom/html/HTMLSelectElement.h +++ b/dom/html/HTMLSelectElement.h @@ -147,6 +147,12 @@ public: virtual int32_t TabIndexDefault() MOZ_OVERRIDE; + // Element + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE + { + return true; + } + // nsIDOMHTMLSelectElement NS_DECL_NSIDOMHTMLSELECTELEMENT diff --git a/dom/html/HTMLTextAreaElement.h b/dom/html/HTMLTextAreaElement.h index b4cac14a316..d7ced597fbc 100644 --- a/dom/html/HTMLTextAreaElement.h +++ b/dom/html/HTMLTextAreaElement.h @@ -53,6 +53,12 @@ public: virtual int32_t TabIndexDefault() MOZ_OVERRIDE; + // Element + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE + { + return true; + } + // nsIDOMHTMLTextAreaElement NS_DECL_NSIDOMHTMLTEXTAREAELEMENT diff --git a/dom/html/HTMLVideoElement.cpp b/dom/html/HTMLVideoElement.cpp index 310a154c44c..c1eb344e93d 100644 --- a/dom/html/HTMLVideoElement.cpp +++ b/dom/html/HTMLVideoElement.cpp @@ -126,6 +126,12 @@ nsresult HTMLVideoElement::SetAcceptHeader(nsIHttpChannel* aChannel) false); } +bool +HTMLVideoElement::IsInteractiveHTMLContent() const +{ + return HasAttr(kNameSpaceID_None, nsGkAtoms::controls); +} + uint32_t HTMLVideoElement::MozParsedFrames() const { MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread."); diff --git a/dom/html/HTMLVideoElement.h b/dom/html/HTMLVideoElement.h index ccfea1c1fdf..6359c20629a 100644 --- a/dom/html/HTMLVideoElement.h +++ b/dom/html/HTMLVideoElement.h @@ -49,6 +49,9 @@ public: virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel) MOZ_OVERRIDE; + // Element + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE; + // WebIDL uint32_t Width() const diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index cc7eab64540..dbc685dc583 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -1791,6 +1791,15 @@ nsGenericHTMLElement::IsLabelable() const Tag() == nsGkAtoms::meter; } +bool +nsGenericHTMLElement::IsInteractiveHTMLContent() const +{ + return Tag() == nsGkAtoms::details || + Tag() == nsGkAtoms::embed || + Tag() == nsGkAtoms::keygen || + HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex); +} + already_AddRefed nsGenericHTMLElement::GetUndoManager() { diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h index f812ae25b3b..942c775519a 100644 --- a/dom/html/nsGenericHTMLElement.h +++ b/dom/html/nsGenericHTMLElement.h @@ -904,6 +904,7 @@ public: } virtual bool IsLabelable() const MOZ_OVERRIDE; + virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE; static bool TouchEventsEnabled(JSContext* /* unused */, JSObject* /* unused */); diff --git a/dom/html/test/forms/mochitest.ini b/dom/html/test/forms/mochitest.ini index ad1fe7de67c..423f235d492 100644 --- a/dom/html/test/forms/mochitest.ini +++ b/dom/html/test/forms/mochitest.ini @@ -64,6 +64,7 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only skip-if = buildapp == 'mulet' [test_input_untrusted_key_events.html] [test_input_url.html] +[test_interactive_content_in_label.html] [test_label_control_attribute.html] [test_label_input_controls.html] [test_max_attribute.html] @@ -81,6 +82,7 @@ skip-if = e10s [test_output_element.html] [test_pattern_attribute.html] [test_progress_element.html] +[test_radio_in_label.html] [test_radio_radionodelist.html] [test_required_attribute.html] skip-if = e10s diff --git a/dom/html/test/forms/test_interactive_content_in_label.html b/dom/html/test/forms/test_interactive_content_in_label.html new file mode 100644 index 00000000000..86a7860066a --- /dev/null +++ b/dom/html/test/forms/test_interactive_content_in_label.html @@ -0,0 +1,99 @@ + + + + + Test for Bug 229925 + + + + + + +Mozilla Bug 229925 +

+
+ +
+ + + + + diff --git a/dom/html/test/forms/test_radio_in_label.html b/dom/html/test/forms/test_radio_in_label.html new file mode 100644 index 00000000000..93de6d4fd58 --- /dev/null +++ b/dom/html/test/forms/test_radio_in_label.html @@ -0,0 +1,51 @@ + + + + + Test for Bug 229925 + + + + + + +Mozilla Bug 229925 +

+
+ +
+ + + +