mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1744573: Cache the transform matrix r=eeejay,Jamie
Differential Revision: https://phabricator.services.mozilla.com/D133134
This commit is contained in:
parent
ac056a416f
commit
618acab981
@ -5,6 +5,7 @@
|
||||
|
||||
#include "AccAttributes.h"
|
||||
#include "StyleInfo.h"
|
||||
#include "mozilla/ToString.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
@ -65,6 +66,9 @@ void AccAttributes::StringFromValueAndName(nsAtom* aAttrName,
|
||||
[&aValueString](const uint64_t& val) { aValueString.AppendInt(val); },
|
||||
[&aValueString](const UniquePtr<AccGroupInfo>& val) {
|
||||
aValueString.Assign(u"AccGroupInfo{...}");
|
||||
},
|
||||
[&aValueString](const UniquePtr<gfx::Matrix4x4>& val) {
|
||||
aValueString.AppendPrintf("Matrix4x4=%s", ToString(*val).c_str());
|
||||
});
|
||||
}
|
||||
|
||||
@ -157,6 +161,10 @@ void AccAttributes::CopyTo(AccAttributes* aDest) const {
|
||||
[](const UniquePtr<AccGroupInfo>& val) {
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"Trying to copy an AccAttributes containing an AccGroupInfo");
|
||||
},
|
||||
[](const UniquePtr<gfx::Matrix4x4>& val) {
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"Trying to copy an AccAttributes containing a matrix");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsTHashMap.h"
|
||||
#include "nsAtom.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
|
||||
class nsVariant;
|
||||
|
||||
@ -68,7 +69,8 @@ class AccAttributes {
|
||||
using AttrValueType =
|
||||
Variant<bool, float, double, int32_t, RefPtr<nsAtom>, nsTArray<int32_t>,
|
||||
CSSCoord, FontSize, Color, DeleteEntry, UniquePtr<nsString>,
|
||||
RefPtr<AccAttributes>, uint64_t, UniquePtr<AccGroupInfo>>;
|
||||
RefPtr<AccAttributes>, uint64_t, UniquePtr<AccGroupInfo>,
|
||||
UniquePtr<gfx::Matrix4x4>>;
|
||||
static_assert(sizeof(AttrValueType) <= 16);
|
||||
using AtomVariantMap = nsTHashMap<nsRefPtrHashKey<nsAtom>, AttrValueType>;
|
||||
|
||||
@ -87,6 +89,7 @@ class AccAttributes {
|
||||
template <typename T, typename std::enable_if<
|
||||
!std::is_convertible_v<T, nsString> &&
|
||||
!std::is_convertible_v<T, AccGroupInfo*> &&
|
||||
!std::is_convertible_v<T, gfx::Matrix4x4> &&
|
||||
!std::is_convertible_v<T, nsAtom*>,
|
||||
bool>::type = true>
|
||||
void SetAttribute(nsAtom* aAttrName, T&& aAttrValue) {
|
||||
@ -101,6 +104,11 @@ class AccAttributes {
|
||||
|
||||
void SetAttribute(nsAtom* aAttrName, AccGroupInfo* aAttrValue) {
|
||||
UniquePtr<AccGroupInfo> value(aAttrValue);
|
||||
}
|
||||
|
||||
void SetAttribute(nsAtom* aAttrName, gfx::Matrix4x4&& aAttrValue) {
|
||||
UniquePtr<gfx::Matrix4x4> value = MakeUnique<gfx::Matrix4x4>();
|
||||
*value = std::forward<gfx::Matrix4x4>(aAttrValue);
|
||||
mData.InsertOrUpdate(aAttrName, AsVariant(std::move(value)));
|
||||
}
|
||||
|
||||
@ -120,6 +128,11 @@ class AccAttributes {
|
||||
const T& val = *(value->as<UniquePtr<nsString>>().get());
|
||||
return SomeRef(val);
|
||||
}
|
||||
} else if constexpr (std::is_same_v<gfx::Matrix4x4, T>) {
|
||||
if (value->is<UniquePtr<gfx::Matrix4x4>>()) {
|
||||
const T& val = *(value->as<UniquePtr<gfx::Matrix4x4>>());
|
||||
return SomeRef(val);
|
||||
}
|
||||
} else {
|
||||
if (value->is<T>()) {
|
||||
const T& val = value->as<T>();
|
||||
@ -184,6 +197,11 @@ class AccAttributes {
|
||||
const T& val = *(mValue->as<UniquePtr<nsString>>().get());
|
||||
return SomeRef(val);
|
||||
}
|
||||
} else if constexpr (std::is_same_v<gfx::Matrix4x4, T>) {
|
||||
if (mValue->is<UniquePtr<gfx::Matrix4x4>>()) {
|
||||
const T& val = *(mValue->as<UniquePtr<gfx::Matrix4x4>>());
|
||||
return SomeRef(val);
|
||||
}
|
||||
} else {
|
||||
if (mValue->is<T>()) {
|
||||
const T& val = mValue->as<T>();
|
||||
|
@ -22,6 +22,7 @@ class CacheDomain {
|
||||
static constexpr uint64_t GroupInfo = ((uint64_t)0x1) << 7;
|
||||
static constexpr uint64_t Actions = ((uint64_t)0x1) << 8;
|
||||
static constexpr uint64_t Style = ((uint64_t)0x1) << 9;
|
||||
static constexpr uint64_t TransformMatrix = ((uint64_t)0x1) << 10;
|
||||
static constexpr uint64_t All = ~((uint64_t)0x0);
|
||||
};
|
||||
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
#include "mozilla/dom/HTMLAnchorElement.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIFormControl.h"
|
||||
|
||||
@ -606,8 +607,44 @@ LocalAccessible* LocalAccessible::LocalChildAtPoint(
|
||||
return accessible;
|
||||
}
|
||||
|
||||
nsRect LocalAccessible::ParentRelativeBounds() {
|
||||
nsIFrame* LocalAccessible::FindNearestAccessibleAncestorFrame() {
|
||||
nsIFrame* frame = GetFrame();
|
||||
nsIFrame* boundingFrame = nullptr;
|
||||
|
||||
if (IsDoc() &&
|
||||
nsCoreUtils::IsTopLevelContentDocInProcess(AsDoc()->DocumentNode())) {
|
||||
// Tab documents and OOP iframe docs won't have ancestor accessibles
|
||||
// with frames. Instead, bound by their presshell's root frame.
|
||||
boundingFrame = nsLayoutUtils::GetContainingBlockForClientRect(frame);
|
||||
}
|
||||
|
||||
// Iterate through accessible's ancestors to find one with a frame.
|
||||
LocalAccessible* ancestor = mParent;
|
||||
while (ancestor && !boundingFrame) {
|
||||
if (ancestor->IsDoc()) {
|
||||
// If we find a doc accessible, use its presshell's root frame
|
||||
// (since doc accessibles themselves don't have frames).
|
||||
boundingFrame = nsLayoutUtils::GetContainingBlockForClientRect(frame);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((boundingFrame = ancestor->GetFrame())) {
|
||||
// Otherwise, if the ancestor has a frame, use that
|
||||
break;
|
||||
}
|
||||
|
||||
ancestor = ancestor->LocalParent();
|
||||
}
|
||||
|
||||
if (!boundingFrame) {
|
||||
MOZ_ASSERT_UNREACHABLE("No ancestor with frame?");
|
||||
boundingFrame = nsLayoutUtils::GetContainingBlockForClientRect(frame);
|
||||
}
|
||||
|
||||
return boundingFrame;
|
||||
}
|
||||
|
||||
nsRect LocalAccessible::ParentRelativeBounds() {
|
||||
nsIFrame* frame = GetFrame();
|
||||
if (frame && mContent) {
|
||||
if (mContent->GetProperty(nsGkAtoms::hitregion) && mContent->IsElement()) {
|
||||
@ -632,43 +669,7 @@ nsRect LocalAccessible::ParentRelativeBounds() {
|
||||
}
|
||||
}
|
||||
|
||||
// We need to find a frame to make our bounds relative to. We'll store this
|
||||
// in `boundingFrame`. Ultimately, we'll create screen-relative coordinates
|
||||
// by summing the x, y offsets of our ancestors' bounds in
|
||||
// RemoteAccessibleBase::Bounds(), so it is important that our bounding
|
||||
// frame have a corresponding accessible.
|
||||
if (IsDoc() &&
|
||||
nsCoreUtils::IsTopLevelContentDocInProcess(AsDoc()->DocumentNode())) {
|
||||
// Tab documents and OOP iframe docs won't have ancestor accessibles with
|
||||
// frames. We'll use their presshell root frame instead.
|
||||
// XXX bug 1736635: Should DocAccessibles return their presShell frame on
|
||||
// GetFrame()?
|
||||
boundingFrame = nsLayoutUtils::GetContainingBlockForClientRect(frame);
|
||||
}
|
||||
|
||||
// Iterate through ancestors to find one with a frame.
|
||||
LocalAccessible* parent = mParent;
|
||||
while (parent && !boundingFrame) {
|
||||
if (parent->IsDoc()) {
|
||||
// If we find a doc accessible, use its presshell's root frame
|
||||
// (since doc accessibles themselves don't have frames).
|
||||
boundingFrame = nsLayoutUtils::GetContainingBlockForClientRect(frame);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((boundingFrame = parent->GetFrame())) {
|
||||
// Otherwise, if the parent has a frame, use that
|
||||
break;
|
||||
}
|
||||
|
||||
parent = parent->LocalParent();
|
||||
}
|
||||
|
||||
if (!boundingFrame) {
|
||||
MOZ_ASSERT_UNREACHABLE("No ancestor with frame?");
|
||||
boundingFrame = nsLayoutUtils::GetContainingBlockForClientRect(frame);
|
||||
}
|
||||
|
||||
nsIFrame* boundingFrame = FindNearestAccessibleAncestorFrame();
|
||||
nsRect unionRect = nsLayoutUtils::GetAllInFlowRectsUnion(
|
||||
frame, boundingFrame, nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
|
||||
|
||||
@ -3246,6 +3247,34 @@ already_AddRefed<AccAttributes> LocalAccessible::BundleFieldsForCache(
|
||||
}
|
||||
}
|
||||
|
||||
if (aCacheDomain & CacheDomain::TransformMatrix) {
|
||||
nsIFrame* frame = GetFrame();
|
||||
|
||||
if (frame && frame->IsTransformed()) {
|
||||
// We need to find a frame to make our transform relative to.
|
||||
// It's important this frame have a corresponding accessible,
|
||||
// because this transform is applied while walking the accessibility
|
||||
// tree (in the parent process), not the frame tree.
|
||||
nsIFrame* boundingFrame = FindNearestAccessibleAncestorFrame();
|
||||
// This matrix is only valid when applied to CSSPixel points/rects
|
||||
// in the coordinate space of `frame`. It also includes the translation
|
||||
// to the parent space.
|
||||
gfx::Matrix4x4 mtx = nsLayoutUtils::GetTransformToAncestor(
|
||||
RelativeTo{frame}, RelativeTo{boundingFrame},
|
||||
nsIFrame::IN_CSS_UNITS)
|
||||
.GetMatrix();
|
||||
|
||||
UniquePtr<gfx::Matrix4x4> ptr = MakeUnique<gfx::Matrix4x4>(mtx);
|
||||
fields->SetAttribute(nsGkAtoms::transform, std::move(ptr));
|
||||
} else {
|
||||
// Otherwise, if we're bundling a transform update but this
|
||||
// frame isn't transformed (or doesn't exist), we need
|
||||
// to send a DeleteEntry() to remove any
|
||||
// transform that was previously cached for this frame.
|
||||
fields->SetAttribute(nsGkAtoms::transform, DeleteEntry());
|
||||
}
|
||||
}
|
||||
|
||||
if (aCacheDomain & CacheDomain::DOMNodeID && mContent) {
|
||||
nsAtom* id = mContent->GetID();
|
||||
if (id) {
|
||||
@ -3327,6 +3356,11 @@ already_AddRefed<AccAttributes> LocalAccessible::BundleFieldsForCache(
|
||||
// Note our frame's current computed style so we can track style changes
|
||||
// later on.
|
||||
mOldComputedStyle = frame->Style();
|
||||
if (frame->IsTransformed()) {
|
||||
mStateFlags |= eOldFrameHasValidTransformStyle;
|
||||
} else {
|
||||
mStateFlags &= ~eOldFrameHasValidTransformStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3352,7 +3386,39 @@ void LocalAccessible::MaybeQueueCacheUpdateForStyleChanges() {
|
||||
mDoc->QueueCacheUpdate(this, CacheDomain::Style);
|
||||
}
|
||||
|
||||
bool newHasValidTransformStyle = frame->IsTransformed();
|
||||
bool oldHasValidTransformStyle =
|
||||
(mStateFlags & eOldFrameHasValidTransformStyle) != 0;
|
||||
|
||||
// We should send a transform update if we're adding or
|
||||
// removing transform styling altogether.
|
||||
bool sendTransformUpdate =
|
||||
newHasValidTransformStyle || oldHasValidTransformStyle;
|
||||
|
||||
if (newHasValidTransformStyle && oldHasValidTransformStyle) {
|
||||
// If we continue to have transform styling, verify
|
||||
// our transform has actually changed.
|
||||
nsChangeHint transformHint =
|
||||
newStyle->StyleDisplay()->CalcTransformPropertyDifference(
|
||||
*mOldComputedStyle->StyleDisplay());
|
||||
// If this hint exists, it implies we found a property difference
|
||||
sendTransformUpdate = !!transformHint;
|
||||
}
|
||||
|
||||
if (sendTransformUpdate) {
|
||||
// Queuing a cache update for the TransformMatrix domain doesn't
|
||||
// necessarily mean we'll send the matrix itself, we may
|
||||
// send a DeleteEntry() instead. See BundleFieldsForCache for
|
||||
// more information.
|
||||
mDoc->QueueCacheUpdate(this, CacheDomain::TransformMatrix);
|
||||
}
|
||||
|
||||
mOldComputedStyle = newStyle;
|
||||
if (newHasValidTransformStyle) {
|
||||
mStateFlags |= eOldFrameHasValidTransformStyle;
|
||||
} else {
|
||||
mStateFlags &= ~eOldFrameHasValidTransformStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -861,8 +861,11 @@ class LocalAccessible : public nsISupports, public Accessible {
|
||||
eRelocated = 1 << 7, // accessible was moved in tree
|
||||
eNoKidsFromDOM = 1 << 8, // accessible doesn't allow children from DOM
|
||||
eHasTextKids = 1 << 9, // accessible have a text leaf in children
|
||||
eOldFrameHasValidTransformStyle =
|
||||
1 << 10, // frame prior to most recent style change both has transform
|
||||
// styling and supports transforms
|
||||
|
||||
eLastStateFlag = eHasTextKids
|
||||
eLastStateFlag = eOldFrameHasValidTransformStyle
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1045,6 +1048,13 @@ class LocalAccessible : public nsISupports, public Accessible {
|
||||
LocalAccessible() = delete;
|
||||
LocalAccessible(const LocalAccessible&) = delete;
|
||||
LocalAccessible& operator=(const LocalAccessible&) = delete;
|
||||
|
||||
/**
|
||||
* Traverses the accessible's parent chain in search of an accessible with
|
||||
* a frame. Returns the frame when found. Includes special handling for
|
||||
* OOP iframe docs and tab documents.
|
||||
*/
|
||||
nsIFrame* FindNearestAccessibleAncestorFrame();
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(LocalAccessible, NS_ACCESSIBLE_IMPL_IID)
|
||||
|
@ -20,6 +20,7 @@ using mozilla::a11y::AccType from "mozilla/a11y/IPCTypes.h";
|
||||
using mozilla::a11y::AccGenericType from "mozilla/a11y/IPCTypes.h";
|
||||
[RefCounted] using mozilla::a11y::AccAttributes from "mozilla/a11y/IPCTypes.h";
|
||||
using mozilla::a11y::CacheUpdateType from "mozilla/a11y/IPCTypes.h";
|
||||
using mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
@ -20,6 +20,7 @@ using mozilla::a11y::CacheUpdateType from "mozilla/a11y/IPCTypes.h";
|
||||
[RefCounted] using mozilla::a11y::AccAttributes from "mozilla/a11y/IPCTypes.h";
|
||||
using mozilla::WindowsHandle from "mozilla/ipc/IPCTypes.h";
|
||||
using mozilla::LayoutDeviceIntRect from "Units.h";
|
||||
using mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
@ -2560,28 +2560,7 @@ nsChangeHint nsStyleDisplay::CalcDifference(
|
||||
* comparisons but turn all the resulting change hints into
|
||||
* nsChangeHint_NeutralChange.
|
||||
*/
|
||||
nsChangeHint transformHint = nsChangeHint(0);
|
||||
|
||||
transformHint |= CompareTransformValues(mTransform, aNewData.mTransform);
|
||||
transformHint |= CompareTransformValues(mRotate, aNewData.mRotate);
|
||||
transformHint |= CompareTransformValues(mTranslate, aNewData.mTranslate);
|
||||
transformHint |= CompareTransformValues(mScale, aNewData.mScale);
|
||||
transformHint |= CompareMotionValues(*this, aNewData);
|
||||
|
||||
if (mTransformOrigin != aNewData.mTransformOrigin) {
|
||||
transformHint |= nsChangeHint_UpdateTransformLayer |
|
||||
nsChangeHint_UpdatePostTransformOverflow;
|
||||
}
|
||||
|
||||
if (mPerspectiveOrigin != aNewData.mPerspectiveOrigin ||
|
||||
mTransformStyle != aNewData.mTransformStyle ||
|
||||
mTransformBox != aNewData.mTransformBox) {
|
||||
transformHint |= nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
|
||||
}
|
||||
|
||||
if (mBackfaceVisibility != aNewData.mBackfaceVisibility) {
|
||||
transformHint |= nsChangeHint_RepaintFrame;
|
||||
}
|
||||
nsChangeHint transformHint = CalcTransformPropertyDifference(aNewData);
|
||||
|
||||
if (transformHint) {
|
||||
if (HasTransformStyle()) {
|
||||
@ -2692,6 +2671,34 @@ nsChangeHint nsStyleDisplay::CalcDifference(
|
||||
return hint;
|
||||
}
|
||||
|
||||
nsChangeHint nsStyleDisplay::CalcTransformPropertyDifference(
|
||||
const nsStyleDisplay& aNewData) const {
|
||||
nsChangeHint transformHint = nsChangeHint(0);
|
||||
|
||||
transformHint |= CompareTransformValues(mTransform, aNewData.mTransform);
|
||||
transformHint |= CompareTransformValues(mRotate, aNewData.mRotate);
|
||||
transformHint |= CompareTransformValues(mTranslate, aNewData.mTranslate);
|
||||
transformHint |= CompareTransformValues(mScale, aNewData.mScale);
|
||||
transformHint |= CompareMotionValues(*this, aNewData);
|
||||
|
||||
if (mTransformOrigin != aNewData.mTransformOrigin) {
|
||||
transformHint |= nsChangeHint_UpdateTransformLayer |
|
||||
nsChangeHint_UpdatePostTransformOverflow;
|
||||
}
|
||||
|
||||
if (mPerspectiveOrigin != aNewData.mPerspectiveOrigin ||
|
||||
mTransformStyle != aNewData.mTransformStyle ||
|
||||
mTransformBox != aNewData.mTransformBox) {
|
||||
transformHint |= nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
|
||||
}
|
||||
|
||||
if (mBackfaceVisibility != aNewData.mBackfaceVisibility) {
|
||||
transformHint |= nsChangeHint_RepaintFrame;
|
||||
}
|
||||
|
||||
return transformHint;
|
||||
}
|
||||
|
||||
// --------------------
|
||||
// nsStyleVisibility
|
||||
//
|
||||
|
@ -1191,6 +1191,9 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
|
||||
nsChangeHint CalcDifference(const nsStyleDisplay& aNewData,
|
||||
const nsStylePosition& aOldPosition) const;
|
||||
|
||||
nsChangeHint CalcTransformPropertyDifference(
|
||||
const nsStyleDisplay& aNewData) const;
|
||||
|
||||
nsStyleAutoArray<mozilla::StyleTransition> mTransitions;
|
||||
// The number of elements in mTransitions that are not from repeating
|
||||
// a list due to another property being longer.
|
||||
|
Loading…
Reference in New Issue
Block a user