Bug 1745149 - Remove SVGPathSeg APIs and related code. r=longsonr,boris,webidl,devtools-reviewers,smaug,nchevobbe

These were unshipped a long time ago...

Differential Revision: https://phabricator.services.mozilla.com/D214278
This commit is contained in:
Emilio Cobos Álvarez 2024-06-20 09:44:00 +00:00
Родитель 2c6909e66f
Коммит 597601a294
30 изменённых файлов: 52 добавлений и 2588 удалений

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

@ -1,6 +1,5 @@
[DEFAULT]
prefs = [
"dom.svg.pathSeg.enabled=true",
"layout.css.properties-and-values.enabled=true"
]
tags = "devtools"

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

@ -779,65 +779,13 @@ function assertPathSegments(pathEl, hasClosePath, expectedValues) {
);
}
function isExpectedPath(pathEl, hasClosePath, expectedValues) {
const pathSegList = pathEl.pathSegList;
if (!pathSegList) {
return false;
}
if (
!expectedValues.every(value =>
isPassingThrough(pathSegList, value.x, value.y)
)
) {
return false;
}
if (hasClosePath) {
const closePathSeg = pathSegList.getItem(pathSegList.numberOfItems - 1);
if (closePathSeg.pathSegType !== closePathSeg.PATHSEG_CLOSEPATH) {
return false;
}
}
function isExpectedPath(_pathEl, _hasClosePath, _expectedValues) {
// FIXME(bug 1903594): Probably re-implement with some other API, or manually parse it:
// * https://github.com/progers/pathseg
// * https://www.w3.org/TR/svg-paths/#InterfaceSVGPathData
return true;
}
/**
* Check whether the given vertex is passing throug on the path.
*
* @param {pathSegList} pathSegList - pathSegList of <path> element.
* @param {float} x - x of vertex.
* @param {float} y - y of vertex.
* @return {boolean} true: passing through, false: no on the path.
*/
function isPassingThrough(pathSegList, x, y) {
let previousPathSeg = pathSegList.getItem(0);
for (let i = 0; i < pathSegList.numberOfItems; i++) {
const pathSeg = pathSegList.getItem(i);
if (pathSeg.x === undefined) {
continue;
}
const currentX = parseFloat(pathSeg.x.toFixed(3));
const currentY = parseFloat(pathSeg.y.toFixed(3));
if (currentX === x && currentY === y) {
return true;
}
const previousX = parseFloat(previousPathSeg.x.toFixed(3));
const previousY = parseFloat(previousPathSeg.y.toFixed(3));
if (
previousX <= x &&
x <= currentX &&
Math.min(previousY, currentY) <= y &&
y <= Math.max(previousY, currentY)
) {
return true;
}
previousPathSeg = pathSeg;
}
return false;
}
/**
* Return animation item element by the index.
*

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

@ -816,111 +816,6 @@ DOMInterfaces = {
'headerFile': 'DOMSVGNumberList.h'
},
'SVGPathSeg': {
'nativeType': 'mozilla::dom::DOMSVGPathSeg',
'headerFile': 'DOMSVGPathSeg.h',
},
'SVGPathSegClosePath': {
'nativeType': 'mozilla::dom::DOMSVGPathSegClosePath',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegMovetoAbs': {
'nativeType': 'mozilla::dom::DOMSVGPathSegMovetoAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegMovetoRel': {
'nativeType': 'mozilla::dom::DOMSVGPathSegMovetoRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoAbs': {
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoRel': {
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoCubicAbs': {
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoCubicAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoCubicRel': {
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoCubicRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoQuadraticAbs': {
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoQuadraticAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoQuadraticRel': {
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoQuadraticRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegArcAbs': {
'nativeType': 'mozilla::dom::DOMSVGPathSegArcAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegArcRel': {
'nativeType': 'mozilla::dom::DOMSVGPathSegArcRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoHorizontalAbs': {
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoHorizontalAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoHorizontalRel': {
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoHorizontalRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoVerticalAbs': {
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoVerticalAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoVerticalRel': {
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoVerticalRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoCubicSmoothAbs': {
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoCubicSmoothAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoCubicSmoothRel': {
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoCubicSmoothRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoQuadraticSmoothAbs': {
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoQuadraticSmoothAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoQuadraticSmoothRel': {
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoQuadraticSmoothRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegList': {
'nativeType': 'mozilla::dom::DOMSVGPathSegList',
'headerFile': 'DOMSVGPathSegList.h'
},
'SVGPoint': {
'nativeType': 'mozilla::dom::DOMSVGPoint',
'headerFile': 'DOMSVGPoint.h'

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

@ -1,314 +0,0 @@
/* -*- 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 "SVGElement.h"
#include "mozAutoDocUpdate.h"
#include "nsError.h"
// See the architecture comment in DOMSVGPathSegList.h.
namespace mozilla::dom {
using namespace dom::SVGPathSeg_Binding;
// 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_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPathSeg)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END
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; \
} \
AutoChangePathSegListNotifier 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:
MOZ_ASSERT_UNREACHABLE("Invalid path segment type");
return nullptr;
}
}
} // namespace mozilla::dom

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

@ -1,639 +0,0 @@
/* -*- 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/. */
#ifndef DOM_SVG_DOMSVGPATHSEG_H_
#define DOM_SVG_DOMSVGPATHSEG_H_
#include "DOMSVGPathSegList.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "SVGPathSegUtils.h"
#include "mozilla/dom/SVGPathSegBinding.h"
#define MOZ_SVG_LIST_INDEX_BIT_COUNT 31
namespace mozilla::dom {
class SVGElement;
#define CHECK_ARG_COUNT_IN_SYNC(segType) \
MOZ_ASSERT( \
ArrayLength(mArgs) == \
SVGPathSegUtils::ArgCountForType(uint32_t(segType)) || \
uint32_t(segType) == dom::SVGPathSeg_Binding::PATHSEG_CLOSEPATH, \
"Arg count/array size out of sync")
#define IMPL_SVGPATHSEG_SUBCLASS_COMMON(segName, segType) \
explicit DOMSVGPathSeg##segName(const float* aArgs) : DOMSVGPathSeg() { \
CHECK_ARG_COUNT_IN_SYNC(segType); \
memcpy( \
mArgs, aArgs, \
SVGPathSegUtils::ArgCountForType(uint32_t(segType)) * sizeof(float)); \
} \
DOMSVGPathSeg##segName(DOMSVGPathSegList* aList, uint32_t aListIndex, \
bool aIsAnimValItem) \
: DOMSVGPathSeg(aList, aListIndex, aIsAnimValItem) { \
CHECK_ARG_COUNT_IN_SYNC(segType); \
} \
/* From DOMSVGPathSeg: */ \
uint32_t Type() const override { return segType; } \
DOMSVGPathSeg* Clone() override { \
/* InternalItem() + 1, because we're skipping the encoded seg type */ \
float* args = IsInList() ? InternalItem() + 1 : mArgs; \
return new DOMSVGPathSeg##segName(args); \
} \
float* PtrToMemberArgs() override { return mArgs; } \
\
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) \
override { \
return dom::SVGPathSeg##segName##_Binding::Wrap(aCx, this, aGivenProto); \
}
/**
* Class DOMSVGPathSeg
*
* This class is the base class of the classes that create the DOM objects that
* wrap the internal path segments that are encoded in an SVGPathData. Its
* sub-classes are also used to create the objects returned by
* SVGPathElement.createSVGPathSegXxx().
*
* See the architecture comment in DOMSVGPathSegList.h for an overview of the
* important points regarding these DOM wrapper structures.
*
* See the architecture comment in DOMSVGLength.h (yes, LENGTH) for an overview
* of the important points regarding how this specific class works.
*
* The main differences between this class and DOMSVGLength is that we have
* sub-classes (it does not), and the "internal counterpart" that we provide a
* DOM wrapper for is a list of floats, not an instance of an internal class.
*/
class DOMSVGPathSeg : public nsWrapperCache {
template <class T>
friend class AutoChangePathSegListNotifier;
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMSVGPathSeg)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMSVGPathSeg)
/**
* Unlike the other list classes, we hide our ctor (because no one should be
* creating instances of this class directly). This factory method in exposed
* instead to take care of creating instances of the correct sub-class.
*/
static DOMSVGPathSeg* CreateFor(DOMSVGPathSegList* aList, uint32_t aListIndex,
bool aIsAnimValItem);
/**
* Create an unowned copy of this object. The caller is responsible for the
* first AddRef()!
*/
virtual DOMSVGPathSeg* Clone() = 0;
bool IsInList() const { return !!mList; }
/**
* Returns true if our attribute is animating (in which case our animVal is
* not simply a mirror of our baseVal).
*/
bool AttrIsAnimating() const { return mList && mList->AttrIsAnimating(); }
/**
* In future, if this class is used for non-list segments, this will be
* different to IsInList().
*/
bool HasOwner() const { return !!mList; }
/**
* This method is called to notify this DOM object that it is being inserted
* into a list, and give it the information it needs as a result.
*
* This object MUST NOT already belong to a list when this method is called.
* That's not to say that script can't move these DOM objects between
* lists - it can - it's just that the logic to handle that (and send out
* the necessary notifications) is located elsewhere (in DOMSVGPathSegList).)
*/
void InsertingIntoList(DOMSVGPathSegList* aList, uint32_t aListIndex,
bool aIsAnimValItem);
static uint32_t MaxListIndex() {
return (1U << MOZ_SVG_LIST_INDEX_BIT_COUNT) - 1;
}
/// This method is called to notify this object that its list index changed.
void UpdateListIndex(uint32_t aListIndex) { mListIndex = aListIndex; }
/**
* This method is called to notify this DOM object that it is about to be
* removed from its current DOM list so that it can first make a copy of its
* internal counterpart's values. (If it didn't do this, then it would
* "lose" its value on being removed.)
*/
void RemovingFromList();
/**
* This method converts the segment to a string of floats as found in
* SVGPathData (i.e. the first float contains the type of the segment,
* encoded into a float, followed by its arguments in the same order as they
* are given in the <path> element's 'd' attribute).
*/
void ToSVGPathSegEncodedData(float* aRaw);
/**
* The type of this path segment.
*/
virtual uint32_t Type() const = 0;
// WebIDL
DOMSVGPathSegList* GetParentObject() { return mList; }
uint16_t PathSegType() const { return Type(); }
void GetPathSegTypeAsLetter(nsAString& aPathSegTypeAsLetter) {
aPathSegTypeAsLetter = SVGPathSegUtils::GetPathSegTypeAsLetter(Type());
}
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override = 0;
protected:
/**
* Generic ctor for DOMSVGPathSeg objects that are created for an attribute.
*/
DOMSVGPathSeg(DOMSVGPathSegList* aList, uint32_t aListIndex,
bool aIsAnimValItem);
/**
* Ctor for creating the objects returned by
* SVGPathElement.createSVGPathSegXxx(), which do not initially belong to an
* attribute.
*/
DOMSVGPathSeg();
virtual ~DOMSVGPathSeg() {
// Our mList's weak ref to us must be nulled out when we die. If GC has
// unlinked us using the cycle collector code, then that has already
// happened, and mList is null.
if (mList) {
mList->ItemAt(mListIndex) = nullptr;
}
}
dom::SVGElement* Element() { return mList->Element(); }
/**
* Get a reference to the internal SVGPathSeg list item that this DOM wrapper
* object currently wraps.
*
* To simplify the code we just have this one method for obtaining both
* baseVal and animVal internal items. This means that animVal items don't
* get const protection, but then our setter methods guard against changing
* animVal items.
*/
float* InternalItem();
virtual float* PtrToMemberArgs() = 0;
#ifdef DEBUG
bool IndexIsValid();
#endif
RefPtr<DOMSVGPathSegList> mList;
// Bounds for the following are checked in the ctor, so be sure to update
// that if you change the capacity of any of the following.
uint32_t mListIndex : MOZ_SVG_LIST_INDEX_BIT_COUNT;
uint32_t mIsAnimValItem : 1; // uint32_t because MSVC won't pack otherwise
};
class DOMSVGPathSegClosePath : public DOMSVGPathSeg {
public:
DOMSVGPathSegClosePath() {}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(ClosePath,
dom::SVGPathSeg_Binding::PATHSEG_CLOSEPATH)
protected:
// To allow IMPL_SVGPATHSEG_SUBCLASS_COMMON above to compile we need an
// mArgs, but since C++ doesn't allow zero-sized arrays we need to give it
// one (unused) element.
float mArgs[1];
};
class DOMSVGPathSegMovetoAbs : public DOMSVGPathSeg {
public:
DOMSVGPathSegMovetoAbs(float x, float y) {
mArgs[0] = x;
mArgs[1] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(MovetoAbs,
dom::SVGPathSeg_Binding::PATHSEG_MOVETO_ABS)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
protected:
float mArgs[2];
};
class DOMSVGPathSegMovetoRel : public DOMSVGPathSeg {
public:
DOMSVGPathSegMovetoRel(float x, float y) {
mArgs[0] = x;
mArgs[1] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(MovetoRel,
dom::SVGPathSeg_Binding::PATHSEG_MOVETO_REL)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
protected:
float mArgs[2];
};
class DOMSVGPathSegLinetoAbs : public DOMSVGPathSeg {
public:
DOMSVGPathSegLinetoAbs(float x, float y) {
mArgs[0] = x;
mArgs[1] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(LinetoAbs,
dom::SVGPathSeg_Binding::PATHSEG_LINETO_ABS)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
protected:
float mArgs[2];
};
class DOMSVGPathSegLinetoRel : public DOMSVGPathSeg {
public:
DOMSVGPathSegLinetoRel(float x, float y) {
mArgs[0] = x;
mArgs[1] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(LinetoRel,
dom::SVGPathSeg_Binding::PATHSEG_LINETO_REL)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
protected:
float mArgs[2];
};
class DOMSVGPathSegCurvetoCubicAbs : public DOMSVGPathSeg {
public:
DOMSVGPathSegCurvetoCubicAbs(float x1, float y1, float x2, float y2, float x,
float y) {
mArgs[0] = x1;
mArgs[1] = y1;
mArgs[2] = x2;
mArgs[3] = y2;
mArgs[4] = x;
mArgs[5] = y;
}
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
float X1();
void SetX1(float aX1, ErrorResult& rv);
float Y1();
void SetY1(float aY1, ErrorResult& rv);
float X2();
void SetX2(float aX2, ErrorResult& rv);
float Y2();
void SetY2(float aY2, ErrorResult& rv);
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
CurvetoCubicAbs, dom::SVGPathSeg_Binding::PATHSEG_CURVETO_CUBIC_ABS)
protected:
float mArgs[6];
};
class DOMSVGPathSegCurvetoCubicRel : public DOMSVGPathSeg {
public:
DOMSVGPathSegCurvetoCubicRel(float x1, float y1, float x2, float y2, float x,
float y) {
mArgs[0] = x1;
mArgs[1] = y1;
mArgs[2] = x2;
mArgs[3] = y2;
mArgs[4] = x;
mArgs[5] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
CurvetoCubicRel, dom::SVGPathSeg_Binding::PATHSEG_CURVETO_CUBIC_REL)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
float X1();
void SetX1(float aX1, ErrorResult& rv);
float Y1();
void SetY1(float aY1, ErrorResult& rv);
float X2();
void SetX2(float aX2, ErrorResult& rv);
float Y2();
void SetY2(float aY2, ErrorResult& rv);
protected:
float mArgs[6];
};
class DOMSVGPathSegCurvetoQuadraticAbs : public DOMSVGPathSeg {
public:
DOMSVGPathSegCurvetoQuadraticAbs(float x1, float y1, float x, float y) {
mArgs[0] = x1;
mArgs[1] = y1;
mArgs[2] = x;
mArgs[3] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
CurvetoQuadraticAbs,
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_ABS)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
float X1();
void SetX1(float aX1, ErrorResult& rv);
float Y1();
void SetY1(float aY1, ErrorResult& rv);
protected:
float mArgs[4];
};
class DOMSVGPathSegCurvetoQuadraticRel : public DOMSVGPathSeg {
public:
DOMSVGPathSegCurvetoQuadraticRel(float x1, float y1, float x, float y) {
mArgs[0] = x1;
mArgs[1] = y1;
mArgs[2] = x;
mArgs[3] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
CurvetoQuadraticRel,
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_REL)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
float X1();
void SetX1(float aX1, ErrorResult& rv);
float Y1();
void SetY1(float aY1, ErrorResult& rv);
protected:
float mArgs[4];
};
class DOMSVGPathSegArcAbs : public DOMSVGPathSeg {
public:
DOMSVGPathSegArcAbs(float r1, float r2, float angle, bool largeArcFlag,
bool sweepFlag, float x, float y) {
mArgs[0] = r1;
mArgs[1] = r2;
mArgs[2] = angle;
mArgs[3] = largeArcFlag;
mArgs[4] = sweepFlag;
mArgs[5] = x;
mArgs[6] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(ArcAbs,
dom::SVGPathSeg_Binding::PATHSEG_ARC_ABS)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
float R1();
void SetR1(float aR1, ErrorResult& rv);
float R2();
void SetR2(float aR2, ErrorResult& rv);
float Angle();
void SetAngle(float aAngle, ErrorResult& rv);
bool LargeArcFlag();
void SetLargeArcFlag(bool aLargeArcFlag, ErrorResult& rv);
bool SweepFlag();
void SetSweepFlag(bool aSweepFlag, ErrorResult& rv);
protected:
float mArgs[7];
};
class DOMSVGPathSegArcRel : public DOMSVGPathSeg {
public:
DOMSVGPathSegArcRel(float r1, float r2, float angle, bool largeArcFlag,
bool sweepFlag, float x, float y) {
mArgs[0] = r1;
mArgs[1] = r2;
mArgs[2] = angle;
mArgs[3] = largeArcFlag;
mArgs[4] = sweepFlag;
mArgs[5] = x;
mArgs[6] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(ArcRel,
dom::SVGPathSeg_Binding::PATHSEG_ARC_REL)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
float R1();
void SetR1(float aR1, ErrorResult& rv);
float R2();
void SetR2(float aR2, ErrorResult& rv);
float Angle();
void SetAngle(float aAngle, ErrorResult& rv);
bool LargeArcFlag();
void SetLargeArcFlag(bool aLargeArcFlag, ErrorResult& rv);
bool SweepFlag();
void SetSweepFlag(bool aSweepFlag, ErrorResult& rv);
protected:
float mArgs[7];
};
class DOMSVGPathSegLinetoHorizontalAbs : public DOMSVGPathSeg {
public:
explicit DOMSVGPathSegLinetoHorizontalAbs(float x) { mArgs[0] = x; }
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
LinetoHorizontalAbs,
dom::SVGPathSeg_Binding::PATHSEG_LINETO_HORIZONTAL_ABS)
float X();
void SetX(float aX, ErrorResult& rv);
protected:
float mArgs[1];
};
class DOMSVGPathSegLinetoHorizontalRel : public DOMSVGPathSeg {
public:
explicit DOMSVGPathSegLinetoHorizontalRel(float x) { mArgs[0] = x; }
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
LinetoHorizontalRel,
dom::SVGPathSeg_Binding::PATHSEG_LINETO_HORIZONTAL_REL)
float X();
void SetX(float aX, ErrorResult& rv);
protected:
float mArgs[1];
};
class DOMSVGPathSegLinetoVerticalAbs : public DOMSVGPathSeg {
public:
explicit DOMSVGPathSegLinetoVerticalAbs(float y) { mArgs[0] = y; }
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
LinetoVerticalAbs, dom::SVGPathSeg_Binding::PATHSEG_LINETO_VERTICAL_ABS)
float Y();
void SetY(float aY, ErrorResult& rv);
protected:
float mArgs[1];
};
class DOMSVGPathSegLinetoVerticalRel : public DOMSVGPathSeg {
public:
explicit DOMSVGPathSegLinetoVerticalRel(float y) { mArgs[0] = y; }
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
LinetoVerticalRel, dom::SVGPathSeg_Binding::PATHSEG_LINETO_VERTICAL_REL)
float Y();
void SetY(float aY, ErrorResult& rv);
protected:
float mArgs[1];
};
class DOMSVGPathSegCurvetoCubicSmoothAbs : public DOMSVGPathSeg {
public:
DOMSVGPathSegCurvetoCubicSmoothAbs(float x2, float y2, float x, float y) {
mArgs[0] = x2;
mArgs[1] = y2;
mArgs[2] = x;
mArgs[3] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
CurvetoCubicSmoothAbs,
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
float X2();
void SetX2(float aX2, ErrorResult& rv);
float Y2();
void SetY2(float aY2, ErrorResult& rv);
protected:
float mArgs[4];
};
class DOMSVGPathSegCurvetoCubicSmoothRel : public DOMSVGPathSeg {
public:
DOMSVGPathSegCurvetoCubicSmoothRel(float x2, float y2, float x, float y) {
mArgs[0] = x2;
mArgs[1] = y2;
mArgs[2] = x;
mArgs[3] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
CurvetoCubicSmoothRel,
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_CUBIC_SMOOTH_REL)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
float X2();
void SetX2(float aX2, ErrorResult& rv);
float Y2();
void SetY2(float aY2, ErrorResult& rv);
protected:
float mArgs[4];
};
class DOMSVGPathSegCurvetoQuadraticSmoothAbs : public DOMSVGPathSeg {
public:
DOMSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y) {
mArgs[0] = x;
mArgs[1] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
CurvetoQuadraticSmoothAbs,
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
protected:
float mArgs[2];
};
class DOMSVGPathSegCurvetoQuadraticSmoothRel : public DOMSVGPathSeg {
public:
DOMSVGPathSegCurvetoQuadraticSmoothRel(float x, float y) {
mArgs[0] = x;
mArgs[1] = y;
}
IMPL_SVGPATHSEG_SUBCLASS_COMMON(
CurvetoQuadraticSmoothRel,
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL)
float X();
void SetX(float aX, ErrorResult& rv);
float Y();
void SetY(float aY, ErrorResult& rv);
protected:
float mArgs[2];
};
} // namespace mozilla::dom
#undef MOZ_SVG_LIST_INDEX_BIT_COUNT
#endif // DOM_SVG_DOMSVGPATHSEG_H_

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

@ -1,537 +0,0 @@
/* -*- 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 "DOMSVGPathSegList.h"
#include "DOMSVGPathSeg.h"
#include "nsError.h"
#include "SVGAnimatedPathSegList.h"
#include "SVGAttrTearoffTable.h"
#include "SVGPathSegUtils.h"
#include "mozilla/dom/SVGElement.h"
#include "mozilla/dom/SVGPathElement.h"
#include "mozilla/dom/SVGPathSegListBinding.h"
#include "mozilla/RefPtr.h"
// See the comment in this file's header.
namespace mozilla::dom {
static inline SVGAttrTearoffTable<void, DOMSVGPathSegList>&
SVGPathSegListTearoffTable() {
static SVGAttrTearoffTable<void, DOMSVGPathSegList>
sSVGPathSegListTearoffTable;
return sSVGPathSegListTearoffTable;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGPathSegList)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPathSegList)
// No unlinking of mElement, we'd need to null out the value pointer (the
// object it points to is held by the element) and null-check it everywhere.
tmp->RemoveFromTearoffTable();
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPathSegList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPathSegList)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGPathSegList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGPathSegList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGPathSegList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
/* static */
already_AddRefed<DOMSVGPathSegList> DOMSVGPathSegList::GetDOMWrapper(
void* aList, SVGPathElement* aElement) {
RefPtr<DOMSVGPathSegList> wrapper =
SVGPathSegListTearoffTable().GetTearoff(aList);
if (!wrapper) {
wrapper = new DOMSVGPathSegList(
aElement, aElement->GetAnimPathSegList()->GetAnimValKey() == aList);
SVGPathSegListTearoffTable().AddTearoff(aList, wrapper);
}
return wrapper.forget();
}
/* static */
DOMSVGPathSegList* DOMSVGPathSegList::GetDOMWrapperIfExists(void* aList) {
return SVGPathSegListTearoffTable().GetTearoff(aList);
}
void DOMSVGPathSegList::RemoveFromTearoffTable() {
// There are now no longer any references to us held by script or list items.
// Note we must use GetAnimValKey/GetBaseValKey here, NOT InternalList()!
void* key = mIsAnimValList ? InternalAList().GetAnimValKey()
: InternalAList().GetBaseValKey();
SVGPathSegListTearoffTable().RemoveTearoff(key);
}
DOMSVGPathSegList::~DOMSVGPathSegList() { RemoveFromTearoffTable(); }
JSObject* DOMSVGPathSegList::WrapObject(JSContext* cx,
JS::Handle<JSObject*> aGivenProto) {
return mozilla::dom::SVGPathSegList_Binding::Wrap(cx, this, aGivenProto);
}
void DOMSVGPathSegList::InternalListWillChangeTo(const SVGPathData& aNewValue) {
// When the number of items in our internal counterpart changes, we MUST stay
// in sync. Everything in the scary comment in
// DOMSVGLengthList::InternalBaseValListWillChangeTo applies here just as
// much, but we have the additional issue that failing to stay in sync would
// mean that - assuming we aren't reading bad memory - we would likely end up
// decoding command types from argument floats when looking in our
// SVGPathData's data array! Either way, we'll likely then go down
// MOZ_ASSERT_UNREACHABLE code paths, or end up reading/setting more bad
// memory!!
// The only time that our other DOM list type implementations remove items is
// if those items become surplus items due to an attribute change or SMIL
// animation sample shortening the list. In general though, they try to keep
// their existing DOM items, even when things change. To be consistent, we'd
// really like to do the same thing. However, because different types of path
// segment correspond to different DOMSVGPathSeg subclasses, the type of
// items in our list are generally not the same, which makes this harder for
// us. We have to remove DOM segments if their type is not the same as the
// type of the new internal segment at their index.
//
// We also need to sync up mInternalDataIndex, but since we need to loop over
// all the items in the new list checking types anyway, that's almost
// insignificant in terms of overhead.
//
// Note that this method is called on every single SMIL animation resample
// and we have no way to short circuit the overhead since we don't have a
// way to tell if the call is due to a new animation, or a resample of an
// existing animation (when the number and type of items would be the same).
// (Note that a new animation could start overriding an existing animation at
// any time, so checking IsAnimating() wouldn't work.) Because we get called
// on every sample, it would not be acceptable alternative to throw away all
// our items and let them be recreated lazily, since that would break what
// script sees!
uint32_t length = mItems.Length();
uint32_t index = 0;
uint32_t dataLength = aNewValue.mData.Length();
uint32_t dataIndex = 0; // index into aNewValue's raw data array
uint32_t newSegType;
RefPtr<DOMSVGPathSegList> kungFuDeathGrip;
if (length) {
// RemovingFromList() might clear last reference to |this|.
// Retain a temporary reference to keep from dying before returning.
//
// NOTE: For path-seg lists (unlike other list types), we have to do this
// *whenever our list is nonempty* (even if we're growing in length).
// That's because the path-seg-type of any segment could differ between old
// list vs. new list, which will make us destroy & recreate that segment,
// which could remove the last reference to us.
//
// (We explicitly *don't* want to create a kungFuDeathGrip in the length=0
// case, though, because we do hit this code inside our constructor before
// any other owning references have been added, and at that point, the
// deathgrip-removal would make us die before we exit our constructor.)
kungFuDeathGrip = this;
}
while (index < length && dataIndex < dataLength) {
newSegType = SVGPathSegUtils::DecodeType(aNewValue.mData[dataIndex]);
if (ItemAt(index) && ItemAt(index)->Type() != newSegType) {
ItemAt(index)->RemovingFromList();
ItemAt(index) = nullptr;
}
// Only after the RemovingFromList() can we touch mInternalDataIndex!
mItems[index].mInternalDataIndex = dataIndex;
++index;
dataIndex += 1 + SVGPathSegUtils::ArgCountForType(newSegType);
}
MOZ_ASSERT((index == length && dataIndex <= dataLength) ||
(index <= length && dataIndex == dataLength),
"very bad - list corruption?");
if (index < length) {
// aNewValue has fewer items than our previous internal counterpart
uint32_t newLength = index;
// Remove excess items from the list:
for (; index < length; ++index) {
if (ItemAt(index)) {
ItemAt(index)->RemovingFromList();
ItemAt(index) = nullptr;
}
}
// Only now may we truncate mItems
mItems.TruncateLength(newLength);
} else if (dataIndex < dataLength) {
// aNewValue has more items than our previous internal counterpart
// Sync mItems:
while (dataIndex < dataLength) {
if (mItems.Length() &&
mItems.Length() - 1 > DOMSVGPathSeg::MaxListIndex()) {
// It's safe to get out of sync with our internal list as long as we
// have FEWER items than it does.
return;
}
if (!mItems.AppendElement(ItemProxy(nullptr, dataIndex), fallible)) {
// OOM
ErrorResult rv;
Clear(rv);
MOZ_ASSERT(!rv.Failed());
return;
}
dataIndex +=
1 + SVGPathSegUtils::ArgCountForType(
SVGPathSegUtils::DecodeType(aNewValue.mData[dataIndex]));
}
}
MOZ_ASSERT(dataIndex == dataLength, "Serious processing error");
MOZ_ASSERT(index == length, "Serious counting error");
}
bool DOMSVGPathSegList::AttrIsAnimating() const {
return InternalAList().IsAnimating();
}
bool DOMSVGPathSegList::AnimListMirrorsBaseList() const {
return GetDOMWrapperIfExists(InternalAList().GetAnimValKey()) &&
!AttrIsAnimating();
}
SVGPathData& DOMSVGPathSegList::InternalList() const {
SVGAnimatedPathSegList* alist = mElement->GetAnimPathSegList();
return mIsAnimValList && alist->IsAnimating() ? *alist->mAnimVal
: alist->mBaseVal;
}
SVGAnimatedPathSegList& DOMSVGPathSegList::InternalAList() const {
MOZ_ASSERT(mElement->GetAnimPathSegList(), "Internal error");
return *mElement->GetAnimPathSegList();
}
// ----------------------------------------------------------------------------
// nsIDOMSVGPathSegList implementation:
void DOMSVGPathSegList::Clear(ErrorResult& aError) {
if (IsAnimValList()) {
aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
return;
}
if (LengthNoFlush() > 0) {
AutoChangePathSegListNotifier notifier(this);
// DOM list items that are to be removed must be removed before we change
// the internal list, otherwise they wouldn't be able to copy their
// internal counterparts' values!
InternalListWillChangeTo(SVGPathData()); // clears mItems
if (!AttrIsAnimating()) {
// The anim val list is in sync with the base val list
DOMSVGPathSegList* animList =
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
if (animList) {
animList->InternalListWillChangeTo(SVGPathData()); // clears its mItems
}
}
InternalList().Clear();
}
}
already_AddRefed<DOMSVGPathSeg> DOMSVGPathSegList::Initialize(
DOMSVGPathSeg& aNewItem, ErrorResult& aError) {
if (IsAnimValList()) {
aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
return nullptr;
}
// If aNewItem is already in a list we should insert a clone of aNewItem,
// and for consistency, this should happen even if *this* is the list that
// aNewItem is currently in. Note that in the case of aNewItem being in this
// list, the Clear() call before the InsertItemBefore() call would remove it
// from this list, and so the InsertItemBefore() call would not insert a
// clone of aNewItem, it would actually insert aNewItem. To prevent that
// from happening we have to do the clone here, if necessary.
RefPtr<DOMSVGPathSeg> domItem = &aNewItem;
if (aNewItem.HasOwner()) {
domItem = aNewItem.Clone();
}
Clear(aError);
MOZ_ASSERT(!aError.Failed(), "How could this fail?");
return InsertItemBefore(*domItem, 0, aError);
}
already_AddRefed<DOMSVGPathSeg> DOMSVGPathSegList::GetItem(uint32_t index,
ErrorResult& error) {
bool found;
RefPtr<DOMSVGPathSeg> item = IndexedGetter(index, found, error);
if (!found) {
error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
}
return item.forget();
}
already_AddRefed<DOMSVGPathSeg> DOMSVGPathSegList::IndexedGetter(
uint32_t aIndex, bool& aFound, ErrorResult& aError) {
if (IsAnimValList()) {
Element()->FlushAnimations();
}
aFound = aIndex < LengthNoFlush();
if (aFound) {
return GetItemAt(aIndex);
}
return nullptr;
}
already_AddRefed<DOMSVGPathSeg> DOMSVGPathSegList::InsertItemBefore(
DOMSVGPathSeg& aNewItem, uint32_t aIndex, ErrorResult& aError) {
if (IsAnimValList()) {
aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
return nullptr;
}
uint32_t internalIndex;
if (aIndex < LengthNoFlush()) {
internalIndex = mItems[aIndex].mInternalDataIndex;
} else {
aIndex = LengthNoFlush();
internalIndex = InternalList().mData.Length();
}
if (aIndex >= DOMSVGPathSeg::MaxListIndex()) {
aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
RefPtr<DOMSVGPathSeg> domItem = &aNewItem;
if (domItem->HasOwner()) {
domItem = domItem->Clone(); // must do this before changing anything!
}
uint32_t argCount = SVGPathSegUtils::ArgCountForType(domItem->Type());
// Ensure we have enough memory so we can avoid complex error handling below:
if (!mItems.SetCapacity(mItems.Length() + 1, fallible) ||
!InternalList().mData.SetCapacity(
InternalList().mData.Length() + 1 + argCount, fallible)) {
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
if (AnimListMirrorsBaseList()) {
DOMSVGPathSegList* animVal =
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
MOZ_ASSERT(animVal, "animVal should be a valid pointer");
if (!animVal->mItems.SetCapacity(animVal->mItems.Length() + 1, fallible)) {
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
}
AutoChangePathSegListNotifier notifier(this);
// Now that we know we're inserting, keep animVal list in sync as necessary.
MaybeInsertNullInAnimValListAt(aIndex, internalIndex, argCount);
float segAsRaw[1 + NS_SVG_PATH_SEG_MAX_ARGS];
domItem->ToSVGPathSegEncodedData(segAsRaw);
MOZ_ALWAYS_TRUE(InternalList().mData.InsertElementsAt(
internalIndex, segAsRaw, 1 + argCount, fallible));
MOZ_ALWAYS_TRUE(mItems.InsertElementAt(
aIndex, ItemProxy(domItem.get(), internalIndex), fallible));
// This MUST come after the insertion into InternalList(), or else under the
// insertion into InternalList() the values read from domItem would be bad
// data from InternalList() itself!:
domItem->InsertingIntoList(this, aIndex, IsAnimValList());
UpdateListIndicesFromIndex(aIndex + 1, argCount + 1);
return domItem.forget();
}
already_AddRefed<DOMSVGPathSeg> DOMSVGPathSegList::ReplaceItem(
DOMSVGPathSeg& aNewItem, uint32_t aIndex, ErrorResult& aError) {
if (IsAnimValList()) {
aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
return nullptr;
}
if (aIndex >= LengthNoFlush()) {
aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
RefPtr<DOMSVGPathSeg> domItem = &aNewItem;
if (domItem->HasOwner()) {
domItem = domItem->Clone(); // must do this before changing anything!
}
AutoChangePathSegListNotifier notifier(this);
if (ItemAt(aIndex)) {
// Notify any existing DOM item of removal *before* modifying the lists so
// that the DOM item can copy the *old* value at its index:
ItemAt(aIndex)->RemovingFromList();
}
uint32_t internalIndex = mItems[aIndex].mInternalDataIndex;
// We use InternalList() to get oldArgCount since we may not have a DOM
// wrapper at the index being replaced.
uint32_t oldType =
SVGPathSegUtils::DecodeType(InternalList().mData[internalIndex]);
// NOTE: ArgCountForType returns a (small) unsigned value, but we're
// intentionally putting it in a signed variable, because we're going to
// subtract these values and might produce something negative.
int32_t oldArgCount = SVGPathSegUtils::ArgCountForType(oldType);
int32_t newArgCount = SVGPathSegUtils::ArgCountForType(domItem->Type());
float segAsRaw[1 + NS_SVG_PATH_SEG_MAX_ARGS];
domItem->ToSVGPathSegEncodedData(segAsRaw);
if (!InternalList().mData.ReplaceElementsAt(internalIndex, 1 + oldArgCount,
segAsRaw, 1 + newArgCount,
fallible)) {
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
ItemAt(aIndex) = domItem;
// This MUST come after the ToSVGPathSegEncodedData call, otherwise that call
// would end up reading bad data from InternalList()!
domItem->InsertingIntoList(this, aIndex, IsAnimValList());
int32_t delta = newArgCount - oldArgCount;
if (delta != 0) {
for (uint32_t i = aIndex + 1; i < LengthNoFlush(); ++i) {
mItems[i].mInternalDataIndex += delta;
}
}
return domItem.forget();
}
already_AddRefed<DOMSVGPathSeg> DOMSVGPathSegList::RemoveItem(
uint32_t aIndex, ErrorResult& aError) {
if (IsAnimValList()) {
aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
return nullptr;
}
if (aIndex >= LengthNoFlush()) {
aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
// We have to return the removed item, so get it, creating it if necessary:
RefPtr<DOMSVGPathSeg> result = GetItemAt(aIndex);
AutoChangePathSegListNotifier notifier(this);
// Notify the DOM item of removal *before* modifying the lists so that the
// DOM item can copy its *old* value:
ItemAt(aIndex)->RemovingFromList();
uint32_t internalIndex = mItems[aIndex].mInternalDataIndex;
uint32_t segType =
SVGPathSegUtils::DecodeType(InternalList().mData[internalIndex]);
// NOTE: ArgCountForType returns a (small) unsigned value, but we're
// intentionally putting it in a signed value, because we're going to
// negate it, and you can't negate an unsigned value.
int32_t argCount = SVGPathSegUtils::ArgCountForType(segType);
// Now that we know we're removing, keep animVal list in sync as necessary.
// Do this *before* touching InternalList() so the removed item can get its
// internal value.
MaybeRemoveItemFromAnimValListAt(aIndex, argCount);
InternalList().mData.RemoveElementsAt(internalIndex, 1 + argCount);
mItems.RemoveElementAt(aIndex);
UpdateListIndicesFromIndex(aIndex, -(argCount + 1));
return result.forget();
}
already_AddRefed<DOMSVGPathSeg> DOMSVGPathSegList::GetItemAt(uint32_t aIndex) {
MOZ_ASSERT(aIndex < mItems.Length());
if (!ItemAt(aIndex)) {
ItemAt(aIndex) = DOMSVGPathSeg::CreateFor(this, aIndex, IsAnimValList());
}
RefPtr<DOMSVGPathSeg> result = ItemAt(aIndex);
return result.forget();
}
void DOMSVGPathSegList::MaybeInsertNullInAnimValListAt(
uint32_t aIndex, uint32_t aInternalIndex, uint32_t aArgCountForItem) {
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
if (!AnimListMirrorsBaseList()) {
return;
}
// The anim val list is in sync with the base val list
DOMSVGPathSegList* animVal =
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
"animVal list not in sync!");
MOZ_ALWAYS_TRUE(animVal->mItems.InsertElementAt(
aIndex, ItemProxy(nullptr, aInternalIndex), fallible));
animVal->UpdateListIndicesFromIndex(aIndex + 1, 1 + aArgCountForItem);
}
void DOMSVGPathSegList::MaybeRemoveItemFromAnimValListAt(
uint32_t aIndex, int32_t aArgCountForItem) {
MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal");
if (!AnimListMirrorsBaseList()) {
return;
}
// This needs to be a strong reference; otherwise, the RemovingFromList call
// below might drop the last reference to animVal before we're done with it.
RefPtr<DOMSVGPathSegList> animVal =
GetDOMWrapperIfExists(InternalAList().GetAnimValKey());
MOZ_ASSERT(animVal, "AnimListMirrorsBaseList() promised a non-null animVal");
MOZ_ASSERT(animVal->mItems.Length() == mItems.Length(),
"animVal list not in sync!");
if (animVal->ItemAt(aIndex)) {
animVal->ItemAt(aIndex)->RemovingFromList();
}
animVal->mItems.RemoveElementAt(aIndex);
animVal->UpdateListIndicesFromIndex(aIndex, -(1 + aArgCountForItem));
}
void DOMSVGPathSegList::UpdateListIndicesFromIndex(
uint32_t aStartingIndex, int32_t aInternalDataIndexDelta) {
uint32_t length = mItems.Length();
for (uint32_t i = aStartingIndex; i < length; ++i) {
mItems[i].mInternalDataIndex += aInternalDataIndexDelta;
if (ItemAt(i)) {
ItemAt(i)->UpdateListIndex(i);
}
}
}
} // namespace mozilla::dom

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

@ -1,266 +0,0 @@
/* -*- 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/. */
#ifndef DOM_SVG_DOMSVGPATHSEGLIST_H_
#define DOM_SVG_DOMSVGPATHSEGLIST_H_
#include "mozAutoDocUpdate.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDebug.h"
#include "nsTArray.h"
#include "SVGPathData.h" // IWYU pragma: keep
#include "mozilla/Attributes.h"
#include "mozilla/RefPtr.h"
#include "mozilla/dom/SVGElement.h"
namespace mozilla {
class ErrorResult;
class SVGAnimatedPathSegList;
namespace dom {
class DOMSVGPathSeg;
class SVGPathElement;
//----------------------------------------------------------------------
// Helper class: AutoChangePathSegListNotifier
// Stack-based helper class to pair calls to WillChangePathSegList and
// DidChangePathSegList. Used by DOMSVGPathSeg and DOMSVGPathSegList.
template <class T>
class MOZ_RAII AutoChangePathSegListNotifier : public mozAutoDocUpdate {
public:
explicit AutoChangePathSegListNotifier(T* aValue)
: mozAutoDocUpdate(aValue->Element()->GetComposedDoc(), true),
mValue(aValue) {
MOZ_ASSERT(mValue, "Expecting non-null value");
mEmptyOrOldValue = mValue->Element()->WillChangePathSegList(*this);
}
~AutoChangePathSegListNotifier() {
mValue->Element()->DidChangePathSegList(mEmptyOrOldValue, *this);
if (mValue->AttrIsAnimating()) {
mValue->Element()->AnimationNeedsResample();
}
}
private:
T* const mValue;
nsAttrValue mEmptyOrOldValue;
};
/**
* Class DOMSVGPathSegList
*
* This class is used to create the DOM tearoff objects that wrap internal
* SVGPathData objects.
*
* See the architecture comment in DOMSVGAnimatedLengthList.h first (that's
* LENGTH list), then continue reading the remainder of this comment.
*
* The architecture of this class is very similar to that of DOMSVGLengthList
* except that, since there is no nsIDOMSVGAnimatedPathSegList interface
* in SVG, we have no parent DOMSVGAnimatedPathSegList (unlike DOMSVGLengthList
* which has a parent DOMSVGAnimatedLengthList class). (There is an
* SVGAnimatedPathData interface, but that is quite different to
* DOMSVGAnimatedLengthList, since it is inherited by elements rather than
* elements having members of that type.) As a consequence, much of the logic
* that would otherwise be in DOMSVGAnimatedPathSegList (and is in
* DOMSVGAnimatedLengthList) is contained in this class.
*
* This class is strongly intertwined with DOMSVGPathSeg. Our DOMSVGPathSeg
* items are friends of us and responsible for nulling out our pointers to
* them when they die.
*
* Our DOM items are created lazily on demand as and when script requests them.
*/
class DOMSVGPathSegList final : public nsISupports, public nsWrapperCache {
template <class T>
friend class AutoChangePathSegListNotifier;
friend class DOMSVGPathSeg;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGPathSegList)
JSObject* WrapObject(JSContext* cx,
JS::Handle<JSObject*> aGivenProto) override;
nsISupports* GetParentObject() { return static_cast<nsIContent*>(mElement); }
/**
* Factory method to create and return a DOMSVGPathSegList wrapper
* for a given internal SVGPathData object. The factory takes care
* of caching the object that it returns so that the same object can be
* returned for the given SVGPathData each time it is requested.
* The cached object is only removed from the cache when it is destroyed due
* to there being no more references to it or to any of its descendant
* objects. If that happens, any subsequent call requesting the DOM wrapper
* for the SVGPathData will naturally result in a new
* DOMSVGPathSegList being returned.
*
* It's unfortunate that aList is a void* instead of a typed argument. This
* is because the mBaseVal and mAnimVal members of SVGAnimatedPathSegList are
* of different types - a plain SVGPathData, and a SVGPathData*. We
* use the addresses of these members as the key for the hash table, and
* clearly SVGPathData* and a SVGPathData** are not the same type.
*/
static already_AddRefed<DOMSVGPathSegList> GetDOMWrapper(
void* aList, dom::SVGPathElement* aElement);
/**
* This method returns the DOMSVGPathSegList wrapper for an internal
* SVGPathData object if it currently has a wrapper. If it does
* not, then nullptr is returned.
*/
static DOMSVGPathSegList* GetDOMWrapperIfExists(void* aList);
/**
* This will normally be the same as InternalList().CountItems(), except if
* we've hit OOM, in which case our length will be zero.
*/
uint32_t LengthNoFlush() const {
MOZ_ASSERT(
mItems.Length() == 0 || mItems.Length() == InternalList().CountItems(),
"DOM wrapper's list length is out of sync");
return mItems.Length();
}
/**
* WATCH OUT! If you add code to call this on a baseVal wrapper, then you
* must also call it on the animVal wrapper too if necessary!! See other
* callers!
*
* Called by internal code to notify us when we need to sync the length of
* this DOM list with its internal list. This is called immediately prior to
* the length of the internal list being changed so that any DOM list items
* that need to be removed from the DOM list can first copy their values from
* their internal counterpart.
*
* The only time this method could fail is on OOM when trying to increase the
* length of the DOM list. If that happens then this method simply clears the
* list and returns. Callers just proceed as normal, and we simply accept
* that the DOM list will be empty (until successfully set to a new value).
*/
void InternalListWillChangeTo(const SVGPathData& aNewValue);
/**
* Returns true if our attribute is animating (in which case our animVal is
* not simply a mirror of our baseVal).
*/
bool AttrIsAnimating() const;
/**
* Returns true if there is an animated list mirroring the base list.
*/
bool AnimListMirrorsBaseList() const;
uint32_t NumberOfItems() const {
if (IsAnimValList()) {
Element()->FlushAnimations();
}
return LengthNoFlush();
}
void Clear(ErrorResult& aError);
already_AddRefed<DOMSVGPathSeg> Initialize(DOMSVGPathSeg& aNewItem,
ErrorResult& aError);
already_AddRefed<DOMSVGPathSeg> GetItem(uint32_t index, ErrorResult& error);
already_AddRefed<DOMSVGPathSeg> IndexedGetter(uint32_t index, bool& found,
ErrorResult& error);
already_AddRefed<DOMSVGPathSeg> InsertItemBefore(DOMSVGPathSeg& aNewItem,
uint32_t aIndex,
ErrorResult& aError);
already_AddRefed<DOMSVGPathSeg> ReplaceItem(DOMSVGPathSeg& aNewItem,
uint32_t aIndex,
ErrorResult& aError);
already_AddRefed<DOMSVGPathSeg> RemoveItem(uint32_t aIndex,
ErrorResult& aError);
already_AddRefed<DOMSVGPathSeg> AppendItem(DOMSVGPathSeg& aNewItem,
ErrorResult& aError) {
return InsertItemBefore(aNewItem, LengthNoFlush(), aError);
}
uint32_t Length() const { return NumberOfItems(); }
private:
/**
* Only our static GetDOMWrapper() factory method may create objects of our
* type.
*/
DOMSVGPathSegList(dom::SVGElement* aElement, bool aIsAnimValList)
: mElement(aElement), mIsAnimValList(aIsAnimValList) {
InternalListWillChangeTo(InternalList()); // Sync mItems
}
~DOMSVGPathSegList();
dom::SVGElement* Element() const { return mElement.get(); }
/// Used to determine if this list is the baseVal or animVal list.
bool IsAnimValList() const { return mIsAnimValList; }
/**
* Get a reference to this object's corresponding internal SVGPathData.
*
* To simplify the code we just have this one method for obtaining both
* base val and anim val internal lists. This means that anim val lists don't
* get const protection, but our setter methods guard against changing
* anim val lists.
*/
SVGPathData& InternalList() const;
SVGAnimatedPathSegList& InternalAList() const;
/// Creates an instance of the appropriate DOMSVGPathSeg sub-class for
// aIndex, if it doesn't already exist, and then returns it.
already_AddRefed<DOMSVGPathSeg> GetItemAt(uint32_t aIndex);
void MaybeInsertNullInAnimValListAt(uint32_t aIndex, uint32_t aInternalIndex,
uint32_t aArgCountForItem);
void MaybeRemoveItemFromAnimValListAt(uint32_t aIndex,
int32_t aArgCountForItem);
// Calls UpdateListIndex on all elements in |mItems| that satisfy ItemAt(),
// from |aStartingIndex| to the end of |mItems|. Also adjusts
// |mItems.mInternalDataIndex| by the requested amount.
void UpdateListIndicesFromIndex(uint32_t aStartingIndex,
int32_t aInternalDataIndexDelta);
DOMSVGPathSeg*& ItemAt(uint32_t aIndex) { return mItems[aIndex].mItem; }
void RemoveFromTearoffTable();
/**
* This struct is used in our array of mItems to provide us with somewhere to
* store the indexes into the internal SVGPathData of the internal seg data
* that our DOMSVGPathSeg items wrap (the internal segment data is or varying
* length, so we can't just use the index of our DOMSVGPathSeg items
* themselves). The reason that we have this separate struct rather than
* just storing the internal indexes in the DOMSVGPathSeg items is because we
* want to create the DOMSVGPathSeg items lazily on demand.
*/
struct ItemProxy {
ItemProxy() : mItem(nullptr), mInternalDataIndex(0) {}
ItemProxy(DOMSVGPathSeg* aItem, uint32_t aInternalDataIndex)
: mItem(aItem), mInternalDataIndex(aInternalDataIndex) {}
DOMSVGPathSeg* mItem;
uint32_t mInternalDataIndex;
};
// Weak refs to our DOMSVGPathSeg items. The items are friends and take care
// of clearing our pointer to them when they die.
FallibleTArray<ItemProxy> mItems;
// Strong ref to our element to keep it alive. We hold this not only for
// ourself, but also for our DOMSVGPathSeg items too.
RefPtr<dom::SVGElement> mElement;
bool mIsAnimValList;
};
} // namespace dom
} // namespace mozilla
#endif // DOM_SVG_DOMSVGPATHSEGLIST_H_

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

@ -8,7 +8,6 @@
#include <utility>
#include "DOMSVGPathSegList.h"
#include "SVGPathSegListSMILType.h"
#include "mozilla/SMILValue.h"
#include "mozilla/StaticPrefs_dom.h"
@ -28,57 +27,14 @@ nsresult SVGAnimatedPathSegList::SetBaseValueString(const nsAString& aValue) {
// we do want to throw any error code from setAttribute if there's a problem.
nsresult rv = newBaseValue.SetValueFromString(aValue);
// We must send these notifications *before* changing mBaseVal! Our baseVal's
// DOM wrapper list may have to remove DOM items from itself, and any removed
// DOM items need to copy their internal counterpart's values *before* we
// change them. See the comments in
// DOMSVGPathSegList::InternalListWillChangeTo().
DOMSVGPathSegList* baseValWrapper = nullptr;
DOMSVGPathSegList* animValWrapper = nullptr;
if (StaticPrefs::dom_svg_pathSeg_enabled()) {
baseValWrapper = DOMSVGPathSegList::GetDOMWrapperIfExists(GetBaseValKey());
if (baseValWrapper) {
baseValWrapper->InternalListWillChangeTo(newBaseValue);
}
if (!IsAnimating()) { // DOM anim val wraps our base val too!
animValWrapper =
DOMSVGPathSegList::GetDOMWrapperIfExists(GetAnimValKey());
if (animValWrapper) {
animValWrapper->InternalListWillChangeTo(newBaseValue);
}
}
}
// Only now may we modify mBaseVal!
// We don't need to call DidChange* here - we're only called by
// SVGElement::ParseAttribute under Element::SetAttr,
// which takes care of notifying.
mBaseVal.SwapWith(newBaseValue);
return rv;
}
void SVGAnimatedPathSegList::ClearBaseValue() {
if (StaticPrefs::dom_svg_pathSeg_enabled()) {
// We must send these notifications *before* changing mBaseVal! (See above.)
DOMSVGPathSegList* baseValWrapper =
DOMSVGPathSegList::GetDOMWrapperIfExists(GetBaseValKey());
if (baseValWrapper) {
baseValWrapper->InternalListWillChangeTo(SVGPathData());
}
if (!IsAnimating()) { // DOM anim val wraps our base val too!
DOMSVGPathSegList* animValWrapper =
DOMSVGPathSegList::GetDOMWrapperIfExists(GetAnimValKey());
if (animValWrapper) {
animValWrapper->InternalListWillChangeTo(SVGPathData());
}
}
}
mBaseVal.Clear();
// Caller notifies
}
@ -91,20 +47,8 @@ nsresult SVGAnimatedPathSegList::SetAnimValue(const SVGPathData& aNewAnimValue,
// Unfortunately it is not possible for us to reliably distinguish between
// calls to this method that are setting a new sample for an existing
// animation, and calls that are setting the first sample of an animation
// that will override an existing animation. In the case of DOMSVGPathSegList
// the InternalListWillChangeTo method is not virtually free as it is for the
// other DOM list classes, so this is a shame. We'd quite like to be able to
// skip the call if possible.
// that will override an existing animation.
if (StaticPrefs::dom_svg_pathSeg_enabled()) {
// We must send these notifications *before* changing mAnimVal! (See above.)
DOMSVGPathSegList* domWrapper =
DOMSVGPathSegList::GetDOMWrapperIfExists(GetAnimValKey());
if (domWrapper) {
domWrapper->InternalListWillChangeTo(aNewAnimValue);
}
}
if (!mAnimVal) {
mAnimVal = MakeUnique<SVGPathData>();
}
@ -119,18 +63,6 @@ nsresult SVGAnimatedPathSegList::SetAnimValue(const SVGPathData& aNewAnimValue,
}
void SVGAnimatedPathSegList::ClearAnimValue(SVGElement* aElement) {
if (StaticPrefs::dom_svg_pathSeg_enabled()) {
// We must send these notifications *before* changing mAnimVal! (See above.)
DOMSVGPathSegList* domWrapper =
DOMSVGPathSegList::GetDOMWrapperIfExists(GetAnimValKey());
if (domWrapper) {
// When all animation ends, animVal simply mirrors baseVal, which may have
// a different number of items to the last active animated value.
//
domWrapper->InternalListWillChangeTo(mBaseVal);
}
}
mAnimVal = nullptr;
aElement->DidAnimatePathSegList();
}

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

@ -22,7 +22,6 @@
#include "SVGPathSegUtils.h"
#include <algorithm>
using namespace mozilla::dom::SVGPathSeg_Binding;
using namespace mozilla::gfx;
namespace mozilla {

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

@ -12,7 +12,6 @@
#include "SVGPathData.h"
#include "SVGPathSegUtils.h"
using namespace mozilla::dom::SVGPathSeg_Binding;
using namespace mozilla::gfx;
namespace mozilla {

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

@ -8,8 +8,6 @@
#include <algorithm>
#include "DOMSVGPathSeg.h"
#include "DOMSVGPathSegList.h"
#include "SVGGeometryProperty.h"
#include "gfx2DGlue.h"
#include "gfxPlatform.h"
@ -21,7 +19,7 @@
#include "mozilla/dom/SVGPathElementBinding.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticPrefs_layout.h"
#include "SVGPathSegUtils.h"
#include "mozilla/SVGContentUtils.h"
NS_IMPL_NS_NEW_SVG_ELEMENT(Path)
@ -56,152 +54,6 @@ void SVGPathElement::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGPathElement)
uint32_t SVGPathElement::GetPathSegAtLength(float distance) {
uint32_t seg = 0;
auto callback = [&](const ComputedStyle* s) {
const nsStyleSVGReset* styleSVGReset = s->StyleSVGReset();
if (styleSVGReset->mD.IsPath()) {
seg = SVGPathData::GetPathSegAtLength(
styleSVGReset->mD.AsPath()._0.AsSpan(), distance);
}
};
FlushStyleIfNeeded();
if (SVGGeometryProperty::DoForComputedStyle(this, callback)) {
return seg;
}
return mD.GetAnimValue().GetPathSegAtLength(distance);
}
already_AddRefed<DOMSVGPathSegClosePath>
SVGPathElement::CreateSVGPathSegClosePath() {
return do_AddRef(new DOMSVGPathSegClosePath());
}
already_AddRefed<DOMSVGPathSegMovetoAbs>
SVGPathElement::CreateSVGPathSegMovetoAbs(float x, float y) {
return do_AddRef(new DOMSVGPathSegMovetoAbs(x, y));
}
already_AddRefed<DOMSVGPathSegMovetoRel>
SVGPathElement::CreateSVGPathSegMovetoRel(float x, float y) {
return do_AddRef(new DOMSVGPathSegMovetoRel(x, y));
}
already_AddRefed<DOMSVGPathSegLinetoAbs>
SVGPathElement::CreateSVGPathSegLinetoAbs(float x, float y) {
return do_AddRef(new DOMSVGPathSegLinetoAbs(x, y));
}
already_AddRefed<DOMSVGPathSegLinetoRel>
SVGPathElement::CreateSVGPathSegLinetoRel(float x, float y) {
return do_AddRef(new DOMSVGPathSegLinetoRel(x, y));
}
already_AddRefed<DOMSVGPathSegCurvetoCubicAbs>
SVGPathElement::CreateSVGPathSegCurvetoCubicAbs(float x, float y, float x1,
float y1, float x2, float y2) {
// Note that we swap from DOM API argument order to the argument order used
// in the <path> element's 'd' attribute (i.e. we put the arguments for the
// end point of the segment last instead of first).
return do_AddRef(new DOMSVGPathSegCurvetoCubicAbs(x1, y1, x2, y2, x, y));
}
already_AddRefed<DOMSVGPathSegCurvetoCubicRel>
SVGPathElement::CreateSVGPathSegCurvetoCubicRel(float x, float y, float x1,
float y1, float x2, float y2) {
// See comment in CreateSVGPathSegCurvetoCubicAbs
return do_AddRef(new DOMSVGPathSegCurvetoCubicRel(x1, y1, x2, y2, x, y));
}
already_AddRefed<DOMSVGPathSegCurvetoQuadraticAbs>
SVGPathElement::CreateSVGPathSegCurvetoQuadraticAbs(float x, float y, float x1,
float y1) {
// See comment in CreateSVGPathSegCurvetoCubicAbs
return do_AddRef(new DOMSVGPathSegCurvetoQuadraticAbs(x1, y1, x, y));
}
already_AddRefed<DOMSVGPathSegCurvetoQuadraticRel>
SVGPathElement::CreateSVGPathSegCurvetoQuadraticRel(float x, float y, float x1,
float y1) {
// See comment in CreateSVGPathSegCurvetoCubicAbs
return do_AddRef(new DOMSVGPathSegCurvetoQuadraticRel(x1, y1, x, y));
}
already_AddRefed<DOMSVGPathSegArcAbs> SVGPathElement::CreateSVGPathSegArcAbs(
float x, float y, float r1, float r2, float angle, bool largeArcFlag,
bool sweepFlag) {
// See comment in CreateSVGPathSegCurvetoCubicAbs
return do_AddRef(
new DOMSVGPathSegArcAbs(r1, r2, angle, largeArcFlag, sweepFlag, x, y));
}
already_AddRefed<DOMSVGPathSegArcRel> SVGPathElement::CreateSVGPathSegArcRel(
float x, float y, float r1, float r2, float angle, bool largeArcFlag,
bool sweepFlag) {
// See comment in CreateSVGPathSegCurvetoCubicAbs
return do_AddRef(
new DOMSVGPathSegArcRel(r1, r2, angle, largeArcFlag, sweepFlag, x, y));
}
already_AddRefed<DOMSVGPathSegLinetoHorizontalAbs>
SVGPathElement::CreateSVGPathSegLinetoHorizontalAbs(float x) {
return do_AddRef(new DOMSVGPathSegLinetoHorizontalAbs(x));
}
already_AddRefed<DOMSVGPathSegLinetoHorizontalRel>
SVGPathElement::CreateSVGPathSegLinetoHorizontalRel(float x) {
return do_AddRef(new DOMSVGPathSegLinetoHorizontalRel(x));
}
already_AddRefed<DOMSVGPathSegLinetoVerticalAbs>
SVGPathElement::CreateSVGPathSegLinetoVerticalAbs(float y) {
return do_AddRef(new DOMSVGPathSegLinetoVerticalAbs(y));
}
already_AddRefed<DOMSVGPathSegLinetoVerticalRel>
SVGPathElement::CreateSVGPathSegLinetoVerticalRel(float y) {
return do_AddRef(new DOMSVGPathSegLinetoVerticalRel(y));
}
already_AddRefed<DOMSVGPathSegCurvetoCubicSmoothAbs>
SVGPathElement::CreateSVGPathSegCurvetoCubicSmoothAbs(float x, float y,
float x2, float y2) {
// See comment in CreateSVGPathSegCurvetoCubicAbs
return do_AddRef(new DOMSVGPathSegCurvetoCubicSmoothAbs(x2, y2, x, y));
}
already_AddRefed<DOMSVGPathSegCurvetoCubicSmoothRel>
SVGPathElement::CreateSVGPathSegCurvetoCubicSmoothRel(float x, float y,
float x2, float y2) {
// See comment in CreateSVGPathSegCurvetoCubicAbs
return do_AddRef(new DOMSVGPathSegCurvetoCubicSmoothRel(x2, y2, x, y));
}
already_AddRefed<DOMSVGPathSegCurvetoQuadraticSmoothAbs>
SVGPathElement::CreateSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y) {
return do_AddRef(new DOMSVGPathSegCurvetoQuadraticSmoothAbs(x, y));
}
already_AddRefed<DOMSVGPathSegCurvetoQuadraticSmoothRel>
SVGPathElement::CreateSVGPathSegCurvetoQuadraticSmoothRel(float x, float y) {
return do_AddRef(new DOMSVGPathSegCurvetoQuadraticSmoothRel(x, y));
}
// FIXME: This API is enabled only if dom.svg.pathSeg.enabled is true. This
// preference is off by default in Bug 1388931, and will be dropped later.
// So we are not planning to map d property for this API.
already_AddRefed<DOMSVGPathSegList> SVGPathElement::PathSegList() {
return DOMSVGPathSegList::GetDOMWrapper(mD.GetBaseValKey(), this);
}
// FIXME: This API is enabled only if dom.svg.pathSeg.enabled is true. This
// preference is off by default in Bug 1388931, and will be dropped later.
// So we are not planning to map d property for this API.
already_AddRefed<DOMSVGPathSegList> SVGPathElement::AnimatedPathSegList() {
return DOMSVGPathSegList::GetDOMWrapper(mD.GetAnimValKey(), this);
}
//----------------------------------------------------------------------
// SVGElement methods
@ -364,12 +216,12 @@ bool SVGPathElement::IsClosedLoop() const {
// FIXME: Bug 1847621, we can cache this value, instead of walking through the
// entire path again and again.
uint32_t i = 0;
uint32_t segType = SVGPathSeg_Binding::PATHSEG_UNKNOWN;
uint32_t segType = PATHSEG_UNKNOWN;
while (i < data.Length()) {
segType = SVGPathSegUtils::DecodeType(data[i++]);
i += SVGPathSegUtils::ArgCountForType(segType);
}
return segType == SVGPathSeg_Binding::PATHSEG_CLOSEPATH;
return segType == PATHSEG_CLOSEPATH;
}
/* static */

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

@ -11,7 +11,6 @@
#include "mozilla/RefPtr.h"
#include "SVGAnimatedPathSegList.h"
#include "SVGGeometryElement.h"
#include "DOMSVGPathSeg.h"
nsresult NS_NewSVGPathElement(
nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
@ -77,52 +76,6 @@ class SVGPathElement final : public SVGPathElementBase {
nsStaticAtom* GetPathDataAttrName() const override { return nsGkAtoms::d; }
// WebIDL
MOZ_CAN_RUN_SCRIPT uint32_t GetPathSegAtLength(float distance);
already_AddRefed<DOMSVGPathSegClosePath> CreateSVGPathSegClosePath();
already_AddRefed<DOMSVGPathSegMovetoAbs> CreateSVGPathSegMovetoAbs(float x,
float y);
already_AddRefed<DOMSVGPathSegMovetoRel> CreateSVGPathSegMovetoRel(float x,
float y);
already_AddRefed<DOMSVGPathSegLinetoAbs> CreateSVGPathSegLinetoAbs(float x,
float y);
already_AddRefed<DOMSVGPathSegLinetoRel> CreateSVGPathSegLinetoRel(float x,
float y);
already_AddRefed<DOMSVGPathSegCurvetoCubicAbs>
CreateSVGPathSegCurvetoCubicAbs(float x, float y, float x1, float y1,
float x2, float y2);
already_AddRefed<DOMSVGPathSegCurvetoCubicRel>
CreateSVGPathSegCurvetoCubicRel(float x, float y, float x1, float y1,
float x2, float y2);
already_AddRefed<DOMSVGPathSegCurvetoQuadraticAbs>
CreateSVGPathSegCurvetoQuadraticAbs(float x, float y, float x1, float y1);
already_AddRefed<DOMSVGPathSegCurvetoQuadraticRel>
CreateSVGPathSegCurvetoQuadraticRel(float x, float y, float x1, float y1);
already_AddRefed<DOMSVGPathSegArcAbs> CreateSVGPathSegArcAbs(
float x, float y, float r1, float r2, float angle, bool largeArcFlag,
bool sweepFlag);
already_AddRefed<DOMSVGPathSegArcRel> CreateSVGPathSegArcRel(
float x, float y, float r1, float r2, float angle, bool largeArcFlag,
bool sweepFlag);
already_AddRefed<DOMSVGPathSegLinetoHorizontalAbs>
CreateSVGPathSegLinetoHorizontalAbs(float x);
already_AddRefed<DOMSVGPathSegLinetoHorizontalRel>
CreateSVGPathSegLinetoHorizontalRel(float x);
already_AddRefed<DOMSVGPathSegLinetoVerticalAbs>
CreateSVGPathSegLinetoVerticalAbs(float y);
already_AddRefed<DOMSVGPathSegLinetoVerticalRel>
CreateSVGPathSegLinetoVerticalRel(float y);
already_AddRefed<DOMSVGPathSegCurvetoCubicSmoothAbs>
CreateSVGPathSegCurvetoCubicSmoothAbs(float x, float y, float x2, float y2);
already_AddRefed<DOMSVGPathSegCurvetoCubicSmoothRel>
CreateSVGPathSegCurvetoCubicSmoothRel(float x, float y, float x2, float y2);
already_AddRefed<DOMSVGPathSegCurvetoQuadraticSmoothAbs>
CreateSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y);
already_AddRefed<DOMSVGPathSegCurvetoQuadraticSmoothRel>
CreateSVGPathSegCurvetoQuadraticSmoothRel(float x, float y);
already_AddRefed<DOMSVGPathSegList> PathSegList();
already_AddRefed<DOMSVGPathSegList> AnimatedPathSegList();
static bool IsDPropertyChangedViaCSS(const ComputedStyle& aNewStyle,
const ComputedStyle& aOldStyle);

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

@ -11,8 +11,6 @@
#include "SVGPathData.h"
#include "SVGPathSegUtils.h"
using namespace mozilla::dom::SVGPathSeg_Binding;
// Indices of boolean flags within 'arc' segment chunks in path-data arrays
// (where '0' would correspond to the index of the encoded segment type):
#define LARGE_ARC_FLAG_IDX 4

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

@ -13,7 +13,6 @@
#include "nsMathUtils.h"
#include "nsTextFormatter.h"
using namespace mozilla::dom::SVGPathSeg_Binding;
using namespace mozilla::gfx;
namespace mozilla {

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

@ -8,20 +8,39 @@
#define DOM_SVG_SVGPATHSEGUTILS_H_
#include "mozilla/ArrayUtils.h"
#include "mozilla/dom/SVGPathSegBinding.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/gfx/Rect.h"
#include "nsDebug.h"
#include "mozilla/Span.h"
#include "nsStringFwd.h"
namespace mozilla {
template <typename Angle, typename LP>
struct StyleGenericShapeCommand;
constexpr uint16_t PATHSEG_UNKNOWN = 0;
constexpr uint16_t PATHSEG_CLOSEPATH = 1;
constexpr uint16_t PATHSEG_MOVETO_ABS = 2;
constexpr uint16_t PATHSEG_MOVETO_REL = 3;
constexpr uint16_t PATHSEG_LINETO_ABS = 4;
constexpr uint16_t PATHSEG_LINETO_REL = 5;
constexpr uint16_t PATHSEG_CURVETO_CUBIC_ABS = 6;
constexpr uint16_t PATHSEG_CURVETO_CUBIC_REL = 7;
constexpr uint16_t PATHSEG_CURVETO_QUADRATIC_ABS = 8;
constexpr uint16_t PATHSEG_CURVETO_QUADRATIC_REL = 9;
constexpr uint16_t PATHSEG_ARC_ABS = 10;
constexpr uint16_t PATHSEG_ARC_REL = 11;
constexpr uint16_t PATHSEG_LINETO_HORIZONTAL_ABS = 12;
constexpr uint16_t PATHSEG_LINETO_HORIZONTAL_REL = 13;
constexpr uint16_t PATHSEG_LINETO_VERTICAL_ABS = 14;
constexpr uint16_t PATHSEG_LINETO_VERTICAL_REL = 15;
constexpr uint16_t PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
constexpr uint16_t PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
constexpr uint16_t PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
constexpr uint16_t PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19;
#define NS_SVG_PATH_SEG_MAX_ARGS 7
#define NS_SVG_PATH_SEG_FIRST_VALID_TYPE \
dom::SVGPathSeg_Binding::PATHSEG_CLOSEPATH
#define NS_SVG_PATH_SEG_LAST_VALID_TYPE \
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL
#define NS_SVG_PATH_SEG_FIRST_VALID_TYPE PATHSEG_CLOSEPATH
#define NS_SVG_PATH_SEG_LAST_VALID_TYPE PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL
#define NS_SVG_PATH_SEG_TYPE_COUNT (NS_SVG_PATH_SEG_LAST_VALID_TYPE + 1)
/**
@ -181,24 +200,21 @@ class SVGPathSegUtils {
}
static bool IsCubicType(uint32_t aType) {
return aType == dom::SVGPathSeg_Binding::PATHSEG_CURVETO_CUBIC_REL ||
aType == dom::SVGPathSeg_Binding::PATHSEG_CURVETO_CUBIC_ABS ||
aType == dom::SVGPathSeg_Binding::PATHSEG_CURVETO_CUBIC_SMOOTH_REL ||
aType == dom::SVGPathSeg_Binding::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
return aType == PATHSEG_CURVETO_CUBIC_REL ||
aType == PATHSEG_CURVETO_CUBIC_ABS ||
aType == PATHSEG_CURVETO_CUBIC_SMOOTH_REL ||
aType == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
}
static bool IsQuadraticType(uint32_t aType) {
return aType == dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_REL ||
aType == dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_ABS ||
aType ==
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL ||
aType ==
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
return aType == PATHSEG_CURVETO_QUADRATIC_REL ||
aType == PATHSEG_CURVETO_QUADRATIC_ABS ||
aType == PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL ||
aType == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
}
static bool IsArcType(uint32_t aType) {
return aType == dom::SVGPathSeg_Binding::PATHSEG_ARC_ABS ||
aType == dom::SVGPathSeg_Binding::PATHSEG_ARC_REL;
return aType == PATHSEG_ARC_ABS || aType == PATHSEG_ARC_REL;
}
static bool IsRelativeOrAbsoluteType(uint32_t aType) {
@ -207,11 +223,10 @@ class SVGPathSegUtils {
// When adding a new path segment type, ensure that the returned condition
// below is still correct.
static_assert(
NS_SVG_PATH_SEG_LAST_VALID_TYPE ==
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL,
NS_SVG_PATH_SEG_LAST_VALID_TYPE == PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL,
"Unexpected type");
return aType >= dom::SVGPathSeg_Binding::PATHSEG_MOVETO_ABS;
return aType >= PATHSEG_MOVETO_ABS;
}
static bool IsRelativeType(uint32_t aType) {
@ -222,8 +237,7 @@ class SVGPathSegUtils {
// When adding a new path segment type, ensure that the returned condition
// below is still correct.
static_assert(
NS_SVG_PATH_SEG_LAST_VALID_TYPE ==
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL,
NS_SVG_PATH_SEG_LAST_VALID_TYPE == PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL,
"Unexpected type");
return aType & 1;
@ -237,8 +251,7 @@ class SVGPathSegUtils {
// When adding a new path segment type, ensure that the returned condition
// below is still correct.
static_assert(
NS_SVG_PATH_SEG_LAST_VALID_TYPE ==
dom::SVGPathSeg_Binding::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL,
NS_SVG_PATH_SEG_LAST_VALID_TYPE == PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL,
"Unexpected type");
return aType | 1;

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

@ -96,7 +96,7 @@ load 1555795.html
load 1560179.html
load 1572904.html
load 1683907.html
pref(dom.svg.pathSeg.enabled,true) load 1715387.html
load 1715387.html
load 1837487.html
load 1858792.html
load 1858806.html

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

@ -79,6 +79,7 @@ EXPORTS.mozilla.dom += [
"SVGMPathElement.h",
"SVGPathData.h",
"SVGPathElement.h",
"SVGPathSegUtils.h",
"SVGPatternElement.h",
"SVGPolygonElement.h",
"SVGPolylineElement.h",
@ -122,8 +123,6 @@ UNIFIED_SOURCES += [
"DOMSVGLengthList.cpp",
"DOMSVGNumber.cpp",
"DOMSVGNumberList.cpp",
"DOMSVGPathSeg.cpp",
"DOMSVGPathSegList.cpp",
"DOMSVGPoint.cpp",
"DOMSVGPointList.cpp",
"DOMSVGStringList.cpp",

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

@ -1,5 +1,4 @@
[DEFAULT]
prefs = ["dom.svg.pathSeg.enabled=true"]
support-files = [
"MutationEventChecker.js",
"a_href_destination.svg",
@ -88,7 +87,6 @@ support-files = [
["test_getElementById.xhtml"]
["test_getPathSegListAtLength_with_d_property.html"]
["test_getSubStringLength.xhtml"]

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

@ -1,55 +0,0 @@
<!DOCTYPE html>
<title>Test for getPathSegAtLength for d property</title>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
svg {
width: 10%;
height: 10%;
background: #eee;
}
svg path {
fill: none;
stroke: #000;
}
</style>
<div id="log"></div>
<svg viewBox="0 0 20 10">
<path id='target1' d="M2,2 L8,8 L12,4"/>
</svg>
<svg viewBox="0 0 20 10">
<path id='target2' style='d: path("M2,2 L8,8 L12,4")' />
</svg>
<script>
/* global test, assert_equals */
'use strict';
test(function() {
let target1 = document.getElementById('target1');
let target2 = document.getElementById('target2');
assert_equals(target1.getPathSegAtLength(5), 1);
assert_equals(target2.getPathSegAtLength(5), 1);
assert_equals(target1.getPathSegAtLength(10), 2);
assert_equals(target2.getPathSegAtLength(10), 2);
}, "getPathSegAtLength works properly on both d attribute and d property");
test(function() {
let target = document.getElementById('target1');
// Note: in order to make sure we flush style properly, we call
// getComputedStyle after setting an initial value first, so if
// getPathSegAtLength(5) doesn't flush style, it returns 0.
target.style.d = 'none';
assert_equals(getComputedStyle(target).d, "none");
target.style.d = 'path("M2,2 h3 v5")';
assert_equals(target.getPathSegAtLength(5), 2);
}, "getPathSegAtLength works properly after updating d property");
</script>

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

@ -1,5 +1,4 @@
[DEFAULT]
prefs = ["dom.svg.pathSeg.enabled=false"]
support-files = [
"497633.html",
"fail.png",

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

@ -1,18 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface mixin SVGAnimatedPathData {
[Pref="dom.svg.pathSeg.enabled"]
readonly attribute SVGPathSegList pathSegList;
[Pref="dom.svg.pathSeg.enabled"]
readonly attribute SVGPathSegList animatedPathSegList;
};

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

@ -11,8 +11,6 @@
*/
[Exposed=Window]
interface SVGPathElement : SVGGeometryElement {
[Pref="dom.svg.pathSeg.enabled"]
unsigned long getPathSegAtLength(float distance);
};
SVGPathElement includes SVGAnimatedPathData;
// TODO: Implement https://www.w3.org/TR/svg-paths/#InterfaceSVGPathData

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

@ -1,254 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSeg {
// Path Segment Types
const unsigned short PATHSEG_UNKNOWN = 0;
const unsigned short PATHSEG_CLOSEPATH = 1;
const unsigned short PATHSEG_MOVETO_ABS = 2;
const unsigned short PATHSEG_MOVETO_REL = 3;
const unsigned short PATHSEG_LINETO_ABS = 4;
const unsigned short PATHSEG_LINETO_REL = 5;
const unsigned short PATHSEG_CURVETO_CUBIC_ABS = 6;
const unsigned short PATHSEG_CURVETO_CUBIC_REL = 7;
const unsigned short PATHSEG_CURVETO_QUADRATIC_ABS = 8;
const unsigned short PATHSEG_CURVETO_QUADRATIC_REL = 9;
const unsigned short PATHSEG_ARC_ABS = 10;
const unsigned short PATHSEG_ARC_REL = 11;
const unsigned short PATHSEG_LINETO_HORIZONTAL_ABS = 12;
const unsigned short PATHSEG_LINETO_HORIZONTAL_REL = 13;
const unsigned short PATHSEG_LINETO_VERTICAL_ABS = 14;
const unsigned short PATHSEG_LINETO_VERTICAL_REL = 15;
const unsigned short PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
const unsigned short PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
const unsigned short PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
const unsigned short PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19;
[Pure]
readonly attribute unsigned short pathSegType;
[Pure]
readonly attribute DOMString pathSegTypeAsLetter;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegClosePath : SVGPathSeg {
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegMovetoAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegMovetoRel : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegLinetoAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegLinetoRel : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegCurvetoCubicAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
[SetterThrows]
attribute float x1;
[SetterThrows]
attribute float y1;
[SetterThrows]
attribute float x2;
[SetterThrows]
attribute float y2;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegCurvetoCubicRel : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
[SetterThrows]
attribute float x1;
[SetterThrows]
attribute float y1;
[SetterThrows]
attribute float x2;
[SetterThrows]
attribute float y2;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegCurvetoQuadraticAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
[SetterThrows]
attribute float x1;
[SetterThrows]
attribute float y1;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegCurvetoQuadraticRel : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
[SetterThrows]
attribute float x1;
[SetterThrows]
attribute float y1;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegArcAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
[SetterThrows]
attribute float r1;
[SetterThrows]
attribute float r2;
[SetterThrows]
attribute float angle;
[SetterThrows]
attribute boolean largeArcFlag;
[SetterThrows]
attribute boolean sweepFlag;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegArcRel : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
[SetterThrows]
attribute float r1;
[SetterThrows]
attribute float r2;
[SetterThrows]
attribute float angle;
[SetterThrows]
attribute boolean largeArcFlag;
[SetterThrows]
attribute boolean sweepFlag;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegLinetoHorizontalAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegLinetoHorizontalRel : SVGPathSeg {
[SetterThrows]
attribute float x;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegLinetoVerticalAbs : SVGPathSeg {
[SetterThrows]
attribute float y;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegLinetoVerticalRel : SVGPathSeg {
[SetterThrows]
attribute float y;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegCurvetoCubicSmoothAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
[SetterThrows]
attribute float x2;
[SetterThrows]
attribute float y2;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegCurvetoCubicSmoothRel : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
[SetterThrows]
attribute float x2;
[SetterThrows]
attribute float y2;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegCurvetoQuadraticSmoothAbs : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
};
[LegacyNoInterfaceObject,
Exposed=Window]
interface SVGPathSegCurvetoQuadraticSmoothRel : SVGPathSeg {
[SetterThrows]
attribute float x;
[SetterThrows]
attribute float y;
};

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

@ -1,22 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*
* The origin of this IDL file is
* http://www.w3.org/TR/SVG11/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
[Exposed=Window,
Pref="dom.svg.pathSeg.enabled"]
interface SVGPathSegList {
readonly attribute unsigned long numberOfItems;
[Throws]
getter SVGPathSeg getItem(unsigned long index);
// Mozilla-specific stuff
readonly attribute unsigned long length; // synonym for numberOfItems
};

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

@ -866,7 +866,6 @@ WEBIDL_FILES = [
"SVGAnimatedLengthList.webidl",
"SVGAnimatedNumber.webidl",
"SVGAnimatedNumberList.webidl",
"SVGAnimatedPathData.webidl",
"SVGAnimatedPoints.webidl",
"SVGAnimatedPreserveAspectRatio.webidl",
"SVGAnimatedRect.webidl",
@ -929,8 +928,6 @@ WEBIDL_FILES = [
"SVGNumber.webidl",
"SVGNumberList.webidl",
"SVGPathElement.webidl",
"SVGPathSeg.webidl",
"SVGPathSegList.webidl",
"SVGPatternElement.webidl",
"SVGPoint.webidl",
"SVGPointList.webidl",

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

@ -9,6 +9,7 @@ headers = [
"mozilla/css/Loader.h",
"mozilla/AnimatedPropertyID.h",
"mozilla/css/SheetLoadData.h",
"mozilla/dom/SVGPathSegUtils.h",
"mozilla/DeclarationBlock.h",
"mozilla/dom/AnimationEffectBinding.h",
"mozilla/dom/HTMLSlotElement.h",
@ -16,7 +17,6 @@ headers = [
"mozilla/dom/MediaList.h",
"mozilla/dom/ScreenBinding.h",
"mozilla/dom/ShadowRoot.h",
"mozilla/dom/SVGPathSegBinding.h",
"mozilla/ipc/ByteBuf.h",
"mozilla/AnimationPropertySegment.h",
"mozilla/ComputedTiming.h",
@ -195,7 +195,7 @@ allowlist-vars = [
"GECKO_IS_NIGHTLY",
"NS_SAME_AS_FOREGROUND_COLOR",
"mozilla::detail::gGkAtoms",
"mozilla::dom::SVGPathSeg_Binding::PATHSEG_.*",
"mozilla::PATHSEG_.*",
]
# TODO(emilio): A bunch of types here can go away once we generate bindings and
# structs together.

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

@ -3353,12 +3353,6 @@
value: true
mirror: always
# This enables the SVGPathSeg APIs
- name: dom.svg.pathSeg.enabled
type: bool
value: false
mirror: always
# Preference that is primarily used for testing of problematic file paths.
# It can also be used for switching between different storage directories, but
# such feature is not officially supported.

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

@ -72,7 +72,7 @@ impl SVGPathData {
/// Decode the svg path raw data from Gecko.
#[cfg(feature = "gecko")]
pub fn decode_from_f32_array(path: &[f32]) -> Result<Self, ()> {
use crate::gecko_bindings::structs::dom::SVGPathSeg_Binding::*;
use crate::gecko_bindings::structs::*;
use crate::values::generics::basic_shape::GenericShapeCommand::*;
let mut result: Vec<PathCommand> = Vec::new();

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

@ -1 +0,0 @@
prefs: [dom.svg.pathSeg.enabled:false]

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

@ -1,2 +0,0 @@
[SVGAnimatedPathData-removed.svg]
prefs: [dom.svg.pathSeg.enabled:false]