Changeset 17498 in webkit


Ignore:
Timestamp:
Oct 31, 2006 2:10:51 PM (17 years ago)
Author:
adele
Message:

LayoutTests:

Reviewed by Adam.

Tests for http://bugs.webkit.org/show_bug.cgi?id=11127 NativeListBox: arrow and drag selection should pivot around one list item
and http://bugs.webkit.org/show_bug.cgi?id=11173 REGRESSION (NativeListBox): Shift-clicking items in list box doesn't expand the current selection
and http://bugs.webkit.org/show_bug.cgi?id=11417 REGRESSION: onchange does not fire for list-style select elements

  • fast/forms/listbox-onchange-expected.txt: Added.
  • fast/forms/listbox-onchange.html: Added.
  • fast/forms/listbox-selection-expected.txt: Added.
  • fast/forms/listbox-selection.html: Added.

WebCore:

Reviewed by Adam.

Tests:

  • LayoutTests/fast/forms/listbox-selection.html
  • LayoutTests/fast/forms/listbox-onchange.html
  • html/HTMLSelectElement.h: Added m_selectedListIndexBase and m_selectedListIndexExtent to track indices for the active selection in progress. Added 2 vectors to cache selection state. One is kept so that the previous selection state can be restored as the active selection grows and shrinks. And one for onChange, that is updated after onChange is fired. Added m_activeSelectionState to keep track of whether the current drag selection is selecting or deselecting.


  • html/HTMLSelectElement.cpp: (WebCore::HTMLSelectElement::HTMLSelectElement): Initialized new variables. (WebCore::HTMLSelectElement::setSelectedIndex): If needed, initialize m_selectedListIndexBase and m_selectedListIndexExtent. (WebCore::HTMLSelectElement::dispatchBlurEvent): Only fire the onChange event here for menu lists. (WebCore::HTMLSelectElement::listBoxDefaultEventHandler): Updates base and extent variables for mouse and key events. (WebCore::HTMLSelectElement::setBase): Added. Also caches the selection state. (WebCore::HTMLSelectElement::setExtent): Added. (WebCore::HTMLSelectElement::updateListBoxSelection): Added. (WebCore::HTMLSelectElement::listBoxOnChange): Added.
  • rendering/RenderListBox.cpp: (WebCore::RenderListBox::updateFromElement): Only scroll to reveal the first index if both the first and last indices aren't visible. (WebCore::RenderListBox::listIndexAtOffset): Added. Replaces optionAtPoint, which is no longer used. (WebCore::RenderListBox::autoscroll): Now sets the selection using the select's base and extent. (WebCore::RenderListBox::stopAutoscroll): Added. Tells the select element to fire onChange. This is needed because the autoscroll can end from a mouseUp outside of the list box, and the select element won't get a mouseUp event directly. But the frame will stop the autoscroll at that point, and now we can notify the select element from here. (WebCore::RenderListBox::scrollToRevealElementAtListIndex): Checks new listIndexIsVisible method. (WebCore::RenderListBox::listIndexIsVisible): Added. (WebCore::RenderListBox::valueChanged): Removed unnecessary printf.
  • page/Frame.cpp: (WebCore::Frame::stopAutoscrollTimer): Added rendererIsBeingDestroyed argument, so when the renderer calls this during destruction, we don't try to use the pointer to that renderer to call stopAutoscroll. This is done so a renderer that's still alive has a chance to do some cleanup after autoscroll.
  • rendering/RenderListBox.h: (WebCore::RenderListBox::shouldAutoscroll): Always returns true now, since we're also updating selection from the autoscroll timer.
  • rendering/RenderObject.h: (WebCore::RenderObject::stopAutoscroll): Added.
  • rendering/RenderObject.cpp: (WebCore::RenderObject::destroy): Calls stopAutoscrollTimer with rendererIsBeingDestroyed argument.
Location:
trunk
Files:
4 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r17490 r17498  
     12006-10-31  Adele Peterson  <adele@apple.com>
     2
     3        Reviewed by Adam.
     4
     5        Tests for http://bugs.webkit.org/show_bug.cgi?id=11127 NativeListBox: arrow and drag selection should pivot around one list item
     6        and http://bugs.webkit.org/show_bug.cgi?id=11173 REGRESSION (NativeListBox): Shift-clicking items in list box doesn't expand the current selection
     7        and http://bugs.webkit.org/show_bug.cgi?id=11417 REGRESSION: onchange does not fire for list-style select elements
     8
     9        * fast/forms/listbox-onchange-expected.txt: Added.
     10        * fast/forms/listbox-onchange.html: Added.
     11        * fast/forms/listbox-selection-expected.txt: Added.
     12        * fast/forms/listbox-selection.html: Added.
     13
    1142006-10-31  Justin Garcia  <justin.garcia@apple.com>
    215
  • trunk/WebCore/ChangeLog

    r17496 r17498  
     12006-10-31  Adele Peterson  <adele@apple.com>
     2
     3        Reviewed by Adam.
     4
     5        - Fix for http://bugs.webkit.org/show_bug.cgi?id=11127 NativeListBox: arrow and drag selection should pivot around one list item
     6        and http://bugs.webkit.org/show_bug.cgi?id=11173 REGRESSION (NativeListBox): Shift-clicking items in list box doesn't expand the current selection
     7        and http://bugs.webkit.org/show_bug.cgi?id=11417 REGRESSION: onchange does not fire for list-style select elements
     8
     9        Tests:
     10        * LayoutTests/fast/forms/listbox-selection.html
     11        * LayoutTests/fast/forms/listbox-onchange.html
     12
     13        * html/HTMLSelectElement.h: Added m_selectedListIndexBase and m_selectedListIndexExtent to track indices for the active selection in progress.
     14          Added 2 vectors to cache selection state.  One is kept so that the previous selection state can be restored as the active selection grows and shrinks.
     15          And one for onChange, that is updated after onChange is fired.
     16          Added m_activeSelectionState to keep track of whether the current drag selection is selecting or deselecting.
     17 
     18        * html/HTMLSelectElement.cpp:
     19        (WebCore::HTMLSelectElement::HTMLSelectElement): Initialized new variables.
     20        (WebCore::HTMLSelectElement::setSelectedIndex): If needed, initialize m_selectedListIndexBase and m_selectedListIndexExtent.
     21        (WebCore::HTMLSelectElement::dispatchBlurEvent): Only fire the onChange event here for menu lists.
     22        (WebCore::HTMLSelectElement::listBoxDefaultEventHandler): Updates base and extent variables for mouse and key events.
     23        (WebCore::HTMLSelectElement::setBase): Added. Also caches the selection state.
     24        (WebCore::HTMLSelectElement::setExtent): Added.
     25        (WebCore::HTMLSelectElement::updateListBoxSelection): Added.
     26        (WebCore::HTMLSelectElement::listBoxOnChange): Added.
     27
     28        * rendering/RenderListBox.cpp:
     29        (WebCore::RenderListBox::updateFromElement): Only scroll to reveal the first index if both the first and last indices aren't visible.
     30        (WebCore::RenderListBox::listIndexAtOffset): Added.  Replaces optionAtPoint, which is no longer used.
     31        (WebCore::RenderListBox::autoscroll): Now sets the selection using the select's base and extent.
     32        (WebCore::RenderListBox::stopAutoscroll): Added.  Tells the select element to fire onChange.  This is needed because the autoscroll can end from a mouseUp
     33         outside of the list box, and the select element won't get a mouseUp event directly.  But the frame will stop the autoscroll at that point, and now we can
     34         notify the select element from here.
     35        (WebCore::RenderListBox::scrollToRevealElementAtListIndex): Checks new listIndexIsVisible method.
     36        (WebCore::RenderListBox::listIndexIsVisible): Added.
     37        (WebCore::RenderListBox::valueChanged): Removed unnecessary printf.
     38
     39        * page/Frame.cpp: (WebCore::Frame::stopAutoscrollTimer): Added rendererIsBeingDestroyed argument, so when the renderer calls this during destruction,
     40        we don't try to use the pointer to that renderer to call stopAutoscroll.  This is done so a renderer that's still alive has a chance to do some cleanup after autoscroll.
     41        * rendering/RenderListBox.h: (WebCore::RenderListBox::shouldAutoscroll): Always returns true now, since we're also updating selection from the autoscroll timer.
     42        * rendering/RenderObject.h: (WebCore::RenderObject::stopAutoscroll): Added.
     43        * rendering/RenderObject.cpp: (WebCore::RenderObject::destroy): Calls stopAutoscrollTimer with rendererIsBeingDestroyed argument.
     44
    1452006-10-31  Beth Dakin  <bdakin@apple.com>
    246
  • trunk/WebCore/html/HTMLSelectElement.cpp

    r17331 r17498  
    6767    , m_recalcListItems(false)
    6868    , m_lastOnChangeIndex(0)
     69    , m_activeSelectionAnchorIndex(-1)
     70    , m_activeSelectionEndIndex(-1)
     71    , m_activeSelectionState(false)
    6972    , m_repeatingChar(0)
    7073    , m_lastCharTime(0)
     
    162165    int listIndex = optionToListIndex(optionIndex);
    163166    HTMLOptionElement* element = 0;
     167
    164168    if (listIndex >= 0) {
    165169        element = static_cast<HTMLOptionElement*>(items[listIndex]);
    166170        element->setSelected(true);
    167171    }
     172
    168173    if (deselect)
    169174        deselectItems(element);
    170     if (fireOnChange && m_lastOnChangeIndex != optionIndex) {
     175
     176    if (listIndex >= 0) {
     177        if (m_activeSelectionAnchorIndex < 0 || deselect)
     178            setActiveSelectionAnchorIndex(listIndex);
     179        if (m_activeSelectionEndIndex < 0 || deselect)
     180            setActiveSelectionEndIndex(listIndex);
     181    }
     182
     183    if (usesMenuList() && fireOnChange && m_lastOnChangeIndex != optionIndex) {
    171184        m_lastOnChangeIndex = optionIndex;
    172185        onChange();
     
    523536{
    524537#if !ARROW_KEYS_POP_MENU
    525     if (selectedIndex() != m_lastOnChangeIndex) {
     538    if (usesMenuList() && selectedIndex() != m_lastOnChangeIndex) {
    526539        m_lastOnChangeIndex = selectedIndex();
    527540        onChange();
     
    617630    if (evt->type() == mousedownEvent) {
    618631        MouseEvent* mEvt = static_cast<MouseEvent*>(evt);
    619         if (HTMLOptionElement* element = static_cast<RenderListBox*>(renderer())->optionAtPoint(mEvt->x(), mEvt->y())) {
    620             bool deselectOtherOptions = true;
    621             bool shouldSelect = true;
     632        int listIndex = static_cast<RenderListBox*>(renderer())->listIndexAtOffset(mEvt->offsetX(), mEvt->offsetY());
     633        if (listIndex >= 0) {
     634            m_activeSelectionState = true;
    622635           
    623636            bool multiSelectKeyPressed = false;
     
    627640            multiSelectKeyPressed = mEvt->ctrlKey();
    628641#endif
    629             if (multiple() && multiSelectKeyPressed)
    630                 deselectOtherOptions = false;
    631             if (element->selected() && multiSelectKeyPressed)
    632                 shouldSelect = false;
     642
     643            bool shiftSelect = multiple() && mEvt->shiftKey();
     644            bool multiSelect = multiple() && multiSelectKeyPressed && !mEvt->shiftKey();
    633645           
    634             int optionIndex = element->index();
    635             if (!shouldSelect) {
    636                 optionIndex = -1;
    637                 element->m_selected = false;
     646            HTMLElement* clickedElement = listItems()[listIndex];           
     647            HTMLOptionElement* option = 0;
     648            if (clickedElement->hasLocalName(optionTag)) {
     649                option = static_cast<HTMLOptionElement*>(clickedElement);
     650               
     651                // Keep track of whether an active selection (like during drag selection), should select or deselect
     652                if (option->selected() && multiSelectKeyPressed)
     653                    m_activeSelectionState = false;
     654
     655                if (!m_activeSelectionState)
     656                    option->m_selected = false;
    638657            }
    639             setSelectedIndex(optionIndex, deselectOtherOptions);
    640         }
    641     } else if (evt->type() == keypressEvent) {
     658           
     659            // If we're not in any special multiple selection mode, then deselect all other items, excluding the clicked option.
     660            // If no option was clicked, then this will deselect all items in the list.
     661            if (!shiftSelect && !multiSelect)
     662                deselectItems(option);
     663
     664            // 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.
     665            if (m_activeSelectionAnchorIndex < 0 && !multiSelect)
     666                setActiveSelectionAnchorIndex(selectedIndex());
     667
     668            // Set the selection state of the clicked option
     669            if (option && !option->disabled())
     670                option->m_selected = true;
     671           
     672            // If there was no selectedIndex() for the previous initialization, or
     673            // 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.
     674            if (listIndex >= 0 && (m_activeSelectionAnchorIndex < 0 || !shiftSelect))
     675                setActiveSelectionAnchorIndex(listIndex);
     676           
     677            setActiveSelectionEndIndex(listIndex);
     678            updateListBoxSelection(!multiSelect);
     679            renderer()->repaint();
     680        }
     681    } else if (evt->type() == mouseupEvent && document()->frame()->autoscrollRenderer() != renderer())
     682        // This makes sure we fire onChange for a single click.  For drag selection, onChange will fire when the autoscroll timer stops.
     683        listBoxOnChange();
     684    else if (evt->type() == keypressEvent) {
    642685        if (!evt->isKeyboardEvent())
    643686            return;
    644687        String keyIdentifier = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
    645688       
    646         int index = 0;
     689        int endIndex = 0;
    647690        const Vector<HTMLElement*>& items = listItems();
    648 
    649         if (keyIdentifier == "Down") {
    650             index = nextSelectableListIndex(lastSelectedListIndex());
     691       
     692        if (m_activeSelectionEndIndex < 0) {
     693            // Initialize the end index
     694            if (keyIdentifier == "Down")
     695                endIndex = nextSelectableListIndex(lastSelectedListIndex());
     696            else if (keyIdentifier == "Up")
     697                endIndex = previousSelectableListIndex(optionToListIndex(selectedIndex()));
     698        } else {
     699            // Set the end index based on the current end index
     700            if (keyIdentifier == "Down")
     701                endIndex = nextSelectableListIndex(m_activeSelectionEndIndex);
     702            else if (keyIdentifier == "Up")
     703                endIndex = previousSelectableListIndex(m_activeSelectionEndIndex);   
     704        }
     705       
     706        if (keyIdentifier == "Down" || keyIdentifier == "Up") {
     707            ASSERT(endIndex >= 0 && (unsigned)endIndex < items.size());
     708            setActiveSelectionEndIndex(endIndex);
    651709           
    652         } else if (keyIdentifier == "Up") {
    653             index = previousSelectableListIndex(optionToListIndex(selectedIndex()));
    654         }
    655         if (keyIdentifier == "Down" || keyIdentifier == "Up") {
    656             ASSERT(index >= 0 && (unsigned)index < items.size());
    657             HTMLOptionElement* element = static_cast<HTMLOptionElement*>(items[index]);
     710            // 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.
     711            bool deselectOthers = !multiple() || !static_cast<KeyboardEvent*>(evt)->shiftKey();
     712            if (m_activeSelectionAnchorIndex < 0 || deselectOthers) {
     713                m_activeSelectionState = true;
     714                if (deselectOthers)
     715                    deselectItems();
     716                setActiveSelectionAnchorIndex(m_activeSelectionEndIndex);
     717            }
     718
     719            static_cast<RenderListBox*>(renderer())->scrollToRevealElementAtListIndex(endIndex);
     720            evt->setDefaultHandled();
     721            updateListBoxSelection(deselectOthers);
     722            renderer()->repaint();
    658723           
    659             setSelectedIndex(element->index(), !multiple() || !static_cast<KeyboardEvent*>(evt)->shiftKey());
    660             static_cast<RenderListBox*>(renderer())->scrollToRevealElementAtListIndex(index);
    661            
    662             evt->setDefaultHandled();
    663             setChanged();
    664             renderer()->repaint();
    665         }
    666     }
     724            listBoxOnChange();
     725        }
     726    }
     727}
     728
     729void HTMLSelectElement::setActiveSelectionAnchorIndex(int index)
     730{
     731    m_activeSelectionAnchorIndex = index;
     732   
     733    // Cache the selection state so we can restore the old selection as the new selection pivots around this anchor index
     734    const Vector<HTMLElement*>& items = listItems();
     735    m_cachedStateForActiveSelection.clear();
     736    for (unsigned i = 0; i < items.size(); i++) {
     737        if (items[i]->hasLocalName(optionTag)) {
     738            HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]);
     739            m_cachedStateForActiveSelection.append(option->selected());
     740        } else
     741            m_cachedStateForActiveSelection.append(false);
     742    }
     743}
     744
     745void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions)
     746{
     747    unsigned start;
     748    unsigned end;
     749    ASSERT(m_activeSelectionAnchorIndex >= 0);
     750    start = min(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex);
     751    end = max(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex);
     752
     753    const Vector<HTMLElement*>& items = listItems();
     754    for (unsigned i = 0; i < items.size(); i++) {
     755        if (items[i]->hasLocalName(optionTag)) {
     756            HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]);
     757            if (!option->disabled()) {
     758                if (i >= start && i <= end)
     759                    option->m_selected = m_activeSelectionState;
     760                else if (deselectOtherOptions)
     761                    option->m_selected = false;
     762                else
     763                    option->m_selected = m_cachedStateForActiveSelection[i];
     764            }
     765        }
     766    }
     767    if (renderer()->isListBox())
     768        static_cast<RenderListBox*>(renderer())->setSelectionChanged(true);
     769}
     770
     771void HTMLSelectElement::listBoxOnChange()
     772{
     773    const Vector<HTMLElement*>& items = listItems();
     774   
     775    // If the cached selection list is empty, or the size has changed, then rebuild the list, fire onChange, and return early.
     776    if (m_lastOnChangeSelection.isEmpty() || m_lastOnChangeSelection.size() != items.size()) {
     777        m_lastOnChangeSelection.clear();
     778        for (unsigned i = 0; i < items.size(); i++) {
     779            if (items[i]->hasLocalName(optionTag)) {
     780                HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]);
     781                m_lastOnChangeSelection.append(option->selected());
     782            } else
     783                m_lastOnChangeSelection.append(false);
     784        }
     785        onChange();
     786        return;
     787    }
     788   
     789    // Update m_lastOnChangeSelection and fire onChange
     790    bool fireOnChange = false;
     791    for (unsigned i = 0; i < items.size(); i++) {
     792        bool selected = false;
     793        if (items[i]->hasLocalName(optionTag))
     794            selected = static_cast<HTMLOptionElement*>(items[i])->selected();
     795        if (selected != m_lastOnChangeSelection[i])     
     796            fireOnChange = true;
     797        m_lastOnChangeSelection[i] = selected;
     798    }
     799    if (fireOnChange)
     800        onChange();
    667801}
    668802
  • trunk/WebCore/html/HTMLSelectElement.h

    r17331 r17498  
    6262    void setSelectedIndex(int index, bool deselect = true, bool fireOnChange = false);
    6363    void notifyOptionSelected(HTMLOptionElement* selectedOption, bool selected);
    64    
     64    int lastSelectedListIndex() const;
     65
    6566    virtual bool isEnumeratable() const { return true; }
    6667
     
    126127    HTMLCollection::CollectionInfo* collectionInfo() { return &m_collectionInfo; }
    127128   
     129    void setActiveSelectionAnchorIndex(int index);
     130    void setActiveSelectionEndIndex(int index) { m_activeSelectionEndIndex = index; }
     131    void updateListBoxSelection(bool deselectOtherOptions);
     132    void listBoxOnChange();
     133
    128134private:
    129135    void recalcListItems() const;
    130     void deselectItems(HTMLOptionElement* excludeElement);
     136    void deselectItems(HTMLOptionElement* excludeElement = 0);
    131137    bool usesMenuList() const { return !m_multiple && m_size <= 1; }
    132     int lastSelectedListIndex() const;
    133138    int nextSelectableListIndex(int startIndex);
    134139    int previousSelectableListIndex(int startIndex);
     
    138143
    139144    mutable Vector<HTMLElement*> m_listItems;
     145    Vector<bool> m_cachedStateForActiveSelection;
     146    Vector<bool> m_lastOnChangeSelection;
    140147    int m_minwidth;
    141148    int m_size;
     
    143150    mutable bool m_recalcListItems;
    144151    int m_lastOnChangeIndex;
     152   
     153    int m_activeSelectionAnchorIndex;
     154    int m_activeSelectionEndIndex; 
     155    bool m_activeSelectionState;
    145156
    146157    // Instance variables for type-ahead find
  • trunk/WebCore/page/Frame.cpp

    r17494 r17498  
    28562856}
    28572857
    2858 void Frame::stopAutoscrollTimer()
    2859 {
     2858void Frame::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
     2859{
     2860    if (!rendererIsBeingDestroyed && autoscrollRenderer())
     2861        autoscrollRenderer()->stopAutoscroll();
    28602862    setAutoscrollRenderer(0);
    28612863    d->m_autoscrollTimer.stop();
  • trunk/WebCore/page/Frame.h

    r17484 r17498  
    727727  void setNeedsReapplyStyles();
    728728
    729   void stopAutoscrollTimer();
     729  void stopAutoscrollTimer(bool rendererIsBeingDestroyed = false);
    730730  RenderObject* autoscrollRenderer() const;
    731731
  • trunk/WebCore/rendering/RenderListBox.cpp

    r17448 r17498  
    111111    }
    112112   
    113     scrollToRevealElementAtListIndex(select->optionToListIndex(select->selectedIndex()));
     113    int firstIndex = select->optionToListIndex(select->selectedIndex());
     114    int lastIndex = select->lastSelectedListIndex();
     115    if (firstIndex >= 0 && !listIndexIsVisible(firstIndex) && !listIndexIsVisible(lastIndex))
     116        scrollToRevealElementAtListIndex(firstIndex);
    114117}
    115118
     
    344347}
    345348
    346 HTMLOptionElement* RenderListBox::optionAtPoint(int x, int y)
     349int RenderListBox::listIndexAtOffset(int offsetX, int offsetY)
    347350{
    348351    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
    349352    const Vector<HTMLElement*>& listItems = select->listItems();
    350     int yOffset = y - absoluteBoundingBoxRect().y();
    351     int newOffset = max(0, yOffset / (style()->font().height() + optionsSpacingMiddle)) + m_indexOffset;
     353
     354    int newOffset = max(0, offsetY / (style()->font().height() + optionsSpacingMiddle)) + m_indexOffset;
    352355    newOffset = max(0, min((int)listItems.size() - 1, newOffset));
    353356    int scrollbarWidth = m_vBar ? m_vBar->width() : 0;
    354     if (x >= absoluteBoundingBoxRect().x() + borderLeft() + paddingLeft() && x < absoluteBoundingBoxRect().right() - borderRight() - paddingRight() - scrollbarWidth)
    355         return static_cast<HTMLOptionElement*>(listItems[newOffset]);
    356     return 0;
     357    if (offsetX >= borderLeft() + paddingLeft() && offsetX < absoluteBoundingBoxRect().width() - borderRight() - paddingRight() - scrollbarWidth)
     358        return newOffset;
     359           
     360    return -1;
    357361}
    358362
     
    360364{
    361365    IntPoint pos = document()->frame()->view()->windowToContents(document()->frame()->view()->currentMousePosition());
    362     IntRect bounds = absoluteBoundingBoxRect();
    363 
    364     HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
    365     const Vector<HTMLElement*>& items = select->listItems();
    366     HTMLOptionElement* element = 0;
     366
     367    int rx = 0;
     368    int ry = 0;
     369    absolutePosition(rx, ry);
     370    int offsetX = pos.x() - rx;
     371    int offsetY = pos.y() - ry;
     372   
     373    int endIndex = -1;
    367374    int rows = size();
    368375    int offset = m_indexOffset;
    369     if (pos.y() < bounds.y() && scrollToRevealElementAtListIndex(offset - 1) && items[offset - 1]->hasTagName(optionTag))
    370         element = static_cast<HTMLOptionElement*>(items[offset - 1]);
    371     else if (pos.y() > bounds.bottom() && scrollToRevealElementAtListIndex(offset + rows) && items[offset + rows - 1]->hasTagName(optionTag))
    372         element = static_cast<HTMLOptionElement*>(items[offset + rows - 1]);
     376    if (offsetY <  0 && scrollToRevealElementAtListIndex(offset - 1))
     377        endIndex = offset - 1;
     378    else if (offsetY > absoluteBoundingBoxRect().height() && scrollToRevealElementAtListIndex(offset + rows))
     379        endIndex = offset + rows - 1;
    373380    else
    374         element = optionAtPoint(pos.x(), pos.y());
    375        
    376     if (element) {
    377         select->setSelectedIndex(element->index(), !select->multiple());
     381        endIndex = listIndexAtOffset(offsetX, offsetY);
     382
     383    HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node());
     384    if (endIndex >= 0 && select) {
     385        if (!select->multiple())
     386            select->setActiveSelectionAnchorIndex(endIndex);
     387        select->setActiveSelectionEndIndex(endIndex);
     388        select->updateListBoxSelection(!select->multiple());
    378389        repaint();
    379390    }
    380391}
    381392
     393void RenderListBox::stopAutoscroll()
     394{
     395    if ( HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()))
     396        select->listBoxOnChange();
     397}
     398
    382399bool RenderListBox::scrollToRevealElementAtListIndex(int index)
    383400{
     
    385402    const Vector<HTMLElement*>& listItems = select->listItems();
    386403   
    387     if (index < 0 || index > (int)listItems.size() - 1 || (index >= m_indexOffset && index < m_indexOffset + size()))
     404    if (index < 0 || index > (int)listItems.size() - 1 || listIndexIsVisible(index))
    388405        return false;
    389406
     
    403420}
    404421
     422bool RenderListBox::listIndexIsVisible(int index)
     423{   
     424    return index >= m_indexOffset && index < m_indexOffset + size();
     425}
     426
    405427bool RenderListBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
    406428{
     
    421443        if (newOffset != m_indexOffset) {
    422444            m_indexOffset = newOffset;
    423         //    printf("value changed: new offset index: %d\n", newOffset);
    424445            repaint();
    425446            // Fire the scroll DOM event.
  • trunk/WebCore/rendering/RenderListBox.h

    r17448 r17498  
    2828namespace WebCore {
    2929
     30class HTMLElement;
    3031class HTMLSelectElement;
    3132class HTMLOptionElement;
     
    6162    virtual IntRect windowClipRect() const;
    6263
    63     HTMLOptionElement* optionAtPoint(int x, int y);
     64    int listIndexAtOffset(int x, int y);
    6465
    6566    bool scrollToRevealElementAtListIndex(int index);
    6667
    67     virtual bool shouldAutoscroll() const { return numItems() > size(); }
     68    virtual bool shouldAutoscroll() const { return true; }
    6869    virtual void autoscroll();
     70    virtual void stopAutoscroll();
    6971
    7072private:
     
    7577    void paintItemForeground(PaintInfo&, int tx, int ty, int listIndex);
    7678    void paintItemBackground(PaintInfo&, int tx, int ty, int listIndex);
     79    bool listIndexIsVisible(int index);
    7780
    7881    bool m_optionsChanged;
  • trunk/WebCore/rendering/RenderObject.cpp

    r17494 r17498  
    24662466    // If this renderer is being autoscrolled, stop the autoscroll timer
    24672467    if (document() && document()->frame() && document()->frame()->autoscrollRenderer() == this)
    2468         document()->frame()->stopAutoscrollTimer();
     2468        document()->frame()->stopAutoscrollTimer(true);
    24692469
    24702470    if (m_hasCounterNodeMap) {
  • trunk/WebCore/rendering/RenderObject.h

    r17494 r17498  
    609609    virtual bool shouldAutoscroll() const;
    610610    virtual void autoscroll();
     611    virtual void stopAutoscroll() {};
    611612
    612613    // The following seven functions are used to implement collapsing margins.
Note: See TracChangeset for help on using the changeset viewer.