Skip to content

Commit

Permalink
Bug 1715179 - Propagate transform matrix and relevant zoom values to …
Browse files Browse the repository at this point in the history
…convert CSSRect/CSSPoint in OOPIF to top level content document cooords. r=botond

Depends on D186324

Differential Revision: https://phabricator.services.mozilla.com/D186325
  • Loading branch information
hiikezoe committed Nov 28, 2023
1 parent 6418d35 commit b9523aa
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 41 deletions.
6 changes: 3 additions & 3 deletions gfx/ipc/GfxMessageUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ struct ParamTraits<mozilla::gfx::Matrix> {
}
};

template <>
struct ParamTraits<mozilla::gfx::Matrix4x4> {
typedef mozilla::gfx::Matrix4x4 paramType;
template <class SourceUnits, class TargetUnits, class T>
struct ParamTraits<mozilla::gfx::Matrix4x4Typed<SourceUnits, TargetUnits, T>> {
typedef mozilla::gfx::Matrix4x4Typed<SourceUnits, TargetUnits, T> paramType;

static void Write(MessageWriter* writer, const paramType& param) {
#define Wr(_f) WriteParam(writer, param._f)
Expand Down
50 changes: 29 additions & 21 deletions gfx/layers/apz/src/APZCTreeManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3047,6 +3047,14 @@ ScreenMargin APZCTreeManager::GetCompositorFixedLayerMargins() const {
return mCompositorFixedLayerMargins;
}

AsyncPanZoomController* APZCTreeManager::FindRootApzcFor(
LayersId aLayersId) const {
RecursiveMutexAutoLock lock(mTreeLock);

HitTestingTreeNode* resultNode = FindRootNodeForLayersId(aLayersId);
return resultNode ? resultNode->GetApzc() : nullptr;
}

AsyncPanZoomController* APZCTreeManager::FindRootContentApzcForLayersId(
LayersId aLayersId) const {
mTreeLock.AssertCurrentThreadIn();
Expand Down Expand Up @@ -3262,28 +3270,36 @@ ParentLayerToScreenMatrix4x4 APZCTreeManager::GetApzcToGeckoTransformForHit(
return GetApzcToGeckoTransform(aHitResult.mTargetApzc, components);
}

ParentLayerToParentLayerMatrix4x4
APZCTreeManager::GetOopifApzcToRootContentApzcTransform(
CSSToCSSMatrix4x4 APZCTreeManager::GetOopifToRootContentTransform(
AsyncPanZoomController* aApzc) const {
ParentLayerToParentLayerMatrix4x4 result;
MOZ_ASSERT(aApzc->IsRootForLayersId());

RefPtr<AsyncPanZoomController> rootContentApzc = FindZoomableApzc(aApzc);
MOZ_ASSERT(aApzc->GetLayersId() != rootContentApzc->GetLayersId(),
"aApzc must be out-of-process of the rootContentApzc");
if (!rootContentApzc || rootContentApzc == aApzc ||
rootContentApzc->GetLayersId() == aApzc->GetLayersId()) {
return result;
return CSSToCSSMatrix4x4();
}
ParentLayerToParentLayerMatrix4x4 result =
GetApzcToApzcTransform(aApzc, rootContentApzc,
AsyncTransformComponent::eLayout) *
// We need to multiply by the root content APZC's
// GetPaintedResolutionTransform() here; See
// https://phabricator.services.mozilla.com/D184440?vs=755900&id=757585#6173584
// for the details.
ViewAs<AsyncTransformComponentMatrix>(
rootContentApzc->GetPaintedResolutionTransform());

CSSToParentLayerScale thisZoom = aApzc->GetZoom();
result.PreScale(thisZoom.scale, thisZoom.scale, 1.0);
CSSToParentLayerScale rootZoom = rootContentApzc->GetZoom();
if (rootZoom != CSSToParentLayerScale(0)) {
result.PostScale(1.0 / rootZoom.scale, 1.0 / rootZoom.scale, 1.0);
}

return GetApzcToApzcTransform(aApzc, rootContentApzc,
AsyncTransformComponent::eLayout) *
// We need to multiply by the root content APZC's
// GetPaintedResolutionTransform() here; See
// https://phabricator.services.mozilla.com/D184440?vs=755900&id=757585#6173584
// for the details.
ViewAs<AsyncTransformComponentMatrix>(
rootContentApzc->GetPaintedResolutionTransform());
return ViewAs<CSSToCSSMatrix4x4>(result,
PixelCastJustification::UntypedPrePostScale);
}

CSSRect APZCTreeManager::ConvertRectInApzcToRoot(AsyncPanZoomController* aApzc,
Expand All @@ -3294,15 +3310,7 @@ CSSRect APZCTreeManager::ConvertRectInApzcToRoot(AsyncPanZoomController* aApzc,
return aRect;
}

ParentLayerRect rectInParent = aRect * aApzc->GetZoom();
ParentLayerRect rectInRoot =
GetOopifApzcToRootContentApzcTransform(aApzc).TransformBounds(
rectInParent);

if (rootContentApzc->GetZoom() != CSSToParentLayerScale(0)) {
return rectInRoot / rootContentApzc->GetZoom();
}
return rectInRoot / CSSToParentLayerScale(1);
return GetOopifToRootContentTransform(aApzc).TransformBounds(aRect);
}

ScreenPoint APZCTreeManager::GetCurrentMousePosition() const {
Expand Down
11 changes: 10 additions & 1 deletion gfx/layers/apz/src/APZCTreeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
* |aApzc|.
* |aApzc| must be the root APZC of an out-of-process iframe.
*/
ParentLayerToParentLayerMatrix4x4 GetOopifApzcToRootContentApzcTransform(
CSSToCSSMatrix4x4 GetOopifToRootContentTransform(
AsyncPanZoomController* aApzc) const;

/**
Expand Down Expand Up @@ -613,6 +613,8 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
already_AddRefed<AsyncPanZoomController> FindZoomableApzc(
AsyncPanZoomController* aStart) const;

AsyncPanZoomController* FindRootApzcFor(LayersId aLayersId) const;

ScreenMargin GetCompositorFixedLayerMargins() const;

void AdjustEventPointForDynamicToolbar(ScreenIntPoint& aEventPoint,
Expand Down Expand Up @@ -652,6 +654,13 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
TargetApzcForNodeResult GetTargetApzcForNode(const HitTestingTreeNode* aNode);
TargetApzcForNodeResult FindHandoffParent(
const AsyncPanZoomController* aApzc);
/**
* Find the root __content__ APZC for |aLayersId|.
* If |aLayersId| is NOT for the LayersId for the root content, this function
* returns nullptr.
*
* NOTE: Only the top-level content document will have a root content APZC.
*/
HitTestingTreeNode* FindRootNodeForLayersId(LayersId aLayersId) const;
AsyncPanZoomController* FindRootContentApzcForLayersId(
LayersId aLayersId) const;
Expand Down
18 changes: 17 additions & 1 deletion gfx/layers/apz/src/AsyncPanZoomController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3163,12 +3163,27 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(
APZC_LOG_DETAIL("got a double-tap in state %s\n", this,
ToString(mState).c_str());

MOZ_ASSERT(IsRootForLayersId(),
"This function should be called for the root content APZC or "
"OOPIF root APZC");

CSSToCSSMatrix4x4 transformToRootContentApzc;
RefPtr<AsyncPanZoomController> rootContentApzc;
if (IsRootContent()) {
rootContentApzc = RefPtr{this};
} else {
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
rootContentApzc = treeManagerLocal->FindZoomableApzc(this);
if (rootContentApzc) {
MOZ_ASSERT(rootContentApzc->GetLayersId() != GetLayersId());
MOZ_ASSERT(this == treeManagerLocal->FindRootApzcFor(GetLayersId()));
transformToRootContentApzc =
treeManagerLocal->GetOopifToRootContentTransform(this);

CSSPoint rootScrollPosition = rootContentApzc->GetLayoutScrollOffset();
transformToRootContentApzc.PostTranslate(rootScrollPosition.x,
rootScrollPosition.y, 0);
}
}
}

Expand All @@ -3187,7 +3202,8 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(
TapType::eDoubleTap, *geckoScreenPoint, aEvent.modifiers, GetGuid(),
GetCurrentTouchBlock() ? GetCurrentTouchBlock()->GetBlockId() : 0,
Some(DoubleTapToZoomMetrics{rootContentApzc->GetVisualViewport(),
rootContentApzc->GetScrollableRect()}));
rootContentApzc->GetScrollableRect(),
transformToRootContentApzc}));
}
}
return nsEventStatus_eConsumeNoDefault;
Expand Down
5 changes: 5 additions & 0 deletions gfx/layers/apz/src/AsyncPanZoomController.h
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,11 @@ class AsyncPanZoomController {
return Metrics().GetVisualViewport();
}

CSSPoint GetLayoutScrollOffset() const {
RecursiveMutexAutoLock lock(mRecursiveMutex);
return Metrics().GetLayoutScrollOffset();
}

// Returns the delta for the given InputData.
ParentLayerPoint GetDeltaForEvent(const InputData& aEvent) const;

Expand Down
58 changes: 45 additions & 13 deletions gfx/layers/apz/util/DoubleTapToZoom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "nsStyleConsts.h"
#include "mozilla/ViewportUtils.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/layers/APZUtils.h"

namespace mozilla {
namespace layers {
Expand Down Expand Up @@ -95,10 +96,37 @@ static dom::Element* GetNearbyTableCell(
return nullptr;
}

// A utility function returns the given |aElement| rectangle relative to the top
// level content document coordinates.
static CSSRect GetBoundingContentRect(
const dom::Element* aElement,
const RefPtr<dom::Document>& aRootContentDocument,
const nsIScrollableFrame* aRootScrollFrame,
const DoubleTapToZoomMetrics& aMetrics,
mozilla::Maybe<CSSRect>* aOutNearestScrollClip = nullptr) {
if (aRootContentDocument->IsTopLevelContentDocument()) {
return nsLayoutUtils::GetBoundingContentRect(aElement, aRootScrollFrame,
aOutNearestScrollClip);
}

nsIFrame* frame = aElement->GetPrimaryFrame();
if (!frame) {
return CSSRect();
}

// In the case of an element inside an OOP iframe, |aMetrics.mTransformMatrix|
// includes the translation information about the root layout scroll offset,
// thus we use nsIFrame::GetBoundingClientRect rather than
// nsLayoutUtils::GetBoundingContent.
return aMetrics.mTransformMatrix.TransformBounds(
CSSRect::FromAppUnits(frame->GetBoundingClientRect()));
}

static bool ShouldZoomToElement(
const nsCOMPtr<dom::Element>& aElement,
const RefPtr<dom::Document>& aRootContentDocument,
nsIScrollableFrame* aRootScrollFrame, const CSSRect& aRootScrollableRect) {
nsIScrollableFrame* aRootScrollFrame,
const DoubleTapToZoomMetrics& aMetrics) {
if (nsIFrame* frame = aElement->GetPrimaryFrame()) {
if (frame->StyleDisplay()->IsInlineFlow() &&
// Replaced elements are suitable zoom targets because they act like
Expand All @@ -125,9 +153,9 @@ static bool ShouldZoomToElement(
// don't want to zoom to them. This heuristic is quite naive and leaves a lot
// to be desired.
if (dom::Element* tableCell = GetNearbyTableCell(aElement)) {
CSSRect rect =
nsLayoutUtils::GetBoundingContentRect(tableCell, aRootScrollFrame);
if (rect.width < 0.3 * aRootScrollableRect.width) {
CSSRect rect = GetBoundingContentRect(tableCell, aRootContentDocument,
aRootScrollFrame, aMetrics);
if (rect.width < 0.3 * aMetrics.mRootScrollableRect.width) {
return false;
}
}
Expand Down Expand Up @@ -227,9 +255,11 @@ ZoomTarget CalculateRectToZoomTo(
}

CSSPoint documentRelativePoint =
CSSPoint::FromAppUnits(ViewportUtils::VisualToLayout(
CSSPoint::ToAppUnits(aPoint), presShell)) +
CSSPoint::FromAppUnits(rootScrollFrame->GetScrollPosition());
aRootContentDocument->IsTopLevelContentDocument()
? CSSPoint::FromAppUnits(ViewportUtils::VisualToLayout(
CSSPoint::ToAppUnits(aPoint), presShell)) +
CSSPoint::FromAppUnits(rootScrollFrame->GetScrollPosition())
: aMetrics.mTransformMatrix.TransformPoint(aPoint);

nsCOMPtr<dom::Element> element = ElementFromPoint(presShell, aPoint);
if (!element) {
Expand All @@ -242,9 +272,8 @@ ZoomTarget CalculateRectToZoomTo(
? CantZoomOutBehavior::Nothing
: CantZoomOutBehavior::ZoomIn;

while (element &&
!ShouldZoomToElement(element, aRootContentDocument, rootScrollFrame,
aMetrics.mRootScrollableRect)) {
while (element && !ShouldZoomToElement(element, aRootContentDocument,
rootScrollFrame, aMetrics)) {
element = element->GetFlattenedTreeParentElement();
}

Expand All @@ -254,8 +283,9 @@ ZoomTarget CalculateRectToZoomTo(
}

Maybe<CSSRect> nearestScrollClip;
CSSRect rect = nsLayoutUtils::GetBoundingContentRect(element, rootScrollFrame,
&nearestScrollClip);
CSSRect rect =
GetBoundingContentRect(element, aRootContentDocument, rootScrollFrame,
aMetrics, &nearestScrollClip);

// In some cases, like overflow: visible and overflowing content, the bounding
// client rect of the targeted element won't contain the point the user double
Expand Down Expand Up @@ -364,14 +394,16 @@ ZoomTarget CalculateRectToZoomTo(

rect.Round();
elementBoundingRect.Round();

return ZoomTarget{rect, cantZoomOutBehavior, Some(elementBoundingRect),
Some(documentRelativePoint)};
}

std::ostream& operator<<(std::ostream& aStream,
const DoubleTapToZoomMetrics& aMetrics) {
aStream << "{ vv=" << aMetrics.mVisualViewport
<< ", rscr=" << aMetrics.mRootScrollableRect << " }";
<< ", rscr=" << aMetrics.mRootScrollableRect
<< ", transform=" << aMetrics.mTransformMatrix << " }";
return aStream;
}

Expand Down
9 changes: 8 additions & 1 deletion gfx/layers/apz/util/DoubleTapToZoom.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define mozilla_layers_DoubleTapToZoom_h

#include "Units.h"
#include "mozilla/gfx/Matrix.h"

template <class T>
class RefPtr;
Expand Down Expand Up @@ -52,10 +53,16 @@ struct DoubleTapToZoomMetrics {
// The scrollable rect of the root scroll container of the top-level content
// document.
CSSRect mRootScrollableRect;
// If double-tap-to-zoom happens inside an OOP iframe, this transform matrix
// is the matrix converting the coordinates relative to layout viewport origin
// of the OOP iframe to the document origin of the top level content document.
// If not, this is the identity matrix.
CSSToCSSMatrix4x4 mTransformMatrix;

bool operator==(const DoubleTapToZoomMetrics& aOther) const {
return mVisualViewport == aOther.mVisualViewport &&
mRootScrollableRect == aOther.mRootScrollableRect;
mRootScrollableRect == aOther.mRootScrollableRect &&
mTransformMatrix == aOther.mTransformMatrix;
}
friend std::ostream& operator<<(std::ostream& aStream,
const DoubleTapToZoomMetrics& aUpdate);
Expand Down
4 changes: 3 additions & 1 deletion gfx/layers/ipc/LayersMessageUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -1114,11 +1114,13 @@ struct ParamTraits<mozilla::layers::DoubleTapToZoomMetrics> {
static void Write(MessageWriter* aWriter, const paramType& aParam) {
WriteParam(aWriter, aParam.mVisualViewport);
WriteParam(aWriter, aParam.mRootScrollableRect);
WriteParam(aWriter, aParam.mTransformMatrix);
}

static bool Read(MessageReader* aReader, paramType* aResult) {
return (ReadParam(aReader, &aResult->mVisualViewport) &&
ReadParam(aReader, &aResult->mRootScrollableRect));
ReadParam(aReader, &aResult->mRootScrollableRect) &&
ReadParam(aReader, &aResult->mTransformMatrix));
}
};

Expand Down
3 changes: 3 additions & 0 deletions layout/base/UnitTransforms.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ enum class PixelCastJustification : uint8_t {
// use CSS pixels) and code related to the scroll frame in APZ (which wants
// such quantities in OuterCSS pixels).
CSSPixelsOfSurroundingContent,
// The matrix has been converted to a conceptually different type by calling
// PreScale() and/or PostScale()
UntypedPrePostScale,
};

template <class TargetUnits, class SourceUnits>
Expand Down

0 comments on commit b9523aa

Please sign in to comment.