Skip to content
Permalink
Browse files
2010-01-20 Simon Fraser <simon.fraser@apple.com>
        Reviewed by Dave Hyatt.

        Hit testing on composited plugins is broken
        https://bugs.webkit.org/show_bug.cgi?id=33927
        <rdar://problem/7559069>

        RenderWidget::paint()'s strategy of moving widgets at paint time, using tx and ty, was flawed
        because tx,ty are not always root-relative, especially when painting into compositing layers.
        This would move widgets to the wrong location, which caused hit testing issues.

        Widgets are usually positioned by layout. The one time this was not true was scrolling fixed-position
        elements, so we now reposition widgets after scrolling too.

        There was a related problem, which was that widgets expect the graphics context to be set up for
        root-relative painting. To fix this, adjust the CTM and the paintRect when the widget's frameRect
        is in a different coordinate system to the painting offset.

        Test: plugins/mouse-events-fixedpos.html

        * page/FrameView.cpp:
        (WebCore::FrameView::scrollPositionChanged): Update widget positions, to handle widgets in fixed position
        elements, but only if we're not already inside of layout.

        * platform/graphics/GraphicsContext.h:
        (WebCore::GraphicsContext::translate): Add a translate() convenience method that takes a FloatSize.

        * platform/graphics/IntSize.h:
        (WebCore::IntSize::isZero): Add a convenience method for testing for a zero size.

        * platform/mac/WidgetMac.mm:
        (WebCore::Widget::paint): Adjust a comment.

        * rendering/RenderWidget.cpp:
        (WebCore::RenderWidget::paint): Detect when the widget's frame is in a different coordinate system
        to painting, and adjust the CTM and paintRect in that case.

Canonical link: https://commits.webkit.org/45036@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@53637 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
smfr committed Jan 21, 2010
1 parent ebda764 commit 689d7602041e41fdd734f1ebbc40cb2ef5689337
Showing 9 changed files with 143 additions and 9 deletions.
@@ -1,3 +1,16 @@
2010-01-20 Simon Fraser <simon.fraser@apple.com>

Reviewed by Dave Hyatt.

Hit testing on composited plugins is broken
https://bugs.webkit.org/show_bug.cgi?id=33927
<rdar://problem/7559069>

Testcase for hit testing on a fixed-position plugin after scrolling.

* plugins/mouse-events-fixedpos-expected.txt: Added.
* plugins/mouse-events-fixedpos.html: Added.

2010-01-21 Diego Gonzalez <diego.gonzalez@openbossa.org>

Reviewed by Kenneth Rohde Christiansen.
@@ -0,0 +1,7 @@
CONSOLE MESSAGE: line 0: PLUGIN: getFocusEvent
CONSOLE MESSAGE: line 0: PLUGIN: mouseDown at (50, 50)
CONSOLE MESSAGE: line 0: PLUGIN: mouseUp at (50, 50)
CONSOLE MESSAGE: line 0: PLUGIN: mouseDown at (60, 60)
CONSOLE MESSAGE: line 0: PLUGIN: mouseUp at (70, 60)

Tests for widget positions being correctly updated after scrolling. rdar://problem/7559069
@@ -0,0 +1,58 @@
<html>
<style type="text/css" media="screen">
body {
height: 1000px;
}

.fixed {
position: fixed;
left: 20px;
top: 20px;
}

p {
margin-top: 200px;
}

embed {
margin: 20px;
}
</style>
<script>

function runTest()
{
window.scrollBy(50, 50);

if (!window.layoutTestController) {
document.body.appendChild(document.createTextNode("This test does not work in manual mode."));
return;
}

layoutTestController.dumpAsText();

plg.eventLoggingEnabled = true;

eventSender.mouseMoveTo(70,70);
eventSender.mouseMoveTo(90,90);
eventSender.mouseDown();
eventSender.mouseUp();
eventSender.mouseMoveTo(100,100);
eventSender.mouseDown();
eventSender.mouseMoveTo(110,100);
eventSender.mouseUp();
eventSender.mouseMoveTo(20,20);

plg.eventLoggingEnabled = false; // stop logging so our output doesn't bleed into the next test
}

window.addEventListener('load', runTest, false);
</script>
<body>
<div class="fixed">
<embed name="plg" type="application/x-webkit-test-netscape" width=100 height=100></embed>
</div>

<p>Tests for widget positions being correctly updated after scrolling. <a href="rdar://problem/7559069">rdar://problem/7559069</a></p>
</body>
</html>
@@ -1,3 +1,41 @@
2010-01-20 Simon Fraser <simon.fraser@apple.com>

Reviewed by Dave Hyatt.

Hit testing on composited plugins is broken
https://bugs.webkit.org/show_bug.cgi?id=33927
<rdar://problem/7559069>

RenderWidget::paint()'s strategy of moving widgets at paint time, using tx and ty, was flawed
because tx,ty are not always root-relative, especially when painting into compositing layers.
This would move widgets to the wrong location, which caused hit testing issues.

Widgets are usually positioned by layout. The one time this was not true was scrolling fixed-position
elements, so we now reposition widgets after scrolling too.

There was a related problem, which was that widgets expect the graphics context to be set up for
root-relative painting. To fix this, adjust the CTM and the paintRect when the widget's frameRect
is in a different coordinate system to the painting offset.

Test: plugins/mouse-events-fixedpos.html

* page/FrameView.cpp:
(WebCore::FrameView::scrollPositionChanged): Update widget positions, to handle widgets in fixed position
elements, but only if we're not already inside of layout.

* platform/graphics/GraphicsContext.h:
(WebCore::GraphicsContext::translate): Add a translate() convenience method that takes a FloatSize.

* platform/graphics/IntSize.h:
(WebCore::IntSize::isZero): Add a convenience method for testing for a zero size.

* platform/mac/WidgetMac.mm:
(WebCore::Widget::paint): Adjust a comment.

* rendering/RenderWidget.cpp:
(WebCore::RenderWidget::paint): Detect when the widget's frame is in a different coordinate system
to painting, and adjust the CTM and paintRect in that case.

2010-01-21 Andrei Popescu <andreip@google.com>

Reviewed by David Levin.
@@ -950,6 +950,13 @@ void FrameView::scrollPositionChanged()
if (layer)
layer->updateLayerPositions(RenderLayer::UpdateCompositingLayers);
#endif

// Update widget positions to take care of widgets inside fixed position elements,
// but only if we're not inside of layout.
if (!m_nestedLayoutCount) {
if (RenderView* root = m_frame->contentRenderer())
root->updateWidgetPositions();
}
}

HostWindow* FrameView::hostWindow() const
@@ -291,6 +291,7 @@ namespace WebCore {

void scale(const FloatSize&);
void rotate(float angleInRadians);
void translate(const FloatSize& size) { translate(size.width(), size.height()); }
void translate(float x, float y);
IntPoint origin();

@@ -69,7 +69,8 @@ class IntSize {
void setHeight(int height) { m_height = height; }

bool isEmpty() const { return m_width <= 0 || m_height <= 0; }

bool isZero() const { return !m_width && !m_height; }

void expand(int width, int height)
{
m_width += width;
@@ -197,7 +197,7 @@ static void safeRemoveFromSuperview(NSView *view)
END_BLOCK_OBJC_EXCEPTIONS;
} else {
// This is the case of drawing into a bitmap context other than a window backing store. It gets hit beneath
// -cacheDisplayInRect:toBitmapImageRep:.
// -cacheDisplayInRect:toBitmapImageRep:, and when painting into compositing layers.

// Transparent subframes are in fact implemented with scroll views that return YES from -drawsBackground (whenever the WebView
// itself is in drawsBackground mode). In the normal drawing code path, the scroll views are never asked to draw the background,
@@ -252,18 +252,27 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty)
}

if (m_widget) {
// Move the widget if necessary. We normally move and resize widgets during layout, but sometimes
// widgets can move without layout occurring (most notably when you scroll a document that
// contains fixed positioned elements).
m_widget->move(tx + borderLeft() + paddingLeft(), ty + borderTop() + paddingTop());

// Tell the widget to paint now. This is the only time the widget is allowed
// to paint itself. That way it will composite properly with z-indexed layers.
if (m_substituteImage)
paintInfo.context->drawImage(m_substituteImage.get(), style()->colorSpace(), m_widget->frameRect());
else
m_widget->paint(paintInfo.context, paintInfo.rect);
else {
IntPoint widgetLocation = m_widget->frameRect().location();
IntPoint paintLocation(tx + borderLeft() + paddingLeft(), ty + borderTop() + paddingTop());
IntRect paintRect = paintInfo.rect;

IntSize paintOffset = paintLocation - widgetLocation;
// When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer,
// not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing.
if (!paintOffset.isZero()) {
paintInfo.context->translate(paintOffset);
paintRect.move(-paintOffset);
}
m_widget->paint(paintInfo.context, paintRect);

if (!paintOffset.isZero())
paintInfo.context->translate(-paintOffset);
}
if (m_widget->isFrameView() && paintInfo.overlapTestRequests && !static_cast<FrameView*>(m_widget.get())->useSlowRepaintsIfNotOverlapped()) {
ASSERT(!paintInfo.overlapTestRequests->contains(this));
paintInfo.overlapTestRequests->set(this, m_widget->frameRect());

0 comments on commit 689d760

Please sign in to comment.