зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
618acab981
Коммит
7aae56705c
|
@ -670,8 +670,8 @@ nsRect LocalAccessible::ParentRelativeBounds() {
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIFrame* boundingFrame = FindNearestAccessibleAncestorFrame();
|
nsIFrame* boundingFrame = FindNearestAccessibleAncestorFrame();
|
||||||
nsRect unionRect = nsLayoutUtils::GetAllInFlowRectsUnion(
|
nsRect unionRect =
|
||||||
frame, boundingFrame, nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
|
nsLayoutUtils::GetAllInFlowRectsUnion(frame, boundingFrame);
|
||||||
|
|
||||||
if (unionRect.IsEmpty()) {
|
if (unionRect.IsEmpty()) {
|
||||||
// If we end up with a 0x0 rect from above (or one with negative
|
// 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()) {
|
if (nsIFrame* frame = GetFrame()) {
|
||||||
const ComputedStyle* newStyle = frame->Style();
|
const ComputedStyle* newStyle = frame->Style();
|
||||||
MOZ_ASSERT(newStyle != mOldComputedStyle, "New style matches old style!");
|
|
||||||
|
|
||||||
nsAutoCString oldVal, newVal;
|
nsAutoCString oldVal, newVal;
|
||||||
mOldComputedStyle->GetComputedPropertyValue(eCSSProperty_display, oldVal);
|
mOldComputedStyle->GetComputedPropertyValue(eCSSProperty_display, oldVal);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "mozilla/dom/BrowserParent.h"
|
#include "mozilla/dom/BrowserParent.h"
|
||||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||||
#include "mozilla/dom/DocumentInlines.h"
|
#include "mozilla/dom/DocumentInlines.h"
|
||||||
|
#include "mozilla/gfx/Matrix.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
#include "nsAccUtils.h"
|
#include "nsAccUtils.h"
|
||||||
#include "nsTextEquivUtils.h"
|
#include "nsTextEquivUtils.h"
|
||||||
|
@ -313,13 +314,39 @@ Maybe<nsRect> RemoteAccessibleBase<Derived>::RetrieveCachedBounds() const {
|
||||||
return Nothing();
|
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>
|
template <class Derived>
|
||||||
LayoutDeviceIntRect RemoteAccessibleBase<Derived>::Bounds() const {
|
LayoutDeviceIntRect RemoteAccessibleBase<Derived>::Bounds() const {
|
||||||
if (mCachedFields) {
|
if (mCachedFields) {
|
||||||
Maybe<nsRect> maybeBounds = RetrieveCachedBounds();
|
Maybe<nsRect> maybeBounds = RetrieveCachedBounds();
|
||||||
if (maybeBounds) {
|
if (maybeBounds) {
|
||||||
nsRect bounds = *maybeBounds;
|
nsRect bounds = *maybeBounds;
|
||||||
LayoutDeviceIntRect devPxBounds;
|
|
||||||
dom::CanonicalBrowsingContext* cbc =
|
dom::CanonicalBrowsingContext* cbc =
|
||||||
static_cast<dom::BrowserParent*>(mDoc->Manager())
|
static_cast<dom::BrowserParent*>(mDoc->Manager())
|
||||||
->GetBrowsingContext()
|
->GetBrowsingContext()
|
||||||
|
@ -328,7 +355,11 @@ LayoutDeviceIntRect RemoteAccessibleBase<Derived>::Bounds() const {
|
||||||
nsPresContext* presContext =
|
nsPresContext* presContext =
|
||||||
bp->GetOwnerElement()->OwnerDoc()->GetPresContext();
|
bp->GetOwnerElement()->OwnerDoc()->GetPresContext();
|
||||||
|
|
||||||
|
Unused << ApplyTransform(bounds);
|
||||||
|
|
||||||
|
LayoutDeviceIntRect devPxBounds;
|
||||||
const Accessible* acc = this;
|
const Accessible* acc = this;
|
||||||
|
|
||||||
while (acc) {
|
while (acc) {
|
||||||
if (LocalAccessible* localAcc =
|
if (LocalAccessible* localAcc =
|
||||||
const_cast<Accessible*>(acc)->AsLocal()) {
|
const_cast<Accessible*>(acc)->AsLocal()) {
|
||||||
|
@ -349,7 +380,6 @@ LayoutDeviceIntRect RemoteAccessibleBase<Derived>::Bounds() const {
|
||||||
// by GetFullZoom because LocalAccessible::Bounds already does
|
// by GetFullZoom because LocalAccessible::Bounds already does
|
||||||
// that.
|
// that.
|
||||||
devPxBounds.MoveBy(localBounds.X(), localBounds.Y());
|
devPxBounds.MoveBy(localBounds.X(), localBounds.Y());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,6 +390,7 @@ LayoutDeviceIntRect RemoteAccessibleBase<Derived>::Bounds() const {
|
||||||
(remoteAcc == this) ? Nothing() : remoteAcc->RetrieveCachedBounds();
|
(remoteAcc == this) ? Nothing() : remoteAcc->RetrieveCachedBounds();
|
||||||
|
|
||||||
if (maybeRemoteBounds) {
|
if (maybeRemoteBounds) {
|
||||||
|
nsRect remoteBounds = *maybeRemoteBounds;
|
||||||
// We need to take into account a non-1 resolution set on the
|
// We need to take into account a non-1 resolution set on the
|
||||||
// presshell. This happens with async pinch zooming, among other
|
// presshell. This happens with async pinch zooming, among other
|
||||||
// things. We can't reliably query this value in the parent process,
|
// 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));
|
bounds.ScaleRoundOut(res.valueOr(1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regardless of whether this is a doc, we should offset `bounds`
|
// We should offset `bounds` by the bounds retrieved above.
|
||||||
// by the bounds retrieved here. This is how we build screen
|
// This is how we build screen coordinates from relative coordinates.
|
||||||
// coordinates from relative coordinates.
|
|
||||||
nsRect remoteBounds = *maybeRemoteBounds;
|
|
||||||
bounds.MoveBy(remoteBounds.X(), remoteBounds.Y());
|
bounds.MoveBy(remoteBounds.X(), remoteBounds.Y());
|
||||||
|
Unused << remoteAcc->ApplyTransform(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
acc = acc->Parent();
|
acc = acc->Parent();
|
||||||
|
|
|
@ -320,6 +320,7 @@ class RemoteAccessibleBase : public Accessible, public HyperTextAccessibleBase {
|
||||||
protected:
|
protected:
|
||||||
void SetParent(Derived* aParent);
|
void SetParent(Derived* aParent);
|
||||||
Maybe<nsRect> RetrieveCachedBounds() const;
|
Maybe<nsRect> RetrieveCachedBounds() const;
|
||||||
|
bool ApplyTransform(nsRect& aBounds) const;
|
||||||
|
|
||||||
virtual void ARIAGroupPosition(int32_t* aLevel, int32_t* aSetSize,
|
virtual void ARIAGroupPosition(int32_t* aLevel, int32_t* aSetSize,
|
||||||
int32_t* aPosInSet) const override;
|
int32_t* aPosInSet) const override;
|
||||||
|
|
|
@ -17,3 +17,4 @@ https_first_disabled = true
|
||||||
skip-if = e10s && os == 'win' # bug 1372296
|
skip-if = e10s && os == 'win' # bug 1372296
|
||||||
[browser_zero_area.js]
|
[browser_zero_area.js]
|
||||||
[browser_test_display_contents.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);
|
nsLayoutUtils::TransformRect(outer, mRelativeTo, r);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
r += outer->GetOffsetTo(mRelativeTo);
|
if (aFrame->PresContext() != mRelativeTo->PresContext()) {
|
||||||
|
r += outer->GetOffsetToCrossDoc(mRelativeTo);
|
||||||
|
} else {
|
||||||
|
r += outer->GetOffsetTo(mRelativeTo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mCallback->AddRect(r);
|
mCallback->AddRect(r);
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче