Chromium Code Reviews| 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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 } | 131 } |
| 132 | 132 |
| 133 void HTMLFormElement::removedFrom(ContainerNode* insertionPoint) | 133 void HTMLFormElement::removedFrom(ContainerNode* insertionPoint) |
| 134 { | 134 { |
| 135 // FIXME: We don't need to notify formRemovedFromTree to associated elements | 135 // 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 | 136 // attribute becuse IdTargetObserver handles it. |
| 137 // that this form doesn't have elements associated by parser or associated | 137 if (m_hasElementsAssociatedByParser) { |
| 138 // with 'form' content attribute. | 138 Node* root = highestAncestor(); |
| 139 Node* root = highestAncestor(); | 139 if (!m_associatedElementsAreDirty) { |
| 140 Vector<FormAssociatedElement*> elements(associatedElements()); | 140 notifyFormRemovedFromTree(associatedElements(), root); |
|
tkent
2014/01/29 01:02:16
We need to pass a copy of associatedElement(). Unl
| |
| 141 notifyFormRemovedFromTree(elements, root); | 141 } else { |
| 142 Vector<FormAssociatedElement*> elements; | |
| 143 collectAssociatedElements(insertionPoint->highestAncestor(), element s); | |
| 144 notifyFormRemovedFromTree(elements, root); | |
| 145 collectAssociatedElements(root, elements); | |
| 146 notifyFormRemovedFromTree(elements, root); | |
| 147 } | |
| 142 | 148 |
| 143 if (m_hasElementsAssociatedByParser) { | |
| 144 if (!m_imageElementsAreDirty) { | 149 if (!m_imageElementsAreDirty) { |
| 145 Vector<HTMLImageElement*> images(imageElements()); | 150 Vector<HTMLImageElement*> images(imageElements()); |
| 146 notifyFormRemovedFromTree(images, root); | 151 notifyFormRemovedFromTree(images, root); |
| 147 } else { | 152 } else { |
| 148 Vector<HTMLImageElement*> images; | 153 Vector<HTMLImageElement*> images; |
| 149 collectImageElements(insertionPoint->highestAncestor(), images); | 154 collectImageElements(insertionPoint->highestAncestor(), images); |
| 150 notifyFormRemovedFromTree(images, root); | 155 notifyFormRemovedFromTree(images, root); |
| 151 collectImageElements(root, images); | 156 collectImageElements(root, images); |
| 152 notifyFormRemovedFromTree(images, root); | 157 notifyFormRemovedFromTree(images, root); |
| 153 } | 158 } |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 513 else if (name == accept_charsetAttr) | 518 else if (name == accept_charsetAttr) |
| 514 m_attributes.setAcceptCharset(value); | 519 m_attributes.setAcceptCharset(value); |
| 515 else if (name == onautocompleteAttr) | 520 else if (name == onautocompleteAttr) |
| 516 setAttributeEventListener(EventTypeNames::autocomplete, createAttributeE ventListener(this, name, value)); | 521 setAttributeEventListener(EventTypeNames::autocomplete, createAttributeE ventListener(this, name, value)); |
| 517 else if (name == onautocompleteerrorAttr) | 522 else if (name == onautocompleteerrorAttr) |
| 518 setAttributeEventListener(EventTypeNames::autocompleteerror, createAttri buteEventListener(this, name, value)); | 523 setAttributeEventListener(EventTypeNames::autocompleteerror, createAttri buteEventListener(this, name, value)); |
| 519 else | 524 else |
| 520 HTMLElement::parseAttribute(name, value); | 525 HTMLElement::parseAttribute(name, value); |
| 521 } | 526 } |
| 522 | 527 |
| 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) | 528 void HTMLFormElement::associate(FormAssociatedElement& e) |
| 604 { | 529 { |
| 605 m_associatedElements.insert(formElementIndex(e), &e); | 530 m_associatedElementsAreDirty = true; |
| 531 m_associatedElements.clear(); | |
| 606 } | 532 } |
| 607 | 533 |
| 608 void HTMLFormElement::disassociate(FormAssociatedElement& e) | 534 void HTMLFormElement::disassociate(FormAssociatedElement& e) |
| 609 { | 535 { |
| 610 unsigned index; | 536 m_associatedElementsAreDirty = true; |
| 611 for (index = 0; index < m_associatedElements.size(); ++index) { | 537 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)); | 538 removeFromPastNamesMap(toHTMLElement(e)); |
| 621 removeFromVector(m_associatedElements, &e); | |
| 622 } | 539 } |
| 623 | 540 |
| 624 bool HTMLFormElement::isURLAttribute(const Attribute& attribute) const | 541 bool HTMLFormElement::isURLAttribute(const Attribute& attribute) const |
| 625 { | 542 { |
| 626 return attribute.name() == actionAttr || HTMLElement::isURLAttribute(attribu te); | 543 return attribute.name() == actionAttr || HTMLElement::isURLAttribute(attribu te); |
| 627 } | 544 } |
| 628 | 545 |
| 629 void HTMLFormElement::associate(HTMLImageElement& e) | 546 void HTMLFormElement::associate(HTMLImageElement& e) |
| 630 { | 547 { |
| 631 m_imageElementsAreDirty = true; | 548 m_imageElementsAreDirty = true; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 648 { | 565 { |
| 649 if (m_didFinishParsingChildren) | 566 if (m_didFinishParsingChildren) |
| 650 m_hasElementsAssociatedByParser = true; | 567 m_hasElementsAssociatedByParser = true; |
| 651 } | 568 } |
| 652 | 569 |
| 653 PassRefPtr<HTMLCollection> HTMLFormElement::elements() | 570 PassRefPtr<HTMLCollection> HTMLFormElement::elements() |
| 654 { | 571 { |
| 655 return ensureCachedHTMLCollection(FormControls); | 572 return ensureCachedHTMLCollection(FormControls); |
| 656 } | 573 } |
| 657 | 574 |
| 575 void HTMLFormElement::collectAssociatedElements(Node* root, Vector<FormAssociate dElement*>& elements) const | |
| 576 { | |
| 577 elements.clear(); | |
| 578 for (Node* node = root; node; node = NodeTraversal::next(*node)) { | |
| 579 if (!node->isHTMLElement()) | |
| 580 continue; | |
| 581 FormAssociatedElement* element = 0; | |
| 582 if (toElement(node)->isFormControlElement()) | |
| 583 element = toHTMLFormControlElement(node); | |
| 584 else if (node->hasTagName(objectTag)) | |
| 585 element = toHTMLObjectElement(node); | |
| 586 else | |
| 587 continue; | |
| 588 if (element->form()== this) | |
| 589 elements.append(element); | |
| 590 } | |
| 591 } | |
| 592 | |
| 593 // This function should be const conceptually. However we update some fields | |
| 594 // because of lazy evaluation. | |
| 595 const Vector<FormAssociatedElement*>& HTMLFormElement::associatedElements() cons t | |
| 596 { | |
| 597 if (!m_associatedElementsAreDirty) | |
| 598 return m_associatedElements; | |
| 599 HTMLFormElement* mutableThis = const_cast<HTMLFormElement*>(this); | |
| 600 Node* scope = mutableThis; | |
| 601 if (m_hasElementsAssociatedByParser) | |
| 602 scope = highestAncestor(); | |
| 603 if (inDocument() && treeScope().idTargetObserverRegistry().hasObservers(fast GetAttribute(idAttr))) | |
| 604 scope = &treeScope().rootNode(); | |
| 605 collectAssociatedElements(scope, mutableThis->m_associatedElements); | |
| 606 mutableThis->m_associatedElementsAreDirty = false; | |
| 607 return m_associatedElements; | |
| 608 } | |
| 609 | |
| 658 void HTMLFormElement::collectImageElements(Node* root, Vector<HTMLImageElement*> & elements) | 610 void HTMLFormElement::collectImageElements(Node* root, Vector<HTMLImageElement*> & elements) |
| 659 { | 611 { |
| 660 elements.clear(); | 612 elements.clear(); |
| 661 for (Node* node = root; node; node = NodeTraversal::next(*node)) { | 613 for (Node* node = root; node; node = NodeTraversal::next(*node)) { |
| 662 if (node->isHTMLElement() && node->hasTagName(imgTag) && toHTMLElement(n ode)->formOwner() == this) | 614 if (node->isHTMLElement() && node->hasTagName(imgTag) && toHTMLElement(n ode)->formOwner() == this) |
| 663 elements.append(toHTMLImageElement(node)); | 615 elements.append(toHTMLImageElement(node)); |
| 664 } | 616 } |
| 665 } | 617 } |
| 666 | 618 |
| 667 const Vector<HTMLImageElement*>& HTMLFormElement::imageElements() | 619 const Vector<HTMLImageElement*>& HTMLFormElement::imageElements() |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 859 } | 811 } |
| 860 | 812 |
| 861 void HTMLFormElement::setDemoted(bool demoted) | 813 void HTMLFormElement::setDemoted(bool demoted) |
| 862 { | 814 { |
| 863 if (demoted) | 815 if (demoted) |
| 864 UseCounter::count(document(), UseCounter::DemotedFormElement); | 816 UseCounter::count(document(), UseCounter::DemotedFormElement); |
| 865 m_wasDemoted = demoted; | 817 m_wasDemoted = demoted; |
| 866 } | 818 } |
| 867 | 819 |
| 868 } // namespace | 820 } // namespace |
| OLD | NEW |