mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 509693. Don't use SW_SCROLLCHILDREN if some child has a descendant window that's outside the scrolled rectangle. r=jmathies
--HG-- extra : rebase_source : d6762b4e570d90e7a2561597ddc071383a923092
This commit is contained in:
parent
69525d5240
commit
56caf25e1b
@ -2105,6 +2105,37 @@ ClipRegionContainedInRect(const nsTArray<nsIntRect>& aClipRects,
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// This function determines whether the given window has a descendant that
|
||||
// does not intersect the given aScreenRect. If we encounter a window owned
|
||||
// by another thread (which includes another process, since thread IDs
|
||||
// are unique system-wide), then we give up and conservatively return true.
|
||||
static PRBool
|
||||
HasDescendantWindowOutsideRect(DWORD aThisThreadID, HWND aWnd,
|
||||
const RECT& aScreenRect)
|
||||
{
|
||||
// If the window is owned by another thread, give up now, don't try to
|
||||
// look at its children since they could change asynchronously.
|
||||
// XXX should we try harder here for out-of-process plugins?
|
||||
if (GetWindowThreadProcessId(aWnd, NULL) != aThisThreadID) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
for (HWND child = ::GetWindow(aWnd, GW_CHILD); child;
|
||||
child = ::GetWindow(child, GW_HWNDNEXT)) {
|
||||
RECT childScreenRect;
|
||||
::GetWindowRect(child, &childScreenRect);
|
||||
RECT result;
|
||||
if (!::IntersectRect(&result, &childScreenRect, &aScreenRect)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (HasDescendantWindowOutsideRect(aThisThreadID, child, aScreenRect)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::Scroll(const nsIntPoint& aDelta,
|
||||
const nsTArray<nsIntRect>& aDestRects,
|
||||
@ -2129,6 +2160,8 @@ nsWindow::Scroll(const nsIntPoint& aDelta,
|
||||
w->SetWindowClipRegion(configuration.mClipRegion, PR_TRUE);
|
||||
}
|
||||
|
||||
DWORD ourThreadID = GetWindowThreadProcessId(mWnd, NULL);
|
||||
|
||||
for (PRUint32 i = 0; i < aDestRects.Length(); ++i) {
|
||||
nsIntRect affectedRect;
|
||||
affectedRect.UnionRect(aDestRects[i], aDestRects[i] - aDelta);
|
||||
@ -2148,6 +2181,24 @@ nsWindow::Scroll(const nsIntPoint& aDelta,
|
||||
// used on it again by a later rectangle in aDestRects, we
|
||||
// don't want it to move twice!
|
||||
scrolledWidgets.RawRemoveEntry(entry);
|
||||
|
||||
nsIntPoint screenOffset = WidgetToScreenOffset();
|
||||
RECT screenAffectedRect = {
|
||||
screenOffset.x + affectedRect.x,
|
||||
screenOffset.y + affectedRect.y,
|
||||
screenOffset.x + affectedRect.XMost(),
|
||||
screenOffset.y + affectedRect.YMost()
|
||||
};
|
||||
if (HasDescendantWindowOutsideRect(ourThreadID, w->mWnd,
|
||||
screenAffectedRect)) {
|
||||
// SW_SCROLLCHILDREN seems to not move descendant windows
|
||||
// that don't intersect the scrolled rectangle, *even if* the
|
||||
// immediate child window of the scrolled window *does* intersect
|
||||
// the scrolled window. So if w has a descendant window
|
||||
// that would not be moved, SW_SCROLLCHILDREN will hopelessly mess
|
||||
// things up and we must not use it.
|
||||
flags &= ~SW_SCROLLCHILDREN;
|
||||
}
|
||||
} else {
|
||||
flags &= ~SW_SCROLLCHILDREN;
|
||||
// We may have removed some children from scrolledWidgets even
|
||||
|
@ -61,6 +61,7 @@ _TEST_FILES = test_bug343416.xul \
|
||||
test_wheeltransaction.xul \
|
||||
window_wheeltransaction.xul \
|
||||
test_imestate.html \
|
||||
test_plugin_scroll_consistency.html \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
|
||||
|
58
widget/tests/test_plugin_scroll_consistency.html
Normal file
58
widget/tests/test_plugin_scroll_consistency.html
Normal file
@ -0,0 +1,58 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for plugin child widgets not being messed up by scrolling</title>
|
||||
<script type="text/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="setTimeout(runTests, 0)">
|
||||
<p id="display">
|
||||
<div style="overflow:hidden; height:100px;" id="scroll">
|
||||
<embed type="application/x-test" wmode="window" width="100" height="800" id="plugin"></object>
|
||||
<div style="height:1000px;"></div>
|
||||
</div>
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var plugin = document.getElementById("plugin");
|
||||
|
||||
function consistencyCheck(state) {
|
||||
var s = plugin.doInternalConsistencyCheck();
|
||||
ok(s == "", "Consistency check: " + state + ": " + s);
|
||||
}
|
||||
|
||||
consistencyCheck("Initial state");
|
||||
|
||||
function runTests()
|
||||
{
|
||||
var scroll = document.getElementById("scroll");
|
||||
scroll.scrollTop = 10;
|
||||
consistencyCheck("Scrolled down a bit");
|
||||
|
||||
setTimeout(function() {
|
||||
consistencyCheck("Before scrolling back to top");
|
||||
scroll.scrollTop = 0;
|
||||
consistencyCheck("Scrolled to top");
|
||||
|
||||
setTimeout(function() {
|
||||
consistencyCheck("After scrolling to top");
|
||||
|
||||
SimpleTest.finish();
|
||||
}, 0);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user