From fda2a403ee086902a652d7436ed7a27913a8dc8e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Wed, 28 Dec 2011 16:24:18 +1300 Subject: [PATCH] Bug 591718. Part 1: rename some poorly-named methods, rework global-transform methods to avoid computing bounding-boxes more than once when there are are multiple transformed ancestors, make sure nsIFrame::GetTransformMatrix can stop at any desired ancestor. r=mats --- layout/base/nsDisplayList.cpp | 2 +- layout/base/nsLayoutUtils.cpp | 97 +++++++++++-------- layout/base/nsLayoutUtils.h | 22 +++-- layout/forms/nsComboboxControlFrame.cpp | 4 +- layout/generic/nsFrame.cpp | 8 +- layout/generic/nsIFrame.h | 21 ++-- .../svg/base/src/nsSVGForeignObjectFrame.cpp | 3 +- layout/svg/base/src/nsSVGForeignObjectFrame.h | 3 +- 8 files changed, 95 insertions(+), 65 deletions(-) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 50d8f6afa1b..a3eadf257b2 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -460,7 +460,7 @@ GetDisplayPortBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) } const nsRect* displayport = aBuilder->GetDisplayPort(); - nsRect result = nsLayoutUtils::TransformRectToBoundsInAncestor( + nsRect result = nsLayoutUtils::TransformAncestorRectToFrame( frame, nsRect(0, 0, displayport->width, displayport->height), aBuilder->ReferenceFrame()); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 2ac11bea1d7..753384b96c8 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -975,7 +975,7 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aF * out how to convert back to aFrame's coordinates and must use the CTM. */ if (transformFound) - return InvertTransformsToRoot(aFrame, widgetToView); + return TransformRootPointToFrame(aFrame, widgetToView); /* Otherwise, all coordinate systems are translations of one another, * so we can just subtract out the different. @@ -1117,68 +1117,62 @@ nsLayoutUtils::MatrixTransformPoint(const nsPoint &aPoint, NSFloatPixelsToAppUnits(float(image.y), aFactor)); } -static gfxPoint -InvertTransformsToAncestor(nsIFrame *aFrame, - const gfxPoint &aPoint, - nsIFrame *aStopAtAncestor = nsnull) +static gfx3DMatrix +GetTransformToAncestor(nsIFrame *aFrame, nsIFrame *aAncestor) { - NS_PRECONDITION(aFrame, "Why are you inverting transforms when there is no frame?"); - - /* To invert everything to the root, we'll get the CTM, invert it, and use it to transform - * the point. - */ - nsIFrame *parent = nsnull; - gfx3DMatrix ctm = aFrame->GetTransformMatrix(&parent); - gfxPoint result = aPoint; - - if (parent && parent != aStopAtAncestor) { - result = InvertTransformsToAncestor(parent, aPoint, aStopAtAncestor); + nsIFrame* parent; + gfx3DMatrix ctm = aFrame->GetTransformMatrix(aAncestor, &parent); + while (parent && parent != aAncestor) { + ctm = ctm * parent->GetTransformMatrix(aAncestor, &parent); } + return ctm; +} - result = ctm.Inverse().ProjectPoint(result); - return result; +static gfxPoint +TransformGfxPointFromAncestor(nsIFrame *aFrame, + const gfxPoint &aPoint, + nsIFrame *aAncestor) +{ + gfx3DMatrix ctm = GetTransformToAncestor(aFrame, aAncestor); + return ctm.Inverse().ProjectPoint(aPoint); } static gfxRect -InvertGfxRectToAncestor(nsIFrame *aFrame, - const gfxRect &aRect, - nsIFrame *aStopAtAncestor = nsnull) +TransformGfxRectFromAncestor(nsIFrame *aFrame, + const gfxRect &aRect, + nsIFrame *aAncestor) { - NS_PRECONDITION(aFrame, "Why are you inverting transforms when there is no frame?"); + gfx3DMatrix ctm = GetTransformToAncestor(aFrame, aAncestor); + return ctm.Inverse().ProjectRectBounds(aRect); +} - /* To invert everything to the root, we'll get the CTM, invert it, and use it to transform - * the point. - */ - nsIFrame *parent = nsnull; - gfx3DMatrix ctm = aFrame->GetTransformMatrix(&parent); - gfxRect result = aRect; - - if (parent && parent != aStopAtAncestor) { - result = InvertGfxRectToAncestor(parent, aRect, aStopAtAncestor); - } - - result = ctm.Inverse().ProjectRectBounds(result); - return result; +static gfxRect +TransformGfxRectToAncestor(nsIFrame *aFrame, + const gfxRect &aRect, + nsIFrame *aAncestor) +{ + gfx3DMatrix ctm = GetTransformToAncestor(aFrame, aAncestor); + return ctm.ProjectRectBounds(aRect); } nsPoint -nsLayoutUtils::InvertTransformsToRoot(nsIFrame *aFrame, - const nsPoint &aPoint) +nsLayoutUtils::TransformRootPointToFrame(nsIFrame *aFrame, + const nsPoint &aPoint) { float factor = aFrame->PresContext()->AppUnitsPerDevPixel(); gfxPoint result(NSAppUnitsToFloatPixels(aPoint.x, factor), NSAppUnitsToFloatPixels(aPoint.y, factor)); - result = InvertTransformsToAncestor(aFrame, result); + result = TransformGfxPointFromAncestor(aFrame, result, nsnull); return nsPoint(NSFloatPixelsToAppUnits(float(result.x), factor), NSFloatPixelsToAppUnits(float(result.y), factor)); } nsRect -nsLayoutUtils::TransformRectToBoundsInAncestor(nsIFrame* aFrame, - const nsRect &aRect, - nsIFrame* aStopAtAncestor) +nsLayoutUtils::TransformAncestorRectToFrame(nsIFrame* aFrame, + const nsRect &aRect, + nsIFrame* aAncestor) { float factor = aFrame->PresContext()->AppUnitsPerDevPixel(); gfxRect result(NSAppUnitsToFloatPixels(aRect.x, factor), @@ -1186,7 +1180,7 @@ nsLayoutUtils::TransformRectToBoundsInAncestor(nsIFrame* aFrame, NSAppUnitsToFloatPixels(aRect.width, factor), NSAppUnitsToFloatPixels(aRect.height, factor)); - result = InvertGfxRectToAncestor(aFrame, result, aStopAtAncestor); + result = TransformGfxRectFromAncestor(aFrame, result, aAncestor); return nsRect(NSFloatPixelsToAppUnits(float(result.x), factor), NSFloatPixelsToAppUnits(float(result.y), factor), @@ -1194,6 +1188,25 @@ nsLayoutUtils::TransformRectToBoundsInAncestor(nsIFrame* aFrame, NSFloatPixelsToAppUnits(float(result.height), factor)); } +nsRect +nsLayoutUtils::TransformFrameRectToAncestor(nsIFrame* aFrame, + const nsRect& aRect, + nsIFrame* aAncestor) +{ + float factor = aFrame->PresContext()->AppUnitsPerDevPixel(); + gfxRect result(NSAppUnitsToFloatPixels(aRect.x, factor), + NSAppUnitsToFloatPixels(aRect.y, factor), + NSAppUnitsToFloatPixels(aRect.width, factor), + NSAppUnitsToFloatPixels(aRect.height, factor)); + + result = TransformGfxRectToAncestor(aFrame, result, aAncestor); + + return nsRect(NSFloatPixelsToAppUnits(float(result.x), factor), + NSFloatPixelsToAppUnits(float(result.y), factor), + NSFloatPixelsToAppUnits(float(result.width), factor), + NSFloatPixelsToAppUnits(float(result.height), factor)); +} + static nsIntPoint GetWidgetOffset(nsIWidget* aWidget, nsIWidget*& aRootWidget) { nsIntPoint offset(0, 0); nsIWidget* parent = aWidget->GetParent(); diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index fc53096a714..1396a99f49c 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -515,11 +515,21 @@ public: bool aShouldIgnoreSuppression = false, bool aIgnoreRootScrollFrame = false); - + /** + * Transform aRect relative to aAncestor down to the coordinate system of + * aFrame. Computes the bounding-box of the true quadrilateral. + */ + static nsRect TransformAncestorRectToFrame(nsIFrame* aFrame, + const nsRect& aRect, + nsIFrame* aAncestor); - static nsRect TransformRectToBoundsInAncestor(nsIFrame* aFrame, - const nsRect& aRect, - nsIFrame* aStopAtAncestor); + /** + * Transform aRect relative to aFrame up to the coordinate system of + * aAncestor. Computes the bounding-box of the true quadrilateral. + */ + static nsRect TransformFrameRectToAncestor(nsIFrame* aFrame, + const nsRect& aRect, + nsIFrame* aAncestor); /** * Given a point in the global coordinate space, returns that point expressed @@ -530,8 +540,8 @@ public: * @param aPoint The point, in the global space, to get in the frame-local space. * @return aPoint, expressed in aFrame's canonical coordinate space. */ - static nsPoint InvertTransformsToRoot(nsIFrame* aFrame, - const nsPoint &aPt); + static nsPoint TransformRootPointToFrame(nsIFrame* aFrame, + const nsPoint &aPt); /** * Helper function that, given a rectangle and a matrix, returns the smallest diff --git a/layout/forms/nsComboboxControlFrame.cpp b/layout/forms/nsComboboxControlFrame.cpp index f74f1e789fc..b232bab9366 100644 --- a/layout/forms/nsComboboxControlFrame.cpp +++ b/layout/forms/nsComboboxControlFrame.cpp @@ -550,8 +550,8 @@ nsComboboxControlFrame::GetCSSTransformTranslation() bool is3DTransform = false; gfxMatrix transform; while (frame) { - nsIFrame* parent = nsnull; - gfx3DMatrix ctm = frame->GetTransformMatrix(&parent); + nsIFrame* parent; + gfx3DMatrix ctm = frame->GetTransformMatrix(nsnull, &parent); gfxMatrix matrix; if (ctm.Is2D(&matrix)) { transform = transform * matrix; diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index b5f78934dd3..ae69c9064ba 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4541,7 +4541,8 @@ nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY, } gfx3DMatrix -nsIFrame::GetTransformMatrix(nsIFrame **aOutAncestor) +nsIFrame::GetTransformMatrix(nsIFrame* aStopAtAncestor, + nsIFrame** aOutAncestor) { NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!"); @@ -4553,7 +4554,8 @@ nsIFrame::GetTransformMatrix(nsIFrame **aOutAncestor) /* 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!"); + NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this), + "Cannot transform the viewport frame!"); PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel(); gfx3DMatrix result = @@ -4582,7 +4584,7 @@ nsIFrame::GetTransformMatrix(nsIFrame **aOutAncestor) return gfx3DMatrix(); /* Keep iterating while the frame can't possibly be transformed. */ - while (!(*aOutAncestor)->IsTransformed()) { + while (!(*aOutAncestor)->IsTransformed() && *aOutAncestor != aStopAtAncestor) { /* If no parent, stop iterating. Otherwise, update the ancestor. */ nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor); if (!parent) diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 3dfeecc8710..f44a90f795d 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -1932,17 +1932,20 @@ public: virtual nsIAtom* GetType() const = 0; /** - * Returns a transformation matrix that converts points in this frame's coordinate space - * to points in some ancestor frame's coordinate space. The frame decides which ancestor - * it will use as a reference point. If this frame has no ancestor, aOutAncestor will be - * set to null. + * Returns a transformation matrix that converts points in this frame's + * coordinate space to points in some ancestor frame's coordinate space. + * 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 aOutAncestor [out] The ancestor frame the frame has chosen. If this frame has no - * ancestor, aOutAncestor will be nsnull. - * @return A gfxMatrix that converts points in this frame's coordinate space into - * points in aOutAncestor's coordinate space. + * @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 + * this frame has no ancestor, *aOutAncestor will be set to null. + * @return A gfxMatrix that converts points in this frame's coordinate space + * into points in aOutAncestor's coordinate space. */ - virtual gfx3DMatrix GetTransformMatrix(nsIFrame **aOutAncestor); + virtual gfx3DMatrix GetTransformMatrix(nsIFrame* aStopAtAncestor, + nsIFrame **aOutAncestor); /** * Bit-flags to pass to IsFrameOfType() diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp index ab488d4d090..d6c1045205b 100644 --- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp @@ -283,7 +283,8 @@ nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext, } gfx3DMatrix -nsSVGForeignObjectFrame::GetTransformMatrix(nsIFrame **aOutAncestor) +nsSVGForeignObjectFrame::GetTransformMatrix(nsIFrame* aAncestor, + nsIFrame **aOutAncestor) { NS_PRECONDITION(aOutAncestor, "We need an ancestor to write to!"); diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.h b/layout/svg/base/src/nsSVGForeignObjectFrame.h index c73f062ce7f..6f5914f71ce 100644 --- a/layout/svg/base/src/nsSVGForeignObjectFrame.h +++ b/layout/svg/base/src/nsSVGForeignObjectFrame.h @@ -93,7 +93,8 @@ public: /** * Foreign objects can return a transform matrix. */ - virtual gfx3DMatrix GetTransformMatrix(nsIFrame **aOutAncestor); + virtual gfx3DMatrix GetTransformMatrix(nsIFrame* aAncestor, + nsIFrame **aOutAncestor); /** * Get the "type" of the frame