| Index: Source/core/rendering/RenderListBox.cpp
|
| diff --git a/Source/core/rendering/RenderListBox.cpp b/Source/core/rendering/RenderListBox.cpp
|
| index bdeaa58697891a4f86199f8e8b4f0ef9ea4fb248..4a5fa8f77e09ac0b0f303ce00a2278bf701b3de2 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
|
|
|