diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/rendering/RenderListBox.cpp | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/rendering/RenderListBox.cpp')
-rw-r--r-- | Source/WebCore/rendering/RenderListBox.cpp | 743 |
1 files changed, 743 insertions, 0 deletions
diff --git a/Source/WebCore/rendering/RenderListBox.cpp b/Source/WebCore/rendering/RenderListBox.cpp new file mode 100644 index 0000000..ed7f8ee --- /dev/null +++ b/Source/WebCore/rendering/RenderListBox.cpp @@ -0,0 +1,743 @@ +/* + * This file is part of the select element renderer in WebCore. + * + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderListBox.h" + +#include "AXObjectCache.h" +#include "CSSStyleSelector.h" +#include "Document.h" +#include "EventHandler.h" +#include "EventNames.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HTMLNames.h" +#include "HitTestResult.h" +#include "OptionGroupElement.h" +#include "OptionElement.h" +#include "Page.h" +#include "RenderScrollbar.h" +#include "RenderTheme.h" +#include "RenderView.h" +#include "Scrollbar.h" +#include "SelectElement.h" +#include "SelectionController.h" +#include "NodeRenderStyle.h" +#include <math.h> + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +const int rowSpacing = 1; + +const int optionsSpacingHorizontal = 2; + +const int minSize = 4; +const int maxDefaultSize = 10; + +// FIXME: This hardcoded baselineAdjustment is what we used to do for the old +// widget, but I'm not sure this is right for the new control. +const int baselineAdjustment = 7; + +RenderListBox::RenderListBox(Element* element) + : RenderBlock(element) + , m_optionsChanged(true) + , m_scrollToRevealSelectionAfterLayout(false) + , m_inAutoscroll(false) + , m_optionsWidth(0) + , m_indexOffset(0) +{ +} + +RenderListBox::~RenderListBox() +{ + setHasVerticalScrollbar(false); +} + +void RenderListBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderBlock::styleDidChange(diff, oldStyle); + setReplaced(isInline()); +} + +void RenderListBox::updateFromElement() +{ + if (m_optionsChanged) { + const Vector<Element*>& listItems = toSelectElement(static_cast<Element*>(node()))->listItems(); + int size = numItems(); + + float width = 0; + for (int i = 0; i < size; ++i) { + Element* element = listItems[i]; + String text; + Font itemFont = style()->font(); + if (OptionElement* optionElement = toOptionElement(element)) + text = optionElement->textIndentedToRespectGroupLabel(); + else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) { + text = optionGroupElement->groupLabelText(); + FontDescription d = itemFont.fontDescription(); + d.setWeight(d.bolderWeight()); + itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); + itemFont.update(document()->styleSelector()->fontSelector()); + } + + if (!text.isEmpty()) { + float textWidth = itemFont.floatWidth(TextRun(text.impl(), 0, 0, 0, false, false, false, false)); + width = max(width, textWidth); + } + } + m_optionsWidth = static_cast<int>(ceilf(width)); + m_optionsChanged = false; + + setHasVerticalScrollbar(true); + + setNeedsLayoutAndPrefWidthsRecalc(); + } +} + +void RenderListBox::selectionChanged() +{ + repaint(); + if (!m_inAutoscroll) { + if (m_optionsChanged || needsLayout()) + m_scrollToRevealSelectionAfterLayout = true; + else + scrollToRevealSelection(); + } + + if (AXObjectCache::accessibilityEnabled()) + document()->axObjectCache()->selectedChildrenChanged(this); +} + +void RenderListBox::layout() +{ + RenderBlock::layout(); + if (m_scrollToRevealSelectionAfterLayout) + scrollToRevealSelection(); +} + +void RenderListBox::scrollToRevealSelection() +{ + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + + m_scrollToRevealSelectionAfterLayout = false; + + int firstIndex = select->activeSelectionStartListIndex(); + if (firstIndex >= 0 && !listIndexIsVisible(select->activeSelectionEndListIndex())) + scrollToRevealElementAtListIndex(firstIndex); +} + +void RenderListBox::computePreferredLogicalWidths() +{ + ASSERT(!m_optionsChanged); + + m_minPreferredLogicalWidth = 0; + m_maxPreferredLogicalWidth = 0; + + if (style()->width().isFixed() && style()->width().value() > 0) + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->width().value()); + else { + m_maxPreferredLogicalWidth = m_optionsWidth + 2 * optionsSpacingHorizontal; + if (m_vBar) + m_maxPreferredLogicalWidth += m_vBar->width(); + } + + if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { + m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value())); + m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value())); + } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent())) + m_minPreferredLogicalWidth = 0; + else + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth; + + if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) { + m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value())); + m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value())); + } + + int toAdd = borderAndPaddingWidth(); + m_minPreferredLogicalWidth += toAdd; + m_maxPreferredLogicalWidth += toAdd; + + setPreferredLogicalWidthsDirty(false); +} + +int RenderListBox::size() const +{ + int specifiedSize = toSelectElement(static_cast<Element*>(node()))->size(); + if (specifiedSize > 1) + return max(minSize, specifiedSize); + return min(max(minSize, numItems()), maxDefaultSize); +} + +int RenderListBox::numVisibleItems() const +{ + // Only count fully visible rows. But don't return 0 even if only part of a row shows. + return max(1, (contentHeight() + rowSpacing) / itemHeight()); +} + +int RenderListBox::numItems() const +{ + return toSelectElement(static_cast<Element*>(node()))->listItems().size(); +} + +int RenderListBox::listHeight() const +{ + return itemHeight() * numItems() - rowSpacing; +} + +void RenderListBox::computeLogicalHeight() +{ + int toAdd = borderAndPaddingHeight(); + + int itemHeight = RenderListBox::itemHeight(); + setHeight(itemHeight * size() - rowSpacing + toAdd); + + RenderBlock::computeLogicalHeight(); + + if (m_vBar) { + bool enabled = numVisibleItems() < numItems(); + m_vBar->setEnabled(enabled); + m_vBar->setSteps(1, min(1, numVisibleItems() - 1), itemHeight); + m_vBar->setProportion(numVisibleItems(), numItems()); + if (!enabled) + m_indexOffset = 0; + } +} + +int RenderListBox::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode lineDirection, LinePositionMode linePositionMode) const +{ + return RenderBox::baselinePosition(baselineType, firstLine, lineDirection, linePositionMode) - baselineAdjustment; +} + +IntRect RenderListBox::itemBoundingBoxRect(int tx, int ty, int index) +{ + return IntRect(tx + borderLeft() + paddingLeft(), + ty + borderTop() + paddingTop() + itemHeight() * (index - m_indexOffset), + contentWidth(), itemHeight()); +} + +void RenderListBox::paintObject(PaintInfo& paintInfo, int tx, int ty) +{ + if (style()->visibility() != VISIBLE) + return; + + int listItemsSize = numItems(); + + if (paintInfo.phase == PaintPhaseForeground) { + int index = m_indexOffset; + while (index < listItemsSize && index <= m_indexOffset + numVisibleItems()) { + paintItemForeground(paintInfo, tx, ty, index); + index++; + } + } + + // Paint the children. + RenderBlock::paintObject(paintInfo, tx, ty); + + if (paintInfo.phase == PaintPhaseBlockBackground) + paintScrollbar(paintInfo, tx, ty); + else if (paintInfo.phase == PaintPhaseChildBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) { + int index = m_indexOffset; + while (index < listItemsSize && index <= m_indexOffset + numVisibleItems()) { + paintItemBackground(paintInfo, tx, ty, index); + index++; + } + } +} + +void RenderListBox::paintScrollbar(PaintInfo& paintInfo, int tx, int ty) +{ + if (m_vBar) { + IntRect scrollRect(tx + width() - borderRight() - m_vBar->width(), + ty + borderTop(), + m_vBar->width(), + height() - (borderTop() + borderBottom())); + m_vBar->setFrameRect(scrollRect); + m_vBar->paint(paintInfo.context, paintInfo.rect); + } +} + +void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, int listIndex) +{ + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + const Vector<Element*>& listItems = select->listItems(); + Element* element = listItems[listIndex]; + OptionElement* optionElement = toOptionElement(element); + + String itemText; + if (optionElement) + itemText = optionElement->textIndentedToRespectGroupLabel(); + else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) + itemText = optionGroupElement->groupLabelText(); + + // Determine where the item text should be placed + IntRect r = itemBoundingBoxRect(tx, ty, listIndex); + r.move(optionsSpacingHorizontal, style()->font().ascent()); + + RenderStyle* itemStyle = element->renderStyle(); + if (!itemStyle) + itemStyle = style(); + + Color textColor = element->renderStyle() ? element->renderStyle()->visitedDependentColor(CSSPropertyColor) : style()->visitedDependentColor(CSSPropertyColor); + if (optionElement && optionElement->selected()) { + if (frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node()) + textColor = theme()->activeListBoxSelectionForegroundColor(); + // Honor the foreground color for disabled items + else if (!element->disabled()) + textColor = theme()->inactiveListBoxSelectionForegroundColor(); + } + + ColorSpace colorSpace = itemStyle->colorSpace(); + paintInfo.context->setFillColor(textColor, colorSpace); + + Font itemFont = style()->font(); + if (isOptionGroupElement(element)) { + FontDescription d = itemFont.fontDescription(); + d.setWeight(d.bolderWeight()); + itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); + itemFont.update(document()->styleSelector()->fontSelector()); + } + + unsigned length = itemText.length(); + const UChar* string = itemText.characters(); + TextRun textRun(string, length, 0, 0, 0, !itemStyle->isLeftToRightDirection(), itemStyle->unicodeBidi() == Override, false, false); + + // Draw the item text + if (itemStyle->visibility() != HIDDEN) + paintInfo.context->drawBidiText(itemFont, textRun, r.location()); +} + +void RenderListBox::paintItemBackground(PaintInfo& paintInfo, int tx, int ty, int listIndex) +{ + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + const Vector<Element*>& listItems = select->listItems(); + Element* element = listItems[listIndex]; + OptionElement* optionElement = toOptionElement(element); + + Color backColor; + if (optionElement && optionElement->selected()) { + if (frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node()) + backColor = theme()->activeListBoxSelectionBackgroundColor(); + else + backColor = theme()->inactiveListBoxSelectionBackgroundColor(); + } else + backColor = element->renderStyle() ? element->renderStyle()->visitedDependentColor(CSSPropertyBackgroundColor) : style()->visitedDependentColor(CSSPropertyBackgroundColor); + + // Draw the background for this list box item + if (!element->renderStyle() || element->renderStyle()->visibility() != HIDDEN) { + ColorSpace colorSpace = element->renderStyle() ? element->renderStyle()->colorSpace() : style()->colorSpace(); + IntRect itemRect = itemBoundingBoxRect(tx, ty, listIndex); + itemRect.intersect(controlClipRect(tx, ty)); + paintInfo.context->fillRect(itemRect, backColor, colorSpace); + } +} + +bool RenderListBox::isPointInOverflowControl(HitTestResult& result, int _x, int _y, int _tx, int _ty) +{ + if (!m_vBar) + return false; + + IntRect vertRect(_tx + width() - borderRight() - m_vBar->width(), + _ty + borderTop(), + m_vBar->width(), + height() - borderTop() - borderBottom()); + + if (vertRect.contains(_x, _y)) { + result.setScrollbar(m_vBar.get()); + return true; + } + return false; +} + +int RenderListBox::listIndexAtOffset(int offsetX, int offsetY) +{ + if (!numItems()) + return -1; + + if (offsetY < borderTop() + paddingTop() || offsetY > height() - paddingBottom() - borderBottom()) + return -1; + + int scrollbarWidth = m_vBar ? m_vBar->width() : 0; + if (offsetX < borderLeft() + paddingLeft() || offsetX > width() - borderRight() - paddingRight() - scrollbarWidth) + return -1; + + int newOffset = (offsetY - borderTop() - paddingTop()) / itemHeight() + m_indexOffset; + return newOffset < numItems() ? newOffset : -1; +} + +void RenderListBox::panScroll(const IntPoint& panStartMousePosition) +{ + const int maxSpeed = 20; + const int iconRadius = 7; + const int speedReducer = 4; + + // FIXME: This doesn't work correctly with transforms. + FloatPoint absOffset = localToAbsolute(); + + IntPoint currentMousePosition = frame()->eventHandler()->currentMousePosition(); + // 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 + static IntPoint previousMousePosition; + if (currentMousePosition.y() < 0) + currentMousePosition = previousMousePosition; + else + previousMousePosition = currentMousePosition; + + int yDelta = currentMousePosition.y() - panStartMousePosition.y(); + + // If the point is too far from the center we limit the speed + yDelta = max(min(yDelta, maxSpeed), -maxSpeed); + + if (abs(yDelta) < iconRadius) // at the center we let the space for the icon + return; + + if (yDelta > 0) + //offsetY = view()->viewHeight(); + absOffset.move(0, listHeight()); + else if (yDelta < 0) + yDelta--; + + // Let's attenuate the speed + yDelta /= speedReducer; + + IntPoint scrollPoint(0, 0); + scrollPoint.setY(absOffset.y() + yDelta); + int newOffset = scrollToward(scrollPoint); + if (newOffset < 0) + return; + + m_inAutoscroll = true; + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + select->updateListBoxSelection(!select->multiple()); + m_inAutoscroll = false; +} + +int RenderListBox::scrollToward(const IntPoint& destination) +{ + // FIXME: This doesn't work correctly with transforms. + FloatPoint absPos = localToAbsolute(); + int offsetX = destination.x() - absPos.x(); + int offsetY = destination.y() - absPos.y(); + + int rows = numVisibleItems(); + int offset = m_indexOffset; + + if (offsetY < borderTop() + paddingTop() && scrollToRevealElementAtListIndex(offset - 1)) + return offset - 1; + + if (offsetY > height() - paddingBottom() - borderBottom() && scrollToRevealElementAtListIndex(offset + rows)) + return offset + rows - 1; + + return listIndexAtOffset(offsetX, offsetY); +} + +void RenderListBox::autoscroll() +{ + IntPoint pos = frame()->view()->windowToContents(frame()->eventHandler()->currentMousePosition()); + + int endIndex = scrollToward(pos); + if (endIndex >= 0) { + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + m_inAutoscroll = true; + + if (!select->multiple()) + select->setActiveSelectionAnchorIndex(endIndex); + + select->setActiveSelectionEndIndex(endIndex); + select->updateListBoxSelection(!select->multiple()); + m_inAutoscroll = false; + } +} + +void RenderListBox::stopAutoscroll() +{ + toSelectElement(static_cast<Element*>(node()))->listBoxOnChange(); +} + +bool RenderListBox::scrollToRevealElementAtListIndex(int index) +{ + if (index < 0 || index >= numItems() || listIndexIsVisible(index)) + return false; + + int newOffset; + if (index < m_indexOffset) + newOffset = index; + else + newOffset = index - numVisibleItems() + 1; + + m_indexOffset = newOffset; + if (m_vBar) + m_vBar->setValue(m_indexOffset, Scrollbar::NotFromScrollAnimator); + + return true; +} + +bool RenderListBox::listIndexIsVisible(int index) +{ + return index >= m_indexOffset && index < m_indexOffset + numVisibleItems(); +} + +bool RenderListBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node**) +{ + return m_vBar && m_vBar->scroll(direction, granularity, multiplier); +} + +bool RenderListBox::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node**) +{ + return m_vBar && m_vBar->scroll(logicalToPhysical(direction, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier); +} + +void RenderListBox::valueChanged(unsigned listIndex) +{ + Element* element = static_cast<Element*>(node()); + SelectElement* select = toSelectElement(element); + select->setSelectedIndex(select->listToOptionIndex(listIndex)); + element->dispatchFormControlChangeEvent(); +} + +int RenderListBox::scrollSize(ScrollbarOrientation orientation) const +{ + return ((orientation == VerticalScrollbar) && m_vBar) ? (m_vBar->totalSize() - m_vBar->visibleSize()) : 0; +} + +void RenderListBox::setScrollOffsetFromAnimation(const IntPoint& offset) +{ + if (m_vBar) + m_vBar->setValue(offset.y(), Scrollbar::FromScrollAnimator); +} + +void RenderListBox::valueChanged(Scrollbar*) +{ + int newOffset = m_vBar->value(); + if (newOffset != m_indexOffset) { + m_indexOffset = newOffset; + repaint(); + node()->dispatchEvent(Event::create(eventNames().scrollEvent, false, false)); + } +} + +int RenderListBox::itemHeight() const +{ + return style()->font().height() + rowSpacing; +} + +int RenderListBox::verticalScrollbarWidth() const +{ + return m_vBar ? m_vBar->width() : 0; +} + +// FIXME: We ignore padding in the vertical direction as far as these values are concerned, since that's +// how the control currently paints. +int RenderListBox::scrollWidth() const +{ + // There is no horizontal scrolling allowed. + return clientWidth(); +} + +int RenderListBox::scrollHeight() const +{ + return max(clientHeight(), listHeight()); +} + +int RenderListBox::scrollLeft() const +{ + return 0; +} + +void RenderListBox::setScrollLeft(int) +{ +} + +int RenderListBox::scrollTop() const +{ + return m_indexOffset * itemHeight(); +} + +void RenderListBox::setScrollTop(int newTop) +{ + // Determine an index and scroll to it. + int index = newTop / itemHeight(); + if (index < 0 || index >= numItems() || index == m_indexOffset) + return; + m_indexOffset = index; + if (m_vBar) + m_vBar->setValue(index, Scrollbar::NotFromScrollAnimator); +} + +bool RenderListBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) +{ + if (!RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, hitTestAction)) + return false; + const Vector<Element*>& listItems = toSelectElement(static_cast<Element*>(node()))->listItems(); + int size = numItems(); + tx += this->x(); + ty += this->y(); + for (int i = 0; i < size; ++i) { + if (itemBoundingBoxRect(tx, ty, i).contains(x, y)) { + if (Element* node = listItems[i]) { + result.setInnerNode(node); + if (!result.innerNonSharedNode()) + result.setInnerNonSharedNode(node); + result.setLocalPoint(IntPoint(x - tx, y - ty)); + break; + } + } + } + + return true; +} + +IntRect RenderListBox::controlClipRect(int tx, int ty) const +{ + IntRect clipRect = contentBoxRect(); + clipRect.move(tx, ty); + return clipRect; +} + +bool RenderListBox::isActive() const +{ + Page* page = frame()->page(); + return page && page->focusController()->isActive(); +} + +void RenderListBox::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) +{ + IntRect scrollRect = rect; + scrollRect.move(width() - borderRight() - scrollbar->width(), borderTop()); + repaintRectangle(scrollRect); +} + +IntRect RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const +{ + RenderView* view = this->view(); + if (!view) + return scrollbarRect; + + IntRect rect = scrollbarRect; + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + rect.move(scrollbarLeft, scrollbarTop); + + return view->frameView()->convertFromRenderer(this, rect); +} + +IntRect RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const +{ + RenderView* view = this->view(); + if (!view) + return parentRect; + + IntRect rect = view->frameView()->convertToRenderer(this, parentRect); + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + rect.move(-scrollbarLeft, -scrollbarTop); + return rect; +} + +IntPoint RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const +{ + RenderView* view = this->view(); + if (!view) + return scrollbarPoint; + + IntPoint point = scrollbarPoint; + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + point.move(scrollbarLeft, scrollbarTop); + + return view->frameView()->convertFromRenderer(this, point); +} + +IntPoint RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const +{ + RenderView* view = this->view(); + if (!view) + return parentPoint; + + IntPoint point = view->frameView()->convertToRenderer(this, parentPoint); + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + point.move(-scrollbarLeft, -scrollbarTop); + return point; +} + +PassRefPtr<Scrollbar> RenderListBox::createScrollbar() +{ + RefPtr<Scrollbar> widget; + bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR); + if (hasCustomScrollbarStyle) + widget = RenderScrollbar::createCustomScrollbar(this, VerticalScrollbar, this); + else + widget = Scrollbar::createNativeScrollbar(this, VerticalScrollbar, theme()->scrollbarControlSizeForPart(ListboxPart)); + document()->view()->addChild(widget.get()); + return widget.release(); +} + +void RenderListBox::destroyScrollbar() +{ + if (!m_vBar) + return; + + m_vBar->removeFromParent(); + m_vBar->setClient(0); + m_vBar = 0; +} + +void RenderListBox::setHasVerticalScrollbar(bool hasScrollbar) +{ + if (hasScrollbar == (m_vBar != 0)) + return; + + if (hasScrollbar) + m_vBar = createScrollbar(); + else + destroyScrollbar(); + + if (m_vBar) + m_vBar->styleChanged(); + +#if ENABLE(DASHBOARD_SUPPORT) + // Force an update since we know the scrollbars have changed things. + if (document()->hasDashboardRegions()) + document()->setDashboardRegionsDirty(true); +#endif +} + +} // namespace WebCore |