Bug 1404864 - ensure HTMLInputElement.form works per spec in Shadow DOM, r=peterv

This commit is contained in:
Olli Pettay
2018-05-18 20:02:14 +03:00
parent c798bbe8bf
commit aa892e76ad
6 changed files with 126 additions and 34 deletions

View File

@@ -53,6 +53,7 @@
#include "nsHTMLParts.h"
#include "nsContentUtils.h"
#include "mozilla/dom/DirectionalityUtils.h"
#include "mozilla/dom/DocumentOrShadowRoot.h"
#include "nsString.h"
#include "nsUnicharUtils.h"
#include "nsGkAtoms.h"
@@ -1778,13 +1779,13 @@ nsGenericHTMLFormElement::BindToTree(nsIDocument* aDocument,
aDocument->SetAutoFocusElement(this);
}
// If @form is set, the element *has* to be in a document, otherwise it
// wouldn't be possible to find an element with the corresponding id.
// If @form is set, the element *has* to be in a composed document, otherwise
// it wouldn't be possible to find an element with the corresponding id.
// If @form isn't set, the element *has* to have a parent, otherwise it
// wouldn't be possible to find a form ancestor.
// We should not call UpdateFormOwner if none of these conditions are
// fulfilled.
if (HasAttr(kNameSpaceID_None, nsGkAtoms::form) ? !!GetUncomposedDoc()
if (HasAttr(kNameSpaceID_None, nsGkAtoms::form) ? IsInComposedDoc()
: !!aParent) {
UpdateFormOwner(true, nullptr);
}
@@ -1923,9 +1924,9 @@ nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
if (aName == nsGkAtoms::form) {
// We need a new form id observer.
//XXXsmaug How should this work in Shadow DOM?
nsIDocument* doc = GetUncomposedDoc();
if (doc) {
DocumentOrShadowRoot* docOrShadow =
GetUncomposedDocOrConnectedShadowRoot();
if (docOrShadow) {
Element* formIdElement = nullptr;
if (aValue && !aValue->IsEmptyString()) {
formIdElement = AddFormIdObserver();
@@ -2126,36 +2127,21 @@ nsGenericHTMLFormElement::FocusState()
Element*
nsGenericHTMLFormElement::AddFormIdObserver()
{
NS_ASSERTION(GetUncomposedDoc(), "When adding a form id observer, "
"we should be in a document!");
nsAutoString formId;
nsIDocument* doc = OwnerDoc();
DocumentOrShadowRoot* docOrShadow = GetUncomposedDocOrConnectedShadowRoot();
GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId);
NS_ASSERTION(!formId.IsEmpty(),
"@form value should not be the empty string!");
RefPtr<nsAtom> atom = NS_Atomize(formId);
return doc->AddIDTargetObserver(atom, FormIdUpdated, this, false);
return docOrShadow->AddIDTargetObserver(atom, FormIdUpdated, this, false);
}
void
nsGenericHTMLFormElement::RemoveFormIdObserver()
{
/**
* We are using OwnerDoc() because we don't really care about having the
* element actually being in the tree. If it is not and @form value changes,
* this method will be called for nothing but removing an observer which does
* not exist doesn't cost so much (no entry in the hash table) so having a
* boolean for GetUncomposedDoc()/GetOwnerDoc() would make everything look
* more complex for nothing.
*/
nsIDocument* doc = OwnerDoc();
// At this point, we may not have a document anymore. In that case, we can't
// remove the observer. The document did that for us.
if (!doc) {
DocumentOrShadowRoot* docOrShadow = GetUncomposedDocOrConnectedShadowRoot();
if (!docOrShadow) {
return;
}
@@ -2165,7 +2151,7 @@ nsGenericHTMLFormElement::RemoveFormIdObserver()
"@form value should not be the empty string!");
RefPtr<nsAtom> atom = NS_Atomize(formId);
doc->RemoveIDTargetObserver(atom, FormIdUpdated, this, false);
docOrShadow->RemoveIDTargetObserver(atom, FormIdUpdated, this, false);
}
@@ -2246,10 +2232,9 @@ nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
element = aFormIdElement;
}
NS_ASSERTION(GetUncomposedDoc(), "The element should be in a document "
"when UpdateFormOwner is called!");
NS_ASSERTION(!GetUncomposedDoc() ||
element == GetUncomposedDoc()->GetElementById(formId),
NS_ASSERTION(!IsInComposedDoc() ||
element == GetUncomposedDocOrConnectedShadowRoot()->
GetElementById(formId),
"element should be equals to the current element "
"associated with the id in @form!");