Bug 534028, Patch D: Tests for smil animation of mapped attributes. r=roc
authorDaniel Holbert <dholbert@cs.stanford.edu>
Tue, 16 Mar 2010 16:17:33 -0700
changeset 39489 cf62ca96cd0d
parent 39488 33632ecef69c
child 39490 9e96f8553258
push id12227
push userdholbert@mozilla.com
push dateTue, 16 Mar 2010 23:20:42 +0000
treeherdermozilla-central@9e96f8553258 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs534028
milestone1.9.3a4pre
Bug 534028, Patch D: Tests for smil animation of mapped attributes. r=roc
content/smil/test/Makefile.in
content/smil/test/db_smilMappedAttrList.js
content/smil/test/smilTestUtils.js
content/smil/test/test_smilCSSFromBy.xhtml
content/smil/test/test_smilCSSFromTo.xhtml
content/smil/test/test_smilCSSPaced.xhtml
content/smil/test/test_smilMappedAttrFromBy.xhtml
content/smil/test/test_smilMappedAttrFromTo.xhtml
content/smil/test/test_smilMappedAttrPaced.xhtml
layout/reftests/svg/smil/mapped-attr-vs-css-prop-1.svg
layout/reftests/svg/smil/reftest.list
--- a/content/smil/test/Makefile.in
+++ b/content/smil/test/Makefile.in
@@ -44,27 +44,31 @@ relativesrcdir  = content/smil/test
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
 	  db_smilCSSFromBy.js \
 	  db_smilCSSFromTo.js \
 	  db_smilCSSPaced.js \
 	  db_smilCSSPropertyList.js \
+	  db_smilMappedAttrList.js \
 	  smilTestUtils.js \
 	  smilXHR_helper.svg \
 	  test_smilChangeAfterFrozen.xhtml \
 	  test_smilContainerBinding.xhtml \
 	  test_smilCrossContainer.xhtml \
 	  test_smilCSSFontStretchRelative.xhtml \
 	  test_smilCSSFromBy.xhtml \
 	  test_smilCSSFromTo.xhtml \
 	  test_smilCSSInherit.xhtml \
 	  test_smilCSSInvalidValues.xhtml \
 	  test_smilCSSPaced.xhtml \
+	  test_smilMappedAttrFromTo.xhtml \
+	  test_smilMappedAttrFromBy.xhtml \
+	  test_smilMappedAttrPaced.xhtml \
 	  test_smilReset.xhtml \
 	  test_smilRestart.xhtml \
 	  test_smilFillMode.xhtml \
 	  test_smilGetStartTime.xhtml \
 	  test_smilGetSimpleDuration.xhtml \
 	  test_smilKeySplines.xhtml \
 	  test_smilSetCurrentTime.xhtml \
 	  test_smilSync.xhtml \
new file mode 100644
--- /dev/null
+++ b/content/smil/test/db_smilMappedAttrList.js
@@ -0,0 +1,164 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SMIL Test Code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Holbert <dholbert@mozilla.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* List of SVG presentational attributes in the SVG 1.1 spec, for use in
+   mochitests. (These are the attributes that are mapped to CSS properties) */
+
+var gMappedAttrList =
+{
+  // NOTE: The list here should match the MappedAttributeEntry arrays in
+  // nsSVGElement.cpp
+
+  // PresentationAttributes-FillStroke
+  fill:              new AdditiveAttribute("fill", "XML", "rect"),
+  fill_opacity:      new AdditiveAttribute("fill-opacity", "XML", "rect"),
+  fill_rule:         new NonAdditiveAttribute("fill-rule", "XML", "rect"),
+  stroke:            new AdditiveAttribute("stroke", "XML", "rect"),
+  stroke_dasharray:
+    new NonAdditiveAttribute("stroke-dasharray", "XML", "rect"),
+  stroke_dashoffset: new AdditiveAttribute("stroke-dashoffset", "XML", "rect"),
+  stroke_linecap:    new NonAdditiveAttribute("stroke-linecap", "XML", "rect"),
+  stroke_linejoin:   new NonAdditiveAttribute("stroke-linejoin", "XML", "rect"),
+  stroke_miterlimit: new AdditiveAttribute("stroke-miterlimit", "XML", "rect"),
+  stroke_opacity:    new AdditiveAttribute("stroke-opacity", "XML", "rect"),
+  stroke_width:      new AdditiveAttribute("stroke-width", "XML", "rect"),
+
+  // PresentationAttributes-Graphics
+  clip_path:         new NonAdditiveAttribute("clip-path", "XML", "rect"),
+  clip_rule:         new NonAdditiveAttribute("clip-rule", "XML", "circle"),
+  color_interpolation:
+    new NonAdditiveAttribute("color-interpolation", "XML", "rect"),
+  cursor:            new NonAdditiveAttribute("cursor", "XML", "rect"),
+  display:           new NonAdditiveAttribute("display", "XML", "rect"),
+  filter:            new NonAdditiveAttribute("filter", "XML", "rect"),
+  image_rendering:
+    NonAdditiveAttribute("image-rendering", "XML", "image"),
+  mask:              new NonAdditiveAttribute("mask", "XML", "line"),
+  pointer_events:    new NonAdditiveAttribute("pointer-events", "XML", "rect"),
+  shape_rendering:   new NonAdditiveAttribute("shape-rendering", "XML", "rect"),
+  text_rendering:    new NonAdditiveAttribute("text-rendering", "XML", "text"),
+  visibility:        new NonAdditiveAttribute("visibility", "XML", "rect"),
+
+  // PresentationAttributes-TextContentElements
+  // SKIP 'alignment-baseline' property: animatable but not supported by Mozilla
+  // SKIP 'baseline-shift' property: animatable but not supported by Mozilla
+  direction:         new NonAnimatableAttribute("direction", "XML", "text"),
+  dominant_baseline:
+    new NonAdditiveAttribute("dominant-baseline", "XML", "text"),
+  glyph_orientation_horizontal:
+    // NOTE: Not supported by Mozilla, but explicitly non-animatable
+    NonAnimatableAttribute("glyph-orientation-horizontal", "XML", "text"),
+  glyph_orientation_vertical:
+    // NOTE: Not supported by Mozilla, but explicitly non-animatable
+    NonAnimatableAttribute("glyph-orientation-horizontal", "XML", "text"),
+  // SKIP 'kerning' property: animatable but not supported by Mozilla
+  letter_spacing:    new AdditiveAttribute("letter-spacing", "XML", "text"),
+  text_anchor:       new NonAdditiveAttribute("text-anchor", "XML", "text"),
+  text_decoration:   new NonAdditiveAttribute("text-decoration", "XML", "text"),
+  unicode_bidi:      new NonAnimatableAttribute("unicode-bidi", "XML", "text"),
+  word_spacing:      new AdditiveAttribute("word-spacing", "XML", "text"),
+
+  // PresentationAttributes-FontSpecification
+  font_family:       new NonAdditiveAttribute("font-family", "XML", "text"),
+  font_size:         new AdditiveAttribute("font-size", "XML", "text"),
+  font_size_adjust:
+    new NonAdditiveAttribute("font-size-adjust", "XML", "text"),
+  font_stretch:      new NonAdditiveAttribute("font-stretch", "XML", "text"),
+  font_style:        new NonAdditiveAttribute("font-style", "XML", "text"),
+  font_variant:      new NonAdditiveAttribute("font-variant", "XML", "text"),
+  font_weight:       new NonAdditiveAttribute("font-weight", "XML", "text"),
+
+  // PresentationAttributes-GradientStop
+  stop_color:        new AdditiveAttribute("stop-color", "XML", "stop"),
+  stop_opacity:      new AdditiveAttribute("stop-opacity", "XML", "stop"),
+
+  // PresentationAttributes-Viewports
+  overflow:          new NonAdditiveAttribute("overflow", "XML", "marker"),
+  clip:              new AdditiveAttribute("clip", "XML", "marker"),
+
+  // PresentationAttributes-Makers
+  marker:            new NonAdditiveAttribute("marker", "XML", "line"),
+  marker_end:        new NonAdditiveAttribute("marker-end", "XML", "line"),
+  marker_mid:        new NonAdditiveAttribute("marker-mid", "XML", "line"),
+  marker_start:      new NonAdditiveAttribute("marker-start", "XML", "line"),
+
+  // PresentationAttributes-Color
+  color:             new AdditiveAttribute("color", "XML", "rect"),
+
+  // PresentationAttributes-Filters
+  color_interpolation_filters:
+    new NonAdditiveAttribute("color-interpolation-filters", "XML",
+                             "feFlood"),
+
+  // PresentationAttributes-feFlood
+  flood_color:       new AdditiveAttribute("flood-color", "XML", "feFlood"),
+  flood_opacity:     new AdditiveAttribute("flood-opacity", "XML", "feFlood"),
+
+  // PresentationAttributes-LightingEffects
+  lighting_color:
+    new AdditiveAttribute("lighting-color", "XML", "feDiffuseLighting"),
+};
+
+// Utility method to copy a list of TestcaseBundle objects for CSS properties
+// into a list of TestcaseBundles for the corresponding mapped attributes.
+function convertCSSBundlesToMappedAttr(bundleList) {
+  // Create mapping of property names to the corresponding
+  // mapped-attribute object in gMappedAttrList.
+  var propertyNameToMappedAttr = {};
+  for (attributeLabel in gMappedAttrList) {
+    var propName = gMappedAttrList[attributeLabel].attrName;
+    propertyNameToMappedAttr[propName] = gMappedAttrList[attributeLabel];
+  }
+
+  var convertedBundles = [];
+  for (var bundleIdx in bundleList) {
+    var origBundle = bundleList[bundleIdx];
+    var propName = origBundle.animatedAttribute.attrName;
+    if (propertyNameToMappedAttr[propName]) {
+      // There's a mapped attribute by this name! Duplicate the TestcaseBundle,
+      // using the Mapped Attribute instead of the CSS Property.
+      is(origBundle.animatedAttribute.attrType, "CSS",
+         "expecting to be converting from CSS to XML");
+      convertedBundles.push(
+        new TestcaseBundle(propertyNameToMappedAttr[propName],
+                           origBundle.testcaseList,
+                           origBundle.skipReason));
+    }
+  }
+  return convertedBundles;
+}
--- a/content/smil/test/smilTestUtils.js
+++ b/content/smil/test/smilTestUtils.js
@@ -73,20 +73,32 @@ var SMILUtil =
   // Returns the first element in the document with the matching tag
   getFirstElemWithTag : function(aTargetTag)
   {
     var elemList = document.getElementsByTagName(aTargetTag);
     return (elemList.length == 0 ? null : elemList[0]);
   },
 
   // Simple wrapper for getComputedStyle
-  getComputedStyleSimple: function(elem, prop) {
+  getComputedStyleSimple: function(elem, prop)
+  {
     return window.getComputedStyle(elem, null).getPropertyValue(prop);
   },
 
+  getAttributeValue: function(elem, attr)
+  {
+    if (attr.attrType == "CSS") {
+      return SMILUtil.getComputedStyleWrapper(elem, attr.attrName);
+    } else if (attr.attrType == "XML") {
+      // XXXdholbert This is appropriate for mapped attributes, but not
+      // for others.
+      return SMILUtil.getComputedStyleWrapper(elem, attr.attrName);
+    }
+  },
+
   // Smart wrapper for getComputedStyle, which will generate a "fake" computed
   // style for recognized shorthand properties (font, overflow, marker)
   getComputedStyleWrapper : function(elem, propName)
   {
     // Special cases for shorthand properties (which aren't directly queriable
     // via getComputedStyle)
     var computedStyle;
     if (propName == "font") {
@@ -131,29 +143,33 @@ var SMILUtil =
     } else {
       computedStyle = SMILUtil.getComputedStyleSimple(elem, propName);
     }
     return computedStyle;
   },
   
   // This method hides (i.e. sets "display: none" on) all of the given node's
   // descendents.  It also hides the node itself, if requested.
-  hideSubtree : function(node, hideNodeItself)
+  hideSubtree : function(node, hideNodeItself, useXMLAttribute)
   {
     // Hide node, if requested
     if (hideNodeItself) {
-      if (node.style) {
+      if (useXMLAttribute) {
+        if (node.setAttribute) {
+          node.setAttribute("display", "none");
+        }
+      } else if (node.style) {
         node.style.display = "none";
       }
     }
 
     // Hide node's descendents
     var child = node.firstChild;
     while (child) {
-      SMILUtil.hideSubtree(child, true);
+      SMILUtil.hideSubtree(child, true, useXMLAttribute);
       child = child.nextSibling;
     }
   },
 }
 
 // Wrapper for timing information
 function SMILTimingData(aBegin, aDur)
 {
@@ -294,47 +310,46 @@ AnimTestcase.prototype =
   computedValMap      : null,
   skipReason          : null,
   
   // Methods
   /**
    * runTest: Runs this AnimTestcase
    *
    * @param aTargetElem The node to be targeted in our test animation.
-   * @param aAnimAttr An Attribute object representing the attribute
-   *                  to be targeted in our test animation.
+   * @param aTargetAttr An Attribute object representing the attribute
+   *                    to be targeted in our test animation.
    * @param aTimeData A SMILTimingData object with timing information for
    *                  our test animation.
    * @param aIsFreeze If true, indicates that our test animation should use
    *                  fill="freeze"; otherwise, we'll default to fill="remove".
    */
-  runTest : function(aTargetElem, aAnimAttr, aTimeData, aIsFreeze)
+  runTest : function(aTargetElem, aTargetAttr, aTimeData, aIsFreeze)
   {
     // SANITY CHECKS
     if (!SMILUtil.getSVGRoot().animationsPaused()) {
       ok(false, "Should start each test with animations paused");
     }
     if (SMILUtil.getSVGRoot().getCurrentTime() != 0) {
       ok(false, "Should start each test at time = 0");
     }
 
     // SET UP
     // Cache initial computed value
-    var baseVal = SMILUtil.getComputedStyleWrapper(aTargetElem,
-                                                   aAnimAttr.attrName);
+    var baseVal = SMILUtil.getAttributeValue(aTargetElem, aTargetAttr);
 
     // Create & append animation element
-    var anim = this.setupAnimationElement(aAnimAttr, aTimeData, aIsFreeze);
+    var anim = this.setupAnimationElement(aTargetAttr, aTimeData, aIsFreeze);
     aTargetElem.appendChild(anim);
 
     // Build a list of [seek-time, expectedValue, errorMessage] triplets
-    var seekList = this.buildSeekList(aAnimAttr, baseVal, aTimeData, aIsFreeze);
+    var seekList = this.buildSeekList(aTargetAttr, baseVal, aTimeData, aIsFreeze);
 
     // DO THE ACTUAL TESTING
-    this.seekAndTest(seekList, aTargetElem, aAnimAttr.attrName);
+    this.seekAndTest(seekList, aTargetElem, aTargetAttr);
 
     // CLEAN UP
     aTargetElem.removeChild(anim);
     SMILUtil.getSVGRoot().setCurrentTime(0);
   },
 
   // HELPER FUNCTIONS
   // setupAnimationElement: <animate> element
@@ -368,17 +383,17 @@ AnimTestcase.prototype =
   },
 
   seekAndTest : function(aSeekList, aTargetElem, aTargetAttr)
   {
     var svg = document.getElementById("svg");
     for (var i in aSeekList) {
       var entry = aSeekList[i];
       SMILUtil.getSVGRoot().setCurrentTime(entry[0]);
-      is(SMILUtil.getComputedStyleWrapper(aTargetElem, aTargetAttr),
+      is(SMILUtil.getAttributeValue(aTargetElem, aTargetAttr),
          entry[1], entry[2]);
     }
   },
 
   // methods that expect to be overridden in subclasses
   buildSeekListStatic : function(aAnimAttr, aBaseVal,
                                  aTimeData, aReasonStatic) {},
   buildSeekListAnimated : function(aAnimAttr, aBaseVal,
@@ -418,16 +433,23 @@ AnimTestcaseFrom.prototype =
                    msgPrefix + "(after animation end) - " + aReasonStatic]);
     return seekList;
   },
 
   buildSeekListAnimated : function(aAnimAttr, aBaseVal, aTimeData, aIsFreeze)
   {
     var seekList = new Array();
     var msgPrefix = aAnimAttr.attrName + ": ";
+    if (aTimeData.getBeginTime() > 0.1) {
+      seekList.push([aTimeData.getBeginTime() - 0.1,
+                    aBaseVal,
+                     msgPrefix + "checking that base value is set " +
+                     "before start of animation"]);
+    }
+
     seekList.push([aTimeData.getBeginTime(),
                    this.computedValMap.fromComp || this.from,
                    msgPrefix + "checking that 'from' value is set " +
                    "at start of animation"]);
     seekList.push([aTimeData.getFractionalTime(1/2),
                    this.computedValMap.midComp ||
                    this.computedValMap.toComp || this.to,
                    msgPrefix + "checking value halfway through animation"]);
--- a/content/smil/test/test_smilCSSFromBy.xhtml
+++ b/content/smil/test/test_smilCSSFromBy.xhtml
@@ -41,17 +41,17 @@ function main()
   // Start out with document paused
   var svg = SMILUtil.getSVGRoot();
   ok(svg.animationsPaused(), "should be paused by <svg> load handler");
   is(svg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
 
   testBundleList(gFromByBundles, new SMILTimingData(1.0, 1.0));
 
   // Set "display:none" on everything and run the tests again
-  SMILUtil.hideSubtree(SMILUtil.getSVGRoot(), false);
+  SMILUtil.hideSubtree(SMILUtil.getSVGRoot(), false, false);
   testBundleList(gFromByBundles, new SMILTimingData(1.0, 1.0));
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", main, false);
 ]]>
 </script>
--- a/content/smil/test/test_smilCSSFromTo.xhtml
+++ b/content/smil/test/test_smilCSSFromTo.xhtml
@@ -68,17 +68,17 @@ function main()
 
   // FIRST: Warn about any properties that are missing tests
   checkForUntestedProperties(gFromToBundles);
 
   // Run the actual tests
   testBundleList(gFromToBundles, new SMILTimingData(1.0, 1.0));
 
   // Set "display:none" on everything and run the tests again
-  SMILUtil.hideSubtree(SMILUtil.getSVGRoot(), false);
+  SMILUtil.hideSubtree(SMILUtil.getSVGRoot(), false, false);
   testBundleList(gFromToBundles, new SMILTimingData(1.0, 1.0));
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", main, false);
 ]]>
 </script>
--- a/content/smil/test/test_smilCSSPaced.xhtml
+++ b/content/smil/test/test_smilCSSPaced.xhtml
@@ -35,17 +35,17 @@ function main()
 
   // Start out with document paused
   var svg = SMILUtil.getSVGRoot();
   ok(svg.animationsPaused(), "should be paused by <svg> load handler");
   is(svg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
 
   testBundleList(gPacedBundles, new SMILTimingData(1.0, 6.0));
   // Set "display:none" on everything and run the tests again
-  SMILUtil.hideSubtree(SMILUtil.getSVGRoot(), false);
+  SMILUtil.hideSubtree(SMILUtil.getSVGRoot(), false, false);
   testBundleList(gPacedBundles, new SMILTimingData(1.0, 6.0));
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", main, false);
 ]]>
 </script>
copy from content/smil/test/test_smilCSSFromBy.xhtml
copy to content/smil/test/test_smilMappedAttrFromBy.xhtml
--- a/content/smil/test/test_smilCSSFromBy.xhtml
+++ b/content/smil/test/test_smilMappedAttrFromBy.xhtml
@@ -1,14 +1,15 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
   <title>Test for Animation Behavior on CSS Properties</title>
   <script type="text/javascript" src="/MochiKit/packed.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="smilTestUtils.js"></script>
+  <script type="text/javascript" src="db_smilMappedAttrList.js"></script>
   <script type="text/javascript" src="db_smilCSSPropertyList.js"></script>
   <script type="text/javascript" src="db_smilCSSFromBy.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <p id="display"></p>
 <div id="content">
 <svg xmlns="http://www.w3.org/2000/svg"
@@ -38,21 +39,22 @@ function main()
     return;
   }
 
   // Start out with document paused
   var svg = SMILUtil.getSVGRoot();
   ok(svg.animationsPaused(), "should be paused by <svg> load handler");
   is(svg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
 
-  testBundleList(gFromByBundles, new SMILTimingData(1.0, 1.0));
+  var testBundles = convertCSSBundlesToMappedAttr(gFromByBundles);
+  testBundleList(testBundles, new SMILTimingData(1.0, 1.0));
 
   // Set "display:none" on everything and run the tests again
-  SMILUtil.hideSubtree(SMILUtil.getSVGRoot(), false);
-  testBundleList(gFromByBundles, new SMILTimingData(1.0, 1.0));
+  SMILUtil.hideSubtree(SMILUtil.getSVGRoot(), false, true);
+  testBundleList(testBundles, new SMILTimingData(1.0, 1.0));
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", main, false);
 ]]>
 </script>
 </pre>
new file mode 100644
--- /dev/null
+++ b/content/smil/test/test_smilMappedAttrFromTo.xhtml
@@ -0,0 +1,90 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <title>Test for Animation Behavior on CSS Properties</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="smilTestUtils.js"></script>
+  <script type="text/javascript" src="db_smilMappedAttrList.js"></script>
+  <script type="text/javascript" src="db_smilCSSPropertyList.js"></script>
+  <script type="text/javascript" src="db_smilCSSFromTo.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+<svg xmlns="http://www.w3.org/2000/svg"
+     width="200px" height="200px" font-size="50px" style="color: rgb(50,50,50)"
+     onload="this.pauseAnimations()">
+  <rect x="20" y="20" width="200" height="200"/>
+  <!-- NOTE: hard-wiring 'line-height' so that computed value of 'font' is
+       more predictable. (otherwise, line-height varies depending on platform)
+    -->
+  <text x="20" y="20">testing 123</text>
+  <line/>
+  <image/>
+  <marker/>
+  <clipPath><circle/></clipPath>
+  <filter><feFlood/></filter>
+  <filter><feDiffuseLighting/></filter>
+  <linearGradient><stop/></linearGradient>
+</svg>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function checkForUntestedAttributes(bundleList)
+{
+  // Create the set of all the attributes we know about
+  var attributeSet = {};
+  for (attributeLabel in gMappedAttrList) {
+    // insert attribute
+    attributeSet[gMappedAttrList[attributeLabel].attrName] = null;
+  }
+  // Remove tested properties from the set
+  for (var bundleIdx in bundleList) {
+    var bundle = bundleList[bundleIdx];
+    delete attributeSet[bundle.animatedAttribute.attrName];
+  }
+  // Warn about remaining (untested) properties
+  for (var untestedProp in attributeSet) {
+    ok(false, "No tests for attribute '" + untestedProp + "'");
+  }
+}
+
+function main()
+{
+  if (!SMILUtil.isSMILEnabled()) {
+    ok(false, "SMIL dosn't seem to be enabled");
+    SimpleTest.finish();
+    return;
+  }
+
+  // Start out with document paused
+  var svg = SMILUtil.getSVGRoot();
+  ok(svg.animationsPaused(), "should be paused by <svg> load handler");
+  is(svg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
+
+  var testBundles = convertCSSBundlesToMappedAttr(gFromToBundles);
+
+  // FIRST: Warn about any attributes that are missing tests
+  checkForUntestedAttributes(testBundles);
+
+  // Run the actual tests
+  testBundleList(testBundles, new SMILTimingData(1.0, 1.0));
+
+  // Set "display:none" on everything and run the tests again
+  SMILUtil.hideSubtree(SMILUtil.getSVGRoot(), false, true);
+  testBundleList(testBundles, new SMILTimingData(1.0, 1.0));
+
+  SimpleTest.finish();
+}
+
+window.addEventListener("load", main, false);
+]]>
+</script>
+</pre>
+</body>
+</html>
copy from content/smil/test/test_smilCSSPaced.xhtml
copy to content/smil/test/test_smilMappedAttrPaced.xhtml
--- a/content/smil/test/test_smilCSSPaced.xhtml
+++ b/content/smil/test/test_smilMappedAttrPaced.xhtml
@@ -1,14 +1,15 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
   <title>Test for Animation Behavior on CSS Properties</title>
   <script type="text/javascript" src="/MochiKit/packed.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="smilTestUtils.js"></script>
+  <script type="text/javascript" src="db_smilMappedAttrList.js"></script>
   <script type="text/javascript" src="db_smilCSSPropertyList.js"></script>
   <script type="text/javascript" src="db_smilCSSPaced.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <p id="display"></p>
 <div id="content">
 <svg xmlns="http://www.w3.org/2000/svg"
@@ -33,20 +34,22 @@ function main()
     return;
   }
 
   // Start out with document paused
   var svg = SMILUtil.getSVGRoot();
   ok(svg.animationsPaused(), "should be paused by <svg> load handler");
   is(svg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
 
-  testBundleList(gPacedBundles, new SMILTimingData(1.0, 6.0));
+  var testBundles = convertCSSBundlesToMappedAttr(gPacedBundles);
+  testBundleList(testBundles, new SMILTimingData(1.0, 6.0));
+
   // Set "display:none" on everything and run the tests again
-  SMILUtil.hideSubtree(SMILUtil.getSVGRoot(), false);
-  testBundleList(gPacedBundles, new SMILTimingData(1.0, 6.0));
+  SMILUtil.hideSubtree(SMILUtil.getSVGRoot(), false, true);
+  testBundleList(testBundles, new SMILTimingData(1.0, 6.0));
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", main, false);
 ]]>
 </script>
 </pre>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/smil/mapped-attr-vs-css-prop-1.svg
@@ -0,0 +1,125 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     class="reftest-wait"
+     onload="setTimeAndSnapshot(1, false)">
+  <script xlink:href="smil-util.js" type="text/javascript"/>
+  <!-- This test consists of a 4x3 grid, containing various cases with
+       animations that have attributeType="CSS" vs "XML", for the
+       presentational ("mapped") attribute 'fill-opacity'.
+
+       As one would expect, the "CSS" and "XML" versions are treated as
+       separate animation targets.  However, there are some interactions:
+         - When they conflict, both the inline style & any animations with
+           attributeType="CSS" will have higher priority than the XML attribute
+           and animations with attributeType="XML".
+         - However, as described in the "FIRST ROW" comment below, animations
+           with attributeType="XML" can sometimes feed in to the base value
+           used for animations with attributeType="CSS". -->
+
+  <!-- GIANT GREEN BACKGROUND -->
+  <!-- (We'll put red rects on top, and then animate them to be transparent -->
+  <rect height="100%" width="100%" fill="lime" />
+
+  <!-- FIRST ROW: Additive CSS and XML animations, with CSS or XML base values.
+
+       When the base value is set using the inline style attribute, the
+       attributeType="XML" animation should be ignored, because the XML
+       attribute gets masked by the inline style.
+
+       However, when the base value is set using the XML attribute (or more
+       generally, when attributeType="XML" animations aren't masked by a value
+       in the inline style or in a stylesheet), then the animations will
+       effectively add together, because the (animated) XML attribute feeds
+       into the computed style, which gets used as the base value for the CSS
+       animation. -->
+  <g>
+    <!-- CSS base value + CSS animation + XML animation -->
+    <rect x="0" width="50" height="50" fill="red" style="fill-opacity: 0.5">
+      <animate attributeName="fill-opacity" attributeType="XML"
+               by="1" dur="1s" fill="freeze"/>
+      <animate attributeName="fill-opacity" attributeType="CSS"
+               by="-0.5" dur="1s" fill="freeze"/>
+    </rect>
+    <!-- CSS base value + XML animation + CSS animation -->
+    <rect x="50" width="50" height="50" fill="red" style="fill-opacity: 0.5">
+      <animate attributeName="fill-opacity" attributeType="CSS"
+               by="-0.5" dur="1s" fill="freeze"/>
+      <animate attributeName="fill-opacity" attributeType="XML"
+               by="1" dur="1s" fill="freeze"/>
+    </rect>
+    <!-- XML base value + CSS animation + XML animation -->
+    <rect x="100" width="50" height="50" fill="red" fill-opacity="0.5">
+      <animate attributeName="fill-opacity" attributeType="XML"
+               by="-0.2" dur="1s" fill="freeze"/>
+      <animate attributeName="fill-opacity" attributeType="CSS"
+               by="-0.3" dur="1s" fill="freeze"/>
+    </rect>
+    <!-- XML base value + XML animation + CSS animation -->
+    <rect x="150" width="50" height="50" fill="red" fill-opacity="0.5">
+      <animate attributeName="fill-opacity" attributeType="CSS"
+               by="-0.2" dur="1s" fill="freeze"/>
+      <animate attributeName="fill-opacity" attributeType="XML"
+               by="-0.3" dur="1s" fill="freeze"/>
+    </rect>
+  </g>
+
+  <!-- SECOND ROW: Single animation, with CSS or XML attributeType & base value.
+       In every case except for CSS-base-value + XML animation, the animation
+       should take effect. -->
+  <g transform="translate(0, 50)">
+    <!-- CSS base value + CSS animation -->
+    <rect x="0" width="50" height="50" fill="red" style="fill-opacity: 0.5">
+      <animate attributeName="fill-opacity" attributeType="CSS"
+               to="0" dur="1s" fill="freeze"/>
+    </rect>
+    <!-- CSS base value + XML animation -->
+    <!-- (starting at fill-opacity 0, since anim shouldn't have any effect -->
+    <rect x="50" width="50" height="50" fill="red" style="fill-opacity: 0">
+      <animate attributeName="fill-opacity" attributeType="XML"
+               to="0.5" dur="1s" fill="freeze"/>
+    </rect>
+    <!-- XML base value + CSS animation -->
+    <rect x="100" width="50" height="50" fill="red" fill-opacity="0.5">
+      <animate attributeName="fill-opacity" attributeType="CSS"
+               to="0" dur="1s" fill="freeze"/>
+    </rect>
+    <!-- XML base value + XML animation -->
+    <rect x="150" width="50" height="50" fill="red" fill-opacity="0.5">
+      <animate attributeName="fill-opacity" attributeType="XML"
+               to="0" dur="1s" fill="freeze"/>
+    </rect>
+  </g>
+
+  <!-- THIRD ROW: Competing animations, with CSS or XML attributeType & base
+       value. In each case, the attributeType="CSS" animation should win. -->
+  <g transform="translate(0, 100)">
+    <!-- CSS base value + CSS animation animation vs XML animation -->
+    <rect x="0" width="50" height="50" fill="red" style="fill-opacity: 0.5">
+      <animate attributeName="fill-opacity" attributeType="CSS"
+               to="0" dur="1s" fill="freeze"/>
+      <animate attributeName="fill-opacity" attributeType="XML"
+               to="1" dur="1s" fill="freeze"/>
+    </rect>
+    <!-- CSS base value + XML animation vs CSS animation -->
+    <rect x="50" width="50" height="50" fill="red" style="fill-opacity: 0.5">
+      <animate attributeName="fill-opacity" attributeType="XML"
+               to="1" dur="1s" fill="freeze"/>
+      <animate attributeName="fill-opacity" attributeType="CSS"
+               to="0" dur="1s" fill="freeze"/>
+    </rect>
+    <!-- XML base value + CSS animation vs XML animation -->
+    <rect x="100" width="50" height="50" fill="red" fill-opacity="0.5">
+      <animate attributeName="fill-opacity" attributeType="CSS"
+               to="0" dur="1s" fill="freeze"/>
+      <animate attributeName="fill-opacity" attributeType="XML"
+               to="1" dur="1s" fill="freeze"/>
+    </rect>
+    <!-- XML base value + XML animation vs CSS animation -->
+    <rect x="150" width="50" height="50" fill="red" fill-opacity="0.5">
+      <animate attributeName="fill-opacity" attributeType="XML"
+               to="1" dur="1s" fill="freeze"/>
+      <animate attributeName="fill-opacity" attributeType="CSS"
+               to="0" dur="1s" fill="freeze"/>
+    </rect>
+  </g>
+</svg>
--- a/layout/reftests/svg/smil/reftest.list
+++ b/layout/reftests/svg/smil/reftest.list
@@ -56,17 +56,17 @@ include syncbase/reftest.list
 == anim-discrete-to-1.svg          anim-standard-ref.svg
 == anim-discrete-to-2.svg          anim-standard-ref.svg
 == anim-discrete-to-3.svg          anim-standard-ref.svg
 == anim-discrete-to-4.svg          anim-standard-ref.svg
 
 fails == anim-fillcolor-1.svg      anim-standard-ref.svg # bug 436296
 == anim-fillopacity-1none.svg anim-standard-ref.svg
 == anim-fillopacity-1css.svg  anim-standard-ref.svg
-fails == anim-fillopacity-1xml.svg  anim-standard-ref.svg # bug 534028
+== anim-fillopacity-1xml.svg  anim-standard-ref.svg
 
 == anim-height-done-1a.svg anim-standard-ref.svg
 == anim-height-done-1b.svg anim-standard-ref.svg
 == anim-height-interp-1.svg anim-height-interp-1-ref.svg
 == anim-height-interp-2.svg anim-height-interp-2-ref.svg
 == anim-height-interp-3.svg anim-height-interp-3-ref.svg
 == anim-height-interp-4.svg anim-height-interp-4-ref.svg
 == anim-height-interp-5.svg anim-height-interp-5-ref.svg
@@ -116,17 +116,17 @@ fails == anim-fillopacity-1xml.svg  anim
 == anim-retarget-3.svg anim-standard-ref.svg
 == anim-retarget-4.svg anim-standard-ref.svg
 == anim-retarget-5.svg anim-standard-ref.svg
 == anim-retarget-6.svg anim-standard-ref.svg
 == anim-retarget-7.svg anim-standard-ref.svg
 == anim-retarget-8.svg anim-standard-ref.svg
 
 fails == anim-strokecolor-1.svg anim-standard-ref.svg # bug 436296
-fails == anim-strokewidth-1xml.svg anim-standard-ref.svg # bug 534028
+== anim-strokewidth-1xml.svg anim-standard-ref.svg
 
 == anim-targethref-1.svg anim-standard-ref.svg
 == anim-targethref-2.svg anim-standard-ref.svg
 == anim-targethref-3.svg anim-standard-ref.svg
 == anim-targethref-4.svg anim-standard-ref.svg
 == anim-targethref-5.svg anim-standard-ref.svg
 == anim-targethref-6.svg anim-standard-ref.svg
 == anim-targethref-7.svg anim-standard-ref.svg
@@ -157,12 +157,15 @@ fails == anim-strokewidth-1xml.svg anim-
 == freeze-applied-late-1.svg anim-standard-ref.svg
 == freeze-applied-late-2.svg anim-standard-ref.svg
 == freeze-applied-late-3.svg anim-standard-ref.svg
 == freeze-applied-late-4.svg anim-standard-ref.svg
 
 == inactivate-with-active-unchanged-1.svg anim-standard-ref.svg
 == inactivate-with-active-unchanged-2.svg anim-standard-ref.svg
 
+# interaction between xml mapped attributes and their css equivalents
+== mapped-attr-vs-css-prop-1.svg lime.svg
+
 == smil-transitions-interaction-1.svg lime.svg
 == smil-transitions-interaction-2.svg lime.svg
 == smil-transitions-interaction-3.svg lime.svg
 == smil-transitions-interaction-4.svg lime.svg