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

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: White background 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/core/v8/ExceptionState.h" 32 #include "bindings/core/v8/ExceptionState.h"
33 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 33 #include "bindings/core/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()) {
tkent 2014/07/08 04:43:46 This change looks unnecessary.
keishi 2014/07/10 09:48:03 Done.
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)
tkent 2014/07/08 02:20:59 This change looks unnecessary.
keishi 2014/07/10 09:48:03 Done.
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(const ChildrenChange& change) 406 void HTMLSelectElement::childrenChanged(const ChildrenChange& change)
396 { 407 {
397 setRecalcListItems(); 408 setRecalcListItems();
398 setNeedsValidityCheck(); 409 setNeedsValidityCheck();
399 m_lastOnChangeSelection.clear();
tkent 2014/07/08 04:43:46 Why do you remove this?
keishi 2014/07/10 09:48:03 Reverted. See comment for HTMLSelectElement::listB
400 410
401 HTMLFormControlElementWithState::childrenChanged(change); 411 HTMLFormControlElementWithState::childrenChanged(change);
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);
tkent 2014/07/08 04:43:46 This cast is unnecessary. isDisabledFormControl an
keishi 2014/07/10 09:48:03 Done.
538 if (option.isDisabledFormControl())
539 continue;
540 if (!usesMenuList() && !option.renderer())
541 continue;
542 } else {
527 continue; 543 continue;
tkent 2014/07/08 04:43:46 We prefer early continue. if (!isHTMLOptionElemen
keishi 2014/07/10 09:48:03 Done.
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 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
619 636
620 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 637 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
621 for (unsigned i = 0; i < items.size(); ++i) { 638 for (unsigned i = 0; i < items.size(); ++i) {
622 HTMLElement* element = items[i]; 639 HTMLElement* element = items[i];
623 m_cachedStateForActiveSelection.append(isHTMLOptionElement(*element) && toHTMLOptionElement(element)->selected()); 640 m_cachedStateForActiveSelection.append(isHTMLOptionElement(*element) && toHTMLOptionElement(element)->selected());
624 } 641 }
625 } 642 }
626 643
627 void HTMLSelectElement::setActiveSelectionEndIndex(int index) 644 void HTMLSelectElement::setActiveSelectionEndIndex(int index)
628 { 645 {
646 if (index == m_activeSelectionEndIndex)
647 return;
629 m_activeSelectionEndIndex = index; 648 m_activeSelectionEndIndex = index;
649 setNeedsStyleRecalc(SubtreeStyleChange);
630 } 650 }
631 651
632 void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions) 652 void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions)
633 { 653 {
634 ASSERT(renderer() && (renderer()->isListBox() || m_multiple)); 654 ASSERT(renderer() && (renderer()->isListBox() || m_multiple));
635 ASSERT(!listItems().size() || m_activeSelectionAnchorIndex >= 0); 655 ASSERT(!listItems().size() || m_activeSelectionAnchorIndex >= 0);
636 656
637 unsigned start = std::min(m_activeSelectionAnchorIndex, m_activeSelectionEnd Index); 657 unsigned start = std::min(m_activeSelectionAnchorIndex, m_activeSelectionEnd Index);
638 unsigned end = std::max(m_activeSelectionAnchorIndex, m_activeSelectionEndIn dex); 658 unsigned end = std::max(m_activeSelectionAnchorIndex, m_activeSelectionEndIn dex);
639 659
640 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 660 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
641 for (unsigned i = 0; i < items.size(); ++i) { 661 for (unsigned i = 0; i < items.size(); ++i) {
642 HTMLElement* element = items[i]; 662 HTMLElement* element = items[i];
643 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDi sabledFormControl() || toHTMLOptionElement(element)->isDisplayNone()) 663 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDi sabledFormControl() || !toHTMLOptionElement(element)->renderer())
644 continue; 664 continue;
645 665
646 if (i >= start && i <= end) 666 if (i >= start && i <= end)
647 toHTMLOptionElement(element)->setSelectedState(m_activeSelectionStat e); 667 toHTMLOptionElement(element)->setSelectedState(m_activeSelectionStat e);
648 else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.si ze()) 668 else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.si ze())
649 toHTMLOptionElement(element)->setSelectedState(false); 669 toHTMLOptionElement(element)->setSelectedState(false);
650 else 670 else
651 toHTMLOptionElement(element)->setSelectedState(m_cachedStateForActiv eSelection[i]); 671 toHTMLOptionElement(element)->setSelectedState(m_cachedStateForActiv eSelection[i]);
652 } 672 }
653 673
674 setNeedsValidityCheck();
654 scrollToSelection(); 675 scrollToSelection();
655 setNeedsValidityCheck();
656 notifyFormStateChanged(); 676 notifyFormStateChanged();
657 } 677 }
658 678
659 void HTMLSelectElement::listBoxOnChange() 679 void HTMLSelectElement::listBoxOnChange()
tkent 2014/07/08 04:43:46 Is the change in this function necessary now?
keishi 2014/07/10 09:48:03 Because we animate scrolling now, RenderListBox::s
660 { 680 {
661 ASSERT(!usesMenuList() || m_multiple); 681 ASSERT(!usesMenuList() || m_multiple);
662 682
663 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 683 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
664 684
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. 685 // Update m_lastOnChangeSelection and fire dispatchFormControlChangeEvent.
674 bool fireOnChange = false; 686 bool fireOnChange = false;
675 for (unsigned i = 0; i < items.size(); ++i) { 687 for (unsigned i = 0; i < items.size(); ++i) {
676 HTMLElement* element = items[i]; 688 HTMLElement* element = items[i];
677 bool selected = isHTMLOptionElement(*element) && toHTMLOptionElement(ele ment)->selected(); 689 bool selected = isHTMLOptionElement(*element) && toHTMLOptionElement(ele ment)->selected();
678 if (selected != m_lastOnChangeSelection[i]) 690 if (i < m_lastOnChangeSelection.size()) {
691 if (selected != m_lastOnChangeSelection[i]) {
692 fireOnChange = true;
693 break;
694 }
695 } else if (selected) {
679 fireOnChange = true; 696 fireOnChange = true;
680 m_lastOnChangeSelection[i] = selected; 697 break;
698 }
681 } 699 }
682 700
683 if (fireOnChange) { 701 if (fireOnChange) {
702 saveLastSelection();
684 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this); 703 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this);
685 dispatchInputEvent(); 704 dispatchInputEvent();
686 dispatchFormControlChangeEvent(); 705 dispatchFormControlChangeEvent();
687 } 706 }
688 } 707 }
689 708
690 void HTMLSelectElement::dispatchInputAndChangeEventForMenuList(bool requiresUser Gesture) 709 void HTMLSelectElement::dispatchInputAndChangeEventForMenuList(bool requiresUser Gesture)
691 { 710 {
692 ASSERT(usesMenuList()); 711 ASSERT(usesMenuList());
693 712
694 int selected = selectedIndex(); 713 int selected = selectedIndex();
695 if (m_lastOnChangeIndex != selected && (!requiresUserGesture || m_isProcessi ngUserDrivenChange)) { 714 if (m_lastOnChangeIndex != selected && (!requiresUserGesture || m_isProcessi ngUserDrivenChange)) {
696 m_lastOnChangeIndex = selected; 715 m_lastOnChangeIndex = selected;
697 m_isProcessingUserDrivenChange = false; 716 m_isProcessingUserDrivenChange = false;
698 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this); 717 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this);
699 dispatchInputEvent(); 718 dispatchInputEvent();
700 dispatchFormControlChangeEvent(); 719 dispatchFormControlChangeEvent();
701 } 720 }
702 } 721 }
703 722
704 void HTMLSelectElement::scrollToSelection() 723 void HTMLSelectElement::scrollToSelection()
705 { 724 {
725 if (!isFinishedParsingChildren())
726 return;
706 if (usesMenuList()) 727 if (usesMenuList())
707 return; 728 return;
708 729 scrollTo(activeSelectionEndListIndex());
709 if (RenderObject* renderer = this->renderer()) 730 if (AXObjectCache* cache = document().existingAXObjectCache())
710 toRenderListBox(renderer)->selectionChanged(); 731 cache->selectedChildrenChanged(this);
711 } 732 }
712 733
713 void HTMLSelectElement::setOptionsChangedOnRenderer() 734 void HTMLSelectElement::setOptionsChangedOnRenderer()
714 { 735 {
715 if (RenderObject* renderer = this->renderer()) { 736 if (RenderObject* renderer = this->renderer()) {
716 if (usesMenuList()) 737 if (usesMenuList())
717 toRenderMenuList(renderer)->setOptionsChanged(true); 738 toRenderMenuList(renderer)->setOptionsChanged(true);
718 else
719 toRenderListBox(renderer)->setOptionsChanged(true);
720 } 739 }
721 } 740 }
722 741
723 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& HTMLSelectElement::lis tItems() const 742 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& HTMLSelectElement::lis tItems() const
724 { 743 {
725 if (m_shouldRecalcListItems) 744 if (m_shouldRecalcListItems)
726 recalcListItems(); 745 recalcListItems();
727 else { 746 else {
728 #if ASSERT_ENABLED 747 #if ASSERT_ENABLED
729 WillBeHeapVector<RawPtrWillBeMember<HTMLElement> > items = m_listItems; 748 WillBeHeapVector<RawPtrWillBeMember<HTMLElement> > items = m_listItems;
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 { 870 {
852 return m_suggestedIndex; 871 return m_suggestedIndex;
853 } 872 }
854 873
855 void HTMLSelectElement::setSuggestedIndex(int suggestedIndex) 874 void HTMLSelectElement::setSuggestedIndex(int suggestedIndex)
856 { 875 {
857 m_suggestedIndex = suggestedIndex; 876 m_suggestedIndex = suggestedIndex;
858 877
859 if (RenderObject* renderer = this->renderer()) { 878 if (RenderObject* renderer = this->renderer()) {
860 renderer->updateFromElement(); 879 renderer->updateFromElement();
861 if (renderer->isListBox()) 880 scrollTo(suggestedIndex);
862 toRenderListBox(renderer)->scrollToRevealElementAtListIndex(suggeste dIndex);
863 } 881 }
864 } 882 }
865 883
884 void HTMLSelectElement::scrollTo(int listIndex)
885 {
886 if (listIndex < 0)
887 return;
888 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
889 int listSize = static_cast<int>(items.size());
890 if (listIndex >= listSize)
891 return;
892 items[listIndex]->scrollIntoViewIfNeeded(false);
893 }
894
866 void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, b ool optionIsSelected) 895 void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, b ool optionIsSelected)
867 { 896 {
868 ASSERT(option->ownerSelectElement() == this); 897 ASSERT(option->ownerSelectElement() == this);
869 if (optionIsSelected) 898 if (optionIsSelected)
870 selectOption(option->index()); 899 selectOption(option->index());
871 else if (!usesMenuList() || multiple()) 900 else if (!usesMenuList() || multiple())
872 selectOption(-1); 901 selectOption(-1);
873 else 902 else
874 selectOption(nextSelectableListIndex(-1)); 903 selectOption(nextSelectableListIndex(-1));
875 } 904 }
876 905
906 void HTMLSelectElement::optionRemoved(HTMLOptionElement* option)
tkent 2014/07/08 04:43:46 probably the argument type should be |const HTMLOp
keishi 2014/07/10 09:48:03 Done.
keishi 2014/07/10 09:48:03 Done.
907 {
908 if (m_activeSelectionAnchorIndex < 0 && m_activeSelectionEndIndex < 0)
909 return;
910 int listIndex = optionToListIndex(option->index());
911 if (listIndex <= m_activeSelectionAnchorIndex)
912 m_activeSelectionAnchorIndex--;
913 if (listIndex <= m_activeSelectionEndIndex)
914 m_activeSelectionEndIndex--;
915 }
916
877 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags) 917 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags)
878 { 918 {
879 bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions); 919 bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions);
880 920
881 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 921 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
882 int listIndex = optionToListIndex(optionIndex); 922 int listIndex = optionToListIndex(optionIndex);
883 923
884 HTMLElement* element = 0; 924 HTMLElement* element = 0;
885 if (listIndex >= 0) { 925 if (listIndex >= 0) {
886 element = items[listIndex]; 926 element = items[listIndex];
(...skipping 15 matching lines...) Expand all
902 942
903 scrollToSelection(); 943 scrollToSelection();
904 944
905 setNeedsValidityCheck(); 945 setNeedsValidityCheck();
906 946
907 if (usesMenuList()) { 947 if (usesMenuList()) {
908 m_isProcessingUserDrivenChange = flags & UserDriven; 948 m_isProcessingUserDrivenChange = flags & UserDriven;
909 if (flags & DispatchInputAndChangeEvent) 949 if (flags & DispatchInputAndChangeEvent)
910 dispatchInputAndChangeEventForMenuList(); 950 dispatchInputAndChangeEventForMenuList();
911 if (RenderObject* renderer = this->renderer()) { 951 if (RenderObject* renderer = this->renderer()) {
912 if (usesMenuList()) 952 if (usesMenuList()) {
913 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex); 953 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex);
914 else if (renderer->isListBox()) 954 } else if (renderer->isListBox()) {
915 toRenderListBox(renderer)->selectionChanged(); 955 if (AXObjectCache* cache = document().existingAXObjectCache())
956 cache->selectedChildrenChanged(this);
957 }
916 } 958 }
917 } 959 }
918 960
919 notifyFormStateChanged(); 961 notifyFormStateChanged();
920 } 962 }
921 963
922 int HTMLSelectElement::optionToListIndex(int optionIndex) const 964 int HTMLSelectElement::optionToListIndex(int optionIndex) const
923 { 965 {
924 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 966 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
925 int listSize = static_cast<int>(items.size()); 967 int listSize = static_cast<int>(items.size());
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1046 startIndex = foundIndex + 1; 1088 startIndex = foundIndex + 1;
1047 } 1089 }
1048 } 1090 }
1049 1091
1050 setOptionsChangedOnRenderer(); 1092 setOptionsChangedOnRenderer();
1051 setNeedsValidityCheck(); 1093 setNeedsValidityCheck();
1052 } 1094 }
1053 1095
1054 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value) 1096 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value)
1055 { 1097 {
1056 bool oldUsesMenuList = usesMenuList();
1057 m_multiple = !value.isNull(); 1098 m_multiple = !value.isNull();
1058 setNeedsValidityCheck(); 1099 setNeedsValidityCheck();
1059 if (oldUsesMenuList != usesMenuList()) 1100
1060 lazyReattachIfAttached(); 1101 lazyReattachIfAttached();
1061 } 1102 }
1062 1103
1063 bool HTMLSelectElement::appendFormData(FormDataList& list, bool) 1104 bool HTMLSelectElement::appendFormData(FormDataList& list, bool)
1064 { 1105 {
1065 const AtomicString& name = this->name(); 1106 const AtomicString& name = this->name();
1066 if (name.isEmpty()) 1107 if (name.isEmpty())
1067 return false; 1108 return false;
1068 1109
1069 bool successful = false; 1110 bool successful = false;
1070 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 1111 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 1369 // 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 1370 // ctrl), then initialize the anchor index to the listIndex that just got
1330 // clicked. 1371 // clicked.
1331 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect) 1372 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect)
1332 setActiveSelectionAnchorIndex(listIndex); 1373 setActiveSelectionAnchorIndex(listIndex);
1333 1374
1334 setActiveSelectionEndIndex(listIndex); 1375 setActiveSelectionEndIndex(listIndex);
1335 updateListBoxSelection(!multiSelect); 1376 updateListBoxSelection(!multiSelect);
1336 } 1377 }
1337 1378
1379 int HTMLSelectElement::listIndexForEventTargetOption(const Event& event)
1380 {
1381 Node* targetNode = event.target()->toNode();
1382 if (!targetNode || !isHTMLOptionElement(*targetNode))
1383 return -1;
1384 return listIndexForOption(toHTMLOptionElement(*targetNode));
1385 }
1386
1387 int HTMLSelectElement::listIndexForOption(const HTMLOptionElement& option)
1388 {
1389 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = this->list Items();
1390 size_t length = items.size();
1391 for (size_t i = 0; i < length; ++i) {
1392 if (items[i] == &option)
1393 return i;
1394 }
1395 return -1;
1396 }
1397
1398 AutoscrollController* HTMLSelectElement::autoscrollController() const
1399 {
1400 if (Page* page = document().page())
1401 return &page->autoscrollController();
1402 return 0;
1403 }
1404
1338 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) 1405 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event)
1339 { 1406 {
1340 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems(); 1407 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems();
1341 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent()) { 1408 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent()) {
1342 focus(); 1409 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. 1410 // 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()) 1411 if (!renderer() || !renderer()->isListBox())
1345 return; 1412 return;
1346 1413
1347 // Convert to coords relative to the list box if needed. 1414 // Convert to coords relative to the list box if needed.
1348 GestureEvent& gestureEvent = toGestureEvent(*event); 1415 GestureEvent& gestureEvent = toGestureEvent(*event);
1349 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(gestu reEvent.absoluteLocation(), UseTransforms)); 1416 int listIndex = listIndexForEventTargetOption(gestureEvent);
1350 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset));
1351 if (listIndex >= 0) { 1417 if (listIndex >= 0) {
1352 if (!isDisabledFormControl()) 1418 if (!isDisabledFormControl())
1353 updateSelectedState(listIndex, true, gestureEvent.shiftKey()); 1419 updateSelectedState(listIndex, true, gestureEvent.shiftKey());
1354 event->setDefaultHandled(); 1420 event->setDefaultHandled();
1355 } 1421 }
1356 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent () && toMouseEvent(event)->button() == LeftButton) { 1422 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent () && toMouseEvent(event)->button() == LeftButton) {
1357 focus(); 1423 focus();
1358 // Calling focus() may cause us to lose our renderer, in which case do n ot want to handle the event. 1424 // 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()) 1425 if (!renderer() || !renderer()->isListBox() || isDisabledFormControl())
1360 return; 1426 return;
1361 1427
1428 if (Page* page = document().page())
1429 page->autoscrollController().startAutoscrollForSelection(renderer()) ;
1430
1362 // Convert to coords relative to the list box if needed. 1431 // Convert to coords relative to the list box if needed.
1363 MouseEvent* mouseEvent = toMouseEvent(event); 1432 MouseEvent* mouseEvent = toMouseEvent(event);
1364 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse Event->absoluteLocation(), UseTransforms)); 1433 int listIndex = listIndexForEventTargetOption(*mouseEvent);
1365 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset));
1366 if (listIndex >= 0) { 1434 if (listIndex >= 0) {
1367 if (!isDisabledFormControl()) { 1435 if (!isDisabledFormControl()) {
1368 #if OS(MACOSX) 1436 #if OS(MACOSX)
1369 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent ->shiftKey()); 1437 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent ->shiftKey());
1370 #else 1438 #else
1371 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent ->shiftKey()); 1439 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent ->shiftKey());
1372 #endif 1440 #endif
1373 } 1441 }
1374 if (LocalFrame* frame = document().frame()) 1442 if (LocalFrame* frame = document().frame())
1375 frame->eventHandler().setMouseDownMayStartAutoscroll(); 1443 frame->eventHandler().setMouseDownMayStartAutoscroll();
1376 1444
1377 event->setDefaultHandled(); 1445 event->setDefaultHandled();
1378 } 1446 }
1379 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent () && !toRenderBox(renderer())->canBeScrolledAndHasScrollableArea()) { 1447 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent ()) {
1380 MouseEvent* mouseEvent = toMouseEvent(event); 1448 MouseEvent* mouseEvent = toMouseEvent(event);
1381 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown()) 1449 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown())
1382 return; 1450 return;
1383 1451 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) { 1452 if (listIndex >= 0) {
1387 if (!isDisabledFormControl()) { 1453 if (!isDisabledFormControl()) {
1388 if (m_multiple) { 1454 if (m_multiple) {
1389 // Only extend selection if there is something selected. 1455 // Only extend selection if there is something selected.
1390 if (m_activeSelectionAnchorIndex < 0) 1456 if (m_activeSelectionAnchorIndex < 0)
1391 return; 1457 return;
1392 1458
1393 setActiveSelectionEndIndex(listIndex); 1459 setActiveSelectionEndIndex(listIndex);
1394 updateListBoxSelection(false); 1460 updateListBoxSelection(false);
1395 } else { 1461 } else {
1396 setActiveSelectionAnchorIndex(listIndex); 1462 setActiveSelectionAnchorIndex(listIndex);
1397 setActiveSelectionEndIndex(listIndex); 1463 setActiveSelectionEndIndex(listIndex);
1398 updateListBoxSelection(true); 1464 updateListBoxSelection(true);
1399 } 1465 }
1400 } 1466 }
1401 } 1467 }
1402 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton && renderer() && !toRenderBox(re nderer())->autoscrollInProgress()) { 1468 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton && renderer()) {
tkent 2014/07/08 04:43:46 Is it safe to remove autoscrollInProgress check?
keishi 2014/07/10 09:48:03 I added back this check and added a call to stopAu
1403 // We didn't start this click/drag on any options. 1469 // We didn't start this click/drag on any options.
1404 if (m_lastOnChangeSelection.isEmpty()) 1470 if (m_lastOnChangeSelection.isEmpty())
1405 return; 1471 return;
1406 listBoxOnChange(); 1472 listBoxOnChange();
1407 } else if (event->type() == EventTypeNames::keydown) { 1473 } else if (event->type() == EventTypeNames::keydown) {
1408 if (!event->isKeyboardEvent()) 1474 if (!event->isKeyboardEvent())
1409 return; 1475 return;
1410 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier(); 1476 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier();
1411 1477
1412 bool handled = false; 1478 bool handled = false;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1471 m_activeSelectionState = true; 1537 m_activeSelectionState = true;
1472 // If the anchor is unitialized, or if we're going to deselect all 1538 // 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. 1539 // other options, then set the anchor index equal to the end index.
1474 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift Key() && selectNewItem); 1540 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift Key() && selectNewItem);
1475 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { 1541 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) {
1476 if (deselectOthers) 1542 if (deselectOthers)
1477 deselectItemsWithoutValidation(); 1543 deselectItemsWithoutValidation();
1478 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); 1544 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex);
1479 } 1545 }
1480 1546
1481 toRenderListBox(renderer())->scrollToRevealElementAtListIndex(endInd ex); 1547 scrollTo(endIndex);
1482 if (selectNewItem) { 1548 if (selectNewItem) {
1483 updateListBoxSelection(deselectOthers); 1549 updateListBoxSelection(deselectOthers);
1484 listBoxOnChange(); 1550 listBoxOnChange();
1485 } else 1551 } else
1486 scrollToSelection(); 1552 scrollToSelection();
1487 1553
1488 event->setDefaultHandled(); 1554 event->setDefaultHandled();
1489 } 1555 }
1490 } else if (event->type() == EventTypeNames::keypress) { 1556 } else if (event->type() == EventTypeNames::keypress) {
1491 if (!event->isKeyboardEvent()) 1557 if (!event->isKeyboardEvent())
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1622 ++options; 1688 ++options;
1623 } 1689 }
1624 1690
1625 return options; 1691 return options;
1626 } 1692 }
1627 1693
1628 void HTMLSelectElement::finishParsingChildren() 1694 void HTMLSelectElement::finishParsingChildren()
1629 { 1695 {
1630 HTMLFormControlElementWithState::finishParsingChildren(); 1696 HTMLFormControlElementWithState::finishParsingChildren();
1631 updateListItemSelectedStates(); 1697 updateListItemSelectedStates();
1698 scrollToSelection();
1632 } 1699 }
1633 1700
1634 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR awPtr<HTMLOptionElement> value, ExceptionState& exceptionState) 1701 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR awPtr<HTMLOptionElement> value, ExceptionState& exceptionState)
1635 { 1702 {
1636 if (!value) { // undefined or null 1703 if (!value) { // undefined or null
1637 remove(index); 1704 remove(index);
1638 return true; 1705 return true;
1639 } 1706 }
1640 setOption(index, value.get(), exceptionState); 1707 setOption(index, value.get(), exceptionState);
1641 return true; 1708 return true;
(...skipping 15 matching lines...) Expand all
1657 } 1724 }
1658 1725
1659 void HTMLSelectElement::trace(Visitor* visitor) 1726 void HTMLSelectElement::trace(Visitor* visitor)
1660 { 1727 {
1661 #if ENABLE(OILPAN) 1728 #if ENABLE(OILPAN)
1662 visitor->trace(m_listItems); 1729 visitor->trace(m_listItems);
1663 #endif 1730 #endif
1664 HTMLFormControlElementWithState::trace(visitor); 1731 HTMLFormControlElementWithState::trace(visitor);
1665 } 1732 }
1666 1733
1734 void HTMLSelectElement::didAddUserAgentShadowRoot(ShadowRoot& root)
1735 {
1736 RefPtrWillBeRawPtr<HTMLContentElement> content = HTMLContentElement::create( document());
1737 content->setAttribute(selectAttr, "option,optgroup");
1738 root.appendChild(content);
1739 }
1740
1741 HTMLOptionElement* HTMLSelectElement::spatialNavigationFocusedOption()
1742 {
1743 if (!isSpatialNavigationEnabled(document().frame()))
1744 return nullptr;
1745 int focusedIndex = activeSelectionEndListIndex();
1746 if (focusedIndex < 0)
1747 focusedIndex = firstSelectableListIndex();
1748 if (focusedIndex < 0)
1749 return nullptr;
1750 HTMLElement* focused = listItems()[focusedIndex];
1751 return isHTMLOptionElement(focused) ? toHTMLOptionElement(focused) : nullptr ;
1752 }
1753
1667 } // namespace 1754 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698