Bug 1733509 - Use TryInferEnclosingResolution for event retargeting. r=botond

Differential Revision: https://phabricator.services.mozilla.com/D205378
This commit is contained in:
Alex Jakobi 2024-04-17 18:47:01 +00:00
parent 1f3a258de0
commit 5cd899a399
7 changed files with 147 additions and 15 deletions

View file

@ -91,5 +91,17 @@ GpuProcessQueryId GpuProcessQueryId::GetNext() {
return GpuProcessQueryId{++sCounter};
}
std::ostream& operator<<(std::ostream& os, ScrollDirection aDirection) {
switch (aDirection) {
case ScrollDirection::eHorizontal:
os << "horizontal";
break;
case ScrollDirection::eVertical:
os << "vertical";
break;
}
return os;
}
} // namespace layers
} // namespace mozilla

View file

@ -463,6 +463,8 @@ MOZ_DEFINE_ENUM_CLASS_WITH_BASE(ScrollDirection, uint8_t, (
eHorizontal
));
std::ostream& operator<<(std::ostream& os, ScrollDirection aDirection);
using ScrollDirections = EnumSet<ScrollDirection, uint8_t>;
constexpr ScrollDirections EitherScrollDirection(ScrollDirection::eVertical,ScrollDirection::eHorizontal);

View file

@ -6,6 +6,7 @@
#include "PositionedEventTargeting.h"
#include "Units.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Preferences.h"
@ -13,18 +14,23 @@
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_ui.h"
#include "mozilla/ToString.h"
#include "mozilla/ViewportUtils.h"
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/gfx/Matrix.h"
#include "mozilla/layers/LayersTypes.h"
#include "nsContainerFrame.h"
#include "nsCoord.h"
#include "nsFrameList.h" // for DEBUG_FRAME_DUMP
#include "nsHTMLParts.h"
#include "nsLayoutUtils.h"
#include "nsGkAtoms.h"
#include "nsFontMetrics.h"
#include "nsIContentInlines.h"
#include "nsPresContext.h"
#include "nsPrintfCString.h"
#include "mozilla/dom/Element.h"
#include "nsRegion.h"
#include "nsDeviceContext.h"
#include "nsIContentInlines.h"
#include "nsIFrame.h"
#include <algorithm>
@ -276,15 +282,40 @@ static nsIContent* GetClickableAncestor(
return nullptr;
}
static nscoord AppUnitsFromMM(RelativeTo aFrame, uint32_t aMM) {
nsPresContext* pc = aFrame.mFrame->PresContext();
float result = float(aMM) * (pc->DeviceContext()->AppUnitsPerPhysicalInch() /
MM_PER_INCH_FLOAT);
if (aFrame.mViewportType == ViewportType::Layout) {
PresShell* presShell = pc->PresShell();
result = result / presShell->GetResolution();
static Scale2D AppUnitsToMMScale(RelativeTo aFrame) {
nsPresContext* presContext = aFrame.mFrame->PresContext();
const int32_t appUnitsPerInch =
presContext->DeviceContext()->AppUnitsPerPhysicalInch();
const float appUnits =
static_cast<float>(appUnitsPerInch) / MM_PER_INCH_FLOAT;
// Visual coordinates are only used for quantities relative to the
// cross-process root content document's root frame. There should
// not be an enclosing resolution or transform scale above that.
if (aFrame.mViewportType != ViewportType::Layout) {
const nscoord scale = NSToCoordRound(appUnits);
return Scale2D{static_cast<float>(scale), static_cast<float>(scale)};
}
return NSToCoordRound(result);
Scale2D localResolution{1.0f, 1.0f};
Scale2D enclosingResolution{1.0f, 1.0f};
if (auto* pc = presContext->GetInProcessRootContentDocumentPresContext()) {
PresShell* presShell = pc->PresShell();
localResolution = {presShell->GetResolution(), presShell->GetResolution()};
enclosingResolution = ViewportUtils::TryInferEnclosingResolution(presShell);
}
const gfx::MatrixScales parentScale =
nsLayoutUtils::GetTransformToAncestorScale(aFrame.mFrame);
const Scale2D resolution =
localResolution * parentScale * enclosingResolution;
const nscoord scaleX = NSToCoordRound(appUnits / resolution.xScale);
const nscoord scaleY = NSToCoordRound(appUnits / resolution.yScale);
return {static_cast<float>(scaleX), static_cast<float>(scaleY)};
}
/**
@ -303,10 +334,11 @@ static nsRect GetTargetRect(RelativeTo aRootFrame,
const nsPoint& aPointRelativeToRootFrame,
const nsIFrame* aRestrictToDescendants,
const EventRadiusPrefs& aPrefs, uint32_t aFlags) {
nsMargin m(AppUnitsFromMM(aRootFrame, aPrefs.mRadiusTopmm),
AppUnitsFromMM(aRootFrame, aPrefs.mRadiusRightmm),
AppUnitsFromMM(aRootFrame, aPrefs.mRadiusBottommm),
AppUnitsFromMM(aRootFrame, aPrefs.mRadiusLeftmm));
const Scale2D scale = AppUnitsToMMScale(aRootFrame);
nsMargin m(aPrefs.mRadiusTopmm * scale.yScale,
aPrefs.mRadiusRightmm * scale.xScale,
aPrefs.mRadiusBottommm * scale.yScale,
aPrefs.mRadiusLeftmm * scale.xScale);
nsRect r(aPointRelativeToRootFrame, nsSize(0, 0));
r.Inflate(m);
if (!(aFlags & INPUT_IGNORE_ROOT_SCROLL_FRAME)) {

View file

@ -260,6 +260,9 @@ const nsIFrame* ViewportUtils::IsZoomedContentRoot(const nsIFrame* aFrame) {
}
Scale2D ViewportUtils::TryInferEnclosingResolution(PresShell* aShell) {
if (!XRE_IsContentProcess()) {
return {1.0f, 1.0f};
}
MOZ_ASSERT(aShell && aShell->GetPresContext());
MOZ_ASSERT(!aShell->GetPresContext()->GetParentPresContext(),
"TryInferEnclosingResolution can only be called for a root pres "

View file

@ -0,0 +1,30 @@
<html>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
<style>
body {
margin: 0;
padding: 20;
background-color: blueviolet;
}
button {
margin: 0;
}
</style>
<body>
<button id="btn">Click me</button>
</body>
<script>
// Silence SimpleTest warning about missing assertions by having it wait
// indefinitely. We don't need to give it an explicit finish because the
// entire window this test runs in will be closed after the main browser test
// finished.
SimpleTest.waitForExplicitFinish();
</script>
</html>

View file

@ -247,6 +247,7 @@ support-files = ["file_dynamic_toolbar_max_height.html"]
["test_emulate_color_scheme.html"]
["test_event_target_radius.html"]
support-files = ["helper_bug1733509.html"]
skip-if = ["xorigin"] # JavaScript error: resource://specialpowers/SpecialPowersChild.sys.mjs, line 73: SecurityError: Permission denied to access property "windowUtils" on cross-origin object
["test_frame_reconstruction_body_table.html"]

View file

@ -2,14 +2,19 @@
<html id="html" style="height:100%">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=780847
https://bugzilla.mozilla.org/show_bug.cgi?id=1733509
-->
<head>
<title>Test radii for mouse events</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
.target { position:absolute; left:100px; top:100px; width:100px; height:100px; background:blue; }
.scaled { background: green; transform: scale(0.5); }
iframe { margin:0; padding:0; width:50; height:50; border:1px solid black; background:yellowgreen; }
</style>
</head>
<body id="body" onload="setTimeout(startTest, 0)" style="margin:0; width:100%; height:100%; overflow:hidden">
@ -73,6 +78,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=780847
<div id="t13_touchlistener" style="width: 50px; height: 50px; background:red" ontouchend="x=1"></div>
<div id="t13_notouchlistener" style="width: 50px; height: 50px; background:green"></div>
</div>
<div id="t14" class="target scaled" hidden>
<iframe id="t14iframe"></iframe>
</div>
</div>
<pre id="test">
<script type="application/javascript">
@ -414,7 +423,50 @@ function testTouchable() {
testTouch("t13", 10, 50 - (2*mm), "t13_touchlistener", "touch inside t13_touchlistener bottom edge");
setShowing("t13", false);
endTest();
test4();
}
// https://bugzilla.mozilla.org/show_bug.cgi?id=1733509
function test4() {
// Skip non-Fission for now because of bug 1890522
if (SpecialPowers.Services.appinfo.fissionAutostart) {
waitUntilApzStable().then(async () => doTest4()).then(endTest);
} else {
endTest();
}
}
async function doTest4() {
setShowing("t14", true);
let iframeURL = SimpleTest.getTestFileURL("helper_bug1733509.html");
// todo: Also perform this test for an in-process iframe
// once bug 1890522 is fixed.
const iframe = document.querySelector("#t14iframe");
iframeURL = iframeURL.replace(window.location.origin, "https://example.com");
await setupIframe(iframe, iframeURL);
var result = await SpecialPowers.spawn(iframe, [], async () => {
await content.wrappedJSObject.waitUntilApzStable();
var iframeEventTarget = null;
content.window.onmousedown = function (event) { iframeEventTarget = event.target; };
content.wrappedJSObject.synthesizeMouse(content.document.documentElement, 2, 2, {});
return iframeEventTarget && iframeEventTarget.id === "btn";
});
ok(result, "Failed to target button inside iframe");
setShowing("t14", false);
}
async function setupIframe(aIFrame, aURL) {
const iframeLoadPromise = promiseOneEvent(aIFrame, "load", null);
aIFrame.src = aURL;
await iframeLoadPromise;
await SpecialPowers.spawn(aIFrame, [], async () => {
await content.wrappedJSObject.waitUntilApzStable();
await SpecialPowers.contentTransformsReceived(content);
});
}
</script>
</pre>