[OS X] [RTL Scrollbars] List boxes should obey RTL scrollbars
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Mar 2016 17:34:20 +0000 (17:34 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Mar 2016 17:34:20 +0000 (17:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=155991

Reviewed by Darin Adler.

Source/WebCore:

List boxes were created before RenderLayers, and therefore don't share
the scollbar logic with them. Instead, they manage their own Scrollbars.
The placement logic needs to be updated to take RTL scrollbars into
account.

Tests: fast/scrolling/rtl-scrollbars-listbox-scroll.html
       fast/scrolling/rtl-scrollbars-listbox-select-left.html
       fast/scrolling/rtl-scrollbars-listbox-select-right.html
       fast/scrolling/rtl-scrollbars-listbox-simple.html
       fast/scrolling/rtl-scrollbars-listbox.html

* rendering/RenderBox.cpp:
(WebCore::RenderBox::contentBoxRect):
* rendering/RenderBox.h:
(WebCore::RenderBox::contentBoxRect): Deleted.
* rendering/RenderListBox.cpp:
(WebCore::RenderListBox::itemBoundingBoxRect):
(WebCore::RenderListBox::paintScrollbar):
(WebCore::RenderListBox::paintItemBackground):
(WebCore::RenderListBox::isPointInOverflowControl):
(WebCore::RenderListBox::listIndexAtOffset):
(WebCore::RenderListBox::nodeAtPoint):
(WebCore::RenderListBox::controlClipRect):
(WebCore::RenderListBox::invalidateScrollbarRect):
(WebCore::RenderListBox::convertFromScrollbarToContainingView):
(WebCore::RenderListBox::convertFromContainingViewToScrollbar):
(WebCore::RenderListBox::scrolledToTop):
(WebCore::RenderListBox::scrolledToBottom):

LayoutTests:

As with the previous patches, mark new tests as failing on all OSes that
don't support RTL scrollbars.

* TestExpectations:
* fast/scrolling/rtl-scrollbars-listbox-expected.html: Added.
* fast/scrolling/rtl-scrollbars-listbox-scroll-expected.html: Added.
* fast/scrolling/rtl-scrollbars-listbox-scroll.html: Added.
* fast/scrolling/rtl-scrollbars-listbox-select-left-expected.html: Added.
* fast/scrolling/rtl-scrollbars-listbox-select-left.html: Added.
* fast/scrolling/rtl-scrollbars-listbox-select-right-expected.html: Added.
* fast/scrolling/rtl-scrollbars-listbox-select-right.html: Added.
* fast/scrolling/rtl-scrollbars-listbox-simple-expected-mismatch.html: Added.
* fast/scrolling/rtl-scrollbars-listbox-simple.html: Added.
* fast/scrolling/rtl-scrollbars-listbox.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198843 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/fast/scrolling/rtl-scrollbars-listbox-expected.html [new file with mode: 0644]
LayoutTests/fast/scrolling/rtl-scrollbars-listbox-scroll-expected.html [new file with mode: 0644]
LayoutTests/fast/scrolling/rtl-scrollbars-listbox-scroll.html [new file with mode: 0644]
LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-left-expected.html [new file with mode: 0644]
LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-left.html [new file with mode: 0644]
LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-right-expected.html [new file with mode: 0644]
LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-right.html [new file with mode: 0644]
LayoutTests/fast/scrolling/rtl-scrollbars-listbox-simple-expected-mismatch.html [new file with mode: 0644]
LayoutTests/fast/scrolling/rtl-scrollbars-listbox-simple.html [new file with mode: 0644]
LayoutTests/fast/scrolling/rtl-scrollbars-listbox.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderBox.cpp
Source/WebCore/rendering/RenderBox.h
Source/WebCore/rendering/RenderListBox.cpp

index 35b6276..58d61d8 100644 (file)
@@ -1,3 +1,25 @@
+2016-03-30  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [OS X] [RTL Scrollbars] List boxes should obey RTL scrollbars
+        https://bugs.webkit.org/show_bug.cgi?id=155991
+
+        Reviewed by Darin Adler.
+
+        As with the previous patches, mark new tests as failing on all OSes that
+        don't support RTL scrollbars.
+
+        * TestExpectations:
+        * fast/scrolling/rtl-scrollbars-listbox-expected.html: Added.
+        * fast/scrolling/rtl-scrollbars-listbox-scroll-expected.html: Added.
+        * fast/scrolling/rtl-scrollbars-listbox-scroll.html: Added.
+        * fast/scrolling/rtl-scrollbars-listbox-select-left-expected.html: Added.
+        * fast/scrolling/rtl-scrollbars-listbox-select-left.html: Added.
+        * fast/scrolling/rtl-scrollbars-listbox-select-right-expected.html: Added.
+        * fast/scrolling/rtl-scrollbars-listbox-select-right.html: Added.
+        * fast/scrolling/rtl-scrollbars-listbox-simple-expected-mismatch.html: Added.
+        * fast/scrolling/rtl-scrollbars-listbox-simple.html: Added.
+        * fast/scrolling/rtl-scrollbars-listbox.html: Added.
+
 2016-03-30  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [JSC] Implement String.prototype.repeat in builtins JS
index 187ed88..ff6ce49 100644 (file)
@@ -1013,3 +1013,8 @@ fast/scrolling/rtl-scrollbars-iframe-offset.html [ ImageOnlyFailure ]
 fast/scrolling/rtl-scrollbars-elementFromPoint-static.html [ Failure ]
 fast/scrolling/rtl-scrollbars-iframe-scrolled.html [ ImageOnlyFailure ]
 fast/scrolling/rtl-scrollbars-positioning.html [ ImageOnlyFailure ]
+fast/scrolling/rtl-scrollbars-listbox-scroll.html [ ImageOnlyFailure ]
+fast/scrolling/rtl-scrollbars-listbox-select-left.html [ ImageOnlyFailure ]
+fast/scrolling/rtl-scrollbars-listbox-select-right.html [ ImageOnlyFailure ]
+fast/scrolling/rtl-scrollbars-listbox-simple.html [ ImageOnlyFailure ]
+fast/scrolling/rtl-scrollbars-listbox.html [ ImageOnlyFailure ]
diff --git a/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-expected.html b/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-expected.html
new file mode 100644 (file)
index 0000000..d0b6d6f
--- /dev/null
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body style="margin: 0px;">
+<div style="position: absolute; left: 8px; top: 200px;">This test makes sure that list boxes obey RTL scrollbars.</div>
+<div style="position: relative; width: 400px; height: 400px; overflow: hidden;">
+<select multiple="multiple" style="margin: 0px; border: 0px solid black; padding: 0px; width: 400px; height: 100px; position: absolute; left: 11px; top: 0px;">
+<option>January</option>
+<option>February</option>
+<option>March</option>
+<option>April</option>
+<option>May</option>
+<option>June</option>
+<option>July</option>
+<option>August</option>
+<option>September</option>
+<option>October</option>
+<option>November</option>
+<option>December</option>
+</select>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-scroll-expected.html b/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-scroll-expected.html
new file mode 100644 (file)
index 0000000..abcd492
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE html><!-- webkit-test-runner [ rtlScrollbars=true ] -->
+<html>
+<head>
+</head>
+<body style="margin: 0px;">
+<div style="position: absolute; left: 8px; top: 200px;">This test makes sure that list boxes obey RTL scrollbars.</div>
+<select id="container" multiple="multiple" style="margin: 0px; border: 0px solid black; padding: 0px;">
+<option>January</option>
+<option>February</option>
+<option>March</option>
+<option>April</option>
+<option>May</option>
+<option>June</option>
+<option>July</option>
+<option>August</option>
+<option>September</option>
+<option>October</option>
+<option>November</option>
+<option>December</option>
+</select>
+<script>
+var container = document.getElementById("container");
+container.scrollTop = container.scrollHeight - container.clientHeight;
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-scroll.html b/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-scroll.html
new file mode 100644 (file)
index 0000000..864ca7c
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html><!-- webkit-test-runner [ rtlScrollbars=true ] -->
+<html>
+<head>
+</head>
+<body style="margin: 0px;">
+<div style="position: absolute; left: 8px; top: 200px;">This test makes sure that list boxes obey RTL scrollbars.</div>
+<select multiple="multiple" style="margin: 0px; border: 0px solid black; padding: 0px;">
+<option>January</option>
+<option>February</option>
+<option>March</option>
+<option>April</option>
+<option>May</option>
+<option>June</option>
+<option>July</option>
+<option>August</option>
+<option>September</option>
+<option>October</option>
+<option>November</option>
+<option>December</option>
+</select>
+<script>
+if (window.eventSender) {
+    eventSender.mouseMoveTo(25, 5);
+    eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -20, "began", "none");
+    eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, "ended", "none");
+}
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-left-expected.html b/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-left-expected.html
new file mode 100644 (file)
index 0000000..361e4f6
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE html><!-- webkit-test-runner [ rtlScrollbars=true ] -->
+<html>
+<head>
+</head>
+<body style="margin: 0px;">
+<div style="position: absolute; left: 8px; top: 200px;">This test makes sure that cliking on an LTR scrollbar doesn't select an item in a list box.</div>
+<select id="container" multiple="multiple" style="margin: 0px; border: 0px solid black; padding: 0px;">
+<option>January</option>
+<option>February</option>
+<option>March</option>
+<option>April</option>
+<option>May</option>
+<option>June</option>
+<option>July</option>
+<option>August</option>
+<option>September</option>
+<option>October</option>
+<option>November</option>
+<option>December</option>
+</select>
+<script>
+var container = document.getElementById("container");
+container.focus();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-left.html b/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-left.html
new file mode 100644 (file)
index 0000000..231cd71
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html><!-- webkit-test-runner [ rtlScrollbars=true ] -->
+<html>
+<head>
+</head>
+<body style="margin: 0px;">
+<div style="position: absolute; left: 8px; top: 200px;">This test makes sure that cliking on an LTR scrollbar doesn't select an item in a list box.</div>
+<select multiple="multiple" style="margin: 0px; border: 0px solid black; padding: 0px;">
+<option>January</option>
+<option>February</option>
+<option>March</option>
+<option>April</option>
+<option>May</option>
+<option>June</option>
+<option>July</option>
+<option>August</option>
+<option>September</option>
+<option>October</option>
+<option>November</option>
+<option>December</option>
+</select>
+<script>
+if (window.eventSender) {
+    eventSender.mouseMoveTo(5, 5);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-right-expected.html b/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-right-expected.html
new file mode 100644 (file)
index 0000000..d701efa
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html><!-- webkit-test-runner [ rtlScrollbars=true ] -->
+<html>
+<head>
+</head>
+<body style="margin: 0px;">
+<div style="position: absolute; left: 8px; top: 200px;">This test makes sure that cliking on the rightmost part of an item causes it to be selected.</div>
+<select id="container" multiple="multiple" style="margin: 0px; border: 0px solid black; padding: 0px; width: 200px;">
+<option id="january">January</option>
+<option>February</option>
+<option>March</option>
+<option>April</option>
+<option>May</option>
+<option>June</option>
+<option>July</option>
+<option>August</option>
+<option>September</option>
+<option>October</option>
+<option>November</option>
+<option>December</option>
+</select>
+<script>
+var container = document.getElementById("container");
+container.focus();
+var january = document.getElementById("january");
+january.selected = true;
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-right.html b/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-select-right.html
new file mode 100644 (file)
index 0000000..cb735c9
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html><!-- webkit-test-runner [ rtlScrollbars=true ] -->
+<html>
+<head>
+</head>
+<body style="margin: 0px;">
+<div style="position: absolute; left: 8px; top: 200px;">This test makes sure that cliking on the rightmost part of an item causes it to be selected.</div>
+<select multiple="multiple" style="margin: 0px; border: 0px solid black; padding: 0px; width: 200px;">
+<option>January</option>
+<option>February</option>
+<option>March</option>
+<option>April</option>
+<option>May</option>
+<option>June</option>
+<option>July</option>
+<option>August</option>
+<option>September</option>
+<option>October</option>
+<option>November</option>
+<option>December</option>
+</select>
+<script>
+if (window.eventSender) {
+    eventSender.mouseMoveTo(195, 5);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-simple-expected-mismatch.html b/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-simple-expected-mismatch.html
new file mode 100644 (file)
index 0000000..bcd562e
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<p>This test makes sure that list boxes obey RTL scrollbars.</p>
+<select multiple="multiple">
+<option>January</option>
+<option>February</option>
+<option>March</option>
+<option>April</option>
+<option>May</option>
+<option>June</option>
+<option>July</option>
+<option>August</option>
+<option>September</option>
+<option>October</option>
+<option>November</option>
+<option>December</option>
+</select>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-simple.html b/LayoutTests/fast/scrolling/rtl-scrollbars-listbox-simple.html
new file mode 100644 (file)
index 0000000..e974b68
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html><!-- webkit-test-runner [ rtlScrollbars=true ] -->
+<html>
+<head>
+</head>
+<body>
+<p>This test makes sure that list boxes obey RTL scrollbars.</p>
+<select multiple="multiple">
+<option>January</option>
+<option>February</option>
+<option>March</option>
+<option>April</option>
+<option>May</option>
+<option>June</option>
+<option>July</option>
+<option>August</option>
+<option>September</option>
+<option>October</option>
+<option>November</option>
+<option>December</option>
+</select>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/fast/scrolling/rtl-scrollbars-listbox.html b/LayoutTests/fast/scrolling/rtl-scrollbars-listbox.html
new file mode 100644 (file)
index 0000000..ce26936
--- /dev/null
@@ -0,0 +1,24 @@
+<!DOCTYPE html><!-- webkit-test-runner [ rtlScrollbars=true ] -->
+<html>
+<head>
+</head>
+<body style="margin: 0px;">
+<div style="position: absolute; left: 8px; top: 200px;">This test makes sure that list boxes obey RTL scrollbars.</div>
+<div style="position: relative; width: 385px; height: 400px; overflow: hidden; left: 11px;">
+<select multiple="multiple" style="margin: 0px; border: 0px solid black; padding: 0px; width: 400px; height: 100px; position: absolute; left: -11px; top: 0px;">
+<option>January</option>
+<option>February</option>
+<option>March</option>
+<option>April</option>
+<option>May</option>
+<option>June</option>
+<option>July</option>
+<option>August</option>
+<option>September</option>
+<option>October</option>
+<option>November</option>
+<option>December</option>
+</select>
+</div>
+</body>
+</html>
\ No newline at end of file
index a0a68ea..fa32a56 100644 (file)
@@ -1,5 +1,41 @@
 2016-03-30  Myles C. Maxfield  <mmaxfield@apple.com>
 
+        [OS X] [RTL Scrollbars] List boxes should obey RTL scrollbars
+        https://bugs.webkit.org/show_bug.cgi?id=155991
+
+        Reviewed by Darin Adler.
+
+        List boxes were created before RenderLayers, and therefore don't share
+        the scollbar logic with them. Instead, they manage their own Scrollbars.
+        The placement logic needs to be updated to take RTL scrollbars into
+        account.
+
+        Tests: fast/scrolling/rtl-scrollbars-listbox-scroll.html
+               fast/scrolling/rtl-scrollbars-listbox-select-left.html
+               fast/scrolling/rtl-scrollbars-listbox-select-right.html
+               fast/scrolling/rtl-scrollbars-listbox-simple.html
+               fast/scrolling/rtl-scrollbars-listbox.html
+
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::contentBoxRect):
+        * rendering/RenderBox.h:
+        (WebCore::RenderBox::contentBoxRect): Deleted.
+        * rendering/RenderListBox.cpp:
+        (WebCore::RenderListBox::itemBoundingBoxRect):
+        (WebCore::RenderListBox::paintScrollbar):
+        (WebCore::RenderListBox::paintItemBackground):
+        (WebCore::RenderListBox::isPointInOverflowControl):
+        (WebCore::RenderListBox::listIndexAtOffset):
+        (WebCore::RenderListBox::nodeAtPoint):
+        (WebCore::RenderListBox::controlClipRect):
+        (WebCore::RenderListBox::invalidateScrollbarRect):
+        (WebCore::RenderListBox::convertFromScrollbarToContainingView):
+        (WebCore::RenderListBox::convertFromContainingViewToScrollbar):
+        (WebCore::RenderListBox::scrolledToTop):
+        (WebCore::RenderListBox::scrolledToBottom):
+
+2016-03-30  Myles C. Maxfield  <mmaxfield@apple.com>
+
         Use references instead of pointers in scrollbar-related code
         https://bugs.webkit.org/show_bug.cgi?id=155998
 
index d50c117..bb801b5 100644 (file)
@@ -690,6 +690,15 @@ RoundedRect::Radii RenderBox::borderRadii() const
     return style.getRoundedBorderFor(bounds).radii();
 }
 
+LayoutRect RenderBox::contentBoxRect() const
+{
+    LayoutUnit x = borderLeft() + paddingLeft();
+    if (layer() && layer()->verticalScrollbarIsOnLeft())
+        x += verticalScrollbarWidth();
+    LayoutUnit y = borderTop() + paddingTop();
+    return LayoutRect(x, y, contentWidth(), contentHeight());
+}
+
 IntRect RenderBox::absoluteContentBox() const
 {
     // This is wrong with transforms and flipped writing modes.
index 61b6e7f..971eb60 100644 (file)
@@ -158,7 +158,7 @@ public:
     WEBCORE_EXPORT RoundedRect::Radii borderRadii() const;
 
     // The content area of the box (excludes padding - and intrinsic padding for table cells, etc... - and border).
-    LayoutRect contentBoxRect() const { return LayoutRect(borderLeft() + paddingLeft(), borderTop() + paddingTop(), contentWidth(), contentHeight()); }
+    LayoutRect contentBoxRect() const;
     // The content box in absolute coords. Ignores transforms.
     IntRect absoluteContentBox() const;
     // The content box converted to absolute coords (taking transforms into account).
index 8971c2e..cc61f3c 100644 (file)
@@ -265,9 +265,11 @@ int RenderListBox::baselinePosition(FontBaseline baselineType, bool firstLine, L
 
 LayoutRect RenderListBox::itemBoundingBoxRect(const LayoutPoint& additionalOffset, int index)
 {
-    return LayoutRect(additionalOffset.x() + borderLeft() + paddingLeft(),
-                   additionalOffset.y() + borderTop() + paddingTop() + itemHeight() * (index - m_indexOffset),
-                   contentWidth(), itemHeight());
+    LayoutUnit x = additionalOffset.x() + borderLeft() + paddingLeft();
+    if (verticalScrollbarIsOnLeft() && m_vBar)
+        x += m_vBar->occupiedWidth();
+    LayoutUnit y = additionalOffset.y() + borderTop() + paddingTop() + itemHeight() * (index - m_indexOffset);
+    return LayoutRect(x, y, contentWidth(), itemHeight());
 }
     
 void RenderListBox::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
@@ -340,14 +342,16 @@ void RenderListBox::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoi
 
 void RenderListBox::paintScrollbar(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
 {
-    if (m_vBar) {
-        IntRect scrollRect = snappedIntRect(paintOffset.x() + width() - borderRight() - m_vBar->width(),
-            paintOffset.y() + borderTop(),
-            m_vBar->width(),
-            height() - (borderTop() + borderBottom()));
-        m_vBar->setFrameRect(scrollRect);
-        m_vBar->paint(paintInfo.context(), snappedIntRect(paintInfo.rect));
-    }
+    if (!m_vBar)
+        return;
+
+    LayoutUnit left = paintOffset.x() + (verticalScrollbarIsOnLeft() ? borderLeft() : width() - borderRight() - m_vBar->width());
+    LayoutUnit top = paintOffset.y() + borderTop();
+    LayoutUnit width = m_vBar->width();
+    LayoutUnit height = this->height() - (borderTop() + borderBottom());
+    IntRect scrollRect = snappedIntRect(left, top, width, height);
+    m_vBar->setFrameRect(scrollRect);
+    m_vBar->paint(paintInfo.context(), snappedIntRect(paintInfo.rect));
 }
 
 static LayoutSize itemOffsetForAlignment(TextRun textRun, RenderStyle* itemStyle, FontCascade itemFont, LayoutRect itemBoudingBox)
@@ -431,11 +435,12 @@ void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint&
         backColor = itemStyle.visitedDependentColor(CSSPropertyBackgroundColor);
 
     // Draw the background for this list box item
-    if (itemStyle.visibility() != HIDDEN) {
-        LayoutRect itemRect = itemBoundingBoxRect(paintOffset, listIndex);
-        itemRect.intersect(controlClipRect(paintOffset));
-        paintInfo.context().fillRect(snappedIntRect(itemRect), backColor);
-    }
+    if (itemStyle.visibility() == HIDDEN)
+        return;
+
+    LayoutRect itemRect = itemBoundingBoxRect(paintOffset, listIndex);
+    itemRect.intersect(controlClipRect(paintOffset));
+    paintInfo.context().fillRect(snappedIntRect(itemRect), backColor);
 }
 
 bool RenderListBox::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset)
@@ -443,16 +448,17 @@ bool RenderListBox::isPointInOverflowControl(HitTestResult& result, const Layout
     if (!m_vBar || !m_vBar->shouldParticipateInHitTesting())
         return false;
 
-    LayoutRect vertRect(accumulatedOffset.x() + width() - borderRight() - m_vBar->width(),
-                        accumulatedOffset.y() + borderTop(),
-                        m_vBar->width(),
-                        height() - borderTop() - borderBottom());
+    LayoutUnit x = accumulatedOffset.x() + (verticalScrollbarIsOnLeft() ? borderLeft() : width() - borderRight() - m_vBar->width());
+    LayoutUnit y = accumulatedOffset.y() + borderTop();
+    LayoutUnit width = m_vBar->width();
+    LayoutUnit height = this->height() - borderTop() - borderBottom();
+    LayoutRect vertRect(x, y, width, height);
 
-    if (vertRect.contains(locationInContainer)) {
-        result.setScrollbar(m_vBar.get());
-        return true;
-    }
-    return false;
+    if (!vertRect.contains(locationInContainer))
+        return false;
+
+    result.setScrollbar(m_vBar.get());
+    return true;
 }
 
 int RenderListBox::listIndexAtOffset(const LayoutSize& offset)
@@ -464,7 +470,9 @@ int RenderListBox::listIndexAtOffset(const LayoutSize& offset)
         return -1;
 
     int scrollbarWidth = m_vBar ? m_vBar->width() : 0;
-    if (offset.width() < borderLeft() + paddingLeft() || offset.width() > width() - borderRight() - paddingRight() - scrollbarWidth)
+    if (verticalScrollbarIsOnLeft() && (offset.width() < borderLeft() + paddingLeft() + scrollbarWidth || offset.width() > width() - borderRight() - paddingRight()))
+        return -1;
+    if (!verticalScrollbarIsOnLeft() && (offset.width() < borderLeft() + paddingLeft() || offset.width() > width() - borderRight() - paddingRight() - scrollbarWidth))
         return -1;
 
     int newOffset = (offset.height() - borderTop() - paddingTop()) / itemHeight() + m_indexOffset;
@@ -702,14 +710,14 @@ 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]) {
-                result.setInnerNode(node);
-                if (!result.innerNonSharedNode())
-                    result.setInnerNonSharedNode(node);
-                result.setLocalPoint(locationInContainer.point() - toLayoutSize(adjustedLocation));
-                break;
-            }
+        if (!itemBoundingBoxRect(adjustedLocation, i).contains(locationInContainer.point()))
+            continue;
+        if (Element* node = listItems[i]) {
+            result.setInnerNode(node);
+            if (!result.innerNonSharedNode())
+                result.setInnerNonSharedNode(node);
+            result.setLocalPoint(locationInContainer.point() - toLayoutSize(adjustedLocation));
+            break;
         }
     }
 
@@ -719,6 +727,8 @@ bool RenderListBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
 LayoutRect RenderListBox::controlClipRect(const LayoutPoint& additionalOffset) const
 {
     LayoutRect clipRect = contentBoxRect();
+    if (verticalScrollbarIsOnLeft() && (!layer() || !layer()->verticalScrollbarIsOnLeft()))
+        clipRect.move(m_vBar->occupiedWidth(), 0);
     clipRect.moveBy(additionalOffset);
     return clipRect;
 }
@@ -732,14 +742,14 @@ bool RenderListBox::isActive() const
 void RenderListBox::invalidateScrollbarRect(Scrollbar& scrollbar, const IntRect& rect)
 {
     IntRect scrollRect = rect;
-    scrollRect.move(width() - borderRight() - scrollbar.width(), borderTop());
+    scrollRect.move(verticalScrollbarIsOnLeft() ? borderLeft() : width() - borderRight() - scrollbar.width(), borderTop());
     repaintRectangle(scrollRect);
 }
 
 IntRect RenderListBox::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntRect& scrollbarRect) const
 {
     IntRect rect = scrollbarRect;
-    int scrollbarLeft = width() - borderRight() - scrollbar.width();
+    int scrollbarLeft = verticalScrollbarIsOnLeft() ? borderLeft() : width() - borderRight() - scrollbar.width();
     int scrollbarTop = borderTop();
     rect.move(scrollbarLeft, scrollbarTop);
     return view().frameView().convertFromRendererToContainingView(this, rect);
@@ -748,7 +758,7 @@ IntRect RenderListBox::convertFromScrollbarToContainingView(const Scrollbar& scr
 IntRect RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntRect& parentRect) const
 {
     IntRect rect = view().frameView().convertFromContainingViewToRenderer(this, parentRect);
-    int scrollbarLeft = width() - borderRight() - scrollbar.width();
+    int scrollbarLeft = verticalScrollbarIsOnLeft() ? borderLeft() : width() - borderRight() - scrollbar.width();
     int scrollbarTop = borderTop();
     rect.move(-scrollbarLeft, -scrollbarTop);
     return rect;
@@ -757,7 +767,7 @@ IntRect RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar& scr
 IntPoint RenderListBox::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntPoint& scrollbarPoint) const
 {
     IntPoint point = scrollbarPoint;
-    int scrollbarLeft = width() - borderRight() - scrollbar.width();
+    int scrollbarLeft = verticalScrollbarIsOnLeft() ? borderLeft() : width() - borderRight() - scrollbar.width();
     int scrollbarTop = borderTop();
     point.move(scrollbarLeft, scrollbarTop);
     return view().frameView().convertFromRendererToContainingView(this, point);
@@ -766,7 +776,7 @@ IntPoint RenderListBox::convertFromScrollbarToContainingView(const Scrollbar& sc
 IntPoint RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntPoint& parentPoint) const
 {
     IntPoint point = view().frameView().convertFromContainingViewToRenderer(this, parentPoint);
-    int scrollbarLeft = width() - borderRight() - scrollbar.width();
+    int scrollbarLeft = verticalScrollbarIsOnLeft() ? borderLeft() : width() - borderRight() - scrollbar.width();
     int scrollbarTop = borderTop();
     point.move(-scrollbarLeft, -scrollbarTop);
     return point;
@@ -880,11 +890,10 @@ void RenderListBox::setHasVerticalScrollbar(bool hasScrollbar)
 
 bool RenderListBox::scrolledToTop() const
 {
-    Scrollbar* vbar = verticalScrollbar();
-    if (!vbar)
-        return true;
-    
+    if (Scrollbar* vbar = verticalScrollbar())
     return vbar->value() <= 0;
+
+    return true;
 }
 
 bool RenderListBox::scrolledToBottom() const