diff options
Diffstat (limited to 'Source/core/rendering/RenderListBox.cpp')
-rw-r--r-- | Source/core/rendering/RenderListBox.cpp | 127 |
1 files changed, 98 insertions, 29 deletions
diff --git a/Source/core/rendering/RenderListBox.cpp b/Source/core/rendering/RenderListBox.cpp index bdeaa5869..4a5fa8f77 100644 --- a/Source/core/rendering/RenderListBox.cpp +++ b/Source/core/rendering/RenderListBox.cpp @@ -86,6 +86,7 @@ RenderListBox::RenderListBox(Element* element) , m_inAutoscroll(false) , m_optionsWidth(0) , m_indexOffset(0) + , m_listItemCount(0) { ASSERT(element); ASSERT(element->isHTMLElement()); @@ -118,24 +119,36 @@ inline HTMLSelectElement* RenderListBox::selectElement() const void RenderListBox::updateFromElement() { FontCachePurgePreventer fontCachePurgePreventer; - if (m_optionsChanged) { const Vector<HTMLElement*>& listItems = selectElement()->listItems(); - int size = numItems(); + int size = static_cast<int>(listItems.size()); float width = 0; + m_listItemCount = 0; for (int i = 0; i < size; ++i) { - HTMLElement* element = listItems[i]; + const HTMLElement& element = *listItems[i]; + String text; Font itemFont = style()->font(); - if (isHTMLOptionElement(*element)) { - text = toHTMLOptionElement(*element).textIndentedToRespectGroupLabel(); - } else if (isHTMLOptGroupElement(*element)) { - text = toHTMLOptGroupElement(*element).groupLabelText(); + 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()) { @@ -206,9 +219,10 @@ void RenderListBox::scrollToRevealSelection() m_scrollToRevealSelectionAfterLayout = false; - int firstIndex = select->activeSelectionStartListIndex(); - if (firstIndex >= 0 && !listIndexIsVisible(select->activeSelectionEndListIndex())) - scrollToRevealElementAtListIndex(firstIndex); + 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 @@ -266,7 +280,7 @@ int RenderListBox::numVisibleItems() const int RenderListBox::numItems() const { - return selectElement()->listItems().size(); + return m_listItemCount; } LayoutUnit RenderListBox::listHeight() const @@ -285,7 +299,7 @@ int RenderListBox::baselinePosition(FontBaseline baselineType, bool firstLine, L return RenderBox::baselinePosition(baselineType, firstLine, lineDirection, linePositionMode) - baselineAdjustment; } -LayoutRect RenderListBox::itemBoundingBoxRect(const LayoutPoint& additionalOffset, int index) +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; @@ -347,7 +361,7 @@ void RenderListBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& // Focus the last selected item. int selectedItem = select->activeSelectionEndListIndex(); if (selectedItem >= 0) { - rects.append(pixelSnappedIntRect(itemBoundingBoxRect(additionalOffset, selectedItem))); + rects.append(pixelSnappedIntRect(itemBoundingBoxRectInternal(additionalOffset, selectedItem))); return; } @@ -355,9 +369,9 @@ void RenderListBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& int size = numItems(); const Vector<HTMLElement*>& listItems = select->listItems(); for (int i = 0; i < size; ++i) { - HTMLElement* element = listItems[i]; + HTMLElement* element = listItems[renderListBoxIndexToListIndex(i)]; if (isHTMLOptionElement(*element) && !element->isDisabledFormControl()) { - rects.append(pixelSnappedIntRect(itemBoundingBoxRect(additionalOffset, i))); + rects.append(pixelSnappedIntRect(itemBoundingBoxRectInternal(additionalOffset, i))); return; } } @@ -412,7 +426,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint& HTMLSelectElement* select = selectElement(); const Vector<HTMLElement*>& listItems = select->listItems(); - HTMLElement* element = listItems[listIndex]; + HTMLElement* element = listItems[renderListBoxIndexToListIndex(listIndex)]; RenderStyle* itemStyle = element->renderStyle(); if (!itemStyle) @@ -442,7 +456,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint& TextRun textRun(itemText, 0, 0, TextRun::AllowTrailingExpansion, itemStyle->direction(), isOverride(itemStyle->unicodeBidi()), true, TextRun::NoRounding); Font itemFont = style()->font(); - LayoutRect r = itemBoundingBoxRect(paintOffset, listIndex); + LayoutRect r = itemBoundingBoxRectInternal(paintOffset, listIndex); r.move(itemOffsetForAlignment(textRun, itemStyle, itemFont, r)); if (isHTMLOptGroupElement(*element)) { @@ -461,7 +475,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint& void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint& paintOffset, int listIndex) { const Vector<HTMLElement*>& listItems = selectElement()->listItems(); - HTMLElement* element = listItems[listIndex]; + HTMLElement* element = listItems[renderListBoxIndexToListIndex(listIndex)]; Color backColor; if (isHTMLOptionElement(*element) && ((toHTMLOptionElement(*element).selected() && selectElement()->suggestedIndex() < 0) || listIndex == selectElement()->suggestedIndex())) { @@ -475,7 +489,7 @@ void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint& // Draw the background for this list box item if (!element->renderStyle() || element->renderStyle()->visibility() != HIDDEN) { - LayoutRect itemRect = itemBoundingBoxRect(paintOffset, listIndex); + LayoutRect itemRect = itemBoundingBoxRectInternal(paintOffset, listIndex); itemRect.intersect(controlClipRect(paintOffset)); paintInfo.context->fillRect(pixelSnappedIntRect(itemRect), backColor); } @@ -498,7 +512,7 @@ bool RenderListBox::isPointInOverflowControl(HitTestResult& result, const Layout return false; } -int RenderListBox::listIndexAtOffset(const LayoutSize& offset) +int RenderListBox::listIndexAtOffset(const LayoutSize& offset) const { if (!numItems()) return -1; @@ -514,7 +528,7 @@ int RenderListBox::listIndexAtOffset(const LayoutSize& offset) return -1; int newOffset = (offset.height() - borderTop() - paddingTop()) / itemHeight() + m_indexOffset; - return newOffset < numItems() ? newOffset : -1; + return newOffset < numItems() ? renderListBoxIndexToListIndex(newOffset) : -1; } void RenderListBox::panScroll(const IntPoint& panStartMousePosition) @@ -571,10 +585,10 @@ int RenderListBox::scrollToward(const IntPoint& destination) int rows = numVisibleItems(); int offset = m_indexOffset; - if (positionOffset.height() < borderTop() + paddingTop() && scrollToRevealElementAtListIndex(offset - 1)) + if (positionOffset.height() < borderTop() + paddingTop() && scrollToRevealElementAtListIndexInternal(offset - 1)) return offset - 1; - if (positionOffset.height() > height() - paddingBottom() - borderBottom() && scrollToRevealElementAtListIndex(offset + rows)) + if (positionOffset.height() > height() - paddingBottom() - borderBottom() && scrollToRevealElementAtListIndexInternal(offset + rows)) return offset + rows - 1; return listIndexAtOffset(positionOffset); @@ -593,9 +607,9 @@ void RenderListBox::autoscroll(const IntPoint&) m_inAutoscroll = true; if (!select->multiple()) - select->setActiveSelectionAnchorIndex(endIndex); + select->setActiveSelectionAnchorIndex(renderListBoxIndexToListIndex(endIndex)); - select->setActiveSelectionEndIndex(endIndex); + select->setActiveSelectionEndIndex(renderListBoxIndexToListIndex(endIndex)); select->updateListBoxSelection(!select->multiple()); m_inAutoscroll = false; } @@ -609,7 +623,7 @@ void RenderListBox::stopAutoscroll() selectElement()->listBoxOnChange(); } -bool RenderListBox::scrollToRevealElementAtListIndex(int index) +bool RenderListBox::scrollToRevealElementAtListIndexInternal(int index) { if (index < 0 || index >= numItems() || listIndexIsVisible(index)) return false; @@ -625,7 +639,7 @@ bool RenderListBox::scrollToRevealElementAtListIndex(int index) return true; } -bool RenderListBox::listIndexIsVisible(int index) +bool RenderListBox::listIndexIsVisible(int index) const { return index >= m_indexOffset && index < m_indexOffset + numVisibleItems(); } @@ -721,8 +735,8 @@ bool RenderListBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re LayoutPoint adjustedLocation = accumulatedOffset + location(); for (int i = 0; i < size; ++i) { - if (itemBoundingBoxRect(adjustedLocation, i).contains(locationInContainer.point())) { - if (Element* node = listItems[i]) { + if (itemBoundingBoxRectInternal(adjustedLocation, i).contains(locationInContainer.point())) { + if (Element* node = listItems[renderListBoxIndexToListIndex(i)]) { result.setInnerNode(node); if (!result.innerNonSharedNode()) result.setInnerNonSharedNode(node); @@ -953,4 +967,59 @@ void RenderListBox::setHasVerticalScrollbar(bool hasScrollbar) document().setAnnotatedRegionsDirty(true); } +int RenderListBox::renderListBoxIndexToListIndex(int index) const +{ + const Vector<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 Vector<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)); +} + } // namespace WebCore |