mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 775730 - Ensure AttributeWillChange is always paired with AttributeDidChange. r=dholbert
This commit is contained in:
parent
65b417b381
commit
e3e8ce789d
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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); \
|
||||
} \
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@ class SVGAnimatedPathSegList;
|
||||
class DOMSVGPathSegList MOZ_FINAL : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
friend class AutoChangePathSegListNotifier;
|
||||
friend class DOMSVGPathSeg;
|
||||
|
||||
public:
|
||||
|
@ -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;
|
||||
|
@ -39,6 +39,8 @@ class SVGMatrix;
|
||||
*/
|
||||
class DOMSVGPoint MOZ_FINAL : public nsISVGPoint
|
||||
{
|
||||
friend class AutoChangePointNotifier;
|
||||
|
||||
typedef mozilla::gfx::Point Point;
|
||||
|
||||
public:
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,7 @@ class SVGAnimatedPointList;
|
||||
class DOMSVGPointList MOZ_FINAL : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
friend class AutoChangePointListNotifier;
|
||||
friend class nsISVGPoint;
|
||||
friend class mozilla::DOMSVGPoint;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user