Bug 505115 - Part 8c - Use ray tracing to untransform 2d points on a 3d plane. r=roc

This commit is contained in:
Matt Woodrow 2011-08-03 15:04:21 +12:00
Родитель a1dcca3e9c
Коммит 85e14ced8b
5 изменённых файлов: 97 добавлений и 65 удалений

Просмотреть файл

@ -921,16 +921,12 @@ AppUnitsPerDevPixel(nsDisplayItem* aItem)
static void
RestrictVisibleRegionForLayer(Layer* aLayer, const nsIntRect& aItemVisible)
{
gfxMatrix transform;
if (!aLayer->GetTransform().Is2D(&transform))
return;
gfx3DMatrix transform = aLayer->GetTransform();
// if 'transform' is not invertible, then nothing will be displayed
// for the layer, so it doesn't really matter what we do here
gfxMatrix inverse = transform;
inverse.Invert();
gfxRect itemVisible(aItemVisible.x, aItemVisible.y, aItemVisible.width, aItemVisible.height);
gfxRect layerVisible = inverse.TransformBounds(itemVisible);
gfxRect layerVisible = transform.Inverse().ProjectRectBounds(itemVisible);
layerVisible.RoundOut();
nsIntRect visibleRect;

Просмотреть файл

@ -451,19 +451,16 @@ static nsRect GetDisplayPortBounds(nsDisplayListBuilder* aBuilder,
PRBool aIgnoreTransform)
{
nsIFrame* frame = aItem->GetUnderlyingFrame();
nscoord auPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
gfx3DMatrix transform;
const nsRect* displayport = aBuilder->GetDisplayPort();
if (!aIgnoreTransform) {
transform = nsLayoutUtils::GetTransformToAncestor(frame,
aBuilder->ReferenceFrame());
transform.Invert();
if (aIgnoreTransform) {
return *displayport;
}
const nsRect* displayport = aBuilder->GetDisplayPort();
return nsLayoutUtils::MatrixTransformRect(
return nsLayoutUtils::TransformRectToBoundsInAncestor(
frame,
nsRect(0, 0, displayport->width, displayport->height),
transform, auPerDevPixel);
aBuilder->ReferenceFrame());
}
PRBool
@ -2482,13 +2479,13 @@ void nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder,
* Thus we have to invert the matrix, which normally does
* the reverse operation (e.g. regular->transformed)
*/
matrix.Invert();
/* Now, apply the transform and pass it down the channel. */
nsRect resultingRect;
if (aRect.width == 1 && aRect.height == 1) {
gfxPoint point = matrix.Transform(gfxPoint(NSAppUnitsToFloatPixels(aRect.x, factor),
NSAppUnitsToFloatPixels(aRect.y, factor)));
gfxPoint point = matrix.Inverse().ProjectPoint(
gfxPoint(NSAppUnitsToFloatPixels(aRect.x, factor),
NSAppUnitsToFloatPixels(aRect.y, factor)));
resultingRect = nsRect(NSFloatPixelsToAppUnits(float(point.x), factor),
NSFloatPixelsToAppUnits(float(point.y), factor),
@ -2500,7 +2497,7 @@ void nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder,
NSAppUnitsToFloatPixels(aRect.width, factor),
NSAppUnitsToFloatPixels(aRect.height, factor));
gfxRect rect = matrix.TransformBounds(originalRect);
gfxRect rect = matrix.Inverse().ProjectRectBounds(originalRect);;
resultingRect = nsRect(NSFloatPixelsToAppUnits(float(rect.X()), factor),
NSFloatPixelsToAppUnits(float(rect.Y()), factor),
@ -2693,14 +2690,21 @@ PRBool nsDisplayTransform::UntransformRect(const nsRect &aUntransformedBounds,
*/
float factor = nsPresContext::AppUnitsPerCSSPixel();
gfx3DMatrix matrix = GetResultingTransformMatrix(aFrame, aOrigin, factor, nsnull);
if (matrix.IsSingular() || !matrix.Is2D())
if (matrix.IsSingular())
return PR_FALSE;
/* We want to untransform the matrix, so invert the transformation first! */
matrix.Invert();
gfxRect result(NSAppUnitsToFloatPixels(aUntransformedBounds.x, factor),
NSAppUnitsToFloatPixels(aUntransformedBounds.y, factor),
NSAppUnitsToFloatPixels(aUntransformedBounds.width, factor),
NSAppUnitsToFloatPixels(aUntransformedBounds.height, factor));
*aOutRect = nsLayoutUtils::MatrixTransformRect(aUntransformedBounds, matrix,
factor);
/* We want to untransform the matrix, so invert the transformation first! */
result = matrix.Inverse().ProjectRectBounds(result);
*aOutRect = nsRect(NSFloatPixelsToAppUnits(float(result.x), factor),
NSFloatPixelsToAppUnits(float(result.y), factor),
NSFloatPixelsToAppUnits(float(result.width), factor),
NSFloatPixelsToAppUnits(float(result.height), factor));
return PR_TRUE;
}

Просмотреть файл

@ -77,6 +77,7 @@
#include "nsIDocShellTreeItem.h"
#include "nsIWidget.h"
#include "gfxMatrix.h"
#include "gfxPoint3D.h"
#include "gfxTypes.h"
#include "gfxUserFontSet.h"
#include "nsTArray.h"
@ -1111,43 +1112,81 @@ nsLayoutUtils::MatrixTransformPoint(const nsPoint &aPoint,
NSFloatPixelsToAppUnits(float(image.y), aFactor));
}
gfx3DMatrix nsLayoutUtils::GetTransformToAncestor(nsIFrame *aFrame,
nsIFrame* aStopAtAncestor)
{
gfx3DMatrix ctm;
/* Starting at the specified frame, we'll use the GetTransformMatrix
* function of the frame, which gives us a matrix from this frame up
* to some other ancestor frame. If aStopAtAncestor frame is not reached,
* we stop at root. We get the CTM by simply accumulating all of these
* matrices together.
*/
while (aFrame && aFrame != aStopAtAncestor) {
ctm *= aFrame->GetTransformMatrix(&aFrame);
}
NS_ASSERTION(aFrame == aStopAtAncestor, "How did we manage to miss the ancestor?");
return ctm;
}
nsPoint
nsLayoutUtils::InvertTransformsToRoot(nsIFrame *aFrame,
const nsPoint &aPoint)
static gfxPoint
InvertTransformsToAncestor(nsIFrame *aFrame,
const gfxPoint &aPoint,
nsIFrame *aStopAtAncestor = nsnull)
{
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.
*/
gfx3DMatrix ctm = GetTransformToAncestor(aFrame);
nsIFrame *parent = nsnull;
gfx3DMatrix ctm = aFrame->GetTransformMatrix(&parent);
gfxPoint result = aPoint;
/* If the ctm is singular, hand back (0, 0) as a sentinel. */
if (ctm.IsSingular())
return nsPoint(0, 0);
if (parent && parent != aStopAtAncestor) {
result = InvertTransformsToAncestor(parent, aPoint, aStopAtAncestor);
}
/* TODO: Correctly handle 3d transforms when they start being used */
result = ctm.Inverse().ProjectPoint(result);
return result;
}
/* Otherwise, invert the CTM and use it to transform the point. */
return MatrixTransformPoint(aPoint, ctm.Invert(), aFrame->PresContext()->AppUnitsPerDevPixel());
static gfxRect
InvertGfxRectToAncestor(nsIFrame *aFrame,
const gfxRect &aRect,
nsIFrame *aStopAtAncestor = nsnull)
{
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);
gfxRect result = aRect;
if (parent && parent != aStopAtAncestor) {
result = InvertGfxRectToAncestor(parent, aRect, aStopAtAncestor);
}
result = ctm.Inverse().ProjectRectBounds(result);
return result;
}
nsPoint
nsLayoutUtils::InvertTransformsToRoot(nsIFrame *aFrame,
const nsPoint &aPoint)
{
float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
gfxPoint result(NSAppUnitsToFloatPixels(aPoint.x, factor),
NSAppUnitsToFloatPixels(aPoint.y, factor));
result = InvertTransformsToAncestor(aFrame, result);
return nsPoint(NSFloatPixelsToAppUnits(float(result.x), factor),
NSFloatPixelsToAppUnits(float(result.y), factor));
}
nsRect
nsLayoutUtils::TransformRectToBoundsInAncestor(nsIFrame* aFrame,
const nsRect &aRect,
nsIFrame* aStopAtAncestor)
{
float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
gfxRect result(NSAppUnitsToFloatPixels(aRect.x, factor),
NSAppUnitsToFloatPixels(aRect.y, factor),
NSAppUnitsToFloatPixels(aRect.width, factor),
NSAppUnitsToFloatPixels(aRect.height, factor));
result = InvertGfxRectToAncestor(aFrame, result, aStopAtAncestor);
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) {

Просмотреть файл

@ -510,17 +510,11 @@ public:
PRBool aShouldIgnoreSuppression = PR_FALSE,
PRBool aIgnoreRootScrollFrame = PR_FALSE);
/**
* Returns the CTM at the specified frame. This matrix can be used to map
* coordinates from aFrame's to aStopAtAncestor's coordinate system.
*
* @param aFrame The frame at which we should calculate the CTM.
* @param aStopAtAncestor is an ancestor frame to stop at. If it's nsnull,
* matrix accumulating stops at root.
* @return The CTM at the specified frame.
*/
static gfx3DMatrix GetTransformToAncestor(nsIFrame *aFrame,
nsIFrame* aStopAtAncestor = nsnull);
static nsRect TransformRectToBoundsInAncestor(nsIFrame* aFrame,
const nsRect& aRect,
nsIFrame* aStopAtAncestor);
/**
* Given a point in the global coordinate space, returns that point expressed
@ -534,7 +528,6 @@ public:
static nsPoint InvertTransformsToRoot(nsIFrame* aFrame,
const nsPoint &aPt);
/**
* Helper function that, given a rectangle and a matrix, returns the smallest
* rectangle containing the image of the source rectangle.

Просмотреть файл

@ -4544,7 +4544,7 @@ nsIFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0),
scaleFactor);
/* Combine the raw transform with a translation to our parent. */
result = result * gfx3DMatrix::Translation
result *= gfx3DMatrix::Translation
(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
NSAppUnitsToFloatPixels(delta.y, scaleFactor),
0.0f);