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

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

Issue 347773002: Implement select listbox using shadow DOM (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Fixed Created 6 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 | Annotate | Revision Log
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 21 matching lines...) Expand all
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.
(...skipping 11 matching lines...) Expand all
73 , m_activeSelectionState(false) 80 , m_activeSelectionState(false)
74 , m_shouldRecalcListItems(false) 81 , m_shouldRecalcListItems(false)
75 , m_suggestedIndex(-1) 82 , m_suggestedIndex(-1)
76 { 83 {
77 ScriptWrappable::init(this); 84 ScriptWrappable::init(this);
78 setHasCustomStyleCallbacks(); 85 setHasCustomStyleCallbacks();
79 } 86 }
80 87
81 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do cument) 88 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do cument)
82 { 89 {
83 return adoptRefWillBeNoop(new HTMLSelectElement(document, 0)); 90 RefPtrWillBeRawPtr<HTMLSelectElement> select = adoptRefWillBeNoop(new HTMLSe lectElement(document, 0));
91 select->ensureUserAgentShadowRoot();
92 return select.release();
84 } 93 }
85 94
86 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do cument, HTMLFormElement* form) 95 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do cument, HTMLFormElement* form)
87 { 96 {
88 return adoptRefWillBeNoop(new HTMLSelectElement(document, form)); 97 RefPtrWillBeRawPtr<HTMLSelectElement> select = adoptRefWillBeNoop(new HTMLSe lectElement(document, form));
98 select->ensureUserAgentShadowRoot();
99 return select.release();
89 } 100 }
90 101
91 const AtomicString& HTMLSelectElement::formControlType() const 102 const AtomicString& HTMLSelectElement::formControlType() const
92 { 103 {
93 DEFINE_STATIC_LOCAL(const AtomicString, selectMultiple, ("select-multiple", AtomicString::ConstructFromLiteral)); 104 DEFINE_STATIC_LOCAL(const AtomicString, selectMultiple, ("select-multiple", AtomicString::ConstructFromLiteral));
94 DEFINE_STATIC_LOCAL(const AtomicString, selectOne, ("select-one", AtomicStri ng::ConstructFromLiteral)); 105 DEFINE_STATIC_LOCAL(const AtomicString, selectOne, ("select-one", AtomicStri ng::ConstructFromLiteral));
95 return m_multiple ? selectMultiple : selectOne; 106 return m_multiple ? selectMultiple : selectOne;
96 } 107 }
97 108
98 void HTMLSelectElement::optionSelectedByUser(int optionIndex, bool fireOnChangeN ow, bool allowMultipleSelection) 109 void HTMLSelectElement::optionSelectedByUser(int optionIndex, bool fireOnChangeN ow, bool allowMultipleSelection)
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 sizeAttribute->setValue(attrSize); 338 sizeAttribute->setValue(attrSize);
328 } 339 }
329 size = std::max(size, 1); 340 size = std::max(size, 1);
330 341
331 // Ensure that we've determined selectedness of the items at least once prior to changing the size. 342 // Ensure that we've determined selectedness of the items at least once prior to changing the size.
332 if (oldSize != size) 343 if (oldSize != size)
333 updateListItemSelectedStates(); 344 updateListItemSelectedStates();
334 345
335 m_size = size; 346 m_size = size;
336 setNeedsValidityCheck(); 347 setNeedsValidityCheck();
337 if (m_size != oldSize && inActiveDocument()) { 348 if (m_size != oldSize && document().isActive() && inDocument()) {
338 lazyReattachIfAttached(); 349 lazyReattachIfAttached();
339 setRecalcListItems(); 350 setRecalcListItems();
340 } 351 }
341 } else if (name == multipleAttr) 352 } else if (name == multipleAttr)
342 parseMultipleAttribute(value); 353 parseMultipleAttribute(value);
343 else if (name == accesskeyAttr) { 354 else if (name == accesskeyAttr) {
344 // FIXME: ignore for the moment. 355 // FIXME: ignore for the moment.
345 // 356 //
346 } else if (name == disabledAttr) { 357 } else if (name == disabledAttr) {
347 HTMLFormControlElementWithState::parseAttribute(name, value); 358 HTMLFormControlElementWithState::parseAttribute(name, value);
(...skipping 11 matching lines...) Expand all
359 bool HTMLSelectElement::shouldShowFocusRingOnMouseFocus() const 370 bool HTMLSelectElement::shouldShowFocusRingOnMouseFocus() const
360 { 371 {
361 return true; 372 return true;
362 } 373 }
363 374
364 bool HTMLSelectElement::canSelectAll() const 375 bool HTMLSelectElement::canSelectAll() const
365 { 376 {
366 return !usesMenuList(); 377 return !usesMenuList();
367 } 378 }
368 379
369 RenderObject* HTMLSelectElement::createRenderer(RenderStyle*) 380 RenderObject* HTMLSelectElement::createRenderer(RenderStyle* style)
370 { 381 {
371 if (usesMenuList()) 382 if (usesMenuList())
372 return new RenderMenuList(this); 383 return new RenderMenuList(this);
373 return new RenderListBox(this); 384 return new RenderListBox(this);
374 } 385 }
375 386
376 PassRefPtrWillBeRawPtr<HTMLCollection> HTMLSelectElement::selectedOptions() 387 PassRefPtrWillBeRawPtr<HTMLCollection> HTMLSelectElement::selectedOptions()
377 { 388 {
378 updateListItemSelectedStates(); 389 updateListItemSelectedStates();
379 return ensureCachedHTMLCollection(SelectedOptions); 390 return ensureCachedHTMLCollection(SelectedOptions);
380 } 391 }
381 392
382 PassRefPtrWillBeRawPtr<HTMLOptionsCollection> HTMLSelectElement::options() 393 PassRefPtrWillBeRawPtr<HTMLOptionsCollection> HTMLSelectElement::options()
383 { 394 {
384 return toHTMLOptionsCollection(ensureCachedHTMLCollection(SelectOptions).get ()); 395 return toHTMLOptionsCollection(ensureCachedHTMLCollection(SelectOptions).get ());
385 } 396 }
386 397
387 void HTMLSelectElement::updateListItemSelectedStates() 398 void HTMLSelectElement::updateListItemSelectedStates()
388 { 399 {
389 if (!m_shouldRecalcListItems) 400 if (!m_shouldRecalcListItems)
390 return; 401 return;
391 recalcListItems(); 402 recalcListItems();
392 setNeedsValidityCheck(); 403 setNeedsValidityCheck();
393 } 404 }
394 405
395 void HTMLSelectElement::childrenChanged(bool changedByParser, Node* beforeChange , Node* afterChange, int childCountDelta) 406 void HTMLSelectElement::childrenChanged(bool changedByParser, Node* beforeChange , Node* afterChange, int childCountDelta)
396 { 407 {
397 setRecalcListItems(); 408 setRecalcListItems();
398 setNeedsValidityCheck(); 409 setNeedsValidityCheck();
399 m_lastOnChangeSelection.clear();
400 410
401 HTMLFormControlElementWithState::childrenChanged(changedByParser, beforeChan ge, afterChange, childCountDelta); 411 HTMLFormControlElementWithState::childrenChanged(changedByParser, beforeChan ge, afterChange, childCountDelta);
402 } 412 }
403 413
404 void HTMLSelectElement::optionElementChildrenChanged() 414 void HTMLSelectElement::optionElementChildrenChanged()
405 { 415 {
406 setRecalcListItems(); 416 setRecalcListItems();
407 setNeedsValidityCheck(); 417 setNeedsValidityCheck();
408 418
409 if (renderer()) { 419 if (renderer()) {
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 // Valid means that it is enabled and an option element. 526 // Valid means that it is enabled and an option element.
517 int HTMLSelectElement::nextValidIndex(int listIndex, SkipDirection direction, in t skip) const 527 int HTMLSelectElement::nextValidIndex(int listIndex, SkipDirection direction, in t skip) const
518 { 528 {
519 ASSERT(direction == -1 || direction == 1); 529 ASSERT(direction == -1 || direction == 1);
520 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems(); 530 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems();
521 int lastGoodIndex = listIndex; 531 int lastGoodIndex = listIndex;
522 int size = listItems.size(); 532 int size = listItems.size();
523 for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex + = direction) { 533 for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex + = direction) {
524 --skip; 534 --skip;
525 HTMLElement* element = listItems[listIndex]; 535 HTMLElement* element = listItems[listIndex];
526 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDi sabledFormControl() || toHTMLOptionElement(element)->isDisplayNone()) 536 if (isHTMLOptionElement(*element)) {
537 const HTMLOptionElement& option = toHTMLOptionElement(*element);
538 if (option.isDisabledFormControl())
539 continue;
540 if (!usesMenuList() && !option.renderer())
keishi 2014/07/01 05:06:35 I was able to get rid of isDisplayNone
541 continue;
542 } else {
527 continue; 543 continue;
544 }
528 lastGoodIndex = listIndex; 545 lastGoodIndex = listIndex;
529 if (skip <= 0) 546 if (skip <= 0)
530 break; 547 break;
531 } 548 }
532 return lastGoodIndex; 549 return lastGoodIndex;
533 } 550 }
534 551
535 int HTMLSelectElement::nextSelectableListIndex(int startIndex) const 552 int HTMLSelectElement::nextSelectableListIndex(int startIndex) const
536 { 553 {
537 return nextValidIndex(startIndex, SkipForwards, 1); 554 return nextValidIndex(startIndex, SkipForwards, 1);
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
633 { 650 {
634 ASSERT(renderer() && (renderer()->isListBox() || m_multiple)); 651 ASSERT(renderer() && (renderer()->isListBox() || m_multiple));
635 ASSERT(!listItems().size() || m_activeSelectionAnchorIndex >= 0); 652 ASSERT(!listItems().size() || m_activeSelectionAnchorIndex >= 0);
636 653
637 unsigned start = std::min(m_activeSelectionAnchorIndex, m_activeSelectionEnd Index); 654 unsigned start = std::min(m_activeSelectionAnchorIndex, m_activeSelectionEnd Index);
638 unsigned end = std::max(m_activeSelectionAnchorIndex, m_activeSelectionEndIn dex); 655 unsigned end = std::max(m_activeSelectionAnchorIndex, m_activeSelectionEndIn dex);
639 656
640 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 657 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
641 for (unsigned i = 0; i < items.size(); ++i) { 658 for (unsigned i = 0; i < items.size(); ++i) {
642 HTMLElement* element = items[i]; 659 HTMLElement* element = items[i];
643 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDi sabledFormControl() || toHTMLOptionElement(element)->isDisplayNone()) 660 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDi sabledFormControl() || !toHTMLOptionElement(element)->renderer())
644 continue; 661 continue;
645 662
646 if (i >= start && i <= end) 663 if (i >= start && i <= end)
647 toHTMLOptionElement(element)->setSelectedState(m_activeSelectionStat e); 664 toHTMLOptionElement(element)->setSelectedState(m_activeSelectionStat e);
648 else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.si ze()) 665 else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.si ze())
649 toHTMLOptionElement(element)->setSelectedState(false); 666 toHTMLOptionElement(element)->setSelectedState(false);
650 else 667 else
651 toHTMLOptionElement(element)->setSelectedState(m_cachedStateForActiv eSelection[i]); 668 toHTMLOptionElement(element)->setSelectedState(m_cachedStateForActiv eSelection[i]);
652 } 669 }
653 670
654 scrollToSelection(); 671 scrollToSelection();
655 setNeedsValidityCheck(); 672 setNeedsValidityCheck();
656 notifyFormStateChanged(); 673 notifyFormStateChanged();
657 } 674 }
658 675
659 void HTMLSelectElement::listBoxOnChange() 676 void HTMLSelectElement::listBoxOnChange()
660 { 677 {
661 ASSERT(!usesMenuList() || m_multiple); 678 ASSERT(!usesMenuList() || m_multiple);
662 679
663 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 680 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
664 681
665 // If the cached selection list is empty, or the size has changed, then fire
666 // dispatchFormControlChangeEvent, and return early.
667 // FIXME: Why? This looks unreasonable.
668 if (m_lastOnChangeSelection.isEmpty() || m_lastOnChangeSelection.size() != i tems.size()) {
669 dispatchFormControlChangeEvent();
670 return;
671 }
672
673 // Update m_lastOnChangeSelection and fire dispatchFormControlChangeEvent. 682 // Update m_lastOnChangeSelection and fire dispatchFormControlChangeEvent.
674 bool fireOnChange = false; 683 bool fireOnChange = false;
675 for (unsigned i = 0; i < items.size(); ++i) { 684 for (unsigned i = 0; i < items.size(); ++i) {
676 HTMLElement* element = items[i]; 685 HTMLElement* element = items[i];
677 bool selected = isHTMLOptionElement(*element) && toHTMLOptionElement(ele ment)->selected(); 686 bool selected = isHTMLOptionElement(*element) && toHTMLOptionElement(ele ment)->selected();
678 if (selected != m_lastOnChangeSelection[i]) 687 if (i < m_lastOnChangeSelection.size()) {
688 if (selected != m_lastOnChangeSelection[i]) {
689 fireOnChange = true;
690 break;
691 }
692 } else if (selected) {
679 fireOnChange = true; 693 fireOnChange = true;
680 m_lastOnChangeSelection[i] = selected; 694 break;
695 }
681 } 696 }
682 697
683 if (fireOnChange) { 698 if (fireOnChange) {
699 saveLastSelection();
684 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this); 700 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this);
685 dispatchInputEvent(); 701 dispatchInputEvent();
686 dispatchFormControlChangeEvent(); 702 dispatchFormControlChangeEvent();
687 } 703 }
688 } 704 }
689 705
690 void HTMLSelectElement::dispatchInputAndChangeEventForMenuList(bool requiresUser Gesture) 706 void HTMLSelectElement::dispatchInputAndChangeEventForMenuList(bool requiresUser Gesture)
691 { 707 {
692 ASSERT(usesMenuList()); 708 ASSERT(usesMenuList());
693 709
694 int selected = selectedIndex(); 710 int selected = selectedIndex();
695 if (m_lastOnChangeIndex != selected && (!requiresUserGesture || m_isProcessi ngUserDrivenChange)) { 711 if (m_lastOnChangeIndex != selected && (!requiresUserGesture || m_isProcessi ngUserDrivenChange)) {
696 m_lastOnChangeIndex = selected; 712 m_lastOnChangeIndex = selected;
697 m_isProcessingUserDrivenChange = false; 713 m_isProcessingUserDrivenChange = false;
698 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this); 714 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this);
699 dispatchInputEvent(); 715 dispatchInputEvent();
700 dispatchFormControlChangeEvent(); 716 dispatchFormControlChangeEvent();
701 } 717 }
702 } 718 }
703 719
704 void HTMLSelectElement::scrollToSelection() 720 void HTMLSelectElement::scrollToSelection()
705 { 721 {
722 if (!isFinishedParsingChildren())
723 return;
706 if (usesMenuList()) 724 if (usesMenuList())
707 return; 725 return;
708 726 scrollTo(activeSelectionEndListIndex());
709 if (RenderObject* renderer = this->renderer()) 727 if (AXObjectCache* cache = document().existingAXObjectCache())
710 toRenderListBox(renderer)->selectionChanged(); 728 cache->selectedChildrenChanged(this);
711 } 729 }
712 730
713 void HTMLSelectElement::setOptionsChangedOnRenderer() 731 void HTMLSelectElement::setOptionsChangedOnRenderer()
714 { 732 {
715 if (RenderObject* renderer = this->renderer()) { 733 if (RenderObject* renderer = this->renderer()) {
716 if (usesMenuList()) 734 if (usesMenuList())
717 toRenderMenuList(renderer)->setOptionsChanged(true); 735 toRenderMenuList(renderer)->setOptionsChanged(true);
718 else
719 toRenderListBox(renderer)->setOptionsChanged(true);
720 } 736 }
721 } 737 }
722 738
723 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& HTMLSelectElement::lis tItems() const 739 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& HTMLSelectElement::lis tItems() const
724 { 740 {
725 if (m_shouldRecalcListItems) 741 if (m_shouldRecalcListItems)
726 recalcListItems(); 742 recalcListItems();
727 else { 743 else {
728 #if ASSERT_ENABLED 744 #if ASSERT_ENABLED
729 WillBeHeapVector<RawPtrWillBeMember<HTMLElement> > items = m_listItems; 745 WillBeHeapVector<RawPtrWillBeMember<HTMLElement> > items = m_listItems;
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 { 867 {
852 return m_suggestedIndex; 868 return m_suggestedIndex;
853 } 869 }
854 870
855 void HTMLSelectElement::setSuggestedIndex(int suggestedIndex) 871 void HTMLSelectElement::setSuggestedIndex(int suggestedIndex)
856 { 872 {
857 m_suggestedIndex = suggestedIndex; 873 m_suggestedIndex = suggestedIndex;
858 874
859 if (RenderObject* renderer = this->renderer()) { 875 if (RenderObject* renderer = this->renderer()) {
860 renderer->updateFromElement(); 876 renderer->updateFromElement();
861 if (renderer->isListBox()) 877 scrollTo(suggestedIndex);
862 toRenderListBox(renderer)->scrollToRevealElementAtListIndex(suggeste dIndex);
863 } 878 }
864 } 879 }
865 880
881 void HTMLSelectElement::scrollTo(int listIndex)
882 {
883 if (listIndex < 0)
884 return;
885 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
886 int listSize = static_cast<int>(items.size());
887 if (listIndex >= listSize)
888 return;
889 items[listIndex]->scrollIntoViewIfNeeded(false);
890 }
891
866 void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, b ool optionIsSelected) 892 void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, b ool optionIsSelected)
867 { 893 {
868 ASSERT(option->ownerSelectElement() == this); 894 ASSERT(option->ownerSelectElement() == this);
869 if (optionIsSelected) 895 if (optionIsSelected)
870 selectOption(option->index()); 896 selectOption(option->index());
871 else if (!usesMenuList() || multiple()) 897 else if (!usesMenuList() || multiple())
872 selectOption(-1); 898 selectOption(-1);
873 else 899 else
874 selectOption(nextSelectableListIndex(-1)); 900 selectOption(nextSelectableListIndex(-1));
875 } 901 }
876 902
903 void HTMLSelectElement::optionRemoved(HTMLOptionElement* option)
904 {
905 if (m_activeSelectionAnchorIndex < 0 && m_activeSelectionEndIndex < 0)
906 return;
907 int listIndex = optionToListIndex(option->index());
908 if (listIndex <= m_activeSelectionAnchorIndex)
909 m_activeSelectionAnchorIndex--;
910 if (listIndex <= m_activeSelectionEndIndex)
911 m_activeSelectionEndIndex--;
912 }
913
877 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags) 914 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags)
878 { 915 {
879 bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions); 916 bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions);
880 917
881 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 918 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
882 int listIndex = optionToListIndex(optionIndex); 919 int listIndex = optionToListIndex(optionIndex);
883 920
884 HTMLElement* element = 0; 921 HTMLElement* element = 0;
885 if (listIndex >= 0) { 922 if (listIndex >= 0) {
886 element = items[listIndex]; 923 element = items[listIndex];
(...skipping 15 matching lines...) Expand all
902 939
903 scrollToSelection(); 940 scrollToSelection();
904 941
905 setNeedsValidityCheck(); 942 setNeedsValidityCheck();
906 943
907 if (usesMenuList()) { 944 if (usesMenuList()) {
908 m_isProcessingUserDrivenChange = flags & UserDriven; 945 m_isProcessingUserDrivenChange = flags & UserDriven;
909 if (flags & DispatchInputAndChangeEvent) 946 if (flags & DispatchInputAndChangeEvent)
910 dispatchInputAndChangeEventForMenuList(); 947 dispatchInputAndChangeEventForMenuList();
911 if (RenderObject* renderer = this->renderer()) { 948 if (RenderObject* renderer = this->renderer()) {
912 if (usesMenuList()) 949 if (usesMenuList()) {
913 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex); 950 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex);
914 else if (renderer->isListBox()) 951 } else if (renderer->isListBox()) {
915 toRenderListBox(renderer)->selectionChanged(); 952 if (AXObjectCache* cache = document().existingAXObjectCache())
953 cache->selectedChildrenChanged(this);
954 }
916 } 955 }
917 } 956 }
918 957
919 notifyFormStateChanged(); 958 notifyFormStateChanged();
920 } 959 }
921 960
922 int HTMLSelectElement::optionToListIndex(int optionIndex) const 961 int HTMLSelectElement::optionToListIndex(int optionIndex) const
923 { 962 {
924 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 963 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
925 int listSize = static_cast<int>(items.size()); 964 int listSize = static_cast<int>(items.size());
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1046 startIndex = foundIndex + 1; 1085 startIndex = foundIndex + 1;
1047 } 1086 }
1048 } 1087 }
1049 1088
1050 setOptionsChangedOnRenderer(); 1089 setOptionsChangedOnRenderer();
1051 setNeedsValidityCheck(); 1090 setNeedsValidityCheck();
1052 } 1091 }
1053 1092
1054 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value) 1093 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value)
1055 { 1094 {
1056 bool oldUsesMenuList = usesMenuList();
1057 m_multiple = !value.isNull(); 1095 m_multiple = !value.isNull();
1058 setNeedsValidityCheck(); 1096 setNeedsValidityCheck();
1059 if (oldUsesMenuList != usesMenuList()) 1097
1060 lazyReattachIfAttached(); 1098 lazyReattachIfAttached();
1061 } 1099 }
1062 1100
1063 bool HTMLSelectElement::appendFormData(FormDataList& list, bool) 1101 bool HTMLSelectElement::appendFormData(FormDataList& list, bool)
1064 { 1102 {
1065 const AtomicString& name = this->name(); 1103 const AtomicString& name = this->name();
1066 if (name.isEmpty()) 1104 if (name.isEmpty())
1067 return false; 1105 return false;
1068 1106
1069 bool successful = false; 1107 bool successful = false;
1070 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 1108 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
1328 // we're doing a single selection, or a multiple selection (using cmd or 1366 // 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 1367 // ctrl), then initialize the anchor index to the listIndex that just got
1330 // clicked. 1368 // clicked.
1331 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect) 1369 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect)
1332 setActiveSelectionAnchorIndex(listIndex); 1370 setActiveSelectionAnchorIndex(listIndex);
1333 1371
1334 setActiveSelectionEndIndex(listIndex); 1372 setActiveSelectionEndIndex(listIndex);
1335 updateListBoxSelection(!multiSelect); 1373 updateListBoxSelection(!multiSelect);
1336 } 1374 }
1337 1375
1376 int HTMLSelectElement::listIndexForEventTargetOption(const Event& event)
1377 {
1378 Node* targetNode = event.target()->toNode();
1379 if (!targetNode || !isHTMLOptionElement(*targetNode))
1380 return -1;
1381 return listIndexForOption(toHTMLOptionElement(*targetNode));
1382 }
1383
1384 int HTMLSelectElement::listIndexForOption(const HTMLOptionElement& option)
1385 {
1386 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = this->list Items();
1387 size_t length = items.size();
1388 for (size_t i = 0; i < length; ++i) {
1389 if (items[i] == &option)
1390 return i;
1391 }
1392 return -1;
1393 }
1394
1395 AutoscrollController* HTMLSelectElement::autoscrollController() const
1396 {
1397 if (Page* page = document().page())
1398 return &page->autoscrollController();
1399 return 0;
1400 }
1401
1338 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) 1402 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event)
1339 { 1403 {
1340 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems(); 1404 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems();
1341 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent()) { 1405 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent()) {
1342 focus(); 1406 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. 1407 // 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()) 1408 if (!renderer() || !renderer()->isListBox())
1345 return; 1409 return;
1346 1410
1347 // Convert to coords relative to the list box if needed. 1411 // Convert to coords relative to the list box if needed.
1348 GestureEvent& gestureEvent = toGestureEvent(*event); 1412 GestureEvent& gestureEvent = toGestureEvent(*event);
1349 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(gestu reEvent.absoluteLocation(), UseTransforms)); 1413 int listIndex = listIndexForEventTargetOption(gestureEvent);
1350 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset));
1351 if (listIndex >= 0) { 1414 if (listIndex >= 0) {
1352 if (!isDisabledFormControl()) 1415 if (!isDisabledFormControl())
1353 updateSelectedState(listIndex, true, gestureEvent.shiftKey()); 1416 updateSelectedState(listIndex, true, gestureEvent.shiftKey());
1354 event->setDefaultHandled(); 1417 event->setDefaultHandled();
1355 } 1418 }
1356 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent () && toMouseEvent(event)->button() == LeftButton) { 1419 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent () && toMouseEvent(event)->button() == LeftButton) {
1357 focus(); 1420 focus();
1358 // Calling focus() may cause us to lose our renderer, in which case do n ot want to handle the event. 1421 // 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()) 1422 if (!renderer() || !renderer()->isListBox() || isDisabledFormControl())
1360 return; 1423 return;
1361 1424
1425 if (Page* page = document().page())
1426 page->autoscrollController().startAutoscrollForSelection(renderer()) ;
1427
1362 // Convert to coords relative to the list box if needed. 1428 // Convert to coords relative to the list box if needed.
1363 MouseEvent* mouseEvent = toMouseEvent(event); 1429 MouseEvent* mouseEvent = toMouseEvent(event);
1364 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse Event->absoluteLocation(), UseTransforms)); 1430 int listIndex = listIndexForEventTargetOption(*mouseEvent);
1365 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset));
1366 if (listIndex >= 0) { 1431 if (listIndex >= 0) {
1367 if (!isDisabledFormControl()) { 1432 if (!isDisabledFormControl()) {
1368 #if OS(MACOSX) 1433 #if OS(MACOSX)
1369 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent ->shiftKey()); 1434 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent ->shiftKey());
1370 #else 1435 #else
1371 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent ->shiftKey()); 1436 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent ->shiftKey());
1372 #endif 1437 #endif
1373 } 1438 }
1374 if (LocalFrame* frame = document().frame()) 1439 if (LocalFrame* frame = document().frame())
1375 frame->eventHandler().setMouseDownMayStartAutoscroll(); 1440 frame->eventHandler().setMouseDownMayStartAutoscroll();
1376 1441
1377 event->setDefaultHandled(); 1442 event->setDefaultHandled();
1378 } 1443 }
1379 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent () && !toRenderBox(renderer())->canBeScrolledAndHasScrollableArea()) { 1444 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent ()) {
1380 MouseEvent* mouseEvent = toMouseEvent(event); 1445 MouseEvent* mouseEvent = toMouseEvent(event);
1381 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown()) 1446 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown())
1382 return; 1447 return;
1383 1448 int listIndex = listIndexForEventTargetOption(*mouseEvent);
1384 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse Event->absoluteLocation(), UseTransforms));
1385 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset));
1386 if (listIndex >= 0) { 1449 if (listIndex >= 0) {
1387 if (!isDisabledFormControl()) { 1450 if (!isDisabledFormControl()) {
1388 if (m_multiple) { 1451 if (m_multiple) {
1389 // Only extend selection if there is something selected. 1452 // Only extend selection if there is something selected.
1390 if (m_activeSelectionAnchorIndex < 0) 1453 if (m_activeSelectionAnchorIndex < 0)
1391 return; 1454 return;
1392 1455
1393 setActiveSelectionEndIndex(listIndex); 1456 setActiveSelectionEndIndex(listIndex);
1394 updateListBoxSelection(false); 1457 updateListBoxSelection(false);
1395 } else { 1458 } else {
1396 setActiveSelectionAnchorIndex(listIndex); 1459 setActiveSelectionAnchorIndex(listIndex);
1397 setActiveSelectionEndIndex(listIndex); 1460 setActiveSelectionEndIndex(listIndex);
1398 updateListBoxSelection(true); 1461 updateListBoxSelection(true);
1399 } 1462 }
1400 } 1463 }
1401 } 1464 }
1402 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton && renderer() && !toRenderBox(re nderer())->autoscrollInProgress()) { 1465 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton && renderer()) {
1403 // We didn't start this click/drag on any options. 1466 // We didn't start this click/drag on any options.
1404 if (m_lastOnChangeSelection.isEmpty()) 1467 if (m_lastOnChangeSelection.isEmpty())
1405 return; 1468 return;
1406 listBoxOnChange(); 1469 listBoxOnChange();
1407 } else if (event->type() == EventTypeNames::keydown) { 1470 } else if (event->type() == EventTypeNames::keydown) {
1408 if (!event->isKeyboardEvent()) 1471 if (!event->isKeyboardEvent())
1409 return; 1472 return;
1410 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier(); 1473 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier();
1411 1474
1412 bool handled = false; 1475 bool handled = false;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1471 m_activeSelectionState = true; 1534 m_activeSelectionState = true;
1472 // If the anchor is unitialized, or if we're going to deselect all 1535 // 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. 1536 // other options, then set the anchor index equal to the end index.
1474 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift Key() && selectNewItem); 1537 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift Key() && selectNewItem);
1475 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { 1538 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) {
1476 if (deselectOthers) 1539 if (deselectOthers)
1477 deselectItemsWithoutValidation(); 1540 deselectItemsWithoutValidation();
1478 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); 1541 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex);
1479 } 1542 }
1480 1543
1481 toRenderListBox(renderer())->scrollToRevealElementAtListIndex(endInd ex); 1544 scrollTo(endIndex);
1482 if (selectNewItem) { 1545 if (selectNewItem) {
1483 updateListBoxSelection(deselectOthers); 1546 updateListBoxSelection(deselectOthers);
1484 listBoxOnChange(); 1547 listBoxOnChange();
1485 } else 1548 } else
1486 scrollToSelection(); 1549 scrollToSelection();
1487 1550
1488 event->setDefaultHandled(); 1551 event->setDefaultHandled();
1489 } 1552 }
1490 } else if (event->type() == EventTypeNames::keypress) { 1553 } else if (event->type() == EventTypeNames::keypress) {
1491 if (!event->isKeyboardEvent()) 1554 if (!event->isKeyboardEvent())
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1622 ++options; 1685 ++options;
1623 } 1686 }
1624 1687
1625 return options; 1688 return options;
1626 } 1689 }
1627 1690
1628 void HTMLSelectElement::finishParsingChildren() 1691 void HTMLSelectElement::finishParsingChildren()
1629 { 1692 {
1630 HTMLFormControlElementWithState::finishParsingChildren(); 1693 HTMLFormControlElementWithState::finishParsingChildren();
1631 updateListItemSelectedStates(); 1694 updateListItemSelectedStates();
1695 scrollToSelection();
1632 } 1696 }
1633 1697
1634 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR awPtr<HTMLOptionElement> value, ExceptionState& exceptionState) 1698 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR awPtr<HTMLOptionElement> value, ExceptionState& exceptionState)
1635 { 1699 {
1636 if (!value) { // undefined or null 1700 if (!value) { // undefined or null
1637 remove(index); 1701 remove(index);
1638 return true; 1702 return true;
1639 } 1703 }
1640 setOption(index, value.get(), exceptionState); 1704 setOption(index, value.get(), exceptionState);
1641 return true; 1705 return true;
(...skipping 15 matching lines...) Expand all
1657 } 1721 }
1658 1722
1659 void HTMLSelectElement::trace(Visitor* visitor) 1723 void HTMLSelectElement::trace(Visitor* visitor)
1660 { 1724 {
1661 #if ENABLE(OILPAN) 1725 #if ENABLE(OILPAN)
1662 visitor->trace(m_listItems); 1726 visitor->trace(m_listItems);
1663 #endif 1727 #endif
1664 HTMLFormControlElementWithState::trace(visitor); 1728 HTMLFormControlElementWithState::trace(visitor);
1665 } 1729 }
1666 1730
1731 void HTMLSelectElement::didAddUserAgentShadowRoot(ShadowRoot& root)
1732 {
1733 RefPtrWillBeRawPtr<HTMLContentElement> content = HTMLContentElement::create( document());
1734 content->setAttribute(selectAttr, "option,optgroup");
1735 root.appendChild(content);
1736 }
1737
1667 } // namespace 1738 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698