Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1135)

Side by Side Diff: third_party/WebKit/Source/core/html/HTMLSelectElement.cpp

Issue 2131073002: SELECT element: Avoid to use listItems() in HTMLSelectElement::selectOption() (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
3 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
4 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 1999 Antti Koivisto (koivisto@kde.org)
5 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * (C) 2001 Dirk Mueller (mueller@kde.org)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved. 6 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved.
7 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) 7 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
8 * Copyright (C) 2010 Google Inc. All rights reserved. 8 * Copyright (C) 2010 Google Inc. All rights reserved.
9 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo bile.com/) 9 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo bile.com/)
10 * 10 *
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 // selection pivots around this anchor index. 637 // selection pivots around this anchor index.
638 // Example: 638 // Example:
639 // 1. Press the mouse button on the second OPTION 639 // 1. Press the mouse button on the second OPTION
640 // m_activeSelectionAnchorIndex = 1 640 // m_activeSelectionAnchorIndex = 1
641 // 2. Drag the mouse pointer onto the fifth OPTION 641 // 2. Drag the mouse pointer onto the fifth OPTION
642 // m_activeSelectionEndIndex = 4, options at 1-4 indices are selected. 642 // m_activeSelectionEndIndex = 4, options at 1-4 indices are selected.
643 // 3. Drag the mouse pointer onto the fourth OPTION 643 // 3. Drag the mouse pointer onto the fourth OPTION
644 // m_activeSelectionEndIndex = 3, options at 1-3 indices are selected. 644 // m_activeSelectionEndIndex = 3, options at 1-3 indices are selected.
645 // updateListBoxSelection needs to clear selection of the fifth OPTION. 645 // updateListBoxSelection needs to clear selection of the fifth OPTION.
646 m_cachedStateForActiveSelection.resize(0); 646 m_cachedStateForActiveSelection.resize(0);
647 for (auto& element : listItems()) { 647 for (const auto& option : optionList()) {
648 m_cachedStateForActiveSelection.append(isHTMLOptionElement(*element) && toHTMLOptionElement(element)->selected()); 648 m_cachedStateForActiveSelection.append(option->selected());
649 } 649 }
650 } 650 }
651 651
652 void HTMLSelectElement::setActiveSelectionEnd(HTMLOptionElement* option) 652 void HTMLSelectElement::setActiveSelectionEnd(HTMLOptionElement* option)
653 { 653 {
654 m_activeSelectionEnd = option; 654 m_activeSelectionEnd = option;
655 } 655 }
656 656
657 void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions, bool s croll) 657 void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions, bool s croll)
658 { 658 {
659 ASSERT(layoutObject()); 659 ASSERT(layoutObject());
660 ASSERT(layoutObject()->isListBox() || m_multiple); 660 ASSERT(layoutObject()->isListBox() || m_multiple);
661 661
662 int activeSelectionAnchorIndex = m_activeSelectionAnchor ? m_activeSelection Anchor->listIndex() : -1; 662 int activeSelectionAnchorIndex = m_activeSelectionAnchor ? m_activeSelection Anchor->index() : -1;
663 int activeSelectionEndIndex = m_activeSelectionEnd ? m_activeSelectionEnd->l istIndex() : -1; 663 int activeSelectionEndIndex = m_activeSelectionEnd ? m_activeSelectionEnd->i ndex() : -1;
664 int start = std::min(activeSelectionAnchorIndex, activeSelectionEndIndex); 664 int start = std::min(activeSelectionAnchorIndex, activeSelectionEndIndex);
665 int end = std::max(activeSelectionAnchorIndex, activeSelectionEndIndex); 665 int end = std::max(activeSelectionAnchorIndex, activeSelectionEndIndex);
666 666
667 const ListItems& items = listItems(); 667 int i = 0;
668 for (int i = 0; i < static_cast<int>(items.size()); ++i) { 668 for (const auto& option : optionList()) {
669 if (!isHTMLOptionElement(*items[i])) 669 if (option->isDisabledFormControl() || !option->layoutObject()) {
670 ++i;
670 continue; 671 continue;
671 HTMLOptionElement& option = toHTMLOptionElement(*items[i]); 672 }
672 if (option.isDisabledFormControl() || !option.layoutObject())
673 continue;
674 if (i >= start && i <= end) { 673 if (i >= start && i <= end) {
675 option.setSelectedState(m_activeSelectionState); 674 option->setSelectedState(m_activeSelectionState);
676 option.setDirty(true); 675 option->setDirty(true);
677 } else if (deselectOtherOptions || i >= static_cast<int>(m_cachedStateFo rActiveSelection.size())) { 676 } else if (deselectOtherOptions || i >= static_cast<int>(m_cachedStateFo rActiveSelection.size())) {
678 option.setSelectedState(false); 677 option->setSelectedState(false);
679 option.setDirty(true); 678 option->setDirty(true);
680 } else { 679 } else {
681 option.setSelectedState(m_cachedStateForActiveSelection[i]); 680 option->setSelectedState(m_cachedStateForActiveSelection[i]);
682 } 681 }
682 ++i;
683 } 683 }
684 684
685 setNeedsValidityCheck(); 685 setNeedsValidityCheck();
686 if (scroll) 686 if (scroll)
687 scrollToSelection(); 687 scrollToSelection();
688 notifyFormStateChanged(); 688 notifyFormStateChanged();
689 } 689 }
690 690
691 void HTMLSelectElement::listBoxOnChange() 691 void HTMLSelectElement::listBoxOnChange()
692 { 692 {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 763
764 return m_listItems; 764 return m_listItems;
765 } 765 }
766 766
767 void HTMLSelectElement::invalidateSelectedItems() 767 void HTMLSelectElement::invalidateSelectedItems()
768 { 768 {
769 if (HTMLCollection* collection = cachedCollection<HTMLCollection>(SelectedOp tions)) 769 if (HTMLCollection* collection = cachedCollection<HTMLCollection>(SelectedOp tions))
770 collection->invalidateCache(); 770 collection->invalidateCache();
771 } 771 }
772 772
773 void HTMLSelectElement::setRecalcListItems(HTMLElement& subject) 773 void HTMLSelectElement::setRecalcListItems()
774 { 774 {
775 // FIXME: This function does a bunch of confusing things depending on if it 775 // FIXME: This function does a bunch of confusing things depending on if it
776 // is in the document or not. 776 // is in the document or not.
777 777
778 bool shouldRecalc = true; 778 m_shouldRecalcListItems = true;
779 if (!m_shouldRecalcListItems && !isHTMLOptGroupElement(subject)) {
780 if (firstChild() == &subject) {
781 // The subject was prepended. This doesn't handle elements in an
782 // OPTGROUP.
783 DCHECK(m_listItems.size() == 0 || m_listItems[0] != &subject);
784 m_listItems.prepend(&subject);
785 shouldRecalc = false;
786 } else if (lastChild() == &subject) {
787 // The subject was appended. This doesn't handle elements in an
788 // OPTGROUP.
789 DCHECK(m_listItems.size() == 0 || m_listItems.last() != &subject);
790 m_listItems.append(&subject);
791 shouldRecalc = false;
792 } else if (!subject.isDescendantOf(this)) {
793 // |subject| was removed from this. This logic works well with
794 // SELECT children and OPTGROUP children.
795
796 // m_listItems might be empty, or might not have the OPTION.
797 // 1. Remove an OPTGROUP with OPTION children from a SELECT.
798 // 2. This function is called for the OPTGROUP removal.
799 // 3. m_shouldRecalcListItems becomes true.
800 // 4. recalcListItems() happens. m_listItems has no OPTGROUP and
801 // no its children. m_shouldRecalcListItems becomes false.
802 // 5. This function is called for the removal of an OPTION child
803 // of the OPTGROUP.
804 if (m_listItems.size() > 0) {
805 size_t index;
806 // Avoid Vector::find() in typical cases.
807 if (m_listItems.first() == &subject)
808 index = 0;
809 else if (m_listItems.last() == &subject)
810 index = m_listItems.size() - 1;
811 else
812 index = m_listItems.find(&subject);
813 if (index != WTF::kNotFound) {
814 m_listItems.remove(index);
815 shouldRecalc = false;
816 }
817 }
818 }
819 }
820 m_shouldRecalcListItems = shouldRecalc;
821 779
822 setOptionsChangedOnLayoutObject(); 780 setOptionsChangedOnLayoutObject();
823 if (!inShadowIncludingDocument()) { 781 if (!inShadowIncludingDocument()) {
824 if (HTMLOptionsCollection* collection = cachedCollection<HTMLOptionsColl ection>(SelectOptions)) 782 if (HTMLOptionsCollection* collection = cachedCollection<HTMLOptionsColl ection>(SelectOptions))
825 collection->invalidateCache(); 783 collection->invalidateCache();
826 invalidateSelectedItems(); 784 invalidateSelectedItems();
827 } 785 }
828 786
829 if (layoutObject()) { 787 if (layoutObject()) {
830 if (AXObjectCache* cache = layoutObject()->document().existingAXObjectCa che()) 788 if (AXObjectCache* cache = layoutObject()->document().existingAXObjectCa che())
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
911 lastSelectedOption = firstEnabledOption; 869 lastSelectedOption = firstEnabledOption;
912 didChange = true; 870 didChange = true;
913 } 871 }
914 if (didChange) 872 if (didChange)
915 setNeedsValidityCheck(); 873 setNeedsValidityCheck();
916 m_lastOnChangeOption = lastSelectedOption; 874 m_lastOnChangeOption = lastSelectedOption;
917 } 875 }
918 876
919 HTMLOptionElement* HTMLSelectElement::selectedOption() const 877 HTMLOptionElement* HTMLSelectElement::selectedOption() const
920 { 878 {
921 for (const auto& element : listItems()) { 879 for (const auto option : optionList()) {
keishi 2016/07/11 02:00:39 &?
tkent 2016/07/11 02:12:32 & is not used intentionally. If we add & here, com
922 if (isHTMLOptionElement(*element) && toHTMLOptionElement(*element).selec ted()) 880 if (option->selected())
923 return toHTMLOptionElement(element); 881 return option;
924 } 882 }
925 return nullptr; 883 return nullptr;
926 } 884 }
927 885
928 int HTMLSelectElement::selectedIndex() const 886 int HTMLSelectElement::selectedIndex() const
929 { 887 {
930 unsigned index = 0; 888 unsigned index = 0;
931 889
932 // Return the number of the first option selected. 890 // Return the number of the first option selected.
933 for (auto& element : listItems()) { 891 for (auto& element : listItems()) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
997 selectOption(option, multiple() ? 0 : DeselectOtherOptions); 955 selectOption(option, multiple() ? 0 : DeselectOtherOptions);
998 else if (!usesMenuList() || multiple()) 956 else if (!usesMenuList() || multiple())
999 selectOption(nullptr, multiple() ? 0 : DeselectOtherOptions); 957 selectOption(nullptr, multiple() ? 0 : DeselectOtherOptions);
1000 else 958 else
1001 selectOption(nextSelectableOption(nullptr), DeselectOtherOptions); 959 selectOption(nextSelectableOption(nullptr), DeselectOtherOptions);
1002 } 960 }
1003 961
1004 void HTMLSelectElement::optionInserted(HTMLOptionElement& option, bool optionIsS elected) 962 void HTMLSelectElement::optionInserted(HTMLOptionElement& option, bool optionIsS elected)
1005 { 963 {
1006 ASSERT(option.ownerSelectElement() == this); 964 ASSERT(option.ownerSelectElement() == this);
1007 setRecalcListItems(option); 965 setRecalcListItems();
1008 if (optionIsSelected) { 966 if (optionIsSelected) {
1009 selectOption(&option, multiple() ? 0 : DeselectOtherOptions); 967 selectOption(&option, multiple() ? 0 : DeselectOtherOptions);
1010 } else { 968 } else {
1011 // No need to reset if we already have a selected option. 969 // No need to reset if we already have a selected option.
1012 if (!m_lastOnChangeOption) 970 if (!m_lastOnChangeOption)
1013 resetToDefaultSelection(); 971 resetToDefaultSelection();
1014 } 972 }
1015 setNeedsValidityCheck(); 973 setNeedsValidityCheck();
1016 m_lastOnChangeSelection.clear(); 974 m_lastOnChangeSelection.clear();
1017 } 975 }
1018 976
1019 void HTMLSelectElement::optionRemoved(HTMLOptionElement& option) 977 void HTMLSelectElement::optionRemoved(HTMLOptionElement& option)
1020 { 978 {
1021 setRecalcListItems(option); 979 setRecalcListItems();
1022 if (option.selected()) 980 if (option.selected())
1023 resetToDefaultSelection(ResetReasonSelectedOptionRemoved); 981 resetToDefaultSelection(ResetReasonSelectedOptionRemoved);
1024 else if (!m_lastOnChangeOption) 982 else if (!m_lastOnChangeOption)
1025 resetToDefaultSelection(); 983 resetToDefaultSelection();
1026 if (m_lastOnChangeOption == &option) 984 if (m_lastOnChangeOption == &option)
1027 m_lastOnChangeOption.clear(); 985 m_lastOnChangeOption.clear();
1028 if (m_optionToScrollTo == &option) 986 if (m_optionToScrollTo == &option)
1029 m_optionToScrollTo.clear(); 987 m_optionToScrollTo.clear();
1030 if (m_activeSelectionAnchor == &option) 988 if (m_activeSelectionAnchor == &option)
1031 m_activeSelectionAnchor.clear(); 989 m_activeSelectionAnchor.clear();
1032 if (m_activeSelectionEnd == &option) 990 if (m_activeSelectionEnd == &option)
1033 m_activeSelectionEnd.clear(); 991 m_activeSelectionEnd.clear();
1034 if (m_suggestedOption == &option) 992 if (m_suggestedOption == &option)
1035 setSuggestedOption(nullptr); 993 setSuggestedOption(nullptr);
1036 if (option.selected()) 994 if (option.selected())
1037 setAutofilled(false); 995 setAutofilled(false);
1038 setNeedsValidityCheck(); 996 setNeedsValidityCheck();
1039 m_lastOnChangeSelection.clear(); 997 m_lastOnChangeSelection.clear();
1040 } 998 }
1041 999
1042 void HTMLSelectElement::optGroupInsertedOrRemoved(HTMLOptGroupElement& optgroup) 1000 void HTMLSelectElement::optGroupInsertedOrRemoved(HTMLOptGroupElement& optgroup)
1043 { 1001 {
1044 setRecalcListItems(optgroup); 1002 setRecalcListItems();
1045 setNeedsValidityCheck(); 1003 setNeedsValidityCheck();
1046 m_lastOnChangeSelection.clear(); 1004 m_lastOnChangeSelection.clear();
1047 } 1005 }
1048 1006
1049 void HTMLSelectElement::hrInsertedOrRemoved(HTMLHRElement& hr) 1007 void HTMLSelectElement::hrInsertedOrRemoved(HTMLHRElement& hr)
1050 { 1008 {
1051 setRecalcListItems(hr); 1009 setRecalcListItems();
1052 m_lastOnChangeSelection.clear(); 1010 m_lastOnChangeSelection.clear();
1053 } 1011 }
1054 1012
1055 // TODO(tkent): This function is not efficient. It contains multiple O(N) 1013 // TODO(tkent): This function is not efficient. It contains multiple O(N)
1056 // operations. crbug.com/577989. 1014 // operations. crbug.com/577989.
1057 void HTMLSelectElement::selectOption(HTMLOptionElement* element, SelectOptionFla gs flags) 1015 void HTMLSelectElement::selectOption(HTMLOptionElement* element, SelectOptionFla gs flags)
1058 { 1016 {
1059 TRACE_EVENT0("blink", "HTMLSelectElement::selectOption"); 1017 TRACE_EVENT0("blink", "HTMLSelectElement::selectOption");
1060 1018
1061 // selectedOption() is O(N). 1019 // selectedOption() is O(N).
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
1167 m_typeAhead.resetSession(); 1125 m_typeAhead.resetSession();
1168 // We only need to fire change events here for menu lists, because we fire 1126 // We only need to fire change events here for menu lists, because we fire
1169 // change events for list boxes whenever the selection change is actually 1127 // change events for list boxes whenever the selection change is actually
1170 // made. This matches other browsers' behavior. 1128 // made. This matches other browsers' behavior.
1171 if (usesMenuList()) 1129 if (usesMenuList())
1172 dispatchInputAndChangeEventForMenuList(); 1130 dispatchInputAndChangeEventForMenuList();
1173 m_lastOnChangeSelection.clear(); 1131 m_lastOnChangeSelection.clear();
1174 HTMLFormControlElementWithState::dispatchBlurEvent(newFocusedElement, type, sourceCapabilities); 1132 HTMLFormControlElementWithState::dispatchBlurEvent(newFocusedElement, type, sourceCapabilities);
1175 } 1133 }
1176 1134
1177 void HTMLSelectElement::deselectItemsWithoutValidation(HTMLElement* excludeEleme nt) 1135 void HTMLSelectElement::deselectItemsWithoutValidation(HTMLOptionElement* exclud eElement)
1178 { 1136 {
1179 if (!multiple() && usesMenuList() && m_lastOnChangeOption && m_lastOnChangeO ption != excludeElement) { 1137 if (!multiple() && usesMenuList() && m_lastOnChangeOption && m_lastOnChangeO ption != excludeElement) {
1180 m_lastOnChangeOption->setSelectedState(false); 1138 m_lastOnChangeOption->setSelectedState(false);
1181 return; 1139 return;
1182 } 1140 }
1183 for (auto& element : listItems()) { 1141 for (const auto& option : optionList()) {
1184 if (element != excludeElement && isHTMLOptionElement(*element)) 1142 if (option != excludeElement)
1185 toHTMLOptionElement(element)->setSelectedState(false); 1143 option->setSelectedState(false);
1186 } 1144 }
1187 } 1145 }
1188 1146
1189 FormControlState HTMLSelectElement::saveFormControlState() const 1147 FormControlState HTMLSelectElement::saveFormControlState() const
1190 { 1148 {
1191 const ListItems& items = listItems(); 1149 const ListItems& items = listItems();
1192 size_t length = items.size(); 1150 size_t length = items.size();
1193 FormControlState state; 1151 FormControlState state;
1194 for (unsigned i = 0; i < length; ++i) { 1152 for (unsigned i = 0; i < length; ++i) {
1195 if (!isHTMLOptionElement(*items[i])) 1153 if (!isHTMLOptionElement(*items[i]))
(...skipping 934 matching lines...) Expand 10 before | Expand all | Expand 10 after
2130 } 2088 }
2131 2089
2132 void HTMLSelectElement::didMutateSubtree() 2090 void HTMLSelectElement::didMutateSubtree()
2133 { 2091 {
2134 DCHECK(popupIsVisible()); 2092 DCHECK(popupIsVisible());
2135 DCHECK(m_popup); 2093 DCHECK(m_popup);
2136 m_popup->updateFromElement(PopupMenu::ByDOMChange); 2094 m_popup->updateFromElement(PopupMenu::ByDOMChange);
2137 } 2095 }
2138 2096
2139 } // namespace blink 2097 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/html/HTMLSelectElement.h ('k') | third_party/WebKit/Source/core/html/forms/OptionList.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698