WebCore:

2009-07-02  David Hyatt  <hyatt@apple.com>

        Reviewed by Simon Fraser.

        Fix for bug 22119, clicks in the scrollbars of transformed content don't work.  Add new
        conversion methods for going across parent/child widget boundaries that can be implemented
        by the FrameView and ScrollbarClient to be transform-aware.

        Test cases added in platform/mac/fast/forms and platform/mac/fast/overflow.

        * WebCore.base.exp:
        * page/EventHandler.cpp:
        (WebCore::EventHandler::handleMouseMoveEvent):
        * page/FrameView.cpp:
        (WebCore::FrameView::convertFromScrollbarToContainingView):
        (WebCore::FrameView::convertFromContainingViewToScrollbar):
        (WebCore::FrameView::convertFromRenderer):
        (WebCore::FrameView::convertToRenderer):
        (WebCore::FrameView::convertToContainingView):
        (WebCore::FrameView::convertFromContainingView):
        * page/FrameView.h:
        * platform/ScrollView.h:
        * platform/Scrollbar.cpp:
        (WebCore::Scrollbar::convertToContainingView):
        (WebCore::Scrollbar::convertFromContainingView):
        * platform/Scrollbar.h:
        * platform/ScrollbarClient.h:
        (WebCore::ScrollbarClient::convertFromScrollbarToContainingView):
        (WebCore::ScrollbarClient::convertFromContainingViewToScrollbar):
        * platform/Widget.cpp:
        (WebCore::Widget::convertFromContainingWindow):
        (WebCore::Widget::convertToContainingWindow):
        (WebCore::Widget::convertFromRootToContainingWindow):
        (WebCore::Widget::convertFromContainingWindowToRoot):
        (WebCore::Widget::convertToContainingView):
        (WebCore::Widget::convertFromContainingView):
        * platform/Widget.h:
        * platform/graphics/IntPoint.h:
        (WebCore::IntPoint::move):
        * platform/mac/WidgetMac.mm:
        (WebCore::Widget::convertFromRootToContainingWindow):
        (WebCore::Widget::convertFromContainingWindowToRoot):
        * rendering/RenderBlock.cpp:
        (WebCore::RenderBlock::isPointInOverflowControl):
        * rendering/RenderDataGrid.cpp:
        (WebCore::RenderDataGrid::convertFromScrollbarToContainingView):
        (WebCore::RenderDataGrid::convertFromContainingViewToScrollbar):
        * rendering/RenderDataGrid.h:
        * rendering/RenderLayer.cpp:
        (WebCore::RenderLayer::convertFromScrollbarToContainingView):
        (WebCore::RenderLayer::convertFromContainingViewToScrollbar):
        (WebCore::RenderLayer::scrollbarOffset):
        (WebCore::RenderLayer::hitTestOverflowControls):
        * rendering/RenderLayer.h:
        * rendering/RenderListBox.cpp:
        (WebCore::RenderListBox::isPointInOverflowControl):
        (WebCore::RenderListBox::convertFromScrollbarToContainingView):
        (WebCore::RenderListBox::convertFromContainingViewToScrollbar):
        * rendering/RenderListBox.h:

LayoutTests:

2009-07-02  David Hyatt  <hyatt@apple.com>

        Reviewed by Simon Fraser.

        Test cases for bug 22119, clicks in scrollbar of transformed element don't work.

        * platform/mac/fast/forms/listbox-scrollbar-hit-test-expected.txt: Added.
        * platform/mac/fast/forms/listbox-scrollbar-hit-test.html: Added.
        * platform/mac/fast/overflow/overflow-scrollbar-hit-test-expected.txt: Added.
        * platform/mac/fast/overflow/overflow-scrollbar-hit-test.html: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@45478 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 5ef22c6..3621bc3 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,14 @@
+2009-07-02  David Hyatt  <hyatt@apple.com>
+
+        Reviewed by Simon Fraser.
+
+        Test cases for bug 22119, clicks in scrollbar of transformed element don't work.
+
+        * platform/mac/fast/forms/listbox-scrollbar-hit-test-expected.txt: Added.
+        * platform/mac/fast/forms/listbox-scrollbar-hit-test.html: Added.
+        * platform/mac/fast/overflow/overflow-scrollbar-hit-test-expected.txt: Added.
+        * platform/mac/fast/overflow/overflow-scrollbar-hit-test.html: Added.
+
 2009-07-02  Dan Bernstein  <mitz@apple.com>
 
         Reviewed by Dave Hyatt and Simon Fraser.
diff --git a/LayoutTests/platform/mac/fast/forms/listbox-scrollbar-hit-test-expected.txt b/LayoutTests/platform/mac/fast/forms/listbox-scrollbar-hit-test-expected.txt
new file mode 100644
index 0000000..e3a2785
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/forms/listbox-scrollbar-hit-test-expected.txt
@@ -0,0 +1,10 @@
+  
+Testing clicks on select1
+Scrolled down by itemHeight on down arrow click: PASS
+Scrolled up by itemHeight on up arrow click: PASS
+
+Testing clicks on select2
+Scrolled down by itemHeight on down arrow click: PASS
+Scrolled up by itemHeight on up arrow click: PASS
+
+
diff --git a/LayoutTests/platform/mac/fast/forms/listbox-scrollbar-hit-test.html b/LayoutTests/platform/mac/fast/forms/listbox-scrollbar-hit-test.html
new file mode 100644
index 0000000..8eb04cd
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/forms/listbox-scrollbar-hit-test.html
@@ -0,0 +1,112 @@
+<html>
+<head>
+  <title>Listbox scrollbar hit testing</title>
+  <style type="text/css" media="screen">
+    select {
+      border: 20px inset gray;
+      padding: 10px;
+    }
+    
+    #results {
+      margin-top: 50px;
+    }
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    function sendClick(element, clientX, clientY)
+    {
+      if (window.eventSender) {
+        eventSender.mouseMoveTo(clientX, clientY);
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+      }
+    }
+
+    function mouseDownOnSelect(selId, translateX, translateY)
+    {
+      log('Testing clicks on ' + selId);
+
+      var selectElement = document.getElementById(selId);
+      var itemHeight = 14;
+      var border = 20;
+      var scrollbarWidth = 10;
+      var scrollbarButtonHeight = 12;
+      
+      var scrollbarMidX = translateX + selectElement.offsetLeft + selectElement.offsetWidth - border - scrollbarWidth / 2;
+      // Recall that DRT runs with both scroll arrows at the end of the scrollbar
+      var scrollbarTopArrowY = translateY + selectElement.offsetTop + selectElement.offsetHeight - border - scrollbarButtonHeight - 3;
+      var scrollbarBottomArrowY = translateY + selectElement.offsetTop + selectElement.offsetHeight - border - 3;
+      
+      sendClick(selectElement, scrollbarMidX, scrollbarBottomArrowY);
+      sendClick(selectElement, scrollbarMidX, scrollbarBottomArrowY);
+      if (selectElement.scrollTop == 2 * itemHeight)
+        log('Scrolled down by itemHeight on down arrow click: PASS');
+      else
+        log('Failed to scroll down - scrollTop is ' + selectElement.scrollTop + ': FAIL');
+
+      sendClick(selectElement, scrollbarMidX, scrollbarTopArrowY);
+      if (selectElement.scrollTop == itemHeight)
+        log('Scrolled up by itemHeight on up arrow click: PASS');
+      else
+        log('Failed to scroll up - scrollTop is ' + selectElement.scrollTop + ': FAIL');
+
+      log('');
+    }
+    
+    function log(msg)
+    {
+      var results = document.getElementById('results');
+      results.innerHTML += msg + '<br>';
+    }
+    
+    function test()
+    {
+      if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+      }
+      
+      if (!window.eventSender) {
+        log('This test only runs in DRT');
+      }
+      
+      // Have to wait for the select to be painted before the
+      // scrollbar is sized correctly.
+      setTimeout(function() {
+        mouseDownOnSelect('select1', 0, 0);
+        mouseDownOnSelect('select2', 50, 50);
+        if (window.layoutTestController)
+          layoutTestController.notifyDone();
+      }, 0);
+    }
+  </script>
+</head>
+<body onload="test()">
+
+  <select id="select1" size="5">
+    <option selected value="0">item 0</option>
+    <option value="1">item 1</option>
+    <option value="2">item 2</option>
+    <option value="3">item 3</option>
+    <option value="4">item 4</option>
+    <option value="5">item 5</option>
+    <option value="6">item 6</option>
+    <option value="7">item 7</option>
+    <option value="8">item 8</option>
+  </select>
+
+  <select id="select2" size="5" style="-webkit-transform: translate(50px, 50px);">
+    <option selected value="0">item 0</option>
+    <option value="1">item 1</option>
+    <option value="2">item 2</option>
+    <option value="3">item 3</option>
+    <option value="4">item 4</option>
+    <option value="5">item 5</option>
+    <option value="6">item 6</option>
+    <option value="7">item 7</option>
+    <option value="8">item 8</option>
+  </select>
+
+  <div id="results">
+  </div>
+</body>
+</html>
diff --git a/LayoutTests/platform/mac/fast/overflow/overflow-scrollbar-hit-test-expected.txt b/LayoutTests/platform/mac/fast/overflow/overflow-scrollbar-hit-test-expected.txt
new file mode 100644
index 0000000..549c793
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/overflow/overflow-scrollbar-hit-test-expected.txt
@@ -0,0 +1,12 @@
+Inner
+ 
+Inner
+Testing clicks on box1
+Scrolled down by 80 on down arrow click: PASS
+Scrolled up by 40 on up arrow click: PASS
+
+Testing clicks on box2
+Scrolled down by 80 on down arrow click: PASS
+Scrolled up by 40 on up arrow click: PASS
+
+
diff --git a/LayoutTests/platform/mac/fast/overflow/overflow-scrollbar-hit-test.html b/LayoutTests/platform/mac/fast/overflow/overflow-scrollbar-hit-test.html
new file mode 100644
index 0000000..8d8c674
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/overflow/overflow-scrollbar-hit-test.html
@@ -0,0 +1,108 @@
+<html>
+<head>
+  <title>Overflow scrollbar hit testing</title>
+  <style type="text/css" media="screen">
+    .box {
+      display: inline-block;
+      width: 150px;
+      height: 150px;
+      border: 20px inset gray;
+      padding: 10px;
+      margin: 15px;
+      overflow: scroll;
+    }
+    
+    .inner {
+      width: 300px;
+      height: 300px;
+      border: 1px solid gray;
+    }
+    
+    #results {
+      margin-top: 50px;
+    }
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    function sendClick(element, clientX, clientY)
+    {
+      if (window.eventSender) {
+        eventSender.mouseMoveTo(clientX, clientY);
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+      }
+    }
+
+    function mouseDownOnOverflowDiv(elementId, translateX, translateY)
+    {
+      log('Testing clicks on ' + elementId);
+
+      var element = document.getElementById(elementId);
+      var scrollIncrement = 40;
+      var border = 20;
+      var scrollbarWidth = 16;
+      var scrollbarHeight = 16;
+      
+      var scrollbarMidX = translateX + element.offsetLeft + element.offsetWidth - border - scrollbarWidth / 2;
+      // Recall that DRT sets scroll arrows to be together at end end of the scrollbar
+      var scrollbarTopArrowY = translateY + element.offsetTop + element.offsetHeight - border - scrollbarHeight - scrollbarHeight - 3;
+      var scrollbarBottomArrowY = translateY + element.offsetTop + element.offsetHeight - border - scrollbarHeight - 3;
+      
+      sendClick(element, scrollbarMidX, scrollbarBottomArrowY);
+      sendClick(element, scrollbarMidX, scrollbarBottomArrowY);
+      if (element.scrollTop == 2 * scrollIncrement)
+        log('Scrolled down by ' + (2 * scrollIncrement) + ' on down arrow click: PASS');
+      else
+        log('Failed to scroll down - scrollTop is ' + element.scrollTop + ': FAIL');
+
+      sendClick(element, scrollbarMidX, scrollbarTopArrowY);
+      if (element.scrollTop == scrollIncrement)
+        log('Scrolled up by ' + scrollIncrement + ' on up arrow click: PASS');
+      else
+        log('Failed to scroll up - scrollTop is ' + element.scrollTop + ': FAIL');
+
+      log('');
+    }
+    
+    function log(msg)
+    {
+      var results = document.getElementById('results');
+      results.innerHTML += msg + '<br>';
+    }
+    
+    function test()
+    {
+      if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+      }
+      
+      if (!window.eventSender) {
+        log('This test only runs in DRT');
+      }
+      
+      // Have to wait for the select to be painted before the
+      // scrollbar is sized correctly.
+      setTimeout(function() {
+        mouseDownOnOverflowDiv('box1', 0, 0);
+        mouseDownOnOverflowDiv('box2', 50, 50);
+        if (window.layoutTestController)
+          layoutTestController.notifyDone();
+      }, 0);
+    }
+  </script>
+</head>
+<body onload="test()">
+
+
+  <div class="box" id="box1">
+    <div class="inner">Inner</div>
+  </div>
+
+  <div class="box" id="box2" style="-webkit-transform: translate(50px, 50px);">
+    <div class="inner">Inner</div>
+  </div>
+
+  <div id="results">
+  </div>
+</body>
+</html>
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 2b8197f..dddc854 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,63 @@
+2009-07-02  David Hyatt  <hyatt@apple.com>
+
+        Reviewed by Simon Fraser.
+
+        Fix for bug 22119, clicks in the scrollbars of transformed content don't work.  Add new
+        conversion methods for going across parent/child widget boundaries that can be implemented
+        by the FrameView and ScrollbarClient to be transform-aware.
+
+        Test cases added in platform/mac/fast/forms and platform/mac/fast/overflow.
+
+        * WebCore.base.exp:
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::handleMouseMoveEvent):
+        * page/FrameView.cpp:
+        (WebCore::FrameView::convertFromScrollbarToContainingView):
+        (WebCore::FrameView::convertFromContainingViewToScrollbar):
+        (WebCore::FrameView::convertFromRenderer):
+        (WebCore::FrameView::convertToRenderer):
+        (WebCore::FrameView::convertToContainingView):
+        (WebCore::FrameView::convertFromContainingView):
+        * page/FrameView.h:
+        * platform/ScrollView.h:
+        * platform/Scrollbar.cpp:
+        (WebCore::Scrollbar::convertToContainingView):
+        (WebCore::Scrollbar::convertFromContainingView):
+        * platform/Scrollbar.h:
+        * platform/ScrollbarClient.h:
+        (WebCore::ScrollbarClient::convertFromScrollbarToContainingView):
+        (WebCore::ScrollbarClient::convertFromContainingViewToScrollbar):
+        * platform/Widget.cpp:
+        (WebCore::Widget::convertFromContainingWindow):
+        (WebCore::Widget::convertToContainingWindow):
+        (WebCore::Widget::convertFromRootToContainingWindow):
+        (WebCore::Widget::convertFromContainingWindowToRoot):
+        (WebCore::Widget::convertToContainingView):
+        (WebCore::Widget::convertFromContainingView):
+        * platform/Widget.h:
+        * platform/graphics/IntPoint.h:
+        (WebCore::IntPoint::move):
+        * platform/mac/WidgetMac.mm:
+        (WebCore::Widget::convertFromRootToContainingWindow):
+        (WebCore::Widget::convertFromContainingWindowToRoot):
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::isPointInOverflowControl):
+        * rendering/RenderDataGrid.cpp:
+        (WebCore::RenderDataGrid::convertFromScrollbarToContainingView):
+        (WebCore::RenderDataGrid::convertFromContainingViewToScrollbar):
+        * rendering/RenderDataGrid.h:
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::convertFromScrollbarToContainingView):
+        (WebCore::RenderLayer::convertFromContainingViewToScrollbar):
+        (WebCore::RenderLayer::scrollbarOffset):
+        (WebCore::RenderLayer::hitTestOverflowControls):
+        * rendering/RenderLayer.h:
+        * rendering/RenderListBox.cpp:
+        (WebCore::RenderListBox::isPointInOverflowControl):
+        (WebCore::RenderListBox::convertFromScrollbarToContainingView):
+        (WebCore::RenderListBox::convertFromContainingViewToScrollbar):
+        * rendering/RenderListBox.h:
+
 2009-07-02  Dan Bernstein  <mitz@apple.com>
 
         Reviewed by Dave Hyatt and Simon Fraser.
diff --git a/WebCore/WebCore.base.exp b/WebCore/WebCore.base.exp
index d5fac6a..11def5f 100644
--- a/WebCore/WebCore.base.exp
+++ b/WebCore/WebCore.base.exp
@@ -932,6 +932,10 @@
 __ZNK7WebCore6String9substringEjj
 __ZNK7WebCore6StringcvN3JSC7UStringEEv
 __ZNK7WebCore6Widget9frameRectEv
+__ZNK7WebCore6Widget23convertToContainingViewERKNS_8IntPointE
+__ZNK7WebCore6Widget23convertToContainingViewERKNS_7IntRectE
+__ZNK7WebCore6Widget25convertFromContainingViewERKNS_7IntRectE
+__ZNK7WebCore6Widget25convertFromContainingViewERKNS_8IntPointE
 __ZNK7WebCore7CString4dataEv
 __ZNK7WebCore7CString6lengthEv
 __ZNK7WebCore7Element12getAttributeERKNS_13QualifiedNameE
diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp
index 87e9ecc02..42edc69 100644
--- a/WebCore/page/EventHandler.cpp
+++ b/WebCore/page/EventHandler.cpp
@@ -1297,7 +1297,7 @@
 
     // Send events right to a scrollbar if the mouse is pressed.
     if (m_lastScrollbarUnderMouse && m_mousePressed)
-        return m_lastScrollbarUnderMouse->mouseMoved(m_lastScrollbarUnderMouse->transformEvent(mouseEvent));
+        return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
 
     // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
     // if we are allowed to select.
@@ -1349,7 +1349,7 @@
             swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
     } else {
         if (scrollbar && !m_mousePressed)
-            scrollbar->mouseMoved(scrollbar->transformEvent(mouseEvent)); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
+            scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
         if (Page* page = m_frame->page()) {
             if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !page->mainFrame()->eventHandler()->panScrollInProgress()) {
                 if (FrameView* view = m_frame->view())
diff --git a/WebCore/page/FrameView.cpp b/WebCore/page/FrameView.cpp
index 45fc0ad..65c825a 100644
--- a/WebCore/page/FrameView.cpp
+++ b/WebCore/page/FrameView.cpp
@@ -1294,6 +1294,39 @@
     tickmarks = frame()->document()->renderedRectsForMarkers(DocumentMarker::TextMatch);
 }
 
+IntRect FrameView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
+{
+    // Scrollbars won't be transformed within us
+    IntRect newRect = localRect;
+    newRect.move(scrollbar->x(), scrollbar->y());
+    return newRect;
+}
+
+IntRect FrameView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
+{
+    IntRect newRect = parentRect;
+    // Scrollbars won't be transformed within us
+    newRect.move(-scrollbar->x(), -scrollbar->y());
+    return newRect;
+}
+
+// FIXME: test these on windows
+IntPoint FrameView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
+{
+    // Scrollbars won't be transformed within us
+    IntPoint newPoint = localPoint;
+    newPoint.move(scrollbar->x(), scrollbar->y());
+    return newPoint;
+}
+
+IntPoint FrameView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
+{
+    IntPoint newPoint = parentPoint;
+    // Scrollbars won't be transformed within us
+    newPoint.move(-scrollbar->x(), -scrollbar->y());
+    return newPoint;
+}
+
 IntRect FrameView::windowResizerRect() const
 {
     Page* page = frame() ? frame()->page() : 0;
@@ -1519,4 +1552,142 @@
         *newBottom = oldBottom;
 }
 
+IntRect FrameView::convertFromRenderer(const RenderObject* renderer, const IntRect& rendererRect) const
+{
+    IntRect rect = renderer->localToAbsoluteQuad(FloatRect(rendererRect)).enclosingBoundingBox();
+
+    // Convert from page ("absolute") to FrameView coordinates.
+    rect.move(-scrollX(), -scrollY());
+
+    return rect;
+}
+
+IntRect FrameView::convertToRenderer(const RenderObject* renderer, const IntRect& viewRect) const
+{
+    IntRect rect = viewRect;
+    
+    // Convert from FrameView coords into page ("absolute") coordinates.
+    rect.move(scrollX(), scrollY());
+
+    // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
+    // move the rect for now.
+    rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), false, true /* use transforms */)));
+    return rect;
+}
+
+IntPoint FrameView::convertFromRenderer(const RenderObject* renderer, const IntPoint& rendererPoint) const
+{
+    IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, false, true /* use transforms */));
+
+    // Convert from page ("absolute") to FrameView coordinates.
+    point.move(-scrollX(), -scrollY());
+    return point;
+}
+
+IntPoint FrameView::convertToRenderer(const RenderObject* renderer, const IntPoint& viewPoint) const
+{
+    IntPoint point = viewPoint;
+    
+    // Convert from FrameView coords into page ("absolute") coordinates.
+    point += IntSize(scrollX(), scrollY());
+
+    return roundedIntPoint(renderer->absoluteToLocal(point, false, true /* use transforms */));
+}
+
+IntRect FrameView::convertToContainingView(const IntRect& localRect) const
+{
+    if (const ScrollView* parentScrollView = parent()) {
+        if (parentScrollView->isFrameView()) {
+            const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
+            // Get our renderer in the parent view
+            RenderPart* renderer = m_frame->ownerRenderer();
+            if (!renderer)
+                return localRect;
+                
+            IntRect rect(localRect);
+            // Add borders and padding??
+            rect.move(renderer->borderLeft() + renderer->paddingLeft(),
+                      renderer->borderTop() + renderer->paddingTop());
+            return parentView->convertFromRenderer(renderer, rect);
+        }
+        
+        return Widget::convertToContainingView(localRect);
+    }
+    
+    return localRect;
+}
+
+IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
+{
+    if (const ScrollView* parentScrollView = parent()) {
+        if (parentScrollView->isFrameView()) {
+            const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
+
+            // Get our renderer in the parent view
+            RenderPart* renderer = m_frame->ownerRenderer();
+            if (!renderer)
+                return parentRect;
+
+            IntRect rect = parentView->convertToRenderer(renderer, parentRect);
+            // Subtract borders and padding
+            rect.move(-renderer->borderLeft() - renderer->paddingLeft(),
+                      -renderer->borderTop() - renderer->paddingTop());
+            return rect;
+        }
+        
+        return Widget::convertFromContainingView(parentRect);
+    }
+    
+    return parentRect;
+}
+
+IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
+{
+    if (const ScrollView* parentScrollView = parent()) {
+        if (parentScrollView->isFrameView()) {
+            const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
+
+            // Get our renderer in the parent view
+            RenderPart* renderer = m_frame->ownerRenderer();
+            if (!renderer)
+                return localPoint;
+                
+            IntPoint point(localPoint);
+
+            // Add borders and padding
+            point.move(renderer->borderLeft() + renderer->paddingLeft(),
+                       renderer->borderTop() + renderer->paddingTop());
+            return parentView->convertFromRenderer(renderer, point);
+        }
+        
+        return Widget::convertToContainingView(localPoint);
+    }
+    
+    return localPoint;
+}
+
+IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const
+{
+    if (const ScrollView* parentScrollView = parent()) {
+        if (parentScrollView->isFrameView()) {
+            const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
+
+            // Get our renderer in the parent view
+            RenderPart* renderer = m_frame->ownerRenderer();
+            if (!renderer)
+                return parentPoint;
+
+            IntPoint point = parentView->convertToRenderer(renderer, parentPoint);
+            // Subtract borders and padding
+            point.move(-renderer->borderLeft() - renderer->paddingLeft(),
+                       -renderer->borderTop() - renderer->paddingTop());
+            return point;
+        }
+        
+        return Widget::convertFromContainingView(parentPoint);
+    }
+    
+    return parentPoint;
+}
+
 } // namespace WebCore
diff --git a/WebCore/page/FrameView.h b/WebCore/page/FrameView.h
index 9dabe56..9ab281e 100644
--- a/WebCore/page/FrameView.h
+++ b/WebCore/page/FrameView.h
@@ -126,11 +126,6 @@
     virtual IntRect windowClipRect(bool clipToContents = true) const;
     IntRect windowClipRectForLayer(const RenderLayer*, bool clipToLayerContents) const;
 
-    virtual bool isActive() const;
-    virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&);
-    virtual void valueChanged(Scrollbar*);
-    virtual void getTickmarks(Vector<IntRect>&) const;
-
     virtual IntRect windowResizerRect() const;
 
     virtual void scrollRectIntoViewRecursively(const IntRect&);
@@ -188,6 +183,11 @@
     bool lockedToAnchor() { return m_lockedToAnchor; }
     void setLockedToAnchor(bool lockedToAnchor) { m_lockedToAnchor = lockedToAnchor; }
 
+    // Methods to convert points and rects between the coordinate space of the renderer, and this view.
+    virtual IntRect convertFromRenderer(const RenderObject*, const IntRect&) const;
+    virtual IntRect convertToRenderer(const RenderObject*, const IntRect&) const;
+    virtual IntPoint convertFromRenderer(const RenderObject*, const IntPoint&) const;
+    virtual IntPoint convertToRenderer(const RenderObject*, const IntPoint&) const;
 
 private:
     FrameView(Frame*);
@@ -215,6 +215,23 @@
             layout();
     }
 
+    // Override ScrollView methods to do point conversion via renderers, in order to
+    // take transforms into account.
+    virtual IntRect convertToContainingView(const IntRect&) const;
+    virtual IntRect convertFromContainingView(const IntRect&) const;
+    virtual IntPoint convertToContainingView(const IntPoint&) const;
+    virtual IntPoint convertFromContainingView(const IntPoint&) const;
+
+    // ScrollBarClient interface
+    virtual void valueChanged(Scrollbar*);
+    virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&);
+    virtual bool isActive() const;
+    virtual void getTickmarks(Vector<IntRect>&) const;
+    virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const;
+    virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const;
+    virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const;
+    virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const;
+
     void deferredRepaintTimerFired(Timer<FrameView>*);
     void doDeferredRepaints();
     void updateDeferredRepaintDelay();
diff --git a/WebCore/platform/ScrollView.h b/WebCore/platform/ScrollView.h
index 814b704..5bb49e6 100644
--- a/WebCore/platform/ScrollView.h
+++ b/WebCore/platform/ScrollView.h
@@ -221,6 +221,11 @@
 
     virtual bool scrollbarCornerPresent() const;
 
+    virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const = 0;
+    virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const = 0;
+    virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const = 0;
+    virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const = 0;
+
 protected:
     virtual void repaintContentRectangle(const IntRect&, bool now = false);
     virtual void paintContents(GraphicsContext*, const IntRect& damageRect) = 0;
diff --git a/WebCore/platform/Scrollbar.cpp b/WebCore/platform/Scrollbar.cpp
index babf3d4..4574f63 100644
--- a/WebCore/platform/Scrollbar.cpp
+++ b/WebCore/platform/Scrollbar.cpp
@@ -449,9 +449,36 @@
         m_client->invalidateScrollbarRect(this, rect);
 }
 
-PlatformMouseEvent Scrollbar::transformEvent(const PlatformMouseEvent& event)
+IntRect Scrollbar::convertToContainingView(const IntRect& localRect) const
 {
-    return event;
+    if (m_client)
+        return m_client->convertFromScrollbarToContainingView(this, localRect);
+
+    return Widget::convertToContainingView(localRect);
+}
+
+IntRect Scrollbar::convertFromContainingView(const IntRect& parentRect) const
+{
+    if (m_client)
+        return m_client->convertFromContainingViewToScrollbar(this, parentRect);
+
+    return Widget::convertFromContainingView(parentRect);
+}
+
+IntPoint Scrollbar::convertToContainingView(const IntPoint& localPoint) const
+{
+    if (m_client)
+        return m_client->convertFromScrollbarToContainingView(this, localPoint);
+
+    return Widget::convertToContainingView(localPoint);
+}
+
+IntPoint Scrollbar::convertFromContainingView(const IntPoint& parentPoint) const
+{
+    if (m_client)
+        return m_client->convertFromContainingViewToScrollbar(this, parentPoint);
+
+    return Widget::convertFromContainingView(parentPoint);
 }
 
 }
diff --git a/WebCore/platform/Scrollbar.h b/WebCore/platform/Scrollbar.h
index 711ae36..78430b1 100644
--- a/WebCore/platform/Scrollbar.h
+++ b/WebCore/platform/Scrollbar.h
@@ -110,10 +110,6 @@
     bool contextMenu(const PlatformMouseEvent& event);
 #endif
 
-    // Takes an event and accounts for any transforms that might occur on the scrollbar.  Returns
-    // a new event that has had all of the transforms applied.
-    PlatformMouseEvent transformEvent(const PlatformMouseEvent&);
-    
     ScrollbarTheme* theme() const { return m_theme; }
 
     virtual void setParent(ScrollView*);
@@ -126,13 +122,19 @@
 
     virtual void styleChanged() { }
 
+    virtual IntRect convertToContainingView(const IntRect&) const;
+    virtual IntRect convertFromContainingView(const IntRect&) const;
+    
+    virtual IntPoint convertToContainingView(const IntPoint&) const;
+    virtual IntPoint convertFromContainingView(const IntPoint&) const;
+
 private:
     virtual bool isScrollbar() const { return true; }
 
 protected:
     virtual void updateThumbPosition();
     virtual void updateThumbProportion();
-    
+
     void autoscrollTimerFired(Timer<Scrollbar>*);
     void startTimerIfNeeded(double delay);
     void stopTimerIfNeeded();
diff --git a/WebCore/platform/ScrollbarClient.h b/WebCore/platform/ScrollbarClient.h
index f720e95..3b44216 100644
--- a/WebCore/platform/ScrollbarClient.h
+++ b/WebCore/platform/ScrollbarClient.h
@@ -27,12 +27,11 @@
 #define ScrollbarClient_h
 
 #include "IntRect.h"
+#include "ScrollBar.h"
 #include <wtf/Vector.h>
 
 namespace WebCore {
 
-class Scrollbar;
-
 class ScrollbarClient {
 public:
     virtual ~ScrollbarClient() {}
@@ -45,6 +44,29 @@
     virtual bool scrollbarCornerPresent() const = 0;
 
     virtual void getTickmarks(Vector<IntRect>&) const { }
+
+    // Convert points and rects between the scrollbar and its containing view.
+    // The client needs to implement these in order to be aware of layout effects
+    // like CSS transforms.
+    virtual IntRect convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
+    {
+        return scrollbar->Widget::convertToContainingView(scrollbarRect);
+    }
+    
+    virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
+    {
+        return scrollbar->Widget::convertFromContainingView(parentRect);
+    }
+    
+    virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
+    {
+        return scrollbar->Widget::convertToContainingView(scrollbarPoint);
+    }
+    
+    virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
+    {
+        return scrollbar->Widget::convertFromContainingView(parentPoint);
+    }
 };
 
 }
diff --git a/WebCore/platform/Widget.cpp b/WebCore/platform/Widget.cpp
index a456431..5bb903b 100644
--- a/WebCore/platform/Widget.cpp
+++ b/WebCore/platform/Widget.cpp
@@ -69,42 +69,61 @@
         parent()->removeChild(this);
 }
 
+IntRect Widget::convertFromContainingWindow(const IntRect& windowRect) const
+{
+    if (const ScrollView* parentScrollView = parent()) {
+        IntRect parentRect = parentScrollView->convertFromContainingWindow(windowRect);
+        return convertFromContainingView(parentRect);
+    }
+    return convertFromContainingWindowToRoot(this, windowRect);
+}
+
+IntRect Widget::convertToContainingWindow(const IntRect& localRect) const
+{
+    if (const ScrollView* parentScrollView = parent()) {
+        IntRect parentRect = convertToContainingView(localRect);
+        return parentScrollView->convertToContainingWindow(parentRect);
+    }
+    return convertFromRootToContainingWindow(this, localRect);
+}
+
+IntPoint Widget::convertFromContainingWindow(const IntPoint& windowPoint) const
+{
+    if (const ScrollView* parentScrollView = parent()) {
+        IntPoint parentPoint = parentScrollView->convertFromContainingWindow(windowPoint);
+        return convertFromContainingView(parentPoint);
+    }
+    return convertFromContainingWindowToRoot(this, windowPoint);
+}
+
+IntPoint Widget::convertToContainingWindow(const IntPoint& localPoint) const
+{
+    if (const ScrollView* parentScrollView = parent()) {
+        IntPoint parentPoint = convertToContainingView(localPoint);
+        return parentScrollView->convertToContainingWindow(parentPoint);
+    }
+    return convertFromRootToContainingWindow(this, localPoint);
+}
+
 #if !PLATFORM(MAC)
-
-IntRect Widget::convertToContainingWindow(const IntRect& rect) const
+IntRect Widget::convertFromRootToContainingWindow(const Widget*, const IntRect& rect)
 {
-    IntRect convertedRect = rect;
-    convertedRect.setLocation(convertToContainingWindow(convertedRect.location()));
-    return convertedRect;
+    return rect;
 }
 
-IntPoint Widget::convertToContainingWindow(const IntPoint& point) const
+IntRect Widget::convertFromContainingWindowToRoot(const Widget*, const IntRect& rect)
 {
-    IntPoint windowPoint = point;
-    const Widget* childWidget = this;
-    for (const ScrollView* parentScrollView = parent();
-         parentScrollView;
-         childWidget = parentScrollView, parentScrollView = parentScrollView->parent())
-        windowPoint = parentScrollView->convertChildToSelf(childWidget, windowPoint);
-    return windowPoint;
+    return rect;
 }
 
-IntPoint Widget::convertFromContainingWindow(const IntPoint& point) const
+IntPoint Widget::convertFromRootToContainingWindow(const Widget*, const IntPoint& point)
 {
-    IntPoint widgetPoint = point;
-    const Widget* childWidget = this;
-    for (const ScrollView* parentScrollView = parent();
-         parentScrollView;
-         childWidget = parentScrollView, parentScrollView = parentScrollView->parent())
-        widgetPoint = parentScrollView->convertSelfToChild(childWidget, widgetPoint);
-    return widgetPoint;
+    return point;
 }
 
-IntRect Widget::convertFromContainingWindow(const IntRect& rect) const
+IntPoint Widget::convertFromContainingWindowToRoot(const Widget*, const IntPoint& point)
 {
-    IntRect result = rect;
-    result.setLocation(convertFromContainingWindow(rect.location()));
-    return result;
+    return point;
 }
 #endif
 
@@ -118,4 +137,41 @@
 }
 #endif
 
+IntRect Widget::convertToContainingView(const IntRect& localRect) const
+{
+    if (const ScrollView* parentScrollView = parent()) {
+        IntRect parentRect(localRect);
+        parentRect.setLocation(parentScrollView->convertChildToSelf(this, localRect.location()));
+        return parentRect;
+    }
+    return localRect;
 }
+
+IntRect Widget::convertFromContainingView(const IntRect& parentRect) const
+{
+    if (const ScrollView* parentScrollView = parent()) {
+        IntRect localRect = parentRect;
+        localRect.setLocation(parentScrollView->convertSelfToChild(this, localRect.location()));
+        return localRect;
+    }
+
+    return parentRect;
+}
+
+IntPoint Widget::convertToContainingView(const IntPoint& localPoint) const
+{
+    if (const ScrollView* parentScrollView = parent())
+        return parentScrollView->convertChildToSelf(this, localPoint);
+
+    return localPoint;
+}
+
+IntPoint Widget::convertFromContainingView(const IntPoint& parentPoint) const
+{
+    if (const ScrollView* parentScrollView = parent())
+        return parentScrollView->convertSelfToChild(this, parentPoint);
+
+    return parentPoint;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/Widget.h b/WebCore/platform/Widget.h
index b6c0054..80e16da 100644
--- a/WebCore/platform/Widget.h
+++ b/WebCore/platform/Widget.h
@@ -81,7 +81,6 @@
 class GraphicsContext;
 class PlatformMouseEvent;
 class ScrollView;
-class WidgetClient;
 class WidgetPrivate;
 
 // The Widget class serves as a base class for three kinds of objects:
@@ -164,9 +163,10 @@
     // up with an inaccurate rect.  Always make sure to use the rect-based convertFromContainingWindow method
     // when converting window rects.
     IntRect convertToContainingWindow(const IntRect&) const;
-    IntPoint convertToContainingWindow(const IntPoint&) const;
-    IntPoint convertFromContainingWindow(const IntPoint&) const; // See comment above about when not to use this method.
     IntRect convertFromContainingWindow(const IntRect&) const;
+    
+    IntPoint convertToContainingWindow(const IntPoint&) const;
+    IntPoint convertFromContainingWindow(const IntPoint&) const;
 
     virtual void frameRectsChanged() {}
 
@@ -179,12 +179,26 @@
     void removeFromSuperview();
 #endif
 
+    // Virtual methods to convert points to/from the containing ScrollView
+    virtual IntRect convertToContainingView(const IntRect&) const;
+    virtual IntRect convertFromContainingView(const IntRect&) const;
+    virtual IntPoint convertToContainingView(const IntPoint&) const;
+    virtual IntPoint convertFromContainingView(const IntPoint&) const;
+
 private:
     void init(PlatformWidget); // Must be called by all Widget constructors to initialize cross-platform data.
 
     void releasePlatformWidget();
     void retainPlatformWidget();
     
+    // These methods are used to convert from the root widget to the containing window,
+    // which has behavior that may differ between platforms (e.g. Mac uses flipped window coordinates).
+    static IntRect convertFromRootToContainingWindow(const Widget* rootWidget, const IntRect&);
+    static IntRect convertFromContainingWindowToRoot(const Widget* rootWidget, const IntRect&);
+    
+    static IntPoint convertFromRootToContainingWindow(const Widget* rootWidget, const IntPoint&);
+    static IntPoint convertFromContainingWindowToRoot(const Widget* rootWidget, const IntPoint&);
+
 private:
     ScrollView* m_parent;
     PlatformWidget m_widget;
diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h
index 1cae191..21af67b 100644
--- a/WebCore/platform/graphics/IntPoint.h
+++ b/WebCore/platform/graphics/IntPoint.h
@@ -80,6 +80,7 @@
     void setX(int x) { m_x = x; }
     void setY(int y) { m_y = y; }
 
+    void move(const IntSize& s) { move(s.width(), s.height()); } 
     void move(int dx, int dy) { m_x += dx; m_y += dy; }
     
     IntPoint expandedTo(const IntPoint& other) const
diff --git a/WebCore/platform/mac/WidgetMac.mm b/WebCore/platform/mac/WidgetMac.mm
index 1aaf4b2..8653a03 100644
--- a/WebCore/platform/mac/WidgetMac.mm
+++ b/WebCore/platform/mac/WidgetMac.mm
@@ -283,72 +283,52 @@
     }
 }
 
-IntPoint Widget::convertFromContainingWindow(const IntPoint& point) const
+// These are here to deal with flipped coords on Mac.
+IntRect Widget::convertFromRootToContainingWindow(const Widget* rootWidget, const IntRect& rect)
 {
-    if (!platformWidget()) {
-        if (!parent())
-            return point;
-        IntPoint result = parent()->convertFromContainingWindow(point);
-        result.move(parent()->scrollX() - x(), parent()->scrollY() - y());
-        return result;
-    }
-    
-    BEGIN_BLOCK_OBJC_EXCEPTIONS;
-    return IntPoint([platformWidget() convertPoint:point fromView:nil]);
-    END_BLOCK_OBJC_EXCEPTIONS;
-    
-    return point;
-}
+    if (!rootWidget->platformWidget())
+        return rect;
 
-IntRect Widget::convertFromContainingWindow(const IntRect& rect) const
-{
-    if (!platformWidget()) {
-        if (!parent())
-            return rect;
-        IntRect result = parent()->convertFromContainingWindow(rect);
-        result.move(parent()->scrollX() - x(), parent()->scrollY() - y());
-        return result;
-    }
-    
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
-    return enclosingIntRect([platformWidget() convertRect:rect fromView:nil]);
+    return enclosingIntRect([rootWidget->platformWidget() convertRect:rect toView:nil]);
     END_BLOCK_OBJC_EXCEPTIONS;
-    
+
     return rect;
 }
 
-IntRect Widget::convertToContainingWindow(const IntRect& r) const
+IntRect Widget::convertFromContainingWindowToRoot(const Widget* rootWidget, const IntRect& rect)
 {
-    if (!platformWidget()) {
-        if (!parent())
-            return r;
-        IntRect result = r;
-        result.move(parent()->scrollX() - x(), parent()->scrollY() - y());
-        return parent()->convertToContainingWindow(result);
-    }
-    
+    if (!rootWidget->platformWidget())
+        return rect;
+
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
-    return IntRect([platformWidget() convertRect:r toView:nil]);
+    return enclosingIntRect([rootWidget->platformWidget() convertRect:rect fromView:nil]);
     END_BLOCK_OBJC_EXCEPTIONS;
 
-    return r;
+    return rect;
 }
- 
-IntPoint Widget::convertToContainingWindow(const IntPoint& p) const
+
+IntPoint Widget::convertFromRootToContainingWindow(const Widget* rootWidget, const IntPoint& point)
 {
-    if (!platformWidget()) {
-        if (!parent())
-            return p;
-        IntPoint result = p;
-        result.move(parent()->scrollX() - x(), parent()->scrollY() - y());
-        return parent()->convertToContainingWindow(result);
-    }
-    
+    if (!rootWidget->platformWidget())
+        return point;
+
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
-    return IntPoint([platformWidget() convertPoint:p toView:nil]);
+    return IntPoint([rootWidget->platformWidget() convertPoint:point toView:nil]);
+    END_BLOCK_OBJC_EXCEPTIONS;
+    return point;
+}
+
+IntPoint Widget::convertFromContainingWindowToRoot(const Widget* rootWidget, const IntPoint& point)
+{
+    if (!rootWidget->platformWidget())
+        return point;
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+    return IntPoint([rootWidget->platformWidget() convertPoint:point fromView:nil]);
     END_BLOCK_OBJC_EXCEPTIONS;
 
-    return p;
+    return point;
 }
 
 void Widget::releasePlatformWidget()
diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp
index 98426ed..39123ef 100644
--- a/WebCore/rendering/RenderBlock.cpp
+++ b/WebCore/rendering/RenderBlock.cpp
@@ -3246,12 +3246,12 @@
     m_overflowHeight = max(m_overflowHeight, r.bottom());
 }
 
-bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int, int, int, int)
+bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int _x, int _y, int _tx, int _ty)
 {
     if (!scrollsOverflow())
         return false;
 
-    return layer()->hitTestOverflowControls(result);
+    return layer()->hitTestOverflowControls(result, IntPoint(_x - _tx, _y - _ty));
 }
 
 bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
diff --git a/WebCore/rendering/RenderDataGrid.cpp b/WebCore/rendering/RenderDataGrid.cpp
index 7e5cb53..bdf723f 100644
--- a/WebCore/rendering/RenderDataGrid.cpp
+++ b/WebCore/rendering/RenderDataGrid.cpp
@@ -34,6 +34,7 @@
 #include "Frame.h"
 #include "GraphicsContext.h"
 #include "Page.h"
+#include "RenderView.h"
 #include "Scrollbar.h"
 
 using std::min;
@@ -185,6 +186,65 @@
     return page && page->focusController()->isActive();
 }
 
+
+IntRect RenderDataGrid::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
+{
+    RenderView* view = this->view();
+    if (!view)
+        return scrollbarRect;
+
+    IntRect rect = scrollbarRect;
+
+    int scrollbarLeft = width() - borderRight() - scrollbar->width();
+    int scrollbarTop = borderTop();
+    rect.move(scrollbarLeft, scrollbarTop);
+
+    return view->frameView()->convertFromRenderer(this, rect);
+}
+
+IntRect RenderDataGrid::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
+{
+    RenderView* view = this->view();
+    if (!view)
+        return parentRect;
+
+    IntRect rect = view->frameView()->convertToRenderer(this, parentRect);
+
+    int scrollbarLeft = width() - borderRight() - scrollbar->width();
+    int scrollbarTop = borderTop();
+    rect.move(-scrollbarLeft, -scrollbarTop);
+    return rect;
+}
+
+IntPoint RenderDataGrid::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
+{
+    RenderView* view = this->view();
+    if (!view)
+        return scrollbarPoint;
+
+    IntPoint point = scrollbarPoint;
+
+    int scrollbarLeft = width() - borderRight() - scrollbar->width();
+    int scrollbarTop = borderTop();
+    point.move(scrollbarLeft, scrollbarTop);
+
+    return view->frameView()->convertFromRenderer(this, point);
+}
+
+IntPoint RenderDataGrid::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
+{
+    RenderView* view = this->view();
+    if (!view)
+        return parentPoint;
+
+    IntPoint point = view->frameView()->convertToRenderer(this, parentPoint);
+
+    int scrollbarLeft = width() - borderRight() - scrollbar->width();
+    int scrollbarTop = borderTop();
+    point.move(-scrollbarLeft, -scrollbarTop);
+    return point;
+}
+
 }
 
 #endif
diff --git a/WebCore/rendering/RenderDataGrid.h b/WebCore/rendering/RenderDataGrid.h
index 4f9f728..467edcc 100644
--- a/WebCore/rendering/RenderDataGrid.h
+++ b/WebCore/rendering/RenderDataGrid.h
@@ -69,6 +69,10 @@
     virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&);
     virtual bool isActive() const;
     virtual bool scrollbarCornerPresent() const { return false; } // We don't support resize on data grids yet.  If we did this would have to change.
+    virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const;
+    virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const;
+    virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const;
+    virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const;
 
     RefPtr<Scrollbar> m_vBar;
 };
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp
index c51706b..3cde6b8 100644
--- a/WebCore/rendering/RenderLayer.cpp
+++ b/WebCore/rendering/RenderLayer.cpp
@@ -1424,6 +1424,66 @@
     return !scrollCornerRect(this, renderBox()->borderBoxRect()).isEmpty();
 }
 
+IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
+{
+    RenderView* view = renderer()->view();
+    if (!view)
+        return scrollbarRect;
+
+    IntRect rect = scrollbarRect;
+    rect.move(scrollbarOffset(scrollbar));
+
+    return view->frameView()->convertFromRenderer(renderer(), rect);
+}
+
+IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
+{
+    RenderView* view = renderer()->view();
+    if (!view)
+        return parentRect;
+
+    IntRect rect = view->frameView()->convertToRenderer(renderer(), parentRect);
+    rect.move(-scrollbarOffset(scrollbar));
+    return rect;
+}
+
+IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
+{
+    RenderView* view = renderer()->view();
+    if (!view)
+        return scrollbarPoint;
+
+    IntPoint point = scrollbarPoint;
+    point.move(scrollbarOffset(scrollbar));
+    return view->frameView()->convertFromRenderer(renderer(), point);
+}
+
+IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
+{
+    RenderView* view = renderer()->view();
+    if (!view)
+        return parentPoint;
+
+    IntPoint point = view->frameView()->convertToRenderer(renderer(), parentPoint);
+
+    point.move(-scrollbarOffset(scrollbar));
+    return point;
+}
+
+IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const
+{
+    RenderBox* box = renderBox();
+
+    if (scrollbar == m_vBar.get())
+        return IntSize(box->width() - box->borderRight() - scrollbar->width(), box->borderTop());
+
+    if (scrollbar == m_hBar.get())
+        return IntSize(box->borderLeft(), box->height() - box->borderBottom() - scrollbar->height());
+    
+    ASSERT_NOT_REACHED();
+    return IntSize();
+}
+
 void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
 {
     IntRect scrollRect = rect;
@@ -1835,34 +1895,29 @@
     return resizerCornerRect(this, localBounds).contains(localPoint);
 }
     
-bool RenderLayer::hitTestOverflowControls(HitTestResult& result)
+bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint)
 {
     if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
         return false;
 
     RenderBox* box = renderBox();
     ASSERT(box);
-
-    int x = 0;
-    int y = 0;
-    convertToLayerCoords(root(), x, y);
-    IntRect absBounds(x, y, box->width(), box->height());
     
     IntRect resizeControlRect;
     if (renderer()->style()->resize() != RESIZE_NONE) {
-        resizeControlRect = resizerCornerRect(this, absBounds);
-        if (resizeControlRect.contains(result.point()))
+        resizeControlRect = resizerCornerRect(this, box->borderBoxRect());
+        if (resizeControlRect.contains(localPoint))
             return true;
     }
 
     int resizeControlSize = max(resizeControlRect.height(), 0);
 
     if (m_vBar) {
-        IntRect vBarRect(absBounds.right() - box->borderRight() - m_vBar->width(), 
-                         absBounds.y() + box->borderTop(),
+        IntRect vBarRect(box->width() - box->borderRight() - m_vBar->width(), 
+                         box->borderTop(),
                          m_vBar->width(),
-                         absBounds.height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
-        if (vBarRect.contains(result.point())) {
+                         box->height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
+        if (vBarRect.contains(localPoint)) {
             result.setScrollbar(m_vBar.get());
             return true;
         }
@@ -1870,11 +1925,11 @@
 
     resizeControlSize = max(resizeControlRect.width(), 0);
     if (m_hBar) {
-        IntRect hBarRect(absBounds.x() + box->borderLeft(),
-                         absBounds.bottom() - box->borderBottom() - m_hBar->height(),
-                         absBounds.width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
+        IntRect hBarRect(box->borderLeft(),
+                         box->height() - box->borderBottom() - m_hBar->height(),
+                         box->width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
                          m_hBar->height());
-        if (hBarRect.contains(result.point())) {
+        if (hBarRect.contains(localPoint)) {
             result.setScrollbar(m_hBar.get());
             return true;
         }
diff --git a/WebCore/rendering/RenderLayer.h b/WebCore/rendering/RenderLayer.h
index 971c4d1..1138658 100644
--- a/WebCore/rendering/RenderLayer.h
+++ b/WebCore/rendering/RenderLayer.h
@@ -264,7 +264,7 @@
 
     void positionOverflowControls(int tx, int ty);
     bool isPointInResizeControl(const IntPoint& absolutePoint) const;
-    bool hitTestOverflowControls(HitTestResult&);
+    bool hitTestOverflowControls(HitTestResult&, const IntPoint& localPoint);
     IntSize offsetFromResizeCorner(const IntPoint& absolutePoint) const;
 
     void paintOverflowControls(GraphicsContext*, int tx, int ty, const IntRect& damageRect);
@@ -476,11 +476,18 @@
 
     bool shouldBeNormalFlowOnly() const; 
 
+    // ScrollBarClient interface
     virtual void valueChanged(Scrollbar*);
     virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&);
     virtual bool isActive() const;
     virtual bool scrollbarCornerPresent() const;
-
+    virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const;
+    virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const;
+    virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const;
+    virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const;
+    
+    IntSize scrollbarOffset(const Scrollbar*) const;
+    
     void updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow);
 
     void childVisibilityChanged(bool newVisibility);
diff --git a/WebCore/rendering/RenderListBox.cpp b/WebCore/rendering/RenderListBox.cpp
index 83c569e..b4a7e9b 100644
--- a/WebCore/rendering/RenderListBox.cpp
+++ b/WebCore/rendering/RenderListBox.cpp
@@ -370,7 +370,7 @@
         return false;
 
     IntRect vertRect(_tx + width() - borderRight() - m_vBar->width(),
-                     _ty,
+                     _ty + borderTop(),
                      m_vBar->width(),
                      height() - borderTop() - borderBottom());
 
@@ -623,6 +623,64 @@
     repaintRectangle(scrollRect);
 }
 
+IntRect RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
+{
+    RenderView* view = this->view();
+    if (!view)
+        return scrollbarRect;
+
+    IntRect rect = scrollbarRect;
+
+    int scrollbarLeft = width() - borderRight() - scrollbar->width();
+    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 scrollbarLeft = width() - borderRight() - scrollbar->width();
+    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 scrollbarLeft = width() - borderRight() - scrollbar->width();
+    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 scrollbarLeft = width() - borderRight() - scrollbar->width();
+    int scrollbarTop = borderTop();
+    point.move(-scrollbarLeft, -scrollbarTop);
+    return point;
+}
+
 PassRefPtr<Scrollbar> RenderListBox::createScrollbar()
 {
     RefPtr<Scrollbar> widget;
diff --git a/WebCore/rendering/RenderListBox.h b/WebCore/rendering/RenderListBox.h
index b8c0540..dd257a8 100644
--- a/WebCore/rendering/RenderListBox.h
+++ b/WebCore/rendering/RenderListBox.h
@@ -101,6 +101,10 @@
     virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&);
     virtual bool isActive() const;
     virtual bool scrollbarCornerPresent() const { return false; } // We don't support resize on list boxes yet.  If we did this would have to change.
+    virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const;
+    virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const;
+    virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const;
+    virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const;
 
     void setHasVerticalScrollbar(bool hasScrollbar);
     PassRefPtr<Scrollbar> createScrollbar();