diff options
Diffstat (limited to 'dom/svg/nsSVGPolyElement.cpp')
-rw-r--r-- | dom/svg/nsSVGPolyElement.cpp | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/dom/svg/nsSVGPolyElement.cpp b/dom/svg/nsSVGPolyElement.cpp new file mode 100644 index 000000000..441f8aa51 --- /dev/null +++ b/dom/svg/nsSVGPolyElement.cpp @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsSVGPolyElement.h" +#include "DOMSVGPointList.h" +#include "mozilla/gfx/2D.h" +#include "SVGContentUtils.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +//---------------------------------------------------------------------- +// nsISupports methods + +NS_IMPL_ADDREF_INHERITED(nsSVGPolyElement,nsSVGPolyElementBase) +NS_IMPL_RELEASE_INHERITED(nsSVGPolyElement,nsSVGPolyElementBase) + +NS_INTERFACE_MAP_BEGIN(nsSVGPolyElement) +NS_INTERFACE_MAP_END_INHERITING(nsSVGPolyElementBase) + +//---------------------------------------------------------------------- +// Implementation + +nsSVGPolyElement::nsSVGPolyElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo) + : nsSVGPolyElementBase(aNodeInfo) +{ +} + +nsSVGPolyElement::~nsSVGPolyElement() +{ +} + +already_AddRefed<DOMSVGPointList> +nsSVGPolyElement::Points() +{ + void *key = mPoints.GetBaseValKey(); + RefPtr<DOMSVGPointList> points = DOMSVGPointList::GetDOMWrapper(key, this, false); + return points.forget(); +} + +already_AddRefed<DOMSVGPointList> +nsSVGPolyElement::AnimatedPoints() +{ + void *key = mPoints.GetAnimValKey(); + RefPtr<DOMSVGPointList> points = DOMSVGPointList::GetDOMWrapper(key, this, true); + return points.forget(); +} + + +//---------------------------------------------------------------------- +// nsIContent methods + +NS_IMETHODIMP_(bool) +nsSVGPolyElement::IsAttributeMapped(const nsIAtom* name) const +{ + static const MappedAttributeEntry* const map[] = { + sMarkersMap + }; + + return FindAttributeDependence(name, map) || + nsSVGPolyElementBase::IsAttributeMapped(name); +} + +//---------------------------------------------------------------------- +// nsSVGElement methods + +/* virtual */ bool +nsSVGPolyElement::HasValidDimensions() const +{ + return !mPoints.GetAnimValue().IsEmpty(); +} + +//---------------------------------------------------------------------- +// nsSVGPathGeometryElement methods + +bool +nsSVGPolyElement::AttributeDefinesGeometry(const nsIAtom *aName) +{ + if (aName == nsGkAtoms::points) + return true; + + return false; +} + +void +nsSVGPolyElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks) +{ + const SVGPointList &points = mPoints.GetAnimValue(); + + if (!points.Length()) + return; + + float px = points[0].mX, py = points[0].mY, prevAngle = 0.0; + + aMarks->AppendElement(nsSVGMark(px, py, 0, nsSVGMark::eStart)); + + for (uint32_t i = 1; i < points.Length(); ++i) { + float x = points[i].mX; + float y = points[i].mY; + float angle = atan2(y-py, x-px); + + // Vertex marker. + if (i == 1) { + aMarks->ElementAt(0).angle = angle; + } else { + aMarks->ElementAt(aMarks->Length() - 1).angle = + SVGContentUtils::AngleBisect(prevAngle, angle); + } + + aMarks->AppendElement(nsSVGMark(x, y, 0, nsSVGMark::eMid)); + + prevAngle = angle; + px = x; + py = y; + } + + aMarks->LastElement().angle = prevAngle; + aMarks->LastElement().type = nsSVGMark::eEnd; +} + +bool +nsSVGPolyElement::GetGeometryBounds(Rect* aBounds, + const StrokeOptions& aStrokeOptions, + const Matrix& aToBoundsSpace, + const Matrix* aToNonScalingStrokeSpace) +{ + const SVGPointList &points = mPoints.GetAnimValue(); + + if (!points.Length()) { + // Rendering of the element is disabled + aBounds->SetEmpty(); + return true; + } + + if (aStrokeOptions.mLineWidth > 0 || aToNonScalingStrokeSpace) { + // We don't handle non-scaling-stroke or stroke-miterlimit etc. yet + return false; + } + + if (aToBoundsSpace.IsRectilinear()) { + // We can avoid transforming each point and just transform the result. + // Important for large point lists. + Rect bounds(points[0], Size()); + for (uint32_t i = 1; i < points.Length(); ++i) { + bounds.ExpandToEnclose(points[i]); + } + *aBounds = aToBoundsSpace.TransformBounds(bounds); + } else { + *aBounds = Rect(aToBoundsSpace.TransformPoint(points[0]), Size()); + for (uint32_t i = 1; i < points.Length(); ++i) { + aBounds->ExpandToEnclose(aToBoundsSpace.TransformPoint(points[i])); + } + } + return true; +} + |