Bug 775730 - Ensure AttributeWillChange is always paired with AttributeDidChange. r=dholbert

This commit is contained in:
Robert Longson 2013-12-24 22:09:22 +00:00
parent 65b417b381
commit e3e8ce789d
23 changed files with 459 additions and 262 deletions

View File

@ -48,6 +48,38 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGLength)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLength)
NS_INTERFACE_MAP_END
//----------------------------------------------------------------------
// Helper class: AutoChangeLengthNotifier
// Stack-based helper class to pair calls to WillChangeLengthList and
// DidChangeLengthList.
class MOZ_STACK_CLASS AutoChangeLengthNotifier
{
public:
AutoChangeLengthNotifier(DOMSVGLength* aLength MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mLength(aLength)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
MOZ_ASSERT(mLength->HasOwner(),
"Expecting list to have an owner for notification");
mEmptyOrOldValue =
mLength->Element()->WillChangeLengthList(mLength->mAttrEnum);
}
~AutoChangeLengthNotifier()
{
mLength->Element()->DidChangeLengthList(mLength->mAttrEnum,
mEmptyOrOldValue);
if (mLength->mList->IsAnimating()) {
mLength->Element()->AnimationNeedsResample();
}
}
private:
DOMSVGLength* mLength;
nsAttrValue mEmptyOrOldValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
DOMSVGLength::DOMSVGLength(DOMSVGLengthList *aList,
uint8_t aAttrEnum,
uint32_t aListIndex,
@ -129,13 +161,11 @@ DOMSVGLength::SetValue(float aUserUnitValue)
aUserUnitValue) {
return NS_OK;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(mAttrEnum);
if (InternalItem().SetFromUserUnitValue(aUserUnitValue, Element(), Axis()))
{
Element()->DidChangeLengthList(mAttrEnum, emptyOrOldValue);
if (mList->mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
float uuPerUnit = InternalItem().GetUserUnitsPerUnit(Element(), Axis());
float newValue = aUserUnitValue / uuPerUnit;
if (uuPerUnit > 0 && NS_finite(newValue)) {
AutoChangeLengthNotifier notifier(this);
InternalItem().SetValueAndUnit(newValue, InternalItem().GetUnit());
return NS_OK;
}
} else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
@ -173,12 +203,8 @@ DOMSVGLength::SetValueInSpecifiedUnits(float aValue)
if (InternalItem().GetValueInCurrentUnits() == aValue) {
return NS_OK;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(mAttrEnum);
AutoChangeLengthNotifier notifier(this);
InternalItem().SetValueInCurrentUnits(aValue);
Element()->DidChangeLengthList(mAttrEnum, emptyOrOldValue);
if (mList->mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return NS_OK;
}
mValue = aValue;
@ -200,12 +226,8 @@ DOMSVGLength::SetValueAsString(const nsAString& aValue)
if (InternalItem() == value) {
return NS_OK;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(mAttrEnum);
AutoChangeLengthNotifier notifier(this);
InternalItem() = value;
Element()->DidChangeLengthList(mAttrEnum, emptyOrOldValue);
if (mList->mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return NS_OK;
}
mValue = value.GetValueInCurrentUnits();
@ -246,12 +268,8 @@ DOMSVGLength::NewValueSpecifiedUnits(uint16_t aUnit, float aValue)
InternalItem().GetValueInCurrentUnits() == aValue) {
return NS_OK;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(mAttrEnum);
AutoChangeLengthNotifier notifier(this);
InternalItem().SetValueAndUnit(aValue, uint8_t(aUnit));
Element()->DidChangeLengthList(mAttrEnum, emptyOrOldValue);
if (mList->mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return NS_OK;
}
mUnit = uint8_t(aUnit);
@ -273,15 +291,18 @@ DOMSVGLength::ConvertToSpecifiedUnits(uint16_t aUnit)
if (InternalItem().GetUnit() == aUnit) {
return NS_OK;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(mAttrEnum);
if (InternalItem().ConvertToUnit(uint8_t(aUnit), Element(), Axis())) {
Element()->DidChangeLengthList(mAttrEnum, emptyOrOldValue);
float val = InternalItem().GetValueInSpecifiedUnit(
aUnit, Element(), Axis());
if (NS_finite(val)) {
AutoChangeLengthNotifier notifier(this);
InternalItem().SetValueAndUnit(val, aUnit);
return NS_OK;
}
} else {
SVGLength len(mValue, mUnit);
if (len.ConvertToUnit(uint8_t(aUnit), nullptr, 0)) {
mValue = len.GetValueInCurrentUnits();
float val = len.GetValueInSpecifiedUnit(aUnit, nullptr, 0);
if (NS_finite(val)) {
mValue = val;
mUnit = aUnit;
return NS_OK;
}

View File

@ -68,6 +68,8 @@ namespace mozilla {
*/
class DOMSVGLength MOZ_FINAL : public nsIDOMSVGLength
{
friend class AutoChangeLengthNotifier;
public:
NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOMSVGLENGTH_IID)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS

View File

@ -74,6 +74,36 @@ DOMSVGLengthList::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope)
return mozilla::dom::SVGLengthListBinding::Wrap(cx, scope, this);
}
//----------------------------------------------------------------------
// Helper class: AutoChangeLengthListNotifier
// Stack-based helper class to pair calls to WillChangeLengthList and
// DidChangeLengthList.
class MOZ_STACK_CLASS AutoChangeLengthListNotifier
{
public:
AutoChangeLengthListNotifier(DOMSVGLengthList* aLengthList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mLengthList(aLengthList)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
mEmptyOrOldValue =
mLengthList->Element()->WillChangeLengthList(mLengthList->AttrEnum());
}
~AutoChangeLengthListNotifier()
{
mLengthList->Element()->DidChangeLengthList(mLengthList->AttrEnum(),
mEmptyOrOldValue);
if (mLengthList->IsAnimating()) {
mLengthList->Element()->AnimationNeedsResample();
}
}
private:
DOMSVGLengthList* mLengthList;
nsAttrValue mEmptyOrOldValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
void
DOMSVGLengthList::InternalListLengthWillChange(uint32_t aNewLength)
{
@ -130,7 +160,7 @@ DOMSVGLengthList::Clear(ErrorResult& aError)
}
if (LengthNoFlush() > 0) {
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
AutoChangeLengthListNotifier notifier(this);
// Notify any existing DOM items of removal *before* truncating the lists
// so that they can find their SVGLength internal counterparts and copy
// their values. This also notifies the animVal list:
@ -138,10 +168,6 @@ DOMSVGLengthList::Clear(ErrorResult& aError)
mItems.Clear();
InternalList().Clear();
Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
}
}
@ -233,7 +259,7 @@ DOMSVGLengthList::InsertItemBefore(nsIDOMSVGLength *newItem,
return nullptr;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
AutoChangeLengthListNotifier notifier(this);
// Now that we know we're inserting, keep animVal list in sync as necessary.
MaybeInsertNullInAnimValListAt(index);
@ -247,10 +273,6 @@ DOMSVGLengthList::InsertItemBefore(nsIDOMSVGLength *newItem,
UpdateListIndicesFromIndex(mItems, index + 1);
Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return domItem.forget();
}
@ -277,7 +299,7 @@ DOMSVGLengthList::ReplaceItem(nsIDOMSVGLength *newItem,
domItem = domItem->Copy(); // must do this before changing anything!
}
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
AutoChangeLengthListNotifier notifier(this);
if (mItems[index]) {
// Notify any existing DOM item of removal *before* modifying the lists so
// that the DOM item can copy the *old* value at its index:
@ -291,10 +313,6 @@ DOMSVGLengthList::ReplaceItem(nsIDOMSVGLength *newItem,
// would end up reading bad data from InternalList()!
domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return domItem.forget();
}
@ -312,7 +330,7 @@ DOMSVGLengthList::RemoveItem(uint32_t index,
return nullptr;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeLengthList(AttrEnum());
AutoChangeLengthListNotifier notifier(this);
// Now that we know we're removing, keep animVal list in sync as necessary.
// Do this *before* touching InternalList() so the removed item can get its
// internal value.
@ -330,10 +348,6 @@ DOMSVGLengthList::RemoveItem(uint32_t index,
UpdateListIndicesFromIndex(mItems, index);
Element()->DidChangeLengthList(AttrEnum(), emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return result.forget();
}

View File

@ -42,6 +42,7 @@ class DOMSVGLength;
class DOMSVGLengthList MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
friend class AutoChangeLengthListNotifier;
friend class DOMSVGLength;
public:
@ -93,6 +94,14 @@ public:
/// Called to notify us to syncronize our length and detach excess items.
void InternalListLengthWillChange(uint32_t aNewLength);
/**
* Returns true if our attribute is animating (in which case our animVal is
* not simply a mirror of our baseVal).
*/
bool IsAnimating() const {
return mAList->IsAnimating();
}
uint32_t NumberOfItems() const
{
if (IsAnimValList()) {

View File

@ -45,6 +45,42 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGNumber)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGNumber)
NS_INTERFACE_MAP_END
namespace mozilla {
//----------------------------------------------------------------------
// Helper class: AutoChangeNumberNotifier
// Stack-based helper class to pair calls to WillChangeNumberList and
// DidChangeNumberList.
class MOZ_STACK_CLASS AutoChangeNumberNotifier
{
public:
AutoChangeNumberNotifier(DOMSVGNumber* aNumber MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mNumber(aNumber)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
MOZ_ASSERT(mNumber->HasOwner(),
"Expecting list to have an owner for notification");
mEmptyOrOldValue =
mNumber->Element()->WillChangeNumberList(mNumber->mAttrEnum);
}
~AutoChangeNumberNotifier()
{
mNumber->Element()->DidChangeNumberList(mNumber->mAttrEnum,
mEmptyOrOldValue);
if (mNumber->mList->IsAnimating()) {
mNumber->Element()->AnimationNeedsResample();
}
}
private:
DOMSVGNumber* mNumber;
nsAttrValue mEmptyOrOldValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
}
DOMSVGNumber::DOMSVGNumber(DOMSVGNumberList *aList,
uint8_t aAttrEnum,
uint32_t aListIndex,
@ -95,12 +131,8 @@ DOMSVGNumber::SetValue(float aValue)
if (InternalItem() == aValue) {
return NS_OK;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeNumberList(mAttrEnum);
AutoChangeNumberNotifier notifier(this);
InternalItem() = aValue;
Element()->DidChangeNumberList(mAttrEnum, emptyOrOldValue);
if (mList->mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return NS_OK;
}
mValue = aValue;

View File

@ -43,6 +43,8 @@ namespace mozilla {
*/
class DOMSVGNumber MOZ_FINAL : public nsIDOMSVGNumber
{
friend class AutoChangeNumberNotifier;
public:
NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOMSVGNUMBER_IID)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS

View File

@ -75,6 +75,36 @@ DOMSVGNumberList::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope)
return mozilla::dom::SVGNumberListBinding::Wrap(cx, scope, this);
}
//----------------------------------------------------------------------
// Helper class: AutoChangeNumberListNotifier
// Stack-based helper class to pair calls to WillChangeNumberList and
// DidChangeNumberList.
class MOZ_STACK_CLASS AutoChangeNumberListNotifier
{
public:
AutoChangeNumberListNotifier(DOMSVGNumberList* aNumberList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mNumberList(aNumberList)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
mEmptyOrOldValue =
mNumberList->Element()->WillChangeNumberList(mNumberList->AttrEnum());
}
~AutoChangeNumberListNotifier()
{
mNumberList->Element()->DidChangeNumberList(mNumberList->AttrEnum(),
mEmptyOrOldValue);
if (mNumberList->IsAnimating()) {
mNumberList->Element()->AnimationNeedsResample();
}
}
private:
DOMSVGNumberList* mNumberList;
nsAttrValue mEmptyOrOldValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
void
DOMSVGNumberList::InternalListLengthWillChange(uint32_t aNewLength)
{
@ -129,7 +159,7 @@ DOMSVGNumberList::Clear(ErrorResult& error)
}
if (LengthNoFlush() > 0) {
nsAttrValue emptyOrOldValue = Element()->WillChangeNumberList(AttrEnum());
AutoChangeNumberListNotifier notifier(this);
// Notify any existing DOM items of removal *before* truncating the lists
// so that they can find their SVGNumber internal counterparts and copy
// their values. This also notifies the animVal list:
@ -137,10 +167,6 @@ DOMSVGNumberList::Clear(ErrorResult& error)
mItems.Clear();
InternalList().Clear();
Element()->DidChangeNumberList(AttrEnum(), emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
}
}
@ -231,7 +257,7 @@ DOMSVGNumberList::InsertItemBefore(nsIDOMSVGNumber *newItem,
return nullptr;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeNumberList(AttrEnum());
AutoChangeNumberListNotifier notifier(this);
// Now that we know we're inserting, keep animVal list in sync as necessary.
MaybeInsertNullInAnimValListAt(index);
@ -245,10 +271,6 @@ DOMSVGNumberList::InsertItemBefore(nsIDOMSVGNumber *newItem,
UpdateListIndicesFromIndex(mItems, index + 1);
Element()->DidChangeNumberList(AttrEnum(), emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return domItem.forget();
}
@ -275,7 +297,7 @@ DOMSVGNumberList::ReplaceItem(nsIDOMSVGNumber *newItem,
domItem = domItem->Clone(); // must do this before changing anything!
}
nsAttrValue emptyOrOldValue = Element()->WillChangeNumberList(AttrEnum());
AutoChangeNumberListNotifier notifier(this);
if (mItems[index]) {
// Notify any existing DOM item of removal *before* modifying the lists so
// that the DOM item can copy the *old* value at its index:
@ -289,10 +311,6 @@ DOMSVGNumberList::ReplaceItem(nsIDOMSVGNumber *newItem,
// would end up reading bad data from InternalList()!
domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
Element()->DidChangeNumberList(AttrEnum(), emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return domItem.forget();
}
@ -318,7 +336,7 @@ DOMSVGNumberList::RemoveItem(uint32_t index,
// We have to return the removed item, so get it, creating it if necessary:
nsRefPtr<nsIDOMSVGNumber> result = GetItemAt(index);
nsAttrValue emptyOrOldValue = Element()->WillChangeNumberList(AttrEnum());
AutoChangeNumberListNotifier notifier(this);
// Notify the DOM item of removal *before* modifying the lists so that the
// DOM item can copy its *old* value:
mItems[index]->RemovingFromList();
@ -328,10 +346,6 @@ DOMSVGNumberList::RemoveItem(uint32_t index,
UpdateListIndicesFromIndex(mItems, index);
Element()->DidChangeNumberList(AttrEnum(), emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return result.forget();
}

View File

@ -42,6 +42,7 @@ class DOMSVGNumber;
class DOMSVGNumberList MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
friend class AutoChangeNumberListNotifier;
friend class DOMSVGNumber;
public:
@ -93,6 +94,14 @@ public:
/// Called to notify us to syncronize our length and detach excess items.
void InternalListLengthWillChange(uint32_t aNewLength);
/**
* Returns true if our attribute is animating (in which case our animVal is
* not simply a mirror of our baseVal).
*/
bool IsAnimating() const {
return mAList->IsAnimating();
}
uint32_t NumberOfItems() const
{
if (IsAnimValList()) {

View File

@ -40,6 +40,41 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMSVGPathSeg, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGPathSeg, Release)
namespace mozilla {
//----------------------------------------------------------------------
// Helper class: AutoChangePathSegNotifier
// Stack-based helper class to pair calls to WillChangePathSegList
// and DidChangePathSegList.
class MOZ_STACK_CLASS AutoChangePathSegNotifier
{
public:
AutoChangePathSegNotifier(DOMSVGPathSeg* aPathSeg MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mPathSeg(aPathSeg)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
MOZ_ASSERT(mPathSeg->HasOwner(),
"Expecting list to have an owner for notification");
mEmptyOrOldValue =
mPathSeg->Element()->WillChangePathSegList();
}
~AutoChangePathSegNotifier()
{
mPathSeg->Element()->DidChangePathSegList(mEmptyOrOldValue);
if (mPathSeg->mList->AttrIsAnimating()) {
mPathSeg->Element()->AnimationNeedsResample();
}
}
private:
DOMSVGPathSeg* mPathSeg;
nsAttrValue mEmptyOrOldValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
}
DOMSVGPathSeg::DOMSVGPathSeg(DOMSVGPathSegList *aList,
uint32_t aListIndex,
bool aIsAnimValItem)
@ -146,13 +181,8 @@ DOMSVGPathSeg::IndexIsValid()
if (InternalItem()[1+index] == float(a##propName)) { \
return; \
} \
NS_ABORT_IF_FALSE(IsInList(), "Will/DidChangePathSegList() is wrong"); \
nsAttrValue emptyOrOldValue = Element()->WillChangePathSegList(); \
AutoChangePathSegNotifier notifier(this); \
InternalItem()[1+index] = float(a##propName); \
Element()->DidChangePathSegList(emptyOrOldValue); \
if (mList->AttrIsAnimating()) { \
Element()->AnimationNeedsResample(); \
} \
} else { \
mArgs[index] = float(a##propName); \
} \

View File

@ -86,6 +86,8 @@ namespace mozilla {
*/
class DOMSVGPathSeg : public nsWrapperCache
{
friend class AutoChangePathSegNotifier;
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMSVGPathSeg)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMSVGPathSeg)

View File

@ -50,6 +50,35 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGPathSegList)
NS_INTERFACE_MAP_END
//----------------------------------------------------------------------
// Helper class: AutoChangePathSegListNotifier
// Stack-based helper class to pair calls to WillChangePathSegList and
// DidChangePathSegList.
class MOZ_STACK_CLASS AutoChangePathSegListNotifier
{
public:
AutoChangePathSegListNotifier(DOMSVGPathSegList* aPathSegList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mPathSegList(aPathSegList)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
mEmptyOrOldValue =
mPathSegList->Element()->WillChangePathSegList();
}
~AutoChangePathSegListNotifier()
{
mPathSegList->Element()->DidChangePathSegList(mEmptyOrOldValue);
if (mPathSegList->AttrIsAnimating()) {
mPathSegList->Element()->AnimationNeedsResample();
}
}
private:
DOMSVGPathSegList* mPathSegList;
nsAttrValue mEmptyOrOldValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/* static */ already_AddRefed<DOMSVGPathSegList>
DOMSVGPathSegList::GetDOMWrapper(void *aList,
nsSVGElement *aElement,
@ -238,7 +267,7 @@ DOMSVGPathSegList::Clear(ErrorResult& aError)
}
if (LengthNoFlush() > 0) {
nsAttrValue emptyOrOldValue = Element()->WillChangePathSegList();
AutoChangePathSegListNotifier notifier(this);
// DOM list items that are to be removed must be removed before we change
// the internal list, otherwise they wouldn't be able to copy their
// internal counterparts' values!
@ -255,10 +284,6 @@ DOMSVGPathSegList::Clear(ErrorResult& aError)
}
InternalList().Clear();
Element()->DidChangePathSegList(emptyOrOldValue);
if (AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
}
}
@ -349,7 +374,7 @@ DOMSVGPathSegList::InsertItemBefore(DOMSVGPathSeg& aNewItem,
return nullptr;
}
nsAttrValue emptyOrOldValue = Element()->WillChangePathSegList();
AutoChangePathSegListNotifier notifier(this);
// Now that we know we're inserting, keep animVal list in sync as necessary.
MaybeInsertNullInAnimValListAt(aIndex, internalIndex, argCount);
@ -366,10 +391,6 @@ DOMSVGPathSegList::InsertItemBefore(DOMSVGPathSeg& aNewItem,
UpdateListIndicesFromIndex(aIndex + 1, argCount + 1);
Element()->DidChangePathSegList(emptyOrOldValue);
if (AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
return domItem.forget();
}
@ -393,7 +414,7 @@ DOMSVGPathSegList::ReplaceItem(DOMSVGPathSeg& aNewItem,
domItem = domItem->Clone(); // must do this before changing anything!
}
nsAttrValue emptyOrOldValue = Element()->WillChangePathSegList();
AutoChangePathSegListNotifier notifier(this);
if (ItemAt(aIndex)) {
// Notify any existing DOM item of removal *before* modifying the lists so
// that the DOM item can copy the *old* value at its index:
@ -434,10 +455,6 @@ DOMSVGPathSegList::ReplaceItem(DOMSVGPathSeg& aNewItem,
}
}
Element()->DidChangePathSegList(emptyOrOldValue);
if (AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
return domItem.forget();
}
@ -457,7 +474,7 @@ DOMSVGPathSegList::RemoveItem(uint32_t aIndex,
// We have to return the removed item, so get it, creating it if necessary:
nsRefPtr<DOMSVGPathSeg> result = GetItemAt(aIndex);
nsAttrValue emptyOrOldValue = Element()->WillChangePathSegList();
AutoChangePathSegListNotifier notifier(this);
// Notify the DOM item of removal *before* modifying the lists so that the
// DOM item can copy its *old* value:
ItemAt(aIndex)->RemovingFromList();
@ -479,10 +496,6 @@ DOMSVGPathSegList::RemoveItem(uint32_t aIndex,
UpdateListIndicesFromIndex(aIndex, -(argCount + 1));
Element()->DidChangePathSegList(emptyOrOldValue);
if (AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
return result.forget();
}

View File

@ -49,6 +49,7 @@ class SVGAnimatedPathSegList;
class DOMSVGPathSegList MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
friend class AutoChangePathSegListNotifier;
friend class DOMSVGPathSeg;
public:

View File

@ -14,6 +14,41 @@
using namespace mozilla;
namespace mozilla {
//----------------------------------------------------------------------
// Helper class: AutoChangePointNotifier
// Stack-based helper class to pair calls to WillChangePointList and
// DidChangePointList.
class MOZ_STACK_CLASS AutoChangePointNotifier
{
public:
AutoChangePointNotifier(DOMSVGPoint* aPoint MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mPoint(aPoint)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
MOZ_ASSERT(mPoint->HasOwner(),
"Expecting list to have an owner for notification");
mEmptyOrOldValue =
mPoint->Element()->WillChangePointList();
}
~AutoChangePointNotifier()
{
mPoint->Element()->DidChangePointList(mEmptyOrOldValue);
if (mPoint->mList->AttrIsAnimating()) {
mPoint->Element()->AnimationNeedsResample();
}
}
private:
DOMSVGPoint* mPoint;
nsAttrValue mEmptyOrOldValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
}
float
DOMSVGPoint::X()
{
@ -35,12 +70,8 @@ DOMSVGPoint::SetX(float aX, ErrorResult& rv)
if (InternalItem().mX == aX) {
return;
}
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
AutoChangePointNotifier notifier(this);
InternalItem().mX = aX;
Element()->DidChangePointList(emptyOrOldValue);
if (mList->AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
return;
}
mPt.mX = aX;
@ -67,12 +98,8 @@ DOMSVGPoint::SetY(float aY, ErrorResult& rv)
if (InternalItem().mY == aY) {
return;
}
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
AutoChangePointNotifier notifier(this);
InternalItem().mY = aY;
Element()->DidChangePointList(emptyOrOldValue);
if (mList->AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
return;
}
mPt.mY = aY;

View File

@ -39,6 +39,8 @@ class SVGMatrix;
*/
class DOMSVGPoint MOZ_FINAL : public nsISVGPoint
{
friend class AutoChangePointNotifier;
typedef mozilla::gfx::Point Point;
public:

View File

@ -68,6 +68,35 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGPointList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
//----------------------------------------------------------------------
// Helper class: AutoChangePointListNotifier
// Stack-based helper class to pair calls to WillChangePointList and
// DidChangePointList.
class MOZ_STACK_CLASS AutoChangePointListNotifier
{
public:
AutoChangePointListNotifier(DOMSVGPointList* aPointList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mPointList(aPointList)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
mEmptyOrOldValue =
mPointList->Element()->WillChangePointList();
}
~AutoChangePointListNotifier()
{
mPointList->Element()->DidChangePointList(mEmptyOrOldValue);
if (mPointList->AttrIsAnimating()) {
mPointList->Element()->AnimationNeedsResample();
}
}
private:
DOMSVGPointList* mPointList;
nsAttrValue mEmptyOrOldValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/* static */ already_AddRefed<DOMSVGPointList>
DOMSVGPointList::GetDOMWrapper(void *aList,
@ -180,7 +209,7 @@ DOMSVGPointList::Clear(ErrorResult& aError)
}
if (LengthNoFlush() > 0) {
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
AutoChangePointListNotifier notifier(this);
// DOM list items that are to be removed must be removed before we change
// the internal list, otherwise they wouldn't be able to copy their
// internal counterparts' values!
@ -197,10 +226,6 @@ DOMSVGPointList::Clear(ErrorResult& aError)
}
InternalList().Clear();
Element()->DidChangePointList(emptyOrOldValue);
if (AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
}
}
@ -283,7 +308,7 @@ DOMSVGPointList::InsertItemBefore(nsISVGPoint& aNewItem, uint32_t aIndex,
return nullptr;
}
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
AutoChangePointListNotifier notifier(this);
// Now that we know we're inserting, keep animVal list in sync as necessary.
MaybeInsertNullInAnimValListAt(aIndex);
@ -297,10 +322,6 @@ DOMSVGPointList::InsertItemBefore(nsISVGPoint& aNewItem, uint32_t aIndex,
UpdateListIndicesFromIndex(mItems, aIndex + 1);
Element()->DidChangePointList(emptyOrOldValue);
if (AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
return domItem.forget();
}
@ -323,7 +344,7 @@ DOMSVGPointList::ReplaceItem(nsISVGPoint& aNewItem, uint32_t aIndex,
domItem = domItem->Clone(); // must do this before changing anything!
}
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
AutoChangePointListNotifier notifier(this);
if (mItems[aIndex]) {
// Notify any existing DOM item of removal *before* modifying the lists so
// that the DOM item can copy the *old* value at its index:
@ -337,10 +358,6 @@ DOMSVGPointList::ReplaceItem(nsISVGPoint& aNewItem, uint32_t aIndex,
// would end up reading bad data from InternalList()!
domItem->InsertingIntoList(this, aIndex, IsAnimValList());
Element()->DidChangePointList(emptyOrOldValue);
if (AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
return domItem.forget();
}
@ -357,7 +374,7 @@ DOMSVGPointList::RemoveItem(uint32_t aIndex, ErrorResult& aError)
return nullptr;
}
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
AutoChangePointListNotifier notifier(this);
// Now that we know we're removing, keep animVal list in sync as necessary.
// Do this *before* touching InternalList() so the removed item can get its
// internal value.
@ -375,10 +392,6 @@ DOMSVGPointList::RemoveItem(uint32_t aIndex, ErrorResult& aError)
UpdateListIndicesFromIndex(mItems, aIndex);
Element()->DidChangePointList(emptyOrOldValue);
if (AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
return result.forget();
}

View File

@ -50,6 +50,7 @@ class SVGAnimatedPointList;
class DOMSVGPointList MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
friend class AutoChangePointListNotifier;
friend class nsISVGPoint;
friend class mozilla::DOMSVGPoint;

View File

@ -37,6 +37,34 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGStringList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
//----------------------------------------------------------------------
// Helper class: AutoChangeStringListNotifier
// Stack-based helper class to pair calls to WillChangeStringListList and
// DidChangeStringListList.
class MOZ_STACK_CLASS AutoChangeStringListNotifier
{
public:
AutoChangeStringListNotifier(DOMSVGStringList* aStringList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mStringList(aStringList)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
mEmptyOrOldValue =
mStringList->mElement->WillChangeStringList(mStringList->mIsConditionalProcessingAttribute,
mStringList->mAttrEnum);
}
~AutoChangeStringListNotifier()
{
mStringList->mElement->DidChangeStringList(mStringList->mIsConditionalProcessingAttribute,
mStringList->mAttrEnum, mEmptyOrOldValue);
}
private:
DOMSVGStringList* mStringList;
nsAttrValue mEmptyOrOldValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/* static */ already_AddRefed<DOMSVGStringList>
DOMSVGStringList::GetDOMWrapper(SVGStringList *aList,
nsSVGElement *aElement,
@ -85,12 +113,8 @@ void
DOMSVGStringList::Clear()
{
if (InternalList().IsExplicitlySet()) {
nsAttrValue emptyOrOldValue =
mElement->WillChangeStringList(mIsConditionalProcessingAttribute,
mAttrEnum);
AutoChangeStringListNotifier notifier(this);
InternalList().Clear();
mElement->DidChangeStringList(mIsConditionalProcessingAttribute,
mAttrEnum, emptyOrOldValue);
}
}
@ -140,13 +164,8 @@ DOMSVGStringList::InsertItemBefore(const nsAString& aNewItem, uint32_t aIndex,
return;
}
nsAttrValue emptyOrOldValue =
mElement->WillChangeStringList(mIsConditionalProcessingAttribute,
mAttrEnum);
AutoChangeStringListNotifier notifier(this);
InternalList().InsertItem(aIndex, aNewItem);
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum,
emptyOrOldValue);
aRetval = aNewItem;
}
@ -164,13 +183,8 @@ DOMSVGStringList::ReplaceItem(const nsAString& aNewItem, uint32_t aIndex,
}
aRetval = InternalList()[aIndex];
nsAttrValue emptyOrOldValue =
mElement->WillChangeStringList(mIsConditionalProcessingAttribute,
mAttrEnum);
AutoChangeStringListNotifier notifier(this);
InternalList().ReplaceItem(aIndex, aNewItem);
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum,
emptyOrOldValue);
}
void
@ -182,13 +196,8 @@ DOMSVGStringList::RemoveItem(uint32_t aIndex, nsAString& aRetval,
return;
}
nsAttrValue emptyOrOldValue =
mElement->WillChangeStringList(mIsConditionalProcessingAttribute,
mAttrEnum);
AutoChangeStringListNotifier notifier(this);
InternalList().RemoveItem(aIndex);
mElement->DidChangeStringList(mIsConditionalProcessingAttribute, mAttrEnum,
emptyOrOldValue);
}
void

View File

@ -46,6 +46,8 @@ class SVGStringList;
class DOMSVGStringList MOZ_FINAL : public nsISupports
, public nsWrapperCache
{
friend class AutoChangeStringListNotifier;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGStringList)

View File

@ -76,6 +76,35 @@ DOMSVGTransformList::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope)
return mozilla::dom::SVGTransformListBinding::Wrap(cx, scope, this);
}
//----------------------------------------------------------------------
// Helper class: AutoChangeTransformListNotifier
// Stack-based helper class to pair calls to WillChangeTransformList and
// DidChangeTransformList.
class MOZ_STACK_CLASS AutoChangeTransformListNotifier
{
public:
AutoChangeTransformListNotifier(DOMSVGTransformList* aTransformList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mTransformList(aTransformList)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
mEmptyOrOldValue =
mTransformList->Element()->WillChangeTransformList();
}
~AutoChangeTransformListNotifier()
{
mTransformList->Element()->DidChangeTransformList(mEmptyOrOldValue);
if (mTransformList->IsAnimating()) {
mTransformList->Element()->AnimationNeedsResample();
}
}
private:
DOMSVGTransformList* mTransformList;
nsAttrValue mEmptyOrOldValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
void
DOMSVGTransformList::InternalListLengthWillChange(uint32_t aNewLength)
{
@ -133,7 +162,7 @@ DOMSVGTransformList::Clear(ErrorResult& error)
}
if (LengthNoFlush() > 0) {
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
AutoChangeTransformListNotifier notifier(this);
// Notify any existing DOM items of removal *before* truncating the lists
// so that they can find their SVGTransform internal counterparts and copy
// their values. This also notifies the animVal list:
@ -141,10 +170,6 @@ DOMSVGTransformList::Clear(ErrorResult& error)
mItems.Clear();
InternalList().Clear();
Element()->DidChangeTransformList(emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
}
}
@ -226,7 +251,7 @@ DOMSVGTransformList::InsertItemBefore(SVGTransform& newItem,
return nullptr;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
AutoChangeTransformListNotifier notifier(this);
// Now that we know we're inserting, keep animVal list in sync as necessary.
MaybeInsertNullInAnimValListAt(index);
@ -240,10 +265,6 @@ DOMSVGTransformList::InsertItemBefore(SVGTransform& newItem,
UpdateListIndicesFromIndex(mItems, index + 1);
Element()->DidChangeTransformList(emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return domItem.forget();
}
@ -266,7 +287,7 @@ DOMSVGTransformList::ReplaceItem(SVGTransform& newItem,
domItem = newItem.Clone(); // must do this before changing anything!
}
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
AutoChangeTransformListNotifier notifier(this);
if (mItems[index]) {
// Notify any existing DOM item of removal *before* modifying the lists so
// that the DOM item can copy the *old* value at its index:
@ -280,10 +301,6 @@ DOMSVGTransformList::ReplaceItem(SVGTransform& newItem,
// would end up reading bad data from InternalList()!
domItem->InsertingIntoList(this, index, IsAnimValList());
Element()->DidChangeTransformList(emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return domItem.forget();
}
@ -300,7 +317,7 @@ DOMSVGTransformList::RemoveItem(uint32_t index, ErrorResult& error)
return nullptr;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
AutoChangeTransformListNotifier notifier(this);
// Now that we know we're removing, keep animVal list in sync as necessary.
// Do this *before* touching InternalList() so the removed item can get its
// internal value.
@ -318,10 +335,6 @@ DOMSVGTransformList::RemoveItem(uint32_t index, ErrorResult& error)
UpdateListIndicesFromIndex(mItems, index);
Element()->DidChangeTransformList(emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
return result.forget();
}

View File

@ -36,6 +36,7 @@ class SVGTransform;
class DOMSVGTransformList MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
friend class AutoChangeTransformListNotifier;
friend class dom::SVGTransform;
public:
@ -87,6 +88,14 @@ public:
/// Called to notify us to synchronize our length and detach excess items.
void InternalListLengthWillChange(uint32_t aNewLength);
/**
* Returns true if our attribute is animating (in which case our animVal is
* not simply a mirror of our baseVal).
*/
bool IsAnimating() const {
return mAList->IsAnimating();
}
uint32_t NumberOfItems() const
{
if (IsAnimValList()) {

View File

@ -107,27 +107,6 @@ public:
return mValue * GetUserUnitsPerUnit(aElement, aAxis);
}
/**
* Sets this length's value, converting the supplied user unit value to this
* lengths *current* unit (i.e. leaving the length's unit unchanged).
*
* This method returns true, unless the user unit value couldn't be
* converted to this length's current unit, in which case it returns false
* (and the length is left unchanged).
*/
bool SetFromUserUnitValue(float aUserUnitValue,
nsSVGElement *aElement,
uint8_t aAxis) {
float uuPerUnit = GetUserUnitsPerUnit(aElement, aAxis);
float value = aUserUnitValue / uuPerUnit;
if (uuPerUnit > 0 && NS_finite(value)) {
mValue = value;
NS_ASSERTION(IsValid(), "Set invalid SVGLength");
return true;
}
return false;
}
/**
* Get this length's value in the units specified.
*
@ -138,24 +117,6 @@ public:
const nsSVGElement *aElement,
uint8_t aAxis) const;
/**
* Convert this length's value to the unit specified.
*
* This method returns true, unless it isn't possible to convert the
* length to the specified unit. In that case the length is left unchanged
* and this method returns false.
*/
bool ConvertToUnit(uint32_t aUnit, nsSVGElement *aElement, uint8_t aAxis) {
float val = GetValueInSpecifiedUnit(aUnit, aElement, aAxis);
if (NS_finite(val)) {
mValue = val;
mUnit = aUnit;
NS_ASSERTION(IsValid(), "Set invalid SVGLength");
return true;
}
return false;
}
bool IsPercentage() const {
return mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE;
}
@ -165,14 +126,6 @@ public:
unit <= nsIDOMSVGLength::SVG_LENGTHTYPE_PC;
}
private:
#ifdef DEBUG
bool IsValid() const {
return NS_finite(mValue) && IsValidUnitType(mUnit);
}
#endif
/**
* Returns the number of user units per current unit.
*
@ -182,6 +135,14 @@ private:
*/
float GetUserUnitsPerUnit(const nsSVGElement *aElement, uint8_t aAxis) const;
private:
#ifdef DEBUG
bool IsValid() const {
return NS_finite(mValue) && IsValidUnitType(mUnit);
}
#endif
/**
* The conversion factor between user units (CSS px) and CSS inches is
* constant: 96 px per inch.

View File

@ -4,6 +4,8 @@
* 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 "SVGTransform.h"
#include "mozilla/dom/SVGTransform.h"
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/SVGTransformBinding.h"
@ -11,6 +13,10 @@
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGAttrTearoffTable.h"
namespace {
const double radPerDegree = 2.0 * M_PI / 360.0;
}
namespace mozilla {
namespace dom {
@ -59,6 +65,39 @@ SVGTransform::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
return SVGTransformBinding::Wrap(aCx, aScope, this);
}
//----------------------------------------------------------------------
// Helper class: AutoChangeTransformNotifier
// Stack-based helper class to pair calls to WillChangeTransformList
// and DidChangeTransformList.
class MOZ_STACK_CLASS AutoChangeTransformNotifier
{
public:
AutoChangeTransformNotifier(SVGTransform* aTransform MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mTransform(aTransform)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mTransform->HasOwner()) {
mEmptyOrOldValue =
mTransform->Element()->WillChangeTransformList();
}
}
~AutoChangeTransformNotifier()
{
if (mTransform->HasOwner()) {
mTransform->Element()->DidChangeTransformList(mEmptyOrOldValue);
if (mTransform->mList->IsAnimating()) {
mTransform->Element()->AnimationNeedsResample();
}
}
}
private:
SVGTransform* mTransform;
nsAttrValue mEmptyOrOldValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
//----------------------------------------------------------------------
// Ctors:
@ -169,9 +208,8 @@ SVGTransform::SetTranslate(float tx, float ty, ErrorResult& rv)
return;
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
AutoChangeTransformNotifier notifier(this);
Transform().SetTranslate(tx, ty);
NotifyElementDidChange(emptyOrOldValue);
}
void
@ -186,9 +224,8 @@ SVGTransform::SetScale(float sx, float sy, ErrorResult& rv)
Matrixgfx().xx == sx && Matrixgfx().yy == sy) {
return;
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
AutoChangeTransformNotifier notifier(this);
Transform().SetScale(sx, sy);
NotifyElementDidChange(emptyOrOldValue);
}
void
@ -207,9 +244,8 @@ SVGTransform::SetRotate(float angle, float cx, float cy, ErrorResult& rv)
}
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
AutoChangeTransformNotifier notifier(this);
Transform().SetRotate(angle, cx, cy);
NotifyElementDidChange(emptyOrOldValue);
}
void
@ -225,13 +261,13 @@ SVGTransform::SetSkewX(float angle, ErrorResult& rv)
return;
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
nsresult result = Transform().SetSkewX(angle);
if (NS_FAILED(result)) {
rv.Throw(result);
if (!NS_finite(tan(angle * radPerDegree))) {
rv.Throw(NS_ERROR_RANGE_ERR);
return;
}
NotifyElementDidChange(emptyOrOldValue);
AutoChangeTransformNotifier notifier(this);
Transform().SetSkewX(angle);
}
void
@ -247,13 +283,13 @@ SVGTransform::SetSkewY(float angle, ErrorResult& rv)
return;
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
nsresult result = Transform().SetSkewY(angle);
if (NS_FAILED(result)) {
rv.Throw(result);
if (!NS_finite(tan(angle * radPerDegree))) {
rv.Throw(NS_ERROR_RANGE_ERR);
return;
}
NotifyElementDidChange(emptyOrOldValue);
AutoChangeTransformNotifier notifier(this);
Transform().SetSkewY(angle);
}
//----------------------------------------------------------------------
@ -327,23 +363,8 @@ SVGTransform::SetMatrix(const gfxMatrix& aMatrix)
return;
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
AutoChangeTransformNotifier notifier(this);
Transform().SetMatrix(aMatrix);
NotifyElementDidChange(emptyOrOldValue);
}
//----------------------------------------------------------------------
// Implementation helpers
void
SVGTransform::NotifyElementDidChange(const nsAttrValue& aEmptyOrOldValue)
{
if (HasOwner()) {
Element()->DidChangeTransformList(aEmptyOrOldValue);
if (mList->mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
}
}
} // namespace dom

View File

@ -32,6 +32,8 @@ class SVGMatrix;
*/
class SVGTransform MOZ_FINAL : public nsWrapperCache
{
friend class AutoChangeTransformNotifier;
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SVGTransform)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(SVGTransform)
@ -163,8 +165,6 @@ private:
nsSVGTransform& Transform() {
return HasOwner() ? InternalItem() : *mTransform;
}
inline nsAttrValue NotifyElementWillChange();
void NotifyElementDidChange(const nsAttrValue& aEmptyOrOldValue);
nsRefPtr<DOMSVGTransformList> mList;
@ -183,16 +183,6 @@ private:
nsAutoPtr<nsSVGTransform> mTransform;
};
nsAttrValue
SVGTransform::NotifyElementWillChange()
{
nsAttrValue result;
if (HasOwner()) {
result = Element()->WillChangeTransformList();
}
return result;
}
} // namespace dom
} // namespace mozilla