Bug 629200 part 22 - Remove unnecessary serialisation from setting SVGTransformList; r=jwatt

This commit is contained in:
Brian Birtles 2012-02-16 08:40:46 +09:00
Родитель fe5c4aee2d
Коммит 848300c26c
10 изменённых файлов: 202 добавлений и 33 удалений

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

@ -61,6 +61,7 @@
#include "SVGNumberList.h"
#include "SVGPathData.h"
#include "SVGPointList.h"
#include "SVGTransformList.h"
namespace css = mozilla::css;
@ -319,6 +320,11 @@ nsAttrValue::SetTo(const nsAttrValue& aOther)
cont->mSVGPreserveAspectRatio = otherCont->mSVGPreserveAspectRatio;
break;
}
case eSVGTransformList:
{
cont->mSVGTransformList = otherCont->mSVGTransformList;
break;
}
case eSVGViewBox:
{
cont->mSVGViewBox = otherCont->mSVGViewBox;
@ -533,6 +539,20 @@ nsAttrValue::SetTo(const mozilla::SVGAnimatedPreserveAspectRatio& aValue,
}
}
void
nsAttrValue::SetTo(const mozilla::SVGTransformList& aValue,
const nsAString* aSerialized)
{
if (EnsureEmptyMiscContainer()) {
MiscContainer* cont = GetMiscContainer();
cont->mSVGTransformList = &aValue;
cont->mType = eSVGTransformList;
if (aSerialized && aSerialized->Length()) {
SetMiscAtomOrString(aSerialized);
}
}
}
void
nsAttrValue::SetTo(const nsSVGViewBox& aValue, const nsAString* aSerialized)
{
@ -686,6 +706,11 @@ nsAttrValue::ToString(nsAString& aResult) const
GetMiscContainer()->mSVGPreserveAspectRatio->GetBaseValueString(aResult);
break;
}
case eSVGTransformList:
{
GetMiscContainer()->mSVGTransformList->GetValueAsString(aResult);
break;
}
case eSVGViewBox:
{
GetMiscContainer()->mSVGViewBox->GetBaseValueString(aResult);
@ -911,6 +936,10 @@ nsAttrValue::HashValue() const
{
return NS_PTR_TO_INT32(cont->mSVGPreserveAspectRatio);
}
case eSVGTransformList:
{
return NS_PTR_TO_INT32(cont->mSVGTransformList);
}
case eSVGViewBox:
{
return NS_PTR_TO_INT32(cont->mSVGViewBox);
@ -1044,6 +1073,10 @@ nsAttrValue::Equals(const nsAttrValue& aOther) const
return thisCont->mSVGPreserveAspectRatio ==
otherCont->mSVGPreserveAspectRatio;
}
case eSVGTransformList:
{
return thisCont->mSVGTransformList == otherCont->mSVGTransformList;
}
case eSVGViewBox:
{
return thisCont->mSVGViewBox == otherCont->mSVGViewBox;

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

@ -73,6 +73,7 @@ class SVGLengthList;
class SVGNumberList;
class SVGPathData;
class SVGPointList;
class SVGTransformList;
}
#define NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM 12
@ -146,7 +147,8 @@ public:
,eSVGPathData = 0x20
,eSVGPointList = 0x21
,eSVGPreserveAspectRatio = 0x22
,eSVGViewBox = 0x23
,eSVGTransformList = 0x23
,eSVGViewBox = 0x24
};
ValueType Type() const;
@ -173,6 +175,8 @@ public:
void SetTo(const mozilla::SVGPointList& aValue, const nsAString* aSerialized);
void SetTo(const mozilla::SVGAnimatedPreserveAspectRatio& aValue,
const nsAString* aSerialized);
void SetTo(const mozilla::SVGTransformList& aValue,
const nsAString* aSerialized);
void SetTo(const nsSVGViewBox& aValue, const nsAString* aSerialized);
/**
@ -414,6 +418,7 @@ private:
const mozilla::SVGPathData* mSVGPathData;
const mozilla::SVGPointList* mSVGPointList;
const mozilla::SVGAnimatedPreserveAspectRatio* mSVGPreserveAspectRatio;
const mozilla::SVGTransformList* mSVGTransformList;
const nsSVGViewBox* mSVGViewBox;
};
};

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

@ -173,9 +173,7 @@ DOMSVGTransform::SetMatrix(nsIDOMSVGMatrix *matrix)
if (!domMatrix)
return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
Transform().SetMatrix(domMatrix->Matrix());
NotifyElementOfChange();
SetMatrix(domMatrix->Matrix());
return NS_OK;
}
@ -188,8 +186,14 @@ DOMSVGTransform::SetTranslate(float tx, float ty)
}
NS_ENSURE_FINITE2(tx, ty, NS_ERROR_ILLEGAL_VALUE);
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE &&
Matrix().x0 == tx && Matrix().y0 == ty) {
return NS_OK;
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
Transform().SetTranslate(tx, ty);
NotifyElementOfChange();
NotifyElementDidChange(emptyOrOldValue);
return NS_OK;
}
@ -203,8 +207,14 @@ DOMSVGTransform::SetScale(float sx, float sy)
}
NS_ENSURE_FINITE2(sx, sy, NS_ERROR_ILLEGAL_VALUE);
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SCALE &&
Matrix().xx == sx && Matrix().yy == sy) {
return NS_OK;
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
Transform().SetScale(sx, sy);
NotifyElementOfChange();
NotifyElementDidChange(emptyOrOldValue);
return NS_OK;
}
@ -218,8 +228,17 @@ DOMSVGTransform::SetRotate(float angle, float cx, float cy)
}
NS_ENSURE_FINITE3(angle, cx, cy, NS_ERROR_ILLEGAL_VALUE);
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_ROTATE) {
float currentCx, currentCy;
Transform().GetRotationOrigin(currentCx, currentCy);
if (Transform().Angle() == angle && currentCx == cx && currentCy == cy) {
return NS_OK;
}
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
Transform().SetRotate(angle, cx, cy);
NotifyElementOfChange();
NotifyElementDidChange(emptyOrOldValue);
return NS_OK;
}
@ -233,10 +252,16 @@ DOMSVGTransform::SetSkewX(float angle)
}
NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX &&
Transform().Angle() == angle) {
return NS_OK;
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
nsresult rv = Transform().SetSkewX(angle);
if (NS_FAILED(rv))
return rv;
NotifyElementOfChange();
NotifyElementDidChange(emptyOrOldValue);
return NS_OK;
}
@ -250,10 +275,16 @@ DOMSVGTransform::SetSkewY(float angle)
}
NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_SKEWY &&
Transform().Angle() == angle) {
return NS_OK;
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
nsresult rv = Transform().SetSkewY(angle);
if (NS_FAILED(rv))
return rv;
NotifyElementOfChange();
NotifyElementDidChange(emptyOrOldValue);
return NS_OK;
}
@ -324,8 +355,15 @@ DOMSVGTransform::SetMatrix(const gfxMatrix& aMatrix)
{
NS_ABORT_IF_FALSE(!mIsAnimValItem,
"Attempting to modify read-only transform");
if (Transform().Type() == nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX &&
SVGTransform::MatricesEqual(Matrix(), aMatrix)) {
return;
}
nsAttrValue emptyOrOldValue = NotifyElementWillChange();
Transform().SetMatrix(aMatrix);
NotifyElementOfChange();
NotifyElementDidChange(emptyOrOldValue);
}
void
@ -341,10 +379,10 @@ DOMSVGTransform::ClearMatrixTearoff(DOMSVGMatrix* aMatrix)
// Implementation helpers
void
DOMSVGTransform::NotifyElementOfChange()
DOMSVGTransform::NotifyElementDidChange(const nsAttrValue& aEmptyOrOldValue)
{
if (HasOwner()) {
Element()->DidChangeTransformList(true);
Element()->DidChangeTransformList(aEmptyOrOldValue);
if (mList->mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}

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

@ -206,7 +206,8 @@ private:
SVGTransform& Transform() {
return HasOwner() ? InternalItem() : *mTransform;
}
void NotifyElementOfChange();
inline nsAttrValue NotifyElementWillChange();
void NotifyElementDidChange(const nsAttrValue& aEmptyOrOldValue);
nsRefPtr<DOMSVGTransformList> mList;
@ -235,6 +236,16 @@ private:
NS_DEFINE_STATIC_IID_ACCESSOR(DOMSVGTransform, MOZILLA_DOMSVGTRANSFORM_IID)
nsAttrValue
DOMSVGTransform::NotifyElementWillChange()
{
nsAttrValue result;
if (HasOwner()) {
result = Element()->WillChangeTransformList();
}
return result;
}
} // namespace mozilla
#undef MOZ_SVG_LIST_INDEX_BIT_COUNT

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

@ -184,6 +184,7 @@ DOMSVGTransformList::Clear()
}
if (Length() > 0) {
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
// 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:
@ -191,7 +192,7 @@ DOMSVGTransformList::Clear()
mItems.Clear();
InternalList().Clear();
Element()->DidChangeTransformList(true);
Element()->DidChangeTransformList(emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
@ -272,6 +273,7 @@ DOMSVGTransformList::InsertItemBefore(nsIDOMSVGTransform *newItem,
return NS_ERROR_OUT_OF_MEMORY;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
// Now that we know we're inserting, keep animVal list in sync as necessary.
MaybeInsertNullInAnimValListAt(index);
@ -285,7 +287,7 @@ DOMSVGTransformList::InsertItemBefore(nsIDOMSVGTransform *newItem,
UpdateListIndicesFromIndex(mItems, index + 1);
Element()->DidChangeTransformList(true);
Element()->DidChangeTransformList(emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
@ -316,6 +318,7 @@ DOMSVGTransformList::ReplaceItem(nsIDOMSVGTransform *newItem,
domItem = domItem->Clone(); // must do this before changing anything!
}
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
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:
@ -329,7 +332,7 @@ DOMSVGTransformList::ReplaceItem(nsIDOMSVGTransform *newItem,
// would end up reading bad data from InternalList()!
domItem->InsertingIntoList(this, index, IsAnimValList());
Element()->DidChangeTransformList(true);
Element()->DidChangeTransformList(emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}
@ -350,6 +353,7 @@ DOMSVGTransformList::RemoveItem(PRUint32 index, nsIDOMSVGTransform **_retval)
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
nsAttrValue emptyOrOldValue = Element()->WillChangeTransformList();
// 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.
@ -368,7 +372,7 @@ DOMSVGTransformList::RemoveItem(PRUint32 index, nsIDOMSVGTransform **_retval)
UpdateListIndicesFromIndex(mItems, index);
Element()->DidChangeTransformList(true);
Element()->DidChangeTransformList(emptyOrOldValue);
if (mAList->IsAnimating()) {
Element()->AnimationNeedsResample();
}

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

@ -183,6 +183,8 @@ EXPORTS = \
SVGPathSegUtils.h \
SVGPoint.h \
SVGPointList.h \
SVGTransform.h \
SVGTransformList.h \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -97,7 +97,6 @@ public:
nsresult SetSkewX(float aAngle);
nsresult SetSkewY(float aAngle);
protected:
static bool MatricesEqual(const gfxMatrix& a, const gfxMatrix& b)
{
return a.xx == b.xx &&
@ -108,6 +107,7 @@ protected:
a.y0 == b.y0;
}
protected:
gfxMatrix mMatrix;
float mAngle, mOriginX, mOriginY;
PRUint16 mType;

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

@ -580,6 +580,9 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID,
rv = transformList->SetBaseValueString(aValue);
if (NS_FAILED(rv)) {
transformList->ClearBaseValue();
} else {
aResult.SetTo(transformList->GetBaseValue(), &aValue);
didSetResult = true;
}
foundMatch = true;
}
@ -787,8 +790,8 @@ nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName,
if (GetTransformListAttrName() == aName) {
SVGAnimatedTransformList *transformList = GetAnimatedTransformList();
if (transformList) {
MaybeSerializeAttrBeforeRemoval(aName, aNotify);
transformList->ClearBaseValue();
DidChangeTransformList(false);
return;
}
}
@ -2253,22 +2256,22 @@ nsSVGElement::DidAnimatePreserveAspectRatio()
}
}
void
nsSVGElement::DidChangeTransformList(bool aDoSetAttr)
nsAttrValue
nsSVGElement::WillChangeTransformList()
{
if (!aDoSetAttr)
return;
return WillChangeValue(GetTransformListAttrName());
}
SVGAnimatedTransformList* transformList = GetAnimatedTransformList();
NS_ABORT_IF_FALSE(transformList,
"DidChangeTransformList on element with no transform list");
void
nsSVGElement::DidChangeTransformList(const nsAttrValue& aEmptyOrOldValue)
{
NS_ABORT_IF_FALSE(GetTransformListAttrName(),
"Changing non-existent transform list?");
nsAutoString serializedValue;
transformList->GetBaseValue().GetValueAsString(serializedValue);
nsAttrValue newValue;
newValue.SetTo(GetAnimatedTransformList()->GetBaseValue(), nsnull);
nsAttrValue attrValue(serializedValue);
SetParsedAttr(kNameSpaceID_None, GetTransformListAttrName(), nsnull,
attrValue, true);
DidChangeValue(GetTransformListAttrName(), aEmptyOrOldValue, newValue);
}
void

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

@ -180,6 +180,7 @@ public:
nsAttrValue WillChangeLengthList(PRUint8 aAttrEnum);
nsAttrValue WillChangePointList();
nsAttrValue WillChangePathSegList();
nsAttrValue WillChangeTransformList();
void DidChangeLength(PRUint8 aAttrEnum, const nsAttrValue& aEmptyOrOldValue);
void DidChangeNumber(PRUint8 aAttrEnum);
@ -199,7 +200,7 @@ public:
const nsAttrValue& aEmptyOrOldValue);
void DidChangePointList(const nsAttrValue& aEmptyOrOldValue);
void DidChangePathSegList(const nsAttrValue& aEmptyOrOldValue);
virtual void DidChangeTransformList(bool aDoSetAttr);
void DidChangeTransformList(const nsAttrValue& aEmptyOrOldValue);
void DidChangeString(PRUint8 aAttrEnum) {}
void DidChangeStringList(bool aIsConditionalProcessingAttribute,
PRUint8 aAttrEnum);

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

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=602759
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="matrixUtils.js"></script>
<script type="text/javascript" src="MutationEventChecker.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@ -41,7 +42,8 @@ function main()
testCreateSVGTransformFromMatrix,
testReadOnly,
testOrphan,
testFailedSet
testFailedSet,
testMutationEvents
];
for (var i = 0; i < tests.length; i++) {
tests[i](g);
@ -355,6 +357,76 @@ function testFailedSet(g)
"Animated transform list should also be empty after setting bad value");
}
function testMutationEvents(g)
{
// Check mutation events
// Set initial value
g.setAttribute("transform", "translate(50 90)");
var list = g.transform.baseVal;
is(list.numberOfItems, 1, "Unexpected initial length of list");
eventChecker = new MutationEventChecker;
eventChecker.watchAttr(g, "transform");
// consolidate
//
// Consolidate happens to generate two modification events in our
// implementation--it's not ideal but it's better than none
eventChecker.expect("modify modify modify");
g.setAttribute("transform", "translate(10 10) translate(10 10)");
list.consolidate();
// In the following, each of the operations is performed twice but only one
// mutation event is expected. This is to check that redundant mutation
// events are not sent.
// transform.setMatrix
eventChecker.expect("modify");
var mx = $('svg').createSVGMatrix();
list[0].setMatrix(mx);
list[0].setMatrix(mx);
// transform.setTranslate
eventChecker.expect("modify");
list[0].setTranslate(10, 10);
list[0].setTranslate(10, 10);
// transform.setScale
eventChecker.expect("modify");
list[0].setScale(2, 2);
list[0].setScale(2, 2);
// transform.setRotate
eventChecker.expect("modify");
list[0].setRotate(45, 1, 2);
list[0].setRotate(45, 1, 2);
// transform.setSkewX
eventChecker.expect("modify");
list[0].setSkewX(45);
list[0].setSkewX(45);
// transform.setSkewY
eventChecker.expect("modify");
list[0].setSkewY(25);
list[0].setSkewY(25);
// transform.matrix
eventChecker.expect("modify modify");
list[0].matrix.a = 1;
list[0].matrix.a = 1;
list[0].matrix.e = 5;
list[0].matrix.e = 5;
// setAttribute interaction
eventChecker.expect("modify");
list[0].setMatrix(mx);
eventChecker.expect("");
g.setAttribute("transform", "matrix(1, 0, 0, 1, 0, 0)");
list[0].setMatrix(mx);
eventChecker.finish();
}
window.addEventListener("load", main, false);
]]>