diff options
Diffstat (limited to 'dom/svg/DOMSVGPathSeg.cpp')
-rw-r--r-- | dom/svg/DOMSVGPathSeg.cpp | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/dom/svg/DOMSVGPathSeg.cpp b/dom/svg/DOMSVGPathSeg.cpp new file mode 100644 index 0000000000..95be3521e2 --- /dev/null +++ b/dom/svg/DOMSVGPathSeg.cpp @@ -0,0 +1,383 @@ +/* -*- 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 "DOMSVGPathSeg.h" +#include "DOMSVGPathSegList.h" +#include "SVGAnimatedPathSegList.h" +#include "nsSVGElement.h" +#include "nsError.h" + +// See the architecture comment in DOMSVGPathSegList.h. + +namespace mozilla { + +// We could use NS_IMPL_CYCLE_COLLECTION(, except that in Unlink() we need to +// clear our list's weak ref to us to be safe. (The other option would be to +// not unlink and rely on the breaking of the other edges in the cycle, as +// NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.) +NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGPathSeg) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPathSeg) + // We may not belong to a list, so we must null check tmp->mList. + if (tmp->mList) { + tmp->mList->ItemAt(tmp->mListIndex) = nullptr; + } +NS_IMPL_CYCLE_COLLECTION_UNLINK(mList) +NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPathSeg) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPathSeg) +NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMSVGPathSeg, AddRef) +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGPathSeg, Release) + +//---------------------------------------------------------------------- +// Helper class: AutoChangePathSegNotifier +// Stack-based helper class to pair calls to WillChangePathSegList +// and DidChangePathSegList. +class MOZ_RAII AutoChangePathSegNotifier +{ +public: + explicit AutoChangePathSegNotifier(DOMSVGPathSeg* aPathSeg MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mPathSeg(aPathSeg) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + MOZ_ASSERT(mPathSeg, "Expecting non-null pathSeg"); + MOZ_ASSERT(mPathSeg->HasOwner(), + "Expecting list to have an owner for notification"); + mEmptyOrOldValue = + mPathSeg->Element()->WillChangePathSegList(); + } + + ~AutoChangePathSegNotifier() + { + mPathSeg->Element()->DidChangePathSegList(mEmptyOrOldValue); + if (mPathSeg->mList->AttrIsAnimating()) { + mPathSeg->Element()->AnimationNeedsResample(); + } + } + +private: + DOMSVGPathSeg* const mPathSeg; + nsAttrValue mEmptyOrOldValue; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +DOMSVGPathSeg::DOMSVGPathSeg(DOMSVGPathSegList *aList, + uint32_t aListIndex, + bool aIsAnimValItem) + : mList(aList) + , mListIndex(aListIndex) + , mIsAnimValItem(aIsAnimValItem) +{ + // These shifts are in sync with the members in the header. + MOZ_ASSERT(aList && aListIndex <= MaxListIndex(), "bad arg"); + + MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPathSeg!"); +} + +DOMSVGPathSeg::DOMSVGPathSeg() + : mList(nullptr) + , mListIndex(0) + , mIsAnimValItem(false) +{ +} + +void +DOMSVGPathSeg::InsertingIntoList(DOMSVGPathSegList *aList, + uint32_t aListIndex, + bool aIsAnimValItem) +{ + MOZ_ASSERT(!HasOwner(), "Inserting item that is already in a list"); + + mList = aList; + mListIndex = aListIndex; + mIsAnimValItem = aIsAnimValItem; + + MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPathSeg!"); +} + +void +DOMSVGPathSeg::RemovingFromList() +{ + uint32_t argCount = SVGPathSegUtils::ArgCountForType(Type()); + // InternalItem() + 1, because the args come after the encoded seg type + memcpy(PtrToMemberArgs(), InternalItem() + 1, argCount * sizeof(float)); + mList = nullptr; + mIsAnimValItem = false; +} + +void +DOMSVGPathSeg::ToSVGPathSegEncodedData(float* aRaw) +{ + MOZ_ASSERT(aRaw, "null pointer"); + uint32_t argCount = SVGPathSegUtils::ArgCountForType(Type()); + if (IsInList()) { + // 1 + argCount, because we're copying the encoded seg type and args + memcpy(aRaw, InternalItem(), (1 + argCount) * sizeof(float)); + } else { + aRaw[0] = SVGPathSegUtils::EncodeType(Type()); + // aRaw + 1, because the args go after the encoded seg type + memcpy(aRaw + 1, PtrToMemberArgs(), argCount * sizeof(float)); + } +} + +float* +DOMSVGPathSeg::InternalItem() +{ + uint32_t dataIndex = mList->mItems[mListIndex].mInternalDataIndex; + return &(mList->InternalList().mData[dataIndex]); +} + +#ifdef DEBUG +bool +DOMSVGPathSeg::IndexIsValid() +{ + SVGAnimatedPathSegList *alist = Element()->GetAnimPathSegList(); + return (mIsAnimValItem && + mListIndex < alist->GetAnimValue().CountItems()) || + (!mIsAnimValItem && + mListIndex < alist->GetBaseValue().CountItems()); +} +#endif + + +//////////////////////////////////////////////////////////////////////// +// Implementation of DOMSVGPathSeg sub-classes below this point + +#define IMPL_PROP_WITH_TYPE(segName, propName, index, type) \ + type \ + DOMSVGPathSeg##segName::propName() \ + { \ + if (mIsAnimValItem && HasOwner()) { \ + Element()->FlushAnimations(); /* May make HasOwner() == false */ \ + } \ + return type(HasOwner() ? InternalItem()[1+index] : mArgs[index]); \ + } \ + void \ + DOMSVGPathSeg##segName::Set##propName(type a##propName, ErrorResult& rv) \ + { \ + if (mIsAnimValItem) { \ + rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); \ + return; \ + } \ + if (HasOwner()) { \ + if (InternalItem()[1+index] == float(a##propName)) { \ + return; \ + } \ + AutoChangePathSegNotifier notifier(this); \ + InternalItem()[1+index] = float(a##propName); \ + } else { \ + mArgs[index] = float(a##propName); \ + } \ + } + +// For float, the normal type of arguments +#define IMPL_FLOAT_PROP(segName, propName, index) \ + IMPL_PROP_WITH_TYPE(segName, propName, index, float) + +// For the boolean flags in arc commands +#define IMPL_BOOL_PROP(segName, propName, index) \ + IMPL_PROP_WITH_TYPE(segName, propName, index, bool) + + +/////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(MovetoAbs, X, 0) +IMPL_FLOAT_PROP(MovetoAbs, Y, 1) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(MovetoRel, X, 0) +IMPL_FLOAT_PROP(MovetoRel, Y, 1) + + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(LinetoAbs, X, 0) +IMPL_FLOAT_PROP(LinetoAbs, Y, 1) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(LinetoRel, X, 0) +IMPL_FLOAT_PROP(LinetoRel, Y, 1) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(CurvetoCubicAbs, X1, 0) +IMPL_FLOAT_PROP(CurvetoCubicAbs, Y1, 1) +IMPL_FLOAT_PROP(CurvetoCubicAbs, X2, 2) +IMPL_FLOAT_PROP(CurvetoCubicAbs, Y2, 3) +IMPL_FLOAT_PROP(CurvetoCubicAbs, X, 4) +IMPL_FLOAT_PROP(CurvetoCubicAbs, Y, 5) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(CurvetoCubicRel, X1, 0) +IMPL_FLOAT_PROP(CurvetoCubicRel, Y1, 1) +IMPL_FLOAT_PROP(CurvetoCubicRel, X2, 2) +IMPL_FLOAT_PROP(CurvetoCubicRel, Y2, 3) +IMPL_FLOAT_PROP(CurvetoCubicRel, X, 4) +IMPL_FLOAT_PROP(CurvetoCubicRel, Y, 5) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(CurvetoQuadraticAbs, X1, 0) +IMPL_FLOAT_PROP(CurvetoQuadraticAbs, Y1, 1) +IMPL_FLOAT_PROP(CurvetoQuadraticAbs, X, 2) +IMPL_FLOAT_PROP(CurvetoQuadraticAbs, Y, 3) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(CurvetoQuadraticRel, X1, 0) +IMPL_FLOAT_PROP(CurvetoQuadraticRel, Y1, 1) +IMPL_FLOAT_PROP(CurvetoQuadraticRel, X, 2) +IMPL_FLOAT_PROP(CurvetoQuadraticRel, Y, 3) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(ArcAbs, R1, 0) +IMPL_FLOAT_PROP(ArcAbs, R2, 1) +IMPL_FLOAT_PROP(ArcAbs, Angle, 2) +IMPL_BOOL_PROP(ArcAbs, LargeArcFlag, 3) +IMPL_BOOL_PROP(ArcAbs, SweepFlag, 4) +IMPL_FLOAT_PROP(ArcAbs, X, 5) +IMPL_FLOAT_PROP(ArcAbs, Y, 6) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(ArcRel, R1, 0) +IMPL_FLOAT_PROP(ArcRel, R2, 1) +IMPL_FLOAT_PROP(ArcRel, Angle, 2) +IMPL_BOOL_PROP(ArcRel, LargeArcFlag, 3) +IMPL_BOOL_PROP(ArcRel, SweepFlag, 4) +IMPL_FLOAT_PROP(ArcRel, X, 5) +IMPL_FLOAT_PROP(ArcRel, Y, 6) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(LinetoHorizontalAbs, X, 0) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(LinetoHorizontalRel, X, 0) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(LinetoVerticalAbs, Y, 0) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(LinetoVerticalRel, Y, 0) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, X2, 0) +IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, Y2, 1) +IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, X, 2) +IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, Y, 3) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, X2, 0) +IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, Y2, 1) +IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, X, 2) +IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, Y, 3) + + +//////////////////////////////////////////////////////////////////////// + +IMPL_FLOAT_PROP(CurvetoQuadraticSmoothAbs, X, 0) +IMPL_FLOAT_PROP(CurvetoQuadraticSmoothAbs, Y, 1) + + +//////////////////////////////////////////////////////////////////////// + + +IMPL_FLOAT_PROP(CurvetoQuadraticSmoothRel, X, 0) +IMPL_FLOAT_PROP(CurvetoQuadraticSmoothRel, Y, 1) + + + +// This must come after DOMSVGPathSegClosePath et. al. have been declared. +/* static */ DOMSVGPathSeg* +DOMSVGPathSeg::CreateFor(DOMSVGPathSegList *aList, + uint32_t aListIndex, + bool aIsAnimValItem) +{ + uint32_t dataIndex = aList->mItems[aListIndex].mInternalDataIndex; + float *data = &aList->InternalList().mData[dataIndex]; + uint32_t type = SVGPathSegUtils::DecodeType(data[0]); + + switch (type) + { + case PATHSEG_CLOSEPATH: + return new DOMSVGPathSegClosePath(aList, aListIndex, aIsAnimValItem); + case PATHSEG_MOVETO_ABS: + return new DOMSVGPathSegMovetoAbs(aList, aListIndex, aIsAnimValItem); + case PATHSEG_MOVETO_REL: + return new DOMSVGPathSegMovetoRel(aList, aListIndex, aIsAnimValItem); + case PATHSEG_LINETO_ABS: + return new DOMSVGPathSegLinetoAbs(aList, aListIndex, aIsAnimValItem); + case PATHSEG_LINETO_REL: + return new DOMSVGPathSegLinetoRel(aList, aListIndex, aIsAnimValItem); + case PATHSEG_CURVETO_CUBIC_ABS: + return new DOMSVGPathSegCurvetoCubicAbs(aList, aListIndex, aIsAnimValItem); + case PATHSEG_CURVETO_CUBIC_REL: + return new DOMSVGPathSegCurvetoCubicRel(aList, aListIndex, aIsAnimValItem); + case PATHSEG_CURVETO_QUADRATIC_ABS: + return new DOMSVGPathSegCurvetoQuadraticAbs(aList, aListIndex, aIsAnimValItem); + case PATHSEG_CURVETO_QUADRATIC_REL: + return new DOMSVGPathSegCurvetoQuadraticRel(aList, aListIndex, aIsAnimValItem); + case PATHSEG_ARC_ABS: + return new DOMSVGPathSegArcAbs(aList, aListIndex, aIsAnimValItem); + case PATHSEG_ARC_REL: + return new DOMSVGPathSegArcRel(aList, aListIndex, aIsAnimValItem); + case PATHSEG_LINETO_HORIZONTAL_ABS: + return new DOMSVGPathSegLinetoHorizontalAbs(aList, aListIndex, aIsAnimValItem); + case PATHSEG_LINETO_HORIZONTAL_REL: + return new DOMSVGPathSegLinetoHorizontalRel(aList, aListIndex, aIsAnimValItem); + case PATHSEG_LINETO_VERTICAL_ABS: + return new DOMSVGPathSegLinetoVerticalAbs(aList, aListIndex, aIsAnimValItem); + case PATHSEG_LINETO_VERTICAL_REL: + return new DOMSVGPathSegLinetoVerticalRel(aList, aListIndex, aIsAnimValItem); + case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: + return new DOMSVGPathSegCurvetoCubicSmoothAbs(aList, aListIndex, aIsAnimValItem); + case PATHSEG_CURVETO_CUBIC_SMOOTH_REL: + return new DOMSVGPathSegCurvetoCubicSmoothRel(aList, aListIndex, aIsAnimValItem); + case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: + return new DOMSVGPathSegCurvetoQuadraticSmoothAbs(aList, aListIndex, aIsAnimValItem); + case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: + return new DOMSVGPathSegCurvetoQuadraticSmoothRel(aList, aListIndex, aIsAnimValItem); + default: + NS_NOTREACHED("Invalid path segment type"); + return nullptr; + } +} + +} // namespace mozilla |