Unreviewed, rolling out r245857.
[WebKit-https.git] / Source / WebCore / html / FormAssociatedElement.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004-2016 Apple Inc. All rights reserved.
6  *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "FormAssociatedElement.h"
27
28 #include "EditorClient.h"
29 #include "ElementAncestorIterator.h"
30 #include "FormController.h"
31 #include "Frame.h"
32 #include "HTMLFormControlElement.h"
33 #include "HTMLFormElement.h"
34 #include "HTMLNames.h"
35 #include "HTMLObjectElement.h"
36 #include "IdTargetObserver.h"
37
38 namespace WebCore {
39
40 using namespace HTMLNames;
41
42 class FormAttributeTargetObserver final : private IdTargetObserver {
43     WTF_MAKE_FAST_ALLOCATED;
44 public:
45     FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement&);
46
47 private:
48     void idTargetChanged() override;
49
50     FormAssociatedElement& m_element;
51 };
52
53 FormAssociatedElement::FormAssociatedElement(HTMLFormElement* form)
54     : m_form(nullptr)
55     , m_formSetByParser(makeWeakPtr(form))
56 {
57 }
58
59 FormAssociatedElement::~FormAssociatedElement()
60 {
61     setForm(nullptr);
62 }
63
64 void FormAssociatedElement::didMoveToNewDocument(Document&)
65 {
66     HTMLElement& element = asHTMLElement();
67     if (element.hasAttributeWithoutSynchronization(formAttr) && element.isConnected())
68         resetFormAttributeTargetObserver();
69 }
70
71 void FormAssociatedElement::insertedIntoAncestor(Node::InsertionType insertionType, ContainerNode&)
72 {
73     HTMLElement& element = asHTMLElement();
74     if (m_formSetByParser) {
75         // The form could have been removed by a script during parsing.
76         if (m_formSetByParser->isConnected())
77             setForm(m_formSetByParser.get());
78         m_formSetByParser = nullptr;
79     }
80
81     if (m_form && element.rootElement() != m_form->rootElement())
82         setForm(nullptr);
83
84     if (!insertionType.connectedToDocument)
85         return;
86
87     if (element.hasAttributeWithoutSynchronization(formAttr))
88         resetFormAttributeTargetObserver();
89 }
90
91 void FormAssociatedElement::removedFromAncestor(Node::RemovalType, ContainerNode&)
92 {
93     m_formAttributeTargetObserver = nullptr;
94
95     // If the form and element are both in the same tree, preserve the connection to the form.
96     // Otherwise, null out our form and remove ourselves from the form's list of elements.
97     // Do not rely on rootNode() because our IsInTreeScope is outdated.
98     if (m_form && &asHTMLElement().traverseToRootNode() != &m_form->traverseToRootNode())
99         setForm(nullptr);
100 }
101
102 HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element, HTMLFormElement* currentAssociatedForm)
103 {
104     const AtomicString& formId(element->attributeWithoutSynchronization(formAttr));
105     if (!formId.isNull() && element->isConnected()) {
106         // The HTML5 spec says that the element should be associated with
107         // the first element in the document to have an ID that equal to
108         // the value of form attribute, so we put the result of
109         // treeScope().getElementById() over the given element.
110         RefPtr<Element> newFormCandidate = element->treeScope().getElementById(formId);
111         if (is<HTMLFormElement>(newFormCandidate))
112             return downcast<HTMLFormElement>(newFormCandidate.get());
113         return nullptr;
114     }
115
116     if (!currentAssociatedForm)
117         return HTMLFormElement::findClosestFormAncestor(*element);
118
119     return currentAssociatedForm;
120 }
121
122 void FormAssociatedElement::formOwnerRemovedFromTree(const Node& formRoot)
123 {
124     ASSERT(m_form);
125     // Can't use RefPtr here beacuse this function might be called inside ~ShadowRoot via addChildNodesToDeletionQueue. See webkit.org/b/189493.
126     Node* rootNode = &asHTMLElement();
127     for (auto* ancestor = asHTMLElement().parentNode(); ancestor; ancestor = ancestor->parentNode()) {
128         if (ancestor == m_form) {
129             // Form is our ancestor so we don't need to reset our owner, we also no longer
130             // need an id observer since we are no longer connected.
131             m_formAttributeTargetObserver = nullptr;
132             return;
133         }
134         rootNode = ancestor;
135     }
136
137     // We are no longer in the same tree as our form owner so clear our owner.
138     if (rootNode != &formRoot)
139         setForm(nullptr);
140 }
141
142 void FormAssociatedElement::setForm(HTMLFormElement* newForm)
143 {
144     if (m_form == newForm)
145         return;
146     willChangeForm();
147     if (m_form)
148         m_form->removeFormElement(this);
149     m_form = makeWeakPtr(newForm);
150     if (newForm)
151         newForm->registerFormElement(this);
152     didChangeForm();
153 }
154
155 void FormAssociatedElement::willChangeForm()
156 {
157 }
158
159 void FormAssociatedElement::didChangeForm()
160 {
161 }
162
163 void FormAssociatedElement::formWillBeDestroyed()
164 {
165     ASSERT(m_form);
166     if (!m_form)
167         return;
168     willChangeForm();
169     m_form = nullptr;
170     didChangeForm();
171 }
172
173 void FormAssociatedElement::resetFormOwner()
174 {
175     RefPtr<HTMLFormElement> originalForm = m_form.get();
176     setForm(findAssociatedForm(&asHTMLElement(), originalForm.get()));
177     HTMLElement& element = asHTMLElement();
178     auto* newForm = m_form.get();
179     if (newForm && newForm != originalForm && newForm->isConnected())
180         element.document().didAssociateFormControl(element);
181 }
182
183 void FormAssociatedElement::formAttributeChanged()
184 {
185     HTMLElement& element = asHTMLElement();
186     if (!element.hasAttributeWithoutSynchronization(formAttr)) {
187         // The form attribute removed. We need to reset form owner here.
188         RefPtr<HTMLFormElement> originalForm = m_form.get();
189         // FIXME: Why does this not pass originalForm to findClosestFormAncestor?
190         setForm(HTMLFormElement::findClosestFormAncestor(element));
191         auto* newForm = m_form.get();
192         if (newForm && newForm != originalForm && newForm->isConnected())
193             element.document().didAssociateFormControl(element);
194         m_formAttributeTargetObserver = nullptr;
195     } else {
196         resetFormOwner();
197         if (element.isConnected())
198             resetFormAttributeTargetObserver();
199     }
200 }
201
202 bool FormAssociatedElement::customError() const
203 {
204     return willValidate() && !m_customValidationMessage.isEmpty();
205 }
206
207 bool FormAssociatedElement::hasBadInput() const
208 {
209     return false;
210 }
211
212 bool FormAssociatedElement::patternMismatch() const
213 {
214     return false;
215 }
216
217 bool FormAssociatedElement::rangeOverflow() const
218 {
219     return false;
220 }
221
222 bool FormAssociatedElement::rangeUnderflow() const
223 {
224     return false;
225 }
226
227 bool FormAssociatedElement::stepMismatch() const
228 {
229     return false;
230 }
231
232 bool FormAssociatedElement::tooShort() const
233 {
234     return false;
235 }
236
237 bool FormAssociatedElement::tooLong() const
238 {
239     return false;
240 }
241
242 bool FormAssociatedElement::typeMismatch() const
243 {
244     return false;
245 }
246
247 bool FormAssociatedElement::isValid() const
248 {
249     bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
250         || tooShort() || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError();
251     return !someError;
252 }
253
254 bool FormAssociatedElement::valueMissing() const
255 {
256     return false;
257 }
258
259 String FormAssociatedElement::customValidationMessage() const
260 {
261     return m_customValidationMessage;
262 }
263
264 String FormAssociatedElement::validationMessage() const
265 {
266     return customError() ? m_customValidationMessage : String();
267 }
268
269 void FormAssociatedElement::setCustomValidity(const String& error)
270 {
271     m_customValidationMessage = error;
272 }
273
274 void FormAssociatedElement::resetFormAttributeTargetObserver()
275 {
276     ASSERT_WITH_SECURITY_IMPLICATION(asHTMLElement().isConnected());
277     m_formAttributeTargetObserver = std::make_unique<FormAttributeTargetObserver>(asHTMLElement().attributeWithoutSynchronization(formAttr), *this);
278 }
279
280 void FormAssociatedElement::formAttributeTargetChanged()
281 {
282     resetFormOwner();
283 }
284
285 const AtomicString& FormAssociatedElement::name() const
286 {
287     const AtomicString& name = asHTMLElement().getNameAttribute();
288     return name.isNull() ? emptyAtom() : name;
289 }
290
291 bool FormAssociatedElement::isFormControlElementWithState() const
292 {
293     return false;
294 }
295
296 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement& element)
297     : IdTargetObserver(element.asHTMLElement().treeScope().idTargetObserverRegistry(), id)
298     , m_element(element)
299 {
300 }
301
302 void FormAttributeTargetObserver::idTargetChanged()
303 {
304     m_element.formAttributeTargetChanged();
305 }
306
307 } // namespace Webcore