Commit 967bb355 authored by Botond Ballo's avatar Botond Ballo
Browse files

Bug 1556556 - Include the layout-to-visual transform for a zoomed content root...

Bug 1556556 - Include the layout-to-visual transform for a zoomed content root in GetTransformMatrix(). r=kats,mattwoodrow

This is the "core" change of the patch series, which causes most
existing layout codepaths to correctly factor in the visual to
layout transform (or its inverse), as long as the callers correctly
propagate it in the correct ViewportType.

Differential Revision: https://phabricator.services.mozilla.com/D68920
parent 380598f9
......@@ -3634,7 +3634,8 @@ bool PresShell::ScrollFrameRectIntoView(nsIFrame* aFrame, const nsRect& aRect,
}
nsIFrame* parent;
if (container->IsTransformed()) {
container->GetTransformMatrix(nullptr, &parent);
container->GetTransformMatrix(ViewportType::Layout, RelativeTo{nullptr},
&parent);
rect =
nsLayoutUtils::TransformFrameRectToAncestor(container, rect, parent);
} else {
......
......@@ -2619,11 +2619,15 @@ Matrix4x4Flagged nsLayoutUtils::GetTransformToAncestor(
nsIFrame** aOutAncestor) {
nsIFrame* parent;
Matrix4x4Flagged ctm;
// Make sure we don't get an invalid combination of source and destination
// RelativeTo values.
MOZ_ASSERT(!(aFrame.mViewportType == ViewportType::Visual &&
aAncestor.mViewportType == ViewportType::Layout));
if (aFrame == aAncestor) {
return ctm;
}
ctm = ctm *
aFrame.mFrame->GetTransformMatrix(aAncestor.mFrame, &parent, aFlags);
ctm = aFrame.mFrame->GetTransformMatrix(aFrame.mViewportType, aAncestor,
&parent, aFlags);
while (parent && parent != aAncestor.mFrame &&
(!(aFlags & nsIFrame::STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT) ||
(!parent->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) &&
......@@ -2631,7 +2635,8 @@ Matrix4x4Flagged nsLayoutUtils::GetTransformToAncestor(
if (!parent->Extend3DContext()) {
ctm.ProjectTo2D();
}
ctm = ctm * parent->GetTransformMatrix(aAncestor.mFrame, &parent, aFlags);
ctm = ctm * parent->GetTransformMatrix(aFrame.mViewportType, aAncestor,
&parent, aFlags);
}
if (aOutAncestor) {
*aOutAncestor = parent;
......@@ -2660,7 +2665,8 @@ static Matrix4x4Flagged GetTransformToAncestorExcludingAnimated(
if (ActiveLayerTracker::IsScaleSubjectToAnimation(aFrame)) {
return ctm;
}
ctm = aFrame->GetTransformMatrix(aAncestor, &parent);
ctm = aFrame->GetTransformMatrix(ViewportType::Layout, RelativeTo{aAncestor},
&parent);
while (parent && parent != aAncestor) {
if (ActiveLayerTracker::IsScaleSubjectToAnimation(parent)) {
return Matrix4x4Flagged();
......@@ -2668,7 +2674,8 @@ static Matrix4x4Flagged GetTransformToAncestorExcludingAnimated(
if (!parent->Extend3DContext()) {
ctm.ProjectTo2D();
}
ctm = ctm * parent->GetTransformMatrix(aAncestor, &parent);
ctm = ctm * parent->GetTransformMatrix(ViewportType::Layout,
RelativeTo{aAncestor}, &parent);
}
return ctm;
}
......
......@@ -985,6 +985,38 @@ class nsLayoutUtils {
* flag in aFlags will return CSS pixels, by default it returns device
* pixels.
* More info can be found in nsIFrame::GetTransformMatrix.
*
* Some notes on the possible combinations of |aFrame.mViewportType| and
* |aAncestor.mViewportType|:
*
* | aFrame. | aAncestor. | Notes
* | mViewportType | mViewportType |
* ==========================================================================
* | Layout | Layout | Commonplace, when both source and target
* | | | are inside zoom boundary.
* | | |
* | | | Could also happen in non-e10s setups
* | | | when both source and target are outside
* | | | the zoom boundary and the code is
* | | | oblivious to the existence of a zoom
* | | | boundary.
* ==========================================================================
* | Layout | Visual | Commonplace, used when hit testing visual
* | | | coordinates (e.g. coming from user input
* | | | events). We expected to encounter a
* | | | zoomed content root during traversal and
* | | | apply a layout-to-visual transform.
* ==========================================================================
* | Visual | Layout | Should never happen, will assert.
* ==========================================================================
* | Visual | Visual | In e10s setups, should only happen if
* | | | aFrame and aAncestor are both the
* | | | RCD viewport frame.
* | | |
* | | | In non-e10s setups, could happen with
* | | | different frames if they are both
* | | | outside the zoom boundary.
* ==========================================================================
*/
static Matrix4x4Flagged GetTransformToAncestor(
RelativeTo aFrame, RelativeTo aAncestor, uint32_t aFlags = 0,
......
......@@ -466,7 +466,8 @@ nsPoint nsComboboxControlFrame::GetCSSTransformTranslation() {
Matrix transform;
while (frame) {
nsIFrame* parent;
Matrix4x4Flagged ctm = frame->GetTransformMatrix(nullptr, &parent);
Matrix4x4Flagged ctm = frame->GetTransformMatrix(
ViewportType::Layout, RelativeTo{nullptr}, &parent);
Matrix matrix;
if (ctm.Is2D(&matrix)) {
transform = transform * matrix;
......
......@@ -7248,7 +7248,8 @@ nsIWidget* nsIFrame::GetNearestWidget(nsPoint& aOffset) const {
return widget;
}
Matrix4x4Flagged nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
Matrix4x4Flagged nsIFrame::GetTransformMatrix(ViewportType aViewportType,
RelativeTo aStopAtAncestor,
nsIFrame** aOutAncestor,
uint32_t aFlags) const {
MOZ_ASSERT(aOutAncestor, "Need a place to put the ancestor!");
......@@ -7257,20 +7258,53 @@ Matrix4x4Flagged nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
* transform/translate matrix that will apply our current transform, then
* shift us to our parent.
*/
if (IsTransformed()) {
/* Compute the delta to the parent, which we need because we are converting
* coordinates to our parent.
*/
NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
"Cannot transform the viewport frame!");
bool isTransformed = IsTransformed();
const nsIFrame* zoomedContentRoot = nullptr;
if (aStopAtAncestor.mViewportType == ViewportType::Visual) {
zoomedContentRoot = ViewportUtils::IsZoomedContentRoot(this);
if (zoomedContentRoot) {
MOZ_ASSERT(aViewportType != ViewportType::Visual);
}
}
if (isTransformed || zoomedContentRoot) {
Matrix4x4 result;
int32_t scaleFactor =
((aFlags & IN_CSS_UNITS) ? AppUnitsPerCSSPixel()
: PresContext()->AppUnitsPerDevPixel());
Matrix4x4 result = nsDisplayTransform::GetResultingTransformMatrix(
this, nsPoint(0, 0), scaleFactor,
nsDisplayTransform::INCLUDE_PERSPECTIVE |
nsDisplayTransform::OFFSET_BY_ORIGIN);
/* Compute the delta to the parent, which we need because we are converting
* coordinates to our parent.
*/
if (isTransformed) {
NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
"Cannot transform the viewport frame!");
result = result * nsDisplayTransform::GetResultingTransformMatrix(
this, nsPoint(0, 0), scaleFactor,
nsDisplayTransform::INCLUDE_PERSPECTIVE |
nsDisplayTransform::OFFSET_BY_ORIGIN);
}
if (zoomedContentRoot) {
Matrix4x4 layoutToVisual;
ScrollableLayerGuid::ViewID targetScrollId =
nsLayoutUtils::FindOrCreateIDFor(zoomedContentRoot->GetContent());
if (aFlags & nsIFrame::IN_CSS_UNITS) {
layoutToVisual =
ViewportUtils::GetVisualToLayoutTransform(targetScrollId)
.Inverse()
.ToUnknownMatrix();
} else {
layoutToVisual =
ViewportUtils::GetVisualToLayoutTransform<LayoutDevicePixel>(
targetScrollId)
.Inverse()
.ToUnknownMatrix();
}
result = result * layoutToVisual;
}
*aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
/* Combine the raw transform with a translation to our parent. */
......@@ -7336,12 +7370,16 @@ Matrix4x4Flagged nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
/* Keep iterating while the frame can't possibly be transformed. */
const nsIFrame* current = this;
while (!(*aOutAncestor)->IsTransformed() &&
!nsLayoutUtils::IsPopup(*aOutAncestor) &&
*aOutAncestor != aStopAtAncestor &&
(!(aFlags & STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT) ||
(!(*aOutAncestor)->IsStackingContext() &&
!nsLayoutUtils::FrameHasDisplayPort(*aOutAncestor, current)))) {
auto shouldStopAt = [](const nsIFrame* aCurrent, nsIFrame* aAncestor,
uint32_t aFlags) {
return aAncestor->IsTransformed() || nsLayoutUtils::IsPopup(aAncestor) ||
ViewportUtils::IsZoomedContentRoot(aAncestor) ||
((aFlags & STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT) &&
(aAncestor->IsStackingContext() ||
nsLayoutUtils::FrameHasDisplayPort(aAncestor, aCurrent)));
};
while (*aOutAncestor != aStopAtAncestor.mFrame &&
!shouldStopAt(current, *aOutAncestor, aFlags)) {
/* If no parent, stop iterating. Otherwise, update the ancestor. */
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
if (!parent) break;
......
......@@ -2936,6 +2936,8 @@ class nsIFrame : public nsQueryFrame {
* The frame decides which ancestor it will use as a reference point.
* If this frame has no ancestor, aOutAncestor will be set to null.
*
* @param aViewportType specifies whether the starting point is layout
* or visual coordinates
* @param aStopAtAncestor don't look further than aStopAtAncestor. If null,
* all ancestors (including across documents) will be traversed.
* @param aOutAncestor [out] The ancestor frame the frame has chosen. If
......@@ -2944,14 +2946,16 @@ class nsIFrame : public nsQueryFrame {
* document as this frame. If this frame IsTransformed(), then *aOutAncestor
* will be the parent frame (if not preserve-3d) or the nearest
* non-transformed ancestor (if preserve-3d).
* @return A Matrix4x4 that converts points in this frame's coordinate space
* into points in aOutAncestor's coordinate space.
* @return A Matrix4x4 that converts points in the coordinate space
* RelativeTo{this, aViewportType} into points in aOutAncestor's
* coordinate space.
*/
enum {
IN_CSS_UNITS = 1 << 0,
STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT = 1 << 1
};
Matrix4x4Flagged GetTransformMatrix(const nsIFrame* aStopAtAncestor,
Matrix4x4Flagged GetTransformMatrix(ViewportType aViewportType,
RelativeTo aStopAtAncestor,
nsIFrame** aOutAncestor,
uint32_t aFlags = 0) const;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment