Home | History | Annotate | Download | only in rendering
      1 /*
      2  * This file is part of the select element renderer in WebCore.
      3  *
      4  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
      5  *               2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  *
     11  * 1.  Redistributions of source code must retain the above copyright
     12  *     notice, this list of conditions and the following disclaimer.
     13  * 2.  Redistributions in binary form must reproduce the above copyright
     14  *     notice, this list of conditions and the following disclaimer in the
     15  *     documentation and/or other materials provided with the distribution.
     16  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     17  *     its contributors may be used to endorse or promote products derived
     18  *     from this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     21  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     23  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     27  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include "config.h"
     33 #include "RenderListBox.h"
     34 
     35 #include "AXObjectCache.h"
     36 #include "CSSStyleSelector.h"
     37 #include "Document.h"
     38 #include "EventHandler.h"
     39 #include "EventNames.h"
     40 #include "FocusController.h"
     41 #include "Frame.h"
     42 #include "FrameView.h"
     43 #include "GraphicsContext.h"
     44 #include "HTMLNames.h"
     45 #include "HitTestResult.h"
     46 #include "OptionGroupElement.h"
     47 #include "OptionElement.h"
     48 #include "Page.h"
     49 #include "RenderScrollbar.h"
     50 #include "RenderTheme.h"
     51 #include "RenderView.h"
     52 #include "Scrollbar.h"
     53 #include "SelectElement.h"
     54 #include "SelectionController.h"
     55 #include "NodeRenderStyle.h"
     56 #include <math.h>
     57 
     58 using namespace std;
     59 
     60 namespace WebCore {
     61 
     62 using namespace HTMLNames;
     63 
     64 const int rowSpacing = 1;
     65 
     66 const int optionsSpacingHorizontal = 2;
     67 
     68 const int minSize = 4;
     69 const int maxDefaultSize = 10;
     70 
     71 // FIXME: This hardcoded baselineAdjustment is what we used to do for the old
     72 // widget, but I'm not sure this is right for the new control.
     73 const int baselineAdjustment = 7;
     74 
     75 RenderListBox::RenderListBox(Element* element)
     76     : RenderBlock(element)
     77     , m_optionsChanged(true)
     78     , m_scrollToRevealSelectionAfterLayout(false)
     79     , m_inAutoscroll(false)
     80     , m_optionsWidth(0)
     81     , m_indexOffset(0)
     82 {
     83 }
     84 
     85 RenderListBox::~RenderListBox()
     86 {
     87     setHasVerticalScrollbar(false);
     88 }
     89 
     90 void RenderListBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
     91 {
     92     RenderBlock::styleDidChange(diff, oldStyle);
     93     setReplaced(isInline());
     94 }
     95 
     96 void RenderListBox::updateFromElement()
     97 {
     98     if (m_optionsChanged) {
     99         const Vector<Element*>& listItems = toSelectElement(static_cast<Element*>(node()))->listItems();
    100         int size = numItems();
    101 
    102         float width = 0;
    103         for (int i = 0; i < size; ++i) {
    104             Element* element = listItems[i];
    105             String text;
    106             Font itemFont = style()->font();
    107             if (OptionElement* optionElement = toOptionElement(element))
    108                 text = optionElement->textIndentedToRespectGroupLabel();
    109             else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) {
    110                 text = optionGroupElement->groupLabelText();
    111                 FontDescription d = itemFont.fontDescription();
    112                 d.setWeight(d.bolderWeight());
    113                 itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
    114                 itemFont.update(document()->styleSelector()->fontSelector());
    115             }
    116 
    117             if (!text.isEmpty()) {
    118                 float textWidth = itemFont.floatWidth(TextRun(text.impl(), 0, 0, 0, false, false, false, false));
    119                 width = max(width, textWidth);
    120             }
    121         }
    122         m_optionsWidth = static_cast<int>(ceilf(width));
    123         m_optionsChanged = false;
    124 
    125         setHasVerticalScrollbar(true);
    126 
    127         setNeedsLayoutAndPrefWidthsRecalc();
    128     }
    129 }
    130 
    131 void RenderListBox::selectionChanged()
    132 {
    133     repaint();
    134     if (!m_inAutoscroll) {
    135         if (m_optionsChanged || needsLayout())
    136             m_scrollToRevealSelectionAfterLayout = true;
    137         else
    138             scrollToRevealSelection();
    139     }
    140 
    141     if (AXObjectCache::accessibilityEnabled())
    142         document()->axObjectCache()->selectedChildrenChanged(this);
    143 }
    144 
    145 void RenderListBox::layout()
    146 {
    147     RenderBlock::layout();
    148     if (m_scrollToRevealSelectionAfterLayout)
    149         scrollToRevealSelection();
    150 }
    151 
    152 void RenderListBox::scrollToRevealSelection()
    153 {
    154     SelectElement* select = toSelectElement(static_cast<Element*>(node()));
    155 
    156     m_scrollToRevealSelectionAfterLayout = false;
    157 
    158     int firstIndex = select->activeSelectionStartListIndex();
    159     if (firstIndex >= 0 && !listIndexIsVisible(select->activeSelectionEndListIndex()))
    160         scrollToRevealElementAtListIndex(firstIndex);
    161 }
    162 
    163 void RenderListBox::calcPrefWidths()
    164 {
    165     ASSERT(!m_optionsChanged);
    166 
    167     m_minPrefWidth = 0;
    168     m_maxPrefWidth = 0;
    169 
    170     if (style()->width().isFixed() && style()->width().value() > 0)
    171         m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
    172     else {
    173         m_maxPrefWidth = m_optionsWidth + 2 * optionsSpacingHorizontal;
    174         if (m_vBar)
    175             m_maxPrefWidth += m_vBar->width();
    176     }
    177 
    178     if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
    179         m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
    180         m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
    181     } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
    182         m_minPrefWidth = 0;
    183     else
    184         m_minPrefWidth = m_maxPrefWidth;
    185 
    186     if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
    187         m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
    188         m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
    189     }
    190 
    191     int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight();
    192     m_minPrefWidth += toAdd;
    193     m_maxPrefWidth += toAdd;
    194 
    195     setPrefWidthsDirty(false);
    196 }
    197 
    198 int RenderListBox::size() const
    199 {
    200     int specifiedSize = toSelectElement(static_cast<Element*>(node()))->size();
    201     if (specifiedSize > 1)
    202         return max(minSize, specifiedSize);
    203     return min(max(minSize, numItems()), maxDefaultSize);
    204 }
    205 
    206 int RenderListBox::numVisibleItems() const
    207 {
    208     // Only count fully visible rows. But don't return 0 even if only part of a row shows.
    209     return max(1, (contentHeight() + rowSpacing) / itemHeight());
    210 }
    211 
    212 int RenderListBox::numItems() const
    213 {
    214     return toSelectElement(static_cast<Element*>(node()))->listItems().size();
    215 }
    216 
    217 int RenderListBox::listHeight() const
    218 {
    219     return itemHeight() * numItems() - rowSpacing;
    220 }
    221 
    222 void RenderListBox::calcHeight()
    223 {
    224     int toAdd = paddingTop() + paddingBottom() + borderTop() + borderBottom();
    225 
    226     int itemHeight = RenderListBox::itemHeight();
    227     setHeight(itemHeight * size() - rowSpacing + toAdd);
    228 
    229     RenderBlock::calcHeight();
    230 
    231     if (m_vBar) {
    232         bool enabled = numVisibleItems() < numItems();
    233         m_vBar->setEnabled(enabled);
    234         m_vBar->setSteps(1, min(1, numVisibleItems() - 1), itemHeight);
    235         m_vBar->setProportion(numVisibleItems(), numItems());
    236         if (!enabled)
    237             m_indexOffset = 0;
    238     }
    239 }
    240 
    241 int RenderListBox::baselinePosition(bool, bool) const
    242 {
    243     return height() + marginTop() + marginBottom() - baselineAdjustment;
    244 }
    245 
    246 IntRect RenderListBox::itemBoundingBoxRect(int tx, int ty, int index)
    247 {
    248     return IntRect(tx + borderLeft() + paddingLeft(),
    249                    ty + borderTop() + paddingTop() + itemHeight() * (index - m_indexOffset),
    250                    contentWidth(), itemHeight());
    251 }
    252 
    253 void RenderListBox::paintObject(PaintInfo& paintInfo, int tx, int ty)
    254 {
    255     if (style()->visibility() != VISIBLE)
    256         return;
    257 
    258     int listItemsSize = numItems();
    259 
    260     if (paintInfo.phase == PaintPhaseForeground) {
    261         int index = m_indexOffset;
    262         while (index < listItemsSize && index <= m_indexOffset + numVisibleItems()) {
    263             paintItemForeground(paintInfo, tx, ty, index);
    264             index++;
    265         }
    266     }
    267 
    268     // Paint the children.
    269     RenderBlock::paintObject(paintInfo, tx, ty);
    270 
    271     if (paintInfo.phase == PaintPhaseBlockBackground)
    272         paintScrollbar(paintInfo, tx, ty);
    273     else if (paintInfo.phase == PaintPhaseChildBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) {
    274         int index = m_indexOffset;
    275         while (index < listItemsSize && index <= m_indexOffset + numVisibleItems()) {
    276             paintItemBackground(paintInfo, tx, ty, index);
    277             index++;
    278         }
    279     }
    280 }
    281 
    282 void RenderListBox::paintScrollbar(PaintInfo& paintInfo, int tx, int ty)
    283 {
    284     if (m_vBar) {
    285         IntRect scrollRect(tx + width() - borderRight() - m_vBar->width(),
    286                            ty + borderTop(),
    287                            m_vBar->width(),
    288                            height() - (borderTop() + borderBottom()));
    289         m_vBar->setFrameRect(scrollRect);
    290         m_vBar->paint(paintInfo.context, paintInfo.rect);
    291     }
    292 }
    293 
    294 void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, int listIndex)
    295 {
    296     SelectElement* select = toSelectElement(static_cast<Element*>(node()));
    297     const Vector<Element*>& listItems = select->listItems();
    298     Element* element = listItems[listIndex];
    299     OptionElement* optionElement = toOptionElement(element);
    300 
    301     String itemText;
    302     if (optionElement)
    303         itemText = optionElement->textIndentedToRespectGroupLabel();
    304     else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element))
    305         itemText = optionGroupElement->groupLabelText();
    306 
    307     // Determine where the item text should be placed
    308     IntRect r = itemBoundingBoxRect(tx, ty, listIndex);
    309     r.move(optionsSpacingHorizontal, style()->font().ascent());
    310 
    311     RenderStyle* itemStyle = element->renderStyle();
    312     if (!itemStyle)
    313         itemStyle = style();
    314 
    315     Color textColor = element->renderStyle() ? element->renderStyle()->color() : style()->color();
    316     if (optionElement && optionElement->selected()) {
    317         if (document()->frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node())
    318             textColor = theme()->activeListBoxSelectionForegroundColor();
    319         // Honor the foreground color for disabled items
    320         else if (!element->disabled())
    321             textColor = theme()->inactiveListBoxSelectionForegroundColor();
    322     }
    323 
    324     ColorSpace colorSpace = itemStyle->colorSpace();
    325     paintInfo.context->setFillColor(textColor, colorSpace);
    326 
    327     Font itemFont = style()->font();
    328     if (isOptionGroupElement(element)) {
    329         FontDescription d = itemFont.fontDescription();
    330         d.setWeight(d.bolderWeight());
    331         itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
    332         itemFont.update(document()->styleSelector()->fontSelector());
    333     }
    334 
    335     unsigned length = itemText.length();
    336     const UChar* string = itemText.characters();
    337     TextRun textRun(string, length, 0, 0, 0, itemStyle->direction() == RTL, itemStyle->unicodeBidi() == Override, false, false);
    338 
    339     // Draw the item text
    340     if (itemStyle->visibility() != HIDDEN)
    341         paintInfo.context->drawBidiText(itemFont, textRun, r.location());
    342 }
    343 
    344 void RenderListBox::paintItemBackground(PaintInfo& paintInfo, int tx, int ty, int listIndex)
    345 {
    346     SelectElement* select = toSelectElement(static_cast<Element*>(node()));
    347     const Vector<Element*>& listItems = select->listItems();
    348     Element* element = listItems[listIndex];
    349     OptionElement* optionElement = toOptionElement(element);
    350 
    351     Color backColor;
    352     if (optionElement && optionElement->selected()) {
    353         if (document()->frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node())
    354             backColor = theme()->activeListBoxSelectionBackgroundColor();
    355         else
    356             backColor = theme()->inactiveListBoxSelectionBackgroundColor();
    357     } else
    358         backColor = element->renderStyle() ? element->renderStyle()->backgroundColor() : style()->backgroundColor();
    359 
    360     // Draw the background for this list box item
    361     if (!element->renderStyle() || element->renderStyle()->visibility() != HIDDEN) {
    362         ColorSpace colorSpace = element->renderStyle() ? element->renderStyle()->colorSpace() : style()->colorSpace();
    363         IntRect itemRect = itemBoundingBoxRect(tx, ty, listIndex);
    364         itemRect.intersect(controlClipRect(tx, ty));
    365         paintInfo.context->fillRect(itemRect, backColor, colorSpace);
    366     }
    367 }
    368 
    369 bool RenderListBox::isPointInOverflowControl(HitTestResult& result, int _x, int _y, int _tx, int _ty)
    370 {
    371     if (!m_vBar)
    372         return false;
    373 
    374     IntRect vertRect(_tx + width() - borderRight() - m_vBar->width(),
    375                      _ty + borderTop(),
    376                      m_vBar->width(),
    377                      height() - borderTop() - borderBottom());
    378 
    379     if (vertRect.contains(_x, _y)) {
    380         result.setScrollbar(m_vBar.get());
    381         return true;
    382     }
    383     return false;
    384 }
    385 
    386 int RenderListBox::listIndexAtOffset(int offsetX, int offsetY)
    387 {
    388     if (!numItems())
    389         return -1;
    390 
    391     if (offsetY < borderTop() + paddingTop() || offsetY > height() - paddingBottom() - borderBottom())
    392         return -1;
    393 
    394     int scrollbarWidth = m_vBar ? m_vBar->width() : 0;
    395     if (offsetX < borderLeft() + paddingLeft() || offsetX > width() - borderRight() - paddingRight() - scrollbarWidth)
    396         return -1;
    397 
    398     int newOffset = (offsetY - borderTop() - paddingTop()) / itemHeight() + m_indexOffset;
    399     return newOffset < numItems() ? newOffset : -1;
    400 }
    401 
    402 void RenderListBox::panScroll(const IntPoint& panStartMousePosition)
    403 {
    404     const int maxSpeed = 20;
    405     const int iconRadius = 7;
    406     const int speedReducer = 4;
    407 
    408     // FIXME: This doesn't work correctly with transforms.
    409     FloatPoint absOffset = localToAbsolute();
    410 
    411     IntPoint currentMousePosition = document()->frame()->eventHandler()->currentMousePosition();
    412     // We need to check if the current mouse position is out of the window. When the mouse is out of the window, the position is incoherent
    413     static IntPoint previousMousePosition;
    414     if (currentMousePosition.y() < 0)
    415         currentMousePosition = previousMousePosition;
    416     else
    417         previousMousePosition = currentMousePosition;
    418 
    419     int yDelta = currentMousePosition.y() - panStartMousePosition.y();
    420 
    421     // If the point is too far from the center we limit the speed
    422     yDelta = max(min(yDelta, maxSpeed), -maxSpeed);
    423 
    424     if (abs(yDelta) < iconRadius) // at the center we let the space for the icon
    425         return;
    426 
    427     if (yDelta > 0)
    428         //offsetY = view()->viewHeight();
    429         absOffset.move(0, listHeight());
    430     else if (yDelta < 0)
    431         yDelta--;
    432 
    433     // Let's attenuate the speed
    434     yDelta /= speedReducer;
    435 
    436     IntPoint scrollPoint(0, 0);
    437     scrollPoint.setY(absOffset.y() + yDelta);
    438     int newOffset = scrollToward(scrollPoint);
    439     if (newOffset < 0)
    440         return;
    441 
    442     m_inAutoscroll = true;
    443     SelectElement* select = toSelectElement(static_cast<Element*>(node()));
    444     select->updateListBoxSelection(!select->multiple());
    445     m_inAutoscroll = false;
    446 }
    447 
    448 int RenderListBox::scrollToward(const IntPoint& destination)
    449 {
    450     // FIXME: This doesn't work correctly with transforms.
    451     FloatPoint absPos = localToAbsolute();
    452     int offsetX = destination.x() - absPos.x();
    453     int offsetY = destination.y() - absPos.y();
    454 
    455     int rows = numVisibleItems();
    456     int offset = m_indexOffset;
    457 
    458     if (offsetY < borderTop() + paddingTop() && scrollToRevealElementAtListIndex(offset - 1))
    459         return offset - 1;
    460 
    461     if (offsetY > height() - paddingBottom() - borderBottom() && scrollToRevealElementAtListIndex(offset + rows))
    462         return offset + rows - 1;
    463 
    464     return listIndexAtOffset(offsetX, offsetY);
    465 }
    466 
    467 void RenderListBox::autoscroll()
    468 {
    469     IntPoint pos = document()->frame()->view()->windowToContents(document()->frame()->eventHandler()->currentMousePosition());
    470 
    471     int endIndex = scrollToward(pos);
    472     if (endIndex >= 0) {
    473         SelectElement* select = toSelectElement(static_cast<Element*>(node()));
    474         m_inAutoscroll = true;
    475 
    476         if (!select->multiple())
    477             select->setActiveSelectionAnchorIndex(endIndex);
    478 
    479         select->setActiveSelectionEndIndex(endIndex);
    480         select->updateListBoxSelection(!select->multiple());
    481         m_inAutoscroll = false;
    482     }
    483 }
    484 
    485 void RenderListBox::stopAutoscroll()
    486 {
    487     toSelectElement(static_cast<Element*>(node()))->listBoxOnChange();
    488 }
    489 
    490 bool RenderListBox::scrollToRevealElementAtListIndex(int index)
    491 {
    492     if (index < 0 || index >= numItems() || listIndexIsVisible(index))
    493         return false;
    494 
    495     int newOffset;
    496     if (index < m_indexOffset)
    497         newOffset = index;
    498     else
    499         newOffset = index - numVisibleItems() + 1;
    500 
    501     m_indexOffset = newOffset;
    502     if (m_vBar)
    503         m_vBar->setValue(m_indexOffset);
    504 
    505     return true;
    506 }
    507 
    508 bool RenderListBox::listIndexIsVisible(int index)
    509 {
    510     return index >= m_indexOffset && index < m_indexOffset + numVisibleItems();
    511 }
    512 
    513 bool RenderListBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node**)
    514 {
    515     return m_vBar && m_vBar->scroll(direction, granularity, multiplier);
    516 }
    517 
    518 void RenderListBox::valueChanged(unsigned listIndex)
    519 {
    520     Element* element = static_cast<Element*>(node());
    521     SelectElement* select = toSelectElement(element);
    522     select->setSelectedIndex(select->listToOptionIndex(listIndex));
    523     element->dispatchFormControlChangeEvent();
    524 }
    525 
    526 void RenderListBox::valueChanged(Scrollbar*)
    527 {
    528     int newOffset = m_vBar->value();
    529     if (newOffset != m_indexOffset) {
    530         m_indexOffset = newOffset;
    531         repaint();
    532         node()->dispatchEvent(Event::create(eventNames().scrollEvent, false, false));
    533     }
    534 }
    535 
    536 int RenderListBox::itemHeight() const
    537 {
    538     return style()->font().height() + rowSpacing;
    539 }
    540 
    541 int RenderListBox::verticalScrollbarWidth() const
    542 {
    543     return m_vBar ? m_vBar->width() : 0;
    544 }
    545 
    546 // FIXME: We ignore padding in the vertical direction as far as these values are concerned, since that's
    547 // how the control currently paints.
    548 int RenderListBox::scrollWidth() const
    549 {
    550     // There is no horizontal scrolling allowed.
    551     return clientWidth();
    552 }
    553 
    554 int RenderListBox::scrollHeight() const
    555 {
    556     return max(clientHeight(), listHeight());
    557 }
    558 
    559 int RenderListBox::scrollLeft() const
    560 {
    561     return 0;
    562 }
    563 
    564 void RenderListBox::setScrollLeft(int)
    565 {
    566 }
    567 
    568 int RenderListBox::scrollTop() const
    569 {
    570     return m_indexOffset * itemHeight();
    571 }
    572 
    573 void RenderListBox::setScrollTop(int newTop)
    574 {
    575     // Determine an index and scroll to it.
    576     int index = newTop / itemHeight();
    577     if (index < 0 || index >= numItems() || index == m_indexOffset)
    578         return;
    579     m_indexOffset = index;
    580     if (m_vBar)
    581         m_vBar->setValue(index);
    582 }
    583 
    584 bool RenderListBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
    585 {
    586     if (!RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, hitTestAction))
    587         return false;
    588     const Vector<Element*>& listItems = toSelectElement(static_cast<Element*>(node()))->listItems();
    589     int size = numItems();
    590     tx += this->x();
    591     ty += this->y();
    592     for (int i = 0; i < size; ++i) {
    593         if (itemBoundingBoxRect(tx, ty, i).contains(x, y)) {
    594             if (Element* node = listItems[i]) {
    595                 result.setInnerNode(node);
    596                 if (!result.innerNonSharedNode())
    597                     result.setInnerNonSharedNode(node);
    598                 result.setLocalPoint(IntPoint(x - tx, y - ty));
    599                 break;
    600             }
    601         }
    602     }
    603 
    604     return true;
    605 }
    606 
    607 IntRect RenderListBox::controlClipRect(int tx, int ty) const
    608 {
    609     IntRect clipRect = contentBoxRect();
    610     clipRect.move(tx, ty);
    611     return clipRect;
    612 }
    613 
    614 bool RenderListBox::isActive() const
    615 {
    616     Page* page = document()->frame()->page();
    617     return page && page->focusController()->isActive();
    618 }
    619 
    620 void RenderListBox::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
    621 {
    622     IntRect scrollRect = rect;
    623     scrollRect.move(width() - borderRight() - scrollbar->width(), borderTop());
    624     repaintRectangle(scrollRect);
    625 }
    626 
    627 IntRect RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
    628 {
    629     RenderView* view = this->view();
    630     if (!view)
    631         return scrollbarRect;
    632 
    633     IntRect rect = scrollbarRect;
    634 
    635     int scrollbarLeft = width() - borderRight() - scrollbar->width();
    636     int scrollbarTop = borderTop();
    637     rect.move(scrollbarLeft, scrollbarTop);
    638 
    639     return view->frameView()->convertFromRenderer(this, rect);
    640 }
    641 
    642 IntRect RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
    643 {
    644     RenderView* view = this->view();
    645     if (!view)
    646         return parentRect;
    647 
    648     IntRect rect = view->frameView()->convertToRenderer(this, parentRect);
    649 
    650     int scrollbarLeft = width() - borderRight() - scrollbar->width();
    651     int scrollbarTop = borderTop();
    652     rect.move(-scrollbarLeft, -scrollbarTop);
    653     return rect;
    654 }
    655 
    656 IntPoint RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
    657 {
    658     RenderView* view = this->view();
    659     if (!view)
    660         return scrollbarPoint;
    661 
    662     IntPoint point = scrollbarPoint;
    663 
    664     int scrollbarLeft = width() - borderRight() - scrollbar->width();
    665     int scrollbarTop = borderTop();
    666     point.move(scrollbarLeft, scrollbarTop);
    667 
    668     return view->frameView()->convertFromRenderer(this, point);
    669 }
    670 
    671 IntPoint RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
    672 {
    673     RenderView* view = this->view();
    674     if (!view)
    675         return parentPoint;
    676 
    677     IntPoint point = view->frameView()->convertToRenderer(this, parentPoint);
    678 
    679     int scrollbarLeft = width() - borderRight() - scrollbar->width();
    680     int scrollbarTop = borderTop();
    681     point.move(-scrollbarLeft, -scrollbarTop);
    682     return point;
    683 }
    684 
    685 PassRefPtr<Scrollbar> RenderListBox::createScrollbar()
    686 {
    687     RefPtr<Scrollbar> widget;
    688     bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR);
    689     if (hasCustomScrollbarStyle)
    690         widget = RenderScrollbar::createCustomScrollbar(this, VerticalScrollbar, this);
    691     else
    692         widget = Scrollbar::createNativeScrollbar(this, VerticalScrollbar, theme()->scrollbarControlSizeForPart(ListboxPart));
    693     document()->view()->addChild(widget.get());
    694     return widget.release();
    695 }
    696 
    697 void RenderListBox::destroyScrollbar()
    698 {
    699     if (!m_vBar)
    700         return;
    701 
    702     m_vBar->removeFromParent();
    703     m_vBar->setClient(0);
    704     m_vBar = 0;
    705 }
    706 
    707 void RenderListBox::setHasVerticalScrollbar(bool hasScrollbar)
    708 {
    709     if (hasScrollbar == (m_vBar != 0))
    710         return;
    711 
    712     if (hasScrollbar)
    713         m_vBar = createScrollbar();
    714     else
    715         destroyScrollbar();
    716 
    717     if (m_vBar)
    718         m_vBar->styleChanged();
    719 
    720 #if ENABLE(DASHBOARD_SUPPORT)
    721     // Force an update since we know the scrollbars have changed things.
    722     if (document()->hasDashboardRegions())
    723         document()->setDashboardRegionsDirty(true);
    724 #endif
    725 }
    726 
    727 } // namespace WebCore
    728