OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |