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

This commit is contained in:
Robert O'Callahan 2011-12-28 16:24:18 +13:00
parent 667df781bd
commit 93a0a72972
8 changed files with 96 additions and 65 deletions

View File

@ -459,7 +459,8 @@ static nsRect GetDisplayPortBounds(nsDisplayListBuilder* aBuilder,
return *displayport;
}
return nsLayoutUtils::TransformRectToBoundsInAncestor(
// XXX this isn't correct, see bug 701190
return nsLayoutUtils::TransformAncestorRectToFrame(
frame,
nsRect(0, 0, displayport->width, displayport->height),
aBuilder->ReferenceFrame());

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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()

View File

@ -278,7 +278,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!");

View File

@ -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