diff --git a/D84796.diff b/D84796.diff new file mode 100644 --- /dev/null +++ b/D84796.diff @@ -0,0 +1,1443 @@ +diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf +--- a/dom/bindings/Bindings.conf ++++ b/dom/bindings/Bindings.conf +@@ -924,8 +924,8 @@ + }, + + 'SVGPoint': { +- 'nativeType': 'mozilla::dom::nsISVGPoint', +- 'headerFile': 'nsISVGPoint.h' ++ 'nativeType': 'mozilla::dom::DOMSVGPoint', ++ 'headerFile': 'DOMSVGPoint.h' + }, + + 'SVGPointList': { +diff --git a/dom/svg/DOMSVGPoint.h b/dom/svg/DOMSVGPoint.h +--- a/dom/svg/DOMSVGPoint.h ++++ b/dom/svg/DOMSVGPoint.h +@@ -8,18 +8,21 @@ + #define DOM_SVG_DOMSVGPOINT_H_ + + #include "DOMSVGPointList.h" +-#include "mozilla/gfx/2D.h" ++#include "nsCycleCollectionParticipant.h" + #include "nsDebug.h" +-#include "nsISVGPoint.h" + #include "SVGPoint.h" ++#include "nsWrapperCache.h" + #include "mozilla/Attributes.h" + #include "mozilla/FloatingPoint.h" ++#include "mozilla/dom/SVGSVGElement.h" ++#include "mozilla/gfx/2D.h" ++ ++#define MOZ_SVG_LIST_INDEX_BIT_COUNT 30 + + namespace mozilla { + + namespace dom { + struct DOMMatrix2DInit; +-class SVGElement; + + /** + * Class DOMSVGPoint +@@ -35,7 +38,7 @@ + * See the architecture comment in DOMSVGLength.h (yes, LENGTH) for an overview + * of the important points regarding how this specific class works. + */ +-class DOMSVGPoint final : public nsISVGPoint { ++class DOMSVGPoint final : public nsWrapperCache { + friend class AutoChangePointNotifier; + + using Point = gfx::Point; +@@ -45,46 +48,134 @@ + * Generic ctor for DOMSVGPoint objects that are created for an attribute. + */ + DOMSVGPoint(DOMSVGPointList* aList, uint32_t aListIndex, bool aIsAnimValItem) +- : nsISVGPoint() { +- mList = aList; +- mListIndex = aListIndex; +- mIsAnimValItem = aIsAnimValItem; +- ++ : mList(aList), ++ mVal(nullptr), ++ mListIndex(aListIndex), ++ mIsAnimValItem(aIsAnimValItem), ++ mIsTranslatePoint(false) { + // These shifts are in sync with the members. + MOZ_ASSERT(aList && aListIndex <= MaxListIndex(), "bad arg"); + + MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPoint!"); + } + +- explicit DOMSVGPoint(const DOMSVGPoint* aPt = nullptr) : nsISVGPoint() { +- if (aPt) { +- mPt = aPt->ToSVGPoint(); +- } ++ // Constructor for unowned points and SVGSVGElement.createSVGPoint ++ explicit DOMSVGPoint(const Point& aPt) ++ : mList(nullptr), mIsAnimValItem(false), mIsTranslatePoint(false) { ++ // In this case we own mVal ++ mVal = new SVGPoint(aPt.x, aPt.y); + } + +- explicit DOMSVGPoint(const Point& aPt) : nsISVGPoint() { +- mPt.mX = aPt.x; +- mPt.mY = aPt.y; +- NS_ASSERTION(IsFinite(mPt.mX) && IsFinite(mPt.mY), +- "DOMSVGPoint coords are not finite"); ++ private: ++ // The translate of an SVGSVGElement ++ explicit DOMSVGPoint(SVGPoint* aPt, SVGSVGElement* aSVGSVGElement) ++ : mList(nullptr), ++ mVal(aPt), ++ mSVGSVGElement(aSVGSVGElement), ++ mIsAnimValItem(false), ++ mIsTranslatePoint(true) {} ++ ++ virtual ~DOMSVGPoint() { CleanupWeakRefs(); } ++ ++ public: ++ NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMSVGPoint) ++ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMSVGPoint) ++ ++ static already_AddRefed GetTranslateTearOff( ++ SVGPoint* aVal, SVGSVGElement* aSVGSVGElement); ++ ++ bool IsInList() const { return !!mList; } ++ ++ /** ++ * "Owner" here means that the instance has an ++ * internal counterpart from which it gets its values. (A better name may ++ * be HasWrappee().) ++ */ ++ bool HasOwner() const { return !!mList || mIsTranslatePoint; } ++ ++ bool IsTranslatePoint() const { return mIsTranslatePoint; } ++ ++ /** ++ * 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 DOMSVGPointList).) ++ */ ++ void InsertingIntoList(DOMSVGPointList* 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(); ++ ++ SVGPoint ToSVGPoint() { return InternalItem(); } ++ + // WebIDL +- virtual float X() override; +- virtual void SetX(float aX, ErrorResult& rv) override; +- virtual float Y() override; +- virtual void SetY(float aY, ErrorResult& rv) override; +- virtual already_AddRefed MatrixTransform( +- const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) override; +- nsISupports* GetParentObject() override { return mList; } ++ float X(); ++ void SetX(float aX, ErrorResult& rv); ++ float Y(); ++ void SetY(float aY, ErrorResult& rv); ++ already_AddRefed MatrixTransform(const DOMMatrix2DInit& aMatrix, ++ ErrorResult& aRv); ++ ++ nsISupports* GetParentObject() { return Element(); } ++ ++ JSObject* WrapObject(JSContext* cx, ++ JS::Handle aGivenProto) override; ++ ++ DOMSVGPoint* Copy() { return new DOMSVGPoint(InternalItem()); } ++ ++ private: ++#ifdef DEBUG ++ bool IndexIsValid(); ++#endif ++ ++ SVGElement* Element() { return mList ? mList->Element() : mSVGSVGElement; } + +- virtual DOMSVGPoint* Copy() override { return new DOMSVGPoint(this); } ++ /** ++ * Clears soon-to-be-invalid weak references in external objects that were ++ * set up during the creation of this object. This should be called during ++ * destruction and during cycle collection. ++ */ ++ void CleanupWeakRefs(); ++ ++ /** ++ * Get a reference to the internal SVGPoint list item that this DOM wrapper ++ * object currently wraps. ++ */ ++ SVGPoint& InternalItem(); + +- protected: +- SVGElement* Element() { return mList->Element(); } ++ RefPtr mList; ++ ++ SVGPoint* mVal; // If mIsTranslatePoint is true, the element owns ++ // the value. Otherwise we do. ++ RefPtr mSVGSVGElement; ++ ++ // 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; // These flags are uint32_t because MSVC won't ++ uint32_t mIsTranslatePoint : 1; // pack otherwise. + }; + + } // namespace dom + } // namespace mozilla + ++#undef MOZ_SVG_LIST_INDEX_BIT_COUNT ++ + #endif // DOM_SVG_DOMSVGPOINT_H_ +diff --git a/dom/svg/DOMSVGPoint.cpp b/dom/svg/DOMSVGPoint.cpp +--- a/dom/svg/DOMSVGPoint.cpp ++++ b/dom/svg/DOMSVGPoint.cpp +@@ -9,11 +9,9 @@ + #include "DOMSVGPointList.h" + #include "gfx2DGlue.h" + #include "mozAutoDocUpdate.h" +-#include "nsCOMPtr.h" + #include "nsError.h" +-#include "SVGPoint.h" + #include "mozilla/dom/DOMMatrix.h" +-#include "mozilla/dom/SVGElement.h" ++#include "mozilla/dom/SVGPointBinding.h" + + // See the architecture comment in DOMSVGPointList.h. + +@@ -22,6 +20,33 @@ + namespace mozilla { + namespace dom { + ++static SVGAttrTearoffTable sSVGTranslateTearOffTable; ++ ++// 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(DOMSVGPoint) ++ ++NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPoint) ++ tmp->CleanupWeakRefs(); ++ NS_IMPL_CYCLE_COLLECTION_UNLINK(mList) ++ NS_IMPL_CYCLE_COLLECTION_UNLINK(mSVGSVGElement) ++ NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER ++NS_IMPL_CYCLE_COLLECTION_UNLINK_END ++ ++NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPoint) ++ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList) ++ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSVGSVGElement) ++NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END ++ ++NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPoint) ++ NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER ++NS_IMPL_CYCLE_COLLECTION_TRACE_END ++ ++NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMSVGPoint, AddRef) ++NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGPoint, Release) ++ + //---------------------------------------------------------------------- + // Helper class: AutoChangePointNotifier + // Stack-based helper class to pair calls to WillChangePointList and +@@ -34,17 +59,23 @@ + mPoint(aPoint) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + MOZ_ASSERT(mPoint, "Expecting non-null point"); +- MOZ_ASSERT(mPoint->HasOwner(), +- "Expecting list to have an owner for notification"); +- mEmptyOrOldValue = mPoint->Element()->WillChangePointList(*this); ++ if (mPoint->IsInList()) { ++ mEmptyOrOldValue = mPoint->Element()->WillChangePointList(*this); ++ } + } + + ~AutoChangePointNotifier() { +- mPoint->Element()->DidChangePointList(mEmptyOrOldValue, *this); +- // Null check mPoint->mList, since DidChangePointList can run script, +- // potentially removing mPoint from its list. +- if (mPoint->mList && mPoint->mList->AttrIsAnimating()) { +- mPoint->Element()->AnimationNeedsResample(); ++ if (mPoint->IsInList()) { ++ mPoint->Element()->DidChangePointList(mEmptyOrOldValue, *this); ++ // Null check mPoint->mList, since DidChangePointList can run script, ++ // potentially removing mPoint from its list. ++ if (mPoint->mList && mPoint->mList->AttrIsAnimating()) { ++ mPoint->Element()->AnimationNeedsResample(); ++ } ++ } else if (mPoint->mIsTranslatePoint) { ++ nsContentUtils::AddScriptRunner(NewRunnableMethod( ++ "dom::SVGSVGElement::ScaleOrTranslateChanged", mPoint->mSVGSVGElement, ++ &SVGSVGElement::ScaleOrTranslateChanged, true)); + } + } + +@@ -54,55 +85,59 @@ + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + }; + ++JSObject* DOMSVGPoint::WrapObject(JSContext* aCx, ++ JS::Handle aGivenProto) { ++ return SVGPoint_Binding::Wrap(aCx, this, aGivenProto); ++} ++ + float DOMSVGPoint::X() { +- if (mIsAnimValItem && HasOwner()) { +- Element()->FlushAnimations(); // May make HasOwner() == false ++ if (mIsAnimValItem && IsInList()) { ++ Element()->FlushAnimations(); // May make IsInList() == false + } +- return HasOwner() ? InternalItem().mX : mPt.mX; ++ return InternalItem().mX; + } + + void DOMSVGPoint::SetX(float aX, ErrorResult& rv) { +- if (mIsAnimValItem || mIsReadonly) { ++ if (mIsAnimValItem) { + rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); + return; + } + +- if (HasOwner()) { +- if (InternalItem().mX == aX) { +- return; +- } +- AutoChangePointNotifier notifier(this); +- InternalItem().mX = aX; ++ auto& val = InternalItem(); ++ ++ if (val.mX == aX) { + return; + } +- mPt.mX = aX; ++ ++ AutoChangePointNotifier notifier(this); ++ ++ val.mX = aX; + } + + float DOMSVGPoint::Y() { +- if (mIsAnimValItem && HasOwner()) { +- Element()->FlushAnimations(); // May make HasOwner() == false ++ if (mIsAnimValItem && IsInList()) { ++ Element()->FlushAnimations(); // May make IsInList() == false + } +- return HasOwner() ? InternalItem().mY : mPt.mY; ++ return InternalItem().mY; + } + + void DOMSVGPoint::SetY(float aY, ErrorResult& rv) { +- if (mIsAnimValItem || mIsReadonly) { ++ if (mIsAnimValItem) { + rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); + return; + } ++ auto& val = InternalItem(); ++ ++ if (val.mY == aY) { ++ return; ++ } + +- if (HasOwner()) { +- if (InternalItem().mY == aY) { +- return; +- } +- AutoChangePointNotifier notifier(this); +- InternalItem().mY = aY; +- return; +- } +- mPt.mY = aY; ++ AutoChangePointNotifier notifier(this); ++ ++ val.mY = aY; + } + +-already_AddRefed DOMSVGPoint::MatrixTransform( ++already_AddRefed DOMSVGPoint::MatrixTransform( + const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) { + RefPtr matrix = + DOMMatrixReadOnly::FromMatrix(GetParentObject(), aMatrix, aRv); +@@ -114,10 +149,76 @@ + aRv.ThrowTypeError("MatrixTransform matrix"); + return nullptr; + } +- auto pt = matrix2D->TransformPoint(HasOwner() ? InternalItem() : mPt); +- nsCOMPtr newPoint = new DOMSVGPoint(ToPoint(pt)); ++ auto pt = matrix2D->TransformPoint(InternalItem()); ++ RefPtr newPoint = new DOMSVGPoint(ToPoint(pt)); + return newPoint.forget(); + } + ++void DOMSVGPoint::InsertingIntoList(DOMSVGPointList* aList, uint32_t aListIndex, ++ bool aIsAnimValItem) { ++ MOZ_ASSERT(!IsInList(), "Inserting item that is already in a list"); ++ MOZ_ASSERT(!mIsTranslatePoint, "Inserting item that is a currentTranslate"); ++ ++ delete mVal; ++ mVal = nullptr; ++ ++ mList = aList; ++ mListIndex = aListIndex; ++ mIsAnimValItem = aIsAnimValItem; ++ ++ MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPoint!"); ++} ++ ++void DOMSVGPoint::RemovingFromList() { ++ mVal = new SVGPoint(InternalItem()); ++ mList = nullptr; ++ mIsAnimValItem = false; ++} ++ ++SVGPoint& DOMSVGPoint::InternalItem() { ++ return mList ? mList->InternalList().mItems[mListIndex] : *mVal; ++} ++ ++already_AddRefed DOMSVGPoint::GetTranslateTearOff( ++ SVGPoint* aVal, SVGSVGElement* aSVGSVGElement) { ++ RefPtr domPoint = sSVGTranslateTearOffTable.GetTearoff(aVal); ++ if (!domPoint) { ++ domPoint = new DOMSVGPoint(aVal, aSVGSVGElement); ++ sSVGTranslateTearOffTable.AddTearoff(aVal, domPoint); ++ } ++ ++ return domPoint.forget(); ++} ++ ++void DOMSVGPoint::CleanupWeakRefs() { ++ // Our mList's weak ref to us must be nulled out when we die (or when we're ++ // cycle collected), so we that don't leave behind a pointer to ++ // free / soon-to-be-free memory. ++ if (mList) { ++ MOZ_ASSERT(mList->mItems[mListIndex] == this, ++ "Clearing out the wrong list index...?"); ++ mList->mItems[mListIndex] = nullptr; ++ } ++ ++ if (mVal) { ++ if (mIsTranslatePoint) { ++ // Similarly, we must update the tearoff table to remove its (non-owning) ++ // pointer to mVal. ++ sSVGTranslateTearOffTable.RemoveTearoff(mVal); ++ } else { ++ // In this case we own mVal ++ delete mVal; ++ } ++ mVal = nullptr; ++ } ++ mSVGSVGElement = nullptr; ++} ++ ++#ifdef DEBUG ++bool DOMSVGPoint::IndexIsValid() { ++ return mListIndex < mList->InternalList().Length(); ++} ++#endif ++ + } // namespace dom + } // namespace mozilla +diff --git a/dom/svg/DOMSVGPointList.h b/dom/svg/DOMSVGPointList.h +--- a/dom/svg/DOMSVGPointList.h ++++ b/dom/svg/DOMSVGPointList.h +@@ -23,7 +23,6 @@ + namespace dom { + + class DOMSVGPoint; +-class nsISVGPoint; + + /** + * Class DOMSVGPointList +@@ -52,7 +51,6 @@ + */ + class DOMSVGPointList final : public nsISupports, public nsWrapperCache { + friend class AutoChangePointListNotifier; +- friend class nsISVGPoint; + friend class DOMSVGPoint; + + public: +@@ -137,20 +135,20 @@ + return LengthNoFlush(); + } + void Clear(ErrorResult& aError); +- already_AddRefed Initialize(nsISVGPoint& aNewItem, ++ already_AddRefed Initialize(DOMSVGPoint& aNewItem, + ErrorResult& aError); +- already_AddRefed GetItem(uint32_t index, ErrorResult& error); +- already_AddRefed IndexedGetter(uint32_t index, bool& found, ++ already_AddRefed GetItem(uint32_t index, ErrorResult& error); ++ already_AddRefed IndexedGetter(uint32_t index, bool& found, + ErrorResult& error); +- already_AddRefed InsertItemBefore(nsISVGPoint& aNewItem, ++ already_AddRefed InsertItemBefore(DOMSVGPoint& aNewItem, + uint32_t aIndex, + ErrorResult& aError); +- already_AddRefed ReplaceItem(nsISVGPoint& aNewItem, ++ already_AddRefed ReplaceItem(DOMSVGPoint& aNewItem, + uint32_t aIndex, + ErrorResult& aError); +- already_AddRefed RemoveItem(uint32_t aIndex, ++ already_AddRefed RemoveItem(uint32_t aIndex, + ErrorResult& aError); +- already_AddRefed AppendItem(nsISVGPoint& aNewItem, ++ already_AddRefed AppendItem(DOMSVGPoint& aNewItem, + ErrorResult& aError) { + return InsertItemBefore(aNewItem, LengthNoFlush(), aError); + } +@@ -185,20 +183,20 @@ + + SVGAnimatedPointList& InternalAList() const; + +- /// Returns the nsISVGPoint at aIndex, creating it if necessary. +- already_AddRefed GetItemAt(uint32_t aIndex); ++ /// Returns the DOMSVGPoint at aIndex, creating it if necessary. ++ already_AddRefed GetItemAt(uint32_t aIndex); + + void MaybeInsertNullInAnimValListAt(uint32_t aIndex); + void MaybeRemoveItemFromAnimValListAt(uint32_t aIndex); + + void RemoveFromTearoffTable(); + +- // Weak refs to our nsISVGPoint items. The items are friends and take care ++ // Weak refs to our DOMSVGPoint items. The items are friends and take care + // of clearing our pointer to them when they die. +- FallibleTArray mItems; ++ FallibleTArray mItems; + + // Strong ref to our element to keep it alive. We hold this not only for +- // ourself, but also for our nsISVGPoint items too. ++ // ourself, but also for our DOMSVGPoint items too. + RefPtr mElement; + + bool mIsAnimValList; +diff --git a/dom/svg/DOMSVGPointList.cpp b/dom/svg/DOMSVGPointList.cpp +--- a/dom/svg/DOMSVGPointList.cpp ++++ b/dom/svg/DOMSVGPointList.cpp +@@ -6,7 +6,6 @@ + + #include "DOMSVGPointList.h" + +-#include "nsCOMPtr.h" + #include "nsContentUtils.h" + #include "DOMSVGPoint.h" + #include "nsError.h" +@@ -23,7 +22,7 @@ + namespace { + + void UpdateListIndicesFromIndex( +- FallibleTArray& aItemsArray, ++ FallibleTArray& aItemsArray, + uint32_t aStartingIndex) { + uint32_t length = aItemsArray.Length(); + +@@ -138,10 +137,10 @@ + uint32_t oldLength = mItems.Length(); + + uint32_t newLength = aNewValue.Length(); +- if (newLength > nsISVGPoint::MaxListIndex()) { ++ if (newLength > DOMSVGPoint::MaxListIndex()) { + // It's safe to get out of sync with our internal list as long as we have + // FEWER items than it does. +- newLength = nsISVGPoint::MaxListIndex(); ++ newLength = DOMSVGPoint::MaxListIndex(); + } + + RefPtr kungFuDeathGrip; +@@ -222,7 +221,7 @@ + } + } + +-already_AddRefed DOMSVGPointList::Initialize(nsISVGPoint& aNewItem, ++already_AddRefed DOMSVGPointList::Initialize(DOMSVGPoint& aNewItem, + ErrorResult& aError) { + if (IsAnimValList()) { + aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); +@@ -237,9 +236,8 @@ + // clone of aNewItem, it would actually insert aNewItem. To prevent that + // from happening we have to do the clone here, if necessary. + +- nsCOMPtr domItem = &aNewItem; +- if (domItem->HasOwner() || domItem->IsReadonly() || +- domItem->IsTranslatePoint()) { ++ RefPtr domItem = &aNewItem; ++ if (domItem->HasOwner() || domItem->IsTranslatePoint()) { + domItem = domItem->Copy(); // must do this before changing anything! + } + +@@ -249,17 +247,17 @@ + return InsertItemBefore(*domItem, 0, aError); + } + +-already_AddRefed DOMSVGPointList::GetItem(uint32_t index, ++already_AddRefed DOMSVGPointList::GetItem(uint32_t index, + ErrorResult& error) { + bool found; +- RefPtr item = IndexedGetter(index, found, error); ++ RefPtr item = IndexedGetter(index, found, error); + if (!found) { + error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + } + return item.forget(); + } + +-already_AddRefed DOMSVGPointList::IndexedGetter( ++already_AddRefed DOMSVGPointList::IndexedGetter( + uint32_t aIndex, bool& aFound, ErrorResult& aError) { + if (IsAnimValList()) { + Element()->FlushAnimations(); +@@ -271,22 +269,21 @@ + return nullptr; + } + +-already_AddRefed DOMSVGPointList::InsertItemBefore( +- nsISVGPoint& aNewItem, uint32_t aIndex, ErrorResult& aError) { ++already_AddRefed DOMSVGPointList::InsertItemBefore( ++ DOMSVGPoint& aNewItem, uint32_t aIndex, ErrorResult& aError) { + if (IsAnimValList()) { + aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); + return nullptr; + } + + aIndex = std::min(aIndex, LengthNoFlush()); +- if (aIndex >= nsISVGPoint::MaxListIndex()) { ++ if (aIndex >= DOMSVGPoint::MaxListIndex()) { + aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return nullptr; + } + +- nsCOMPtr domItem = &aNewItem; +- if (domItem->HasOwner() || domItem->IsReadonly() || +- domItem->IsTranslatePoint()) { ++ RefPtr domItem = &aNewItem; ++ if (domItem->HasOwner() || domItem->IsTranslatePoint()) { + domItem = domItem->Copy(); // must do this before changing anything! + } + +@@ -323,8 +320,8 @@ + return domItem.forget(); + } + +-already_AddRefed DOMSVGPointList::ReplaceItem( +- nsISVGPoint& aNewItem, uint32_t aIndex, ErrorResult& aError) { ++already_AddRefed DOMSVGPointList::ReplaceItem( ++ DOMSVGPoint& aNewItem, uint32_t aIndex, ErrorResult& aError) { + if (IsAnimValList()) { + aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); + return nullptr; +@@ -335,9 +332,8 @@ + return nullptr; + } + +- nsCOMPtr domItem = &aNewItem; +- if (domItem->HasOwner() || domItem->IsReadonly() || +- domItem->IsTranslatePoint()) { ++ RefPtr domItem = &aNewItem; ++ if (domItem->HasOwner() || domItem->IsTranslatePoint()) { + domItem = domItem->Copy(); // must do this before changing anything! + } + +@@ -358,7 +354,7 @@ + return domItem.forget(); + } + +-already_AddRefed DOMSVGPointList::RemoveItem(uint32_t aIndex, ++already_AddRefed DOMSVGPointList::RemoveItem(uint32_t aIndex, + ErrorResult& aError) { + if (IsAnimValList()) { + aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); +@@ -377,7 +373,7 @@ + MaybeRemoveItemFromAnimValListAt(aIndex); + + // We have to return the removed item, so get it, creating it if necessary: +- RefPtr result = GetItemAt(aIndex); ++ RefPtr result = GetItemAt(aIndex); + + // Notify the DOM item of removal *before* modifying the lists so that the + // DOM item can copy its *old* value: +@@ -391,13 +387,13 @@ + return result.forget(); + } + +-already_AddRefed DOMSVGPointList::GetItemAt(uint32_t aIndex) { ++already_AddRefed DOMSVGPointList::GetItemAt(uint32_t aIndex) { + MOZ_ASSERT(aIndex < mItems.Length()); + + if (!mItems[aIndex]) { + mItems[aIndex] = new DOMSVGPoint(this, aIndex, IsAnimValList()); + } +- RefPtr result = mItems[aIndex]; ++ RefPtr result = mItems[aIndex]; + return result.forget(); + } + +diff --git a/dom/svg/SVGGeometryElement.h b/dom/svg/SVGGeometryElement.h +--- a/dom/svg/SVGGeometryElement.h ++++ b/dom/svg/SVGGeometryElement.h +@@ -10,7 +10,6 @@ + #include "mozilla/dom/SVGGraphicsElement.h" + #include "mozilla/gfx/2D.h" + #include "SVGAnimatedNumber.h" +-#include "nsISVGPoint.h" + + namespace mozilla { + +@@ -32,6 +31,7 @@ + namespace dom { + + class DOMSVGAnimatedNumber; ++class DOMSVGPoint; + + using SVGGeometryElementBase = mozilla::dom::SVGGraphicsElement; + +@@ -219,7 +219,7 @@ + bool IsPointInFill(const DOMPointInit& aPoint); + bool IsPointInStroke(const DOMPointInit& aPoint); + float GetTotalLength(); +- already_AddRefed GetPointAtLength(float distance, ++ already_AddRefed GetPointAtLength(float distance, + ErrorResult& rv); + + protected: +diff --git a/dom/svg/SVGGeometryElement.cpp b/dom/svg/SVGGeometryElement.cpp +--- a/dom/svg/SVGGeometryElement.cpp ++++ b/dom/svg/SVGGeometryElement.cpp +@@ -226,7 +226,7 @@ + return flat ? flat->ComputeLength() : 0.f; + } + +-already_AddRefed SVGGeometryElement::GetPointAtLength( ++already_AddRefed SVGGeometryElement::GetPointAtLength( + float distance, ErrorResult& rv) { + RefPtr path = GetOrBuildPathForMeasuring(); + if (!path) { +@@ -234,7 +234,7 @@ + return nullptr; + } + +- nsCOMPtr point = new DOMSVGPoint(path->ComputePointAtLength( ++ RefPtr point = new DOMSVGPoint(path->ComputePointAtLength( + clamped(distance, 0.f, path->ComputeLength()))); + return point.forget(); + } +diff --git a/dom/svg/SVGPathElement.h b/dom/svg/SVGPathElement.h +--- a/dom/svg/SVGPathElement.h ++++ b/dom/svg/SVGPathElement.h +@@ -20,8 +20,6 @@ + + namespace dom { + +-class nsISVGPoint; +- + using SVGPathElementBase = SVGGeometryElement; + + class SVGPathElement final : public SVGPathElementBase { +diff --git a/dom/svg/SVGPointList.h b/dom/svg/SVGPointList.h +--- a/dom/svg/SVGPointList.h ++++ b/dom/svg/SVGPointList.h +@@ -23,7 +23,6 @@ + namespace dom { + class DOMSVGPoint; + class DOMSVGPointList; +-class nsISVGPoint; + } // namespace dom + + /** +@@ -36,7 +35,6 @@ + * The DOM wrapper class for this class is DOMSVGPointList. + */ + class SVGPointList { +- friend class dom::nsISVGPoint; + friend class SVGAnimatedPointList; + friend class dom::DOMSVGPointList; + friend class dom::DOMSVGPoint; +diff --git a/dom/svg/SVGSVGElement.h b/dom/svg/SVGSVGElement.h +--- a/dom/svg/SVGSVGElement.h ++++ b/dom/svg/SVGSVGElement.h +@@ -25,6 +25,7 @@ + class DOMSVGAngle; + class DOMSVGLength; + class DOMSVGNumber; ++class DOMSVGPoint; + class SVGMatrix; + class SVGRect; + class SVGSVGElement; +@@ -40,35 +41,6 @@ + UniquePtr mTransforms; + }; + +-class DOMSVGTranslatePoint final : public nsISVGPoint { +- public: +- DOMSVGTranslatePoint(SVGPoint* aPt, SVGSVGElement* aElement) +- : nsISVGPoint(aPt, true), mElement(aElement) {} +- +- explicit DOMSVGTranslatePoint(DOMSVGTranslatePoint* aPt) +- : nsISVGPoint(&aPt->mPt, true), mElement(aPt->mElement) {} +- +- NS_DECL_ISUPPORTS_INHERITED +- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DOMSVGTranslatePoint, nsISVGPoint) +- +- virtual DOMSVGPoint* Copy() override; +- +- // WebIDL +- virtual float X() override { return mPt.GetX(); } +- virtual float Y() override { return mPt.GetY(); } +- virtual void SetX(float aValue, ErrorResult& rv) override; +- virtual void SetY(float aValue, ErrorResult& rv) override; +- virtual already_AddRefed MatrixTransform( +- const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) override; +- +- virtual nsISupports* GetParentObject() override; +- +- RefPtr mElement; +- +- private: +- ~DOMSVGTranslatePoint() = default; +-}; +- + using SVGSVGElementBase = SVGViewportElement; + + class SVGSVGElement final : public SVGSVGElementBase { +@@ -96,15 +68,11 @@ + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGSVGElement, SVGSVGElementBase) + +- /** +- * For use by zoom controls to allow currentScale, currentTranslate.x and +- * currentTranslate.y to be set by a single operation that dispatches a +- * single SVGZoom event (instead of one SVGZoom and two SVGScroll events). +- * +- * XXX SVGZoomEvent is no more, is this needed? ++ /* ++ * Send appropriate events and updates if our root scroll or translate ++ * has changed. + */ +- MOZ_CAN_RUN_SCRIPT_BOUNDARY void SetCurrentScaleTranslate(float s, float x, +- float y); ++ void ScaleOrTranslateChanged(bool aScaleUnchanged); + + // nsIContent interface + void GetEventTargetParent(EventChainPreVisitor& aVisitor) override; +@@ -121,8 +89,7 @@ + bool UseCurrentView(); + float CurrentScale(); + void SetCurrentScale(float aCurrentScale); +- already_AddRefed CurrentTranslate(); +- void SetCurrentTranslate(float x, float y); ++ already_AddRefed CurrentTranslate(); + uint32_t SuspendRedraw(uint32_t max_wait_milliseconds); + void UnsuspendRedraw(uint32_t suspend_handle_id); + void UnsuspendRedrawAll(); +@@ -136,7 +103,7 @@ + already_AddRefed CreateSVGNumber(); + already_AddRefed CreateSVGLength(); + already_AddRefed CreateSVGAngle(); +- already_AddRefed CreateSVGPoint(); ++ already_AddRefed CreateSVGPoint(); + already_AddRefed CreateSVGMatrix(); + already_AddRefed CreateSVGRect(); + already_AddRefed CreateSVGTransform(); +@@ -236,13 +203,8 @@ + // for all outermost elements (not nested elements). + UniquePtr mTimedDocumentRoot; + +- // zoom and pan +- // IMPORTANT: see the comment in RecordCurrentScaleTranslate before writing +- // code to change any of these! + SVGPoint mCurrentTranslate; + float mCurrentScale; +- SVGPoint mPreviousTranslate; +- float mPreviousScale; + + // For outermost elements created from parsing, animation is started by + // the onload event in accordance with the SVG spec, but for elements +diff --git a/dom/svg/SVGSVGElement.cpp b/dom/svg/SVGSVGElement.cpp +--- a/dom/svg/SVGSVGElement.cpp ++++ b/dom/svg/SVGSVGElement.cpp +@@ -46,54 +46,6 @@ + SVGElement::EnumInfo SVGSVGElement::sEnumInfo[1] = { + {nsGkAtoms::zoomAndPan, sZoomAndPanMap, SVG_ZOOMANDPAN_MAGNIFY}}; + +-NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMSVGTranslatePoint, nsISVGPoint, mElement) +- +-NS_IMPL_ADDREF_INHERITED(DOMSVGTranslatePoint, nsISVGPoint) +-NS_IMPL_RELEASE_INHERITED(DOMSVGTranslatePoint, nsISVGPoint) +- +-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGTranslatePoint) +- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY +- // We have to qualify nsISVGPoint because NS_GET_IID looks for a class in the +- // global namespace +- NS_INTERFACE_MAP_ENTRY(nsISVGPoint) +- NS_INTERFACE_MAP_ENTRY(nsISupports) +-NS_INTERFACE_MAP_END +- +-DOMSVGPoint* DOMSVGTranslatePoint::Copy() { +- return new DOMSVGPoint(ToPoint(mPt)); +-} +- +-nsISupports* DOMSVGTranslatePoint::GetParentObject() { +- return ToSupports(mElement); +-} +- +-void DOMSVGTranslatePoint::SetX(float aValue, ErrorResult& rv) { +- mElement->SetCurrentTranslate(aValue, mPt.GetY()); +-} +- +-void DOMSVGTranslatePoint::SetY(float aValue, ErrorResult& rv) { +- mElement->SetCurrentTranslate(mPt.GetX(), aValue); +-} +- +-already_AddRefed DOMSVGTranslatePoint::MatrixTransform( +- const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) { +- RefPtr matrix = +- DOMMatrixReadOnly::FromMatrix(GetParentObject(), aMatrix, aRv); +- if (aRv.Failed()) { +- return nullptr; +- } +- +- const auto* matrix2D = matrix->GetInternal2D(); +- if (!matrix2D->IsFinite()) { +- aRv.ThrowTypeError("MatrixTransform matrix"); +- return nullptr; +- } +- +- nsCOMPtr point = +- new DOMSVGPoint(ToPoint(matrix2D->TransformPoint(mPt))); +- return point.forget(); +-} +- + JSObject* SVGSVGElement::WrapNode(JSContext* aCx, + JS::Handle aGivenProto) { + return SVGSVGElement_Binding::Wrap(aCx, this, aGivenProto); +@@ -134,8 +86,6 @@ + : SVGSVGElementBase(std::move(aNodeInfo)), + mCurrentTranslate(0.0f, 0.0f), + mCurrentScale(1.0f), +- mPreviousTranslate(0.0f, 0.0f), +- mPreviousScale(1.0f), + mStartAnimationOnBindToTree(aFromParser == NOT_FROM_PARSER || + aFromParser == FROM_PARSER_FRAGMENT || + aFromParser == FROM_PARSER_XSLT), +@@ -173,14 +123,19 @@ + #define CURRENT_SCALE_MIN 0.0625f + + void SVGSVGElement::SetCurrentScale(float aCurrentScale) { +- SetCurrentScaleTranslate(aCurrentScale, mCurrentTranslate.GetX(), +- mCurrentTranslate.GetY()); ++ // Prevent bizarre behaviour and maxing out of CPU and memory by clamping ++ aCurrentScale = clamped(aCurrentScale, CURRENT_SCALE_MIN, CURRENT_SCALE_MAX); ++ ++ if (aCurrentScale == mCurrentScale) { ++ return; ++ } ++ mCurrentScale = aCurrentScale; ++ ++ ScaleOrTranslateChanged(false); + } + +-already_AddRefed SVGSVGElement::CurrentTranslate() { +- nsCOMPtr point = +- new DOMSVGTranslatePoint(&mCurrentTranslate, this); +- return point.forget(); ++already_AddRefed SVGSVGElement::CurrentTranslate() { ++ return DOMSVGPoint::GetTranslateTearOff(&mCurrentTranslate, this); + } + + uint32_t SVGSVGElement::SuspendRedraw(uint32_t max_wait_milliseconds) { +@@ -269,7 +224,7 @@ + return do_AddRef(new DOMSVGAngle(this)); + } + +-already_AddRefed SVGSVGElement::CreateSVGPoint() { ++already_AddRefed SVGSVGElement::CreateSVGPoint() { + return do_AddRef(new DOMSVGPoint(Point(0, 0))); + } + +@@ -290,45 +245,14 @@ + return do_AddRef(new DOMSVGTransform(matrix, rv)); + } + +-//---------------------------------------------------------------------- +-// helper method for implementing SetCurrentScale/Translate +- +-void SVGSVGElement::SetCurrentScaleTranslate(float s, float x, float y) { +- if (s == mCurrentScale && x == mCurrentTranslate.GetX() && +- y == mCurrentTranslate.GetY()) { +- return; +- } +- +- // Prevent bizarre behaviour and maxing out of CPU and memory by clamping +- if (s < CURRENT_SCALE_MIN) +- s = CURRENT_SCALE_MIN; +- else if (s > CURRENT_SCALE_MAX) +- s = CURRENT_SCALE_MAX; +- +- // IMPORTANT: If either mCurrentTranslate *or* mCurrentScale is changed then +- // mPreviousTranslate_x, mPreviousTranslate_y *and* mPreviousScale must all +- // be updated otherwise SVGZoomEvents will end up with invalid data. I.e. an +- // SVGZoomEvent's properties previousScale and previousTranslate must contain +- // the state of currentScale and currentTranslate immediately before the +- // change that caused the event's dispatch, which is *not* necessarily the +- // same thing as the values of currentScale and currentTranslate prior to +- // their own last change. +- // +- // XXX This comment is out-of-date due to removal of SVGZoomEvent. Can we +- // remove some of this code? +- mPreviousScale = mCurrentScale; +- mPreviousTranslate = mCurrentTranslate; +- +- mCurrentScale = s; +- mCurrentTranslate = SVGPoint(x, y); +- ++void SVGSVGElement::ScaleOrTranslateChanged(bool aScaleUnchanged) { + // now dispatch the appropriate event if we are the root element + Document* doc = GetUncomposedDoc(); + if (doc) { + RefPtr presShell = doc->GetPresShell(); + if (presShell && IsRoot()) { +- nsEventStatus status = nsEventStatus_eIgnore; +- if (mPreviousScale == mCurrentScale) { ++ if (aScaleUnchanged) { ++ nsEventStatus status = nsEventStatus_eIgnore; + WidgetEvent svgScrollEvent(true, eSVGScroll); + presShell->HandleDOMEventWithTarget(this, &svgScrollEvent, &status); + } +@@ -337,10 +261,6 @@ + } + } + +-void SVGSVGElement::SetCurrentTranslate(float x, float y) { +- SetCurrentScaleTranslate(mCurrentScale, x, y); +-} +- + //---------------------------------------------------------------------- + // SVGZoomAndPanValues + uint16_t SVGSVGElement::ZoomAndPan() { +diff --git a/dom/svg/SVGTextContentElement.h b/dom/svg/SVGTextContentElement.h +--- a/dom/svg/SVGTextContentElement.h ++++ b/dom/svg/SVGTextContentElement.h +@@ -19,7 +19,7 @@ + namespace dom { + + struct DOMPointInit; +-class nsISVGPoint; ++class DOMSVGPoint; + class SVGRect; + + using SVGTextContentElementBase = SVGGraphicsElement; +@@ -40,10 +40,10 @@ + MOZ_CAN_RUN_SCRIPT + float GetSubStringLength(uint32_t charnum, uint32_t nchars, ErrorResult& rv); + MOZ_CAN_RUN_SCRIPT +- already_AddRefed GetStartPositionOfChar(uint32_t charnum, ++ already_AddRefed GetStartPositionOfChar(uint32_t charnum, + ErrorResult& rv); + MOZ_CAN_RUN_SCRIPT +- already_AddRefed GetEndPositionOfChar(uint32_t charnum, ++ already_AddRefed GetEndPositionOfChar(uint32_t charnum, + ErrorResult& rv); + MOZ_CAN_RUN_SCRIPT + already_AddRefed GetExtentOfChar(uint32_t charnum, ErrorResult& rv); +diff --git a/dom/svg/SVGTextContentElement.cpp b/dom/svg/SVGTextContentElement.cpp +--- a/dom/svg/SVGTextContentElement.cpp ++++ b/dom/svg/SVGTextContentElement.cpp +@@ -10,7 +10,7 @@ + #include "mozilla/dom/SVGTextContentElementBinding.h" + #include "mozilla/dom/SVGRect.h" + #include "nsBidiUtils.h" +-#include "nsISVGPoint.h" ++#include "DOMSVGPoint.h" + #include "nsTextFragment.h" + #include "nsTextFrameUtils.h" + #include "nsTextNode.h" +@@ -135,7 +135,7 @@ + return textFrame->GetSubStringLength(this, charnum, nchars, rv); + } + +-already_AddRefed SVGTextContentElement::GetStartPositionOfChar( ++already_AddRefed SVGTextContentElement::GetStartPositionOfChar( + uint32_t charnum, ErrorResult& rv) { + SVGTextFrame* textFrame = GetSVGTextFrame(); + if (!textFrame) { +@@ -146,7 +146,7 @@ + return textFrame->GetStartPositionOfChar(this, charnum, rv); + } + +-already_AddRefed SVGTextContentElement::GetEndPositionOfChar( ++already_AddRefed SVGTextContentElement::GetEndPositionOfChar( + uint32_t charnum, ErrorResult& rv) { + SVGTextFrame* textFrame = GetSVGTextFrame(); + if (!textFrame) { +diff --git a/dom/svg/SVGViewportElement.h b/dom/svg/SVGViewportElement.h +--- a/dom/svg/SVGViewportElement.h ++++ b/dom/svg/SVGViewportElement.h +@@ -17,7 +17,7 @@ + #include "SVGAnimatedPreserveAspectRatio.h" + #include "SVGAnimatedViewBox.h" + #include "SVGGraphicsElement.h" +-#include "nsISVGPoint.h" ++#include "SVGPoint.h" + #include "SVGPreserveAspectRatio.h" + + namespace mozilla { +diff --git a/dom/svg/moz.build b/dom/svg/moz.build +--- a/dom/svg/moz.build ++++ b/dom/svg/moz.build +@@ -119,7 +119,6 @@ + 'DOMSVGStringList.cpp', + 'DOMSVGTransform.cpp', + 'DOMSVGTransformList.cpp', +- 'nsISVGPoint.cpp', + 'SVGAElement.cpp', + 'SVGAnimatedBoolean.cpp', + 'SVGAnimatedClass.cpp', +diff --git a/dom/svg/nsISVGPoint.h b/dom/svg/nsISVGPoint.h +deleted file mode 100644 +--- a/dom/svg/nsISVGPoint.h ++++ /dev/null +@@ -1,172 +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/. */ +- +-#pragma once +- +-#include "nsCycleCollectionParticipant.h" +-#include "nsWrapperCache.h" +-#include "mozilla/dom/SVGPointBinding.h" +-#include "DOMSVGPointList.h" +- +-// {d6b6c440-af8d-40ee-856b-02a317cab275} +-#define MOZILLA_NSISVGPOINT_IID \ +- { \ +- 0xd6b6c440, 0xaf8d, 0x40ee, { \ +- 0x85, 0x6b, 0x02, 0xa3, 0x17, 0xca, 0xb2, 0x75 \ +- } \ +- } +- +-#define MOZ_SVG_LIST_INDEX_BIT_COUNT 29 +- +-namespace mozilla { +- +-namespace dom { +-struct DOMMatrix2DInit; +- +-/** +- * Class nsISVGPoint +- * +- * This class creates the DOM objects that wrap internal SVGPoint objects. +- * An nsISVGPoint can be either a DOMSVGPoint or a DOMSVGTranslatePoint +- */ +-class nsISVGPoint : public nsISupports, public nsWrapperCache { +- public: +- NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_NSISVGPOINT_IID) +- NS_DECL_CYCLE_COLLECTING_ISUPPORTS +- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsISVGPoint) +- +- /** +- * Generic ctor for DOMSVGPoint objects that are created for an attribute. +- */ +- explicit nsISVGPoint() +- : mList(nullptr), +- mListIndex(0), +- mIsReadonly(false), +- mIsAnimValItem(false), +- mIsTranslatePoint(false) {} +- +- explicit nsISVGPoint(SVGPoint* aPt, bool aIsTranslatePoint) +- : mList(nullptr), +- mListIndex(0), +- mIsReadonly(false), +- mIsAnimValItem(false), +- mIsTranslatePoint(aIsTranslatePoint) { +- mPt.mX = aPt->GetX(); +- mPt.mY = aPt->GetY(); +- } +- +- protected: +- virtual ~nsISVGPoint() { +- // 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->mItems[mListIndex] = nullptr; +- } +- } +- +- public: +- /** +- * Creates an unowned copy of this object's point as a DOMSVGPoint. +- */ +- virtual DOMSVGPoint* Copy() = 0; +- +- SVGPoint ToSVGPoint() const { +- return HasOwner() ? const_cast(this)->InternalItem() : mPt; +- } +- +- bool IsInList() const { return !!mList; } +- +- /** +- * In future, if this class is used for non-list points, this will be +- * different to IsInList(). "Owner" here means that the instance has an +- * internal counterpart from which it gets its values. (A better name may +- * be HasWrappee().) +- */ +- bool HasOwner() const { return !!mList; } +- +- bool IsTranslatePoint() const { return mIsTranslatePoint; } +- +- /** +- * 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 DOMSVGPointList).) +- */ +- void InsertingIntoList(DOMSVGPointList* 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(); +- +- bool IsReadonly() const { return mIsReadonly; } +- void SetReadonly(bool aReadonly) { mIsReadonly = aReadonly; } +- +- // WebIDL +- virtual float X() = 0; +- virtual void SetX(float aX, ErrorResult& rv) = 0; +- virtual float Y() = 0; +- virtual void SetY(float aY, ErrorResult& rv) = 0; +- virtual already_AddRefed MatrixTransform( +- const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) = 0; +- virtual JSObject* WrapObject(JSContext* cx, +- JS::Handle aGivenProto) override { +- return SVGPoint_Binding::Wrap(cx, this, aGivenProto); +- } +- +- virtual nsISupports* GetParentObject() = 0; +- +- protected: +-#ifdef DEBUG +- bool IndexIsValid(); +-#endif +- +- RefPtr 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 mIsReadonly : 1; // These flags are uint32_t because MSVC won't +- uint32_t mIsAnimValItem : 1; // pack otherwise. +- uint32_t mIsTranslatePoint : 1; +- +- /** +- * Get a reference to the internal SVGPoint 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. +- */ +- SVGPoint& InternalItem(); +- +- // The following member is only used when we're not in a list: +- SVGPoint mPt; +-}; +- +-NS_DEFINE_STATIC_IID_ACCESSOR(nsISVGPoint, MOZILLA_NSISVGPOINT_IID) +- +-} // namespace dom +-} // namespace mozilla +- +-#undef MOZ_SVG_LIST_INDEX_BIT_COUNT +diff --git a/dom/svg/nsISVGPoint.cpp b/dom/svg/nsISVGPoint.cpp +deleted file mode 100644 +--- a/dom/svg/nsISVGPoint.cpp ++++ /dev/null +@@ -1,81 +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 "nsISVGPoint.h" +-#include "DOMSVGPointList.h" +-#include "SVGPoint.h" +-#include "SVGElement.h" +-#include "nsError.h" +-#include "mozilla/dom/SVGPointBinding.h" +- +-// See the architecture comment in DOMSVGPointList.h. +- +-namespace mozilla { +-namespace dom { +- +-// 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(nsISVGPoint) +- +-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsISVGPoint) +- // We may not belong to a list, so we must null check tmp->mList. +- if (tmp->mList) { +- tmp->mList->mItems[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(nsISVGPoint) +- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList) +-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END +- +-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsISVGPoint) +- NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER +-NS_IMPL_CYCLE_COLLECTION_TRACE_END +- +-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsISVGPoint) +-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsISVGPoint) +- +-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsISVGPoint) +- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY +- NS_INTERFACE_MAP_ENTRY(nsISVGPoint) +- NS_INTERFACE_MAP_ENTRY(nsISupports) +-NS_INTERFACE_MAP_END +- +-void nsISVGPoint::InsertingIntoList(DOMSVGPointList* aList, uint32_t aListIndex, +- bool aIsAnimValItem) { +- MOZ_ASSERT(!HasOwner(), "Inserting item that already has an owner"); +- +- mList = aList; +- mListIndex = aListIndex; +- mIsReadonly = false; +- mIsAnimValItem = aIsAnimValItem; +- +- MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPoint!"); +-} +- +-void nsISVGPoint::RemovingFromList() { +- mPt = InternalItem(); +- mList = nullptr; +- MOZ_ASSERT(!mIsReadonly, "mIsReadonly set for list"); +- mIsAnimValItem = false; +-} +- +-SVGPoint& nsISVGPoint::InternalItem() { +- return mList->InternalList().mItems[mListIndex]; +-} +- +-#ifdef DEBUG +-bool nsISVGPoint::IndexIsValid() { +- return mListIndex < mList->InternalList().Length(); +-} +-#endif +- +-} // namespace dom +-} // namespace mozilla +diff --git a/layout/reftests/svg/current-translate-01.svg b/layout/reftests/svg/current-translate-01.svg +new file mode 100644 +--- /dev/null ++++ b/layout/reftests/svg/current-translate-01.svg +@@ -0,0 +1,8 @@ ++ ++ ++ ++ ++ +diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list +--- a/layout/reftests/svg/reftest.list ++++ b/layout/reftests/svg/reftest.list +@@ -65,6 +65,8 @@ + == border-radius-01.html pass.svg + == mask-image-filter-transform.html mask-image-filter-transform-ref.html + ++== current-translate-01.svg pass.svg ++ + == clip-01.svg pass.svg + == clip-02a.svg clip-02-ref.svg + == clip-02b.svg clip-02-ref.svg +diff --git a/layout/svg/SVGTextFrame.h b/layout/svg/SVGTextFrame.h +--- a/layout/svg/SVGTextFrame.h ++++ b/layout/svg/SVGTextFrame.h +@@ -33,7 +33,7 @@ + + namespace dom { + struct DOMPointInit; +-class nsISVGPoint; ++class DOMSVGPoint; + class SVGRect; + class SVGGeometryElement; + } // namespace dom +@@ -244,9 +244,9 @@ + int32_t GetCharNumAtPosition(nsIContent* aContent, + const dom::DOMPointInit& aPoint); + +- already_AddRefed GetStartPositionOfChar( ++ already_AddRefed GetStartPositionOfChar( + nsIContent* aContent, uint32_t aCharNum, ErrorResult& aRv); +- already_AddRefed GetEndPositionOfChar(nsIContent* aContent, ++ already_AddRefed GetEndPositionOfChar(nsIContent* aContent, + uint32_t aCharNum, + ErrorResult& aRv); + already_AddRefed GetExtentOfChar(nsIContent* aContent, +diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp +--- a/layout/svg/SVGTextFrame.cpp ++++ b/layout/svg/SVGTextFrame.cpp +@@ -3829,7 +3829,7 @@ + * Implements the SVG DOM GetStartPositionOfChar method for the specified + * text content element. + */ +-already_AddRefed SVGTextFrame::GetStartPositionOfChar( ++already_AddRefed SVGTextFrame::GetStartPositionOfChar( + nsIContent* aContent, uint32_t aCharNum, ErrorResult& aRv) { + nsIFrame* kid = PrincipalChildList().FirstChild(); + if (kid->IsSubtreeDirty()) { +@@ -3913,7 +3913,7 @@ + * Implements the SVG DOM GetEndPositionOfChar method for the specified + * text content element. + */ +-already_AddRefed SVGTextFrame::GetEndPositionOfChar( ++already_AddRefed SVGTextFrame::GetEndPositionOfChar( + nsIContent* aContent, uint32_t aCharNum, ErrorResult& aRv) { + nsIFrame* kid = PrincipalChildList().FirstChild(); + if (kid->IsSubtreeDirty()) { + diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -922,12 +922,12 @@ 'nativeType': 'mozilla::dom::DOMSVGPathSegList', 'headerFile': 'DOMSVGPathSegList.h' }, 'SVGPoint': { - 'nativeType': 'mozilla::dom::nsISVGPoint', - 'headerFile': 'nsISVGPoint.h' + 'nativeType': 'mozilla::dom::DOMSVGPoint', + 'headerFile': 'DOMSVGPoint.h' }, 'SVGPointList': { 'nativeType': 'mozilla::dom::DOMSVGPointList', 'headerFile': 'DOMSVGPointList.h' diff --git a/dom/svg/DOMSVGPoint.h b/dom/svg/DOMSVGPoint.h --- a/dom/svg/DOMSVGPoint.h +++ b/dom/svg/DOMSVGPoint.h @@ -33,11 +33,11 @@ * 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. */ -class DOMSVGPoint final : public nsISVGPoint { +class DOMSVGPoint final : public nsWrapperCache { friend class AutoChangePointNotifier; typedef mozilla::gfx::Point Point; public: diff --git a/dom/svg/DOMSVGPoint.h.rej b/dom/svg/DOMSVGPoint.h.rej new file mode 100644 --- /dev/null +++ b/dom/svg/DOMSVGPoint.h.rej @@ -0,0 +1,186 @@ +--- DOMSVGPoint.h ++++ DOMSVGPoint.h +@@ -8,18 +8,21 @@ + #define DOM_SVG_DOMSVGPOINT_H_ + + #include "DOMSVGPointList.h" +-#include "mozilla/gfx/2D.h" ++#include "nsCycleCollectionParticipant.h" + #include "nsDebug.h" +-#include "nsISVGPoint.h" + #include "SVGPoint.h" ++#include "nsWrapperCache.h" + #include "mozilla/Attributes.h" + #include "mozilla/FloatingPoint.h" ++#include "mozilla/dom/SVGSVGElement.h" ++#include "mozilla/gfx/2D.h" ++ ++#define MOZ_SVG_LIST_INDEX_BIT_COUNT 30 + + namespace mozilla { + + namespace dom { + struct DOMMatrix2DInit; +-class SVGElement; + + /** + * Class DOMSVGPoint +@@ -45,46 +48,134 @@ + * Generic ctor for DOMSVGPoint objects that are created for an attribute. + */ + DOMSVGPoint(DOMSVGPointList* aList, uint32_t aListIndex, bool aIsAnimValItem) +- : nsISVGPoint() { +- mList = aList; +- mListIndex = aListIndex; +- mIsAnimValItem = aIsAnimValItem; +- ++ : mList(aList), ++ mVal(nullptr), ++ mListIndex(aListIndex), ++ mIsAnimValItem(aIsAnimValItem), ++ mIsTranslatePoint(false) { + // These shifts are in sync with the members. + MOZ_ASSERT(aList && aListIndex <= MaxListIndex(), "bad arg"); + + MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPoint!"); + } + +- explicit DOMSVGPoint(const DOMSVGPoint* aPt = nullptr) : nsISVGPoint() { +- if (aPt) { +- mPt = aPt->ToSVGPoint(); +- } ++ // Constructor for unowned points and SVGSVGElement.createSVGPoint ++ explicit DOMSVGPoint(const Point& aPt) ++ : mList(nullptr), mIsAnimValItem(false), mIsTranslatePoint(false) { ++ // In this case we own mVal ++ mVal = new SVGPoint(aPt.x, aPt.y); + } + +- explicit DOMSVGPoint(const Point& aPt) : nsISVGPoint() { +- mPt.mX = aPt.x; +- mPt.mY = aPt.y; +- NS_ASSERTION(IsFinite(mPt.mX) && IsFinite(mPt.mY), +- "DOMSVGPoint coords are not finite"); ++ private: ++ // The translate of an SVGSVGElement ++ explicit DOMSVGPoint(SVGPoint* aPt, SVGSVGElement* aSVGSVGElement) ++ : mList(nullptr), ++ mVal(aPt), ++ mSVGSVGElement(aSVGSVGElement), ++ mIsAnimValItem(false), ++ mIsTranslatePoint(true) {} ++ ++ virtual ~DOMSVGPoint() { CleanupWeakRefs(); } ++ ++ public: ++ NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMSVGPoint) ++ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMSVGPoint) ++ ++ static already_AddRefed GetTranslateTearOff( ++ SVGPoint* aVal, SVGSVGElement* aSVGSVGElement); ++ ++ bool IsInList() const { return !!mList; } ++ ++ /** ++ * "Owner" here means that the instance has an ++ * internal counterpart from which it gets its values. (A better name may ++ * be HasWrappee().) ++ */ ++ bool HasOwner() const { return !!mList || mIsTranslatePoint; } ++ ++ bool IsTranslatePoint() const { return mIsTranslatePoint; } ++ ++ /** ++ * 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 DOMSVGPointList).) ++ */ ++ void InsertingIntoList(DOMSVGPointList* 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(); ++ ++ SVGPoint ToSVGPoint() { return InternalItem(); } ++ + // WebIDL +- virtual float X() override; +- virtual void SetX(float aX, ErrorResult& rv) override; +- virtual float Y() override; +- virtual void SetY(float aY, ErrorResult& rv) override; +- virtual already_AddRefed MatrixTransform( +- const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) override; +- nsISupports* GetParentObject() override { return mList; } ++ float X(); ++ void SetX(float aX, ErrorResult& rv); ++ float Y(); ++ void SetY(float aY, ErrorResult& rv); ++ already_AddRefed MatrixTransform(const DOMMatrix2DInit& aMatrix, ++ ErrorResult& aRv); ++ ++ nsISupports* GetParentObject() { return Element(); } ++ ++ JSObject* WrapObject(JSContext* cx, ++ JS::Handle aGivenProto) override; ++ ++ DOMSVGPoint* Copy() { return new DOMSVGPoint(InternalItem()); } ++ ++ private: ++#ifdef DEBUG ++ bool IndexIsValid(); ++#endif ++ ++ SVGElement* Element() { return mList ? mList->Element() : mSVGSVGElement; } + +- virtual DOMSVGPoint* Copy() override { return new DOMSVGPoint(this); } ++ /** ++ * Clears soon-to-be-invalid weak references in external objects that were ++ * set up during the creation of this object. This should be called during ++ * destruction and during cycle collection. ++ */ ++ void CleanupWeakRefs(); ++ ++ /** ++ * Get a reference to the internal SVGPoint list item that this DOM wrapper ++ * object currently wraps. ++ */ ++ SVGPoint& InternalItem(); + +- protected: +- SVGElement* Element() { return mList->Element(); } ++ RefPtr mList; ++ ++ SVGPoint* mVal; // If mIsTranslatePoint is true, the element owns ++ // the value. Otherwise we do. ++ RefPtr mSVGSVGElement; ++ ++ // 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; // These flags are uint32_t because MSVC won't ++ uint32_t mIsTranslatePoint : 1; // pack otherwise. + }; + + } // namespace dom + } // namespace mozilla + ++#undef MOZ_SVG_LIST_INDEX_BIT_COUNT ++ + #endif // DOM_SVG_DOMSVGPOINT_H_ diff --git a/dom/svg/DOMSVGPoint.cpp b/dom/svg/DOMSVGPoint.cpp --- a/dom/svg/DOMSVGPoint.cpp +++ b/dom/svg/DOMSVGPoint.cpp @@ -20,10 +20,37 @@ using namespace mozilla::gfx; namespace mozilla { namespace dom { +static SVGAttrTearoffTable sSVGTranslateTearOffTable; + +// 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(DOMSVGPoint) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPoint) + tmp->CleanupWeakRefs(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mList) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mSVGSVGElement) + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPoint) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSVGSVGElement) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPoint) + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMSVGPoint, AddRef) +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGPoint, Release) + //---------------------------------------------------------------------- // Helper class: AutoChangePointNotifier // Stack-based helper class to pair calls to WillChangePointList and // DidChangePointList. class MOZ_RAII AutoChangePointNotifier : public mozAutoDocUpdate { @@ -32,21 +59,27 @@ DOMSVGPoint* aPoint MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mozAutoDocUpdate(aPoint->Element()->GetComposedDoc(), true), mPoint(aPoint) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; MOZ_ASSERT(mPoint, "Expecting non-null point"); - MOZ_ASSERT(mPoint->HasOwner(), - "Expecting list to have an owner for notification"); - mEmptyOrOldValue = mPoint->Element()->WillChangePointList(*this); + if (mPoint->IsInList()) { + mEmptyOrOldValue = mPoint->Element()->WillChangePointList(*this); + } } ~AutoChangePointNotifier() { - mPoint->Element()->DidChangePointList(mEmptyOrOldValue, *this); - // Null check mPoint->mList, since DidChangePointList can run script, - // potentially removing mPoint from its list. - if (mPoint->mList && mPoint->mList->AttrIsAnimating()) { - mPoint->Element()->AnimationNeedsResample(); + if (mPoint->IsInList()) { + mPoint->Element()->DidChangePointList(mEmptyOrOldValue, *this); + // Null check mPoint->mList, since DidChangePointList can run script, + // potentially removing mPoint from its list. + if (mPoint->mList && mPoint->mList->AttrIsAnimating()) { + mPoint->Element()->AnimationNeedsResample(); + } + } else if (mPoint->mIsTranslatePoint) { + nsContentUtils::AddScriptRunner(NewRunnableMethod( + "dom::SVGSVGElement::ScaleOrTranslateChanged", mPoint->mSVGSVGElement, + &SVGSVGElement::ScaleOrTranslateChanged, true)); } } private: DOMSVGPoint* const mPoint; diff --git a/dom/svg/DOMSVGPoint.cpp.rej b/dom/svg/DOMSVGPoint.cpp.rej new file mode 100644 --- /dev/null +++ b/dom/svg/DOMSVGPoint.cpp.rej @@ -0,0 +1,179 @@ +--- DOMSVGPoint.cpp ++++ DOMSVGPoint.cpp +@@ -9,11 +9,9 @@ + #include "DOMSVGPointList.h" + #include "gfx2DGlue.h" + #include "mozAutoDocUpdate.h" +-#include "nsCOMPtr.h" + #include "nsError.h" +-#include "SVGPoint.h" + #include "mozilla/dom/DOMMatrix.h" +-#include "mozilla/dom/SVGElement.h" ++#include "mozilla/dom/SVGPointBinding.h" + + // See the architecture comment in DOMSVGPointList.h. + +@@ -54,55 +85,59 @@ + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + }; + ++JSObject* DOMSVGPoint::WrapObject(JSContext* aCx, ++ JS::Handle aGivenProto) { ++ return SVGPoint_Binding::Wrap(aCx, this, aGivenProto); ++} ++ + float DOMSVGPoint::X() { +- if (mIsAnimValItem && HasOwner()) { +- Element()->FlushAnimations(); // May make HasOwner() == false ++ if (mIsAnimValItem && IsInList()) { ++ Element()->FlushAnimations(); // May make IsInList() == false + } +- return HasOwner() ? InternalItem().mX : mPt.mX; ++ return InternalItem().mX; + } + + void DOMSVGPoint::SetX(float aX, ErrorResult& rv) { +- if (mIsAnimValItem || mIsReadonly) { ++ if (mIsAnimValItem) { + rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); + return; + } + +- if (HasOwner()) { +- if (InternalItem().mX == aX) { +- return; +- } +- AutoChangePointNotifier notifier(this); +- InternalItem().mX = aX; ++ auto& val = InternalItem(); ++ ++ if (val.mX == aX) { + return; + } +- mPt.mX = aX; ++ ++ AutoChangePointNotifier notifier(this); ++ ++ val.mX = aX; + } + + float DOMSVGPoint::Y() { +- if (mIsAnimValItem && HasOwner()) { +- Element()->FlushAnimations(); // May make HasOwner() == false ++ if (mIsAnimValItem && IsInList()) { ++ Element()->FlushAnimations(); // May make IsInList() == false + } +- return HasOwner() ? InternalItem().mY : mPt.mY; ++ return InternalItem().mY; + } + + void DOMSVGPoint::SetY(float aY, ErrorResult& rv) { +- if (mIsAnimValItem || mIsReadonly) { ++ if (mIsAnimValItem) { + rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); + return; + } ++ auto& val = InternalItem(); ++ ++ if (val.mY == aY) { ++ return; ++ } + +- if (HasOwner()) { +- if (InternalItem().mY == aY) { +- return; +- } +- AutoChangePointNotifier notifier(this); +- InternalItem().mY = aY; +- return; +- } +- mPt.mY = aY; ++ AutoChangePointNotifier notifier(this); ++ ++ val.mY = aY; + } + +-already_AddRefed DOMSVGPoint::MatrixTransform( ++already_AddRefed DOMSVGPoint::MatrixTransform( + const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) { + RefPtr matrix = + DOMMatrixReadOnly::FromMatrix(GetParentObject(), aMatrix, aRv); +@@ -114,10 +149,76 @@ + aRv.ThrowTypeError("MatrixTransform matrix"); + return nullptr; + } +- auto pt = matrix2D->TransformPoint(HasOwner() ? InternalItem() : mPt); +- nsCOMPtr newPoint = new DOMSVGPoint(ToPoint(pt)); ++ auto pt = matrix2D->TransformPoint(InternalItem()); ++ RefPtr newPoint = new DOMSVGPoint(ToPoint(pt)); + return newPoint.forget(); + } + ++void DOMSVGPoint::InsertingIntoList(DOMSVGPointList* aList, uint32_t aListIndex, ++ bool aIsAnimValItem) { ++ MOZ_ASSERT(!IsInList(), "Inserting item that is already in a list"); ++ MOZ_ASSERT(!mIsTranslatePoint, "Inserting item that is a currentTranslate"); ++ ++ delete mVal; ++ mVal = nullptr; ++ ++ mList = aList; ++ mListIndex = aListIndex; ++ mIsAnimValItem = aIsAnimValItem; ++ ++ MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPoint!"); ++} ++ ++void DOMSVGPoint::RemovingFromList() { ++ mVal = new SVGPoint(InternalItem()); ++ mList = nullptr; ++ mIsAnimValItem = false; ++} ++ ++SVGPoint& DOMSVGPoint::InternalItem() { ++ return mList ? mList->InternalList().mItems[mListIndex] : *mVal; ++} ++ ++already_AddRefed DOMSVGPoint::GetTranslateTearOff( ++ SVGPoint* aVal, SVGSVGElement* aSVGSVGElement) { ++ RefPtr domPoint = sSVGTranslateTearOffTable.GetTearoff(aVal); ++ if (!domPoint) { ++ domPoint = new DOMSVGPoint(aVal, aSVGSVGElement); ++ sSVGTranslateTearOffTable.AddTearoff(aVal, domPoint); ++ } ++ ++ return domPoint.forget(); ++} ++ ++void DOMSVGPoint::CleanupWeakRefs() { ++ // Our mList's weak ref to us must be nulled out when we die (or when we're ++ // cycle collected), so we that don't leave behind a pointer to ++ // free / soon-to-be-free memory. ++ if (mList) { ++ MOZ_ASSERT(mList->mItems[mListIndex] == this, ++ "Clearing out the wrong list index...?"); ++ mList->mItems[mListIndex] = nullptr; ++ } ++ ++ if (mVal) { ++ if (mIsTranslatePoint) { ++ // Similarly, we must update the tearoff table to remove its (non-owning) ++ // pointer to mVal. ++ sSVGTranslateTearOffTable.RemoveTearoff(mVal); ++ } else { ++ // In this case we own mVal ++ delete mVal; ++ } ++ mVal = nullptr; ++ } ++ mSVGSVGElement = nullptr; ++} ++ ++#ifdef DEBUG ++bool DOMSVGPoint::IndexIsValid() { ++ return mListIndex < mList->InternalList().Length(); ++} ++#endif ++ + } // namespace dom + } // namespace mozilla diff --git a/dom/svg/DOMSVGPointList.h b/dom/svg/DOMSVGPointList.h --- a/dom/svg/DOMSVGPointList.h +++ b/dom/svg/DOMSVGPointList.h @@ -21,11 +21,10 @@ class SVGAnimatedPointList; namespace dom { class DOMSVGPoint; -class nsISVGPoint; /** * Class DOMSVGPointList * * This class is used to create the DOM tearoff objects that wrap internal @@ -50,11 +49,10 @@ * * Our DOM items are created lazily on demand as and when script requests them. */ class DOMSVGPointList final : public nsISupports, public nsWrapperCache { friend class AutoChangePointListNotifier; - friend class nsISVGPoint; friend class DOMSVGPoint; public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGPointList) @@ -135,24 +133,24 @@ Element()->FlushAnimations(); } return LengthNoFlush(); } void Clear(ErrorResult& aError); - already_AddRefed Initialize(nsISVGPoint& aNewItem, + already_AddRefed Initialize(DOMSVGPoint& aNewItem, ErrorResult& aError); - already_AddRefed GetItem(uint32_t index, ErrorResult& error); - already_AddRefed IndexedGetter(uint32_t index, bool& found, + already_AddRefed GetItem(uint32_t index, ErrorResult& error); + already_AddRefed IndexedGetter(uint32_t index, bool& found, ErrorResult& error); - already_AddRefed InsertItemBefore(nsISVGPoint& aNewItem, + already_AddRefed InsertItemBefore(DOMSVGPoint& aNewItem, uint32_t aIndex, ErrorResult& aError); - already_AddRefed ReplaceItem(nsISVGPoint& aNewItem, + already_AddRefed ReplaceItem(DOMSVGPoint& aNewItem, uint32_t aIndex, ErrorResult& aError); - already_AddRefed RemoveItem(uint32_t aIndex, + already_AddRefed RemoveItem(uint32_t aIndex, ErrorResult& aError); - already_AddRefed AppendItem(nsISVGPoint& aNewItem, + already_AddRefed AppendItem(DOMSVGPoint& aNewItem, ErrorResult& aError) { return InsertItemBefore(aNewItem, LengthNoFlush(), aError); } uint32_t Length() const { return NumberOfItems(); } @@ -183,24 +181,24 @@ */ SVGPointList& InternalList() const; SVGAnimatedPointList& InternalAList() const; - /// Returns the nsISVGPoint at aIndex, creating it if necessary. - already_AddRefed GetItemAt(uint32_t aIndex); + /// Returns the DOMSVGPoint at aIndex, creating it if necessary. + already_AddRefed GetItemAt(uint32_t aIndex); void MaybeInsertNullInAnimValListAt(uint32_t aIndex); void MaybeRemoveItemFromAnimValListAt(uint32_t aIndex); void RemoveFromTearoffTable(); - // Weak refs to our nsISVGPoint items. The items are friends and take care + // Weak refs to our DOMSVGPoint items. The items are friends and take care // of clearing our pointer to them when they die. - FallibleTArray mItems; + FallibleTArray mItems; // Strong ref to our element to keep it alive. We hold this not only for - // ourself, but also for our nsISVGPoint items too. + // ourself, but also for our DOMSVGPoint items too. RefPtr mElement; bool mIsAnimValList; }; diff --git a/dom/svg/DOMSVGPointList.cpp b/dom/svg/DOMSVGPointList.cpp --- a/dom/svg/DOMSVGPointList.cpp +++ b/dom/svg/DOMSVGPointList.cpp @@ -4,11 +4,10 @@ * 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 "DOMSVGPointList.h" -#include "nsCOMPtr.h" #include "nsContentUtils.h" #include "DOMSVGPoint.h" #include "nsError.h" #include "SVGAnimatedPointList.h" #include "SVGAttrTearoffTable.h" @@ -21,11 +20,11 @@ // local helper functions namespace { void UpdateListIndicesFromIndex( - FallibleTArray& aItemsArray, + FallibleTArray& aItemsArray, uint32_t aStartingIndex) { uint32_t length = aItemsArray.Length(); for (uint32_t i = aStartingIndex; i < length; ++i) { if (aItemsArray[i]) { @@ -136,14 +135,14 @@ // DOMSVGLengthList::InternalBaseValListWillChangeTo applies here too! uint32_t oldLength = mItems.Length(); uint32_t newLength = aNewValue.Length(); - if (newLength > nsISVGPoint::MaxListIndex()) { + if (newLength > DOMSVGPoint::MaxListIndex()) { // It's safe to get out of sync with our internal list as long as we have // FEWER items than it does. - newLength = nsISVGPoint::MaxListIndex(); + newLength = DOMSVGPoint::MaxListIndex(); } RefPtr kungFuDeathGrip; if (newLength < oldLength) { // RemovingFromList() might clear last reference to |this|. @@ -220,11 +219,11 @@ InternalList().Clear(); } } -already_AddRefed DOMSVGPointList::Initialize(nsISVGPoint& aNewItem, +already_AddRefed DOMSVGPointList::Initialize(DOMSVGPoint& aNewItem, ErrorResult& aError) { if (IsAnimValList()) { aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return nullptr; } @@ -235,33 +234,32 @@ // 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. - nsCOMPtr domItem = &aNewItem; - if (domItem->HasOwner() || domItem->IsReadonly() || - domItem->IsTranslatePoint()) { + RefPtr domItem = &aNewItem; + if (domItem->HasOwner() || domItem->IsTranslatePoint()) { domItem = domItem->Copy(); // must do this before changing anything! } ErrorResult rv; Clear(rv); MOZ_ASSERT(!rv.Failed()); return InsertItemBefore(*domItem, 0, aError); } -already_AddRefed DOMSVGPointList::GetItem(uint32_t index, +already_AddRefed DOMSVGPointList::GetItem(uint32_t index, ErrorResult& error) { bool found; - RefPtr item = IndexedGetter(index, found, error); + RefPtr item = IndexedGetter(index, found, error); if (!found) { error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); } return item.forget(); } -already_AddRefed DOMSVGPointList::IndexedGetter( +already_AddRefed DOMSVGPointList::IndexedGetter( uint32_t aIndex, bool& aFound, ErrorResult& aError) { if (IsAnimValList()) { Element()->FlushAnimations(); } aFound = aIndex < LengthNoFlush(); @@ -269,26 +267,25 @@ return GetItemAt(aIndex); } return nullptr; } -already_AddRefed DOMSVGPointList::InsertItemBefore( - nsISVGPoint& aNewItem, uint32_t aIndex, ErrorResult& aError) { +already_AddRefed DOMSVGPointList::InsertItemBefore( + DOMSVGPoint& aNewItem, uint32_t aIndex, ErrorResult& aError) { if (IsAnimValList()) { aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return nullptr; } aIndex = std::min(aIndex, LengthNoFlush()); - if (aIndex >= nsISVGPoint::MaxListIndex()) { + if (aIndex >= DOMSVGPoint::MaxListIndex()) { aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return nullptr; } - nsCOMPtr domItem = &aNewItem; - if (domItem->HasOwner() || domItem->IsReadonly() || - domItem->IsTranslatePoint()) { + RefPtr domItem = &aNewItem; + if (domItem->HasOwner() || domItem->IsTranslatePoint()) { domItem = domItem->Copy(); // must do this before changing anything! } // Ensure we have enough memory so we can avoid complex error handling below: if (!mItems.SetCapacity(mItems.Length() + 1, fallible) || @@ -321,25 +318,24 @@ UpdateListIndicesFromIndex(mItems, aIndex + 1); return domItem.forget(); } -already_AddRefed DOMSVGPointList::ReplaceItem( - nsISVGPoint& aNewItem, uint32_t aIndex, ErrorResult& aError) { +already_AddRefed DOMSVGPointList::ReplaceItem( + DOMSVGPoint& 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; } - nsCOMPtr domItem = &aNewItem; - if (domItem->HasOwner() || domItem->IsReadonly() || - domItem->IsTranslatePoint()) { + RefPtr domItem = &aNewItem; + if (domItem->HasOwner() || domItem->IsTranslatePoint()) { domItem = domItem->Copy(); // must do this before changing anything! } AutoChangePointListNotifier notifier(this); if (mItems[aIndex]) { @@ -356,11 +352,11 @@ domItem->InsertingIntoList(this, aIndex, IsAnimValList()); return domItem.forget(); } -already_AddRefed DOMSVGPointList::RemoveItem(uint32_t aIndex, +already_AddRefed DOMSVGPointList::RemoveItem(uint32_t aIndex, ErrorResult& aError) { if (IsAnimValList()) { aError.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return nullptr; } @@ -375,11 +371,11 @@ // Do this *before* touching InternalList() so the removed item can get its // internal value. MaybeRemoveItemFromAnimValListAt(aIndex); // We have to return the removed item, so get it, creating it if necessary: - RefPtr result = GetItemAt(aIndex); + RefPtr result = GetItemAt(aIndex); // Notify the DOM item of removal *before* modifying the lists so that the // DOM item can copy its *old* value: mItems[aIndex]->RemovingFromList(); @@ -389,17 +385,17 @@ UpdateListIndicesFromIndex(mItems, aIndex); return result.forget(); } -already_AddRefed DOMSVGPointList::GetItemAt(uint32_t aIndex) { +already_AddRefed DOMSVGPointList::GetItemAt(uint32_t aIndex) { MOZ_ASSERT(aIndex < mItems.Length()); if (!mItems[aIndex]) { mItems[aIndex] = new DOMSVGPoint(this, aIndex, IsAnimValList()); } - RefPtr result = mItems[aIndex]; + RefPtr result = mItems[aIndex]; return result.forget(); } void DOMSVGPointList::MaybeInsertNullInAnimValListAt(uint32_t aIndex) { MOZ_ASSERT(!IsAnimValList(), "call from baseVal to animVal"); diff --git a/dom/svg/SVGGeometryElement.h b/dom/svg/SVGGeometryElement.h --- a/dom/svg/SVGGeometryElement.h +++ b/dom/svg/SVGGeometryElement.h @@ -8,11 +8,10 @@ #define mozilla_dom_SVGGeometryElement_h #include "mozilla/dom/SVGGraphicsElement.h" #include "mozilla/gfx/2D.h" #include "SVGAnimatedNumber.h" -#include "nsISVGPoint.h" namespace mozilla { struct SVGMark { enum Type { @@ -30,10 +29,11 @@ }; namespace dom { class DOMSVGAnimatedNumber; +class DOMSVGPoint; typedef mozilla::dom::SVGGraphicsElement SVGGeometryElementBase; class SVGGeometryElement : public SVGGeometryElementBase { protected: @@ -217,11 +217,11 @@ // WebIDL already_AddRefed PathLength(); bool IsPointInFill(const DOMPointInit& aPoint); bool IsPointInStroke(const DOMPointInit& aPoint); float GetTotalLength(); - already_AddRefed GetPointAtLength(float distance, + already_AddRefed GetPointAtLength(float distance, ErrorResult& rv); protected: // SVGElement method virtual NumberAttributesInfo GetNumberInfo() override; diff --git a/dom/svg/SVGGeometryElement.cpp b/dom/svg/SVGGeometryElement.cpp --- a/dom/svg/SVGGeometryElement.cpp +++ b/dom/svg/SVGGeometryElement.cpp @@ -222,19 +222,19 @@ float SVGGeometryElement::GetTotalLength() { RefPtr flat = GetOrBuildPathForMeasuring(); return flat ? flat->ComputeLength() : 0.f; } -already_AddRefed SVGGeometryElement::GetPointAtLength( +already_AddRefed SVGGeometryElement::GetPointAtLength( float distance, ErrorResult& rv) { RefPtr path = GetOrBuildPathForMeasuring(); if (!path) { rv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsCOMPtr point = new DOMSVGPoint(path->ComputePointAtLength( + RefPtr point = new DOMSVGPoint(path->ComputePointAtLength( clamped(distance, 0.f, path->ComputeLength()))); return point.forget(); } float SVGGeometryElement::GetPathLengthScale(PathLengthScaleForType aFor) { diff --git a/dom/svg/SVGPathElement.h.rej b/dom/svg/SVGPathElement.h.rej new file mode 100644 --- /dev/null +++ b/dom/svg/SVGPathElement.h.rej @@ -0,0 +1,11 @@ +--- SVGPathElement.h ++++ SVGPathElement.h +@@ -20,8 +20,6 @@ + + namespace dom { + +-class nsISVGPoint; +- + using SVGPathElementBase = SVGGeometryElement; + + class SVGPathElement final : public SVGPathElementBase { diff --git a/dom/svg/SVGPointList.h b/dom/svg/SVGPointList.h --- a/dom/svg/SVGPointList.h +++ b/dom/svg/SVGPointList.h @@ -21,11 +21,10 @@ namespace mozilla { namespace dom { class DOMSVGPoint; class DOMSVGPointList; -class nsISVGPoint; } // namespace dom /** * ATTENTION! WARNING! WATCH OUT!! * @@ -34,11 +33,10 @@ * locked down. * * The DOM wrapper class for this class is DOMSVGPointList. */ class SVGPointList { - friend class dom::nsISVGPoint; friend class SVGAnimatedPointList; friend class dom::DOMSVGPointList; friend class dom::DOMSVGPoint; public: diff --git a/dom/svg/SVGSVGElement.h b/dom/svg/SVGSVGElement.h --- a/dom/svg/SVGSVGElement.h +++ b/dom/svg/SVGSVGElement.h @@ -22,10 +22,11 @@ namespace dom { class DOMSVGAngle; class DOMSVGLength; class DOMSVGNumber; +class DOMSVGPoint; class SVGMatrix; class SVGRect; class SVGSVGElement; // Stores svgView arguments of SVG fragment identifiers. @@ -93,19 +94,15 @@ public: // interfaces: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGSVGElement, SVGSVGElementBase) - /** - * For use by zoom controls to allow currentScale, currentTranslate.x and - * currentTranslate.y to be set by a single operation that dispatches a - * single SVGZoom event (instead of one SVGZoom and two SVGScroll events). - * - * XXX SVGZoomEvent is no more, is this needed? + /* + * Send appropriate events and updates if our root scroll or translate + * has changed. */ - MOZ_CAN_RUN_SCRIPT_BOUNDARY void SetCurrentScaleTranslate(float s, float x, - float y); + void ScaleOrTranslateChanged(bool aScaleUnchanged); // nsIContent interface void GetEventTargetParent(EventChainPreVisitor& aVisitor) override; virtual bool IsEventAttributeNameInternal(nsAtom* aName) override; @@ -118,12 +115,11 @@ already_AddRefed Width(); already_AddRefed Height(); bool UseCurrentView(); float CurrentScale(); void SetCurrentScale(float aCurrentScale); - already_AddRefed CurrentTranslate(); - void SetCurrentTranslate(float x, float y); + already_AddRefed CurrentTranslate(); uint32_t SuspendRedraw(uint32_t max_wait_milliseconds); void UnsuspendRedraw(uint32_t suspend_handle_id); void UnsuspendRedrawAll(); void ForceRedraw(); void PauseAnimations(); @@ -133,11 +129,11 @@ void SetCurrentTime(float seconds); void DeselectAll(); already_AddRefed CreateSVGNumber(); already_AddRefed CreateSVGLength(); already_AddRefed CreateSVGAngle(); - already_AddRefed CreateSVGPoint(); + already_AddRefed CreateSVGPoint(); already_AddRefed CreateSVGMatrix(); already_AddRefed CreateSVGRect(); already_AddRefed CreateSVGTransform(); already_AddRefed CreateSVGTransformFromMatrix( SVGMatrix& matrix); @@ -233,17 +229,12 @@ // The time container for animations within this SVG document fragment. Set // for all outermost elements (not nested elements). UniquePtr mTimedDocumentRoot; - // zoom and pan - // IMPORTANT: see the comment in RecordCurrentScaleTranslate before writing - // code to change any of these! SVGPoint mCurrentTranslate; float mCurrentScale; - SVGPoint mPreviousTranslate; - float mPreviousScale; // For outermost elements created from parsing, animation is started by // the onload event in accordance with the SVG spec, but for elements // created by script or promoted from inner to outermost we need // to manually kick off animation when they are bound to the tree. diff --git a/dom/svg/SVGSVGElement.h.rej b/dom/svg/SVGSVGElement.h.rej new file mode 100644 --- /dev/null +++ b/dom/svg/SVGSVGElement.h.rej @@ -0,0 +1,38 @@ +--- SVGSVGElement.h ++++ SVGSVGElement.h +@@ -40,35 +41,6 @@ + UniquePtr mTransforms; + }; + +-class DOMSVGTranslatePoint final : public nsISVGPoint { +- public: +- DOMSVGTranslatePoint(SVGPoint* aPt, SVGSVGElement* aElement) +- : nsISVGPoint(aPt, true), mElement(aElement) {} +- +- explicit DOMSVGTranslatePoint(DOMSVGTranslatePoint* aPt) +- : nsISVGPoint(&aPt->mPt, true), mElement(aPt->mElement) {} +- +- NS_DECL_ISUPPORTS_INHERITED +- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DOMSVGTranslatePoint, nsISVGPoint) +- +- virtual DOMSVGPoint* Copy() override; +- +- // WebIDL +- virtual float X() override { return mPt.GetX(); } +- virtual float Y() override { return mPt.GetY(); } +- virtual void SetX(float aValue, ErrorResult& rv) override; +- virtual void SetY(float aValue, ErrorResult& rv) override; +- virtual already_AddRefed MatrixTransform( +- const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) override; +- +- virtual nsISupports* GetParentObject() override; +- +- RefPtr mElement; +- +- private: +- ~DOMSVGTranslatePoint() = default; +-}; +- + using SVGSVGElementBase = SVGViewportElement; + + class SVGSVGElement final : public SVGSVGElementBase { diff --git a/dom/svg/SVGSVGElement.cpp b/dom/svg/SVGSVGElement.cpp --- a/dom/svg/SVGSVGElement.cpp +++ b/dom/svg/SVGSVGElement.cpp @@ -124,12 +124,10 @@ already_AddRefed&& aNodeInfo, FromParser aFromParser) : SVGSVGElementBase(std::move(aNodeInfo)), mCurrentTranslate(0.0f, 0.0f), mCurrentScale(1.0f), - mPreviousTranslate(0.0f, 0.0f), - mPreviousScale(1.0f), mStartAnimationOnBindToTree(aFromParser == NOT_FROM_PARSER || aFromParser == FROM_PARSER_FRAGMENT || aFromParser == FROM_PARSER_XSLT), mImageNeedsTransformInvalidation(false) {} @@ -163,18 +161,23 @@ #define CURRENT_SCALE_MAX 16.0f #define CURRENT_SCALE_MIN 0.0625f void SVGSVGElement::SetCurrentScale(float aCurrentScale) { - SetCurrentScaleTranslate(aCurrentScale, mCurrentTranslate.GetX(), - mCurrentTranslate.GetY()); + // Prevent bizarre behaviour and maxing out of CPU and memory by clamping + aCurrentScale = clamped(aCurrentScale, CURRENT_SCALE_MIN, CURRENT_SCALE_MAX); + + if (aCurrentScale == mCurrentScale) { + return; + } + mCurrentScale = aCurrentScale; + + ScaleOrTranslateChanged(false); } -already_AddRefed SVGSVGElement::CurrentTranslate() { - nsCOMPtr point = - new DOMSVGTranslatePoint(&mCurrentTranslate, this); - return point.forget(); +already_AddRefed SVGSVGElement::CurrentTranslate() { + return DOMSVGPoint::GetTranslateTearOff(&mCurrentTranslate, this); } uint32_t SVGSVGElement::SuspendRedraw(uint32_t max_wait_milliseconds) { // suspendRedraw is a no-op in Mozilla, so it doesn't matter what // we return @@ -280,61 +283,26 @@ already_AddRefed SVGSVGElement::CreateSVGTransformFromMatrix( SVGMatrix& matrix) { return do_AddRef(new DOMSVGTransform(matrix.GetMatrix())); } -//---------------------------------------------------------------------- -// helper method for implementing SetCurrentScale/Translate - -void SVGSVGElement::SetCurrentScaleTranslate(float s, float x, float y) { - if (s == mCurrentScale && x == mCurrentTranslate.GetX() && - y == mCurrentTranslate.GetY()) { - return; - } - - // Prevent bizarre behaviour and maxing out of CPU and memory by clamping - if (s < CURRENT_SCALE_MIN) - s = CURRENT_SCALE_MIN; - else if (s > CURRENT_SCALE_MAX) - s = CURRENT_SCALE_MAX; - - // IMPORTANT: If either mCurrentTranslate *or* mCurrentScale is changed then - // mPreviousTranslate_x, mPreviousTranslate_y *and* mPreviousScale must all - // be updated otherwise SVGZoomEvents will end up with invalid data. I.e. an - // SVGZoomEvent's properties previousScale and previousTranslate must contain - // the state of currentScale and currentTranslate immediately before the - // change that caused the event's dispatch, which is *not* necessarily the - // same thing as the values of currentScale and currentTranslate prior to - // their own last change. - // - // XXX This comment is out-of-date due to removal of SVGZoomEvent. Can we - // remove some of this code? - mPreviousScale = mCurrentScale; - mPreviousTranslate = mCurrentTranslate; - - mCurrentScale = s; - mCurrentTranslate = SVGPoint(x, y); - +void SVGSVGElement::ScaleOrTranslateChanged(bool aScaleUnchanged) { // now dispatch the appropriate event if we are the root element Document* doc = GetUncomposedDoc(); if (doc) { RefPtr presShell = doc->GetPresShell(); if (presShell && IsRoot()) { - nsEventStatus status = nsEventStatus_eIgnore; - if (mPreviousScale == mCurrentScale) { + if (aScaleUnchanged) { + nsEventStatus status = nsEventStatus_eIgnore; WidgetEvent svgScrollEvent(true, eSVGScroll); presShell->HandleDOMEventWithTarget(this, &svgScrollEvent, &status); } InvalidateTransformNotifyFrame(); } } } -void SVGSVGElement::SetCurrentTranslate(float x, float y) { - SetCurrentScaleTranslate(mCurrentScale, x, y); -} - //---------------------------------------------------------------------- // SVGZoomAndPanValues uint16_t SVGSVGElement::ZoomAndPan() { return mEnumAttributes[ZOOMANDPAN].GetAnimValue(); } diff --git a/dom/svg/SVGSVGElement.cpp.rej b/dom/svg/SVGSVGElement.cpp.rej new file mode 100644 --- /dev/null +++ b/dom/svg/SVGSVGElement.cpp.rej @@ -0,0 +1,66 @@ +--- SVGSVGElement.cpp ++++ SVGSVGElement.cpp +@@ -46,54 +46,6 @@ + SVGElement::EnumInfo SVGSVGElement::sEnumInfo[1] = { + {nsGkAtoms::zoomAndPan, sZoomAndPanMap, SVG_ZOOMANDPAN_MAGNIFY}}; + +-NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMSVGTranslatePoint, nsISVGPoint, mElement) +- +-NS_IMPL_ADDREF_INHERITED(DOMSVGTranslatePoint, nsISVGPoint) +-NS_IMPL_RELEASE_INHERITED(DOMSVGTranslatePoint, nsISVGPoint) +- +-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGTranslatePoint) +- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY +- // We have to qualify nsISVGPoint because NS_GET_IID looks for a class in the +- // global namespace +- NS_INTERFACE_MAP_ENTRY(nsISVGPoint) +- NS_INTERFACE_MAP_ENTRY(nsISupports) +-NS_INTERFACE_MAP_END +- +-DOMSVGPoint* DOMSVGTranslatePoint::Copy() { +- return new DOMSVGPoint(ToPoint(mPt)); +-} +- +-nsISupports* DOMSVGTranslatePoint::GetParentObject() { +- return ToSupports(mElement); +-} +- +-void DOMSVGTranslatePoint::SetX(float aValue, ErrorResult& rv) { +- mElement->SetCurrentTranslate(aValue, mPt.GetY()); +-} +- +-void DOMSVGTranslatePoint::SetY(float aValue, ErrorResult& rv) { +- mElement->SetCurrentTranslate(mPt.GetX(), aValue); +-} +- +-already_AddRefed DOMSVGTranslatePoint::MatrixTransform( +- const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) { +- RefPtr matrix = +- DOMMatrixReadOnly::FromMatrix(GetParentObject(), aMatrix, aRv); +- if (aRv.Failed()) { +- return nullptr; +- } +- +- const auto* matrix2D = matrix->GetInternal2D(); +- if (!matrix2D->IsFinite()) { +- aRv.ThrowTypeError("MatrixTransform matrix"); +- return nullptr; +- } +- +- nsCOMPtr point = +- new DOMSVGPoint(ToPoint(matrix2D->TransformPoint(mPt))); +- return point.forget(); +-} +- + JSObject* SVGSVGElement::WrapNode(JSContext* aCx, + JS::Handle aGivenProto) { + return SVGSVGElement_Binding::Wrap(aCx, this, aGivenProto); +@@ -269,7 +224,7 @@ + return do_AddRef(new DOMSVGAngle(this)); + } + +-already_AddRefed SVGSVGElement::CreateSVGPoint() { ++already_AddRefed SVGSVGElement::CreateSVGPoint() { + return do_AddRef(new DOMSVGPoint(Point(0, 0))); + } + diff --git a/dom/svg/SVGTextContentElement.h b/dom/svg/SVGTextContentElement.h --- a/dom/svg/SVGTextContentElement.h +++ b/dom/svg/SVGTextContentElement.h @@ -17,11 +17,11 @@ namespace mozilla { namespace dom { struct DOMPointInit; -class nsISVGPoint; +class DOMSVGPoint; class SVGRect; typedef SVGGraphicsElement SVGTextContentElementBase; class SVGTextContentElement : public SVGTextContentElementBase { @@ -38,14 +38,14 @@ MOZ_CAN_RUN_SCRIPT void SelectSubString(uint32_t charnum, uint32_t nchars, ErrorResult& rv); MOZ_CAN_RUN_SCRIPT float GetSubStringLength(uint32_t charnum, uint32_t nchars, ErrorResult& rv); MOZ_CAN_RUN_SCRIPT - already_AddRefed GetStartPositionOfChar(uint32_t charnum, + already_AddRefed GetStartPositionOfChar(uint32_t charnum, ErrorResult& rv); MOZ_CAN_RUN_SCRIPT - already_AddRefed GetEndPositionOfChar(uint32_t charnum, + already_AddRefed GetEndPositionOfChar(uint32_t charnum, ErrorResult& rv); MOZ_CAN_RUN_SCRIPT already_AddRefed GetExtentOfChar(uint32_t charnum, ErrorResult& rv); MOZ_CAN_RUN_SCRIPT float GetRotationOfChar(uint32_t charnum, ErrorResult& rv); MOZ_CAN_RUN_SCRIPT int32_t GetCharNumAtPosition(const DOMPointInit& aPoint); diff --git a/dom/svg/SVGTextContentElement.cpp b/dom/svg/SVGTextContentElement.cpp --- a/dom/svg/SVGTextContentElement.cpp +++ b/dom/svg/SVGTextContentElement.cpp @@ -8,11 +8,11 @@ #include "mozilla/dom/SVGLengthBinding.h" #include "mozilla/dom/SVGTextContentElementBinding.h" #include "mozilla/dom/SVGRect.h" #include "nsBidiUtils.h" -#include "nsISVGPoint.h" +#include "DOMSVGPoint.h" #include "nsTextFragment.h" #include "nsTextFrameUtils.h" #include "nsTextNode.h" #include "SVGTextFrame.h" @@ -133,22 +133,22 @@ if (!textFrame) return 0.0f; return textFrame->GetSubStringLength(this, charnum, nchars, rv); } -already_AddRefed SVGTextContentElement::GetStartPositionOfChar( +already_AddRefed SVGTextContentElement::GetStartPositionOfChar( uint32_t charnum, ErrorResult& rv) { SVGTextFrame* textFrame = GetSVGTextFrame(); if (!textFrame) { rv.ThrowInvalidStateError("No layout information available for SVG text"); return nullptr; } return textFrame->GetStartPositionOfChar(this, charnum, rv); } -already_AddRefed SVGTextContentElement::GetEndPositionOfChar( +already_AddRefed SVGTextContentElement::GetEndPositionOfChar( uint32_t charnum, ErrorResult& rv) { SVGTextFrame* textFrame = GetSVGTextFrame(); if (!textFrame) { rv.ThrowInvalidStateError("No layout information available for SVG text"); return nullptr; diff --git a/dom/svg/SVGViewportElement.h.rej b/dom/svg/SVGViewportElement.h.rej new file mode 100644 --- /dev/null +++ b/dom/svg/SVGViewportElement.h.rej @@ -0,0 +1,11 @@ +--- SVGViewportElement.h ++++ SVGViewportElement.h +@@ -17,7 +17,7 @@ + #include "SVGAnimatedPreserveAspectRatio.h" + #include "SVGAnimatedViewBox.h" + #include "SVGGraphicsElement.h" +-#include "nsISVGPoint.h" ++#include "SVGPoint.h" + #include "SVGPreserveAspectRatio.h" + + namespace mozilla { diff --git a/dom/svg/moz.build b/dom/svg/moz.build --- a/dom/svg/moz.build +++ b/dom/svg/moz.build @@ -116,11 +116,10 @@ 'DOMSVGPoint.cpp', 'DOMSVGPointList.cpp', 'DOMSVGStringList.cpp', 'DOMSVGTransform.cpp', 'DOMSVGTransformList.cpp', - 'nsISVGPoint.cpp', 'SVGAElement.cpp', 'SVGAnimatedBoolean.cpp', 'SVGAnimatedClass.cpp', 'SVGAnimatedEnumeration.cpp', 'SVGAnimatedInteger.cpp', diff --git a/dom/svg/nsISVGPoint.h.rej b/dom/svg/nsISVGPoint.h.rej new file mode 100644 --- /dev/null +++ b/dom/svg/nsISVGPoint.h.rej @@ -0,0 +1,175 @@ +--- nsISVGPoint.h ++++ nsISVGPoint.h +@@ -1,172 +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/. */ +- +-#pragma once +- +-#include "nsCycleCollectionParticipant.h" +-#include "nsWrapperCache.h" +-#include "mozilla/dom/SVGPointBinding.h" +-#include "DOMSVGPointList.h" +- +-// {d6b6c440-af8d-40ee-856b-02a317cab275} +-#define MOZILLA_NSISVGPOINT_IID \ +- { \ +- 0xd6b6c440, 0xaf8d, 0x40ee, { \ +- 0x85, 0x6b, 0x02, 0xa3, 0x17, 0xca, 0xb2, 0x75 \ +- } \ +- } +- +-#define MOZ_SVG_LIST_INDEX_BIT_COUNT 29 +- +-namespace mozilla { +- +-namespace dom { +-struct DOMMatrix2DInit; +- +-/** +- * Class nsISVGPoint +- * +- * This class creates the DOM objects that wrap internal SVGPoint objects. +- * An nsISVGPoint can be either a DOMSVGPoint or a DOMSVGTranslatePoint +- */ +-class nsISVGPoint : public nsISupports, public nsWrapperCache { +- public: +- NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_NSISVGPOINT_IID) +- NS_DECL_CYCLE_COLLECTING_ISUPPORTS +- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsISVGPoint) +- +- /** +- * Generic ctor for DOMSVGPoint objects that are created for an attribute. +- */ +- explicit nsISVGPoint() +- : mList(nullptr), +- mListIndex(0), +- mIsReadonly(false), +- mIsAnimValItem(false), +- mIsTranslatePoint(false) {} +- +- explicit nsISVGPoint(SVGPoint* aPt, bool aIsTranslatePoint) +- : mList(nullptr), +- mListIndex(0), +- mIsReadonly(false), +- mIsAnimValItem(false), +- mIsTranslatePoint(aIsTranslatePoint) { +- mPt.mX = aPt->GetX(); +- mPt.mY = aPt->GetY(); +- } +- +- protected: +- virtual ~nsISVGPoint() { +- // 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->mItems[mListIndex] = nullptr; +- } +- } +- +- public: +- /** +- * Creates an unowned copy of this object's point as a DOMSVGPoint. +- */ +- virtual DOMSVGPoint* Copy() = 0; +- +- SVGPoint ToSVGPoint() const { +- return HasOwner() ? const_cast(this)->InternalItem() : mPt; +- } +- +- bool IsInList() const { return !!mList; } +- +- /** +- * In future, if this class is used for non-list points, this will be +- * different to IsInList(). "Owner" here means that the instance has an +- * internal counterpart from which it gets its values. (A better name may +- * be HasWrappee().) +- */ +- bool HasOwner() const { return !!mList; } +- +- bool IsTranslatePoint() const { return mIsTranslatePoint; } +- +- /** +- * 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 DOMSVGPointList).) +- */ +- void InsertingIntoList(DOMSVGPointList* 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(); +- +- bool IsReadonly() const { return mIsReadonly; } +- void SetReadonly(bool aReadonly) { mIsReadonly = aReadonly; } +- +- // WebIDL +- virtual float X() = 0; +- virtual void SetX(float aX, ErrorResult& rv) = 0; +- virtual float Y() = 0; +- virtual void SetY(float aY, ErrorResult& rv) = 0; +- virtual already_AddRefed MatrixTransform( +- const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) = 0; +- virtual JSObject* WrapObject(JSContext* cx, +- JS::Handle aGivenProto) override { +- return SVGPoint_Binding::Wrap(cx, this, aGivenProto); +- } +- +- virtual nsISupports* GetParentObject() = 0; +- +- protected: +-#ifdef DEBUG +- bool IndexIsValid(); +-#endif +- +- RefPtr 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 mIsReadonly : 1; // These flags are uint32_t because MSVC won't +- uint32_t mIsAnimValItem : 1; // pack otherwise. +- uint32_t mIsTranslatePoint : 1; +- +- /** +- * Get a reference to the internal SVGPoint 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. +- */ +- SVGPoint& InternalItem(); +- +- // The following member is only used when we're not in a list: +- SVGPoint mPt; +-}; +- +-NS_DEFINE_STATIC_IID_ACCESSOR(nsISVGPoint, MOZILLA_NSISVGPOINT_IID) +- +-} // namespace dom +-} // namespace mozilla +- +-#undef MOZ_SVG_LIST_INDEX_BIT_COUNT diff --git a/dom/svg/nsISVGPoint.cpp b/dom/svg/nsISVGPoint.cpp deleted file mode 100644 --- a/dom/svg/nsISVGPoint.cpp +++ /dev/null @@ -1,81 +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 "nsISVGPoint.h" -#include "DOMSVGPointList.h" -#include "SVGPoint.h" -#include "SVGElement.h" -#include "nsError.h" -#include "mozilla/dom/SVGPointBinding.h" - -// See the architecture comment in DOMSVGPointList.h. - -namespace mozilla { -namespace dom { - -// 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(nsISVGPoint) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsISVGPoint) - // We may not belong to a list, so we must null check tmp->mList. - if (tmp->mList) { - tmp->mList->mItems[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(nsISVGPoint) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsISVGPoint) - NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsISVGPoint) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsISVGPoint) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsISVGPoint) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISVGPoint) - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -void nsISVGPoint::InsertingIntoList(DOMSVGPointList* aList, uint32_t aListIndex, - bool aIsAnimValItem) { - MOZ_ASSERT(!HasOwner(), "Inserting item that already has an owner"); - - mList = aList; - mListIndex = aListIndex; - mIsReadonly = false; - mIsAnimValItem = aIsAnimValItem; - - MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPoint!"); -} - -void nsISVGPoint::RemovingFromList() { - mPt = InternalItem(); - mList = nullptr; - MOZ_ASSERT(!mIsReadonly, "mIsReadonly set for list"); - mIsAnimValItem = false; -} - -SVGPoint& nsISVGPoint::InternalItem() { - return mList->InternalList().mItems[mListIndex]; -} - -#ifdef DEBUG -bool nsISVGPoint::IndexIsValid() { - return mListIndex < mList->InternalList().Length(); -} -#endif - -} // namespace dom -} // namespace mozilla diff --git a/layout/reftests/svg/current-translate-01.svg b/layout/reftests/svg/current-translate-01.svg new file mode 100644 --- /dev/null +++ b/layout/reftests/svg/current-translate-01.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -58,10 +58,12 @@ fuzzy(0-11,0-7155) == blur-inside-clipPath.svg blur-inside-clipPath-ref.svg == border-radius-01.html pass.svg == mask-image-filter-transform.html mask-image-filter-transform-ref.html +== current-translate-01.svg pass.svg + == clip-01.svg pass.svg == clip-02a.svg clip-02-ref.svg == clip-02b.svg clip-02-ref.svg fuzzy-if(webrender,0-1,0-10000) == clip-surface-clone-01.svg clip-surface-clone-01-ref.svg == clip-use-element-01.svg pass.svg diff --git a/layout/svg/SVGTextFrame.h b/layout/svg/SVGTextFrame.h --- a/layout/svg/SVGTextFrame.h +++ b/layout/svg/SVGTextFrame.h @@ -31,11 +31,11 @@ struct TextRenderedRun; class TextRenderedRunIterator; namespace dom { struct DOMPointInit; -class nsISVGPoint; +class DOMSVGPoint; class SVGRect; class SVGGeometryElement; } // namespace dom /** diff --git a/layout/svg/SVGTextFrame.h.rej b/layout/svg/SVGTextFrame.h.rej new file mode 100644 --- /dev/null +++ b/layout/svg/SVGTextFrame.h.rej @@ -0,0 +1,14 @@ +--- SVGTextFrame.h ++++ SVGTextFrame.h +@@ -244,9 +244,9 @@ + int32_t GetCharNumAtPosition(nsIContent* aContent, + const dom::DOMPointInit& aPoint); + +- already_AddRefed GetStartPositionOfChar( ++ already_AddRefed GetStartPositionOfChar( + nsIContent* aContent, uint32_t aCharNum, ErrorResult& aRv); +- already_AddRefed GetEndPositionOfChar(nsIContent* aContent, ++ already_AddRefed GetEndPositionOfChar(nsIContent* aContent, + uint32_t aCharNum, + ErrorResult& aRv); + already_AddRefed GetExtentOfChar(nsIContent* aContent, diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp --- a/layout/svg/SVGTextFrame.cpp +++ b/layout/svg/SVGTextFrame.cpp @@ -3825,11 +3825,11 @@ /** * Implements the SVG DOM GetStartPositionOfChar method for the specified * text content element. */ -already_AddRefed SVGTextFrame::GetStartPositionOfChar( +already_AddRefed SVGTextFrame::GetStartPositionOfChar( nsIContent* aContent, uint32_t aCharNum, ErrorResult& aRv) { nsIFrame* kid = PrincipalChildList().FirstChild(); if (NS_SUBTREE_DIRTY(kid)) { // We're never reflowed if we're under a non-SVG element that is // never reflowed (such as the HTML 'caption' element). @@ -3909,11 +3909,11 @@ /** * Implements the SVG DOM GetEndPositionOfChar method for the specified * text content element. */ -already_AddRefed SVGTextFrame::GetEndPositionOfChar( +already_AddRefed SVGTextFrame::GetEndPositionOfChar( nsIContent* aContent, uint32_t aCharNum, ErrorResult& aRv) { nsIFrame* kid = PrincipalChildList().FirstChild(); if (NS_SUBTREE_DIRTY(kid)) { // We're never reflowed if we're under a non-SVG element that is // never reflowed (such as the HTML 'caption' element).