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 |