| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2001 Dirk Mueller (mueller@kde.org) | 4 * (C) 2001 Dirk Mueller (mueller@kde.org) |
| 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. | 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. |
| 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) | 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 #include "config.h" | 25 #include "config.h" |
| 26 #include "core/html/HTMLFormElement.h" | 26 #include "core/html/HTMLFormElement.h" |
| 27 | 27 |
| 28 #include <limits> | 28 #include <limits> |
| 29 #include "HTMLNames.h" | 29 #include "HTMLNames.h" |
| 30 #include "bindings/v8/ScriptController.h" | 30 #include "bindings/v8/ScriptController.h" |
| 31 #include "bindings/v8/ScriptEventListener.h" | 31 #include "bindings/v8/ScriptEventListener.h" |
| 32 #include "core/dom/Attribute.h" | 32 #include "core/dom/Attribute.h" |
| 33 #include "core/dom/Document.h" | 33 #include "core/dom/Document.h" |
| 34 #include "core/dom/ElementTraversal.h" | 34 #include "core/dom/ElementTraversal.h" |
| 35 #include "core/dom/IdTargetObserverRegistry.h" |
| 35 #include "core/events/AutocompleteErrorEvent.h" | 36 #include "core/events/AutocompleteErrorEvent.h" |
| 36 #include "core/events/Event.h" | 37 #include "core/events/Event.h" |
| 37 #include "core/events/ScopedEventQueue.h" | 38 #include "core/events/ScopedEventQueue.h" |
| 38 #include "core/events/ThreadLocalEventNames.h" | 39 #include "core/events/ThreadLocalEventNames.h" |
| 39 #include "core/html/HTMLCollection.h" | 40 #include "core/html/HTMLCollection.h" |
| 40 #include "core/html/HTMLDialogElement.h" | 41 #include "core/html/HTMLDialogElement.h" |
| 41 #include "core/html/HTMLImageElement.h" | 42 #include "core/html/HTMLImageElement.h" |
| 42 #include "core/html/HTMLInputElement.h" | 43 #include "core/html/HTMLInputElement.h" |
| 43 #include "core/html/HTMLObjectElement.h" | 44 #include "core/html/HTMLObjectElement.h" |
| 44 #include "core/html/RadioNodeList.h" | 45 #include "core/html/RadioNodeList.h" |
| 45 #include "core/html/forms/FormController.h" | 46 #include "core/html/forms/FormController.h" |
| 46 #include "core/loader/FrameLoader.h" | 47 #include "core/loader/FrameLoader.h" |
| 47 #include "core/loader/FrameLoaderClient.h" | 48 #include "core/loader/FrameLoaderClient.h" |
| 48 #include "core/frame/ContentSecurityPolicy.h" | 49 #include "core/frame/ContentSecurityPolicy.h" |
| 49 #include "core/frame/DOMWindow.h" | 50 #include "core/frame/DOMWindow.h" |
| 50 #include "core/frame/Frame.h" | 51 #include "core/frame/Frame.h" |
| 51 #include "core/frame/UseCounter.h" | 52 #include "core/frame/UseCounter.h" |
| 52 #include "core/rendering/RenderTextControl.h" | 53 #include "core/rendering/RenderTextControl.h" |
| 53 #include "platform/UserGestureIndicator.h" | 54 #include "platform/UserGestureIndicator.h" |
| 54 | 55 |
| 55 using namespace std; | 56 using namespace std; |
| 56 | 57 |
| 57 namespace WebCore { | 58 namespace WebCore { |
| 58 | 59 |
| 59 using namespace HTMLNames; | 60 using namespace HTMLNames; |
| 60 | 61 |
| 61 HTMLFormElement::HTMLFormElement(Document& document) | 62 HTMLFormElement::HTMLFormElement(Document& document) |
| 62 : HTMLElement(formTag, document) | 63 : HTMLElement(formTag, document) |
| 63 , m_associatedElementsBeforeIndex(0) | |
| 64 , m_associatedElementsAfterIndex(0) | |
| 65 , m_weakPtrFactory(this) | 64 , m_weakPtrFactory(this) |
| 65 , m_associatedElementsAreDirty(false) |
| 66 , m_imageElementsAreDirty(false) | 66 , m_imageElementsAreDirty(false) |
| 67 , m_hasElementsAssociatedByParser(false) | 67 , m_hasElementsAssociatedByParser(false) |
| 68 , m_didFinishParsingChildren(false) | 68 , m_didFinishParsingChildren(false) |
| 69 , m_wasUserSubmitted(false) | 69 , m_wasUserSubmitted(false) |
| 70 , m_isSubmittingOrPreparingForSubmission(false) | 70 , m_isSubmittingOrPreparingForSubmission(false) |
| 71 , m_shouldSubmit(false) | 71 , m_shouldSubmit(false) |
| 72 , m_isInResetFunction(false) | 72 , m_isInResetFunction(false) |
| 73 , m_wasDemoted(false) | 73 , m_wasDemoted(false) |
| 74 , m_requestAutocompleteTimer(this, &HTMLFormElement::requestAutocompleteTime
rFired) | 74 , m_requestAutocompleteTimer(this, &HTMLFormElement::requestAutocompleteTime
rFired) |
| 75 { | 75 { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 this->document().didAssociateFormControl(this); | 121 this->document().didAssociateFormControl(this); |
| 122 return InsertionDone; | 122 return InsertionDone; |
| 123 } | 123 } |
| 124 | 124 |
| 125 template<class T> | 125 template<class T> |
| 126 void notifyFormRemovedFromTree(const Vector<T*>& elements, Node* root) | 126 void notifyFormRemovedFromTree(const Vector<T*>& elements, Node* root) |
| 127 { | 127 { |
| 128 size_t size = elements.size(); | 128 size_t size = elements.size(); |
| 129 for (size_t i = 0; i < size; ++i) | 129 for (size_t i = 0; i < size; ++i) |
| 130 elements[i]->formRemovedFromTree(root); | 130 elements[i]->formRemovedFromTree(root); |
| 131 ASSERT(elements.size() == size); |
| 131 } | 132 } |
| 132 | 133 |
| 133 void HTMLFormElement::removedFrom(ContainerNode* insertionPoint) | 134 void HTMLFormElement::removedFrom(ContainerNode* insertionPoint) |
| 134 { | 135 { |
| 135 // FIXME: We don't need to notify formRemovedFromTree to associated elements | 136 // We don't need to take care of form association by 'form' content |
| 136 // which are descendants of this form. We can skip this process if we know | 137 // attribute becuse IdTargetObserver handles it. |
| 137 // that this form doesn't have elements associated by parser or associated | 138 if (m_hasElementsAssociatedByParser) { |
| 138 // with 'form' content attribute. | 139 Node* root = highestAncestor(); |
| 139 Node* root = highestAncestor(); | 140 if (!m_associatedElementsAreDirty) { |
| 140 Vector<FormAssociatedElement*> elements(associatedElements()); | 141 Vector<FormAssociatedElement*> elements(associatedElements()); |
| 141 notifyFormRemovedFromTree(elements, root); | 142 notifyFormRemovedFromTree(elements, root); |
| 143 } else { |
| 144 Vector<FormAssociatedElement*> elements; |
| 145 collectAssociatedElements(insertionPoint->highestAncestor(), element
s); |
| 146 notifyFormRemovedFromTree(elements, root); |
| 147 collectAssociatedElements(root, elements); |
| 148 notifyFormRemovedFromTree(elements, root); |
| 149 } |
| 142 | 150 |
| 143 if (m_hasElementsAssociatedByParser) { | |
| 144 if (!m_imageElementsAreDirty) { | 151 if (!m_imageElementsAreDirty) { |
| 145 Vector<HTMLImageElement*> images(imageElements()); | 152 Vector<HTMLImageElement*> images(imageElements()); |
| 146 notifyFormRemovedFromTree(images, root); | 153 notifyFormRemovedFromTree(images, root); |
| 147 } else { | 154 } else { |
| 148 Vector<HTMLImageElement*> images; | 155 Vector<HTMLImageElement*> images; |
| 149 collectImageElements(insertionPoint->highestAncestor(), images); | 156 collectImageElements(insertionPoint->highestAncestor(), images); |
| 150 notifyFormRemovedFromTree(images, root); | 157 notifyFormRemovedFromTree(images, root); |
| 151 collectImageElements(root, images); | 158 collectImageElements(root, images); |
| 152 notifyFormRemovedFromTree(images, root); | 159 notifyFormRemovedFromTree(images, root); |
| 153 } | 160 } |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 513 else if (name == accept_charsetAttr) | 520 else if (name == accept_charsetAttr) |
| 514 m_attributes.setAcceptCharset(value); | 521 m_attributes.setAcceptCharset(value); |
| 515 else if (name == onautocompleteAttr) | 522 else if (name == onautocompleteAttr) |
| 516 setAttributeEventListener(EventTypeNames::autocomplete, createAttributeE
ventListener(this, name, value)); | 523 setAttributeEventListener(EventTypeNames::autocomplete, createAttributeE
ventListener(this, name, value)); |
| 517 else if (name == onautocompleteerrorAttr) | 524 else if (name == onautocompleteerrorAttr) |
| 518 setAttributeEventListener(EventTypeNames::autocompleteerror, createAttri
buteEventListener(this, name, value)); | 525 setAttributeEventListener(EventTypeNames::autocompleteerror, createAttri
buteEventListener(this, name, value)); |
| 519 else | 526 else |
| 520 HTMLElement::parseAttribute(name, value); | 527 HTMLElement::parseAttribute(name, value); |
| 521 } | 528 } |
| 522 | 529 |
| 523 template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T*
item) | |
| 524 { | |
| 525 size_t size = vec.size(); | |
| 526 for (size_t i = 0; i != size; ++i) | |
| 527 if (vec[i] == item) { | |
| 528 vec.remove(i); | |
| 529 break; | |
| 530 } | |
| 531 } | |
| 532 | |
| 533 unsigned HTMLFormElement::formElementIndexWithFormAttribute(Element* element, un
signed rangeStart, unsigned rangeEnd) | |
| 534 { | |
| 535 if (m_associatedElements.isEmpty()) | |
| 536 return 0; | |
| 537 | |
| 538 ASSERT(rangeStart <= rangeEnd); | |
| 539 | |
| 540 if (rangeStart == rangeEnd) | |
| 541 return rangeStart; | |
| 542 | |
| 543 unsigned left = rangeStart; | |
| 544 unsigned right = rangeEnd - 1; | |
| 545 unsigned short position; | |
| 546 | |
| 547 // Does binary search on m_associatedElements in order to find the index | |
| 548 // to be inserted. | |
| 549 while (left != right) { | |
| 550 unsigned middle = left + ((right - left) / 2); | |
| 551 ASSERT(middle < m_associatedElementsBeforeIndex || middle >= m_associate
dElementsAfterIndex); | |
| 552 position = element->compareDocumentPosition(toHTMLElement(m_associatedEl
ements[middle])); | |
| 553 if (position & DOCUMENT_POSITION_FOLLOWING) | |
| 554 right = middle; | |
| 555 else | |
| 556 left = middle + 1; | |
| 557 } | |
| 558 | |
| 559 ASSERT(left < m_associatedElementsBeforeIndex || left >= m_associatedElement
sAfterIndex); | |
| 560 position = element->compareDocumentPosition(toHTMLElement(m_associatedElemen
ts[left])); | |
| 561 if (position & DOCUMENT_POSITION_FOLLOWING) | |
| 562 return left; | |
| 563 return left + 1; | |
| 564 } | |
| 565 | |
| 566 unsigned HTMLFormElement::formElementIndex(FormAssociatedElement& associatedElem
ent) | |
| 567 { | |
| 568 HTMLElement& associatedHTMLElement = toHTMLElement(associatedElement); | |
| 569 // Treats separately the case where this element has the form attribute | |
| 570 // for performance consideration. | |
| 571 if (associatedHTMLElement.fastHasAttribute(formAttr)) { | |
| 572 unsigned short position = compareDocumentPosition(&associatedHTMLElement
); | |
| 573 if (position & DOCUMENT_POSITION_PRECEDING) { | |
| 574 ++m_associatedElementsBeforeIndex; | |
| 575 ++m_associatedElementsAfterIndex; | |
| 576 return HTMLFormElement::formElementIndexWithFormAttribute(&associate
dHTMLElement, 0, m_associatedElementsBeforeIndex - 1); | |
| 577 } | |
| 578 if (position & DOCUMENT_POSITION_FOLLOWING && !(position & DOCUMENT_POSI
TION_CONTAINED_BY)) | |
| 579 return HTMLFormElement::formElementIndexWithFormAttribute(&associate
dHTMLElement, m_associatedElementsAfterIndex, m_associatedElements.size()); | |
| 580 } | |
| 581 | |
| 582 // Check for the special case where this element is the very last thing in | |
| 583 // the form's tree of children; we don't want to walk the entire tree in tha
t | |
| 584 // common case that occurs during parsing; instead we'll just return a value | |
| 585 // that says "add this form element to the end of the array". | |
| 586 if (ElementTraversal::next(associatedHTMLElement, this)) { | |
| 587 unsigned i = m_associatedElementsBeforeIndex; | |
| 588 for (Element* element = this; element; element = ElementTraversal::next(
*element, this)) { | |
| 589 if (element == associatedHTMLElement) { | |
| 590 ++m_associatedElementsAfterIndex; | |
| 591 return i; | |
| 592 } | |
| 593 if (!element->isFormControlElement() && !element->hasTagName(objectT
ag)) | |
| 594 continue; | |
| 595 if (!element->isHTMLElement() || toHTMLElement(element)->formOwner()
!= this) | |
| 596 continue; | |
| 597 ++i; | |
| 598 } | |
| 599 } | |
| 600 return m_associatedElementsAfterIndex++; | |
| 601 } | |
| 602 | |
| 603 void HTMLFormElement::associate(FormAssociatedElement& e) | 530 void HTMLFormElement::associate(FormAssociatedElement& e) |
| 604 { | 531 { |
| 605 m_associatedElements.insert(formElementIndex(e), &e); | 532 m_associatedElementsAreDirty = true; |
| 533 m_associatedElements.clear(); |
| 606 } | 534 } |
| 607 | 535 |
| 608 void HTMLFormElement::disassociate(FormAssociatedElement& e) | 536 void HTMLFormElement::disassociate(FormAssociatedElement& e) |
| 609 { | 537 { |
| 610 unsigned index; | 538 m_associatedElementsAreDirty = true; |
| 611 for (index = 0; index < m_associatedElements.size(); ++index) { | 539 m_associatedElements.clear(); |
| 612 if (m_associatedElements[index] == &e) | |
| 613 break; | |
| 614 } | |
| 615 ASSERT_WITH_SECURITY_IMPLICATION(index < m_associatedElements.size()); | |
| 616 if (index < m_associatedElementsBeforeIndex) | |
| 617 --m_associatedElementsBeforeIndex; | |
| 618 if (index < m_associatedElementsAfterIndex) | |
| 619 --m_associatedElementsAfterIndex; | |
| 620 removeFromPastNamesMap(toHTMLElement(e)); | 540 removeFromPastNamesMap(toHTMLElement(e)); |
| 621 removeFromVector(m_associatedElements, &e); | |
| 622 } | 541 } |
| 623 | 542 |
| 624 bool HTMLFormElement::isURLAttribute(const Attribute& attribute) const | 543 bool HTMLFormElement::isURLAttribute(const Attribute& attribute) const |
| 625 { | 544 { |
| 626 return attribute.name() == actionAttr || HTMLElement::isURLAttribute(attribu
te); | 545 return attribute.name() == actionAttr || HTMLElement::isURLAttribute(attribu
te); |
| 627 } | 546 } |
| 628 | 547 |
| 629 void HTMLFormElement::associate(HTMLImageElement& e) | 548 void HTMLFormElement::associate(HTMLImageElement& e) |
| 630 { | 549 { |
| 631 m_imageElementsAreDirty = true; | 550 m_imageElementsAreDirty = true; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 650 return; | 569 return; |
| 651 m_hasElementsAssociatedByParser = true; | 570 m_hasElementsAssociatedByParser = true; |
| 652 UseCounter::count(document(), UseCounter::FormAssociationByParser); | 571 UseCounter::count(document(), UseCounter::FormAssociationByParser); |
| 653 } | 572 } |
| 654 | 573 |
| 655 PassRefPtr<HTMLCollection> HTMLFormElement::elements() | 574 PassRefPtr<HTMLCollection> HTMLFormElement::elements() |
| 656 { | 575 { |
| 657 return ensureCachedHTMLCollection(FormControls); | 576 return ensureCachedHTMLCollection(FormControls); |
| 658 } | 577 } |
| 659 | 578 |
| 579 void HTMLFormElement::collectAssociatedElements(Node* root, Vector<FormAssociate
dElement*>& elements) const |
| 580 { |
| 581 elements.clear(); |
| 582 for (Node* node = root; node; node = NodeTraversal::next(*node)) { |
| 583 if (!node->isHTMLElement()) |
| 584 continue; |
| 585 FormAssociatedElement* element = 0; |
| 586 if (toElement(node)->isFormControlElement()) |
| 587 element = toHTMLFormControlElement(node); |
| 588 else if (node->hasTagName(objectTag)) |
| 589 element = toHTMLObjectElement(node); |
| 590 else |
| 591 continue; |
| 592 if (element->form()== this) |
| 593 elements.append(element); |
| 594 } |
| 595 } |
| 596 |
| 597 // This function should be const conceptually. However we update some fields |
| 598 // because of lazy evaluation. |
| 599 const Vector<FormAssociatedElement*>& HTMLFormElement::associatedElements() cons
t |
| 600 { |
| 601 if (!m_associatedElementsAreDirty) |
| 602 return m_associatedElements; |
| 603 HTMLFormElement* mutableThis = const_cast<HTMLFormElement*>(this); |
| 604 Node* scope = mutableThis; |
| 605 if (m_hasElementsAssociatedByParser) |
| 606 scope = highestAncestor(); |
| 607 if (inDocument() && treeScope().idTargetObserverRegistry().hasObservers(fast
GetAttribute(idAttr))) |
| 608 scope = &treeScope().rootNode(); |
| 609 collectAssociatedElements(scope, mutableThis->m_associatedElements); |
| 610 mutableThis->m_associatedElementsAreDirty = false; |
| 611 return m_associatedElements; |
| 612 } |
| 613 |
| 660 void HTMLFormElement::collectImageElements(Node* root, Vector<HTMLImageElement*>
& elements) | 614 void HTMLFormElement::collectImageElements(Node* root, Vector<HTMLImageElement*>
& elements) |
| 661 { | 615 { |
| 662 elements.clear(); | 616 elements.clear(); |
| 663 for (Node* node = root; node; node = NodeTraversal::next(*node)) { | 617 for (Node* node = root; node; node = NodeTraversal::next(*node)) { |
| 664 if (node->isHTMLElement() && node->hasTagName(imgTag) && toHTMLElement(n
ode)->formOwner() == this) | 618 if (node->isHTMLElement() && node->hasTagName(imgTag) && toHTMLElement(n
ode)->formOwner() == this) |
| 665 elements.append(toHTMLImageElement(node)); | 619 elements.append(toHTMLImageElement(node)); |
| 666 } | 620 } |
| 667 } | 621 } |
| 668 | 622 |
| 669 const Vector<HTMLImageElement*>& HTMLFormElement::imageElements() | 623 const Vector<HTMLImageElement*>& HTMLFormElement::imageElements() |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 863 } | 817 } |
| 864 | 818 |
| 865 void HTMLFormElement::setDemoted(bool demoted) | 819 void HTMLFormElement::setDemoted(bool demoted) |
| 866 { | 820 { |
| 867 if (demoted) | 821 if (demoted) |
| 868 UseCounter::count(document(), UseCounter::DemotedFormElement); | 822 UseCounter::count(document(), UseCounter::DemotedFormElement); |
| 869 m_wasDemoted = demoted; | 823 m_wasDemoted = demoted; |
| 870 } | 824 } |
| 871 | 825 |
| 872 } // namespace | 826 } // namespace |
| OLD | NEW |