Bug 930577 - Convert much of the SVG code for calculating path lengths and position at an offset along a path to Moz2D. r=heycam

This commit is contained in:
Jonathan Watt 2013-11-18 01:29:06 +00:00
Родитель 0b523bd06b
Коммит 986088b126
12 изменённых файлов: 114 добавлений и 50 удалений

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

@ -7,6 +7,7 @@
#include "mozilla/dom/SVGAnimationElement.h"
#include "mozilla/dom/SVGPathElement.h" // for nsSVGPathList
#include "mozilla/dom/SVGMPathElement.h"
#include "mozilla/gfx/2D.h"
#include "nsAttrValue.h"
#include "nsAttrValueInlines.h"
#include "nsSMILParserUtils.h"
@ -15,9 +16,10 @@
#include "SVGMotionSMILType.h"
#include "SVGMotionSMILPathUtils.h"
namespace mozilla {
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace dom;
namespace mozilla {
SVGMotionSMILAnimationFunction::SVGMotionSMILAnimationFunction()
: mRotateType(eRotateType_Explicit),
@ -227,7 +229,8 @@ SVGMotionSMILAnimationFunction::
bool ok =
path.GetDistancesFromOriginToEndsOfVisibleSegments(&mPathVertices);
if (ok && mPathVertices.Length()) {
mPath = pathElem->GetPath(gfxMatrix());
RefPtr<Path> path = pathElem->GetPathForLengthOrPositionMeasuring();
mPath = new gfxPath(path);
}
}
}
@ -252,7 +255,8 @@ SVGMotionSMILAnimationFunction::RebuildPathAndVerticesFromPathAttr()
return;
}
mPath = path.ToPath(gfxMatrix());
RefPtr<Path> moz2dpath = path.ToPathForLengthOrPositionMeasuring();
mPath = new gfxPath(moz2dpath);
bool ok = path.GetDistancesFromOriginToEndsOfVisibleSegments(&mPathVertices);
if (!ok || !mPathVertices.Length()) {
mPath = nullptr;

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

@ -806,17 +806,18 @@ SVGPathData::ConstructPath(gfxContext *aCtx) const
MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS;
}
already_AddRefed<gfxPath>
SVGPathData::ToPath(const gfxMatrix& aMatrix) const
TemporaryRef<Path>
SVGPathData::ToPathForLengthOrPositionMeasuring() const
{
nsRefPtr<gfxContext> tmpCtx =
new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
// Since the path that we return will not be used for painting it doesn't
// matter what we pass to BuildPath as aFillRule. Hawever, we do want to
// pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as aStrokeLineCap
// to avoid the insertion of extra little lines (by
// ApproximateZeroLengthSubpathSquareCaps), in which case the value that we
// pass as aStrokeWidth doesn't matter (since it's only used to determine the
// length of those extra little lines).
tmpCtx->SetMatrix(aMatrix);
ConstructPath(tmpCtx);
tmpCtx->IdentityMatrix();
return tmpCtx->CopyPath();
return BuildPath(FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 0);
}
static double

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

@ -159,8 +159,12 @@ public:
*/
bool GetDistancesFromOriginToEndsOfVisibleSegments(nsTArray<double> *aArray) const;
already_AddRefed<gfxPath>
ToPath(const gfxMatrix& aMatrix) const;
/**
* This returns a path without the extra little line segments that
* ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps.
* See the comment for that function for more info on that.
*/
TemporaryRef<Path> ToPathForLengthOrPositionMeasuring() const;
void ConstructPath(gfxContext *aCtx) const;
TemporaryRef<Path> BuildPath(FillRule aFillRule,

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

@ -11,7 +11,9 @@
#include "DOMSVGPathSegList.h"
#include "DOMSVGPoint.h"
#include "gfxPath.h"
#include "gfx2DGlue.h"
#include "mozilla/dom/SVGPathElementBinding.h"
#include "mozilla/gfx/2D.h"
#include "nsCOMPtr.h"
#include "nsComputedDOMStyle.h"
#include "nsGkAtoms.h"
@ -59,25 +61,27 @@ SVGPathElement::PathLength()
float
SVGPathElement::GetTotalLength(ErrorResult& rv)
{
nsRefPtr<gfxPath> flat = GetPath(gfxMatrix());
RefPtr<Path> flat = GetPathForLengthOrPositionMeasuring();
if (!flat) {
rv.Throw(NS_ERROR_FAILURE);
return 0.f;
}
return flat->GetLength();
return flat->ComputeLength();
}
already_AddRefed<nsISVGPoint>
SVGPathElement::GetPointAtLength(float distance, ErrorResult& rv)
{
nsRefPtr<gfxPath> flat = GetPath(gfxMatrix());
if (!flat) {
RefPtr<Path> path = GetPathForLengthOrPositionMeasuring();
if (!path) {
rv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<gfxPath> flat = new gfxPath(path);
float totalLength = flat->GetLength();
if (mPathLength.IsExplicitlySet()) {
float pathLength = mPathLength.GetAnimValue();
@ -298,10 +302,10 @@ SVGPathElement::IsAttributeMapped(const nsIAtom* name) const
SVGPathElementBase::IsAttributeMapped(name);
}
already_AddRefed<gfxPath>
SVGPathElement::GetPath(const gfxMatrix &aMatrix)
TemporaryRef<Path>
SVGPathElement::GetPathForLengthOrPositionMeasuring()
{
return mD.GetAnimValue().ToPath(aMatrix);
return mD.GetAnimValue().ToPathForLengthOrPositionMeasuring();
}
//----------------------------------------------------------------------
@ -340,16 +344,22 @@ SVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor)
if (mPathLength.IsExplicitlySet()) {
float authorsPathLengthEstimate = mPathLength.GetAnimValue();
if (authorsPathLengthEstimate > 0) {
gfxMatrix matrix;
RefPtr<Path> path = GetPathForLengthOrPositionMeasuring();
if (aFor == eForTextPath) {
// For textPath, a transform on the referenced path affects the
// textPath layout, so when calculating the actual path length
// we need to take that into account.
matrix = PrependLocalTransformsTo(matrix);
gfxMatrix matrix = PrependLocalTransformsTo(gfxMatrix());
if (!matrix.IsIdentity()) {
RefPtr<PathBuilder> builder =
path->TransformedCopyToBuilder(ToMatrix(matrix));
path = builder->Finish();
}
}
nsRefPtr<gfxPath> path = GetPath(matrix);
if (path) {
return path->GetLength() / authorsPathLengthEstimate;
return path->ComputeLength() / authorsPathLengthEstimate;
}
}
}

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

@ -6,6 +6,8 @@
#ifndef mozilla_dom_SVGPathElement_h
#define mozilla_dom_SVGPathElement_h
#include "mozilla/gfx/2D.h"
#include "mozilla/RefPtr.h"
#include "nsSVGNumber2.h"
#include "nsSVGPathGeometryElement.h"
#include "SVGAnimatedPathSegList.h"
@ -28,6 +30,8 @@ class SVGPathElement MOZ_FINAL : public SVGPathElementBase
{
friend class nsSVGPathFrame;
typedef mozilla::gfx::Path Path;
protected:
friend nsresult (::NS_NewSVGPathElement(nsIContent **aResult,
already_AddRefed<nsINodeInfo> aNodeInfo));
@ -49,7 +53,13 @@ public:
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
virtual already_AddRefed<gfxPath> GetPath(const gfxMatrix &aMatrix) MOZ_OVERRIDE;
/**
* This returns a path without the extra little line segments that
* ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps.
* See the comment for that function for more info on that.
*/
virtual TemporaryRef<Path>
GetPathForLengthOrPositionMeasuring() MOZ_OVERRIDE;
// nsIContent interface
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;

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

@ -60,8 +60,8 @@ nsSVGPathGeometryElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
{
}
already_AddRefed<gfxPath>
nsSVGPathGeometryElement::GetPath(const gfxMatrix &aMatrix)
TemporaryRef<Path>
nsSVGPathGeometryElement::GetPathForLengthOrPositionMeasuring()
{
return nullptr;
}

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

@ -66,7 +66,7 @@ public:
*/
virtual mozilla::TemporaryRef<Path> BuildPath() = 0;
virtual already_AddRefed<gfxPath> GetPath(const gfxMatrix &aMatrix);
virtual mozilla::TemporaryRef<Path> GetPathForLengthOrPositionMeasuring();
/**
* Returns a PathBuilder object created using the current computed value of

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

@ -12,6 +12,7 @@
#include "gfxContext.h"
#include "gfxMatrix.h"
#include "gfxPlatform.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/LookAndFeel.h"
#include "nsBidiPresUtils.h"
#include "nsDisplayList.h"
@ -28,6 +29,7 @@
#include "SVGLengthList.h"
using namespace mozilla;
using namespace mozilla::gfx;
struct CharacterPosition {
gfxPoint pos;
@ -739,15 +741,17 @@ nsSVGGlyphFrame::GetCharacterPositions(nsTArray<CharacterPosition>* aCharacterPo
nsSVGTextPathFrame *textPath = FindTextPathParent();
if (textPath) {
nsRefPtr<gfxPath> data = textPath->GetPath();
RefPtr<Path> path = textPath->GetPath();
// textPath frame, but invalid target
if (!data)
if (!path)
return false;
if (!aCharacterPositions->SetLength(strLength))
return false;
nsRefPtr<gfxPath> data = new gfxPath(path);
gfxFloat pathScale = textPath->GetOffsetScale();
CharacterPosition *cp = aCharacterPositions->Elements();

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

@ -8,10 +8,12 @@
// Keep others in (case-insensitive) order:
#include "DOMSVGPoint.h"
#include "gfx2DGlue.h"
#include "gfxFont.h"
#include "gfxSkipChars.h"
#include "gfxTypes.h"
#include "LookAndFeel.h"
#include "mozilla/gfx/2D.h"
#include "nsAlgorithm.h"
#include "nsBlockFrame.h"
#include "nsCaret.h"
@ -47,6 +49,7 @@
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::gfx;
// ============================================================================
// Utility functions
@ -4715,16 +4718,25 @@ nsSVGTextFrame2::GetTextPathPathFrame(nsIFrame* aTextPathFrame)
return property->GetReferencedFrame(nsGkAtoms::svgPathGeometryFrame, nullptr);
}
already_AddRefed<gfxPath>
TemporaryRef<Path>
nsSVGTextFrame2::GetTextPath(nsIFrame* aTextPathFrame)
{
nsIFrame *path = GetTextPathPathFrame(aTextPathFrame);
nsIFrame *pathFrame = GetTextPathPathFrame(aTextPathFrame);
if (path) {
if (pathFrame) {
nsSVGPathGeometryElement *element =
static_cast<nsSVGPathGeometryElement*>(path->GetContent());
static_cast<nsSVGPathGeometryElement*>(pathFrame->GetContent());
return element->GetPath(element->PrependLocalTransformsTo(gfxMatrix()));
RefPtr<Path> path = element->GetPathForLengthOrPositionMeasuring();
gfxMatrix matrix = element->PrependLocalTransformsTo(gfxMatrix());
if (!matrix.IsIdentity()) {
RefPtr<PathBuilder> builder =
path->TransformedCopyToBuilder(ToMatrix(matrix));
path = builder->Finish();
}
return path.forget();
}
return nullptr;
}
@ -4749,10 +4761,10 @@ nsSVGTextFrame2::GetStartOffset(nsIFrame* aTextPathFrame)
&tp->mLengthAttributes[dom::SVGTextPathElement::STARTOFFSET];
if (length->IsPercentage()) {
nsRefPtr<gfxPath> data = GetTextPath(aTextPathFrame);
RefPtr<Path> data = GetTextPath(aTextPathFrame);
return data ?
length->GetAnimValInSpecifiedUnits() * data->GetLength() / 100.0 :
0.0;
length->GetAnimValInSpecifiedUnits() * data->ComputeLength() / 100.0 :
0.0;
}
return length->GetAnimValue(tp) * GetOffsetScale(aTextPathFrame);
}
@ -4772,7 +4784,8 @@ nsSVGTextFrame2::DoTextPathLayout()
}
// Get the path itself.
nsRefPtr<gfxPath> data = GetTextPath(textPathFrame);
RefPtr<Path> path = GetTextPath(textPathFrame);
nsRefPtr<gfxPath> data = new gfxPath(path);
if (!data) {
it.AdvancePastCurrentTextPathFrame();
continue;

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

@ -7,6 +7,8 @@
#define NS_SVGTEXTFRAME2_H
#include "mozilla/Attributes.h"
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/2D.h"
#include "gfxMatrix.h"
#include "gfxRect.h"
#include "gfxSVGGlyphs.h"
@ -251,6 +253,7 @@ class nsSVGTextFrame2 : public nsSVGTextFrame2Base
friend class MutationObserver;
friend class nsDisplaySVGText;
typedef mozilla::gfx::Path Path;
typedef mozilla::SVGTextContextPaint SVGTextContextPaint;
protected:
@ -585,7 +588,7 @@ private:
// Methods to get information for a <textPath> frame.
nsIFrame* GetTextPathPathFrame(nsIFrame* aTextPathFrame);
already_AddRefed<gfxPath> GetTextPath(nsIFrame* aTextPathFrame);
mozilla::TemporaryRef<Path> GetTextPath(nsIFrame* aTextPathFrame);
gfxFloat GetOffsetScale(nsIFrame* aTextPathFrame);
gfxFloat GetStartOffset(nsIFrame* aTextPathFrame);

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

@ -7,16 +7,19 @@
#include "nsSVGTextPathFrame.h"
// Keep others in (case-insensitive) order:
#include "gfx2DGlue.h"
#include "gfxPath.h"
#include "nsContentUtils.h"
#include "nsSVGEffects.h"
#include "nsSVGLength2.h"
#include "mozilla/dom/SVGPathElement.h"
#include "mozilla/dom/SVGTextPathElement.h"
#include "mozilla/gfx/2D.h"
#include "SVGLengthList.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::gfx;
//----------------------------------------------------------------------
// Implementation
@ -111,16 +114,25 @@ nsSVGTextPathFrame::GetPathFrame()
return frame && frame->GetContent()->Tag() == nsGkAtoms::path ? frame : nullptr;
}
already_AddRefed<gfxPath>
TemporaryRef<Path>
nsSVGTextPathFrame::GetPath()
{
nsIFrame *path = GetPathFrame();
nsIFrame *pathFrame = GetPathFrame();
if (path) {
if (pathFrame) {
nsSVGPathGeometryElement *element =
static_cast<nsSVGPathGeometryElement*>(path->GetContent());
static_cast<nsSVGPathGeometryElement*>(pathFrame->GetContent());
return element->GetPath(element->PrependLocalTransformsTo(gfxMatrix()));
RefPtr<Path> path = element->GetPathForLengthOrPositionMeasuring();
gfxMatrix matrix = element->PrependLocalTransformsTo(gfxMatrix());
if (!matrix.IsIdentity()) {
RefPtr<PathBuilder> builder =
path->TransformedCopyToBuilder(ToMatrix(matrix));
path = builder->Finish();
}
return path.forget();
}
return nullptr;
}
@ -132,8 +144,8 @@ nsSVGTextPathFrame::GetStartOffset()
nsSVGLength2 *length = &tp->mLengthAttributes[SVGTextPathElement::STARTOFFSET];
if (length->IsPercentage()) {
nsRefPtr<gfxPath> data = GetPath();
return data ? (length->GetAnimValInSpecifiedUnits() * data->GetLength() / 100.0) : 0.0;
RefPtr<Path> path = GetPath();
return path ? (length->GetAnimValInSpecifiedUnits() * path->ComputeLength() / 100.0) : 0.0;
}
return length->GetAnimValue(tp) * GetOffsetScale();
}

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

@ -7,6 +7,8 @@
#define NSSVGTEXTPATHFRAME_H
#include "mozilla/Attributes.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/RefPtr.h"
#include "gfxTypes.h"
#include "nsCOMPtr.h"
#include "nsFrame.h"
@ -30,6 +32,7 @@ typedef nsSVGTSpanFrame nsSVGTextPathFrameBase;
class nsSVGTextPathFrame : public nsSVGTextPathFrameBase
{
typedef mozilla::gfx::Path Path;
typedef mozilla::SVGNumberList SVGNumberList;
friend nsIFrame*
@ -65,7 +68,7 @@ public:
#endif
// nsSVGTextPathFrame methods:
already_AddRefed<gfxPath> GetPath();
mozilla::TemporaryRef<Path> GetPath();
nsIFrame *GetPathFrame();
/**