15f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian/*
25f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
35f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian *
45f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * This library is free software; you can redistribute it and/or
55f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * modify it under the terms of the GNU Library General Public
65f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * License as published by the Free Software Foundation; either
75f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * version 2 of the License, or (at your option) any later version.
85f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian *
95f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * This library is distributed in the hope that it will be useful,
105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * but WITHOUT ANY WARRANTY; without even the implied warranty of
115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * Library General Public License for more details.
135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian *
145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * You should have received a copy of the GNU Library General Public License
155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * along with this library; see the file COPYING.LIB.  If not, write to
165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * Boston, MA 02110-1301, USA.
185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian *
195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian */
205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "config.h"
225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "SelectElement.h"
235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
24e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include "Attribute.h"
25d0825bca7fe65beaee391d30da42e937db621564Steve Block#include "Chrome.h"
265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "ChromeClient.h"
275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "Element.h"
285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "EventHandler.h"
295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "EventNames.h"
305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "FormDataList.h"
315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "Frame.h"
325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "HTMLFormElement.h"
33e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include "HTMLNames.h"
345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "HTMLSelectElement.h"
355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "KeyboardEvent.h"
365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "MouseEvent.h"
375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "OptionElement.h"
385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "OptionGroupElement.h"
395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "Page.h"
405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "RenderListBox.h"
415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "RenderMenuList.h"
4228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "SpatialNavigation.h"
435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include <wtf/Assertions.h>
442fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <wtf/unicode/CharacterNames.h>
455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#if ENABLE(WML)
475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "WMLNames.h"
485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "WMLSelectElement.h"
495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif
505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// Configure platform-specific behavior when focused pop-up receives arrow/space/return keystroke.
52231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// (PLATFORM(MAC) and PLATFORM(GTK) are always false in Chromium, hence the extra tests.)
53d0825bca7fe65beaee391d30da42e937db621564Steve Block#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#define ARROW_KEYS_POP_MENU 1
550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#define SPACE_OR_RETURN_POP_MENU 0
56bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#elif PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (OS(LINUX) || OS(FREEBSD)))
570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#define ARROW_KEYS_POP_MENU 0
580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#define SPACE_OR_RETURN_POP_MENU 1
595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#else
605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#define ARROW_KEYS_POP_MENU 0
610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#define SPACE_OR_RETURN_POP_MENU 0
625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif
635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianusing std::min;
655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianusing std::max;
665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianusing namespace WTF;
675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianusing namespace Unicode;
685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qiannamespace WebCore {
705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic const DOMTimeStamp typeAheadTimeout = 1000;
725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochenum SkipDirection {
742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    SkipBackwards = -1,
752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    SkipForwards = 1
762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch};
772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// Returns the 1st valid item |skip| items from |listIndex| in direction |direction| if there is one.
792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// Otherwise, it returns the valid item closest to that boundary which is past |listIndex| if there is one.
802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// Otherwise, it returns |listIndex|.
812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// Valid means that it is enabled and an option element.
822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int nextValidIndex(const Vector<Element*>& listItems, int listIndex, SkipDirection direction, int skip)
832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    ASSERT(direction == -1 || direction == 1);
852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    int lastGoodIndex = listIndex;
862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    int size = listItems.size();
872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex += direction) {
882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        --skip;
892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if (!listItems[listIndex]->disabled() && isOptionElement(listItems[listIndex])) {
902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            lastGoodIndex = listIndex;
912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            if (skip <= 0)
922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                break;
932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        }
942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    }
952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return lastGoodIndex;
962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int nextSelectableListIndex(SelectElementData& data, Element* element, int startIndex)
992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
1002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return nextValidIndex(data.listItems(element), startIndex, SkipForwards, 1);
1012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
1022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int previousSelectableListIndex(SelectElementData& data, Element* element, int startIndex)
1042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
1052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (startIndex == -1)
1062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        startIndex = data.listItems(element).size();
1072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return nextValidIndex(data.listItems(element), startIndex, SkipBackwards, 1);
1082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
1092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int firstSelectableListIndex(SelectElementData& data, Element* element)
1112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
1122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    const Vector<Element*>& items = data.listItems(element);
1132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    int index = nextValidIndex(items, items.size(), SkipBackwards, INT_MAX);
1142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (static_cast<unsigned>(index) == items.size())
1152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return -1;
1162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return index;
1172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
1182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int lastSelectableListIndex(SelectElementData& data, Element* element)
1202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
1212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return nextValidIndex(data.listItems(element), -1, SkipForwards, INT_MAX);
1222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
1232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// Returns the index of the next valid item one page away from |startIndex| in direction |direction|.
1252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int nextSelectableListIndexPageAway(SelectElementData& data, Element* element, int startIndex, SkipDirection direction)
1262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
1272daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    const Vector<Element*>& items = data.listItems(element);
1282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // Can't use data->size() because renderer forces a minimum size.
1292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    int pageSize = 0;
1302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (element->renderer()->isListBox())
1312daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        pageSize = toRenderListBox(element->renderer())->size() - 1; // -1 so we still show context
1322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // One page away, but not outside valid bounds.
1342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // If there is a valid option item one page away, the index is chosen.
1352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // If there is no exact one page away valid option, returns startIndex or the most far index.
1362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    int edgeIndex = (direction == SkipForwards) ? 0 : (items.size() - 1);
1372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    int skipAmount = pageSize + ((direction == SkipForwards) ? startIndex : (edgeIndex - startIndex));
1382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return nextValidIndex(items, edgeIndex, direction, skipAmount);
1392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
1402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::selectAll(SelectElementData& data, Element* element)
1425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    ASSERT(!data.usesMenuList());
1445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!element->renderer() || !data.multiple())
1455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
1465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Save the selection so it can be compared to the new selectAll selection when dispatching change events
1485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    saveLastSelection(data, element);
1495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    data.setActiveSelectionState(true);
1515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    setActiveSelectionAnchorIndex(data, element, nextSelectableListIndex(data, element, -1));
1525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    setActiveSelectionEndIndex(data, previousSelectableListIndex(data, element, -1));
1535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    updateListBoxSelection(data, element, false);
1555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    listBoxOnChange(data, element);
1565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
1575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::saveLastSelection(SelectElementData& data, Element* element)
1595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (data.usesMenuList()) {
1615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        data.setLastOnChangeIndex(selectedIndex(data, element));
1625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
1635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
1645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Vector<bool>& lastOnChangeSelection = data.lastOnChangeSelection();
1665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    lastOnChangeSelection.clear();
1675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
1695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (unsigned i = 0; i < items.size(); ++i) {
1705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        OptionElement* optionElement = toOptionElement(items[i]);
1715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        lastOnChangeSelection.append(optionElement && optionElement->selected());
1725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
1735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
1745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::setActiveSelectionAnchorIndex(SelectElementData& data, Element* element, int index)
1765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    data.setActiveSelectionAnchorIndex(index);
1785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Cache the selection state so we can restore the old selection as the new selection pivots around this anchor index
1805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Vector<bool>& cachedStateForActiveSelection = data.cachedStateForActiveSelection();
1815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    cachedStateForActiveSelection.clear();
1825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
1845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (unsigned i = 0; i < items.size(); ++i) {
1855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        OptionElement* optionElement = toOptionElement(items[i]);
1865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        cachedStateForActiveSelection.append(optionElement && optionElement->selected());
1875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
1885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
1895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::setActiveSelectionEndIndex(SelectElementData& data, int index)
1915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    data.setActiveSelectionEndIndex(index);
1935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
1945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::updateListBoxSelection(SelectElementData& data, Element* element, bool deselectOtherOptions)
1965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
197dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT(element->renderer() && (element->renderer()->isListBox() || data.multiple()));
198a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    ASSERT(!data.listItems(element).size() || data.activeSelectionAnchorIndex() >= 0);
1995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    unsigned start = min(data.activeSelectionAnchorIndex(), data.activeSelectionEndIndex());
2015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    unsigned end = max(data.activeSelectionAnchorIndex(), data.activeSelectionEndIndex());
2025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Vector<bool>& cachedStateForActiveSelection = data.cachedStateForActiveSelection();
2035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
2055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (unsigned i = 0; i < items.size(); ++i) {
2065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        OptionElement* optionElement = toOptionElement(items[i]);
2075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!optionElement || items[i]->disabled())
2085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            continue;
2095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (i >= start && i <= end)
2115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            optionElement->setSelectedState(data.activeSelectionState());
2125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        else if (deselectOtherOptions || i >= cachedStateForActiveSelection.size())
2135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            optionElement->setSelectedState(false);
2145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        else
2155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            optionElement->setSelectedState(cachedStateForActiveSelection[i]);
2165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
2175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
218f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    toSelectElement(element)->updateValidity();
2195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    scrollToSelection(data, element);
2205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
2215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::listBoxOnChange(SelectElementData& data, Element* element)
2235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
224dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT(!data.usesMenuList() || data.multiple());
2255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Vector<bool>& lastOnChangeSelection = data.lastOnChangeSelection();
2275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
2285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // If the cached selection list is empty, or the size has changed, then fire dispatchFormControlChangeEvent, and return early.
2305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (lastOnChangeSelection.isEmpty() || lastOnChangeSelection.size() != items.size()) {
2315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        element->dispatchFormControlChangeEvent();
2325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
2335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
2345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Update lastOnChangeSelection and fire dispatchFormControlChangeEvent
2365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    bool fireOnChange = false;
2375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (unsigned i = 0; i < items.size(); ++i) {
2385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        OptionElement* optionElement = toOptionElement(items[i]);
2395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        bool selected = optionElement &&  optionElement->selected();
2405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (selected != lastOnChangeSelection[i])
2415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            fireOnChange = true;
2425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        lastOnChangeSelection[i] = selected;
2435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
2445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (fireOnChange)
2465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        element->dispatchFormControlChangeEvent();
2475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
2485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::menuListOnChange(SelectElementData& data, Element* element)
2505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
2515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    ASSERT(data.usesMenuList());
2525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int selected = selectedIndex(data, element);
2540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (data.lastOnChangeIndex() != selected && data.userDrivenChange()) {
2555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        data.setLastOnChangeIndex(selected);
2560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        data.setUserDrivenChange(false);
2575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        element->dispatchFormControlChangeEvent();
2585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
2595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
2605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::scrollToSelection(SelectElementData& data, Element* element)
2625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
2635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (data.usesMenuList())
2645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
2655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (RenderObject* renderer = element->renderer())
2670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        toRenderListBox(renderer)->selectionChanged();
2685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
2695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
270d0825bca7fe65beaee391d30da42e937db621564Steve Blockvoid SelectElement::setOptionsChangedOnRenderer(SelectElementData& data, Element* element)
2715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
272d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (RenderObject* renderer = element->renderer()) {
2735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (data.usesMenuList())
2740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            toRenderMenuList(renderer)->setOptionsChanged(true);
2755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        else
2760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            toRenderListBox(renderer)->setOptionsChanged(true);
277d0825bca7fe65beaee391d30da42e937db621564Steve Block    }
2785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
2795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::setRecalcListItems(SelectElementData& data, Element* element)
2815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
2825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    data.setShouldRecalcListItems(true);
2835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    data.setActiveSelectionAnchorIndex(-1); // Manual selection anchor is reset when manipulating the select programmatically.
284d0825bca7fe65beaee391d30da42e937db621564Steve Block    setOptionsChangedOnRenderer(data, element);
2855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    element->setNeedsStyleRecalc();
2865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
2875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::recalcListItems(SelectElementData& data, const Element* element, bool updateSelectedStates)
2895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
2905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Vector<Element*>& listItems = data.rawListItems();
2915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    listItems.clear();
2925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
293d0825bca7fe65beaee391d30da42e937db621564Steve Block    data.setShouldRecalcListItems(false);
294d0825bca7fe65beaee391d30da42e937db621564Steve Block
2955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    OptionElement* foundSelected = 0;
2965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (Node* currentNode = element->firstChild(); currentNode;) {
2975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!currentNode->isElementNode()) {
2985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            currentNode = currentNode->traverseNextSibling(element);
2995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            continue;
3005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
3015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        Element* current = static_cast<Element*>(currentNode);
3035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // optgroup tags may not nest. However, both FireFox and IE will
3055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // flatten the tree automatically, so we follow suit.
3065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // (http://www.w3.org/TR/html401/interact/forms.html#h-17.6)
3075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (isOptionGroupElement(current)) {
3085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            listItems.append(current);
3095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            if (current->firstChild()) {
3105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                currentNode = current->firstChild();
3115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                continue;
3125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            }
3135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
3145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (OptionElement* optionElement = toOptionElement(current)) {
3165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            listItems.append(current);
3175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
318dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            if (updateSelectedStates && !data.multiple()) {
319dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                if (!foundSelected && (data.size() <= 1 || optionElement->selected())) {
3205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                    foundSelected = optionElement;
3215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                    foundSelected->setSelectedState(true);
322dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                } else if (foundSelected && optionElement->selected()) {
3235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                    foundSelected->setSelectedState(false);
3245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                    foundSelected = optionElement;
3255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                }
3265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            }
3275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
3285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (current->hasTagName(HTMLNames::hrTag))
3305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            listItems.append(current);
3315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // In conforming HTML code, only <optgroup> and <option> will be found
3335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // within a <select>. We call traverseNextSibling so that we only step
3345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // into those tags that we choose to. For web-compat, we should cope
3355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // with the case where odd tags like a <div> have been added but we
3365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // handle this because such tags have already been removed from the
3375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // <select>'s subtree at this point.
3385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        currentNode = currentNode->traverseNextSibling(element);
3395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
3405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
3415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianint SelectElement::selectedIndex(const SelectElementData& data, const Element* element)
3435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
3445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    unsigned index = 0;
3455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // return the number of the first option selected
3475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
3485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (size_t i = 0; i < items.size(); ++i) {
3495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (OptionElement* optionElement = toOptionElement(items[i])) {
3505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            if (optionElement->selected())
3515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                return index;
3525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            ++index;
3535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
3545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
3555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return -1;
3575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
3585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid SelectElement::setSelectedIndex(SelectElementData& data, Element* element, int optionIndex, bool deselect, bool fireOnChangeNow, bool userDrivenChange)
3605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
3612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (optionIndex == -1 && !deselect && !data.multiple())
3622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        optionIndex = nextSelectableListIndex(data, element, -1);
3635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!data.multiple())
3645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        deselect = true;
3655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    const Vector<Element*>& items = data.listItems(element);
3672fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    int listIndex = optionToListIndex(data, element, optionIndex);
3682fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
3695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Element* excludeElement = 0;
3705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (OptionElement* optionElement = (listIndex >= 0 ? toOptionElement(items[listIndex]) : 0)) {
3715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        excludeElement = items[listIndex];
3725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (data.activeSelectionAnchorIndex() < 0 || deselect)
3735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            setActiveSelectionAnchorIndex(data, element, listIndex);
3745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (data.activeSelectionEndIndex() < 0 || deselect)
3755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            setActiveSelectionEndIndex(data, listIndex);
3765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        optionElement->setSelectedState(true);
3775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
3785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (deselect)
3805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        deselectItems(data, element, excludeElement);
3815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // For the menu list case, this is what makes the selected element appear.
3835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (RenderObject* renderer = element->renderer())
3845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        renderer->updateFromElement();
3855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    scrollToSelection(data, element);
3875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // This only gets called with fireOnChangeNow for menu lists.
3890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (data.usesMenuList()) {
3900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        data.setUserDrivenChange(userDrivenChange);
3910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (fireOnChangeNow)
3920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            menuListOnChange(data, element);
39306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        RenderObject* renderer = element->renderer();
39406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        if (renderer) {
39506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            if (data.usesMenuList())
39606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                toRenderMenuList(renderer)->didSetSelectedIndex();
39706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            else if (renderer->isListBox())
39806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                toRenderListBox(renderer)->selectionChanged();
39906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        }
4000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
4015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (Frame* frame = element->document()->frame())
4035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        frame->page()->chrome()->client()->formStateDidChange(element);
4045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
4055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianint SelectElement::optionToListIndex(const SelectElementData& data, const Element* element, int optionIndex)
4075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
4085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
4095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int listSize = (int) items.size();
4105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (optionIndex < 0 || optionIndex >= listSize)
4115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return -1;
4125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int optionIndex2 = -1;
4145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (int listIndex = 0; listIndex < listSize; ++listIndex) {
4155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (isOptionElement(items[listIndex])) {
4165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            ++optionIndex2;
4175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            if (optionIndex2 == optionIndex)
4185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                return listIndex;
4195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
4205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
4215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return -1;
4235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
4245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianint SelectElement::listToOptionIndex(const SelectElementData& data, const Element* element, int listIndex)
4265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
4275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
4285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (listIndex < 0 || listIndex >= int(items.size()) ||
4295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        !isOptionElement(items[listIndex]))
4305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return -1;
4315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list
4335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (int i = 0; i < listIndex; ++i)
4345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (isOptionElement(items[i]))
4355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            ++optionIndex;
4365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return optionIndex;
4385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
4395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::dispatchFocusEvent(SelectElementData& data, Element* element)
4415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
4425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Save the selection so it can be compared to the new selection when dispatching change events during blur event dispatchal
4435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (data.usesMenuList())
4445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        saveLastSelection(data, element);
4455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
4465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::dispatchBlurEvent(SelectElementData& data, Element* element)
4485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
4495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // We only need to fire change events here for menu lists, because we fire change events for list boxes whenever the selection change is actually made.
4505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // This matches other browsers' behavior.
4515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (data.usesMenuList())
4525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        menuListOnChange(data, element);
4535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
4545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::deselectItems(SelectElementData& data, Element* element, Element* excludeElement)
4565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
4575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
4585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (unsigned i = 0; i < items.size(); ++i) {
4595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (items[i] == excludeElement)
4605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            continue;
4615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (OptionElement* optionElement = toOptionElement(items[i]))
4635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            optionElement->setSelectedState(false);
4645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
4655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
4665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianbool SelectElement::saveFormControlState(const SelectElementData& data, const Element* element, String& value)
4685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
4695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
4705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int length = items.size();
4715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // FIXME: Change this code to use the new StringImpl::createUninitialized code path.
4735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Vector<char, 1024> characters(length);
4745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (int i = 0; i < length; ++i) {
4755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        OptionElement* optionElement = toOptionElement(items[i]);
4765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        bool selected = optionElement && optionElement->selected();
4775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        characters[i] = selected ? 'X' : '.';
4785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
4795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    value = String(characters.data(), length);
4815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return true;
4825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
4835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::restoreFormControlState(SelectElementData& data, Element* element, const String& state)
4855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
4865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    recalcListItems(data, element);
4875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
4895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int length = items.size();
4905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (int i = 0; i < length; ++i) {
4925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (OptionElement* optionElement = toOptionElement(items[i]))
4935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            optionElement->setSelectedState(state[i] == 'X');
4945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
4955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
496d0825bca7fe65beaee391d30da42e937db621564Steve Block    setOptionsChangedOnRenderer(data, element);
4975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
4985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
499e78cbe89e6f337f2f1fe40315be88f742b547151Steve Blockvoid SelectElement::parseMultipleAttribute(SelectElementData& data, Element* element, Attribute* attribute)
5005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
5015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    bool oldUsesMenuList = data.usesMenuList();
5025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    data.setMultiple(!attribute->isNull());
503f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    toSelectElement(element)->updateValidity();
5045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (oldUsesMenuList != data.usesMenuList() && element->attached()) {
5055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        element->detach();
5065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        element->attach();
5075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
5085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
5095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
5105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianbool SelectElement::appendFormData(SelectElementData& data, Element* element, FormDataList& list)
5115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
5125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const AtomicString& name = element->formControlName();
5135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (name.isEmpty())
5145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return false;
5155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
5165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    bool successful = false;
5175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
5185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
5195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (unsigned i = 0; i < items.size(); ++i) {
5205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        OptionElement* optionElement = toOptionElement(items[i]);
521dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (optionElement && optionElement->selected() && !optionElement->disabled()) {
5225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            list.appendData(name, optionElement->value());
5235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            successful = true;
5245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
5255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
5265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
527dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // It's possible that this is a menulist with multiple options and nothing
528dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // will be submitted (!successful). We won't send a unselected non-disabled
529dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // option as fallback. This behavior matches to other browsers.
5305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return successful;
5315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
5325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
5335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::reset(SelectElementData& data, Element* element)
5345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
5355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    OptionElement* firstOption = 0;
5360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    OptionElement* selectedOption = 0;
5375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
5385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
5395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (unsigned i = 0; i < items.size(); ++i) {
5405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        OptionElement* optionElement = toOptionElement(items[i]);
5415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!optionElement)
5425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            continue;
5435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
544f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if (items[i]->fastHasAttribute(HTMLNames::selectedAttr)) {
5450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if (selectedOption && !data.multiple())
5460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                selectedOption->setSelectedState(false);
5475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            optionElement->setSelectedState(true);
5480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            selectedOption = optionElement;
5495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        } else
5505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            optionElement->setSelectedState(false);
5515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
5525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!firstOption)
5535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            firstOption = optionElement;
5545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
5555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
556dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!selectedOption && firstOption && !data.multiple() && data.size() <= 1)
5575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        firstOption->setSelectedState(true);
5585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
559d0825bca7fe65beaee391d30da42e937db621564Steve Block    setOptionsChangedOnRenderer(data, element);
5605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    element->setNeedsStyleRecalc();
5615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
5625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
563ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Blockvoid SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm)
5645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
5655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (event->type() == eventNames().keydownEvent) {
5665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!element->renderer() || !event->isKeyboardEvent())
5675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            return;
5685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
5696b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIdentifier();
5705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        bool handled = false;
5715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
5725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#if ARROW_KEYS_POP_MENU
5736b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        if (!isSpatialNavigationEnabled(element->document()->frame())) {
5746b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            if (keyIdentifier == "Down" || keyIdentifier == "Up") {
5756b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                element->focus();
576a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
5776b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                if (!element->renderer()) // Calling focus() may cause us to lose our renderer, in which case do not want to handle the event.
5786b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                    return;
579a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
5806b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                // Save the selection so it can be compared to the new selection when dispatching change events during setSelectedIndex,
5816b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu.
5826b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                saveLastSelection(data, element);
5836b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                if (RenderMenuList* menuList = toRenderMenuList(element->renderer()))
5846b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                    menuList->showPopup();
5856b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
5866b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner                event->setDefaultHandled();
5876b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            }
5886b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            return;
5895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
5906b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner#endif
591a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // When using spatial navigation, we want to be able to navigate away from the select element
592a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // when the user hits any of the arrow keys, instead of changing the selection.
59328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        if (isSpatialNavigationEnabled(element->document()->frame()))
59428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            if (!data.activeSelectionState())
595a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                return;
596a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
597e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        UNUSED_PARAM(htmlForm);
5985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        const Vector<Element*>& listItems = data.listItems(element);
5995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
6005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        int listIndex = optionToListIndex(data, element, selectedIndex(data, element));
6015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (keyIdentifier == "Down" || keyIdentifier == "Right") {
6020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            listIndex = nextValidIndex(listItems, listIndex, SkipForwards, 1);
6035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            handled = true;
6045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        } else if (keyIdentifier == "Up" || keyIdentifier == "Left") {
6050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            listIndex = nextValidIndex(listItems, listIndex, SkipBackwards, 1);
6060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            handled = true;
6070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        } else if (keyIdentifier == "PageDown") {
6080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            listIndex = nextValidIndex(listItems, listIndex, SkipForwards, 3);
6090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            handled = true;
6100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        } else if (keyIdentifier == "PageUp") {
6110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            listIndex = nextValidIndex(listItems, listIndex, SkipBackwards, 3);
6120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            handled = true;
6130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        } else if (keyIdentifier == "Home") {
6140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            listIndex = nextValidIndex(listItems, -1, SkipForwards, 1);
6150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            handled = true;
6160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        } else if (keyIdentifier == "End") {
6170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            listIndex = nextValidIndex(listItems, listItems.size(), SkipBackwards, 1);
6185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            handled = true;
6195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
6202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
6212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if (handled && listIndex >= 0 && static_cast<unsigned>(listIndex) < listItems.size())
6220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            setSelectedIndex(data, element, listToOptionIndex(data, element, listIndex));
6236b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
6245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (handled)
6255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            event->setDefaultHandled();
6265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
6275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
6285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Use key press event here since sending simulated mouse events
6295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // on key down blocks the proper sending of the key press event.
6305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (event->type() == eventNames().keypressEvent) {
6315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!element->renderer() || !event->isKeyboardEvent())
6325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            return;
6335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
6345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        int keyCode = static_cast<KeyboardEvent*>(event)->keyCode();
6355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        bool handled = false;
6365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
6376b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        if (keyCode == ' ' && isSpatialNavigationEnabled(element->document()->frame())) {
6386b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            // Use space to toggle arrow key handling for selection change or spatial navigation.
6396b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            data.setActiveSelectionState(!data.activeSelectionState());
6406b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            event->setDefaultHandled();
6416b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            return;
6426b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        }
6436b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
6440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#if SPACE_OR_RETURN_POP_MENU
6450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (keyCode == ' ' || keyCode == '\r') {
6460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            element->focus();
647a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
648a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (!element->renderer()) // Calling focus() may cause us to lose our renderer, in which case do not want to handle the event.
649a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                return;
650a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
6510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            // Save the selection so it can be compared to the new selection when dispatching change events during setSelectedIndex,
6520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu.
6530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            saveLastSelection(data, element);
6540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if (RenderMenuList* menuList = toRenderMenuList(element->renderer()))
6550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                menuList->showPopup();
6560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            handled = true;
6570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        }
6580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#elif ARROW_KEYS_POP_MENU
6595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (keyCode == ' ') {
6605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            element->focus();
661a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
662a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (!element->renderer()) // Calling focus() may cause us to lose our renderer, in which case do not want to handle the event.
663a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                return;
664a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
6655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            // Save the selection so it can be compared to the new selection when dispatching change events during setSelectedIndex,
6665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu.
6675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            saveLastSelection(data, element);
6680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if (RenderMenuList* menuList = toRenderMenuList(element->renderer()))
6695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                menuList->showPopup();
6705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            handled = true;
6715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        } else if (keyCode == '\r') {
672ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block            if (htmlForm)
673ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block                htmlForm->submitImplicitly(event, false);
6745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            menuListOnChange(data, element);
6755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            handled = true;
6765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
6775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#else
6785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        int listIndex = optionToListIndex(data, element, selectedIndex(data, element));
6795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (keyCode == '\r') {
6805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            // listIndex should already be selected, but this will fire the onchange handler.
6815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            setSelectedIndex(data, element, listToOptionIndex(data, element, listIndex), true, true);
6825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            handled = true;
6835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
6845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif
6855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (handled)
6865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            event->setDefaultHandled();
6875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
6885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
6895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
6905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        element->focus();
691231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (element->renderer() && element->renderer()->isMenuList()) {
692231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            if (RenderMenuList* menuList = toRenderMenuList(element->renderer())) {
693231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                if (menuList->popupIsVisible())
694231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                    menuList->hidePopup();
695231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                else {
696231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                    // Save the selection so it can be compared to the new selection when we call onChange during setSelectedIndex,
697231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                    // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu.
698231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                    saveLastSelection(data, element);
699231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                    menuList->showPopup();
700231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                }
7015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            }
7025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
7035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        event->setDefaultHandled();
7045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
7055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
7065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
707dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid SelectElement::updateSelectedState(SelectElementData& data, Element* element, int listIndex,
708dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                        bool multi, bool shift)
709dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
710dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT(listIndex >= 0);
711dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
712dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Save the selection so it can be compared to the new selection when dispatching change events during mouseup, or after autoscroll finishes.
713dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    saveLastSelection(data, element);
714dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
715dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    data.setActiveSelectionState(true);
716dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
717dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    bool shiftSelect = data.multiple() && shift;
718dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    bool multiSelect = data.multiple() && multi && !shift;
719dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
720dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    Element* clickedElement = data.listItems(element)[listIndex];
721dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    OptionElement* option = toOptionElement(clickedElement);
722dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (option) {
723dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // Keep track of whether an active selection (like during drag selection), should select or deselect
724dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (option->selected() && multi)
725dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            data.setActiveSelectionState(false);
726dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
727dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (!data.activeSelectionState())
728dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            option->setSelectedState(false);
729dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
730dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
731dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // If we're not in any special multiple selection mode, then deselect all other items, excluding the clicked option.
732dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // If no option was clicked, then this will deselect all items in the list.
733dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!shiftSelect && !multiSelect)
734dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        deselectItems(data, element, clickedElement);
735dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
736dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // If the anchor hasn't been set, and we're doing a single selection or a shift selection, then initialize the anchor to the first selected index.
737dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (data.activeSelectionAnchorIndex() < 0 && !multiSelect)
738dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        setActiveSelectionAnchorIndex(data, element, selectedIndex(data, element));
739dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
740dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Set the selection state of the clicked option
741dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (option && !clickedElement->disabled())
742dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        option->setSelectedState(true);
743dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
744dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // If there was no selectedIndex() for the previous initialization, or
745dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // If we're doing a single selection, or a multiple selection (using cmd or ctrl), then initialize the anchor index to the listIndex that just got clicked.
746dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (data.activeSelectionAnchorIndex() < 0 || !shiftSelect)
747dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        setActiveSelectionAnchorIndex(data, element, listIndex);
748dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
749dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    setActiveSelectionEndIndex(data, listIndex);
750dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    updateListBoxSelection(data, element, !multiSelect);
751dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
752dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
753ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Blockvoid SelectElement::listBoxDefaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm)
7545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
7555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& listItems = data.listItems(element);
7565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
7575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
7585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        element->focus();
7595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
760a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (!element->renderer()) // Calling focus() may cause us to lose our renderer, in which case do not want to handle the event.
761a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            return;
762a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
7635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // Convert to coords relative to the list box if needed.
7645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
7655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        IntPoint localOffset = roundedIntPoint(element->renderer()->absoluteToLocal(mouseEvent->absoluteLocation(), false, true));
7660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        int listIndex = toRenderListBox(element->renderer())->listIndexAtOffset(localOffset.x(), localOffset.y());
7675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (listIndex >= 0) {
768d0825bca7fe65beaee391d30da42e937db621564Steve Block#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
769dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            updateSelectedState(data, element, listIndex, mouseEvent->metaKey(), mouseEvent->shiftKey());
7705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#else
771dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            updateSelectedState(data, element, listIndex, mouseEvent->ctrlKey(), mouseEvent->shiftKey());
7725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif
7735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            if (Frame* frame = element->document()->frame())
7745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                frame->eventHandler()->setMouseDownMayStartAutoscroll();
7755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
7765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            event->setDefaultHandled();
7775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
7786b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    } else if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton && element->document()->frame()->eventHandler()->autoscrollRenderer() != element->renderer()) {
7795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // This makes sure we fire dispatchFormControlChangeEvent for a single click.  For drag selection, onChange will fire when the autoscroll timer stops.
7805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        listBoxOnChange(data, element);
7816b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    } else if (event->type() == eventNames().keydownEvent) {
7825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!event->isKeyboardEvent())
7835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            return;
7846b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIdentifier();
7855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
7862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        bool handled = false;
7872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        int endIndex = 0;
7885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (data.activeSelectionEndIndex() < 0) {
7895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            // Initialize the end index
7902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            if (keyIdentifier == "Down" || keyIdentifier == "PageDown") {
7912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                int startIndex = lastSelectedListIndex(data, element);
7922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                handled = true;
7932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                if (keyIdentifier == "Down")
7942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                    endIndex = nextSelectableListIndex(data, element, startIndex);
7952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                else
7962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                    endIndex = nextSelectableListIndexPageAway(data, element, startIndex, SkipForwards);
7972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            } else if (keyIdentifier == "Up" || keyIdentifier == "PageUp") {
7982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                int startIndex = optionToListIndex(data, element, selectedIndex(data, element));
7992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                handled = true;
8002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                if (keyIdentifier == "Up")
8012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                    endIndex = previousSelectableListIndex(data, element, startIndex);
8022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                else
8032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                    endIndex = nextSelectableListIndexPageAway(data, element, startIndex, SkipBackwards);
8042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            }
8055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        } else {
8065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            // Set the end index based on the current end index
8072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            if (keyIdentifier == "Down") {
8085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                endIndex = nextSelectableListIndex(data, element, data.activeSelectionEndIndex());
8092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                handled = true;
8102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            } else if (keyIdentifier == "Up") {
8112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                endIndex = previousSelectableListIndex(data, element, data.activeSelectionEndIndex());
8122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                handled = true;
8132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            } else if (keyIdentifier == "PageDown") {
8142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                endIndex = nextSelectableListIndexPageAway(data, element, data.activeSelectionEndIndex(), SkipForwards);
8152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                handled = true;
8162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            } else if (keyIdentifier == "PageUp") {
8172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                endIndex = nextSelectableListIndexPageAway(data, element, data.activeSelectionEndIndex(), SkipBackwards);
8182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                handled = true;
8192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            }
8202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        }
8212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if (keyIdentifier == "Home") {
8222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            endIndex = firstSelectableListIndex(data, element);
8232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            handled = true;
8242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        } else if (keyIdentifier == "End") {
8252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            endIndex = lastSelectableListIndex(data, element);
8262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            handled = true;
8275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
82828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
82928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        if (isSpatialNavigationEnabled(element->document()->frame()))
83028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            // Check if the selection moves to the boundary.
83128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            if (keyIdentifier == "Left" || keyIdentifier == "Right" || ((keyIdentifier == "Down" || keyIdentifier == "Up") && endIndex == data.activeSelectionEndIndex()))
83228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu                return;
83328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
8342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if (endIndex >= 0 && handled) {
8355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            // Save the selection so it can be compared to the new selection when dispatching change events immediately after making the new selection.
8365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            saveLastSelection(data, element);
8375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
8382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            ASSERT_UNUSED(listItems, !listItems.size() || (endIndex >= 0 && static_cast<unsigned>(endIndex) < listItems.size()));
8395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            setActiveSelectionEndIndex(data, endIndex);
8402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
84181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            bool selectNewItem = !data.multiple() || static_cast<KeyboardEvent*>(event)->shiftKey() || !isSpatialNavigationEnabled(element->document()->frame());
84281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            if (selectNewItem)
84381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                data.setActiveSelectionState(true);
8445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            // If the anchor is unitialized, or if we're going to deselect all other options, then set the anchor index equal to the end index.
84581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            bool deselectOthers = !data.multiple() || (!static_cast<KeyboardEvent*>(event)->shiftKey() && selectNewItem);
8465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            if (data.activeSelectionAnchorIndex() < 0 || deselectOthers) {
8475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                if (deselectOthers)
8485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                    deselectItems(data, element);
8495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                setActiveSelectionAnchorIndex(data, element, data.activeSelectionEndIndex());
8505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            }
8515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
8520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            toRenderListBox(element->renderer())->scrollToRevealElementAtListIndex(endIndex);
85381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            if (selectNewItem) {
85481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                updateListBoxSelection(data, element, deselectOthers);
85581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                listBoxOnChange(data, element);
85681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            } else
85781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                scrollToSelection(data, element);
85881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
8595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            event->setDefaultHandled();
8605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
861ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    } else if (event->type() == eventNames().keypressEvent) {
862ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block        if (!event->isKeyboardEvent())
863ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block            return;
864ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block        int keyCode = static_cast<KeyboardEvent*>(event)->keyCode();
865ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block
866ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block        if (keyCode == '\r') {
867ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block            if (htmlForm)
868ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block                htmlForm->submitImplicitly(event, false);
869ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block            event->setDefaultHandled();
87081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        } else if (data.multiple() && keyCode == ' ' && isSpatialNavigationEnabled(element->document()->frame())) {
87181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            // Use space to toggle selection change.
87281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            data.setActiveSelectionState(!data.activeSelectionState());
87381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            updateSelectedState(data, element, listToOptionIndex(data, element, data.activeSelectionEndIndex()), true /*multi*/, false /*shift*/);
87481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            listBoxOnChange(data, element);
87581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            event->setDefaultHandled();
876ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block        }
8775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
8785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
8795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
880ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Blockvoid SelectElement::defaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm)
8815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
8825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!element->renderer())
8835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
8845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
8855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (data.usesMenuList())
886ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block        menuListDefaultEventHandler(data, element, event, htmlForm);
8875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    else
888ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block        listBoxDefaultEventHandler(data, element, event, htmlForm);
8895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
8905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (event->defaultHandled())
8915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
8925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
8935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (event->type() == eventNames().keypressEvent && event->isKeyboardEvent()) {
8945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(event);
8955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!keyboardEvent->ctrlKey() && !keyboardEvent->altKey() && !keyboardEvent->metaKey() && isPrintableChar(keyboardEvent->charCode())) {
8965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            typeAheadFind(data, element, keyboardEvent);
8975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            event->setDefaultHandled();
8985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            return;
8995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
9005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
9015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
9025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianint SelectElement::lastSelectedListIndex(const SelectElementData& data, const Element* element)
9045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
9055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // return the number of the last option selected
9065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    unsigned index = 0;
9075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    bool found = false;
9085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
9095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (size_t i = 0; i < items.size(); ++i) {
9105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (OptionElement* optionElement = toOptionElement(items[i])) {
9115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            if (optionElement->selected()) {
9125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                index = i;
9135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                found = true;
9145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            }
9155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
9165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
9175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return found ? (int) index : -1;
9195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
9205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic String stripLeadingWhiteSpace(const String& string)
9225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
9235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int length = string.length();
9245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int i;
9265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (i = 0; i < length; ++i) {
9275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (string[i] != noBreakSpace && (string[i] <= 0x7F ? !isASCIISpace(string[i]) : (direction(string[i]) != WhiteSpaceNeutral)))
9285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            break;
9295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
9305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return string.substring(i, length - i);
9325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
9335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::typeAheadFind(SelectElementData& data, Element* element, KeyboardEvent* event)
9355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
9365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (event->timeStamp() < data.lastCharTime())
9375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
9385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    DOMTimeStamp delta = event->timeStamp() - data.lastCharTime();
9405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    data.setLastCharTime(event->timeStamp());
9415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    UChar c = event->charCode();
9435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    String prefix;
9455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int searchStartOffset = 1;
9465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (delta > typeAheadTimeout) {
9475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        prefix = String(&c, 1);
9485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        data.setTypedString(prefix);
9495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        data.setRepeatingChar(c);
9505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    } else {
9515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        data.typedString().append(c);
9525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (c == data.repeatingChar())
9545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            // The user is likely trying to cycle through all the items starting with this character, so just search on the character
9555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            prefix = String(&c, 1);
9565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        else {
9575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            data.setRepeatingChar(0);
9585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            prefix = data.typedString();
9595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            searchStartOffset = 0;
9605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
9615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
9625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
9645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int itemCount = items.size();
9655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (itemCount < 1)
9665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
9675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int selected = selectedIndex(data, element);
9695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int index = (optionToListIndex(data, element, selected >= 0 ? selected : 0) + searchStartOffset) % itemCount;
9705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    ASSERT(index >= 0);
9715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
972cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    // Compute a case-folded copy of the prefix string before beginning the search for
973cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    // a matching element. This code uses foldCase to work around the fact that
974cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    // String::startWith does not fold non-ASCII characters. This code can be changed
975cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    // to use startWith once that is fixed.
976cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    String prefixWithCaseFolded(prefix.foldCase());
9775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (int i = 0; i < itemCount; ++i, index = (index + 1) % itemCount) {
9785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        OptionElement* optionElement = toOptionElement(items[index]);
9795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!optionElement || items[index]->disabled())
9805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            continue;
9815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
982cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        // Fold the option string and check if its prefix is equal to the folded prefix.
9835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        String text = optionElement->textIndentedToRespectGroupLabel();
984cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        if (stripLeadingWhiteSpace(text).foldCase().startsWith(prefixWithCaseFolded)) {
9855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            setSelectedIndex(data, element, listToOptionIndex(data, element, index));
9865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            if (!data.usesMenuList())
9875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                listBoxOnChange(data, element);
988d0825bca7fe65beaee391d30da42e937db621564Steve Block
989d0825bca7fe65beaee391d30da42e937db621564Steve Block            setOptionsChangedOnRenderer(data, element);
9905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            element->setNeedsStyleRecalc();
9915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            return;
9925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
9935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
9945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
9955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
9965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::insertedIntoTree(SelectElementData& data, Element* element)
9975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
9985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // When the element is created during document parsing, it won't have any items yet - but for innerHTML
9995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // and related methods, this method is called after the whole subtree is constructed.
10005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    recalcListItems(data, element, true);
10015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
10025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::accessKeySetSelectedIndex(SelectElementData& data, Element* element, int index)
10045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
10055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // first bring into focus the list box
10065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!element->focused())
10075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        element->accessKeyAction(false);
10085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // if this index is already selected, unselect. otherwise update the selected index
10105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = data.listItems(element);
10115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int listIndex = optionToListIndex(data, element, index);
10125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (OptionElement* optionElement = (listIndex >= 0 ? toOptionElement(items[listIndex]) : 0)) {
10135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (optionElement->selected())
10145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            optionElement->setSelectedState(false);
10155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        else
10165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            setSelectedIndex(data, element, index, false, true);
10175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
10184a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch
10194a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch    if (data.usesMenuList())
10204a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch        menuListOnChange(data, element);
10214a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch    else
10224a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch        listBoxOnChange(data, element);
10234a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch
10245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    scrollToSelection(data, element);
10255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
10265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochunsigned SelectElement::optionCount(const SelectElementData& data, const Element* element)
10280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
10290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    unsigned options = 0;
10300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    const Vector<Element*>& items = data.listItems(element);
10320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for (unsigned i = 0; i < items.size(); ++i) {
10330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (isOptionElement(items[i]))
10340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            ++options;
10350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
10360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return options;
10380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
10390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
10405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian// SelectElementData
10415f1ab04193ad0130ca8204aadaceae083aca9881Feng QianSelectElementData::SelectElementData()
10425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    : m_multiple(false)
10435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    , m_size(0)
10445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    , m_lastOnChangeIndex(-1)
10455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    , m_activeSelectionState(false)
10465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    , m_activeSelectionAnchorIndex(-1)
10475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    , m_activeSelectionEndIndex(-1)
10485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    , m_recalcListItems(false)
10495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    , m_repeatingChar(0)
10505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    , m_lastCharTime(0)
10515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
10525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
10535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1054a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochSelectElementData::~SelectElementData()
1055a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
1056a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
1057a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
10585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElementData::checkListItems(const Element* element) const
10595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1060d0825bca7fe65beaee391d30da42e937db621564Steve Block#if !ASSERT_DISABLED
1061dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    Vector<Element*> items = m_listItems;
10625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    SelectElement::recalcListItems(*const_cast<SelectElementData*>(this), element, false);
10635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    ASSERT(items == m_listItems);
10645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#else
10655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    UNUSED_PARAM(element);
10665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif
10675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
10685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10695f1ab04193ad0130ca8204aadaceae083aca9881Feng QianVector<Element*>& SelectElementData::listItems(const Element* element)
10705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
10715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (m_recalcListItems)
10725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        SelectElement::recalcListItems(*this, element);
10735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    else
10745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        checkListItems(element);
10755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return m_listItems;
10775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
10785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianconst Vector<Element*>& SelectElementData::listItems(const Element* element) const
10805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
10815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (m_recalcListItems)
10825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        SelectElement::recalcListItems(*const_cast<SelectElementData*>(this), element);
10835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    else
10845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        checkListItems(element);
10855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return m_listItems;
10875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
10885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10895f1ab04193ad0130ca8204aadaceae083aca9881Feng QianSelectElement* toSelectElement(Element* element)
10905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
10912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (element->isHTMLElement() && element->hasTagName(HTMLNames::selectTag))
10922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return static_cast<HTMLSelectElement*>(element);
10935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#if ENABLE(WML)
10955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (element->isWMLElement() && element->hasTagName(WMLNames::selectTag))
10965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return static_cast<WMLSelectElement*>(element);
10975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif
10985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return 0;
11005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
11015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
1103