зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1731009 - Properly check whether the given nsIFrame is inside an OOP Iframe visible rect or not even if the frame size is (0x0). r=tnikkel
Before this change, in nsLayoutUtils::FrameIsScrolledOutOfViewInCrossProcess we call BaseRect::IsEmpty() for the returned value of GetFrameVisibleRectOnScreen, unfortunately if the returned value size is (0x0), BaseRect::IsEmpty() returns true thus we misthink the given nsIFrame is out of the visible area of the OOP iframe where the nsIFrame lives. Note that we have already done the same check for in-process cases in IsFrameScrolledOutOfView [1]. The test case in this change fails without this change, suceeds with the change. Though, to be honest, I don't know the reason those styles , `display: grid`, etc. generate (0x0) sized frame even if decendants have sized. [1] https://searchfox.org/mozilla-central/rev/15de05f0e6d841cbc2ac66f8dcad72ebdada47f6/layout/generic/nsIFrame.cpp#11090-11094 Differential Revision: https://phabricator.services.mozilla.com/D126312
This commit is contained in:
Родитель
26910d70ce
Коммит
3608e394a5
|
@ -22,7 +22,6 @@ support-files =
|
|||
mozilla/file_disable_animations_api_implicit_keyframes.html
|
||||
mozilla/file_disable_animations_api_timelines.html
|
||||
mozilla/file_discrete_animations.html
|
||||
mozilla/file_restyles.html
|
||||
mozilla/file_transition_finish_on_compositor.html
|
||||
../../../layout/style/test/property_database.js
|
||||
testcommon.js
|
||||
|
@ -53,6 +52,9 @@ skip-if = (os == 'win' && bits == 64) # Bug 1363957
|
|||
skip-if =
|
||||
fission && xorigin && os == "linux" && !debug # Bug 1716403 - New fission platform triage
|
||||
[mozilla/test_restyles.html]
|
||||
support-files =
|
||||
mozilla/file_restyles.html
|
||||
mozilla/empty.html
|
||||
skip-if =
|
||||
os == 'win' && !webrender # Bug 1663509
|
||||
[mozilla/test_restyling_xhr_doc.html]
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="../testcommon.js"></script>
|
|
@ -2165,6 +2165,60 @@ waitForAllPaints(() => {
|
|||
|
||||
await ensureElementRemoval(div);
|
||||
});
|
||||
|
||||
add_task_if_omta_enabled(async function transform_animation_on_collapsed_element() {
|
||||
const iframe = document.createElement('iframe');
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
// Load a cross origin iframe.
|
||||
const targetURL = SimpleTest.getTestFileURL("empty.html")
|
||||
.replace(window.location.origin, "http://example.com/");
|
||||
iframe.src = targetURL;
|
||||
await new Promise(resolve => {
|
||||
iframe.onload = resolve;
|
||||
});
|
||||
|
||||
await SpecialPowers.spawn(iframe, [MS_PER_SEC], async (MS_PER_SEC) => {
|
||||
// Create a flex item with "preserve-3d" having an abs-pos child inside
|
||||
// a grid container.
|
||||
// These styles make the the flex item size (0x0).
|
||||
const gridContainer = content.document.createElement("div");
|
||||
gridContainer.style.display = "grid";
|
||||
gridContainer.style.placeItems = "center";
|
||||
|
||||
const target = content.document.createElement("div");
|
||||
target.style.display = "flex";
|
||||
target.style.transformStyle = "preserve-3d";
|
||||
gridContainer.appendChild(target);
|
||||
|
||||
const child = content.document.createElement("div");
|
||||
child.style.position = "absolute";
|
||||
child.style.transform = "rotateY(0deg)";
|
||||
child.style.width = "100px";
|
||||
child.style.height = "100px";
|
||||
child.style.backgroundColor = "green";
|
||||
target.appendChild(child);
|
||||
|
||||
content.document.body.appendChild(gridContainer);
|
||||
|
||||
const animation =
|
||||
target.animate({ transform: [ "rotateY(0deg)", "rotateY(360deg)" ] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
id: "test",
|
||||
easing: 'step-end' });
|
||||
await content.wrappedJSObject.waitForAnimationReadyToRestyle(animation);
|
||||
ok(SpecialPowers.wrap(animation).isRunningOnCompositor,
|
||||
'transform animation on a collapsed element should run on the ' +
|
||||
'compositor');
|
||||
|
||||
const markers = await content.wrappedJSObject.observeStyling(5);
|
||||
is(markers.length, 0,
|
||||
'transform animation on a collapsed element animation should not ' +
|
||||
'update styles on the main thread');
|
||||
});
|
||||
|
||||
await ensureElementRemoval(iframe);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
@ -9714,32 +9714,40 @@ ComputedStyle* nsLayoutUtils::StyleForScrollbar(nsIFrame* aScrollbarPart) {
|
|||
return style.get();
|
||||
}
|
||||
|
||||
// NOTE: Returns Nothing() if |aFrame| is not in out-of-process or if we haven't
|
||||
// received enough information from APZ.
|
||||
static Maybe<ScreenRect> GetFrameVisibleRectOnScreen(const nsIFrame* aFrame) {
|
||||
enum class FramePosition : uint8_t {
|
||||
Unknown,
|
||||
InView,
|
||||
OutOfView,
|
||||
};
|
||||
|
||||
// NOTE: Returns a pair of Nothing() and `FramePosition::Unknown` if |aFrame|
|
||||
// is not in out-of-process or if we haven't received enough information from
|
||||
// APZ.
|
||||
static std::pair<Maybe<ScreenRect>, FramePosition> GetFrameVisibleRectOnScreen(
|
||||
const nsIFrame* aFrame) {
|
||||
// We actually want the in-process top prescontext here.
|
||||
nsPresContext* topContextInProcess =
|
||||
aFrame->PresContext()->GetInProcessRootContentDocumentPresContext();
|
||||
if (!topContextInProcess) {
|
||||
// We are in chrome process.
|
||||
return Nothing();
|
||||
return std::make_pair(Nothing(), FramePosition::Unknown);
|
||||
}
|
||||
|
||||
if (topContextInProcess->Document()->IsTopLevelContentDocument()) {
|
||||
// We are in the top of content document.
|
||||
return Nothing();
|
||||
return std::make_pair(Nothing(), FramePosition::Unknown);
|
||||
}
|
||||
|
||||
nsIDocShell* docShell = topContextInProcess->GetDocShell();
|
||||
BrowserChild* browserChild = BrowserChild::GetFrom(docShell);
|
||||
if (!browserChild) {
|
||||
// We are not in out-of-process iframe.
|
||||
return Nothing();
|
||||
return std::make_pair(Nothing(), FramePosition::Unknown);
|
||||
}
|
||||
|
||||
if (!browserChild->GetEffectsInfo().IsVisible()) {
|
||||
// There is no visible rect on this iframe at all.
|
||||
return Some(ScreenRect());
|
||||
return std::make_pair(Some(ScreenRect()), FramePosition::Unknown);
|
||||
}
|
||||
|
||||
Maybe<ScreenRect> visibleRect =
|
||||
|
@ -9747,7 +9755,7 @@ static Maybe<ScreenRect> GetFrameVisibleRectOnScreen(const nsIFrame* aFrame) {
|
|||
if (!visibleRect) {
|
||||
// We are unsure if we haven't received the transformed rectangle of the
|
||||
// iframe's visible area.
|
||||
return Nothing();
|
||||
return std::make_pair(Nothing(), FramePosition::Unknown);
|
||||
}
|
||||
|
||||
nsIFrame* rootFrame = topContextInProcess->PresShell()->GetRootFrame();
|
||||
|
@ -9762,24 +9770,42 @@ static Maybe<ScreenRect> GetFrameVisibleRectOnScreen(const nsIFrame* aFrame) {
|
|||
rectInLayoutDevicePixel),
|
||||
PixelCastJustification::ContentProcessIsLayerInUiProcess);
|
||||
|
||||
return Some(visibleRect->Intersect(transformedToRoot));
|
||||
FramePosition position = FramePosition::Unknown;
|
||||
// we need to check whether the transformed rect is outside the iframe
|
||||
// visible rect or not because in some cases the rect size is (0x0), thus
|
||||
// the intersection between the transformed rect and the iframe visible rect
|
||||
// would also be (0x0), then we can't tell whether the given nsIFrame is
|
||||
// inside the iframe visible rect or not by calling BaseRect::IsEmpty for the
|
||||
// intersection.
|
||||
if (transformedToRoot.x > visibleRect->XMost() ||
|
||||
transformedToRoot.y > visibleRect->YMost() ||
|
||||
visibleRect->x > transformedToRoot.XMost() ||
|
||||
visibleRect->y > transformedToRoot.YMost()) {
|
||||
position = FramePosition::OutOfView;
|
||||
} else {
|
||||
position = FramePosition::InView;
|
||||
}
|
||||
|
||||
return std::make_pair(Some(visibleRect->Intersect(transformedToRoot)),
|
||||
position);
|
||||
}
|
||||
|
||||
// static
|
||||
bool nsLayoutUtils::FrameIsScrolledOutOfViewInCrossProcess(
|
||||
const nsIFrame* aFrame) {
|
||||
Maybe<ScreenRect> visibleRect = GetFrameVisibleRectOnScreen(aFrame);
|
||||
auto [visibleRect, framePosition] = GetFrameVisibleRectOnScreen(aFrame);
|
||||
if (visibleRect.isNothing()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return visibleRect->IsEmpty();
|
||||
return visibleRect->IsEmpty() && framePosition != FramePosition::InView;
|
||||
}
|
||||
|
||||
// static
|
||||
bool nsLayoutUtils::FrameIsMostlyScrolledOutOfViewInCrossProcess(
|
||||
const nsIFrame* aFrame, nscoord aMargin) {
|
||||
Maybe<ScreenRect> visibleRect = GetFrameVisibleRectOnScreen(aFrame);
|
||||
auto [visibleRect, framePosition] = GetFrameVisibleRectOnScreen(aFrame);
|
||||
(void)framePosition;
|
||||
if (visibleRect.isNothing()) {
|
||||
return false;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче