Bug 917755. Part 1: Add nsLayoutUtils::TransformCSSPoints and nsLayoutUtils::GetFirstNonAnonymousFrame. r=matspal

--HG--
extra : rebase_source : 06e2c83a984d12fce29cd23b93dde54a2e05cf43
This commit is contained in:
Robert O'Callahan 2013-09-20 22:21:03 +12:00
parent 3edac283b7
commit 242ffba63c
2 changed files with 146 additions and 22 deletions

View File

@ -1893,6 +1893,66 @@ nsLayoutUtils::GetTransformToAncestor(nsIFrame *aFrame, const nsIFrame *aAncesto
return ctm;
}
static nsIFrame*
FindNearestCommonAncestorFrame(nsIFrame* aFrame1, nsIFrame* aFrame2)
{
nsAutoTArray<nsIFrame*,100> ancestors1;
nsAutoTArray<nsIFrame*,100> ancestors2;
nsIFrame* commonAncestor = nullptr;
if (aFrame1->PresContext() == aFrame2->PresContext()) {
commonAncestor = aFrame1->PresContext()->PresShell()->GetRootFrame();
}
for (nsIFrame* f = aFrame1; f != commonAncestor;
f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
ancestors1.AppendElement(f);
}
for (nsIFrame* f = aFrame2; f != commonAncestor;
f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
ancestors2.AppendElement(f);
}
uint32_t minLengths = std::min(ancestors1.Length(), ancestors2.Length());
for (uint32_t i = 1; i <= minLengths; ++i) {
if (ancestors1[ancestors1.Length() - i] == ancestors2[ancestors2.Length() - i]) {
commonAncestor = ancestors1[ancestors1.Length() - i];
} else {
break;
}
}
return commonAncestor;
}
nsLayoutUtils::TransformResult
nsLayoutUtils::TransformPoints(nsIFrame* aFromFrame, nsIFrame* aToFrame,
uint32_t aPointCount, CSSPoint* aPoints)
{
nsIFrame* nearestCommonAncestor = FindNearestCommonAncestorFrame(aFromFrame, aToFrame);
if (!nearestCommonAncestor) {
return NO_COMMON_ANCESTOR;
}
gfx3DMatrix downToDest = GetTransformToAncestor(aToFrame, nearestCommonAncestor);
if (downToDest.IsSingular()) {
return NONINVERTIBLE_TRANSFORM;
}
downToDest.Invert();
gfx3DMatrix upToAncestor = GetTransformToAncestor(aFromFrame, nearestCommonAncestor);
CSSToLayoutDeviceScale devPixelsPerCSSPixelFromFrame(
double(nsPresContext::AppUnitsPerCSSPixel())/
aFromFrame->PresContext()->AppUnitsPerDevPixel());
CSSToLayoutDeviceScale devPixelsPerCSSPixelToFrame(
double(nsPresContext::AppUnitsPerCSSPixel())/
aToFrame->PresContext()->AppUnitsPerDevPixel());
for (uint32_t i = 0; i < aPointCount; ++i) {
LayoutDevicePoint devPixels = aPoints[i] * devPixelsPerCSSPixelFromFrame;
gfxPoint toDevPixels = downToDest.ProjectPoint(
upToAncestor.ProjectPoint(gfxPoint(devPixels.x, devPixels.y)));
// Divide here so that when the devPixelsPerCSSPixels are the same, we get the correct
// answer instead of some inaccuracy multiplying a number by its reciprocal.
aPoints[i] = LayoutDevicePoint(toDevPixels.x, toDevPixels.y) /
devPixelsPerCSSPixelToFrame;
}
return TRANSFORM_SUCCEEDED;
}
bool
nsLayoutUtils::GetLayerTransformForFrame(nsIFrame* aFrame,
gfx3DMatrix* aTransform)
@ -2586,6 +2646,43 @@ nsLayoutUtils::GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback)
}
}
nsIFrame*
nsLayoutUtils::GetFirstNonAnonymousFrame(nsIFrame* aFrame)
{
while (aFrame) {
nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
if (pseudoType == nsCSSAnonBoxes::tableOuter) {
nsIFrame* f = GetFirstNonAnonymousFrame(aFrame->GetFirstPrincipalChild());
if (f) {
return f;
}
nsIFrame* kid = aFrame->GetFirstChild(nsIFrame::kCaptionList);
if (kid) {
f = GetFirstNonAnonymousFrame(kid);
if (f) {
return f;
}
}
} else if (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock ||
pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock ||
pseudoType == nsCSSAnonBoxes::mozMathMLAnonymousBlock ||
pseudoType == nsCSSAnonBoxes::mozXULAnonymousBlock) {
for (nsIFrame* kid = aFrame->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
nsIFrame* f = GetFirstNonAnonymousFrame(kid);
if (f) {
return f;
}
}
} else {
return aFrame;
}
aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame);
}
return nullptr;
}
struct BoxToRect : public nsLayoutUtils::BoxCallback {
nsIFrame* mRelativeTo;
nsLayoutUtils::RectCallback* mCallback;

View File

@ -6,6 +6,29 @@
#ifndef nsLayoutUtils_h__
#define nsLayoutUtils_h__
#include "mozilla/MemoryReporting.h"
#include "nsChangeHint.h"
#include "nsAutoPtr.h"
#include "nsFrameList.h"
#include "nsThreadUtils.h"
#include "nsIPrincipal.h"
#include "GraphicsFilter.h"
#include "nsCSSPseudoElements.h"
#include "FrameMetrics.h"
#include "gfx3DMatrix.h"
#include "nsIWidget.h"
#include "nsCSSProperty.h"
#include "nsStyleCoord.h"
#include "nsStyleConsts.h"
#include "nsGkAtoms.h"
#include "nsRuleNode.h"
#include "imgIContainer.h"
#include "mozilla/gfx/2D.h"
#include "Units.h"
#include <limits>
#include <algorithm>
class nsIFormControlFrame;
class nsPresContext;
class nsIContent;
@ -30,32 +53,11 @@ class gfxContext;
class nsPIDOMWindow;
class imgIRequest;
class nsIDocument;
class gfxPoint;
struct nsStyleFont;
struct nsStyleImageOrientation;
struct nsOverflowAreas;
#include "mozilla/MemoryReporting.h"
#include "nsChangeHint.h"
#include "nsAutoPtr.h"
#include "nsFrameList.h"
#include "nsThreadUtils.h"
#include "nsIPrincipal.h"
#include "GraphicsFilter.h"
#include "nsCSSPseudoElements.h"
#include "FrameMetrics.h"
#include "gfx3DMatrix.h"
#include "nsIWidget.h"
#include "nsCSSProperty.h"
#include "nsStyleCoord.h"
#include "nsStyleConsts.h"
#include "nsGkAtoms.h"
#include "nsRuleNode.h"
#include "imgIContainer.h"
#include "mozilla/gfx/2D.h"
#include <limits>
#include <algorithm>
namespace mozilla {
class SVGImageContext;
struct IntrinsicSize;
@ -107,6 +109,7 @@ class nsLayoutUtils
public:
typedef mozilla::layers::FrameMetrics FrameMetrics;
typedef FrameMetrics::ViewID ViewID;
typedef mozilla::CSSPoint CSSPoint;
/**
* Finds previously assigned ViewID for the given content element, if any.
@ -683,6 +686,24 @@ public:
*/
static gfx3DMatrix GetTransformToAncestor(nsIFrame *aFrame, const nsIFrame *aAncestor);
/**
* Transforms a list of CSSPoints from aFromFrame to aToFrame, taking into
* account all relevant transformations on the frames up to (but excluding)
* their nearest common ancestor.
* If we encounter a transform that we need to invert but which is
* non-invertible, we return NONINVERTIBLE_TRANSFORM. If the frames have
* no common ancestor, we return NO_COMMON_ANCESTOR.
* If this returns TRANSFORM_SUCCEEDED, the points in aPoints are transformed
* in-place, otherwise they are untouched.
*/
enum TransformResult {
TRANSFORM_SUCCEEDED,
NO_COMMON_ANCESTOR,
NONINVERTIBLE_TRANSFORM
};
static TransformResult TransformPoints(nsIFrame* aFromFrame, nsIFrame* aToFrame,
uint32_t aPointCount, CSSPoint* aPoints);
/**
* Return true if a "layer transform" could be computed for aFrame,
* and optionally return the computed transform. The returned
@ -877,6 +898,12 @@ public:
*/
static void GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback);
/**
* Find the first frame descendant of aFrame (including aFrame) which is
* not an anonymous frame that getBoxQuads/getClientRects should ignore.
*/
static nsIFrame* GetFirstNonAnonymousFrame(nsIFrame* aFrame);
class RectCallback {
public:
virtual void AddRect(const nsRect& aRect) = 0;