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