Bug 539576 - SVGTransform matrix changes still not live in all circumstances. r=jwatt
authorRobert Longson <longsonr@gmail.com>
Mon, 25 Jan 2010 12:26:15 +0000
changeset 37470 5f41d14731bcaddecc29e933007c86bfbae840ca
parent 37469 36f740e8b791ea2e70c8e2d96df0575e6f9923d4
child 37471 ac2f963843327fe08c2a1053fdb6ba126cadff4e
push idunknown
push userunknown
push dateunknown
reviewersjwatt
bugs539576
milestone1.9.3a1pre
Bug 539576 - SVGTransform matrix changes still not live in all circumstances. r=jwatt
content/svg/content/src/nsSVGMatrix.cpp
content/svg/content/src/nsSVGTransform.cpp
content/svg/content/test/test_transform.xhtml
--- a/content/svg/content/src/nsSVGMatrix.cpp
+++ b/content/svg/content/src/nsSVGMatrix.cpp
@@ -310,29 +310,33 @@ NS_IMETHODIMP nsSVGMatrix::FlipY(nsIDOMS
 
 /* nsIDOMSVGMatrix skewX (in float angle); */
 NS_IMETHODIMP nsSVGMatrix::SkewX(float angle, nsIDOMSVGMatrix **_retval)
 {
   NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
 
   double ta = tan( angle*radPerDegree );
 
+  NS_ENSURE_FINITE(ta, NS_ERROR_DOM_SVG_INVALID_VALUE_ERR);
+
   return NS_NewSVGMatrix(_retval,
                          mA,                    mB,
                          (float) ( mC + mA*ta), (float) ( mD + mB*ta),
                          mE,                    mF);
 }
 
 /* nsIDOMSVGMatrix skewY (in float angle); */
 NS_IMETHODIMP nsSVGMatrix::SkewY(float angle, nsIDOMSVGMatrix **_retval)
 {
   NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
 
   double ta = tan( angle*radPerDegree );
 
+  NS_ENSURE_FINITE(ta, NS_ERROR_DOM_SVG_INVALID_VALUE_ERR);
+
   return NS_NewSVGMatrix(_retval,
                          (float) (mA + mC*ta), (float) (mB + mD*ta),
                          mC,                    mD,
                          mE,                    mF);
 }
 
 
 //----------------------------------------------------------------------
--- a/content/svg/content/src/nsSVGTransform.cpp
+++ b/content/svg/content/src/nsSVGTransform.cpp
@@ -41,16 +41,18 @@
 #include "nsSVGMatrix.h"
 #include "nsISVGValueUtils.h"
 #include "nsWeakReference.h"
 #include "nsSVGMatrix.h"
 #include "nsTextFormatter.h"
 #include "nsContentUtils.h"
 #include "nsDOMError.h"
 
+const double radPerDegree = 2.0*3.1415926535 / 360.0;
+
 //----------------------------------------------------------------------
 // Implementation
 
 nsresult
 nsSVGTransform::Create(nsIDOMSVGTransform** aResult)
 {
   nsSVGTransform *pl = new nsSVGTransform();
   NS_ENSURE_TRUE(pl, NS_ERROR_OUT_OF_MEMORY);
@@ -198,16 +200,19 @@ NS_IMETHODIMP nsSVGTransform::WillModify
 {
   WillModify();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsSVGTransform::DidModifySVGObservable (nsISVGValue* observable,
                                                       modificationType aModType)
 {
+  // we become a general matrix transform if mMatrix changes
+  mType = SVG_TRANSFORM_MATRIX;
+  mAngle = 0.0f;
   DidModify();
   return NS_OK;
 }
 
 
 //----------------------------------------------------------------------
 // nsIDOMSVGTransform methods:
 
@@ -240,76 +245,76 @@ NS_IMETHODIMP nsSVGTransform::SetMatrix(
 
   if (!matrix)
     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
 
   WillModify();
 
   mType = SVG_TRANSFORM_MATRIX;
   mAngle = 0.0f;
-  mOriginX = 0.0f;
-  mOriginY = 0.0f;
   
   matrix->GetA(&a);
   matrix->GetB(&b);
   matrix->GetC(&c);
   matrix->GetD(&d);
   matrix->GetE(&e);
   matrix->GetF(&f);
 
+  NS_REMOVE_SVGVALUE_OBSERVER(mMatrix);
   mMatrix->SetA(a);
   mMatrix->SetB(b);
   mMatrix->SetC(c);
   mMatrix->SetD(d);
   mMatrix->SetE(e);
   mMatrix->SetF(f);
+  NS_ADD_SVGVALUE_OBSERVER(mMatrix);
 
   DidModify();
   return NS_OK;
 }
 
 /* void setTranslate (in float tx, in float ty); */
 NS_IMETHODIMP nsSVGTransform::SetTranslate(float tx, float ty)
 {
   NS_ENSURE_FINITE2(tx, ty, NS_ERROR_ILLEGAL_VALUE);
 
   WillModify();
   
   mType = SVG_TRANSFORM_TRANSLATE;
   mAngle = 0.0f;
-  mOriginX = 0.0f;
-  mOriginY = 0.0f;
+  NS_REMOVE_SVGVALUE_OBSERVER(mMatrix);
   mMatrix->SetA(1.0f);
   mMatrix->SetB(0.0f);
   mMatrix->SetC(0.0f);
   mMatrix->SetD(1.0f);
   mMatrix->SetE(tx);
   mMatrix->SetF(ty);
+  NS_ADD_SVGVALUE_OBSERVER(mMatrix);
 
   DidModify();
   return NS_OK;
 }
 
 /* void setScale (in float sx, in float sy); */
 NS_IMETHODIMP nsSVGTransform::SetScale(float sx, float sy)
 {
   NS_ENSURE_FINITE2(sx, sy, NS_ERROR_ILLEGAL_VALUE);
 
   WillModify();
   
   mType = SVG_TRANSFORM_SCALE;
   mAngle = 0.0f;
-  mOriginX = 0.0f;
-  mOriginY = 0.0f;
+  NS_REMOVE_SVGVALUE_OBSERVER(mMatrix);
   mMatrix->SetA(sx);
   mMatrix->SetB(0.0f);
   mMatrix->SetC(0.0f);
   mMatrix->SetD(sy);
   mMatrix->SetE(0.0f);
   mMatrix->SetF(0.0f);
+  NS_ADD_SVGVALUE_OBSERVER(mMatrix);
 
   DidModify();
   return NS_OK;
 }
 
 /* void setRotate (in float angle, in float cx, in float cy); */
 NS_IMETHODIMP nsSVGTransform::SetRotate(float angle, float cx, float cy)
 {
@@ -317,67 +322,82 @@ NS_IMETHODIMP nsSVGTransform::SetRotate(
 
   WillModify();
   
   mType = SVG_TRANSFORM_ROTATE;
   mAngle = angle;
   mOriginX = cx;
   mOriginY = cy;
 
+  gfxMatrix matrix(1, 0, 0, 1, cx, cy);
+  matrix.Rotate(angle * radPerDegree);
+  matrix.Translate(gfxPoint(-cx, -cy));
+
   NS_REMOVE_SVGVALUE_OBSERVER(mMatrix);
-  NS_NewSVGMatrix(getter_AddRefs(mMatrix));
-  nsCOMPtr<nsIDOMSVGMatrix> temp;
-  mMatrix->Translate(cx, cy, getter_AddRefs(temp));
-  mMatrix = temp;
-  mMatrix->Rotate(angle, getter_AddRefs(temp));
-  mMatrix = temp;
-  mMatrix->Translate(-cx,-cy, getter_AddRefs(temp));
-  mMatrix = temp;
+  mMatrix->SetA(static_cast<float>(matrix.xx));
+  mMatrix->SetB(static_cast<float>(matrix.yx));
+  mMatrix->SetC(static_cast<float>(matrix.xy));
+  mMatrix->SetD(static_cast<float>(matrix.yy));
+  mMatrix->SetE(static_cast<float>(matrix.x0));
+  mMatrix->SetF(static_cast<float>(matrix.y0));
   NS_ADD_SVGVALUE_OBSERVER(mMatrix);
 
   DidModify();
   return NS_OK;
 }
 
 /* void setSkewX (in float angle); */
 NS_IMETHODIMP nsSVGTransform::SetSkewX(float angle)
 {
   NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
 
+  float ta = static_cast<float>(tan(angle * radPerDegree));
+
+  NS_ENSURE_FINITE(ta, NS_ERROR_DOM_SVG_INVALID_VALUE_ERR);
+
   WillModify();
   
   mType = SVG_TRANSFORM_SKEWX;
   mAngle = angle;
 
+
   NS_REMOVE_SVGVALUE_OBSERVER(mMatrix);
-  NS_NewSVGMatrix(getter_AddRefs(mMatrix));
-  nsCOMPtr<nsIDOMSVGMatrix> temp;
-  mMatrix->SkewX(angle, getter_AddRefs(temp));
-  mMatrix = temp;
+  mMatrix->SetA(1.0f);
+  mMatrix->SetB(0.0f);
+  mMatrix->SetC(ta);
+  mMatrix->SetD(ta);
+  mMatrix->SetE(0.0f);
+  mMatrix->SetF(0.0f);
   NS_ADD_SVGVALUE_OBSERVER(mMatrix);
 
   DidModify();
   return NS_OK;
 }
 
 /* void setSkewY (in float angle); */
 NS_IMETHODIMP nsSVGTransform::SetSkewY(float angle)
 {
   NS_ENSURE_FINITE(angle, NS_ERROR_ILLEGAL_VALUE);
 
+  float ta = static_cast<float>(tan(angle * radPerDegree));
+
+  NS_ENSURE_FINITE(ta, NS_ERROR_DOM_SVG_INVALID_VALUE_ERR);
+
   WillModify();
   
   mType = SVG_TRANSFORM_SKEWY;
   mAngle = angle;
 
   NS_REMOVE_SVGVALUE_OBSERVER(mMatrix);
-  NS_NewSVGMatrix(getter_AddRefs(mMatrix));
-  nsCOMPtr<nsIDOMSVGMatrix> temp;
-  mMatrix->SkewY(angle, getter_AddRefs(temp));
-  mMatrix = temp;
+  mMatrix->SetA(ta);
+  mMatrix->SetB(ta);
+  mMatrix->SetC(0.0f);
+  mMatrix->SetD(1.0f);
+  mMatrix->SetE(0.0f);
+  mMatrix->SetF(0.0f);
   NS_ADD_SVGVALUE_OBSERVER(mMatrix);
 
   DidModify();
   return NS_OK;
 }
 
 
 
--- a/content/svg/content/test/test_transform.xhtml
+++ b/content/svg/content/test/test_transform.xhtml
@@ -19,16 +19,24 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 <![CDATA[
 
 SimpleTest.waitForExplicitFinish();
 
+// We don't want to fail just because of rounding errors
+var tolerance = 1 / 65535;
+      
+function isequal( value, expected, tolerance )
+{
+  ok(Math.abs(value - expected) < tolerance, 'matrix value expected:' +expected + ' actual:' + value);
+}
+
 function run()
 {
   var g, svg, t, m, m2;
 
   svg = $('svg');
   g = $('g');
 
   t = g.transform.baseVal.getItem(0);
@@ -75,16 +83,59 @@ function run()
   is(m.a, 1, 'm.a for matrix');
   is(m.b, 2, 'm.b for matrix');
   is(m.c, 3, 'm.c for matrix');
   is(m.d, 4, 'm.d for matrix');
   is(m.e, 5, 'm.e for matrix');
   is(m.f, 6, 'm.f for matrix');
   is(t.angle, 0, 't.angle for matrix');
 
+  // set the SVGTransform to be a translate() then convert to a matrix
+  t.setTranslate(0, 0);
+  m.a = 2;
+
+  // test that the SVGTransform now reflects the matrix value
+  is(t.type, SVGTransform.SVG_TRANSFORM_MATRIX, 't.type for matrix');
+
+  // set the SVGTransform to be a rotate()
+  t.setRotate(90, 0, 0);
+
+  // test that the SVGTransform now reflects the matrix value
+  is(t.type, SVGTransform.SVG_TRANSFORM_ROTATE, 't.type for rotate');
+  isequal(m.a, Math.cos(Math.PI/2), tolerance);
+  isequal(m.b, Math.sin(Math.PI/2), tolerance);
+  isequal(m.c, -Math.sin(Math.PI/2), tolerance);
+  isequal(m.d, Math.cos(Math.PI/2), tolerance);
+  isequal(m.e, 0, tolerance);
+  isequal(m.f, 0, tolerance);
+
+  // set the SVGTransform to be a skewX()
+  t.setSkewX(45);
+
+  // test that the SVGTransform now reflects the matrix value
+  is(t.type, SVGTransform.SVG_TRANSFORM_SKEWX, 't.type for skewx');
+  isequal(m.a, 1, tolerance);
+  isequal(m.b, 0, tolerance);
+  isequal(m.c, Math.tan(Math.PI/4), tolerance);
+  isequal(m.d, Math.tan(Math.PI/4), tolerance);
+  isequal(m.e, 0, tolerance);
+  isequal(m.f, 0, tolerance);
+
+  // set the SVGTransform to be a skewY()
+  t.setSkewY(45);
+
+  // test that the SVGTransform now reflects the matrix value
+  is(t.type, SVGTransform.SVG_TRANSFORM_SKEWY, 't.type for skewy');
+  isequal(m.a, Math.tan(Math.PI/4), tolerance);
+  isequal(m.b, Math.tan(Math.PI/4), tolerance);
+  isequal(m.c, 0, tolerance);
+  isequal(m.d, 1, tolerance);
+  isequal(m.e, 0, tolerance);
+  isequal(m.f, 0, tolerance);
+
   SimpleTest.finish();
 }
 
 window.addEventListener("load", run, false);
 
 ]]>
 </script>
 </pre>