Bug 918189. Part 1: Implement GeometryUtils ConvertQuad/Rect/PointFromNode. r=mats

--HG--
extra : rebase_source : deade5e87ae77b3fe9efdfde9ba2f3254318f387
This commit is contained in:
Robert O'Callahan 2014-03-12 09:11:38 +08:00
parent 905a9306af
commit a89f4549c0
2 changed files with 163 additions and 7 deletions

View File

@ -5,10 +5,13 @@
#include "GeometryUtils.h"
#include "mozilla/dom/DOMPointBinding.h"
#include "mozilla/dom/GeometryUtilsBinding.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Text.h"
#include "mozilla/dom/DOMPoint.h"
#include "mozilla/dom/DOMQuad.h"
#include "mozilla/dom/DOMRect.h"
#include "nsIFrame.h"
#include "nsGenericDOMDataNode.h"
#include "nsCSSFrameConstructor.h"
@ -20,8 +23,6 @@ using namespace mozilla::dom;
namespace mozilla {
typedef OwningTextOrElementOrDocument GeometryNode;
enum GeometryNodeType {
GEOMETRY_NODE_ELEMENT,
GEOMETRY_NODE_TEXT,
@ -55,14 +56,14 @@ GetFrameForNode(nsINode* aNode, GeometryNodeType aType)
}
static nsIFrame*
GetFrameForGeometryNode(const Optional<GeometryNode>& aGeometryNode,
GetFrameForGeometryNode(const Optional<OwningGeometryNode>& aGeometryNode,
nsINode* aDefaultNode)
{
if (!aGeometryNode.WasPassed()) {
return GetFrameForNode(aDefaultNode->OwnerDoc(), GEOMETRY_NODE_DOCUMENT);
}
const GeometryNode& value = aGeometryNode.Value();
const OwningGeometryNode& value = aGeometryNode.Value();
if (value.IsElement()) {
return GetFrameForNode(value.GetAsElement(), GEOMETRY_NODE_ELEMENT);
}
@ -72,6 +73,18 @@ GetFrameForGeometryNode(const Optional<GeometryNode>& aGeometryNode,
return GetFrameForNode(value.GetAsText(), GEOMETRY_NODE_TEXT);
}
static nsIFrame*
GetFrameForGeometryNode(const GeometryNode& aGeometryNode)
{
if (aGeometryNode.IsElement()) {
return GetFrameForNode(&aGeometryNode.GetAsElement(), GEOMETRY_NODE_ELEMENT);
}
if (aGeometryNode.IsDocument()) {
return GetFrameForNode(&aGeometryNode.GetAsDocument(), GEOMETRY_NODE_DOCUMENT);
}
return GetFrameForNode(&aGeometryNode.GetAsText(), GEOMETRY_NODE_TEXT);
}
static nsIFrame*
GetFrameForNode(nsINode* aNode)
{
@ -86,7 +99,7 @@ GetFrameForNode(nsINode* aNode)
}
static nsIFrame*
GetFirstNonAnonymousFrameForGeometryNode(const Optional<GeometryNode>& aNode,
GetFirstNonAnonymousFrameForGeometryNode(const Optional<OwningGeometryNode>& aNode,
nsINode* aDefaultNode)
{
nsIFrame* f = GetFrameForGeometryNode(aNode, aDefaultNode);
@ -96,6 +109,26 @@ GetFirstNonAnonymousFrameForGeometryNode(const Optional<GeometryNode>& aNode,
return f;
}
static nsIFrame*
GetFirstNonAnonymousFrameForGeometryNode(const GeometryNode& aNode)
{
nsIFrame* f = GetFrameForGeometryNode(aNode);
if (f) {
f = nsLayoutUtils::GetFirstNonAnonymousFrame(f);
}
return f;
}
static nsIFrame*
GetFirstNonAnonymousFrameForNode(nsINode* aNode)
{
nsIFrame* f = GetFrameForNode(aNode);
if (f) {
f = nsLayoutUtils::GetFirstNonAnonymousFrame(f);
}
return f;
}
/**
* This can modify aFrame to point to a different frame. This is needed to
* handle SVG, where SVG elements can only compute a rect that's valid with
@ -235,4 +268,102 @@ void GetBoxQuads(nsINode* aNode,
nsLayoutUtils::GetAllInFlowBoxes(frame, &callback);
}
static void
TransformPoints(nsINode* aTo, const GeometryNode& aFrom,
uint32_t aPointCount, CSSPoint* aPoints,
const ConvertCoordinateOptions& aOptions, ErrorResult& aRv)
{
nsIFrame* fromFrame = GetFirstNonAnonymousFrameForGeometryNode(aFrom);
nsIFrame* toFrame = GetFirstNonAnonymousFrameForNode(aTo);
if (!fromFrame || !toFrame) {
aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
return;
}
if (!CheckFramesInSameTopLevelBrowsingContext(fromFrame, toFrame)) {
aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
return;
}
nsPoint fromOffset = GetBoxRectForFrame(&fromFrame, aOptions.mFromBox).TopLeft();
nsPoint toOffset = GetBoxRectForFrame(&toFrame, aOptions.mToBox).TopLeft();
CSSPoint fromOffsetGfx(nsPresContext::AppUnitsToFloatCSSPixels(fromOffset.x),
nsPresContext::AppUnitsToFloatCSSPixels(fromOffset.y));
for (uint32_t i = 0; i < aPointCount; ++i) {
aPoints[i] += fromOffsetGfx;
}
nsLayoutUtils::TransformResult rv =
nsLayoutUtils::TransformPoints(fromFrame, toFrame, aPointCount, aPoints);
if (rv == nsLayoutUtils::TRANSFORM_SUCCEEDED) {
CSSPoint toOffsetGfx(nsPresContext::AppUnitsToFloatCSSPixels(toOffset.x),
nsPresContext::AppUnitsToFloatCSSPixels(toOffset.y));
for (uint32_t i = 0; i < aPointCount; ++i) {
aPoints[i] -= toOffsetGfx;
}
} else {
PodZero(aPoints, aPointCount);
}
}
already_AddRefed<DOMQuad>
ConvertQuadFromNode(nsINode* aTo, dom::DOMQuad& aQuad,
const GeometryNode& aFrom,
const dom::ConvertCoordinateOptions& aOptions,
ErrorResult& aRv)
{
CSSPoint points[4];
for (uint32_t i = 0; i < 4; ++i) {
DOMPoint* p = aQuad.Point(i);
if (p->W() != 1.0 || p->Z() != 0.0) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
points[i] = CSSPoint(p->X(), p->Y());
}
TransformPoints(aTo, aFrom, 4, points, aOptions, aRv);
if (aRv.Failed()) {
return nullptr;
}
nsRefPtr<DOMQuad> result = new DOMQuad(aTo->GetParentObject().mObject, points);
return result.forget();
}
already_AddRefed<DOMQuad>
ConvertRectFromNode(nsINode* aTo, dom::DOMRectReadOnly& aRect,
const GeometryNode& aFrom,
const dom::ConvertCoordinateOptions& aOptions,
ErrorResult& aRv)
{
CSSPoint points[4];
double x = aRect.X(), y = aRect.Y(), w = aRect.Width(), h = aRect.Height();
points[0] = CSSPoint(x, y);
points[1] = CSSPoint(x + w, y);
points[2] = CSSPoint(x + w, y + h);
points[3] = CSSPoint(x, y + h);
TransformPoints(aTo, aFrom, 4, points, aOptions, aRv);
if (aRv.Failed()) {
return nullptr;
}
nsRefPtr<DOMQuad> result = new DOMQuad(aTo->GetParentObject().mObject, points);
return result.forget();
}
already_AddRefed<DOMPoint>
ConvertPointFromNode(nsINode* aTo, const dom::DOMPointInit& aPoint,
const GeometryNode& aFrom,
const dom::ConvertCoordinateOptions& aOptions,
ErrorResult& aRv)
{
if (aPoint.mW != 1.0 || aPoint.mZ != 0.0) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
CSSPoint point(aPoint.mX, aPoint.mY);
TransformPoints(aTo, aFrom, 1, &point, aOptions, aRv);
if (aRv.Failed()) {
return nullptr;
}
nsRefPtr<DOMPoint> result = new DOMPoint(aTo->GetParentObject().mObject, point.x, point.y);
return result.forget();
}
}

View File

@ -22,11 +22,18 @@ namespace mozilla {
namespace dom {
struct BoxQuadOptions;
struct ConvertCoordinateOptions;
class DOMQuad;
class Element;
class Text;
class DOMRectReadOnly;
class DOMPoint;
class DOMPointInit;
class OwningTextOrElementOrDocument;
class TextOrElementOrDocument;
}
typedef dom::TextOrElementOrDocument GeometryNode;
typedef dom::OwningTextOrElementOrDocument OwningGeometryNode;
/**
* Computes quads for aNode using aOptions, according to GeometryUtils.getBoxQuads.
* May set an error in aRv.
@ -36,6 +43,24 @@ void GetBoxQuads(nsINode* aNode,
nsTArray<nsRefPtr<dom::DOMQuad> >& aResult,
ErrorResult& aRv);
already_AddRefed<dom::DOMQuad>
ConvertQuadFromNode(nsINode* aTo, dom::DOMQuad& aQuad,
const GeometryNode& aFrom,
const dom::ConvertCoordinateOptions& aOptions,
ErrorResult& aRv);
already_AddRefed<dom::DOMQuad>
ConvertRectFromNode(nsINode* aTo, dom::DOMRectReadOnly& aRect,
const GeometryNode& aFrom,
const dom::ConvertCoordinateOptions& aOptions,
ErrorResult& aRv);
already_AddRefed<dom::DOMPoint>
ConvertPointFromNode(nsINode* aTo, const dom::DOMPointInit& aPoint,
const GeometryNode& aFrom,
const dom::ConvertCoordinateOptions& aOptions,
ErrorResult& aRv);
}
#endif /* MOZILLA_GEOMETRYUTILS_H_ */