| Index: Source/core/rendering/RenderListBox.cpp
|
| diff --git a/Source/core/rendering/RenderListBox.cpp b/Source/core/rendering/RenderListBox.cpp
|
| index edc2f5498db407bef4c100cf5cb65d13028c6da7..2785915c286b6c304efa9935aa3ab9e283660a2f 100644
|
| --- a/Source/core/rendering/RenderListBox.cpp
|
| +++ b/Source/core/rendering/RenderListBox.cpp
|
| @@ -62,10 +62,6 @@ namespace WebCore {
|
|
|
| using namespace HTMLNames;
|
|
|
| -const int rowSpacing = 1;
|
| -
|
| -const int optionsSpacingHorizontal = 2;
|
| -
|
| // The minSize constant was originally defined to render scrollbars correctly.
|
| // This might vary for different platforms.
|
| const int minSize = 4;
|
| @@ -73,40 +69,18 @@ const int minSize = 4;
|
| // Default size when the multiple attribute is present but size attribute is absent.
|
| const int defaultSize = 4;
|
|
|
| -// 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;
|
| +const int defaultPaddingBottom = 1;
|
|
|
| RenderListBox::RenderListBox(Element* element)
|
| : RenderBlockFlow(element)
|
| - , m_optionsChanged(true)
|
| - , m_scrollToRevealSelectionAfterLayout(true)
|
| - , m_inAutoscroll(false)
|
| - , m_optionsWidth(0)
|
| - , m_indexOffset(0)
|
| - , m_listItemCount(0)
|
| {
|
| ASSERT(element);
|
| ASSERT(element->isHTMLElement());
|
| ASSERT(isHTMLSelectElement(element));
|
| -
|
| - if (FrameView* frameView = frame()->view())
|
| - frameView->addScrollableArea(this);
|
| }
|
|
|
| RenderListBox::~RenderListBox()
|
| {
|
| - setHasVerticalScrollbar(false);
|
| -
|
| - if (FrameView* frameView = frame()->view())
|
| - frameView->removeScrollableArea(this);
|
| -}
|
| -
|
| -// FIXME: Instead of this hack we should add a ShadowRoot to <select> with no insertion point
|
| -// to prevent children from rendering.
|
| -bool RenderListBox::isChildAllowed(RenderObject* object, RenderStyle*) const
|
| -{
|
| - return object->isAnonymous() && !object->isRenderFullScreen();
|
| }
|
|
|
| inline HTMLSelectElement* RenderListBox::selectElement() const
|
| @@ -114,180 +88,38 @@ inline HTMLSelectElement* RenderListBox::selectElement() const
|
| return toHTMLSelectElement(node());
|
| }
|
|
|
| -void RenderListBox::updateFromElement()
|
| -{
|
| - FontCachePurgePreventer fontCachePurgePreventer;
|
| - if (m_optionsChanged) {
|
| - const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
|
| - int size = static_cast<int>(listItems.size());
|
| -
|
| - float width = 0;
|
| - m_listItemCount = 0;
|
| - for (int i = 0; i < size; ++i) {
|
| - const HTMLElement& element = *listItems[i];
|
| -
|
| - String text;
|
| - Font itemFont = style()->font();
|
| - if (isHTMLOptionElement(element)) {
|
| - const HTMLOptionElement& optionElement = toHTMLOptionElement(element);
|
| - if (optionElement.isDisplayNone())
|
| - continue;
|
| - text = optionElement.textIndentedToRespectGroupLabel();
|
| - ++m_listItemCount;
|
| - } else if (isHTMLOptGroupElement(element)) {
|
| - if (toHTMLOptGroupElement(element).isDisplayNone())
|
| - continue;
|
| - text = toHTMLOptGroupElement(element).groupLabelText();
|
| - FontDescription d = itemFont.fontDescription();
|
| - d.setWeight(d.bolderWeight());
|
| - itemFont = Font(d);
|
| - itemFont.update(document().styleEngine()->fontSelector());
|
| - ++m_listItemCount;
|
| - } else if (isHTMLHRElement(element)) {
|
| - // HTMLSelect adds it to its list, so we will also add it to match the count.
|
| - ++m_listItemCount;
|
| - continue;
|
| - }
|
| -
|
| - if (!text.isEmpty()) {
|
| - applyTextTransform(style(), text, ' ');
|
| -
|
| - bool hasStrongDirectionality;
|
| - TextDirection direction = determineDirectionality(text, hasStrongDirectionality);
|
| - TextRun textRun = constructTextRun(this, itemFont, text, style(), TextRun::AllowTrailingExpansion);
|
| - if (hasStrongDirectionality)
|
| - textRun.setDirection(direction);
|
| - textRun.disableRoundingHacks();
|
| - float textWidth = itemFont.width(textRun);
|
| - width = std::max(width, textWidth);
|
| - }
|
| - }
|
| - m_optionsWidth = static_cast<int>(ceilf(width));
|
| - m_optionsChanged = false;
|
| -
|
| - setHasVerticalScrollbar(true);
|
| -
|
| - setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
|
| - }
|
| -}
|
| -
|
| -void RenderListBox::selectionChanged()
|
| -{
|
| - paintInvalidationForWholeRenderer();
|
| - if (!m_inAutoscroll) {
|
| - if (m_optionsChanged || needsLayout())
|
| - m_scrollToRevealSelectionAfterLayout = true;
|
| - else
|
| - scrollToRevealSelection();
|
| - }
|
| -
|
| - if (AXObjectCache* cache = document().existingAXObjectCache())
|
| - cache->selectedChildrenChanged(this);
|
| -}
|
| -
|
| -void RenderListBox::layout()
|
| -{
|
| - RenderBlockFlow::layout();
|
| -
|
| - if (m_vBar) {
|
| - bool enabled = numVisibleItems() < numItems();
|
| - m_vBar->setEnabled(enabled);
|
| - m_vBar->setProportion(numVisibleItems(), numItems());
|
| - if (!enabled) {
|
| - scrollToOffsetWithoutAnimation(VerticalScrollbar, 0);
|
| - m_indexOffset = 0;
|
| - }
|
| - }
|
| -
|
| - if (m_scrollToRevealSelectionAfterLayout) {
|
| - ForceHorriblySlowRectMapping slowRectMapping(*this);
|
| - scrollToRevealSelection();
|
| - }
|
| -}
|
| -
|
| -void RenderListBox::invalidateTreeAfterLayout(const RenderLayerModelObject& invalidationContainer)
|
| -{
|
| - repaintScrollbarIfNeeded();
|
| - RenderBox::invalidateTreeAfterLayout(invalidationContainer);
|
| -}
|
| -
|
| -void RenderListBox::scrollToRevealSelection()
|
| -{
|
| - HTMLSelectElement* select = selectElement();
|
| -
|
| - m_scrollToRevealSelectionAfterLayout = false;
|
| -
|
| - int firstIndex = listIndexToRenderListBoxIndex(select->activeSelectionStartListIndex());
|
| - int lastIndex = listIndexToRenderListBoxIndex(select->activeSelectionEndListIndex());
|
| - if (firstIndex >= 0 && !listIndexIsVisible(lastIndex))
|
| - scrollToRevealElementAtListIndexInternal(firstIndex);
|
| -}
|
| -
|
| -void RenderListBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
|
| -{
|
| - maxLogicalWidth = m_optionsWidth + 2 * optionsSpacingHorizontal + verticalScrollbarWidth();
|
| - if (!style()->width().isPercent())
|
| - minLogicalWidth = maxLogicalWidth;
|
| -}
|
| -
|
| -void RenderListBox::computePreferredLogicalWidths()
|
| -{
|
| - ASSERT(!m_optionsChanged);
|
| -
|
| - m_minPreferredLogicalWidth = 0;
|
| - m_maxPreferredLogicalWidth = 0;
|
| - RenderStyle* styleToUse = style();
|
| -
|
| - if (styleToUse->width().isFixed() && styleToUse->width().value() > 0)
|
| - m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->width().value());
|
| - else
|
| - computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
|
| -
|
| - if (styleToUse->minWidth().isFixed() && styleToUse->minWidth().value() > 0) {
|
| - m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value()));
|
| - m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->minWidth().value()));
|
| - }
|
| -
|
| - if (styleToUse->maxWidth().isFixed()) {
|
| - m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value()));
|
| - m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->maxWidth().value()));
|
| - }
|
| -
|
| - LayoutUnit toAdd = borderAndPaddingWidth();
|
| - m_minPreferredLogicalWidth += toAdd;
|
| - m_maxPreferredLogicalWidth += toAdd;
|
| -
|
| - clearPreferredLogicalWidthsDirty();
|
| -}
|
| -
|
| int RenderListBox::size() const
|
| {
|
| int specifiedSize = selectElement()->size();
|
| if (specifiedSize > 1)
|
| - return std::max(minSize, specifiedSize);
|
| + return max(minSize, specifiedSize);
|
|
|
| return defaultSize;
|
| }
|
|
|
| -int RenderListBox::numVisibleItems() const
|
| +LayoutUnit RenderListBox::defaultItemHeight() const
|
| {
|
| - // Only count fully visible rows. But don't return 0 even if only part of a row shows.
|
| - return std::max<int>(1, (contentHeight() + rowSpacing) / itemHeight());
|
| + return style()->fontMetrics().height() + defaultPaddingBottom;
|
| }
|
|
|
| -int RenderListBox::numItems() const
|
| -{
|
| - return m_listItemCount;
|
| -}
|
| -
|
| -LayoutUnit RenderListBox::listHeight() const
|
| +LayoutUnit RenderListBox::itemHeight() const
|
| {
|
| - return itemHeight() * numItems() - rowSpacing;
|
| + HTMLSelectElement* select = selectElement();
|
| + if (!select)
|
| + return 0;
|
| + RenderObject* baseItemRenderer = firstChild();
|
| + if (!baseItemRenderer)
|
| + return defaultItemHeight();
|
| + if (baseItemRenderer->node() && isHTMLOptGroupElement(baseItemRenderer->node()))
|
| + baseItemRenderer = baseItemRenderer->slowFirstChild();
|
| + if (!baseItemRenderer || !baseItemRenderer->isBox())
|
| + return defaultItemHeight();
|
| + return toRenderBox(baseItemRenderer)->height();
|
| }
|
|
|
| void RenderListBox::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
|
| {
|
| - LayoutUnit height = itemHeight() * size() - rowSpacing;
|
| + LayoutUnit height = itemHeight() * size();
|
| // FIXME: The item height should have been added before updateLogicalHeight was called to avoid this hack.
|
| updateIntrinsicContentLogicalHeight(height);
|
|
|
| @@ -296,732 +128,12 @@ void RenderListBox::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, Logi
|
| RenderBox::computeLogicalHeight(height, logicalTop, computedValues);
|
| }
|
|
|
| -int RenderListBox::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode lineDirection, LinePositionMode linePositionMode) const
|
| -{
|
| - return RenderBox::baselinePosition(baselineType, firstLine, lineDirection, linePositionMode) - baselineAdjustment;
|
| -}
|
| -
|
| -LayoutRect RenderListBox::itemBoundingBoxRectInternal(const LayoutPoint& additionalOffset, int index) const
|
| -{
|
| - // For RTL, items start after the left-side vertical scrollbar.
|
| - int scrollbarOffset = style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? verticalScrollbarWidth() : 0;
|
| - return LayoutRect(additionalOffset.x() + borderLeft() + paddingLeft() + scrollbarOffset,
|
| - additionalOffset.y() + borderTop() + paddingTop() + itemHeight() * (index - m_indexOffset),
|
| - contentWidth(), itemHeight());
|
| -}
|
| -
|
| -void RenderListBox::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
|
| -{
|
| - 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, paintOffset, index);
|
| - index++;
|
| - }
|
| - }
|
| -
|
| - // Paint the children.
|
| - RenderBlockFlow::paintObject(paintInfo, paintOffset);
|
| -
|
| - switch (paintInfo.phase) {
|
| - // Depending on whether we have overlay scrollbars they
|
| - // get rendered in the foreground or background phases
|
| - case PaintPhaseForeground:
|
| - if (m_vBar->isOverlayScrollbar())
|
| - paintScrollbar(paintInfo, paintOffset);
|
| - break;
|
| - case PaintPhaseBlockBackground:
|
| - if (!m_vBar->isOverlayScrollbar())
|
| - paintScrollbar(paintInfo, paintOffset);
|
| - break;
|
| - case PaintPhaseChildBlockBackground:
|
| - case PaintPhaseChildBlockBackgrounds: {
|
| - int index = m_indexOffset;
|
| - while (index < listItemsSize && index <= m_indexOffset + numVisibleItems()) {
|
| - paintItemBackground(paintInfo, paintOffset, index);
|
| - index++;
|
| - }
|
| - break;
|
| - }
|
| - default:
|
| - break;
|
| - }
|
| -}
|
| -
|
| -void RenderListBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
|
| -{
|
| - if (!isSpatialNavigationEnabled(frame()))
|
| - return RenderBlockFlow::addFocusRingRects(rects, additionalOffset, paintContainer);
|
| -
|
| - HTMLSelectElement* select = selectElement();
|
| -
|
| - // Focus the last selected item.
|
| - int selectedItem = select->activeSelectionEndListIndex();
|
| - if (selectedItem >= 0) {
|
| - rects.append(pixelSnappedIntRect(itemBoundingBoxRectInternal(additionalOffset, selectedItem)));
|
| - return;
|
| - }
|
| -
|
| - // No selected items, find the first non-disabled item.
|
| - int size = numItems();
|
| - const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = select->listItems();
|
| - for (int i = 0; i < size; ++i) {
|
| - HTMLElement* element = listItems[renderListBoxIndexToListIndex(i)];
|
| - if (isHTMLOptionElement(*element) && !element->isDisabledFormControl()) {
|
| - rects.append(pixelSnappedIntRect(itemBoundingBoxRectInternal(additionalOffset, i)));
|
| - return;
|
| - }
|
| - }
|
| -}
|
| -
|
| -int RenderListBox::scrollbarLeft() const
|
| -{
|
| - int scrollbarLeft = 0;
|
| - if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
|
| - scrollbarLeft = borderLeft();
|
| - else
|
| - scrollbarLeft = width() - borderRight() - (m_vBar ? m_vBar->width() : 0);
|
| - return scrollbarLeft;
|
| -}
|
| -
|
| -void RenderListBox::paintScrollbar(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
|
| -{
|
| - if (m_vBar) {
|
| - IntRect scrollRect = pixelSnappedIntRect(paintOffset.x() + scrollbarLeft(),
|
| - paintOffset.y() + borderTop(),
|
| - m_vBar->width(),
|
| - height() - (borderTop() + borderBottom()));
|
| - m_vBar->setFrameRect(scrollRect);
|
| - m_vBar->paint(paintInfo.context, paintInfo.rect);
|
| - }
|
| -}
|
| -
|
| -static LayoutSize itemOffsetForAlignment(TextRun textRun, RenderStyle* itemStyle, Font itemFont, LayoutRect itemBoudingBox)
|
| -{
|
| - ETextAlign actualAlignment = itemStyle->textAlign();
|
| - // FIXME: Firefox doesn't respect JUSTIFY. Should we?
|
| - // FIXME: Handle TAEND here
|
| - if (actualAlignment == TASTART || actualAlignment == JUSTIFY)
|
| - actualAlignment = itemStyle->isLeftToRightDirection() ? LEFT : RIGHT;
|
| -
|
| - LayoutSize offset = LayoutSize(0, itemFont.fontMetrics().ascent());
|
| - if (actualAlignment == RIGHT || actualAlignment == WEBKIT_RIGHT) {
|
| - float textWidth = itemFont.width(textRun);
|
| - offset.setWidth(itemBoudingBox.width() - textWidth - optionsSpacingHorizontal);
|
| - } else if (actualAlignment == CENTER || actualAlignment == WEBKIT_CENTER) {
|
| - float textWidth = itemFont.width(textRun);
|
| - offset.setWidth((itemBoudingBox.width() - textWidth) / 2);
|
| - } else
|
| - offset.setWidth(optionsSpacingHorizontal);
|
| - return offset;
|
| -}
|
| -
|
| -void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint& paintOffset, int listIndex)
|
| -{
|
| - FontCachePurgePreventer fontCachePurgePreventer;
|
| -
|
| - HTMLSelectElement* select = selectElement();
|
| -
|
| - const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = select->listItems();
|
| - HTMLElement* element = listItems[renderListBoxIndexToListIndex(listIndex)];
|
| -
|
| - RenderStyle* itemStyle = element->renderStyle();
|
| - if (!itemStyle)
|
| - itemStyle = style();
|
| -
|
| - if (itemStyle->visibility() == HIDDEN)
|
| - return;
|
| -
|
| - String itemText;
|
| - bool isOptionElement = isHTMLOptionElement(*element);
|
| - if (isOptionElement)
|
| - itemText = toHTMLOptionElement(*element).textIndentedToRespectGroupLabel();
|
| - else if (isHTMLOptGroupElement(*element))
|
| - itemText = toHTMLOptGroupElement(*element).groupLabelText();
|
| - applyTextTransform(style(), itemText, ' ');
|
| -
|
| - Color textColor = element->renderStyle() ? resolveColor(element->renderStyle(), CSSPropertyColor) : resolveColor(CSSPropertyColor);
|
| - if (isOptionElement && ((toHTMLOptionElement(*element).selected() && select->suggestedIndex() < 0) || listIndex == select->suggestedIndex())) {
|
| - if (frame()->selection().isFocusedAndActive() && document().focusedElement() == node())
|
| - textColor = RenderTheme::theme().activeListBoxSelectionForegroundColor();
|
| - // Honor the foreground color for disabled items
|
| - else if (!element->isDisabledFormControl() && !select->isDisabledFormControl())
|
| - textColor = RenderTheme::theme().inactiveListBoxSelectionForegroundColor();
|
| - }
|
| -
|
| - paintInfo.context->setFillColor(textColor);
|
| -
|
| - TextRun textRun(itemText, 0, 0, TextRun::AllowTrailingExpansion, itemStyle->direction(), isOverride(itemStyle->unicodeBidi()), true, TextRun::NoRounding);
|
| - Font itemFont = style()->font();
|
| - LayoutRect r = itemBoundingBoxRectInternal(paintOffset, listIndex);
|
| - r.move(itemOffsetForAlignment(textRun, itemStyle, itemFont, r));
|
| -
|
| - if (isHTMLOptGroupElement(*element)) {
|
| - FontDescription d = itemFont.fontDescription();
|
| - d.setWeight(d.bolderWeight());
|
| - itemFont = Font(d);
|
| - itemFont.update(document().styleEngine()->fontSelector());
|
| - }
|
| -
|
| - // Draw the item text
|
| - TextRunPaintInfo textRunPaintInfo(textRun);
|
| - textRunPaintInfo.bounds = r;
|
| - paintInfo.context->drawBidiText(itemFont, textRunPaintInfo, roundedIntPoint(r.location()));
|
| -}
|
| -
|
| -void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint& paintOffset, int listIndex)
|
| -{
|
| - const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
|
| - HTMLElement* element = listItems[renderListBoxIndexToListIndex(listIndex)];
|
| -
|
| - Color backColor;
|
| - if (isHTMLOptionElement(*element) && ((toHTMLOptionElement(*element).selected() && selectElement()->suggestedIndex() < 0) || listIndex == selectElement()->suggestedIndex())) {
|
| - if (frame()->selection().isFocusedAndActive() && document().focusedElement() == node())
|
| - backColor = RenderTheme::theme().activeListBoxSelectionBackgroundColor();
|
| - else
|
| - backColor = RenderTheme::theme().inactiveListBoxSelectionBackgroundColor();
|
| - } else {
|
| - backColor = element->renderStyle() ? resolveColor(element->renderStyle(), CSSPropertyBackgroundColor) : resolveColor(CSSPropertyBackgroundColor);
|
| - }
|
| -
|
| - // Draw the background for this list box item
|
| - if (!element->renderStyle() || element->renderStyle()->visibility() != HIDDEN) {
|
| - LayoutRect itemRect = itemBoundingBoxRectInternal(paintOffset, listIndex);
|
| - itemRect.intersect(controlClipRect(paintOffset));
|
| - paintInfo.context->fillRect(pixelSnappedIntRect(itemRect), backColor);
|
| - }
|
| -}
|
| -
|
| -bool RenderListBox::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset)
|
| -{
|
| - if (!m_vBar || !m_vBar->shouldParticipateInHitTesting())
|
| - return false;
|
| -
|
| - LayoutRect vertRect(accumulatedOffset.x() + scrollbarLeft(),
|
| - accumulatedOffset.y() + borderTop(),
|
| - verticalScrollbarWidth(),
|
| - height() - borderTop() - borderBottom());
|
| -
|
| - if (vertRect.contains(locationInContainer)) {
|
| - result.setScrollbar(m_vBar.get());
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -int RenderListBox::listIndexAtOffset(const LayoutSize& offset) const
|
| -{
|
| - if (!numItems())
|
| - return -1;
|
| -
|
| - if (offset.height() < borderTop() + paddingTop() || offset.height() > height() - paddingBottom() - borderBottom())
|
| - return -1;
|
| -
|
| - int scrollbarWidth = verticalScrollbarWidth();
|
| - int rightScrollbarOffset = style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? scrollbarWidth : 0;
|
| - int leftScrollbarOffset = style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? 0 : scrollbarWidth;
|
| - if (offset.width() < borderLeft() + paddingLeft() + rightScrollbarOffset
|
| - || offset.width() > width() - borderRight() - paddingRight() - leftScrollbarOffset)
|
| - return -1;
|
| -
|
| - int newOffset = (offset.height() - borderTop() - paddingTop()) / itemHeight() + m_indexOffset;
|
| - return newOffset < numItems() ? renderListBoxIndexToListIndex(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 lastKnownMousePosition = frame()->eventHandler().lastKnownMousePosition();
|
| - // We need to check if the last known mouse position is out of the window. When the mouse is out of the window, the position is incoherent
|
| - static IntPoint previousMousePosition;
|
| - if (lastKnownMousePosition.y() < 0)
|
| - lastKnownMousePosition = previousMousePosition;
|
| - else
|
| - previousMousePosition = lastKnownMousePosition;
|
| -
|
| - int yDelta = lastKnownMousePosition.y() - panStartMousePosition.y();
|
| -
|
| - // If the point is too far from the center we limit the speed
|
| - yDelta = std::max<int>(std::min<int>(yDelta, maxSpeed), -maxSpeed);
|
| -
|
| - if (abs(yDelta) < iconRadius) // at the center we let the space for the icon
|
| - return;
|
| -
|
| - if (yDelta > 0)
|
| - absOffset.move(0, listHeight().toFloat());
|
| - 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;
|
| - HTMLSelectElement* select = selectElement();
|
| - select->updateListBoxSelection(!select->multiple());
|
| - m_inAutoscroll = false;
|
| -}
|
| -
|
| -int RenderListBox::scrollToward(const IntPoint& destination)
|
| -{
|
| - // FIXME: This doesn't work correctly with transforms.
|
| - FloatPoint absPos = localToAbsolute();
|
| - IntSize positionOffset = roundedIntSize(destination - absPos);
|
| -
|
| - int rows = numVisibleItems();
|
| - int offset = m_indexOffset;
|
| -
|
| - if (positionOffset.height() < borderTop() + paddingTop() && scrollToRevealElementAtListIndexInternal(offset - 1))
|
| - return offset - 1;
|
| -
|
| - if (positionOffset.height() > height() - paddingBottom() - borderBottom() && scrollToRevealElementAtListIndexInternal(offset + rows))
|
| - return offset + rows - 1;
|
| -
|
| - return listIndexAtOffset(positionOffset);
|
| -}
|
| -
|
| -void RenderListBox::autoscroll(const IntPoint&)
|
| -{
|
| - IntPoint pos = frame()->view()->windowToContents(frame()->eventHandler().lastKnownMousePosition());
|
| -
|
| - int endIndex = scrollToward(pos);
|
| - if (selectElement()->isDisabledFormControl())
|
| - return;
|
| -
|
| - if (endIndex >= 0) {
|
| - HTMLSelectElement* select = selectElement();
|
| - m_inAutoscroll = true;
|
| -
|
| - if (!select->multiple())
|
| - select->setActiveSelectionAnchorIndex(renderListBoxIndexToListIndex(endIndex));
|
| -
|
| - select->setActiveSelectionEndIndex(renderListBoxIndexToListIndex(endIndex));
|
| - select->updateListBoxSelection(!select->multiple());
|
| - m_inAutoscroll = false;
|
| - }
|
| -}
|
| -
|
| void RenderListBox::stopAutoscroll()
|
| {
|
| - if (selectElement()->isDisabledFormControl())
|
| - return;
|
| -
|
| - selectElement()->listBoxOnChange();
|
| -}
|
| -
|
| -bool RenderListBox::scrollToRevealElementAtListIndexInternal(int index)
|
| -{
|
| - if (index < 0 || index >= numItems() || listIndexIsVisible(index))
|
| - return false;
|
| -
|
| - int newOffset;
|
| - if (index < m_indexOffset)
|
| - newOffset = index;
|
| - else
|
| - newOffset = index - numVisibleItems() + 1;
|
| -
|
| - scrollToOffsetWithoutAnimation(VerticalScrollbar, newOffset);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool RenderListBox::listIndexIsVisible(int index) const
|
| -{
|
| - return index >= m_indexOffset && index < m_indexOffset + numVisibleItems();
|
| -}
|
| -
|
| -bool RenderListBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
|
| -{
|
| - return ScrollableArea::scroll(direction, granularity, multiplier);
|
| -}
|
| -
|
| -int RenderListBox::scrollSize(ScrollbarOrientation orientation) const
|
| -{
|
| - return orientation == VerticalScrollbar ? (numItems() - numVisibleItems()) : 0;
|
| -}
|
| -
|
| -IntPoint RenderListBox::scrollPosition() const
|
| -{
|
| - return IntPoint(0, m_indexOffset);
|
| -}
|
| -
|
| -void RenderListBox::setScrollOffset(const IntPoint& offset)
|
| -{
|
| - scrollTo(offset.y());
|
| -}
|
| -
|
| -void RenderListBox::scrollTo(int newOffset)
|
| -{
|
| - if (newOffset == m_indexOffset)
|
| - return;
|
| -
|
| - m_indexOffset = newOffset;
|
| -
|
| - if (frameView()->isInPerformLayout())
|
| - setShouldDoFullPaintInvalidationAfterLayout(true);
|
| - else
|
| - paintInvalidationForWholeRenderer();
|
| -
|
| - node()->document().enqueueScrollEventForNode(node());
|
| -}
|
| -
|
| -LayoutUnit RenderListBox::itemHeight() const
|
| -{
|
| - return style()->fontMetrics().height() + rowSpacing;
|
| -}
|
| -
|
| -int RenderListBox::verticalScrollbarWidth() const
|
| -{
|
| - return m_vBar && !m_vBar->isOverlayScrollbar() ? 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.
|
| -LayoutUnit RenderListBox::scrollWidth() const
|
| -{
|
| - // There is no horizontal scrolling allowed.
|
| - return clientWidth();
|
| -}
|
| -
|
| -LayoutUnit RenderListBox::scrollHeight() const
|
| -{
|
| - return std::max(clientHeight(), listHeight());
|
| -}
|
| -
|
| -LayoutUnit RenderListBox::scrollLeft() const
|
| -{
|
| - return 0;
|
| -}
|
| -
|
| -void RenderListBox::setScrollLeft(LayoutUnit)
|
| -{
|
| -}
|
| -
|
| -LayoutUnit RenderListBox::scrollTop() const
|
| -{
|
| - return m_indexOffset * itemHeight();
|
| -}
|
| -
|
| -void RenderListBox::setScrollTop(LayoutUnit newTop)
|
| -{
|
| - // Determine an index and scroll to it.
|
| - int index = newTop / itemHeight();
|
| - if (index < 0 || index >= numItems() || index == m_indexOffset)
|
| - return;
|
| -
|
| - scrollToOffsetWithoutAnimation(VerticalScrollbar, index);
|
| -}
|
| -
|
| -bool RenderListBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
|
| -{
|
| - if (!RenderBlockFlow::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction))
|
| - return false;
|
| - const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
|
| - int size = numItems();
|
| - LayoutPoint adjustedLocation = accumulatedOffset + location();
|
| -
|
| - for (int i = 0; i < size; ++i) {
|
| - if (itemBoundingBoxRectInternal(adjustedLocation, i).contains(locationInContainer.point())) {
|
| - if (Element* node = listItems[renderListBoxIndexToListIndex(i)]) {
|
| - result.setInnerNode(node);
|
| - if (!result.innerNonSharedNode())
|
| - result.setInnerNonSharedNode(node);
|
| - result.setLocalPoint(locationInContainer.point() - toLayoutSize(adjustedLocation));
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -LayoutRect RenderListBox::controlClipRect(const LayoutPoint& additionalOffset) const
|
| -{
|
| - LayoutRect clipRect = contentBoxRect();
|
| - if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
|
| - clipRect.moveBy(additionalOffset + LayoutPoint(verticalScrollbarWidth(), 0));
|
| - else
|
| - clipRect.moveBy(additionalOffset);
|
| - 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;
|
| - if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
|
| - scrollRect.move(borderLeft(), borderTop());
|
| - else
|
| - scrollRect.move(width() - borderRight() - scrollbar->width(), borderTop());
|
| -
|
| - if (frameView()->isInPerformLayout()) {
|
| - m_verticalBarDamage = scrollRect;
|
| - m_hasVerticalBarDamage = true;
|
| - } else {
|
| - invalidatePaintRectangle(scrollRect);
|
| - }
|
| -}
|
| -
|
| -void RenderListBox::repaintScrollbarIfNeeded()
|
| -{
|
| - if (!hasVerticalBarDamage())
|
| - return;
|
| - invalidatePaintRectangle(verticalBarDamage());
|
| -
|
| - resetScrollbarDamage();
|
| -}
|
| -
|
| -IntRect RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
|
| -{
|
| - RenderView* view = this->view();
|
| - if (!view)
|
| - return scrollbarRect;
|
| -
|
| - IntRect rect = scrollbarRect;
|
| -
|
| - 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 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 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 scrollbarTop = borderTop();
|
| - point.move(-scrollbarLeft(), -scrollbarTop);
|
| - return point;
|
| -}
|
| -
|
| -IntSize RenderListBox::contentsSize() const
|
| -{
|
| - return IntSize(scrollWidth(), scrollHeight());
|
| -}
|
| -
|
| -int RenderListBox::visibleHeight() const
|
| -{
|
| - return height();
|
| -}
|
| -
|
| -int RenderListBox::visibleWidth() const
|
| -{
|
| - return width();
|
| -}
|
| -
|
| -IntPoint RenderListBox::lastKnownMousePosition() const
|
| -{
|
| - RenderView* view = this->view();
|
| - if (!view)
|
| - return IntPoint();
|
| - return view->frameView()->lastKnownMousePosition();
|
| -}
|
| -
|
| -bool RenderListBox::shouldSuspendScrollAnimations() const
|
| -{
|
| - RenderView* view = this->view();
|
| - if (!view)
|
| - return true;
|
| - return view->frameView()->shouldSuspendScrollAnimations();
|
| -}
|
| -
|
| -bool RenderListBox::scrollbarsCanBeActive() const
|
| -{
|
| - RenderView* view = this->view();
|
| - if (!view)
|
| - return false;
|
| - return view->frameView()->scrollbarsCanBeActive();
|
| -}
|
| -
|
| -IntPoint RenderListBox::minimumScrollPosition() const
|
| -{
|
| - return IntPoint();
|
| -}
|
| -
|
| -IntPoint RenderListBox::maximumScrollPosition() const
|
| -{
|
| - return IntPoint(0, std::max(numItems() - numVisibleItems(), 0));
|
| -}
|
| -
|
| -bool RenderListBox::userInputScrollable(ScrollbarOrientation orientation) const
|
| -{
|
| - return orientation == VerticalScrollbar;
|
| -}
|
| -
|
| -bool RenderListBox::shouldPlaceVerticalScrollbarOnLeft() const
|
| -{
|
| - return false;
|
| -}
|
| -
|
| -int RenderListBox::lineStep(ScrollbarOrientation) const
|
| -{
|
| - return 1;
|
| -}
|
| -
|
| -int RenderListBox::pageStep(ScrollbarOrientation orientation) const
|
| -{
|
| - return std::max(1, numVisibleItems() - 1);
|
| -}
|
| -
|
| -float RenderListBox::pixelStep(ScrollbarOrientation) const
|
| -{
|
| - return 1.0f / itemHeight();
|
| -}
|
| -
|
| -IntRect RenderListBox::scrollableAreaBoundingBox() const
|
| -{
|
| - return absoluteBoundingBoxRect();
|
| -}
|
| -
|
| -PassRefPtr<Scrollbar> RenderListBox::createScrollbar()
|
| -{
|
| - RefPtr<Scrollbar> widget;
|
| - bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR);
|
| - if (hasCustomScrollbarStyle)
|
| - widget = RenderScrollbar::createCustomScrollbar(this, VerticalScrollbar, this->node());
|
| - else {
|
| - widget = Scrollbar::create(this, VerticalScrollbar, RenderTheme::theme().scrollbarControlSizeForPart(ListboxPart));
|
| - didAddScrollbar(widget.get(), VerticalScrollbar);
|
| - }
|
| - document().view()->addChild(widget.get());
|
| - return widget.release();
|
| -}
|
| -
|
| -void RenderListBox::destroyScrollbar()
|
| -{
|
| - if (!m_vBar)
|
| - return;
|
| -
|
| - if (!m_vBar->isCustomScrollbar())
|
| - ScrollableArea::willRemoveScrollbar(m_vBar.get(), VerticalScrollbar);
|
| - m_vBar->removeFromParent();
|
| - m_vBar->disconnectFromScrollableArea();
|
| - m_vBar = nullptr;
|
| -}
|
| -
|
| -void RenderListBox::setHasVerticalScrollbar(bool hasScrollbar)
|
| -{
|
| - if (hasScrollbar == (m_vBar != 0))
|
| + HTMLSelectElement* select = selectElement();
|
| + if (select->isDisabledFormControl())
|
| return;
|
| -
|
| - if (hasScrollbar)
|
| - m_vBar = createScrollbar();
|
| - else
|
| - destroyScrollbar();
|
| -
|
| - if (m_vBar)
|
| - m_vBar->styleChanged();
|
| -
|
| - // Force an update since we know the scrollbars have changed things.
|
| - if (document().hasAnnotatedRegions())
|
| - document().setAnnotatedRegionsDirty(true);
|
| -}
|
| -
|
| -int RenderListBox::renderListBoxIndexToListIndex(int index) const
|
| -{
|
| - const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
|
| - const int size = static_cast<int>(listItems.size());
|
| -
|
| - if (size == numItems())
|
| - return index;
|
| -
|
| - int listBoxIndex = 0;
|
| - int listIndex = 0;
|
| - for (; listIndex < size; ++listIndex) {
|
| - const HTMLElement& element = *listItems[listIndex];
|
| - if (isHTMLOptionElement(element) && toHTMLOptionElement(element).isDisplayNone())
|
| - continue;
|
| - if (isHTMLOptGroupElement(element) && toHTMLOptGroupElement(element).isDisplayNone())
|
| - continue;
|
| - if (index == listBoxIndex)
|
| - break;
|
| - ++listBoxIndex;
|
| - }
|
| - return listIndex;
|
| -}
|
| -
|
| -int RenderListBox::listIndexToRenderListBoxIndex(int index) const
|
| -{
|
| - const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = selectElement()->listItems();
|
| - const int size = static_cast<int>(listItems.size());
|
| -
|
| - if (size == numItems())
|
| - return index;
|
| -
|
| - int listBoxIndex = 0;
|
| - for (int listIndex = 0; listIndex < size; ++listIndex) {
|
| - const HTMLElement& element = *listItems[listIndex];
|
| - if (isHTMLOptionElement(element) && toHTMLOptionElement(element).isDisplayNone())
|
| - continue;
|
| - if (isHTMLOptGroupElement(element) && toHTMLOptGroupElement(element).isDisplayNone())
|
| - continue;
|
| - if (index == listIndex)
|
| - break;
|
| - ++listBoxIndex;
|
| - }
|
| - return listBoxIndex;
|
| -}
|
| -
|
| -LayoutRect RenderListBox::itemBoundingBoxRect(const LayoutPoint& point, int index) const
|
| -{
|
| - return itemBoundingBoxRectInternal(point, listIndexToRenderListBoxIndex(index));
|
| -}
|
| -
|
| -bool RenderListBox::scrollToRevealElementAtListIndex(int index)
|
| -{
|
| - return scrollToRevealElementAtListIndexInternal(listIndexToRenderListBoxIndex(index));
|
| + select->listBoxOnChange();
|
| }
|
|
|
| } // namespace WebCore
|
|
|