a90baefd96867beda2abc5fbcba399f93d6060da
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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, 2005, 2006, 2007 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 "core/html/FormAssociatedElement.h"
27
28 #include "core/HTMLNames.h"
29 #include "core/dom/IdTargetObserver.h"
30 #include "core/dom/NodeTraversal.h"
31 #include "core/html/HTMLFormControlElement.h"
32 #include "core/html/HTMLFormElement.h"
33 #include "core/html/HTMLObjectElement.h"
34 #include "core/html/ValidityState.h"
35
36 namespace blink {
37
38 using namespace HTMLNames;
39
40 class FormAttributeTargetObserver : public IdTargetObserver {
41     WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
42 public:
43     static PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> create(const AtomicString& id, FormAssociatedElement*);
44     virtual void trace(Visitor*) OVERRIDE;
45     virtual void idTargetChanged() OVERRIDE;
46
47 private:
48     FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement*);
49
50     RawPtrWillBeMember<FormAssociatedElement> m_element;
51 };
52
53 FormAssociatedElement::FormAssociatedElement()
54     : m_formWasSetByParser(false)
55 {
56 }
57
58 FormAssociatedElement::~FormAssociatedElement()
59 {
60     // We can't call setForm here because it contains virtual calls.
61 }
62
63 void FormAssociatedElement::trace(Visitor* visitor)
64 {
65     visitor->trace(m_formAttributeTargetObserver);
66     visitor->trace(m_form);
67     visitor->trace(m_validityState);
68 }
69
70 ValidityState* FormAssociatedElement::validity()
71 {
72     if (!m_validityState)
73         m_validityState = ValidityState::create(this);
74
75     return m_validityState.get();
76 }
77
78 void FormAssociatedElement::didMoveToNewDocument(Document& oldDocument)
79 {
80     HTMLElement* element = toHTMLElement(this);
81     if (element->fastHasAttribute(formAttr))
82         setFormAttributeTargetObserver(nullptr);
83 }
84
85 void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint)
86 {
87     if (!m_formWasSetByParser || NodeTraversal::highestAncestorOrSelf(*insertionPoint) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
88         resetFormOwner();
89
90     if (!insertionPoint->inDocument())
91         return;
92
93     HTMLElement* element = toHTMLElement(this);
94     if (element->fastHasAttribute(formAttr))
95         resetFormAttributeTargetObserver();
96 }
97
98 void FormAssociatedElement::removedFrom(ContainerNode* insertionPoint)
99 {
100     HTMLElement* element = toHTMLElement(this);
101     if (insertionPoint->inDocument() && element->fastHasAttribute(formAttr))
102         setFormAttributeTargetObserver(nullptr);
103     // If the form and element are both in the same tree, preserve the connection to the form.
104     // Otherwise, null out our form and remove ourselves from the form's list of elements.
105     if (m_form && NodeTraversal::highestAncestorOrSelf(*element) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
106         resetFormOwner();
107 }
108
109 HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element)
110 {
111     const AtomicString& formId(element->fastGetAttribute(formAttr));
112     // 3. If the element is reassociateable, has a form content attribute, and
113     // is itself in a Document, then run these substeps:
114     if (!formId.isNull() && element->inDocument()) {
115         // 3.1. If the first element in the Document to have an ID that is
116         // case-sensitively equal to the element's form content attribute's
117         // value is a form element, then associate the form-associated element
118         // with that form element.
119         // 3.2. Abort the "reset the form owner" steps.
120         Element* newFormCandidate = element->treeScope().getElementById(formId);
121         return isHTMLFormElement(newFormCandidate) ? toHTMLFormElement(newFormCandidate) : 0;
122     }
123     // 4. Otherwise, if the form-associated element in question has an ancestor
124     // form element, then associate the form-associated element with the nearest
125     // such ancestor form element.
126     return element->findFormAncestor();
127 }
128
129 void FormAssociatedElement::formRemovedFromTree(const Node& formRoot)
130 {
131     ASSERT(m_form);
132     if (NodeTraversal::highestAncestorOrSelf(toHTMLElement(*this)) == formRoot)
133         return;
134     resetFormOwner();
135 }
136
137 void FormAssociatedElement::associateByParser(HTMLFormElement* form)
138 {
139     if (form && form->inDocument()) {
140         m_formWasSetByParser = true;
141         setForm(form);
142         form->didAssociateByParser();
143     }
144 }
145
146 void FormAssociatedElement::setForm(HTMLFormElement* newForm)
147 {
148     if (m_form.get() == newForm)
149         return;
150     willChangeForm();
151     if (m_form)
152         m_form->disassociate(*this);
153     if (newForm) {
154 #if ENABLE(OILPAN)
155         m_form = newForm;
156 #else
157         m_form = newForm->createWeakPtr();
158 #endif
159         m_form->associate(*this);
160     } else {
161 #if ENABLE(OILPAN)
162         m_form = nullptr;
163 #else
164         m_form = WeakPtr<HTMLFormElement>();
165 #endif
166     }
167     didChangeForm();
168 }
169
170 void FormAssociatedElement::willChangeForm()
171 {
172 }
173
174 void FormAssociatedElement::didChangeForm()
175 {
176 }
177
178 void FormAssociatedElement::resetFormOwner()
179 {
180     m_formWasSetByParser = false;
181     HTMLElement* element = toHTMLElement(this);
182     const AtomicString& formId(element->fastGetAttribute(formAttr));
183     HTMLFormElement* nearestForm = element->findFormAncestor();
184     // 1. If the element's form owner is not null, and either the element is not
185     // reassociateable or its form content attribute is not present, and the
186     // element's form owner is its nearest form element ancestor after the
187     // change to the ancestor chain, then do nothing, and abort these steps.
188     if (m_form && formId.isNull() && m_form.get() == nearestForm)
189         return;
190
191     HTMLFormElement* originalForm = m_form.get();
192     setForm(findAssociatedForm(element));
193     // FIXME: Move didAssociateFormControl call to didChangeForm or
194     // HTMLFormElement::associate.
195     if (m_form && m_form.get() != originalForm && m_form->inDocument())
196         element->document().didAssociateFormControl(element);
197 }
198
199 void FormAssociatedElement::formAttributeChanged()
200 {
201     resetFormOwner();
202     resetFormAttributeTargetObserver();
203 }
204
205 bool FormAssociatedElement::customError() const
206 {
207     const HTMLElement* element = toHTMLElement(this);
208     return element->willValidate() && !m_customValidationMessage.isEmpty();
209 }
210
211 bool FormAssociatedElement::hasBadInput() const
212 {
213     return false;
214 }
215
216 bool FormAssociatedElement::patternMismatch() const
217 {
218     return false;
219 }
220
221 bool FormAssociatedElement::rangeOverflow() const
222 {
223     return false;
224 }
225
226 bool FormAssociatedElement::rangeUnderflow() const
227 {
228     return false;
229 }
230
231 bool FormAssociatedElement::stepMismatch() const
232 {
233     return false;
234 }
235
236 bool FormAssociatedElement::tooLong() const
237 {
238     return false;
239 }
240
241 bool FormAssociatedElement::typeMismatch() const
242 {
243     return false;
244 }
245
246 bool FormAssociatedElement::valid() const
247 {
248     bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
249         || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError();
250     return !someError;
251 }
252
253 bool FormAssociatedElement::valueMissing() const
254 {
255     return false;
256 }
257
258 String FormAssociatedElement::customValidationMessage() const
259 {
260     return m_customValidationMessage;
261 }
262
263 String FormAssociatedElement::validationMessage() const
264 {
265     return customError() ? m_customValidationMessage : String();
266 }
267
268 void FormAssociatedElement::setCustomValidity(const String& error)
269 {
270     m_customValidationMessage = error;
271 }
272
273 void FormAssociatedElement::setFormAttributeTargetObserver(PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> newObserver)
274 {
275     if (m_formAttributeTargetObserver)
276         m_formAttributeTargetObserver->unregister();
277     m_formAttributeTargetObserver = newObserver;
278 }
279
280 void FormAssociatedElement::resetFormAttributeTargetObserver()
281 {
282     HTMLElement* element = toHTMLElement(this);
283     const AtomicString& formId(element->fastGetAttribute(formAttr));
284     if (!formId.isNull() && element->inDocument())
285         setFormAttributeTargetObserver(FormAttributeTargetObserver::create(formId, this));
286     else
287         setFormAttributeTargetObserver(nullptr);
288 }
289
290 void FormAssociatedElement::formAttributeTargetChanged()
291 {
292     resetFormOwner();
293 }
294
295 const AtomicString& FormAssociatedElement::name() const
296 {
297     const AtomicString& name = toHTMLElement(this)->getNameAttribute();
298     return name.isNull() ? emptyAtom : name;
299 }
300
301 bool FormAssociatedElement::isFormControlElementWithState() const
302 {
303     return false;
304 }
305
306 const HTMLElement& toHTMLElement(const FormAssociatedElement& associatedElement)
307 {
308     if (associatedElement.isFormControlElement())
309         return toHTMLFormControlElement(associatedElement);
310     // Assumes the element is an HTMLObjectElement
311     return toHTMLObjectElement(associatedElement);
312 }
313
314 const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
315 {
316     ASSERT(associatedElement);
317     return &toHTMLElement(*associatedElement);
318 }
319
320 HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
321 {
322     return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
323 }
324
325 HTMLElement& toHTMLElement(FormAssociatedElement& associatedElement)
326 {
327     return const_cast<HTMLElement&>(toHTMLElement(static_cast<const FormAssociatedElement&>(associatedElement)));
328 }
329
330 PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element)
331 {
332     return adoptPtrWillBeNoop(new FormAttributeTargetObserver(id, element));
333 }
334
335 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element)
336     : IdTargetObserver(toHTMLElement(element)->treeScope().idTargetObserverRegistry(), id)
337     , m_element(element)
338 {
339 }
340
341 void FormAttributeTargetObserver::trace(Visitor* visitor)
342 {
343     visitor->trace(m_element);
344     IdTargetObserver::trace(visitor);
345 }
346
347 void FormAttributeTargetObserver::idTargetChanged()
348 {
349     m_element->formAttributeTargetChanged();
350 }
351
352 } // namespace Webcore