mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Bug 1688813 - Draw position:fixed elements relative to the top-left of the document when using drawSnapshot. r=emilio,mstange
Differential Revision: https://phabricator.services.mozilla.com/D104935
This commit is contained in:
parent
5d9d0b4383
commit
cd814ab6a8
@ -177,6 +177,7 @@ support-files = captureStream_common.js
|
||||
support-files = file_drawWindow_source.html file_drawWindow_common.js
|
||||
[test_drawSnapshot.html]
|
||||
support-files = file_drawWindow_source.html file_drawWindow_common.js
|
||||
[test_drawSnapshot_fixed.html]
|
||||
[test_imagebitmap.html]
|
||||
tags = imagebitmap
|
||||
[test_imagebitmap_close.html]
|
||||
|
68
dom/canvas/test/test_drawSnapshot_fixed.html
Normal file
68
dom/canvas/test/test_drawSnapshot_fixed.html
Normal file
@ -0,0 +1,68 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for drawSnapshot</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<style>
|
||||
html {
|
||||
height: 2000px;
|
||||
overflow: hidden;
|
||||
}
|
||||
header {
|
||||
position: fixed;
|
||||
background: red;
|
||||
display: block;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 200px;
|
||||
}
|
||||
</style>
|
||||
<script type="application/javascript">
|
||||
function make_canvas() {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.setAttribute("height", 2000);
|
||||
canvas.setAttribute("width", 500);
|
||||
return canvas;
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.addEventListener("load", runTests);
|
||||
|
||||
window.scrollTo(0, 1000);
|
||||
|
||||
async function runTests(event) {
|
||||
var testCanvas = make_canvas();
|
||||
var testCx = testCanvas.getContext("2d");
|
||||
var testWrapCx = SpecialPowers.wrap(testCx);
|
||||
|
||||
// Take a snapshot of the page while scrolled down, so that the fixed header will
|
||||
// be visually in the middle of the root scroll frame, but should still be at the
|
||||
// top of the snapshot (since snapshots with a rect are taken relative to the document).
|
||||
var rect = new window.DOMRect(0, 0, 500, 2000);
|
||||
let image = await SpecialPowers.snapshotContext(window, rect, "rgb(255, 255, 255)");
|
||||
testWrapCx.drawImage(image, 0, 0);
|
||||
|
||||
var refCanvas = make_canvas();
|
||||
var refCx = refCanvas.getContext("2d");
|
||||
|
||||
// Construct a reference image with an equivalent red square at the top.
|
||||
refCx.fillStyle = "white";
|
||||
refCx.fillRect(0, 0, 500, 2000);
|
||||
refCx.fillStyle = "red";
|
||||
refCx.fillRect(0, 0, 500, 200);
|
||||
|
||||
assertSnapshots(testCanvas, refCanvas, true, null, "position:fixed element with scrolling", "reference");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header></header>
|
||||
</body>
|
||||
</html>
|
@ -119,6 +119,7 @@ PaintFragment PaintFragment::Record(dom::BrowsingContext* aBc,
|
||||
RenderDocumentFlags renderDocFlags = RenderDocumentFlags::None;
|
||||
if (!(aFlags & CrossProcessPaintFlags::DrawView)) {
|
||||
renderDocFlags = (RenderDocumentFlags::IgnoreViewportScrolling |
|
||||
RenderDocumentFlags::ResetViewportScrolling |
|
||||
RenderDocumentFlags::DocumentRelative);
|
||||
}
|
||||
|
||||
|
@ -4607,6 +4607,10 @@ nsresult PresShell::RenderDocument(const nsRect& aRect,
|
||||
wouldFlushRetainedLayers = !IgnoringViewportScrolling();
|
||||
mRenderingStateFlags |= RenderingStateFlags::IgnoringViewportScrolling;
|
||||
}
|
||||
if (aFlags & RenderDocumentFlags::ResetViewportScrolling) {
|
||||
wouldFlushRetainedLayers = true;
|
||||
flags |= PaintFrameFlags::ResetViewportScrolling;
|
||||
}
|
||||
if (aFlags & RenderDocumentFlags::DrawWindowNotFlushing) {
|
||||
mRenderingStateFlags |= RenderingStateFlags::DrawWindowNotFlushing;
|
||||
}
|
||||
|
@ -779,6 +779,9 @@ class PresShell final : public nsStubDocumentObserver,
|
||||
* might choose not to paint themes.
|
||||
* set RenderDocumentFlags::IgnoreViewportScrolling to ignore clipping and
|
||||
* scrollbar painting due to scrolling in the viewport
|
||||
* set RenderDocumentFlags::ResetViewportScrolling to temporarily set the
|
||||
* viewport scroll position to 0 so that position:fixed elements are drawn
|
||||
* at their initial position.
|
||||
* set RenderDocumentFlags::DrawCaret to draw the caret if one would be
|
||||
* visible (by default the caret is never drawn)
|
||||
* set RenderDocumentFlags::UseWidgetLayers to force rendering to go
|
||||
|
@ -160,6 +160,7 @@ enum class RenderDocumentFlags {
|
||||
DocumentRelative = 1 << 5,
|
||||
DrawWindowNotFlushing = 1 << 6,
|
||||
UseHighQualityScaling = 1 << 7,
|
||||
ResetViewportScrolling = 1 << 8,
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(RenderDocumentFlags)
|
||||
|
@ -3224,12 +3224,34 @@ nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
|
||||
visibleRegion = aDirtyRegion;
|
||||
}
|
||||
|
||||
Maybe<nsPoint> originalScrollPosition;
|
||||
auto maybeResetScrollPosition = MakeScopeExit([&]() {
|
||||
if (originalScrollPosition && rootScrollFrame) {
|
||||
nsIScrollableFrame* rootScrollableFrame =
|
||||
presShell->GetRootScrollFrameAsScrollable();
|
||||
MOZ_ASSERT(rootScrollableFrame->GetScrolledFrame()->GetPosition() ==
|
||||
nsPoint());
|
||||
rootScrollableFrame->GetScrolledFrame()->SetPosition(
|
||||
*originalScrollPosition);
|
||||
}
|
||||
});
|
||||
|
||||
PresShell::AutoAssertNoFlush assertNoFlush(*presShell);
|
||||
nsRect canvasArea(nsPoint(0, 0), aFrame->GetSize());
|
||||
bool ignoreViewportScrolling =
|
||||
!aFrame->GetParent() && presShell->IgnoringViewportScrolling();
|
||||
if (ignoreViewportScrolling && rootScrollFrame) {
|
||||
nsIScrollableFrame* rootScrollableFrame =
|
||||
presShell->GetRootScrollFrameAsScrollable();
|
||||
if (aFlags & PaintFrameFlags::ResetViewportScrolling) {
|
||||
// Temporarily scroll the root scroll frame to 0,0 so that position:fixed
|
||||
// elements will appear fixed to the top-left of the document. We manually
|
||||
// set the position of the scrolled frame instead of using ScrollTo, since
|
||||
// the latter fires scroll listeners, which we don't want.
|
||||
originalScrollPosition.emplace(
|
||||
rootScrollableFrame->GetScrolledFrame()->GetPosition());
|
||||
rootScrollableFrame->GetScrolledFrame()->SetPosition(nsPoint());
|
||||
}
|
||||
if (aFlags & PaintFrameFlags::DocumentRelative) {
|
||||
// Make visibleRegion and aRenderingContext relative to the
|
||||
// scrolled frame instead of the root frame.
|
||||
|
@ -1098,6 +1098,7 @@ class nsLayoutUtils {
|
||||
Compressed = 0x200,
|
||||
ForWebRender = 0x400,
|
||||
UseHighQualityScaling = 0x800,
|
||||
ResetViewportScrolling = 0x1000,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1126,6 +1127,9 @@ class nsLayoutUtils {
|
||||
* as being relative to the document (normally it's relative to the CSS
|
||||
* viewport) and the document is painted as if no scrolling has occured.
|
||||
* Only considered if PresShell::IgnoringViewportScrolling is true.
|
||||
* If ResetViewportScrolling is used, then the root scroll frame's scroll
|
||||
* position is set to 0 during painting, so that position:fixed elements
|
||||
* are drawn in their initial position.
|
||||
* PAINT_TO_WINDOW sets painting to window to true on the display list
|
||||
* builder even if we can't tell that we are painting to the window.
|
||||
* If PAINT_EXISTING_TRANSACTION is set, then BeginTransaction() has already
|
||||
|
Loading…
Reference in New Issue
Block a user