Bug 1744573: Apply single-level transforms in RemoteAccessibleBase::Bounds r=eeejay,Jamie,emilio

Differential Revision: https://phabricator.services.mozilla.com/D131554
This commit is contained in:
Morgan Reschenberg 2022-02-25 22:23:13 +00:00
Родитель 618acab981
Коммит 7aae56705c
6 изменённых файлов: 155 добавлений и 10 удалений

Просмотреть файл

@ -670,8 +670,8 @@ nsRect LocalAccessible::ParentRelativeBounds() {
}
nsIFrame* boundingFrame = FindNearestAccessibleAncestorFrame();
nsRect unionRect = nsLayoutUtils::GetAllInFlowRectsUnion(
frame, boundingFrame, nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
nsRect unionRect =
nsLayoutUtils::GetAllInFlowRectsUnion(frame, boundingFrame);
if (unionRect.IsEmpty()) {
// If we end up with a 0x0 rect from above (or one with negative
@ -3377,7 +3377,6 @@ void LocalAccessible::MaybeQueueCacheUpdateForStyleChanges() {
if (nsIFrame* frame = GetFrame()) {
const ComputedStyle* newStyle = frame->Style();
MOZ_ASSERT(newStyle != mOldComputedStyle, "New style matches old style!");
nsAutoCString oldVal, newVal;
mOldComputedStyle->GetComputedPropertyValue(eCSSProperty_display, oldVal);

Просмотреть файл

@ -16,6 +16,7 @@
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/gfx/Matrix.h"
#include "mozilla/Unused.h"
#include "nsAccUtils.h"
#include "nsTextEquivUtils.h"
@ -313,13 +314,39 @@ Maybe<nsRect> RemoteAccessibleBase<Derived>::RetrieveCachedBounds() const {
return Nothing();
}
template <class Derived>
bool RemoteAccessibleBase<Derived>::ApplyTransform(nsRect& aBounds) const {
// First, attempt to retrieve the transform from the cache.
Maybe<const UniquePtr<gfx::Matrix4x4>&> maybeTransform =
mCachedFields->GetAttribute<UniquePtr<gfx::Matrix4x4>>(
nsGkAtoms::transform);
if (!maybeTransform) {
return false;
}
// The transform matrix we cache is meant to operate on rects
// within the coordinate space of the frame to which the
// transform is applied (self-relative rects). We cache bounds
// relative to some ancestor. Remove the relative offset before
// transforming. The transform matrix will add it back in.
aBounds.MoveTo(0, 0);
auto mtxInPixels = gfx::Matrix4x4Typed<CSSPixel, CSSPixel>::FromUnknownMatrix(
*(*maybeTransform));
// Our matrix is in CSS Pixels, so we need our rect to be in CSS
// Pixels too. Convert before applying.
auto boundsInPixels = CSSRect::FromAppUnits(aBounds);
boundsInPixels = mtxInPixels.TransformBounds(boundsInPixels);
aBounds = CSSRect::ToAppUnits(boundsInPixels);
return true;
}
template <class Derived>
LayoutDeviceIntRect RemoteAccessibleBase<Derived>::Bounds() const {
if (mCachedFields) {
Maybe<nsRect> maybeBounds = RetrieveCachedBounds();
if (maybeBounds) {
nsRect bounds = *maybeBounds;
LayoutDeviceIntRect devPxBounds;
dom::CanonicalBrowsingContext* cbc =
static_cast<dom::BrowserParent*>(mDoc->Manager())
->GetBrowsingContext()
@ -328,7 +355,11 @@ LayoutDeviceIntRect RemoteAccessibleBase<Derived>::Bounds() const {
nsPresContext* presContext =
bp->GetOwnerElement()->OwnerDoc()->GetPresContext();
Unused << ApplyTransform(bounds);
LayoutDeviceIntRect devPxBounds;
const Accessible* acc = this;
while (acc) {
if (LocalAccessible* localAcc =
const_cast<Accessible*>(acc)->AsLocal()) {
@ -349,7 +380,6 @@ LayoutDeviceIntRect RemoteAccessibleBase<Derived>::Bounds() const {
// by GetFullZoom because LocalAccessible::Bounds already does
// that.
devPxBounds.MoveBy(localBounds.X(), localBounds.Y());
break;
}
@ -360,6 +390,7 @@ LayoutDeviceIntRect RemoteAccessibleBase<Derived>::Bounds() const {
(remoteAcc == this) ? Nothing() : remoteAcc->RetrieveCachedBounds();
if (maybeRemoteBounds) {
nsRect remoteBounds = *maybeRemoteBounds;
// We need to take into account a non-1 resolution set on the
// presshell. This happens with async pinch zooming, among other
// things. We can't reliably query this value in the parent process,
@ -378,11 +409,10 @@ LayoutDeviceIntRect RemoteAccessibleBase<Derived>::Bounds() const {
bounds.ScaleRoundOut(res.valueOr(1.0f));
}
// Regardless of whether this is a doc, we should offset `bounds`
// by the bounds retrieved here. This is how we build screen
// coordinates from relative coordinates.
nsRect remoteBounds = *maybeRemoteBounds;
// We should offset `bounds` by the bounds retrieved above.
// This is how we build screen coordinates from relative coordinates.
bounds.MoveBy(remoteBounds.X(), remoteBounds.Y());
Unused << remoteAcc->ApplyTransform(bounds);
}
acc = acc->Parent();

Просмотреть файл

@ -320,6 +320,7 @@ class RemoteAccessibleBase : public Accessible, public HyperTextAccessibleBase {
protected:
void SetParent(Derived* aParent);
Maybe<nsRect> RetrieveCachedBounds() const;
bool ApplyTransform(nsRect& aBounds) const;
virtual void ARIAGroupPosition(int32_t* aLevel, int32_t* aSetSize,
int32_t* aPosInSet) const override;

Просмотреть файл

@ -17,3 +17,4 @@ https_first_disabled = true
skip-if = e10s && os == 'win' # bug 1372296
[browser_zero_area.js]
[browser_test_display_contents.js]
[browser_test_simple_transform.js]

Просмотреть файл

@ -0,0 +1,110 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
async function finishContentPaint(browser) {
await SpecialPowers.spawn(browser, [], () => {
return new Promise(function(r) {
content.requestAnimationFrame(() => content.setTimeout(r));
});
});
}
async function testContentBoundsInIframe(iframeDocAcc, id, browser) {
const acc = findAccessibleChildByID(iframeDocAcc, id);
const x = {};
const y = {};
const width = {};
const height = {};
acc.getBounds(x, y, width, height);
await invokeContentTask(
browser,
[id, x.value, y.value, width.value, height.value],
(_id, _x, _y, _width, _height) => {
const { Layout: LayoutUtils } = ChromeUtils.import(
"chrome://mochitests/content/browser/accessible/tests/browser/Layout.jsm"
);
let [
expectedX,
expectedY,
expectedWidth,
expectedHeight,
] = LayoutUtils.getBoundsForDOMElm(_id, content.document);
ok(
_x >= expectedX - 5 || _x <= expectedX + 5,
"Got " + _x + ", accurate x for " + _id
);
ok(
_y >= expectedY - 5 || _y <= expectedY + 5,
"Got " + _y + ", accurate y for " + _id
);
ok(
_width >= expectedWidth - 5 || _width <= expectedWidth + 5,
"Got " + _width + ", accurate width for " + _id
);
ok(
_height >= expectedHeight - 5 || _height <= expectedHeight + 5,
"Got " + _height + ", accurate height for " + _id
);
}
);
}
// test basic translation
addAccessibleTask(
`<p id="translate">hello world</p>`,
async function(browser, iframeDocAcc, contentDocAcc) {
ok(iframeDocAcc, "IFRAME document accessible is present");
await testContentBoundsInIframe(iframeDocAcc, "translate", browser);
await invokeContentTask(browser, [], () => {
let p = content.document.getElementById("translate");
p.style = "transform: translate(100px, 100px);";
});
await finishContentPaint(browser);
await testContentBoundsInIframe(iframeDocAcc, "translate", browser);
},
{ topLevel: true, iframe: true, remoteIframe: true }
);
// test basic rotation
addAccessibleTask(
`<p id="rotate">hello world</p>`,
async function(browser, iframeDocAcc, contentDocAcc) {
ok(iframeDocAcc, "IFRAME document accessible is present");
await testContentBoundsInIframe(iframeDocAcc, "rotate", browser);
await invokeContentTask(browser, [], () => {
let p = content.document.getElementById("rotate");
p.style = "transform: rotate(-40deg);";
});
await finishContentPaint(browser);
await testContentBoundsInIframe(iframeDocAcc, "rotate", browser);
},
{ topLevel: true, iframe: true, remoteIframe: true }
);
// test basic scale
addAccessibleTask(
`<p id="scale">hello world</p>`,
async function(browser, iframeDocAcc, contentDocAcc) {
ok(iframeDocAcc, "IFRAME document accessible is present");
await testContentBoundsInIframe(iframeDocAcc, "scale", browser);
await invokeContentTask(browser, [], () => {
let p = content.document.getElementById("scale");
p.style = "transform: scale(2);";
});
await finishContentPaint(browser);
await testContentBoundsInIframe(iframeDocAcc, "scale", browser);
},
{ topLevel: true, iframe: true, remoteIframe: true }
);

Просмотреть файл

@ -3680,7 +3680,11 @@ struct BoxToRect : public nsLayoutUtils::BoxCallback {
nsLayoutUtils::TransformRect(outer, mRelativeTo, r);
}
} else {
r += outer->GetOffsetTo(mRelativeTo);
if (aFrame->PresContext() != mRelativeTo->PresContext()) {
r += outer->GetOffsetToCrossDoc(mRelativeTo);
} else {
r += outer->GetOffsetTo(mRelativeTo);
}
}
mCallback->AddRect(r);
}