Chromium Code Reviews| 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 21 matching lines...) Expand all Loading... | |
| 32 #include "bindings/v8/ExceptionState.h" | 32 #include "bindings/v8/ExceptionState.h" |
| 33 #include "bindings/v8/ExceptionStatePlaceholder.h" | 33 #include "bindings/v8/ExceptionStatePlaceholder.h" |
| 34 #include "core/HTMLNames.h" | 34 #include "core/HTMLNames.h" |
| 35 #include "core/accessibility/AXObjectCache.h" | 35 #include "core/accessibility/AXObjectCache.h" |
| 36 #include "core/dom/Attribute.h" | 36 #include "core/dom/Attribute.h" |
| 37 #include "core/dom/ElementTraversal.h" | 37 #include "core/dom/ElementTraversal.h" |
| 38 #include "core/dom/NodeTraversal.h" | 38 #include "core/dom/NodeTraversal.h" |
| 39 #include "core/events/GestureEvent.h" | 39 #include "core/events/GestureEvent.h" |
| 40 #include "core/events/KeyboardEvent.h" | 40 #include "core/events/KeyboardEvent.h" |
| 41 #include "core/events/MouseEvent.h" | 41 #include "core/events/MouseEvent.h" |
| 42 #include "core/frame/FrameView.h" | |
| 42 #include "core/frame/LocalFrame.h" | 43 #include "core/frame/LocalFrame.h" |
| 43 #include "core/html/FormDataList.h" | 44 #include "core/html/FormDataList.h" |
| 44 #include "core/html/HTMLFormElement.h" | 45 #include "core/html/HTMLFormElement.h" |
| 46 #include "core/html/HTMLOptGroupElement.h" | |
| 45 #include "core/html/HTMLOptionElement.h" | 47 #include "core/html/HTMLOptionElement.h" |
| 46 #include "core/html/forms/FormController.h" | 48 #include "core/html/forms/FormController.h" |
| 49 #include "core/page/AutoscrollController.h" | |
| 47 #include "core/page/EventHandler.h" | 50 #include "core/page/EventHandler.h" |
| 51 #include "core/page/Page.h" | |
| 48 #include "core/page/SpatialNavigation.h" | 52 #include "core/page/SpatialNavigation.h" |
| 53 #include "core/rendering/HitTestRequest.h" | |
| 54 #include "core/rendering/HitTestResult.h" | |
| 49 #include "core/rendering/RenderListBox.h" | 55 #include "core/rendering/RenderListBox.h" |
| 50 #include "core/rendering/RenderMenuList.h" | 56 #include "core/rendering/RenderMenuList.h" |
| 51 #include "core/rendering/RenderTheme.h" | 57 #include "core/rendering/RenderTheme.h" |
| 58 #include "core/rendering/RenderView.h" | |
| 52 #include "platform/PlatformMouseEvent.h" | 59 #include "platform/PlatformMouseEvent.h" |
| 53 #include "platform/text/PlatformLocale.h" | 60 #include "platform/text/PlatformLocale.h" |
| 54 | 61 |
| 55 using namespace WTF::Unicode; | 62 using namespace WTF::Unicode; |
| 56 | 63 |
| 57 namespace WebCore { | 64 namespace WebCore { |
| 58 | 65 |
| 59 using namespace HTMLNames; | 66 using namespace HTMLNames; |
| 60 | 67 |
| 61 // Upper limit agreed upon with representatives of Opera and Mozilla. | 68 // Upper limit agreed upon with representatives of Opera and Mozilla. |
| 62 static const unsigned maxSelectItems = 10000; | 69 static const unsigned maxSelectItems = 10000; |
| 63 | 70 |
| 64 HTMLSelectElement::HTMLSelectElement(Document& document, HTMLFormElement* form) | 71 HTMLSelectElement::HTMLSelectElement(Document& document, HTMLFormElement* form) |
| 65 : HTMLFormControlElementWithState(selectTag, document, form) | 72 : HTMLFormControlElementWithState(selectTag, document, form) |
| 66 , m_typeAhead(this) | 73 , m_typeAhead(this) |
| 67 , m_size(0) | 74 , m_size(0) |
| 68 , m_lastOnChangeIndex(-1) | 75 , m_lastOnChangeIndex(-1) |
| 69 , m_activeSelectionAnchorIndex(-1) | 76 , m_activeSelectionAnchorIndex(-1) |
| 70 , m_activeSelectionEndIndex(-1) | 77 , m_activeSelectionEndIndex(-1) |
| 71 , m_isProcessingUserDrivenChange(false) | 78 , m_isProcessingUserDrivenChange(false) |
| 72 , m_multiple(false) | 79 , m_multiple(false) |
| 73 , m_activeSelectionState(false) | 80 , m_activeSelectionState(false) |
| 74 , m_shouldRecalcListItems(false) | 81 , m_shouldRecalcListItems(false) |
| 75 , m_suggestedIndex(-1) | 82 , m_suggestedIndex(-1) |
| 83 , m_capturing(false) | |
| 76 { | 84 { |
| 77 ScriptWrappable::init(this); | 85 ScriptWrappable::init(this); |
| 78 setHasCustomStyleCallbacks(); | 86 setHasCustomStyleCallbacks(); |
| 79 } | 87 } |
| 80 | 88 |
| 81 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do cument) | 89 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do cument) |
| 82 { | 90 { |
| 83 return adoptRefWillBeNoop(new HTMLSelectElement(document, 0)); | 91 return adoptRefWillBeNoop(new HTMLSelectElement(document, 0)); |
| 84 } | 92 } |
| 85 | 93 |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 327 sizeAttribute->setValue(attrSize); | 335 sizeAttribute->setValue(attrSize); |
| 328 } | 336 } |
| 329 size = std::max(size, 1); | 337 size = std::max(size, 1); |
| 330 | 338 |
| 331 // Ensure that we've determined selectedness of the items at least once prior to changing the size. | 339 // Ensure that we've determined selectedness of the items at least once prior to changing the size. |
| 332 if (oldSize != size) | 340 if (oldSize != size) |
| 333 updateListItemSelectedStates(); | 341 updateListItemSelectedStates(); |
| 334 | 342 |
| 335 m_size = size; | 343 m_size = size; |
| 336 setNeedsValidityCheck(); | 344 setNeedsValidityCheck(); |
| 337 if (m_size != oldSize && inActiveDocument()) { | 345 if (m_size != oldSize && document().isActive()) { |
| 338 lazyReattachIfAttached(); | 346 // ensureShadowDOM needs to be run even when !inDocument(). |
|
esprehn
2014/06/23 21:59:56
ensureUserAgentShadowRoot should be run by ::creat
| |
| 339 setRecalcListItems(); | 347 updateView(); |
| 348 if (inDocument()) | |
| 349 setRecalcListItems(); | |
| 340 } | 350 } |
| 341 } else if (name == multipleAttr) | 351 } else if (name == multipleAttr) |
| 342 parseMultipleAttribute(value); | 352 parseMultipleAttribute(value); |
| 343 else if (name == accesskeyAttr) { | 353 else if (name == accesskeyAttr) { |
| 344 // FIXME: ignore for the moment. | 354 // FIXME: ignore for the moment. |
| 345 // | 355 // |
| 346 } else if (name == disabledAttr) { | 356 } else if (name == disabledAttr) { |
| 347 HTMLFormControlElementWithState::parseAttribute(name, value); | 357 HTMLFormControlElementWithState::parseAttribute(name, value); |
| 348 if (renderer() && renderer()->isMenuList()) { | 358 if (renderer() && renderer()->isMenuList()) { |
| 349 if (RenderMenuList* menuList = toRenderMenuList(renderer())) { | 359 if (RenderMenuList* menuList = toRenderMenuList(renderer())) { |
| 350 if (menuList->popupIsVisible()) | 360 if (menuList->popupIsVisible()) |
| 351 menuList->hidePopup(); | 361 menuList->hidePopup(); |
| 352 } | 362 } |
| 353 } | 363 } |
| 354 | 364 |
| 355 } else | 365 } else |
| 356 HTMLFormControlElementWithState::parseAttribute(name, value); | 366 HTMLFormControlElementWithState::parseAttribute(name, value); |
| 357 } | 367 } |
| 358 | 368 |
| 359 bool HTMLSelectElement::shouldShowFocusRingOnMouseFocus() const | 369 bool HTMLSelectElement::shouldShowFocusRingOnMouseFocus() const |
| 360 { | 370 { |
| 361 return true; | 371 return true; |
| 362 } | 372 } |
| 363 | 373 |
| 364 bool HTMLSelectElement::canSelectAll() const | 374 bool HTMLSelectElement::canSelectAll() const |
| 365 { | 375 { |
| 366 return !usesMenuList(); | 376 return !usesMenuList(); |
| 367 } | 377 } |
| 368 | 378 |
| 369 RenderObject* HTMLSelectElement::createRenderer(RenderStyle*) | 379 RenderObject* HTMLSelectElement::createRenderer(RenderStyle* style) |
| 370 { | 380 { |
| 371 if (usesMenuList()) | 381 if (usesMenuList()) |
| 372 return new RenderMenuList(this); | 382 return new RenderMenuList(this); |
| 373 return new RenderListBox(this); | 383 return new RenderListBox(this); |
| 374 } | 384 } |
| 375 | 385 |
| 376 PassRefPtrWillBeRawPtr<HTMLCollection> HTMLSelectElement::selectedOptions() | 386 PassRefPtrWillBeRawPtr<HTMLCollection> HTMLSelectElement::selectedOptions() |
| 377 { | 387 { |
| 378 updateListItemSelectedStates(); | 388 updateListItemSelectedStates(); |
| 379 return ensureCachedHTMLCollection(SelectedOptions); | 389 return ensureCachedHTMLCollection(SelectedOptions); |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 696 m_lastOnChangeIndex = selected; | 706 m_lastOnChangeIndex = selected; |
| 697 m_isProcessingUserDrivenChange = false; | 707 m_isProcessingUserDrivenChange = false; |
| 698 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this); | 708 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this); |
| 699 dispatchInputEvent(); | 709 dispatchInputEvent(); |
| 700 dispatchFormControlChangeEvent(); | 710 dispatchFormControlChangeEvent(); |
| 701 } | 711 } |
| 702 } | 712 } |
| 703 | 713 |
| 704 void HTMLSelectElement::scrollToSelection() | 714 void HTMLSelectElement::scrollToSelection() |
| 705 { | 715 { |
| 716 if (!isFinishedParsingChildren()) | |
| 717 return; | |
| 706 if (usesMenuList()) | 718 if (usesMenuList()) |
| 707 return; | 719 return; |
| 708 | 720 scrollTo(activeSelectionEndListIndex()); |
| 709 if (RenderObject* renderer = this->renderer()) | 721 if (AXObjectCache* cache = document().existingAXObjectCache()) |
| 710 toRenderListBox(renderer)->selectionChanged(); | 722 cache->selectedChildrenChanged(this); |
| 711 } | 723 } |
| 712 | 724 |
| 713 void HTMLSelectElement::setOptionsChangedOnRenderer() | 725 void HTMLSelectElement::setOptionsChangedOnRenderer() |
| 714 { | 726 { |
| 715 if (RenderObject* renderer = this->renderer()) { | 727 if (RenderObject* renderer = this->renderer()) { |
| 716 if (usesMenuList()) | 728 if (usesMenuList()) |
| 717 toRenderMenuList(renderer)->setOptionsChanged(true); | 729 toRenderMenuList(renderer)->setOptionsChanged(true); |
| 718 else | |
| 719 toRenderListBox(renderer)->setOptionsChanged(true); | |
| 720 } | 730 } |
| 721 } | 731 } |
| 722 | 732 |
| 723 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& HTMLSelectElement::lis tItems() const | 733 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& HTMLSelectElement::lis tItems() const |
| 724 { | 734 { |
| 725 if (m_shouldRecalcListItems) | 735 if (m_shouldRecalcListItems) |
| 726 recalcListItems(); | 736 recalcListItems(); |
| 727 else { | 737 else { |
| 728 #if ASSERT_ENABLED | 738 #if ASSERT_ENABLED |
| 729 WillBeHeapVector<RawPtrWillBeMember<HTMLElement> > items = m_listItems; | 739 WillBeHeapVector<RawPtrWillBeMember<HTMLElement> > items = m_listItems; |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 851 { | 861 { |
| 852 return m_suggestedIndex; | 862 return m_suggestedIndex; |
| 853 } | 863 } |
| 854 | 864 |
| 855 void HTMLSelectElement::setSuggestedIndex(int suggestedIndex) | 865 void HTMLSelectElement::setSuggestedIndex(int suggestedIndex) |
| 856 { | 866 { |
| 857 m_suggestedIndex = suggestedIndex; | 867 m_suggestedIndex = suggestedIndex; |
| 858 | 868 |
| 859 if (RenderObject* renderer = this->renderer()) { | 869 if (RenderObject* renderer = this->renderer()) { |
| 860 renderer->updateFromElement(); | 870 renderer->updateFromElement(); |
| 861 if (renderer->isListBox()) | 871 scrollTo(suggestedIndex); |
| 862 toRenderListBox(renderer)->scrollToRevealElementAtListIndex(suggeste dIndex); | |
| 863 } | 872 } |
| 864 } | 873 } |
| 865 | 874 |
| 875 void HTMLSelectElement::scrollTo(int listIndex) | |
| 876 { | |
| 877 if (listIndex < 0) | |
| 878 return; | |
| 879 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); | |
| 880 int listSize = static_cast<int>(items.size()); | |
| 881 if (listIndex >= listSize) | |
| 882 return; | |
| 883 items[listIndex]->scrollIntoViewIfNeeded(false); | |
| 884 } | |
| 885 | |
| 866 void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, b ool optionIsSelected) | 886 void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, b ool optionIsSelected) |
| 867 { | 887 { |
| 868 ASSERT(option->ownerSelectElement() == this); | 888 ASSERT(option->ownerSelectElement() == this); |
| 869 if (optionIsSelected) | 889 if (optionIsSelected) |
| 870 selectOption(option->index()); | 890 selectOption(option->index()); |
| 871 else if (!usesMenuList() || multiple()) | 891 else if (!usesMenuList() || multiple()) |
| 872 selectOption(-1); | 892 selectOption(-1); |
| 873 else | 893 else |
| 874 selectOption(nextSelectableListIndex(-1)); | 894 selectOption(nextSelectableListIndex(-1)); |
| 875 } | 895 } |
| 876 | 896 |
| 897 void HTMLSelectElement::optionRemoved(HTMLOptionElement* option) | |
| 898 { | |
| 899 if (m_activeSelectionAnchorIndex < 0 && m_activeSelectionEndIndex < 0) | |
| 900 return; | |
| 901 int listIndex = optionToListIndex(option->index()); | |
|
keishi
2014/06/23 20:42:01
fast/forms/select-max-length.html was slow because
| |
| 902 if (listIndex <= m_activeSelectionAnchorIndex) | |
| 903 m_activeSelectionAnchorIndex--; | |
| 904 if (listIndex <= m_activeSelectionEndIndex) | |
| 905 m_activeSelectionEndIndex--; | |
| 906 } | |
| 907 | |
| 877 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags) | 908 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags) |
| 878 { | 909 { |
| 879 bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions); | 910 bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions); |
| 880 | 911 |
| 881 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); | 912 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); |
| 882 int listIndex = optionToListIndex(optionIndex); | 913 int listIndex = optionToListIndex(optionIndex); |
| 883 | 914 |
| 884 HTMLElement* element = 0; | 915 HTMLElement* element = 0; |
| 885 if (listIndex >= 0) { | 916 if (listIndex >= 0) { |
| 886 element = items[listIndex]; | 917 element = items[listIndex]; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 902 | 933 |
| 903 scrollToSelection(); | 934 scrollToSelection(); |
| 904 | 935 |
| 905 setNeedsValidityCheck(); | 936 setNeedsValidityCheck(); |
| 906 | 937 |
| 907 if (usesMenuList()) { | 938 if (usesMenuList()) { |
| 908 m_isProcessingUserDrivenChange = flags & UserDriven; | 939 m_isProcessingUserDrivenChange = flags & UserDriven; |
| 909 if (flags & DispatchInputAndChangeEvent) | 940 if (flags & DispatchInputAndChangeEvent) |
| 910 dispatchInputAndChangeEventForMenuList(); | 941 dispatchInputAndChangeEventForMenuList(); |
| 911 if (RenderObject* renderer = this->renderer()) { | 942 if (RenderObject* renderer = this->renderer()) { |
| 912 if (usesMenuList()) | 943 if (usesMenuList()) { |
| 913 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex); | 944 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex); |
| 914 else if (renderer->isListBox()) | 945 } else if (renderer->isListBox()) { |
| 915 toRenderListBox(renderer)->selectionChanged(); | 946 if (AXObjectCache* cache = document().existingAXObjectCache()) |
| 947 cache->selectedChildrenChanged(this); | |
| 948 } | |
| 916 } | 949 } |
| 917 } | 950 } |
| 918 | 951 |
| 919 notifyFormStateChanged(); | 952 notifyFormStateChanged(); |
| 920 } | 953 } |
| 921 | 954 |
| 922 int HTMLSelectElement::optionToListIndex(int optionIndex) const | 955 int HTMLSelectElement::optionToListIndex(int optionIndex) const |
| 923 { | 956 { |
| 924 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); | 957 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); |
| 925 int listSize = static_cast<int>(items.size()); | 958 int listSize = static_cast<int>(items.size()); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1046 startIndex = foundIndex + 1; | 1079 startIndex = foundIndex + 1; |
| 1047 } | 1080 } |
| 1048 } | 1081 } |
| 1049 | 1082 |
| 1050 setOptionsChangedOnRenderer(); | 1083 setOptionsChangedOnRenderer(); |
| 1051 setNeedsValidityCheck(); | 1084 setNeedsValidityCheck(); |
| 1052 } | 1085 } |
| 1053 | 1086 |
| 1054 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value) | 1087 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value) |
| 1055 { | 1088 { |
| 1056 bool oldUsesMenuList = usesMenuList(); | |
| 1057 m_multiple = !value.isNull(); | 1089 m_multiple = !value.isNull(); |
| 1058 setNeedsValidityCheck(); | 1090 setNeedsValidityCheck(); |
| 1059 if (oldUsesMenuList != usesMenuList()) | 1091 |
| 1060 lazyReattachIfAttached(); | 1092 updateView(); |
| 1093 } | |
| 1094 | |
| 1095 void HTMLSelectElement::updateView() | |
| 1096 { | |
| 1097 if (!usesMenuList()) | |
| 1098 ensureUserAgentShadowRoot(); | |
| 1099 else if (userAgentShadowRoot() && document().lifecycle().stateAllowsDetach() ) | |
|
esprehn
2014/06/23 21:59:56
This is wrong, you should not be manually interact
| |
| 1100 userAgentShadowRoot()->detach(); | |
| 1101 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); | |
| 1102 unsigned optionCount = 0; | |
| 1103 for (unsigned i = 0; i < items.size(); ++i) { | |
| 1104 HTMLElement* element = items[i]; | |
| 1105 if (isHTMLOptionElement(*element)) { | |
| 1106 toHTMLOptionElement(*element).updateView(); | |
| 1107 optionCount++; | |
| 1108 } else if (isHTMLOptGroupElement(*element)) { | |
| 1109 toHTMLOptGroupElement(*element).updateView(); | |
| 1110 } | |
| 1111 if (optionCount >= maxSelectItems) | |
| 1112 break; | |
| 1113 } | |
| 1114 lazyReattachIfAttached(); | |
|
esprehn
2014/06/23 21:59:56
If you're going to reattach anyway, then there's n
| |
| 1061 } | 1115 } |
| 1062 | 1116 |
| 1063 bool HTMLSelectElement::appendFormData(FormDataList& list, bool) | 1117 bool HTMLSelectElement::appendFormData(FormDataList& list, bool) |
| 1064 { | 1118 { |
| 1065 const AtomicString& name = this->name(); | 1119 const AtomicString& name = this->name(); |
| 1066 if (name.isEmpty()) | 1120 if (name.isEmpty()) |
| 1067 return false; | 1121 return false; |
| 1068 | 1122 |
| 1069 bool successful = false; | 1123 bool successful = false; |
| 1070 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); | 1124 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1328 // we're doing a single selection, or a multiple selection (using cmd or | 1382 // we're doing a single selection, or a multiple selection (using cmd or |
| 1329 // ctrl), then initialize the anchor index to the listIndex that just got | 1383 // ctrl), then initialize the anchor index to the listIndex that just got |
| 1330 // clicked. | 1384 // clicked. |
| 1331 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect) | 1385 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect) |
| 1332 setActiveSelectionAnchorIndex(listIndex); | 1386 setActiveSelectionAnchorIndex(listIndex); |
| 1333 | 1387 |
| 1334 setActiveSelectionEndIndex(listIndex); | 1388 setActiveSelectionEndIndex(listIndex); |
| 1335 updateListBoxSelection(!multiSelect); | 1389 updateListBoxSelection(!multiSelect); |
| 1336 } | 1390 } |
| 1337 | 1391 |
| 1392 int HTMLSelectElement::listIndexForMouseEvent(const MouseEvent& event) | |
| 1393 { | |
| 1394 Node* targetNode = event.target()->toNode(); | |
| 1395 if (targetNode != this) | |
| 1396 return listIndexForEvent(event); | |
| 1397 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | H itTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowCont ent); | |
|
esprehn
2014/06/23 21:59:56
Why are you using HitTestRequest::ConfusingAndOfte
keishi
2014/07/01 04:53:33
I was able to remove this hit test.
| |
| 1398 HitTestResult result(event.absoluteLocation()); | |
| 1399 document().renderView()->hitTest(request, result); | |
|
esprehn
2014/06/23 21:59:56
What makes sure the layout/style is updated before
| |
| 1400 Node* hitNode = result.targetNode(); | |
| 1401 if (!hitNode) | |
| 1402 return -1; | |
| 1403 return listIndexForNode(*hitNode); | |
| 1404 } | |
| 1405 | |
| 1406 int HTMLSelectElement::listIndexForEvent(const Event& event) | |
| 1407 { | |
| 1408 Node* targetNode = event.target()->toNode(); | |
| 1409 if (!targetNode) | |
| 1410 return -1; | |
| 1411 return listIndexForNode(*targetNode); | |
| 1412 } | |
| 1413 | |
| 1414 int HTMLSelectElement::listIndexForNode(const Node& targetNode) | |
|
esprehn
2014/06/23 21:59:56
Can you scope this to a more specific type?
keishi
2014/07/01 04:53:33
Done.
| |
| 1415 { | |
| 1416 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = this->list Items(); | |
| 1417 for (const Node* node = &targetNode; node; node = node->parentOrShadowHostNo de()) { | |
|
esprehn
2014/06/23 21:59:56
This walks all the way up to root of the document,
| |
| 1418 if (node->isElementNode() && (toElement(node)->hasTagName(optionTag) || toElement(node)->hasTagName(optgroupTag))) { | |
| 1419 size_t length = items.size(); | |
| 1420 for (size_t i = 0; i < length; ++i) { | |
| 1421 if (items[i] == node) { | |
| 1422 return i; | |
| 1423 } | |
| 1424 } | |
| 1425 } | |
| 1426 } | |
| 1427 return -1; | |
| 1428 } | |
| 1429 | |
| 1430 AutoscrollController* HTMLSelectElement::autoscrollController() const | |
| 1431 { | |
| 1432 if (Page* page = document().page()) | |
| 1433 return &page->autoscrollController(); | |
| 1434 return 0; | |
| 1435 } | |
| 1436 | |
| 1338 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) | 1437 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) |
| 1339 { | 1438 { |
| 1340 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems(); | 1439 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems(); |
| 1341 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent()) { | 1440 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent()) { |
| 1342 focus(); | 1441 focus(); |
| 1343 // Calling focus() may cause us to lose our renderer or change the rende r type, in which case do not want to handle the event. | 1442 // Calling focus() may cause us to lose our renderer or change the rende r type, in which case do not want to handle the event. |
| 1344 if (!renderer() || !renderer()->isListBox()) | 1443 if (!renderer() || !renderer()->isListBox()) |
| 1345 return; | 1444 return; |
| 1346 | 1445 |
| 1347 // Convert to coords relative to the list box if needed. | 1446 // Convert to coords relative to the list box if needed. |
| 1348 GestureEvent& gestureEvent = toGestureEvent(*event); | 1447 GestureEvent& gestureEvent = toGestureEvent(*event); |
| 1349 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(gestu reEvent.absoluteLocation(), UseTransforms)); | 1448 int listIndex = listIndexForEvent(gestureEvent); |
| 1350 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset)); | |
| 1351 if (listIndex >= 0) { | 1449 if (listIndex >= 0) { |
| 1352 if (!isDisabledFormControl()) | 1450 if (!isDisabledFormControl()) |
| 1353 updateSelectedState(listIndex, true, gestureEvent.shiftKey()); | 1451 updateSelectedState(listIndex, true, gestureEvent.shiftKey()); |
| 1354 event->setDefaultHandled(); | 1452 event->setDefaultHandled(); |
| 1355 } | 1453 } |
| 1356 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent () && toMouseEvent(event)->button() == LeftButton) { | 1454 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent () && toMouseEvent(event)->button() == LeftButton) { |
| 1357 focus(); | 1455 focus(); |
| 1358 // Calling focus() may cause us to lose our renderer, in which case do n ot want to handle the event. | 1456 // Calling focus() may cause us to lose our renderer, in which case do n ot want to handle the event. |
| 1359 if (!renderer() || !renderer()->isListBox() || isDisabledFormControl()) | 1457 if (!renderer() || !renderer()->isListBox() || isDisabledFormControl()) |
| 1360 return; | 1458 return; |
| 1361 | 1459 |
| 1460 if (Page* page = document().page()) | |
| 1461 page->autoscrollController().startAutoscrollForSelection(renderer()) ; | |
| 1462 | |
| 1463 if (LocalFrame* frame = document().frame()) { | |
| 1464 frame->eventHandler().setCapturingMouseEventsNode(this); | |
| 1465 m_capturing = true; | |
| 1466 } | |
| 1467 | |
| 1362 // Convert to coords relative to the list box if needed. | 1468 // Convert to coords relative to the list box if needed. |
| 1363 MouseEvent* mouseEvent = toMouseEvent(event); | 1469 MouseEvent* mouseEvent = toMouseEvent(event); |
| 1364 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse Event->absoluteLocation(), UseTransforms)); | 1470 int listIndex = listIndexForMouseEvent(*mouseEvent); |
| 1365 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset)); | |
| 1366 if (listIndex >= 0) { | 1471 if (listIndex >= 0) { |
| 1367 if (!isDisabledFormControl()) { | 1472 if (!isDisabledFormControl()) { |
| 1368 #if OS(MACOSX) | 1473 #if OS(MACOSX) |
| 1369 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent ->shiftKey()); | 1474 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent ->shiftKey()); |
| 1370 #else | 1475 #else |
| 1371 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent ->shiftKey()); | 1476 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent ->shiftKey()); |
| 1372 #endif | 1477 #endif |
| 1373 } | 1478 } |
| 1374 if (LocalFrame* frame = document().frame()) | 1479 if (LocalFrame* frame = document().frame()) |
| 1375 frame->eventHandler().setMouseDownMayStartAutoscroll(); | 1480 frame->eventHandler().setMouseDownMayStartAutoscroll(); |
| 1376 | 1481 |
| 1377 event->setDefaultHandled(); | 1482 event->setDefaultHandled(); |
| 1378 } | 1483 } |
| 1379 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent () && !toRenderBox(renderer())->canBeScrolledAndHasScrollableArea()) { | 1484 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent ()) { |
| 1380 MouseEvent* mouseEvent = toMouseEvent(event); | 1485 MouseEvent* mouseEvent = toMouseEvent(event); |
| 1381 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown()) | 1486 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown()) |
| 1382 return; | 1487 return; |
| 1383 | 1488 int listIndex = listIndexForMouseEvent(*mouseEvent); |
| 1384 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse Event->absoluteLocation(), UseTransforms)); | |
| 1385 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset)); | |
| 1386 if (listIndex >= 0) { | 1489 if (listIndex >= 0) { |
| 1387 if (!isDisabledFormControl()) { | 1490 if (!isDisabledFormControl()) { |
| 1388 if (m_multiple) { | 1491 if (m_multiple) { |
| 1389 // Only extend selection if there is something selected. | 1492 // Only extend selection if there is something selected. |
| 1390 if (m_activeSelectionAnchorIndex < 0) | 1493 if (m_activeSelectionAnchorIndex < 0) |
| 1391 return; | 1494 return; |
| 1392 | 1495 |
| 1393 setActiveSelectionEndIndex(listIndex); | 1496 setActiveSelectionEndIndex(listIndex); |
| 1394 updateListBoxSelection(false); | 1497 updateListBoxSelection(false); |
| 1395 } else { | 1498 } else { |
| 1396 setActiveSelectionAnchorIndex(listIndex); | 1499 setActiveSelectionAnchorIndex(listIndex); |
| 1397 setActiveSelectionEndIndex(listIndex); | 1500 setActiveSelectionEndIndex(listIndex); |
| 1398 updateListBoxSelection(true); | 1501 updateListBoxSelection(true); |
| 1399 } | 1502 } |
| 1400 } | 1503 } |
| 1401 } | 1504 } |
| 1402 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton && renderer() && !toRenderBox(re nderer())->autoscrollInProgress()) { | 1505 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton && renderer()) { |
| 1506 LocalFrame* frame = document().frame(); | |
| 1507 if (m_capturing && frame) { | |
| 1508 frame->eventHandler().setCapturingMouseEventsNode(nullptr); | |
| 1509 m_capturing = false; | |
| 1510 } | |
| 1403 // We didn't start this click/drag on any options. | 1511 // We didn't start this click/drag on any options. |
| 1404 if (m_lastOnChangeSelection.isEmpty()) | 1512 if (m_lastOnChangeSelection.isEmpty()) |
| 1405 return; | 1513 return; |
| 1406 listBoxOnChange(); | 1514 listBoxOnChange(); |
| 1407 } else if (event->type() == EventTypeNames::keydown) { | 1515 } else if (event->type() == EventTypeNames::keydown) { |
| 1408 if (!event->isKeyboardEvent()) | 1516 if (!event->isKeyboardEvent()) |
| 1409 return; | 1517 return; |
| 1410 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier(); | 1518 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier(); |
| 1411 | 1519 |
| 1412 bool handled = false; | 1520 bool handled = false; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1471 m_activeSelectionState = true; | 1579 m_activeSelectionState = true; |
| 1472 // If the anchor is unitialized, or if we're going to deselect all | 1580 // If the anchor is unitialized, or if we're going to deselect all |
| 1473 // other options, then set the anchor index equal to the end index. | 1581 // other options, then set the anchor index equal to the end index. |
| 1474 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift Key() && selectNewItem); | 1582 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift Key() && selectNewItem); |
| 1475 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { | 1583 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { |
| 1476 if (deselectOthers) | 1584 if (deselectOthers) |
| 1477 deselectItemsWithoutValidation(); | 1585 deselectItemsWithoutValidation(); |
| 1478 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); | 1586 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); |
| 1479 } | 1587 } |
| 1480 | 1588 |
| 1481 toRenderListBox(renderer())->scrollToRevealElementAtListIndex(endInd ex); | 1589 scrollTo(endIndex); |
| 1482 if (selectNewItem) { | 1590 if (selectNewItem) { |
| 1483 updateListBoxSelection(deselectOthers); | 1591 updateListBoxSelection(deselectOthers); |
| 1484 listBoxOnChange(); | 1592 listBoxOnChange(); |
| 1485 } else | 1593 } else |
| 1486 scrollToSelection(); | 1594 scrollToSelection(); |
| 1487 | 1595 |
| 1488 event->setDefaultHandled(); | 1596 event->setDefaultHandled(); |
| 1489 } | 1597 } |
| 1490 } else if (event->type() == EventTypeNames::keypress) { | 1598 } else if (event->type() == EventTypeNames::keypress) { |
| 1491 if (!event->isKeyboardEvent()) | 1599 if (!event->isKeyboardEvent()) |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1622 ++options; | 1730 ++options; |
| 1623 } | 1731 } |
| 1624 | 1732 |
| 1625 return options; | 1733 return options; |
| 1626 } | 1734 } |
| 1627 | 1735 |
| 1628 void HTMLSelectElement::finishParsingChildren() | 1736 void HTMLSelectElement::finishParsingChildren() |
| 1629 { | 1737 { |
| 1630 HTMLFormControlElementWithState::finishParsingChildren(); | 1738 HTMLFormControlElementWithState::finishParsingChildren(); |
| 1631 updateListItemSelectedStates(); | 1739 updateListItemSelectedStates(); |
| 1740 scrollToSelection(); | |
| 1632 } | 1741 } |
| 1633 | 1742 |
| 1634 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR awPtr<HTMLOptionElement> value, ExceptionState& exceptionState) | 1743 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR awPtr<HTMLOptionElement> value, ExceptionState& exceptionState) |
| 1635 { | 1744 { |
| 1636 if (!value) { // undefined or null | 1745 if (!value) { // undefined or null |
| 1637 remove(index); | 1746 remove(index); |
| 1638 return true; | 1747 return true; |
| 1639 } | 1748 } |
| 1640 setOption(index, value.get(), exceptionState); | 1749 setOption(index, value.get(), exceptionState); |
| 1641 return true; | 1750 return true; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1657 } | 1766 } |
| 1658 | 1767 |
| 1659 void HTMLSelectElement::trace(Visitor* visitor) | 1768 void HTMLSelectElement::trace(Visitor* visitor) |
| 1660 { | 1769 { |
| 1661 #if ENABLE(OILPAN) | 1770 #if ENABLE(OILPAN) |
| 1662 visitor->trace(m_listItems); | 1771 visitor->trace(m_listItems); |
| 1663 #endif | 1772 #endif |
| 1664 HTMLFormControlElementWithState::trace(visitor); | 1773 HTMLFormControlElementWithState::trace(visitor); |
| 1665 } | 1774 } |
| 1666 | 1775 |
| 1776 void HTMLSelectElement::didAddUserAgentShadowRoot(ShadowRoot& root) | |
| 1777 { | |
| 1778 RefPtrWillBeRawPtr<HTMLContentElement> content = HTMLContentElement::create( document()); | |
| 1779 content->setAttribute(selectAttr, "option,optgroup"); | |
| 1780 root.appendChild(content); | |
| 1781 } | |
| 1782 | |
| 1667 } // namespace | 1783 } // namespace |
| OLD | NEW |