Index: content/smil/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/content/smil/Makefile.in
diff -N content/smil/Makefile.in
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/Makefile.in	5 Nov 2005 04:39:04 -0000
@@ -0,0 +1,48 @@
+# 
+# ***** 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 the Mozilla SMIL module.
+#
+# The Initial Developer of the Original Code is Brian Birtles.
+# Portions created by the Initial Developer are Copyright (C) 2005
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Brian Birtles <birtles@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of 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 *****
+
+DEPTH		= ../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS		= public src
+
+include $(topsrcdir)/config/rules.mk
+
Index: content/smil/public/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/Makefile.in
diff -N content/smil/public/Makefile.in
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/Makefile.in	5 Nov 2005 04:39:04 -0000
@@ -0,0 +1,62 @@
+#
+# ***** 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 the Mozilla SMIL module.
+#
+# The Initial Developer of the Original Code is Brian Birtles.
+# Portions created by the Initial Developer are Copyright (C) 2005
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Brian Birtles <birtles@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of 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 *****
+
+DEPTH           = ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= content
+
+EXPORTS		= \
+    nsISMILAnimAttr.h \
+	nsISMILAnimElement.h \
+	nsISMILAnimVal.h \
+	nsISMILAnimationController.h \
+	nsISMILAnimationFunction.h \
+	nsISMILAnimationObserver.h \
+	nsISMILAnimationRegistry.h \
+	nsISMILComposable.h \
+	nsISMILTimeClient.h \
+	nsISMILTimeContainer.h \
+	nsISMILTimedElement.h \
+	$(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
Index: content/smil/public/nsISMILAnimAttr.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/nsISMILAnimAttr.h
diff -N content/smil/public/nsISMILAnimAttr.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/nsISMILAnimAttr.h	5 Nov 2005 04:39:04 -0000
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISMILANIMATTR_H__
+#define __NS_ISMILANIMATTR_H__
+
+#include "nsISupports.h"
+
+class nsISMILAnimVal;
+
+////////////////////////////////////////////////////////////////////////
+// nsISMILAnimAttr: Interfaces for data types that can have a base and animated
+//                  value.
+
+// {c487920a-7d12-40ff-bf3b-c39dd4797cff}
+#define NS_ISMILANIMATTR_IID \
+{ 0xc487920a, 0x7d12, 0x40ff, { 0xbf, 0x3b, 0xc3, 0x9d, 0xd4, 0x79, 0x7c, 0xff } }
+
+/**
+ * Interfaces for data types that can have a base and animated value.
+ *
+ * This interface is like a stepping stone between nsISMILAnimElement and
+ * nsISMILAnimVal. It should be possible to do without this interface altogether
+ * and I think this would produce a simpler design. However, keeping it should
+ * mean that nsISMILAnimVal can be implemented by a separate lightweight object,
+ * perhaps even implemented as a tear off from the class implementing
+ * nsISMILAnimAttr.
+ */
+class nsISMILAnimAttr : public nsISupports
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISMILANIMATTR_IID)
+
+  /**
+   * Gets the underlying value of this attribute. It is the same as Create() but
+   * avoids allocating memory.
+   *
+   * @param aValue  The value to fill.
+   * @return NS_OK on success or an error code if getting failed.
+   */
+  virtual nsresult  GetBaseValue(nsISMILAnimVal& aValue) = 0;
+
+  /**
+   * Sets the presentation value of this attribute.
+   *
+   * @param aValue  The value to set.
+   * @return NS_OK on success or an error code if setting failed.
+   */
+  virtual nsresult  SetAnimValue(const nsISMILAnimVal& aValue) = 0;
+
+  /*
+   * Factory methods
+   */
+
+  /**
+   * Creates a new nsISMILAnimVal initialized to the base value of this
+   * attribute.
+   *
+   * @return The newly created object or null if creation failed.
+   */
+  virtual nsISMILAnimVal* Create() const = 0;
+
+  /**
+   * Creates a new nsISMILAnimVal from the given specification.
+   *
+   * @param aSpec   A string representation that should be parsed to determine
+   *                the value of the newly created object.
+   * @return The newly created object or null if creation failed.
+   */
+  virtual nsISMILAnimVal* CreateFromSpec(const nsAString& aSpec) const = 0;
+};
+
+#endif // __NS_ISMILANIMATTR_H__
+
Index: content/smil/public/nsISMILAnimElement.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/nsISMILAnimElement.h
diff -N content/smil/public/nsISMILAnimElement.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/nsISMILAnimElement.h	5 Nov 2005 04:39:04 -0000
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISMILANIMELEMENT__
+#define __NS_ISMILANIMELEMENT__
+
+#include "nsISupports.h"
+#include "nsISMILAnimAttr.h"
+
+////////////////////////////////////////////////////////////////////////
+// nsISMILAnimElement: interface of elements that have attributes
+//                     that can be animated.
+
+// {5DD94E10-FD8D-42FB-B054-8D29F771033A}
+#define NS_ISMILANIMELEMENT_IID \
+{ 0x5dd94e10, 0xfd8d, 0x42fb, { 0xb0, 0x54, 0x8d, 0x29, 0xf7, 0x71, 0x03, 0x3a } }
+
+/**
+ * Interface for elements that have attributes that can be animated.
+ *
+ * This interface is not actually used by the SMIL module. Instead it is used by
+ * the host language to identify targets for animation. However, in a mixed
+ * namespace environment this interface might be used by several modules so it
+ * should probably stay here in SMIL.
+ */
+class nsISMILAnimElement : public nsISupports
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISMILANIMELEMENT_IID)
+
+  /**
+   * Gets an animatable attribute identified by namespace and attribute name.
+   *
+   * @param aNamespaceID  The namespace of the attribute
+   * @param aName The attribute name
+   * @return The attribute or NULL if this attribute does not exist or is not
+   *         animatable.
+   */
+  virtual nsISMILAnimAttr*
+  GetAnimAttribute(PRInt32 aNamespaceID, nsIAtom* aName)=0;
+};
+
+#endif // __NS_ISMILANIMELEMENT__
+
Index: content/smil/public/nsISMILAnimVal.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/nsISMILAnimVal.h
diff -N content/smil/public/nsISMILAnimVal.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/nsISMILAnimVal.h	5 Nov 2005 04:39:05 -0000
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISMILANIMVAL_H__
+#define __NS_ISMILANIMVAL_H__
+
+#include "nsISupports.h"
+
+////////////////////////////////////////////////////////////////////////
+// nsISMILAnimVal
+
+// {01d2aae5-9de4-4e8f-a1e9-ae660ad27925}
+#define NS_ISMILANIMVAL_IID \
+{ 0x01d2aae5, 0x9de4, 0x4e8f, { 0xa1, 0xe9, 0xae, 0x66, 0x0a, 0xd2, 0x79, 0x25 } }
+
+class nsISMILAnimVal : public nsISupports
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISMILANIMVAL_IID)
+
+  /**
+   * Calculates the 'distance' between this value and another. This is the
+   * distance used in paced interpolation.
+   *
+   * @param   aTo       The end of the interval for which the distance should be
+   *                    calculated.
+   * @param   aDistance The result of the calculation.
+   * @return  NS_OK on success, or an appropriate code if there is no notion of
+   *          distance for the underlying data type or the distance could not be
+   *          calculated.
+   */
+  virtual nsresult  ComputeDistance(const nsISMILAnimVal& aTo,
+                                    PRFloat64& aDistance) const = 0;
+
+  /**
+   * Calculates an interpolates value between this value and the specified end
+   * value using the specified proportion.
+   *
+   * @param   aEndVal       The value defining the end of the interval of
+   *                        interpolation.
+   * @param   aUnitDistance A number between 0.0 and 1.0 (inclusive) defining
+   *                        the distance of the interpolated value in the
+   *                        interval.
+   * @param   aResult       The interpolated value.
+   * @result  NS_OK on success, NS_ERROR_FAILURE if this data type cannot be
+   *          interpolated or NS_ERROR_OUT_OF_MEMORY if insufficient memory was
+   *          available for storing the result.
+   */
+  virtual nsresult  Interpolate(const nsISMILAnimVal& aEndVal,
+                                float aUnitDistance,
+                                nsISMILAnimVal& aResult) = 0;
+
+  /**
+   * Add the given value to this value. This method facilitates additive and
+   * cumulative animation.
+   *
+   * This method will fail if the underlying datatype is not additive or was not
+   * specified using an additive syntax.
+   *
+   * See SVG 1.1, section 19.2.5. In particular,
+   *
+   * "If a given attribute or property can take values of keywords (which are
+   * not additive) or numeric values (which are additive), then additive
+   * animations are possible if the subsequent animation uses a numeric value
+   * even if the base animation uses a keyword value; however, if the subsequent
+   * animation uses a keyword value, additive animation is not possible."
+   *
+   * @param   aAddedVal   The value to add to this value.
+   * @return  NS_OK on success, an error code on failure.
+   */
+  virtual nsresult  Add(const nsISMILAnimVal& aAddedVal) = 0;
+
+  /**
+   * Assign this object the value of another. Think of this as the assignment
+   * operator.
+   *
+   * @param   aNewVal     The value to set.
+   * @return  NS_OK on success, an error code on failure such as when the
+   *          underlying type of the specified object differs.
+   */
+  virtual nsresult  Set(const nsISMILAnimVal& aNewVal) = 0;
+
+  /**
+   * Repeats this value or the specified value a number of times. This method
+   * will fail if the underlying data type is not additive.
+   *
+   * @param   aCount        The number of times to repeat the value.
+   * @param   aRepeatValue  The value to repeat. If this parameter is null the
+   *                        current value will be repeated.
+   * @return  NS_OK on success, an error code on failure.
+   */
+  virtual nsresult  Repeat(PRUint32 aCount,
+                           const nsISMILAnimVal* aRepeatValue = nsnull) = 0;
+};
+
+#endif // __NS_ISMILANIMVAL_H__
+
Index: content/smil/public/nsISMILAnimationController.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/nsISMILAnimationController.h
diff -N content/smil/public/nsISMILAnimationController.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/nsISMILAnimationController.h	5 Nov 2005 04:39:05 -0000
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISMILANIMATIONCONTROLLER_H__
+#define __NS_ISMILANIMATIONCONTROLLER_H__
+
+#include "nsIAnimationController.h"
+
+#define NS_ISMILANIMATIONCONTROLLER_IID \
+{ 0xd2c81398, 0x1f30, 0x4303, { 0xbe, 0xbe, 0xc5, 0x0c, 0x01, 0xfd, 0xd8, 0x85 } }
+
+class nsISMILTimeContainer;
+class nsIDocument;
+
+////////////////////////////////////////////////////////////////////////
+// nsISMILAnimationController: Animation controller
+
+class nsISMILAnimationController : public nsIAnimationController
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISMILANIMATIONCONTROLLER_IID)
+
+  // nsIAnimationController methods
+  virtual nsresult  Pause()=0;
+  virtual nsresult  Resume()=0;
+  virtual nsresult  Reset()=0;
+
+  // 
+  // Eventually, this will probably be all nsISMILTimedElements so that it is
+  // possible to have hierarchies of containers (which will implement
+  // nsISMILTimedElement), and then these methods will be replaced with
+  // SetRootElement.
+  //
+  virtual nsresult  AddTimeContainer(nsISMILTimeContainer* aContainer)=0;
+  virtual nsresult  RemoveTimeContainer(nsISMILTimeContainer* aContainer)=0;
+};
+
+nsISMILAnimationController* NS_NewSMILAnimationController(nsIDocument *doc);
+
+#endif // __NS_ISMILANIMATIONCONTROLLER_H__
+
Index: content/smil/public/nsISMILAnimationFunction.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/nsISMILAnimationFunction.h
diff -N content/smil/public/nsISMILAnimationFunction.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/nsISMILAnimationFunction.h	5 Nov 2005 04:39:05 -0000
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISMILANIMFUNCTION_H__
+#define __NS_ISMILANIMFUNCTION_H__
+
+#include "nsISupports.h"
+
+class nsISMILAnimAttr;
+
+// {14eb1aab-e4ba-4c77-be89-195ef975c90d}
+#define NS_ISMILANIMFUNCTION_IID \
+{ 0x14eb1aab, 0xe4ba, 0x4c77, { 0xbe, 0x89, 0x19, 0x5e, 0xf9, 0x75, 0xc9, 0x0d } }
+
+/**
+ * Provides the animation function for an interpolating animation element. This
+ * includes the animation-related attributes. It is intended to be used by
+ * elements such as <animate>, <animateColor> and so on.
+ *
+ * It will likely be split into nsISMILInterpolatingAnimFunc and
+ * nsISMILSimpleAnimFunc when <set> is introduced. Extra parameters or perhaps
+ * a subclass will probably be needed to support <animateTransform>,
+ * <animateMotion> and the like.
+ */
+class nsISMILAnimationFunction : public nsISupports
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISMILANIMFUNCTION_IID)
+
+  virtual nsresult         SetTargetAttribute(nsISMILAnimAttr* aAttribute)=0;
+  virtual nsISMILAnimAttr* GetTargetAttribute()=0;
+  virtual void             SetDocumentPosition(PRUint16 aDocPosition)=0;
+
+  /*
+   * Property setters
+   */
+  virtual nsresult         SetAccumulate(const nsAString& aAccumulate)=0;
+  virtual nsresult         SetAdditive(const nsAString& aAdditive)=0;
+  virtual nsresult         SetBy(const nsAString& aBy)=0;
+  virtual nsresult         SetCalcMode(const nsAString& aCalcMode)=0;
+  virtual nsresult         SetFrom(const nsAString& aFrom)=0;
+  virtual nsresult         SetKeyTimes(const nsAString& aKeyTimes)=0;
+  virtual nsresult         SetKeySplines(const nsAString& aKeySplines)=0;
+  virtual nsresult         SetTo(const nsAString& aTo)=0;
+  virtual nsresult         SetValues(const nsAString& aValues)=0;
+
+  /*
+   * Property unsetters
+   *
+   * Unsetters are used instead of simply passing an empty string to the setters
+   * as in some cases an empty string is an error whereas not specifying an
+   * attribute is not.
+   *
+   * Unsetters are used in preference to setting a default value so that this
+   * object is responsible for supplying default values and not all the
+   * different animation elements that use it.
+   */
+  virtual void             UnsetAdditive()=0;
+  virtual void             UnsetBy()=0;
+  virtual void             UnsetCalcMode()=0;
+  virtual void             UnsetAccumulate()=0;
+  virtual void             UnsetFrom()=0;
+  virtual void             UnsetKeyTimes()=0;
+  virtual void             UnsetKeySplines()=0;
+  virtual void             UnsetTo()=0;
+  virtual void             UnsetValues()=0;
+};
+
+nsISMILAnimationFunction* NS_NewSMILAnimationFunction();
+
+#endif //__NS_ISMILANIMFUNCTION_H__
+
Index: content/smil/public/nsISMILAnimationObserver.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/nsISMILAnimationObserver.h
diff -N content/smil/public/nsISMILAnimationObserver.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/nsISMILAnimationObserver.h	5 Nov 2005 04:39:05 -0000
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISMILANIMATIONOBSERVER_H__
+#define __NS_ISMILANIMATIONOBSERVER_H__
+
+#include "nsISupports.h"
+#include "nsWeakReference.h"
+
+#define NS_ISMILANIMATIONOBSERVER_IID \
+{ 0x8f96dd0c, 0x9c70, 0x4b3a, { 0xa0, 0x72, 0xce, 0x71, 0x0f, 0x47, 0xa0, 0x06 } }
+
+////////////////////////////////////////////////////////////////////////
+// nsISMILAnimationObserver: Interfaces for clients that want to be informed of
+//                           stages in the animation's life cycle
+
+class nsISMILAnimationObserver : public nsSupportsWeakReference
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISMILANIMATIONOBSERVER_IID)
+
+  virtual void      StartSample()=0;
+  virtual void      StartCompositing()=0;
+  virtual void      EndCompositing()=0;
+  virtual void      EndSample()=0;
+};
+
+#endif // __NS_ISMILANIMATIONOBSERVER_H__
+
Index: content/smil/public/nsISMILAnimationRegistry.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/nsISMILAnimationRegistry.h
diff -N content/smil/public/nsISMILAnimationRegistry.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/nsISMILAnimationRegistry.h	5 Nov 2005 04:39:06 -0000
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISMILANIMATIONREGISTRY_H__
+#define __NS_ISMILANIMATIONREGISTRY_H__
+
+#include "nsISupports.h"
+
+class nsISMILAnimationController;
+class nsISMILAnimationObserver;
+class nsISMILComposable;
+class nsISMILAnimAttr;
+class nsISMILTimedElement;
+
+#define NS_ISMILANIMATIONREGISTRY_IID \
+{ 0xdd3c7124, 0xcc1f, 0x447b, { 0xa1, 0x35, 0x4a, 0xd8, 0xfc, 0xd4, 0x9f, 0x31 } }
+
+////////////////////////////////////////////////////////////////////////
+// nsISMILAnimationRegistry: Entry point for SMIL animated documents
+
+class nsISMILAnimationRegistry : public nsISupports
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISMILANIMATIONREGISTRY_IID)
+
+  /**
+   * Sets the animation controller which is needed for registering the time
+   * container managed by this registry.
+   *
+   * @param aController The animation controller. May be NULL to disassociate
+   *                    this registry from any controller.
+   */
+  virtual nsresult  SetController(nsISMILAnimationController* aController)=0;
+
+  /**
+   * Sets the object which will receive notifications when samples begin and end
+   * and when compositing takes place. Currently only one observer can be set at
+   * a time.
+   *
+   * @param aObserver The observer to receive notifications. May be null to
+   *                  remove the currently set observer if any.
+   */
+  virtual void      SetObserver(nsISMILAnimationObserver* aObserver)=0;
+
+  /*
+   * The next five methods correspond to methods in the nsIDOMSVGSVGElement
+   * interface.
+   */
+
+  /**
+   * Starts animation. After creating the registry this method needs to be
+   * called before animation starts. This allows more precise control over when
+   * the animation starts allowing the registry to be created and set up but
+   * only started when the conditions are right.
+   */
+  virtual nsresult  Start()=0;
+
+  /**
+   * Pauses animation.
+   */
+  virtual void      Pause()=0;
+
+  /**
+   * Unpauses animation.
+   */
+  virtual void      Unpause()=0;
+
+  /**
+   * @return true if the animation is in a paused state.
+   */
+  virtual PRBool    IsPaused()=0;
+
+  /**
+   * Returns the current time in seconds relative to the start time of the
+   * animation.
+   */
+  virtual float     GetCurrentTime()=0;
+
+  /**
+   * Adjusts the clock for the animation to the specified time.
+   *
+   * @param aSeconds  The new current time in seconds relative to the start time
+   *                  for this animation.
+   */
+  virtual nsresult  SetCurrentTime(float aSeconds)=0;
+
+  /**
+   * Registers a composable object with the compositor for the specified target
+   * attribute. The composable object may be registered with several target
+   * attributes and each target attribute may have several composable objects
+   * associated with it.
+   */
+  virtual nsresult  RegisterComposable(nsISMILAnimAttr* aTargetAttr,
+                                       nsISMILComposable* aComposable)=0;
+
+  /**
+   * Removes the specified composable object from all compositors with which is
+   * it registered.
+   */
+  virtual nsresult  UnregisterComposable(nsISMILComposable* aComposable)=0;
+
+  /**
+   * Registers the timed element with the time container managed by this
+   * registry.
+   */
+  virtual nsresult  RegisterTimedElement(nsISMILTimedElement* aElement)=0;
+
+  /**
+   * Unregisters the timed element from the time container managed by this
+   * registry.
+   */
+  virtual nsresult  UnregisterTimedElement(nsISMILTimedElement* aElement)=0;
+};
+
+/**
+ * Creates a new animation registry object.
+ */
+nsISMILAnimationRegistry* NS_NewSMILAnimationRegistry();
+
+#endif // __NS_ISMILANIMATIONREGISTRY_H__
+
Index: content/smil/public/nsISMILComposable.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/nsISMILComposable.h
diff -N content/smil/public/nsISMILComposable.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/nsISMILComposable.h	5 Nov 2005 04:39:06 -0000
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISMILCOMPOSABLE_H__
+#define __NS_ISMILCOMPOSABLE_H__
+
+#include "nsISupports.h"
+#include "nsWeakReference.h"
+
+class nsISMILAnimVal;
+
+////////////////////////////////////////////////////////////////////////
+// nsISMILComposable : Interface for animations that can be composited
+//                     by the compositor
+
+// {4b05aa22-712e-4a9e-8452-f7c4b2e507e7}
+#define NS_ISMILCOMPOSABLE_IID \
+{ 0x4b05aa22, 0x712e, 0x4a9e, { 0x84, 0x52, 0xf7, 0xc4, 0xb2, 0xe5, 0x07, 0xe7 } }
+
+class nsISMILComposable : public nsSupportsWeakReference
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISMILCOMPOSABLE_IID)
+
+  /**
+   * Combines the result of this animation function for the last sample with the
+   * specified value.
+   *
+   * @param aResult The value to compose with.
+   */
+  virtual void      ComposeResult(nsISMILAnimVal &aResult)=0;
+
+  /**
+   * Returns the relative priority of this animation to another. The priority is
+   * used for determining the position of the animation in the animation
+   * sandwich.
+   *
+   * @return  -1 if this animation has lower priority or 1 if this animation has
+   *          higher priority
+   *
+   * This method should never return 0.
+   */
+  virtual PRInt8    CompareTo(const nsISMILComposable& composable) const=0;
+
+  /*
+   * The following three methods are used in sorting.
+   */
+
+  /**
+   * Indicates if this animation is a 'to animation'. Such animations appear
+   * 'higher' in the animation sandwich than all other animations.
+   *
+   * @return  True if this animation is a to animation, false otherwise.
+   */
+  virtual PRBool    IsToAnimation() const=0;
+
+  /**
+   * Returns the begin time of this animation for the interval it is currently
+   * animating. For inactive animations this will be LL_MinInt but such
+   * animations should be filtered from compositing anyway.
+   *
+   * @return  A 64-bit integer representing the begin time of this animation.
+   */
+  virtual const PRInt64&  GetBeginTime() const=0;
+
+  /**
+   * Returns a unique (0-based) index indicating the position of this animation
+   * in the document. The first animation will have index 0 as so on. Positions
+   * are recalculated when the document structure is changed.
+   *
+   * @return  An unsigned integer representing this animation's position in the
+   *          document.
+   */
+  virtual PRUint16   GetDocumentPosition() const=0;
+
+  /*
+   * The following methods are provided so that the compositor can optimise its
+   * operations by only composing those animation that will affect the final
+   * result.
+   */
+ 
+  /**
+   * Indicates if the animation is currently active. Inactive animations will
+   * not contribute to the composed result.
+   *
+   * @return  True if the animation active, false otherwise.
+   */
+  virtual PRBool    IsActive() const=0; 
+
+  /**
+   * Indicates if this animation will replace the passed in result rather than
+   * adding to it. Animations that replace the underlying value may be called
+   * without first calling lower priority animations.
+   *
+   * @return  True if the animation will replace, false if it will add or
+   *          otherwise build on the passed in value.
+   */
+  virtual PRBool    WillReplace() const=0;
+
+  /**
+   * Indicates if the parameters for this animation have changed since the last
+   * time it was composited. This allows rendering to be performed only when
+   * necessary, particularly when no animations are active.
+   *
+   * @return  True if the animation parameters have changed, false otherwise.
+   */
+  virtual PRBool    HasChanged() const=0;
+};
+
+#endif // __NS_ISMILCOMPOSABLE_H__
+
Index: content/smil/public/nsISMILTimeClient.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/nsISMILTimeClient.h
diff -N content/smil/public/nsISMILTimeClient.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/nsISMILTimeClient.h	5 Nov 2005 04:39:06 -0000
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISMILTIMECLIENT_H__
+#define __NS_ISMILTIMECLIENT_H__
+
+#include "nsISupports.h"
+
+class nsSMILTimeValue;
+
+////////////////////////////////////////////////////////////////////////
+// nsISMILTimeClient
+
+// {196f66f4-e6f6-420b-a337-da42a2efccde}
+#define NS_ISMILTIMECLIENT_IID \
+{ 0x196f66f4, 0xe6f6, 0x420b, { 0xa3, 0x37, 0xda, 0x42, 0xa2, 0xef, 0xcc, 0xde } }
+
+class nsISMILTimeClient : public nsISupports
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISMILTIMECLIENT_IID)
+
+  /**
+   * Indicate a new sample has occurred.
+   *
+   * @param aSimpleTime The sample time for this timed element expressed in
+   *                    simple time.
+   * @param aSimpleDuration The simple duration for this timed element.
+   * @param aRepeatIteration  The repeat iteration for this sample. The first
+   *                          iteration has a value of 0.
+   */
+  virtual void      SampleAt(const PRInt64& aSimpleTime,
+                             const nsSMILTimeValue& aSimpleDuration,
+                             const PRUint32& aRepeatIteration)=0;
+
+  /**
+   * Indicate to sample using the last value defined for the animation function.
+   * This value is not normally sampled due to the end-point exclusive timing
+   * model but only occurs when the fill mode is "freeze" and the active
+   * duration is an even multiple of the simple duration.
+   *
+   * @param aRepeatIteration  The repeat iteration for this sample. The first
+   *                          iteration has a value of 0.
+   */
+  virtual void      SampleLastValue(const PRUint32& aRepeatIteration)=0;
+
+  /**
+   * Indicate that the timed element is now active. This is used, for example,
+   * to instruct the animation function that it should now add its result to the
+   * animation sandwich. The begin time is also provided for proper
+   * prioritisation of animation functions and for this reason this method must
+   * be called before either of the Sample methods.
+   *
+   * @param aBeginTime The begin time for the newly active interval.
+   */
+  virtual void      ToActive(const PRInt64& aBeginTime)=0;
+
+  /**
+   * Indicate that the timed element is no longer active. This is used, for
+   * example, to instruct the animation function that it should no longer add
+   * its result to the animation sandwich.
+   *
+   * @param aIsFrozen True if this animation should continue to contribute to
+   *                  the animation sandwich using the most recent sample
+   *                  parameters even though these parameters are unlikely to
+   *                  change between samples.
+   */
+  virtual void      ToInactive(PRBool aIsFrozen)=0;
+};
+
+#endif // __NS_ISMILTIMECLIENT_H__
+
Index: content/smil/public/nsISMILTimeContainer.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/nsISMILTimeContainer.h
diff -N content/smil/public/nsISMILTimeContainer.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/nsISMILTimeContainer.h	5 Nov 2005 04:39:07 -0000
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISMILTIMECONTAINER_H__
+#define __NS_ISMILTIMECONTAINER_H__
+
+#include "nsISupports.h"
+#include "nsISMILTimedElement.h"
+
+////////////////////////////////////////////////////////////////////////
+// nsISMILTimeContainer: Time container
+
+// {46b51a7b-d857-45f1-9c7d-4d0d12719238}
+#define NS_ISMILTIMECONTAINER_IID \
+{ 0x46b51a7b, 0xd857, 0x45f1, { 0x9c, 0x7d, 0x4d, 0x0d, 0x12, 0x71, 0x92, 0x38 } }
+
+/**
+ * A SMIL time container.
+ *
+ * When implementing SMIL 2.0 time containers, this interface will most likely
+ * inherit from nsISMILTimedElement, amongst other changes
+ */
+class nsISMILTimeContainer : public nsISupports
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISMILTIMECONTAINER_IID)
+
+  /**
+   * Pause the time container. The time container is initially unpaused.
+   */
+  virtual nsresult  Pause()=0;
+
+  /**
+   * Resume the time container.
+   */
+  virtual nsresult  Resume()=0;
+
+  /**
+   * Returns the paused state of the time container independently of the paused
+   * state of the container's parent.
+   */
+  virtual PRBool    IsPaused()=0;
+
+  /**
+   * Inform the time container that its parent has been paused.
+   *
+   * Currently this is necessary so that the time container will accumulate
+   * pause offsets correctly as these are not maintained by the parent.
+   *
+   * Re-using Pause() and maintaining pause counts can lead to unwanted
+   * behaviour when calls to pause and resume are unbalanced.
+   */
+  virtual nsresult  ParentPaused()=0;
+
+  /**
+   * Inform the time container that its parent has been resumed.
+   */
+  virtual nsresult  ParentResumed()=0;
+
+  /**
+   * Reset the time container's internal state. This is particularly useful when
+   * a cached time container is to be re-used.
+   */
+  virtual nsresult  Reset()=0;
+
+  /**
+   * We may later change this to SampleAt and maintain separate host document
+   * and document fragment times. This would allow more advanced time
+   * manipulations for documents with several animated SVG document fragments.
+   */
+  virtual void      Sample()=0;
+
+  /**
+   * Add a timed element to this container. No attempt is made to check if the
+   * timed element is already a child of this container--in that case the timed
+   * element will be added twice and will be sampled twice.
+   *
+   * @param aElement  The element to add.
+   * @return  NS_OK if the element was successfully added or an error otherwise.
+   */
+  virtual nsresult  AddTimedElement(nsISMILTimedElement* aElement)=0;
+
+  /**
+   * Remove the specified timed element from this container.
+   *
+   * @param aElement  The element to remove.
+   * @return NS_OK if the element is found and successfully removed or an error
+   * otherwise.
+   */
+  virtual nsresult  RemoveTimedElement(nsISMILTimedElement* aElement)=0;
+};
+
+#endif // __NS_ISMILTIMECONTAINER_H__
+
Index: content/smil/public/nsISMILTimedElement.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/public/nsISMILTimedElement.h
diff -N content/smil/public/nsISMILTimedElement.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/public/nsISMILTimedElement.h	5 Nov 2005 04:39:07 -0000
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISMILTIMEDELEMENT_H__
+#define __NS_ISMILTIMEDELEMENT_H__
+
+#include "nsISupports.h"
+
+class nsISMILTimeClient;
+class nsSMILTimeValue;
+class nsSMILInstanceTime;
+class nsSMILTimedDocumentRoot;
+
+////////////////////////////////////////////////////////////////////////
+// nsISMILTimedElement
+
+// {c5f60446-5c1a-4f3b-8ce3-646199ac97f2}
+#define NS_ISMILTIMEDELEMENT_IID \
+{ 0xc5f60446, 0x5c1a, 0x4f3b, { 0x8c, 0xe3, 0x64, 0x61, 0x99, 0xac, 0x97, 0xf2 } }
+
+class nsISMILTimedElement : public nsISupports
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISMILTIMEDELEMENT_IID)
+
+  /**
+   * Adds an instance time object this this element's list of instance times.
+   * These instance times are used when creating intervals.
+   *
+   * This method is typically called by an nsSMILTimeValueSpec to register an
+   * instance time corresponding its specification.
+   *
+   * @param aInstanceTime   The time to add.
+   *
+   * @param aIsBegin        True if the time to be added represents a begin time
+   *                        or false if it represents an end time.
+   */
+  virtual void      AddInstanceTime(nsSMILInstanceTime* aInstanceTime,
+                                    PRBool aIsBegin)=0;
+
+  /**
+   * Associates a timed document root. This is required for resolving wallclock
+   * values and getting the document time in order to create new instance times.
+   * 
+   * @param aRoot The timed document root to associate.
+   */
+  virtual void      SetDocumentRoot(nsSMILTimedDocumentRoot* aRoot)=0;
+
+  /**
+   * Sets the object that will be called by this timed element each time it is
+   * sampled.
+   *
+   * In Schmitz's model it is possible to associate several time clients with
+   * a timed element but for now we only allow one.
+   *
+   * @param aClient   The time client to associate. Any previous time client
+   *                  will be disassociated and no longer sampled. Setting this
+   *                  to NULL will simply disassociate the previous client, if
+   *                  any.
+   */
+  virtual void      SetTimeClient(nsISMILTimeClient* aClient)=0;
+
+  /**
+   * Samples the object at the given document time. Timing intervals are updated
+   * and if this element is active at the given time the associated time client
+   * will be sampled with the appropriate simple time.
+   *
+   * @param aDocumentTime The document time at which to sample.
+   */
+  virtual void      SampleAt(const PRInt64& aDocumentTime)=0;
+
+  /**
+   * Reset the element's internal state. This is useful for repeating time
+   * containers and so that the timing model can be cached.
+   *
+   * @param aHardReset  Perform a hard reset such that all instance times are
+   *                    cleared. For a soft reset only instance times created by
+   *                    DOM calls and events are cleared. A hard reset is needed
+   *                    in the case of a cached timing model whilst for
+   *                    repeating only a soft reset is required.
+   */
+  virtual void      Reset(PRBool aHardReset = PR_FALSE)=0;
+
+  /*
+   * Property setters
+   */
+  virtual nsresult  SetBeginSpec(const nsAString& aBeginSpec)=0;
+  virtual nsresult  SetEndSpec(const nsAString& aEndSpec)=0;
+  virtual nsresult  SetSimpleDuration(const nsAString& aDurSpec)=0;
+  virtual nsresult  SetMin(const nsAString& aMinSpec)=0;
+  virtual nsresult  SetMax(const nsAString& aMaxSpec)=0;
+  virtual nsresult  SetRestart(const nsAString& aRestartSpec)=0;
+  virtual nsresult  SetRepeatCount(const nsAString& aRepeatCountSpec)=0;
+  virtual nsresult  SetRepeatDur(const nsAString& aRepeatDurSpec)=0;
+  virtual nsresult  SetFillMode(const nsAString& aFillModeSpec)=0;
+
+  /*
+   * Property unsetters
+   *
+   * Unsetters are used instead of simply passing an empty string to the setters
+   * as in some cases an empty string is an error whereas not specifying an
+   * attribute is not.
+   *
+   * Unsetters are used in preference to setting a default value so that this
+   * object is responsible for supplying default values and not all the
+   * different animation elements that use it.
+   */
+  virtual void      UnsetBeginSpec()=0;
+  virtual void      UnsetEndSpec()=0;
+  virtual void      UnsetSimpleDuration()=0;
+  virtual void      UnsetMin()=0;
+  virtual void      UnsetMax()=0;
+  virtual void      UnsetRestart()=0;
+  virtual void      UnsetRepeatCount()=0;
+  virtual void      UnsetRepeatDur()=0;
+  virtual void      UnsetFillMode()=0;
+};
+
+nsISMILTimedElement* NS_NewSMILTimedElement();
+
+#endif // __NS_ISMILTIMEDELEMENT_H__
+
Index: content/smil/src/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/Makefile.in
diff -N content/smil/src/Makefile.in
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/Makefile.in	5 Nov 2005 04:39:07 -0000
@@ -0,0 +1,83 @@
+#
+# ***** 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 the Mozilla SMIL module.
+#
+# The Initial Developer of the Original Code is Brian Birtles.
+# Portions created by the Initial Developer are Copyright (C) 2005
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Brian Birtles <birtles@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of 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 *****
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= content
+LIBRARY_NAME	= gkconsmil_s
+LIBXUL_LIBRARY	= 1
+
+REQUIRES	= xpcom \
+		  string \
+		  layout \
+		  content \
+		  unicharutil \
+			widget \
+			dom \
+		  $(NULL)
+
+CPPSRCS		= \
+	nsSMILAnimationController.cpp \
+	nsSMILAnimationFunction.cpp \
+	nsSMILAnimationRegistry.cpp \
+	nsSMILAtoms.cpp \
+	nsSMILCompositor.cpp \
+	nsSMILEnum.cpp \
+	nsSMILInstanceTime.cpp \
+	nsSMILInterval.cpp \
+	nsSMILKeySpline.cpp \
+	nsSMILParserUtils.cpp \
+	nsSMILTimedDocumentRoot.cpp \
+	nsSMILTimedElement.cpp \
+	nsSMILTimeValue.cpp \
+	nsSMILTimeValueSpec.cpp \
+		$(NULL)
+
+include $(topsrcdir)/config/config.mk
+
+# we don't want the shared lib, but we want to force the creation of a static lib.
+FORCE_STATIC_LIB = 1
+
+include $(topsrcdir)/config/rules.mk
+
+DEFINES += -D_IMPL_NS_LAYOUT
+
Index: content/smil/src/nsSMILAnimationController.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILAnimationController.cpp
diff -N content/smil/src/nsSMILAnimationController.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILAnimationController.cpp	5 Nov 2005 04:39:08 -0000
@@ -0,0 +1,430 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsISMILAnimationController.h"
+#include "nsComponentManagerUtils.h"
+#include "nsWeakReference.h"
+#include "nsITimer.h"
+#include "nsISMILTimeContainer.h"
+#include "nsCOMArray.h"
+#include "nsISimpleEnumerator.h"
+#include "nsArrayEnumerator.h"
+#include "nsAutoLock.h"
+#include "nsIDocument.h"
+#include "nsIDOMEventReceiver.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsIDOMPageTransitionListener.h"
+
+class nsSMILAnimationController : public nsISMILAnimationController,
+                                  public nsIDOMPageTransitionListener,
+                                  public nsSupportsWeakReference
+{
+public:
+  nsSMILAnimationController();
+  ~nsSMILAnimationController();
+
+  NS_DECL_ISUPPORTS
+
+  // nsISMILAnimationController
+  virtual nsresult  Pause();
+  virtual nsresult  Resume();
+  virtual nsresult  Reset();
+  virtual nsresult  AddTimeContainer(nsISMILTimeContainer* aContainer);
+  virtual nsresult  RemoveTimeContainer(nsISMILTimeContainer* aContainer);
+
+  // nsIDOMPageTransitionListener,
+  NS_IMETHOD        HandleEvent(nsIDOMEvent *event);
+  NS_IMETHOD        PageShow(nsIDOMEvent *event);
+  NS_IMETHOD        PageHide(nsIDOMEvent *event);
+
+protected:
+  friend nsISMILAnimationController*
+  NS_NewSMILAnimationController(nsIDocument* doc);
+
+  // nsISMILAnimationController
+  nsresult          Init(nsIDocument* doc);
+  nsresult          StartTimer();
+  nsresult          StopTimer();
+  void              SampleChildren();
+  static void       Notify(nsITimer* aTimer, void* aClosure);
+
+  static const PRUint32         kTimerInterval;
+  nsCOMPtr<nsITimer>            mTimer;
+  nsCOMArray<nsIWeakReference>  mTimeContainers;
+  PRLock*                       mAnimationLock;
+  PRUint16                      mPauseCount;
+  PRBool                        mHidden;
+};
+
+////////////////////////////////////////////////////////////////////////
+// nsSMILAnimationController implementation
+
+// 28ms per frame =~ 36fps which seems like a lot (Flash traditionally uses
+// 14fps) but in my fiddling this was the minimum necessary for smooth motion
+// using our current setup.
+const PRUint32 nsSMILAnimationController::kTimerInterval = 28;
+
+//----------------------------------------------------------------------
+// ctors, dtors, factory methods
+
+nsSMILAnimationController::nsSMILAnimationController()
+  : mPauseCount(0),
+    mHidden(PR_FALSE)
+{
+}
+
+nsSMILAnimationController::~nsSMILAnimationController()
+{
+  if (mAnimationLock)
+    PR_Lock(mAnimationLock);
+
+  if (mTimer) {
+    mTimer->Cancel();
+    mTimer = nsnull;
+  }
+
+  if (mAnimationLock) {
+    PR_Unlock(mAnimationLock);
+    PR_DestroyLock(mAnimationLock);
+  }
+}
+
+nsISMILAnimationController* NS_NewSMILAnimationController(nsIDocument* doc)
+{
+  nsSMILAnimationController* animationController = 
+    new nsSMILAnimationController();
+  NS_ENSURE_TRUE(animationController, nsnull);
+
+  nsresult rv = animationController->Init(doc);
+  if (NS_FAILED(rv)) {
+    delete animationController;
+    animationController = nsnull;
+  }
+
+  return animationController;
+}
+
+//----------------------------------------------------------------------
+// nsISupports methods:
+
+NS_IMPL_ISUPPORTS5(nsSMILAnimationController,
+                   nsISMILAnimationController,
+                   nsIAnimationController,
+                   nsIDOMEventListener,
+                   nsIDOMPageTransitionListener,
+                   nsISupportsWeakReference);
+
+//----------------------------------------------------------------------
+// Timer callback
+
+//
+// We use the function callback rather than implementing nsITimerCallback to
+// avoid circular ownership between the timer and this object.
+//
+
+/*static*/ void
+nsSMILAnimationController::Notify(nsITimer* timer, void* aClosure)
+{
+  nsSMILAnimationController* controller = (nsSMILAnimationController*)aClosure;
+
+  NS_ASSERTION(controller->mTimer == timer,
+               "nsSMILAnimationController::Notify called with incorrect timer");
+
+  controller->SampleChildren();
+}
+
+//----------------------------------------------------------------------
+// nsISMILAnimationController methods:
+
+nsresult
+nsSMILAnimationController::Pause()
+{
+  nsAutoLock lock(mAnimationLock);
+
+  if (++mPauseCount > 1)
+    return NS_OK;
+
+  nsresult rv = NS_OK;
+
+  rv = StopTimer();
+
+  // We must tell the children too so they can keep their accumulated offsets
+  // accurate
+  PRUint32 i = mTimeContainers.Count();
+  while (i > 0) {
+    --i;
+    nsCOMPtr<nsISMILTimeContainer> 
+      container( do_QueryReferent(mTimeContainers[i]) );
+
+    // This mess means that we continue processing all the children even if an
+    // error occurs but that we report the first error encountered
+    if (container) {
+      if (NS_SUCCEEDED(rv))
+        rv = container->ParentPaused();
+      else
+        container->ParentPaused();
+    } else {
+      mTimeContainers.RemoveObjectAt(i);
+    }
+  }
+
+  return rv;
+}
+
+nsresult
+nsSMILAnimationController::Resume()
+{
+  nsAutoLock lock(mAnimationLock);
+
+  nsresult rv = NS_OK;
+
+  NS_ASSERTION(mPauseCount > 0, "Unbalanced calls to Pause() and Resume()");
+  if (mPauseCount == 0)
+    return NS_ERROR_FAILURE;
+
+  if (--mPauseCount > 0)
+    return NS_OK;
+
+  // We must tell the children so they can keep their accumulated offsets
+  // accurate
+  PRUint32 i = mTimeContainers.Count();
+  while (i > 0) {
+    --i;
+    nsCOMPtr<nsISMILTimeContainer> 
+      container( do_QueryReferent(mTimeContainers[i]) );
+
+    if (container) {
+      if (NS_SUCCEEDED(rv))
+        rv = container->ParentResumed();
+      else
+        container->ParentResumed();
+    } else {
+      mTimeContainers.RemoveObjectAt(i);
+    }
+  }
+
+  if (mTimeContainers.Count() > 0)
+    StartTimer();
+
+  return rv;
+}
+
+nsresult
+nsSMILAnimationController::Reset()
+{
+  nsresult rv = NS_OK;
+
+  nsAutoLock lock(mAnimationLock);
+
+  PRUint32 i = mTimeContainers.Count();
+  while (i > 0) {
+    --i;
+    nsCOMPtr<nsISMILTimeContainer> 
+      container( do_QueryReferent(mTimeContainers[i]) );
+
+    if (container) {
+      if (NS_SUCCEEDED(rv))
+        rv = container->Reset();
+      else
+        container->Reset();
+    } else {
+      mTimeContainers.RemoveObjectAt(i);
+    }
+  }
+
+  return rv;
+}
+
+nsresult
+nsSMILAnimationController::AddTimeContainer(nsISMILTimeContainer* aContainer)
+{
+  NS_ENSURE_ARG_POINTER(aContainer);
+
+  nsresult rv;
+  nsCOMPtr<nsIWeakReference> weakRef(
+      getter_AddRefs(do_GetWeakReference(aContainer, &rv)) );
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  {
+    nsAutoLock lock(mAnimationLock);
+    rv = (mTimeContainers.AppendObject(weakRef)) ? NS_OK : NS_ERROR_FAILURE;
+    NS_ENSURE_SUCCESS(rv,rv);
+
+    if (mPauseCount > 0) {
+      aContainer->ParentPaused();
+    } else if (mTimeContainers.Count() == 1) {
+      rv = StartTimer();
+    }
+  }
+
+  return rv;
+}
+
+nsresult
+nsSMILAnimationController::RemoveTimeContainer(nsISMILTimeContainer* aContainer)
+{
+  NS_ENSURE_ARG_POINTER(aContainer);
+
+  nsresult rv;
+  nsCOMPtr<nsIWeakReference> weakRef(
+      getter_AddRefs(do_GetWeakReference(aContainer, &rv)) );
+
+  {
+    nsAutoLock lock(mAnimationLock);
+    if (NS_SUCCEEDED(rv))
+      rv = (mTimeContainers.RemoveObject(weakRef)) ? NS_OK : NS_ERROR_FAILURE;
+
+    if (NS_SUCCEEDED(rv) && mPauseCount == 0 && mTimeContainers.Count() == 0)
+      rv = StopTimer();
+  }
+
+  return rv;
+}
+
+//----------------------------------------------------------------------
+// nsIDOMPageTransitionListener methods
+
+nsresult
+nsSMILAnimationController::HandleEvent(nsIDOMEvent * /*event*/)
+{
+  return NS_OK;
+}
+
+nsresult
+nsSMILAnimationController::PageShow(nsIDOMEvent * /*event*/)
+{
+  if (!mHidden)
+    return NS_OK;
+
+  mHidden = PR_FALSE;
+
+  nsresult rv = Reset();
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  return Resume();
+}
+
+nsresult
+nsSMILAnimationController::PageHide(nsIDOMEvent * /*event*/)
+{
+  mHidden = PR_TRUE;
+  return Pause();
+}
+
+//----------------------------------------------------------------------
+// Implementation helpers:
+
+nsresult
+nsSMILAnimationController::Init(nsIDocument *doc)
+{
+  mTimer = do_CreateInstance("@mozilla.org/timer;1");
+  mAnimationLock = PR_NewLock();
+
+  // SMIL should be able to be used from a wide variety of contexts so in the
+  // following we fail silently. It is only necessary to support the bfcache.
+  if (doc) {
+    nsCOMPtr<nsIScriptGlobalObject> global(doc->GetScriptGlobalObject());
+    if (global) {
+      nsCOMPtr<nsIDOMEventReceiver> receiver( do_QueryInterface(global) );
+      if (receiver) {
+        receiver->AddEventListener(NS_LITERAL_STRING("pageshow"), this,
+                                   PR_FALSE);
+        receiver->AddEventListener(NS_LITERAL_STRING("pagehide"), this,
+                                   PR_FALSE);
+      }
+    }
+  }
+
+  return (mTimer && mAnimationLock) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
+nsresult
+nsSMILAnimationController::StartTimer()
+{
+  NS_ENSURE_TRUE(mTimer, NS_ERROR_FAILURE);
+  NS_ASSERTION(mPauseCount == 0, "Starting timer but controller is paused.");
+
+  // Run the first sample manually
+  SampleChildren();
+
+  // 
+  // XXX Make this self-tuning. Sounds like control theory to me and not
+  // something I'm familiar with.
+  //
+  return mTimer->InitWithFuncCallback(nsSMILAnimationController::Notify,
+                                      this,
+                                      kTimerInterval,
+                                      nsITimer::TYPE_REPEATING_PRECISE);
+}
+
+nsresult
+nsSMILAnimationController::StopTimer()
+{
+  NS_ENSURE_TRUE(mTimer, NS_ERROR_FAILURE);
+
+  return mTimer->Cancel();
+}
+
+void
+nsSMILAnimationController::SampleChildren()
+{
+  // Creating a new enumerator each sample provides thread-safety but I'm not
+  // sure what the cost is
+
+  if (mPauseCount > 0)
+    return;
+
+  nsCOMPtr<nsISimpleEnumerator> enumerator;
+  nsresult rv = 
+    NS_NewArrayEnumerator(getter_AddRefs(enumerator), mTimeContainers);
+  NS_ENSURE_SUCCESS(rv,);
+
+  PRBool more = PR_FALSE;
+  nsCOMPtr<nsISMILTimeContainer> container;
+  nsCOMPtr<nsIWeakReference> weakRef;
+
+  while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) {
+    if (NS_FAILED(enumerator->GetNext(getter_AddRefs(weakRef))) || !weakRef)
+      break;
+
+    container = do_QueryReferent(weakRef);
+
+    if (container)
+      container->Sample();
+  }
+}
+
Index: content/smil/src/nsSMILAnimationFunction.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILAnimationFunction.cpp
diff -N content/smil/src/nsSMILAnimationFunction.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILAnimationFunction.cpp	5 Nov 2005 04:39:10 -0000
@@ -0,0 +1,1180 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsISMILAnimationFunction.h"
+#include "nsISMILComposable.h"
+#include "nsISMILTimeClient.h"
+#include "nsSMILTimeValue.h"
+#include "nsISMILAnimVal.h"
+#include "nsISMILAnimAttr.h"
+#include "nsSMILEnum.h"
+#include "nsSMILAtoms.h"
+#include "nsSMILKeySpline.h"
+#include "nsSMILParserUtils.h"
+#include "nsCOMPtr.h"
+#include "nsCOMArray.h"
+#include "nsReadableUtils.h"
+#include "nsString.h"
+#include "nsAutoLock.h"
+#include <math.h>
+
+#define ALLOW_BAD_KEYTIMES
+
+//----------------------------------------------------------------------
+// nsSMILAnimationFunction
+
+class nsSMILAnimationFunction : public nsISMILAnimationFunction,
+                                public nsISMILComposable,
+                                public nsISMILTimeClient
+{
+public:
+  nsSMILAnimationFunction();
+  ~nsSMILAnimationFunction();
+
+  NS_DECL_ISUPPORTS
+
+  nsresult                 Init();
+
+  // nsISMILAnimationFunction
+  virtual nsresult         SetTargetAttribute(nsISMILAnimAttr* aAttribute);
+  virtual nsISMILAnimAttr* GetTargetAttribute();
+  virtual void             SetDocumentPosition(PRUint16 aDocPosition);
+
+  virtual nsresult         SetAccumulate(const nsAString& aAccumulate);
+  virtual nsresult         SetAdditive(const nsAString& aAdditive);
+  virtual nsresult         SetBy(const nsAString& aBy);
+  virtual nsresult         SetCalcMode(const nsAString& aCalcMode);
+  virtual nsresult         SetFrom(const nsAString& aFrom);
+  virtual nsresult         SetKeyTimes(const nsAString& aKeyTimes);
+  virtual nsresult         SetKeySplines(const nsAString& aKeySplines);
+  virtual nsresult         SetTo(const nsAString& aTo);
+  virtual nsresult         SetValues(const nsAString& aValues);
+
+  virtual void             UnsetAdditive();
+  virtual void             UnsetBy();
+  virtual void             UnsetCalcMode();
+  virtual void             UnsetAccumulate();
+  virtual void             UnsetFrom();
+  virtual void             UnsetKeyTimes();
+  virtual void             UnsetKeySplines();
+  virtual void             UnsetTo();
+  virtual void             UnsetValues();
+
+  // nsISMILTimeClient methods
+  virtual void             SampleAt(const PRInt64& aSimpleTime,
+                                    const nsSMILTimeValue& aSimpleDuration,
+                                    const PRUint32& aRepeatIteration);
+  virtual void             SampleLastValue(const PRUint32& aRepeatIteration);
+  virtual void             ToActive(const PRInt64& aBeginTime);
+  virtual void             ToInactive(PRBool aIsFrozen);
+
+  // nsISMILComposable methods
+  virtual void             ComposeResult(nsISMILAnimVal &aResult);
+  virtual PRInt8           CompareTo(const nsISMILComposable& composable) const;
+  virtual PRBool           IsToAnimation() const;
+  virtual const PRInt64&   GetBeginTime() const;
+  virtual PRUint16         GetDocumentPosition() const;
+  virtual PRBool           IsActive() const; 
+  virtual PRBool           WillReplace() const;
+  virtual PRBool           HasChanged() const;
+
+protected:
+  // Implementation helpers
+  nsISMILAnimationFunction*     NS_NewSMILAnimationFunction();
+
+  nsresult  InterpolateResult(nsISMILAnimVal& aResult,
+                              nsISMILAnimVal& aBaseValue);
+  nsresult  AccumulateResult(nsISMILAnimVal& aResult);
+  void      ScaleSimpleDistance(PRFloat64& aDist);
+  void      ScaleIntervalDistance(PRFloat64& aDist, PRUint32 aIntervalIndex, 
+                                  PRUint32 aNumIntervals);
+  void      FillValuesArray();
+  PRBool    IsAdditive() const;
+  void      ClearKeyTimes();
+  void      ClearKeySplines();
+  void      CheckKeyTimes();
+  void      CheckKeySplines();
+
+  // Members
+  
+  /**
+   * The attribute being targeted. This is needed for parsing animation function
+   * values and creating temporary objects.
+   */
+  nsCOMPtr<nsISMILAnimAttr>     mAttribute;
+
+  //
+  // Animation function values.
+  //
+  nsCOMPtr<nsISMILAnimVal>      mFrom;
+  nsCOMPtr<nsISMILAnimVal>      mTo;
+  nsCOMPtr<nsISMILAnimVal>      mBy;
+  nsCOMArray<nsISMILAnimVal>    mValues;
+
+  enum nsSMILCalcMode
+  {
+    calc_linear,
+    calc_discrete,
+    calc_paced,
+    calc_spline
+  };
+  static nsSMILEnumMapping      sCalcModeMap[];
+  nsSMILEnum                    mCalcMode;
+
+  static nsSMILEnumMapping      sAdditiveMap[];
+  nsSMILEnum                    mAdditive;
+
+  static nsSMILEnumMapping      sAccumulateMap[];
+  nsSMILEnum                    mAccumulate;
+
+  // Array of PRFloat64* allocated and free'd by this class
+  nsVoidArray                   mKeyTimes;
+  // Array of nsKeySpline* allocated and free'd by this class
+  nsVoidArray                   mKeySplines;
+
+  PRBool                        mIsActive;
+  PRBool                        mIsFrozen;
+
+  //
+  // These are the parameters provided by the previous sample. Currently we
+  // perform lazy calculation. That is, we only calculate the result if and when
+  // instructed by the compositor. This allows us to apply the result directly
+  // to the animation value and allows the compositor to filter out functions
+  // that it determines will not contribute to the final result.
+  //
+  PRInt64                       mSimpleTime;
+  nsSMILTimeValue               mSimpleDuration;
+  PRUint32                      mRepeatIteration;
+  PRBool                        mLastValue;
+  PRBool                        mHasChanged;
+
+  PRInt64                       mBeginTime;
+  PRUint16                      mDocumentPosition;
+
+  // Keep track of which attributes have been set. This is mostly necessary for
+  // correct error handling but it also used to distinguish between when the
+  // mValues array is filled from a 'values' spec or from the values of
+  // 'from', 'to' and 'by'.
+  //
+  // Currently it is not used for all attributes.
+  PRUint16                      mSetFlags;
+
+  // Which attributes have been set but have had errors. This is not used for
+  // all attributes but only those which have specified error behaviour
+  // associated with them.
+  PRUint16                      mErrorFlags;
+
+  // 
+  // This is for the very specific case where we have a 'to' animation that is
+  // frozen part way through the simple duration and there are other active
+  // lower-priority animations targetting the same attribute. In this case
+  // SMILANIM 3.3.6 says:
+  //
+  //   The value for F(t) when a to-animation is frozen (at the end of the
+  //   simple duration) is just the to value. If a to-animation is frozen
+  //   anywhere within the simple duration (e.g., using a repeatCount of "2.5"),
+  //   the value for F(t) when the animation is frozen is the value computed for
+  //   the end of the active duration. Even if other, lower priority animations
+  //   are active while a to-animation is frozen, the value for F(t) does not
+  //   change.
+  //
+  // To implement this properly we'd need to force a resample of all the lower
+  // priority animations at the active end of this animation--something which
+  // would introduce unwanted coupling between the timing and animation model.
+  // Instead we just save the value calculated when this animation is frozen (in
+  // which case this animation will be sampled at the active end and the lower
+  // priority animations should be sampled at a time pretty close to this,
+  // provided we have a reasonable frame rate and we aren't seeking).
+  //
+  // @see
+  // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#FromToByAndAdditive
+  //
+  nsCOMPtr<nsISMILAnimVal>      mFrozenValue; 
+
+  PRLock*                       mCompositingLock;
+};
+
+//----------------------------------------------------------------------
+// Static members
+
+nsSMILEnumMapping nsSMILAnimationFunction::sCalcModeMap[] = {
+      {&nsSMILAtoms::linear, calc_linear},
+      {&nsSMILAtoms::discrete, calc_discrete},
+      {&nsSMILAtoms::paced, calc_paced},
+      {&nsSMILAtoms::spline, calc_spline},
+      {nsnull, 0}
+};
+
+nsSMILEnumMapping nsSMILAnimationFunction::sAdditiveMap[] = {
+      {&nsSMILAtoms::replace, PR_FALSE},
+      {&nsSMILAtoms::sum, PR_TRUE},
+      {nsnull, 0}
+};
+
+nsSMILEnumMapping nsSMILAnimationFunction::sAccumulateMap[] = {
+      {&nsSMILAtoms::none, PR_FALSE},
+      {&nsSMILAtoms::sum, PR_TRUE},
+      {nsnull, 0}
+};
+
+#define BF_ACCUMULATE  0
+#define BF_ADDITIVE    1
+#define BF_BY          2
+#define BF_CALC_MODE   3
+#define BF_FROM        4
+#define BF_KEY_TIMES   5
+#define BF_KEY_SPLINES 6
+#define BF_TO          7
+#define BF_VALUES      8
+
+// Based on GET/SET_BOOLBIT in nsHTMLInputElement.cpp
+#define GET_FLAG(bitfield, field) (((bitfield) & (0x01 << (field))) \
+                                     ? PR_TRUE : PR_FALSE)
+#define SET_FLAG(bitfield, field, b) ((b) \
+                                     ? ((bitfield) |=  (0x01 << (field))) \
+                                     : ((bitfield) &= ~(0x01 << (field))))
+
+//----------------------------------------------------------------------
+// Constructors etc.
+
+nsSMILAnimationFunction::nsSMILAnimationFunction()
+  : mCalcMode(calc_linear, sCalcModeMap),
+    mAdditive(PR_FALSE, sAdditiveMap),
+    mAccumulate(PR_FALSE, sAccumulateMap),
+    mIsActive(PR_FALSE),
+    mIsFrozen(PR_FALSE),
+    mSimpleTime(-1),
+    mRepeatIteration(0),
+    mLastValue(PR_FALSE),
+    mHasChanged(PR_TRUE),
+    mBeginTime(LL_MinInt()),
+    mDocumentPosition(PR_UINT16_MAX),
+    mSetFlags(0),
+    mErrorFlags(0)
+{
+}
+
+nsSMILAnimationFunction::~nsSMILAnimationFunction()
+{
+  // Wait for the lock in case we're in the middle of compositing
+  if (mCompositingLock) {
+    PR_Lock(mCompositingLock);
+    PR_Unlock(mCompositingLock);
+    PR_DestroyLock(mCompositingLock);
+  }
+
+  ClearKeyTimes();
+  ClearKeySplines();
+}
+
+nsresult
+nsSMILAnimationFunction::Init()
+{
+  mCompositingLock = PR_NewLock();
+  return (mCompositingLock) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+nsISMILAnimationFunction*
+NS_NewSMILAnimationFunction()
+{
+  nsSMILAnimationFunction *func = new nsSMILAnimationFunction();
+  NS_ENSURE_TRUE(func, nsnull);
+
+  if (NS_FAILED(func->Init())) {
+    delete func;
+    return nsnull;
+  }
+
+  return func;
+}
+
+//----------------------------------------------------------------------
+// nsISupports methods:
+
+NS_IMPL_ISUPPORTS4(nsSMILAnimationFunction,
+                   nsISMILAnimationFunction,
+                   nsISMILComposable,
+                   nsISMILTimeClient,
+                   nsISupportsWeakReference)
+
+//----------------------------------------------------------------------
+// nsISMILAnimationFunction methods:
+
+nsresult
+nsSMILAnimationFunction::SetTargetAttribute(nsISMILAnimAttr* aAttribute)
+{
+  nsAutoLock lock(mCompositingLock);
+  mAttribute = aAttribute;
+  mValues.Clear();
+  SET_FLAG(mSetFlags, BF_VALUES, PR_FALSE);
+  mFrom = nsnull;
+  mTo = nsnull;
+  mBy = nsnull;
+  mHasChanged = PR_TRUE;
+
+  return NS_OK;
+}
+
+nsISMILAnimAttr*
+nsSMILAnimationFunction::GetTargetAttribute()
+{
+  return mAttribute;
+}
+
+void
+nsSMILAnimationFunction::SetDocumentPosition(PRUint16 aDocPosition)
+{
+  mDocumentPosition = aDocPosition;
+  mHasChanged = PR_TRUE;
+}
+
+nsresult
+nsSMILAnimationFunction::SetAdditive(const nsAString& aAdditive)
+{
+  mHasChanged = PR_TRUE;
+  return mAdditive.SetStringValue(aAdditive);
+}
+
+void
+nsSMILAnimationFunction::UnsetAdditive()
+{
+  mAdditive.SetIntegerValue((PRUint16)PR_FALSE);
+  mHasChanged = PR_TRUE;
+}
+
+nsresult
+nsSMILAnimationFunction::SetBy(const nsAString& aBy)
+{
+  NS_ENSURE_TRUE(mAttribute, NS_ERROR_FAILURE);
+
+  nsAutoLock lock(mCompositingLock);
+  mBy = mAttribute->CreateFromSpec(aBy);
+  SET_FLAG(mErrorFlags, BF_BY, !mBy);
+  if (!mBy)
+    return NS_ERROR_FAILURE;
+
+  FillValuesArray();
+  mHasChanged = PR_TRUE;
+
+  return NS_OK;
+}
+
+void
+nsSMILAnimationFunction::UnsetBy()
+{
+  nsAutoLock lock(mCompositingLock);
+  mBy = nsnull;
+  FillValuesArray();
+  SET_FLAG(mErrorFlags, BF_BY, PR_FALSE);
+  mHasChanged = PR_TRUE;
+}
+
+nsresult
+nsSMILAnimationFunction::SetCalcMode(const nsAString& aCalcMode)
+{
+  mHasChanged = PR_TRUE;
+  nsresult rv = mCalcMode.SetStringValue(aCalcMode);
+  SET_FLAG(mErrorFlags, BF_CALC_MODE, NS_FAILED(rv));
+  CheckKeyTimes();
+  CheckKeySplines();
+
+  return rv;
+}
+
+void
+nsSMILAnimationFunction::UnsetCalcMode()
+{
+  mCalcMode.SetIntegerValue(calc_linear);
+  SET_FLAG(mErrorFlags, BF_CALC_MODE, PR_FALSE);
+  mHasChanged = PR_TRUE;
+  CheckKeyTimes();
+  CheckKeySplines();
+}
+
+nsresult
+nsSMILAnimationFunction::SetAccumulate(const nsAString& aAccumulate)
+{
+  mHasChanged = PR_TRUE;
+  return mAccumulate.SetStringValue(aAccumulate);
+}
+
+void
+nsSMILAnimationFunction::UnsetAccumulate()
+{
+  mAccumulate.SetIntegerValue((PRUint16)PR_FALSE);
+  mHasChanged = PR_TRUE;
+}
+
+
+nsresult
+nsSMILAnimationFunction::SetFrom(const nsAString& aFrom)
+{
+  NS_ENSURE_TRUE(mAttribute, NS_ERROR_FAILURE);
+
+  nsAutoLock lock(mCompositingLock);
+  mFrom = mAttribute->CreateFromSpec(aFrom);
+  SET_FLAG(mErrorFlags, BF_FROM, !mFrom);
+  if (!mFrom)
+    return NS_ERROR_FAILURE;
+
+  FillValuesArray();
+  mHasChanged = PR_TRUE;
+
+  return NS_OK;
+}
+
+void
+nsSMILAnimationFunction::UnsetFrom()
+{
+  nsAutoLock lock(mCompositingLock);
+  mFrom = nsnull;
+  FillValuesArray();
+  SET_FLAG(mErrorFlags, BF_FROM, PR_FALSE);
+  mHasChanged = PR_TRUE;
+}
+
+nsresult
+nsSMILAnimationFunction::SetKeySplines(const nsAString& aKeySplines)
+{
+  nsAutoLock lock(mCompositingLock);
+
+  ClearKeySplines();
+
+  // This will be filled with PRFloat64*'s
+  nsVoidArray keySplines;
+  nsresult rv = nsSMILParserUtils::GetKeySplines(aKeySplines, keySplines);
+
+  if (keySplines.Count() < 1 || keySplines.Count() % 4)
+    rv = NS_ERROR_FAILURE;
+
+  if (NS_SUCCEEDED(rv))
+  {
+    PRFloat64* x1;
+    PRFloat64* y1;
+    PRFloat64* x2;
+    PRFloat64* y2;
+
+    for (int i = 0; i < keySplines.Count(); i += 4)
+    {
+      x1 = NS_STATIC_CAST(PRFloat64*, keySplines[i]);
+      y1 = NS_STATIC_CAST(PRFloat64*, keySplines[i+1]);
+      x2 = NS_STATIC_CAST(PRFloat64*, keySplines[i+2]);
+      y2 = NS_STATIC_CAST(PRFloat64*, keySplines[i+3]);
+
+      mKeySplines.AppendElement(new nsSMILKeySpline(*x1, *y1, *x2, *y2));
+
+      delete x1;
+      delete y1;
+      delete x2;
+      delete y2;
+    }
+  }
+
+  keySplines.Clear();
+
+  mHasChanged = PR_TRUE;
+  SET_FLAG(mSetFlags, BF_KEY_SPLINES, PR_TRUE);
+
+  CheckKeySplines();
+
+  return NS_OK;
+}
+
+void
+nsSMILAnimationFunction::UnsetKeySplines()
+{
+  nsAutoLock lock(mCompositingLock);
+  ClearKeySplines();
+  SET_FLAG(mErrorFlags, BF_KEY_SPLINES, PR_FALSE);
+  SET_FLAG(mSetFlags, BF_KEY_SPLINES, PR_FALSE);
+  mHasChanged = PR_TRUE;
+}
+
+nsresult
+nsSMILAnimationFunction::SetKeyTimes(const nsAString& aKeyTimes)
+{
+  nsAutoLock lock(mCompositingLock);
+
+  ClearKeyTimes();
+  nsresult rv = nsSMILParserUtils::GetKeyTimes(aKeyTimes, mKeyTimes);
+
+  if (NS_SUCCEEDED(rv) && mKeyTimes.Count() < 1)
+    rv = NS_ERROR_FAILURE;
+
+  if (NS_FAILED(rv))
+    ClearKeyTimes();
+
+  mHasChanged = PR_TRUE;
+  SET_FLAG(mSetFlags, BF_KEY_TIMES, PR_TRUE);
+
+  CheckKeyTimes();
+
+  return NS_OK;
+}
+
+void
+nsSMILAnimationFunction::UnsetKeyTimes()
+{
+  nsAutoLock lock(mCompositingLock);
+  ClearKeyTimes();
+  SET_FLAG(mErrorFlags, BF_KEY_TIMES, PR_FALSE);
+  SET_FLAG(mSetFlags, BF_KEY_TIMES, PR_FALSE);
+  mHasChanged = PR_TRUE;
+}
+
+nsresult
+nsSMILAnimationFunction::SetTo(const nsAString& aTo)
+{
+  NS_ENSURE_TRUE(mAttribute, NS_ERROR_FAILURE);
+
+  nsAutoLock lock(mCompositingLock);
+  mTo = mAttribute->CreateFromSpec(aTo);
+  SET_FLAG(mErrorFlags, BF_TO, !mTo);
+  if (!mTo)
+    return NS_ERROR_FAILURE;
+
+  FillValuesArray();
+  mHasChanged = PR_TRUE;
+
+  return NS_OK;
+}
+
+void
+nsSMILAnimationFunction::UnsetTo()
+{
+  nsAutoLock lock(mCompositingLock);
+  mTo = nsnull;
+  FillValuesArray();
+  SET_FLAG(mErrorFlags, BF_TO, PR_FALSE);
+  mHasChanged = PR_TRUE;
+}
+
+nsresult
+nsSMILAnimationFunction::SetValues(const nsAString& aValues)
+{
+  NS_ENSURE_TRUE(mAttribute, NS_ERROR_FAILURE);
+
+  nsAutoLock lock(mCompositingLock);
+  mValues.Clear();
+  SET_FLAG(mSetFlags, BF_VALUES, PR_FALSE);
+
+  nsresult rv = nsSMILParserUtils::GetValues(aValues, mValues, mAttribute);
+
+  if (NS_SUCCEEDED(rv))
+    SET_FLAG(mSetFlags, BF_VALUES, PR_TRUE);
+  else
+    mValues.Clear();
+
+  mHasChanged = PR_TRUE;
+  SET_FLAG(mErrorFlags, BF_VALUES, NS_FAILED(rv));
+  CheckKeyTimes();
+  CheckKeySplines();
+
+  return rv;
+}
+
+void
+nsSMILAnimationFunction::UnsetValues()
+{
+  nsAutoLock lock(mCompositingLock);
+  SET_FLAG(mSetFlags, BF_VALUES, PR_FALSE);
+  FillValuesArray();
+  SET_FLAG(mErrorFlags, BF_VALUES, PR_FALSE);
+  mHasChanged = PR_TRUE;
+}
+
+//----------------------------------------------------------------------
+// nsISMILTimeClient methods
+
+void
+nsSMILAnimationFunction::SampleAt(const PRInt64& aSimpleTime,
+                                  const nsSMILTimeValue& aSimpleDuration,
+                                  const PRUint32& aRepeatIteration)
+{
+ if (mHasChanged || mLastValue || LL_NE(mSimpleTime, aSimpleTime) || 
+     mSimpleDuration.CompareTo(aSimpleDuration) || 
+     mRepeatIteration != aRepeatIteration)
+    mHasChanged = PR_TRUE;
+
+  mSimpleTime       = aSimpleTime;
+  mSimpleDuration   = aSimpleDuration;
+  mRepeatIteration  = aRepeatIteration;
+  mLastValue        = PR_FALSE;
+}
+
+void
+nsSMILAnimationFunction::SampleLastValue(const PRUint32& aRepeatIteration)
+{
+ if (mHasChanged || !mLastValue || mRepeatIteration != aRepeatIteration)
+    mHasChanged = PR_TRUE;
+
+  mRepeatIteration  = aRepeatIteration;
+  mLastValue        = PR_TRUE;
+}
+
+void
+nsSMILAnimationFunction::ToActive(const PRInt64& aBeginTime)
+{
+  mBeginTime = aBeginTime;
+  mIsActive = PR_TRUE;
+  mIsFrozen = PR_FALSE;
+  mFrozenValue = nsnull;
+}
+
+void
+nsSMILAnimationFunction::ToInactive(PRBool aIsFrozen)
+{
+  mIsActive = PR_FALSE;
+  mIsFrozen = aIsFrozen;
+  mFrozenValue = nsnull;
+  mHasChanged = PR_TRUE;
+}
+
+//----------------------------------------------------------------------
+// nsISMILComposable methods
+
+void
+nsSMILAnimationFunction::ComposeResult(nsISMILAnimVal &aResult)
+{
+  mHasChanged = PR_FALSE;
+
+  // This checks if mValues is empty so we don't need to check it again later
+  if (!IsActive())
+    return;
+
+  nsAutoLock lock(mCompositingLock);
+
+  if (!mAttribute)
+    return;
+
+  NS_ENSURE_TRUE(mSimpleTime >= 0,);
+  NS_ENSURE_TRUE(mSimpleDuration.IsResolved() || 
+                 mSimpleDuration.IsIndefinite(), );
+  
+  nsCOMPtr<nsISMILAnimVal> result(mAttribute->Create());
+  NS_ENSURE_TRUE(result,);
+
+  if (mSimpleDuration.IsIndefinite() ||
+      (GET_FLAG(mSetFlags, BF_VALUES) && mValues.Count() == 1)) {
+
+    // Indefinite duration or only one value set: Always set the first value
+    nsISMILAnimVal* firstValue = mValues.SafeObjectAt(0);
+    NS_ENSURE_TRUE(firstValue,);
+    NS_ENSURE_SUCCESS(result->Set(*firstValue),);
+
+  } else if (mLastValue) {
+
+    // Sampling last value
+    nsISMILAnimVal* lastValue = mValues.SafeObjectAt(mValues.Count() - 1);
+    NS_ENSURE_TRUE(lastValue,);
+    if (mAccumulate.GetIntegerValue() && mRepeatIteration > 0) {
+      if (NS_FAILED(result->Repeat(mRepeatIteration, lastValue)))
+        NS_ENSURE_SUCCESS(result->Set(*lastValue),);
+    } else {
+      NS_ENSURE_SUCCESS(result->Set(*lastValue),);
+    }
+
+  } else if (mFrozenValue && !mHasChanged) {
+
+    // Frozen to animation
+    NS_ENSURE_SUCCESS(result->Set(*mFrozenValue),);
+
+  } else {
+
+    // Interpolation
+    NS_ENSURE_SUCCESS(InterpolateResult(*result, aResult),);
+    NS_ENSURE_SUCCESS(AccumulateResult(*result),);
+
+    if (IsToAnimation() && mIsFrozen) {
+      mFrozenValue = mAttribute->Create();
+      NS_ENSURE_TRUE(mFrozenValue,);
+      NS_ENSURE_SUCCESS(mFrozenValue->Set(*result),);
+    }
+  }
+
+  //
+  // If additive animation isn't required or isn't supported, set the value.
+  //
+  if (!IsAdditive() || NS_FAILED(aResult.Add(*result)))
+    aResult.Set(*result);
+}
+
+PRInt8
+nsSMILAnimationFunction::CompareTo(const nsISMILComposable& composable) const
+{
+  //
+  // Inactive animations sort first
+  //
+  if (!IsActive() && composable.IsActive())
+    return -1;
+
+  if (IsActive() && !composable.IsActive())
+    return 1;
+
+  //
+  // Sort based on begin time
+  //
+  if (LL_NE(mBeginTime, composable.GetBeginTime()))
+    return LL_CMP(mBeginTime, >, composable.GetBeginTime()) ? 1 : -1;
+
+  // XXX When syncbase timing is implemented, we next need to sort based on
+  // dependencies
+
+  //
+  // Animations that appear later in the document sort after those earlier in
+  // the document
+  //
+  NS_ASSERTION(mDocumentPosition != composable.GetDocumentPosition(),
+      "Two animations cannot have the same document position!");
+
+  return (mDocumentPosition > composable.GetDocumentPosition())
+    ? 1
+    : (mDocumentPosition == composable.GetDocumentPosition()) ? 0 : -1;
+}
+
+PRBool
+nsSMILAnimationFunction::IsToAnimation() const
+{
+  return (!GET_FLAG(mSetFlags, BF_VALUES) && mTo && !mFrom);
+}
+
+const PRInt64&
+nsSMILAnimationFunction::GetBeginTime() const
+{
+  return mBeginTime;
+}
+
+PRUint16
+nsSMILAnimationFunction::GetDocumentPosition() const
+{
+  return mDocumentPosition;
+}
+
+PRBool
+nsSMILAnimationFunction::IsActive() const
+{
+  //
+  // Even if an animation should be active, if its attributes are set
+  // incorrectly, it will have no effect and should be considered by the
+  // compositor to be inactive.
+  //
+  // Frozen animations should be considered active for the purposes of
+  // compositing.
+  //
+  return ((mIsActive || mIsFrozen) && mValues.Count() > 0 && mErrorFlags == 0);
+}
+
+
+PRBool
+nsSMILAnimationFunction::WillReplace() const
+{
+  /*
+   * In IsAdditive() we don't consider to animation to be additive as it is
+   * a special case that is dealt with differently in the compositing method but
+   * here we return false for to animation as it builds on the underlying value
+   * unless its a frozen to animation.
+   */
+  return !(IsAdditive() || IsToAnimation()) || 
+    (IsToAnimation() && mIsFrozen && !mHasChanged);
+}
+
+PRBool
+nsSMILAnimationFunction::HasChanged() const
+{
+  return mHasChanged;
+}
+
+//----------------------------------------------------------------------
+// Implementation helpers
+
+nsresult
+nsSMILAnimationFunction::InterpolateResult
+(
+  nsISMILAnimVal& aResult,
+  nsISMILAnimVal& aBaseValue
+)
+{
+  double          fTime;
+  double          fDur;
+  double          simpleDistance;
+  double          intervalDistance;
+  PRInt32         index;
+  nsISMILAnimVal* from = nsnull;
+  nsISMILAnimVal* to   = nsnull;
+  const PRInt64&  dur  = mSimpleDuration.GetMillis();
+
+  LL_L2D(fTime, mSimpleTime);
+  LL_L2D(fDur, dur);
+
+  if (LL_CMP(mSimpleTime, >=, dur) || !LL_GE_ZERO(mSimpleTime)) {
+    NS_ERROR("Animation sampled outside interval.");
+    return NS_ERROR_FAILURE;
+  }
+
+  if (mValues.Count() < 2 && !IsToAnimation()) {
+    NS_ERROR("Unexpected number of values.");
+    return NS_ERROR_FAILURE;
+  }
+
+  simpleDistance = (fDur > 0.0) ? fTime / fDur : 0.0;
+
+#ifdef ALLOW_BAD_KEYTIMES
+  if (GET_FLAG(mSetFlags, BF_KEY_TIMES)) {
+    PRFloat64 first = *NS_STATIC_CAST(PRFloat64*, mKeyTimes[0]);
+    if (first > 0.0 && simpleDistance < first) {
+      if (!IsToAnimation())
+        aResult.Set(*mValues[0]);
+      return NS_OK;
+    }
+    PRFloat64 last = 
+      *NS_STATIC_CAST(PRFloat64*, mKeyTimes[mKeyTimes.Count() - 1]);
+    if (last < 1.0 && simpleDistance >= last) {
+      if (IsToAnimation())
+        aResult.Set(*mValues[0]);
+      else
+        aResult.Set(*mValues[mValues.Count() - 1]);
+      return NS_OK;
+    }
+  }
+#endif
+
+  ScaleSimpleDistance(simpleDistance);
+
+  if (IsToAnimation()) {
+    from = &aBaseValue;
+    to = mValues.SafeObjectAt(0);
+    NS_ENSURE_TRUE(to, NS_ERROR_FAILURE);
+    intervalDistance = simpleDistance;
+    ScaleIntervalDistance(intervalDistance, 0, 1);
+  } else {
+    index = (PRInt32) floor(simpleDistance * (mValues.Count() - 1));
+
+    from = mValues.SafeObjectAt(index);
+    NS_ENSURE_TRUE(from, NS_ERROR_FAILURE);
+
+    to = mValues.SafeObjectAt(index + 1);
+    NS_ENSURE_TRUE(to, NS_ERROR_FAILURE);
+
+    intervalDistance = simpleDistance * (mValues.Count() - 1) - index;
+    ScaleIntervalDistance(intervalDistance, index, mValues.Count() - 1);
+  }
+
+  return from->Interpolate(*to,
+                           NS_STATIC_CAST(float, intervalDistance),
+                           aResult);
+}
+
+nsresult
+nsSMILAnimationFunction::AccumulateResult(nsISMILAnimVal& aResult)
+{
+  if (!IsToAnimation() && mAccumulate.GetIntegerValue() && mRepeatIteration)
+  {
+    nsCOMPtr<nsISMILAnimVal> repeatValue(mAttribute->Create());
+    NS_ENSURE_TRUE(repeatValue, NS_ERROR_FAILURE);
+
+    nsISMILAnimVal* lastValue = mValues.SafeObjectAt(mValues.Count() - 1);
+    NS_ENSURE_TRUE(lastValue, NS_ERROR_FAILURE);
+
+    // If the target attribute doesn't support addition, Repeat will fail and we
+    // leave aResult untouched.
+    if (NS_SUCCEEDED(repeatValue->Repeat(mRepeatIteration - 1, lastValue)))
+      aResult.Add(*repeatValue);
+  }
+
+  return NS_OK;
+}
+
+/*
+ * Scale the simple distance taking into account any keyTimes.
+ */
+void
+nsSMILAnimationFunction::ScaleSimpleDistance(PRFloat64& dist)
+{
+  if (!GET_FLAG(mSetFlags, BF_KEY_TIMES))
+    return;
+
+  PRUint32  numTimes = mKeyTimes.Count();
+
+  if (numTimes < 2)
+    return;
+
+  PRUint32 i = 0;
+  for (;
+       i < numTimes - 2 && dist >= *NS_STATIC_CAST(PRFloat64*, mKeyTimes[i+1]);
+       ++i);
+
+  PRFloat64& intervalStart = *NS_STATIC_CAST(PRFloat64*, mKeyTimes[i]);
+  PRFloat64& intervalEnd = *NS_STATIC_CAST(PRFloat64*, mKeyTimes[i+1]);
+
+  PRFloat64 intervalLength = intervalEnd - intervalStart;
+  if (intervalLength <= 0.0) {
+    dist = intervalStart;
+    return;
+  }
+
+  dist = (i + (dist - intervalStart) / intervalLength) * 
+         1.0 / (PRFloat64)(numTimes - 1);
+}
+
+/*
+ * Scale the interval distance taking into account any keySplines.
+ */
+void
+nsSMILAnimationFunction::ScaleIntervalDistance(PRFloat64& aDist,
+                                               PRUint32 aIntervalIndex,
+                                               PRUint32 aNumIntervals)
+{
+  if (mCalcMode.GetIntegerValue() != calc_spline)
+    return;
+
+  if (!GET_FLAG(mSetFlags, BF_KEY_SPLINES))
+    return;
+
+  NS_ASSERTION(aIntervalIndex >= 0 && 
+               aIntervalIndex < (PRUint32)mKeySplines.Count(),
+               "Invalid interval index.");
+  NS_ASSERTION(aNumIntervals >= 1, "Invalid number of intervals.");
+
+  if (aIntervalIndex < 0 ||
+      aIntervalIndex >= (PRUint32)mKeySplines.Count() ||
+      aNumIntervals < 1)
+    return;
+
+  nsSMILKeySpline *spline = 
+    NS_STATIC_CAST(nsSMILKeySpline*, mKeySplines[aIntervalIndex]);
+  aDist = spline->GetSplineValue(aDist);
+}
+
+/*
+ * SMILANIM specifies the following rules for animation function values:
+ *
+ * (1) if values is set, it overrides everything
+ * (2) for from/to/by animation at least to or by must be specified, from on its
+ *     own (or nothing) is an error--which we will ignore
+ * (3) if both by and to are specified only to will be used, by will be ignored
+ * (4) if by is specified without from (by animation), forces additive behaviour
+ * (5) if to is specified without from (to animation), special care needs to be
+ *     taken when compositing animation as such animations are composited last.
+ *
+ * This helper method applies these rules to fill in the values list and to set
+ * some internal state.
+ */
+void
+nsSMILAnimationFunction::FillValuesArray()
+{
+  if (!GET_FLAG(mSetFlags, BF_VALUES)) {
+    mValues.Clear();
+
+    if (mTo) {
+      if (mFrom) {
+        mValues.AppendObject(mFrom);
+        mValues.AppendObject(mTo);
+      } else {
+        mValues.AppendObject(mTo);
+      }
+    } else if (mBy) {
+      if (mFrom) {
+        //
+        // Set values to 'from; from + to'
+        //
+        mValues.AppendObject(mFrom);
+        nsCOMPtr<nsISMILAnimVal> to (mAttribute->Create());
+        if (to &&
+            NS_SUCCEEDED(to->Set(*mFrom)) &&
+            NS_SUCCEEDED(to->Add(*mBy))) {
+          mValues.AppendObject(to);
+        } else {
+          mValues.Clear();
+        }
+      } else {
+        //
+        // Set values to '0; by'
+        //
+        nsCOMPtr<nsISMILAnimVal> from (mAttribute->Create());
+        if (from) {
+          mValues.AppendObject(from);
+          mValues.AppendObject(mBy);
+        } else {
+          mValues.Clear();
+        }
+      }
+    }
+    // else, do nothing, mValues has been cleared already.
+  }
+
+  // mValues has changed, do we still have the right number of keySplines and
+  // keyTimes?
+  CheckKeyTimes();
+  CheckKeySplines();
+}
+
+inline PRBool
+nsSMILAnimationFunction::IsAdditive() const
+{
+  /*
+   * Animation is additive if:
+   *
+   * (1) additive = "sum" (mAdditive == true), or
+   * (2) it is 'by animation' (by is set, from and values are not)
+   *
+   * Although animation is not additive if it is 'to animation'
+   */
+  return (!IsToAnimation() && 
+      (mAdditive.GetIntegerValue() || 
+       (!GET_FLAG(mSetFlags, BF_VALUES) && mBy && !mFrom)));
+}
+
+inline void
+nsSMILAnimationFunction::ClearKeyTimes()
+{
+  PRUint32 i, count = mKeyTimes.Count();
+  for (i=0; i < count; ++i)
+    delete NS_STATIC_CAST(PRFloat64*, mKeyTimes[i]);
+  mKeyTimes.Clear();
+}
+
+inline void
+nsSMILAnimationFunction::ClearKeySplines()
+{
+  PRUint32 i, count = mKeySplines.Count();
+  for (i=0; i < count; ++i)
+    delete NS_STATIC_CAST(nsSMILKeySpline*, mKeySplines[i]);
+  mKeySplines.Clear();
+}
+
+/**
+ * Performs checks for the keyTimes attribute required by the SMIL spec but
+ * which depend on other attributes and therefore needs to be updated as
+ * dependent attributes are set.
+ */
+void
+nsSMILAnimationFunction::CheckKeyTimes()
+{
+  if (!GET_FLAG(mSetFlags, BF_KEY_TIMES))
+    return;
+
+  // attribute is ignored for calcMode = paced
+  if (mCalcMode.GetIntegerValue() == calc_paced) {
+    SET_FLAG(mErrorFlags, BF_KEY_TIMES, PR_FALSE);
+    return;
+  }
+
+  if (mKeyTimes.Count() < 1) {
+    // keyTimes isn't set or failed preliminary checks
+    SET_FLAG(mErrorFlags, BF_KEY_TIMES, PR_TRUE);
+    return;
+  }
+
+  // no. keyTimes == no. values
+  if ((mKeyTimes.Count() != mValues.Count() && !IsToAnimation()) ||
+      (IsToAnimation() && mKeyTimes.Count() != 2)) {
+    SET_FLAG(mErrorFlags, BF_KEY_TIMES, PR_TRUE);
+    return;
+  }
+
+  // special handling if there is only one keyTime. The spec doesn't say what to
+  // do in this case so we allow the keyTime to be either 0 or 1.
+  if (mKeyTimes.Count() == 1) {
+    PRFloat64& time = *NS_STATIC_CAST(PRFloat64*, mKeyTimes[0]);
+    SET_FLAG(mErrorFlags, BF_KEY_TIMES, !(time == 0.0 || time == 1.0));
+    return;
+  }
+
+  // there is a contradiction in the spec here. We're told the last value must
+  // be 1 for linear or spline calcMode's but then an example is given later of
+  // a from-to animation with a spline calcMode and keyTimes "0.0; 0.7".
+
+#ifndef ALLOW_BAD_KEYTIMES
+  // first value must be 0
+  if (*NS_STATIC_CAST(PRFloat64*,mKeyTimes[0]) != 0.0) {
+    SET_FLAG(mErrorFlags, BF_KEY_TIMES, PR_TRUE);
+    return;
+  }
+
+  // last value must be 1 for linear or spline calcMode's
+  if (mCalcMode.GetIntegerValue() == calc_linear || 
+      mCalcMode.GetIntegerValue() == calc_spline) {
+    PRInt32 count = mKeyTimes.Count();
+    PRFloat64* lastValue = NS_STATIC_CAST(PRFloat64*, mKeyTimes[count - 1]);
+    if (!lastValue || *lastValue != 1.0) {
+      SET_FLAG(mErrorFlags, BF_KEY_TIMES, PR_TRUE);
+      return;
+    }
+  }
+#endif
+
+  SET_FLAG(mErrorFlags, BF_KEY_TIMES, PR_FALSE);
+}
+
+void
+nsSMILAnimationFunction::CheckKeySplines()
+{
+  // attribute is ignored if calc mode is not spline
+  if (mCalcMode.GetIntegerValue() != calc_spline) {
+    SET_FLAG(mErrorFlags, BF_KEY_SPLINES, PR_FALSE);
+    return;
+  }
+
+  // calc mode is spline but the attribute is not set
+  if (!GET_FLAG(mSetFlags, BF_KEY_SPLINES)) {
+    SET_FLAG(mErrorFlags, BF_KEY_SPLINES, PR_FALSE);
+    return;
+  }
+
+  if (mKeySplines.Count() < 1) {
+    // keyTimes isn't set or failed preliminary checks
+    SET_FLAG(mErrorFlags, BF_KEY_SPLINES, PR_TRUE);
+    return;
+  }
+
+  // ignore splines if there's only one value
+  if (mValues.Count() == 1 && !IsToAnimation()) {
+    SET_FLAG(mErrorFlags, BF_KEY_SPLINES, PR_FALSE);
+    return;
+  }
+
+  // no. keySpline specs == no. values - 1
+  PRInt32 splineSpecs = mKeySplines.Count();
+  if ((splineSpecs != mValues.Count() - 1 && !IsToAnimation()) ||
+      (IsToAnimation() && splineSpecs != 1)) {
+    SET_FLAG(mErrorFlags, BF_KEY_SPLINES, PR_TRUE);
+    return;
+  }
+
+  SET_FLAG(mErrorFlags, BF_KEY_SPLINES, PR_FALSE);
+}
+
Index: content/smil/src/nsSMILAnimationRegistry.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILAnimationRegistry.cpp
diff -N content/smil/src/nsSMILAnimationRegistry.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILAnimationRegistry.cpp	5 Nov 2005 04:39:11 -0000
@@ -0,0 +1,337 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSMILAnimationRegistry.h"
+#include "nsISMILAnimationObserver.h"
+#include "nsISMILAnimAttr.h"
+#include "nsISMILComposable.h"
+#include "nsSMILTimedDocumentRoot.h"
+#include "nsSMILCompositor.h"
+#include "nsAutoLock.h"
+
+////////////////////////////////////////////////////////////////////////
+// nsSMILAnimationRegistry implementation
+
+struct CompositorEntry
+{
+  nsISMILAnimAttr*  key;
+  nsSMILCompositor  compositor;
+};
+
+//----------------------------------------------------------------------
+// ctors, dtors, factory methods
+
+nsSMILAnimationRegistry::~nsSMILAnimationRegistry()
+{
+  if (mController && mTimedDocumentRoot)
+    mController->RemoveTimeContainer(mTimedDocumentRoot);
+
+  CompositorEntry*    entry;
+  PRInt32             count = mCompositors.Count();
+
+  PR_Lock(mAnimationLock);
+
+  for (PRInt32 i = 0; i < count; ++i) {
+    entry = NS_STATIC_CAST(CompositorEntry*, mCompositors[i]);
+    mCompositors.ReplaceElementAt(nsnull, i);
+    delete entry;
+  }
+
+  mCompositors.Clear();
+
+  PR_Unlock(mAnimationLock);
+  PR_DestroyLock(mAnimationLock);
+}
+
+nsISMILAnimationRegistry*
+NS_NewSMILAnimationRegistry()
+{
+  nsSMILAnimationRegistry* animationRegistry = new nsSMILAnimationRegistry();
+
+  if (!animationRegistry)
+    return nsnull;
+
+  nsresult rv = animationRegistry->Init();
+  if (NS_FAILED(rv)) {
+    delete animationRegistry;
+    animationRegistry = nsnull;
+  }
+
+  return animationRegistry;
+}
+
+nsresult
+nsSMILAnimationRegistry::Init()
+{
+  mTimedDocumentRoot = new nsSMILTimedDocumentRoot(this);
+  NS_ENSURE_TRUE(mTimedDocumentRoot, NS_ERROR_OUT_OF_MEMORY);
+
+  mTimedDocumentRoot->Pause();
+
+  mAnimationLock = PR_NewLock();
+  NS_ENSURE_TRUE(mAnimationLock, NS_ERROR_OUT_OF_MEMORY);
+
+  return NS_OK;
+}
+
+//----------------------------------------------------------------------
+// nsISupports methods:
+
+NS_IMPL_ISUPPORTS1(nsSMILAnimationRegistry,
+                   nsISMILAnimationRegistry);
+
+//----------------------------------------------------------------------
+// nsISMILAnimationRegistry methods:
+
+nsresult
+nsSMILAnimationRegistry::SetController(nsISMILAnimationController* aController)
+{
+  nsresult rv = NS_OK;
+
+  NS_ENSURE_TRUE(mTimedDocumentRoot, NS_ERROR_FAILURE);
+
+  if (mController) {
+    rv = mController->RemoveTimeContainer(mTimedDocumentRoot);
+    NS_ENSURE_SUCCESS(rv,rv);
+  }
+
+  mController = aController;
+
+  if (mController)
+    rv = mController->AddTimeContainer(mTimedDocumentRoot);
+
+  return rv;
+}
+
+void
+nsSMILAnimationRegistry::SetObserver(nsISMILAnimationObserver* aObserver)
+{
+  if (aObserver) {
+    mObserver = do_GetWeakReference(aObserver);
+  } else {
+    mObserver = nsnull;
+  }
+}
+
+nsresult
+nsSMILAnimationRegistry::Start()
+{
+  NS_ENSURE_TRUE(mTimedDocumentRoot,NS_ERROR_FAILURE);
+  if (!mStarted) {
+    mTimedDocumentRoot->Resume();
+    mStarted = PR_TRUE;
+  }
+  return NS_OK;
+}
+
+void
+nsSMILAnimationRegistry::Pause()
+{
+  NS_ENSURE_TRUE(mTimedDocumentRoot,);
+  NS_ENSURE_TRUE(mStarted,);
+  mTimedDocumentRoot->Pause();
+}
+
+void
+nsSMILAnimationRegistry::Unpause()
+{
+  NS_ENSURE_TRUE(mTimedDocumentRoot,);
+  NS_ENSURE_TRUE(mStarted,);
+  mTimedDocumentRoot->Resume();
+}
+
+PRBool
+nsSMILAnimationRegistry::IsPaused()
+{
+  if (!mStarted)
+    return PR_TRUE;
+
+  NS_ENSURE_TRUE(mTimedDocumentRoot,PR_FALSE);
+
+  return mTimedDocumentRoot->IsPaused();
+}
+
+float
+nsSMILAnimationRegistry::GetCurrentTime()
+{
+  PRFloat64 fCurrentTime;
+  PRInt64 currentTime = mTimedDocumentRoot->GetDocumentTime();
+  LL_L2D(fCurrentTime, currentTime);
+  return (float)(fCurrentTime / PR_MSEC_PER_SEC);
+}
+
+nsresult
+nsSMILAnimationRegistry::SetCurrentTime(float aSeconds)
+{
+  PRInt64 lSeconds;
+  LL_D2L(lSeconds, aSeconds);
+  LL_MUL(lSeconds, PR_MSEC_PER_SEC, lSeconds);
+  return mTimedDocumentRoot->SeekToTime(lSeconds);
+}
+
+nsresult
+nsSMILAnimationRegistry::RegisterComposable(nsISMILAnimAttr* aTargetAttr,
+                                            nsISMILComposable* aComposable)
+{
+  NS_ENSURE_ARG_POINTER(aTargetAttr);
+  NS_ENSURE_ARG_POINTER(aComposable);
+
+  nsSMILCompositor*   compositor = nsnull;
+  CompositorEntry*    entry;
+
+  nsAutoLock lock(mAnimationLock);
+
+  //
+  // Iterate in reverse as if a compositor already exists for this attribute it
+  // is most likely to be the most recently added entry.
+  //
+  for (PRInt32 i = mCompositors.Count() - 1; i >= 0 && !compositor; --i) {
+    entry = (CompositorEntry*)mCompositors[i];
+    if (entry && entry->key == aTargetAttr)
+      compositor = &entry->compositor;
+  }
+
+  if (!compositor) {
+    entry = new CompositorEntry();
+    NS_ENSURE_TRUE(entry,NS_ERROR_OUT_OF_MEMORY);
+
+    nsresult rv = entry->compositor.Init(aTargetAttr);
+    NS_ENSURE_SUCCESS(rv,rv);
+
+    entry->key = aTargetAttr;
+    if (!mCompositors.AppendElement(entry)) {
+      delete entry;
+      return NS_ERROR_FAILURE;
+    }
+
+    compositor = &entry->compositor;
+  }
+
+  return compositor->AddComposable(aComposable);
+}
+
+nsresult
+nsSMILAnimationRegistry::UnregisterComposable(nsISMILComposable* aComposable)
+{
+  NS_ENSURE_ARG_POINTER(aComposable);
+
+  PRBool              found = PR_FALSE;
+  nsresult            result = NS_OK;
+  nsresult            rv = NS_ERROR_FAILURE;
+  CompositorEntry*    entry;
+  PRInt32             count = mCompositors.Count();
+
+  nsAutoLock lock(mAnimationLock);
+
+  for (PRInt32 i = 0; i < count; ++i) {
+    entry = (CompositorEntry*)mCompositors[i];
+    if (entry) {
+      rv = entry->compositor.RemoveComposable(aComposable);
+
+      // This rather complicated error handling just ensures that we report the
+      // first error that occurs, or a generic error if the item wasn't found.
+      if (NS_SUCCEEDED(result))
+        result = rv;
+      found = PR_TRUE;
+    }
+
+    // Even if the entry now no longer has any compositors we don't bother
+    // deleting it as it may be re-used again later.
+  }
+
+  return (found) ? rv : NS_ERROR_FAILURE;
+}
+
+nsresult
+nsSMILAnimationRegistry::RegisterTimedElement(nsISMILTimedElement *aElement)
+{
+  return (mTimedDocumentRoot) ? mTimedDocumentRoot->AddTimedElement(aElement)
+                              : NS_ERROR_FAILURE;
+}
+
+nsresult
+nsSMILAnimationRegistry::UnregisterTimedElement(nsISMILTimedElement *aElement)
+{
+  return (mTimedDocumentRoot) ? mTimedDocumentRoot->RemoveTimedElement(aElement)
+                              : NS_ERROR_FAILURE;
+}
+
+void
+nsSMILAnimationRegistry::StartSample()
+{
+  if (mObserver) {
+    nsCOMPtr<nsISMILAnimationObserver> observer = do_QueryReferent(mObserver);
+    if (observer)
+      observer->StartSample();
+  }
+
+  // Do any pre-animation actions here, e.g. acquiring locks, blocking scripts
+  // etc.
+}
+
+void
+nsSMILAnimationRegistry::EndSample()
+{
+  CompositorEntry*    entry;
+  PRInt32             count = mCompositors.Count();
+  nsCOMPtr<nsISMILAnimationObserver> observer;
+  
+  if (mObserver)
+    observer = do_QueryReferent(mObserver);
+
+  if (observer)
+    observer->StartCompositing();
+
+  PR_Lock(mAnimationLock);
+
+  for (PRInt32 i = 0; i < count; ++i) {
+    entry = NS_STATIC_CAST(CompositorEntry*, mCompositors[i]);
+    if (entry)
+      entry->compositor.ComposeSample();
+  }
+
+  PR_Unlock(mAnimationLock);
+
+  if (observer)
+    observer->EndCompositing();
+
+  // Release any locks etc.
+
+  if (observer)
+    observer->EndSample();
+}
+
Index: content/smil/src/nsSMILAnimationRegistry.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILAnimationRegistry.h
diff -N content/smil/src/nsSMILAnimationRegistry.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILAnimationRegistry.h	5 Nov 2005 04:39:11 -0000
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_SMILANIMATIONREGISTRY_H__
+#define __NS_SMILANIMATIONREGISTRY_H__
+
+#include "nsISMILAnimationRegistry.h"
+#include "nsISMILAnimationController.h"
+#include "nsVoidArray.h"
+#include "nsAutoPtr.h"
+#include "nsWeakPtr.h"
+
+class nsSMILTimedDocumentRoot;
+
+class nsSMILAnimationRegistry : public nsISMILAnimationRegistry
+{
+public:
+  ~nsSMILAnimationRegistry();
+
+  NS_DECL_ISUPPORTS
+
+  virtual void      StartSample();
+  virtual void      EndSample();
+
+  // nsISMILAnimationRegistry
+  virtual nsresult  SetController(nsISMILAnimationController* aController);
+  virtual void      SetObserver(nsISMILAnimationObserver* aObserver);
+  virtual nsresult  Start();
+  virtual void      Pause();
+  virtual void      Unpause();
+  virtual PRBool    IsPaused();
+  virtual float     GetCurrentTime();
+  virtual nsresult  SetCurrentTime(float aSeconds);
+  virtual nsresult  RegisterComposable(nsISMILAnimAttr *aTargetAttr,
+                                       nsISMILComposable *aComposable);
+  virtual nsresult  UnregisterComposable(nsISMILComposable *aComposable);
+  virtual nsresult  RegisterTimedElement(nsISMILTimedElement *aElement);
+  virtual nsresult  UnregisterTimedElement(nsISMILTimedElement *aElement);
+
+protected:
+  friend nsISMILAnimationRegistry* NS_NewSMILAnimationRegistry();
+
+  nsresult          Init();
+
+  nsVoidArray                           mCompositors;
+  nsRefPtr<nsSMILTimedDocumentRoot>     mTimedDocumentRoot;
+  nsCOMPtr<nsISMILAnimationController>  mController;
+  nsWeakPtr                             mObserver;
+  PRBool                                mStarted;
+  PRLock*                               mAnimationLock;
+
+private:
+  // This class should only be created by the factory method
+  nsSMILAnimationRegistry() : mStarted(PR_FALSE) {}
+
+  // Pass by value and assignment should not be used
+  nsSMILAnimationRegistry(const nsSMILAnimationRegistry& other);
+  nsSMILAnimationRegistry& operator=(const nsSMILAnimationRegistry& right);
+};
+
+#endif // __NS_SMILANIMATIONREGISTRY_H__
+
Index: content/smil/src/nsSMILAtomList.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILAtomList.h
diff -N content/smil/src/nsSMILAtomList.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILAtomList.h	5 Nov 2005 04:39:11 -0000
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+/******
+
+  This file contains the list of all SMIL nsIAtoms and their values
+  
+  It is designed to be used as inline input to nsSMILAtoms.cpp *only*
+  through the magic of C preprocessing.
+
+  All entires must be enclosed in the macro SMIL_ATOM which will have cruel
+  and unusual things done to it
+
+  It is recommended (but not strictly necessary) to keep all entries
+  in alphabetical order
+
+  The first argument to SMIL_ATOM is the C++ identifier of the atom
+  The second argument is the string value of the atom
+
+ ******/
+
+// calc modes
+SMIL_ATOM(discrete, "discrete")
+SMIL_ATOM(linear, "linear")
+SMIL_ATOM(paced, "paced")
+SMIL_ATOM(spline, "spline")
+
+// fill modes
+SMIL_ATOM(freeze, "freeze")
+SMIL_ATOM(remove, "remove")
+
+// additive
+SMIL_ATOM(replace, "replace")
+SMIL_ATOM(sum, "sum")
+
+// accumulate
+SMIL_ATOM(none, "none")
+// sum is already listed
+
+// restart modes
+SMIL_ATOM(always, "always")
+SMIL_ATOM(whennotactive, "whenNotActive")
+SMIL_ATOM(never, "never")
+
Index: content/smil/src/nsSMILAtoms.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILAtoms.cpp
diff -N content/smil/src/nsSMILAtoms.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILAtoms.cpp	5 Nov 2005 04:39:12 -0000
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSMILAtoms.h"
+#include "nsStaticAtom.h"
+#include "nsMemory.h"
+
+// define storage for all atoms
+#define SMIL_ATOM(_name, _value) nsIAtom* nsSMILAtoms::_name;
+#include "nsSMILAtomList.h"
+#undef SMIL_ATOM
+
+static const nsStaticAtom SMILAtoms_info[] = {
+#define SMIL_ATOM(name_, value_) { value_, &nsSMILAtoms::name_ },
+#include "nsSMILAtomList.h"
+#undef SMIL_ATOM
+};
+
+void nsSMILAtoms::AddRefAtoms()
+{
+  static bool atomsRegistered = PR_FALSE;
+
+  if (!atomsRegistered) {
+    NS_RegisterStaticAtoms(SMILAtoms_info, NS_ARRAY_LENGTH(SMILAtoms_info));
+    atomsRegistered = PR_TRUE;
+  }
+}
+
Index: content/smil/src/nsSMILAtoms.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILAtoms.h
diff -N content/smil/src/nsSMILAtoms.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILAtoms.h	5 Nov 2005 04:39:12 -0000
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_SMILATOMS_H__
+#define __NS_SMILATOMS_H__
+
+#include "prtypes.h"
+#include "nsIAtom.h"
+
+class nsSMILAtoms 
+{
+public:
+  static void AddRefAtoms();
+
+  /* 
+   * Declare all atoms
+   * 
+   * The atom names and values are stored in nsSMILAtomList.h and are brought to
+   * you by the magic of C preprocessing
+   *
+   * Add new atoms to nsSMILAtomList and all support logic will be
+   * auto-generated
+   */
+#define SMIL_ATOM(_name, _value) static nsIAtom* _name;
+#include "nsSMILAtomList.h"
+#undef SMIL_ATOM
+
+};
+
+#endif /* __NS_SMILATOMS_H__ */
+
Index: content/smil/src/nsSMILCompositor.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILCompositor.cpp
diff -N content/smil/src/nsSMILCompositor.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILCompositor.cpp	5 Nov 2005 04:39:12 -0000
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSMILCompositor.h"
+#include "nsISMILComposable.h"
+#include "nsISimpleEnumerator.h"
+#include "nsArrayEnumerator.h"
+#include "nsISMILAnimAttr.h"
+#include "nsISMILAnimVal.h"
+#include "nsAutoLock.h"
+
+////////////////////////////////////////////////////////////////////////
+// nsSMILCompositor implementation
+
+nsSMILCompositor::~nsSMILCompositor()
+{
+  if (mLock) {
+    PR_Lock(mLock);
+    PR_Unlock(mLock);
+    PR_DestroyLock(mLock);
+  }
+}
+
+nsresult
+nsSMILCompositor::Init(nsISMILAnimAttr* aTargetAttribute)
+{
+  NS_ENSURE_ARG_POINTER(aTargetAttribute);
+
+  nsresult rv;
+  mTargetAttribute = do_GetWeakReference(aTargetAttribute, &rv);
+  if (NS_FAILED(rv)) {
+    mTargetAttribute = nsnull;
+    return rv;
+  }
+
+  mResult = aTargetAttribute->Create();
+  NS_ENSURE_TRUE(mResult, NS_ERROR_OUT_OF_MEMORY);
+
+  mLock = PR_NewLock();
+  NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
+
+  return NS_OK;
+}
+
+nsresult
+nsSMILCompositor::AddComposable(nsISMILComposable* aComposable)
+{
+  NS_ENSURE_ARG_POINTER(aComposable);
+
+  nsresult rv;
+  nsCOMPtr<nsIWeakReference> weakRef(
+      getter_AddRefs(do_GetWeakReference(aComposable, &rv)) );
+
+  nsAutoLock lock(mLock);
+  if (NS_SUCCEEDED(rv))
+    rv = (mChildren.AppendObject(weakRef)) ? NS_OK : NS_ERROR_FAILURE;
+
+  return rv;
+}
+
+nsresult
+nsSMILCompositor::RemoveComposable(nsISMILComposable* aComposable)
+{
+  NS_ENSURE_ARG_POINTER(aComposable);
+
+  nsresult rv;
+  nsCOMPtr<nsIWeakReference> weakRef(
+      getter_AddRefs(do_GetWeakReference(aComposable, &rv)) );
+  
+  nsAutoLock lock(mLock);
+  if (NS_SUCCEEDED(rv))
+    rv = (mChildren.RemoveObject(weakRef)) ? NS_OK : NS_ERROR_FAILURE;
+
+  return rv;
+}
+
+void
+nsSMILCompositor::ComposeSample()
+{
+  NS_ENSURE_TRUE(mTargetAttribute,);
+  NS_ENSURE_TRUE(mResult,);
+  nsresult rv;
+
+  nsCOMPtr<nsISMILAnimAttr> targetAttribute( 
+      do_QueryReferent(mTargetAttribute) );
+  NS_ENSURE_TRUE(targetAttribute,);
+
+  rv = targetAttribute->GetBaseValue(*mResult);
+  NS_ENSURE_SUCCESS(rv,);
+
+  PR_Lock(mLock);
+  mChildren.Sort(SortCompositors, nsnull);
+
+  PRBool changed = PR_FALSE;
+  nsCOMPtr<nsISMILComposable> composable;
+  PRUint32 length = mChildren.Count();
+  PRUint32 i;
+  
+  for (i = length; i > 0; --i) {
+   composable = do_QueryReferent(mChildren[i-1]);
+   if (composable) {
+     changed |= composable->HasChanged();
+     if (composable->WillReplace()) {
+       --i;
+       break;
+     }
+   }
+  }
+
+  if (!changed) {
+    PR_Unlock(mLock);
+    return;
+  }
+
+  for (; i < length; ++i)
+  {
+    composable = do_QueryReferent(mChildren[i]);
+    if (composable)
+      composable->ComposeResult(*mResult);
+  }
+
+  PR_Unlock(mLock);
+  
+  // We can't just call Set on the animated value itself, because the observers
+  // of the animated object as a whole need to be updated too.
+  targetAttribute->SetAnimValue(*mResult);
+}
+
+//----------------------------------------------------------------------
+// Implementation helpers
+
+PR_CALLBACK int
+nsSMILCompositor::SortCompositors(nsIWeakReference* aRef1,
+                                  nsIWeakReference* aRef2,
+                                  void* /*aData*/)      
+{
+  nsCOMPtr<nsISMILComposable> a = do_QueryReferent(aRef1);
+  nsCOMPtr<nsISMILComposable> b = do_QueryReferent(aRef2);
+
+  return (a && b) ? a->CompareTo(*b) : (a) ? 1 : (b) ? -1 : 0;
+}
+
Index: content/smil/src/nsSMILCompositor.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILCompositor.h
diff -N content/smil/src/nsSMILCompositor.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILCompositor.h	5 Nov 2005 04:39:12 -0000
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_SMILCOMPOSITOR_H__
+#define __NS_SMILCOMPOSITOR_H__
+
+#include "nsCOMArray.h"
+#include "nsWeakReference.h"
+#include "nsISMILAnimVal.h"
+#include "prlock.h"
+
+////////////////////////////////////////////////////////////////////////
+// nsSMILCompositor: Collection of nsISMILComposable animations
+
+class nsISMILComposable;
+class nsISMILAnimAttr;
+
+class nsSMILCompositor
+{
+public:
+  nsSMILCompositor() {}
+  ~nsSMILCompositor();
+
+  nsresult  Init(nsISMILAnimAttr* aTargetAttribute);
+
+  nsresult  AddComposable(nsISMILComposable* aComposable);
+  nsresult  RemoveComposable(nsISMILComposable* aComposable);
+  void      ComposeSample();
+
+protected:
+  PR_STATIC_CALLBACK(int) SortCompositors(nsIWeakReference* aRef1,
+                                          nsIWeakReference* aRef2,
+                                          void* aData);
+
+  nsCOMArray<nsIWeakReference>   mChildren;
+  nsCOMPtr<nsISMILAnimVal>       mResult;
+  nsWeakPtr                      mTargetAttribute;
+  PRLock*                        mLock;
+
+private:
+  // Pass by value and assignment should not be used
+  nsSMILCompositor(const nsSMILCompositor& other);
+  nsSMILCompositor& operator=(const nsSMILCompositor& right);
+};
+
+#endif // __NS_SMILCOMPOSITOR_H__
+
Index: content/smil/src/nsSMILEnum.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILEnum.cpp
diff -N content/smil/src/nsSMILEnum.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILEnum.cpp	5 Nov 2005 04:39:12 -0000
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SVG project.
+ *
+ * The Initial Developer of the Original Code is
+ * IBM Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Tim Rowley <tor@cs.brown.edu> (original author)
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSMILEnum.h"
+#include "nsSMILAtoms.h"
+#include "nsString.h"
+#include "nsCRT.h"
+
+//----------------------------------------------------------------------
+// Implementation
+
+nsSMILEnum::nsSMILEnum(PRUint16 value,
+                       nsSMILEnumMapping *mapping)
+    : mValue(value), mMapping(mapping)
+{
+  nsSMILAtoms::AddRefAtoms();
+}
+
+nsresult
+nsSMILEnum::SetStringValue(const nsAString& aValue)
+{
+  // 
+  // According to XML 1.0, section 3.3.3 we need to discard leading and trailing
+  // whitespace for this attribute. Currently nsSVGEnum doesn't do this
+  // otherwise we might try and re-use some of that functionality here
+  //
+  nsAString::const_iterator start;
+  nsAString::const_iterator end;
+
+  aValue.BeginReading(start);
+  aValue.EndReading(end);
+
+  while (*start && NS_IS_SPACE(*start))
+    ++start;
+
+  do --end; while (start != end && NS_IS_SPACE(*end));
+    ++end;
+
+  nsCOMPtr<nsIAtom> valAtom = do_GetAtom(Substring(start, end));
+
+  nsSMILEnumMapping *tmp = mMapping;
+
+  if (!tmp)
+    return NS_ERROR_FAILURE;
+
+  while (tmp->key) {
+    if (valAtom == *(tmp->key)) {
+      mValue = tmp->val;
+      return NS_OK;
+    }
+    tmp++;
+  }
+
+  NS_WARNING("Unknown enumeration key");
+  return NS_ERROR_FAILURE;
+}
+
Index: content/smil/src/nsSMILEnum.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILEnum.h
diff -N content/smil/src/nsSMILEnum.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILEnum.h	5 Nov 2005 04:39:13 -0000
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SVG project.
+ *
+ * The Initial Developer of the Original Code is
+ * IBM Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Tim Rowley <tor@cs.brown.edu> (original author)
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_SMILENUM_H__
+#define __NS_SMILENUM_H__
+
+#include "nsIAtom.h"
+
+struct nsSMILEnumMapping 
+{
+    nsIAtom **key;
+    PRUint16 val;
+};
+
+////////////////////////////////////////////////////////////////////////
+// nsSMILEnum class
+
+class nsSMILEnum
+{
+public:
+  nsSMILEnum(PRUint16 value, nsSMILEnumMapping *mapping);
+
+  PRUint16  GetIntegerValue() const { return mValue; }
+  void      SetIntegerValue(const PRUint16 &aValue) { mValue = aValue; }
+  nsresult  SetStringValue(const nsAString &aValue);
+
+protected:
+  PRUint16          mValue;
+  nsSMILEnumMapping *mMapping;
+};
+
+#endif //__NS_SMILENUM_H__
+
Index: content/smil/src/nsSMILInstanceTime.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILInstanceTime.cpp
diff -N content/smil/src/nsSMILInstanceTime.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILInstanceTime.cpp	5 Nov 2005 04:39:13 -0000
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSMILInstanceTime.h"
+#include "nsSMILTimeValueSpec.h"
+#include "nsSMILTimeValue.h"
+
+//----------------------------------------------------------------------
+// Implementation
+
+nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue &aTime,
+                                       nsSMILTimeValueSpec *aCreator,
+                                       PRBool aClearOnReset /*=false*/)
+  : mTime(aTime), // Copy the time
+    mClearOnReset(aClearOnReset)
+{
+  if (aCreator)
+    mCreator = do_GetWeakReference(aCreator);
+}
+
+NS_IMPL_ISUPPORTS1(nsSMILInstanceTime,
+                   nsSMILInstanceTime)
+
+//----------------------------------------------------------------------
+// nsSMILInstanceTime
+
+PR_CALLBACK int
+nsSMILInstanceTime::ComparisonCallback(nsSMILInstanceTime* aElement1,
+                                       nsSMILInstanceTime* aElement2,
+                                       void* /*aData*/)      
+{
+  return aElement1->Time().CompareTo(aElement2->Time());
+}
+
Index: content/smil/src/nsSMILInstanceTime.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILInstanceTime.h
diff -N content/smil/src/nsSMILInstanceTime.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILInstanceTime.h	5 Nov 2005 04:39:13 -0000
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_SMILINSTANCETIME_H__
+#define __NS_SMILINSTANCETIME_H__
+
+#include "nsISupports.h"
+#include "nsSMILTimeValue.h"
+#include "nsWeakReference.h"
+
+class nsSMILTimeValueSpec;
+
+////////////////////////////////////////////////////////////////////////
+// nsSMILInstanceTime : An instant in document simple time that may be
+//                      used in creating a new interval
+
+// {8d5be43a-f4ce-445b-9c85-181eb6f8e34c}
+#define NS_SMILINSTANCETIME_IID \
+{ 0x8d5be43a, 0xf4ce, 0x445b, { 0x9c, 0x85, 0x18, 0x1e, 0xb6, 0xf8, 0xe3, 0x4c } }
+
+class nsSMILInstanceTime : public nsISupports
+{
+public:
+  nsSMILInstanceTime(const nsSMILTimeValue &aTime,
+                     nsSMILTimeValueSpec *aCreator,
+                     PRBool aClearOnReset = PR_FALSE);
+
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_SMILINSTANCETIME_IID)
+  NS_DECL_ISUPPORTS
+
+  const nsSMILTimeValue&  Time() const { return mTime; }
+
+  PRBool                  ClearOnReset() const { return mClearOnReset; }
+
+  // void DependentUpdate(const nsSMILTimeValue& aNewTime); -- NOT YET IMPL.
+
+  PR_STATIC_CALLBACK(int) ComparisonCallback(nsSMILInstanceTime* aElement1,
+                                             nsSMILInstanceTime* aElement2,
+                                             void* aData);
+  
+protected:
+  nsSMILTimeValue     mTime;
+
+  /**
+   * The nsSMILTimeValueSpec that created this instance time if any. This will
+   * be NULL for instance times that created via DOM calls etc.
+   */
+  nsWeakPtr           mCreator;
+
+  /**
+   * Indicates if this instance time should be removed when the owning timed
+   * element is reset. True for events and DOM calls.
+   */
+  PRBool              mClearOnReset;
+
+  /*
+   * This will only be used for for identifying the instance times associated
+   * with a deleting interval. We will never de-reference this pointer, but only
+   * use it for pointer comparisons. Therefore it's not necessary for instances
+   * of nsSMILInterval to be reference-counted.
+   */
+  // nsSMILInterval   *mTimebase -- NOT YET IMPLEMENTED
+
+private:
+  // Pass by value and assignment should not be used
+  nsSMILInstanceTime(const nsSMILInstanceTime& other);
+  nsSMILInstanceTime& operator=(const nsSMILInstanceTime& right);
+};
+
+#endif // __NS_SMILINSTANCETIME_H__
+
Index: content/smil/src/nsSMILInterval.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILInterval.cpp
diff -N content/smil/src/nsSMILInterval.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILInterval.cpp	5 Nov 2005 04:39:13 -0000
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSMILInterval.h"
+#include "nsSMILInstanceTime.h"
+#include "nsVoidArray.h"
+#include "nsCRT.h"
+
+// Creates a new interval with unresolved begin and end times
+nsSMILInterval::nsSMILInterval()
+: mBegin(),
+  mEnd()
+{
+}
+
+nsSMILInterval::nsSMILInterval(const nsSMILTimeValue& aBegin,
+                               const nsSMILTimeValue& aEnd)
+: mBegin(aBegin),
+  mEnd(aEnd)
+{
+}
+
+//----------------------------------------------------------------------
+// Implementation
+
+NS_IMPL_ISUPPORTS1(nsSMILInterval,
+                   nsSMILInterval)
+
+void
+nsSMILInterval::UpdateBegin(const nsSMILTimeValue &aNewTime)
+{
+  mBegin = aNewTime;
+  // XXX notify dependents
+}
+
+void
+nsSMILInterval::UpdateEnd(const nsSMILTimeValue &aNewTime)
+{
+  mEnd = aNewTime;
+  // XXX notify dependents
+}
+
Index: content/smil/src/nsSMILInterval.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILInterval.h
diff -N content/smil/src/nsSMILInterval.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILInterval.h	5 Nov 2005 04:39:14 -0000
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_SMILINTERVAL_H__
+#define __NS_SMILINTERVAL_H__
+
+#include "nsISupports.h"
+#include "nsSMILTimeValue.h"
+
+class nsVoidArray;
+class nsSMILInstanceTime;
+
+////////////////////////////////////////////////////////////////////////
+// nsSMILInterval class
+
+// {443cdd3f-1d0c-4eb9-b043-5cde9e4ca35b}
+#define NS_SMILINTERVAL_IID \
+{ 0x443cdd3f, 0x1d0c, 0x4eb9, { 0xb0, 0x43, 0x5c, 0xde, 0x9e, 0x4c, 0xa3, 0x5b } }
+
+class nsSMILInterval : public nsISupports
+{
+public:
+  nsSMILInterval();
+  nsSMILInterval(const nsSMILTimeValue &aBegin,
+                 const nsSMILTimeValue &aEnd);
+
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_SMILINTERVAL_IID)
+  NS_DECL_ISUPPORTS
+
+  const nsSMILTimeValue& Begin() { return mBegin; }
+  const nsSMILTimeValue& End() { return mEnd; }
+
+  void UpdateBegin(const nsSMILTimeValue &aNewTime);
+  void UpdateEnd(const nsSMILTimeValue &aNewTime);
+
+  // We will need to track dependent instance times from here
+  //
+  // e.g.
+  // 
+  // void  AddDependent(nsSMILInstanceTime& aDependent, PRBool aForBegin);
+  // void  RemoveDependent(nsSMILInstanceTime& aDependent, PRBool aForBegin);
+
+protected:
+  nsSMILTimeValue   mBegin;
+  nsSMILTimeValue   mEnd;
+};
+
+#endif // __NS_SMILINTERVAL_H__
+
Index: content/smil/src/nsSMILKeySpline.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILKeySpline.cpp
diff -N content/smil/src/nsSMILKeySpline.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILKeySpline.cpp	5 Nov 2005 04:39:14 -0000
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSMILKeySpline.h"
+#include <math.h>
+
+#define NEWTON_ITERATIONS   4
+
+const PRFloat64 nsSMILKeySpline::kSampleStepSize = 
+                                        1.0 / (PRFloat64)(kSplineTableSize - 1);
+
+nsSMILKeySpline::nsSMILKeySpline(const PRFloat64& aX1,
+                                 const PRFloat64& aY1,
+                                 const PRFloat64& aX2,
+                                 const PRFloat64& aY2)
+: mX1(aX1),
+  mY1(aY1),
+  mX2(aX2),
+  mY2(aY2)
+{
+  if (mX1 != mY1 || mX2 != mY2)
+    CalcSampleValues();
+}
+
+PRFloat64
+nsSMILKeySpline::GetSplineValue(const PRFloat64& x)
+{
+  if (mX1 == mY1 && mX2 == mY2)
+    return x;
+
+  return CalcBezier(GetTForX(x), mY1, mY2);
+}
+
+void
+nsSMILKeySpline::CalcSampleValues()
+{
+  for (int i = 0; i < kSplineTableSize; ++i)
+    mSampleValues[i] = CalcBezier((PRFloat64)i * kSampleStepSize, mX1, mX2);
+}
+
+PRFloat64
+nsSMILKeySpline::CalcBezier(const PRFloat64& t,
+                            const PRFloat64& a1,
+                            const PRFloat64& a2)
+{
+  return A(a1, a2) * pow(t,3) + B(a1, a2)*t*t + C(a1) * t;
+}
+
+PRFloat64
+nsSMILKeySpline::GetSlope(const PRFloat64& t,
+                             const PRFloat64& a1,
+                             const PRFloat64& a2)
+{
+  PRFloat64 denom = (3.0 * A(a1, a2)*t*t + 2.0 * B(a1, a2) * t + C(a1)); 
+  return (denom == 0.0) ? 0.0 : 1.0 / denom;
+}
+
+PRFloat64
+nsSMILKeySpline::GetTForX(const PRFloat64& x)
+{
+  int i;
+
+  // Get an initial guess.
+  //
+  // Note: This is better than just taking x as our initial guess as cases such
+  // as where the control points are (1, 1), (0, 0) will take some 20 iterations
+  // to converge to a good accuracy. By taking an initial guess in this way we
+  // only need 3~4 iterations depending on the size of the table.
+  for (i = 0; i < kSplineTableSize - 2 && mSampleValues[i] < x; ++i);
+  PRFloat64 currentT = 
+    (PRFloat64)i * kSampleStepSize + (x - mSampleValues[i]) * kSampleStepSize;
+
+  // Refine with Newton-Raphson iteration
+  for(i = 0; i < NEWTON_ITERATIONS; ++i)
+  {
+    PRFloat64 currentX = CalcBezier(currentT, mX1, mX2);
+    PRFloat64 currentSlope = GetSlope(currentT, mX1, mX2);
+
+    if (currentSlope == 0.0)
+      return currentT;
+
+    currentT -= (currentX - x) * currentSlope;
+  }
+
+  return currentT;
+}
+
Index: content/smil/src/nsSMILKeySpline.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILKeySpline.h
diff -N content/smil/src/nsSMILKeySpline.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILKeySpline.h	5 Nov 2005 04:39:14 -0000
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_SMILKEYSPLINE_H__
+#define __NS_SMILKEYSPLINE_H__
+
+#include "prtypes.h"
+
+/**
+ * Utility class to provide scaling defined in a keySplines element.
+ */
+class nsSMILKeySpline
+{
+public:
+  nsSMILKeySpline(const PRFloat64& aX1, const PRFloat64& aY1,
+                  const PRFloat64& aX2, const PRFloat64& aY2);
+
+  PRFloat64 GetSplineValue(const PRFloat64& x);
+
+private:
+  void
+  CalcSampleValues();
+
+  PRFloat64
+  CalcBezier(const PRFloat64& t, const PRFloat64& a1, const PRFloat64& a2);
+
+  PRFloat64
+  GetSlope(const PRFloat64& t, const PRFloat64& a1, const PRFloat64& a2);
+
+  PRFloat64
+  GetTForX(const PRFloat64& x);
+
+  PRFloat64
+  A(const PRFloat64& a1, const PRFloat64& a2)
+  {
+    return 1.0 - 3.0 * a2 + 3.0 * a1;
+  }
+  
+  PRFloat64
+  B(const PRFloat64& a1, const PRFloat64& a2)
+  {
+    return 3.0 * a2 - 6.0 * a1;
+  }
+
+  PRFloat64
+  C(const PRFloat64& a1)
+  {
+    return 3.0 * a1;
+  }
+
+  const PRFloat64         mX1;
+  const PRFloat64         mY1;
+  const PRFloat64         mX2;
+  const PRFloat64         mY2;
+
+  enum { kSplineTableSize = 11 };
+  PRFloat64               mSampleValues[kSplineTableSize];
+
+  static const PRFloat64  kSampleStepSize;
+};
+
+#endif // __NS_SMILKEYSPLINE_H__
+
Index: content/smil/src/nsSMILParserUtils.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILParserUtils.cpp
diff -N content/smil/src/nsSMILParserUtils.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILParserUtils.cpp	5 Nov 2005 04:39:15 -0000
@@ -0,0 +1,530 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSMILParserUtils.h"
+#include "nsISMILAnimAttr.h"
+#include "nsISMILAnimVal.h"
+#include "nsSMILTimeValue.h"
+#include "nsString.h"
+#include "nsVoidArray.h"
+#include "prdtoa.h"
+#include "nsCRT.h"
+#include "nsCOMPtr.h"
+#include "prlong.h"
+
+const PRUint32 nsSMILParserUtils::MSEC_PER_SEC   = 1000;
+const PRUint32 nsSMILParserUtils::MSEC_PER_MIN   = 1000 * 60;
+const PRUint32 nsSMILParserUtils::MSEC_PER_HOUR  = 1000 * 60 * 60;
+
+nsresult
+nsSMILParserUtils::GetKeySplines(const nsAString& aSpec,
+                                 nsVoidArray &aSplineArray)
+{
+  nsresult  rv            = NS_OK;
+  char*     str           = ToNewCString(aSpec);
+  char*     number        = str;
+  int       i             = 0;
+
+  SkipWsp(number);
+
+  do {
+    char      *rest;
+    PRFloat64 value = PR_strtod(number, &rest);
+
+    if (rest == number) {
+      rv = NS_ERROR_FAILURE;
+      break;
+    }
+
+    if (value > 1.0 || value < 0.0) {
+      rv = NS_ERROR_FAILURE;
+      break;
+    }
+
+    aSplineArray.AppendElement(new PRFloat64(value));
+    number = rest;
+
+    SkipWsp(number);
+    ++i;
+
+    if (i % 4 && *number == ',') {
+      ++number;
+      SkipWsp(number);
+    }
+
+    if (i % 4 && *number && number == rest) {
+      rv = NS_ERROR_FAILURE; // no separator
+      break;
+    }
+  } while (*number && (i % 4 || NS_SUCCEEDED(rv = !(*number++ == ';'))));
+
+  if (*number)
+    rv = NS_ERROR_FAILURE; // Trailing junk
+
+  if (i % 4)
+    rv = NS_ERROR_FAILURE; // wrong number of points
+
+  nsMemory::Free(str);
+
+  return rv;
+}
+
+nsresult
+nsSMILParserUtils::GetKeyTimes(const nsAString& aSpec,
+                               nsVoidArray &aTimeArray)
+{
+  nsresult  rv            = NS_OK;
+  char*     str           = ToNewCString(aSpec);
+  char*     number        = str;
+  PRFloat64 previousValue = -1.0;
+
+  SkipWsp(number);
+
+  do {
+    char      *rest;
+    PRFloat64 value = PR_strtod(number, &rest);
+
+    if (rest == number)
+      break;
+
+    if (value > 1.0 || value < 0.0) {
+      rv = NS_ERROR_FAILURE;
+      break;
+    } else if (value < previousValue) {
+      rv = NS_ERROR_FAILURE;
+      break;
+    }
+    aTimeArray.AppendElement(new PRFloat64(value));
+    number = rest;
+    previousValue = value;
+
+    SkipWsp(number);
+  } while (*number && *number++ == ';');
+  // This terminating condition means we won't mark the document in error for
+  // lists that end in a semi-colon but it's probably ok to be lenient in this
+  // case
+
+  if (*number)
+    rv = NS_ERROR_FAILURE; // Trailing junk
+
+  nsMemory::Free(str);
+
+  return rv;
+}
+
+nsresult
+nsSMILParserUtils::GetValues(const nsAString& aSpec,
+                             nsCOMArray<nsISMILAnimVal>& aValuesArray,
+                             nsISMILAnimAttr* aAttribute)
+{
+  NS_ENSURE_TRUE(aAttribute, NS_ERROR_FAILURE);
+
+  nsresult rv = NS_ERROR_FAILURE;
+  nsAString::const_iterator start;
+  nsAString::const_iterator end;
+  nsAString::const_iterator substr_end;
+  nsAString::const_iterator next;
+
+  aSpec.BeginReading(start);
+  aSpec.EndReading(end);
+
+  while (start != end) {
+    rv = NS_ERROR_FAILURE;
+
+    while (*start && NS_IS_SPACE(*start))
+      ++start;
+
+    if (*start == '\0' || *start == ';')
+      break;
+
+    substr_end = start;
+
+    while (substr_end != end && *substr_end != ';')
+      ++substr_end;
+
+    next = substr_end;
+    if (*substr_end == ';') {
+      ++next;
+      if (next == end)
+        break;
+    }
+
+    do --substr_end; while (start != substr_end && NS_IS_SPACE(*substr_end));
+      ++substr_end;
+
+    nsCOMPtr<nsISMILAnimVal> newValue ( 
+      aAttribute->CreateFromSpec(Substring(start, substr_end)));
+
+    if (!newValue)
+      break;
+
+    aValuesArray.AppendObject(newValue);
+
+    rv = NS_OK;
+    start = next;
+  }
+
+  return rv;
+}
+
+nsresult
+nsSMILParserUtils::GetRepeatCount(const nsAString& aSpec,
+                                  nsSMILTimeValue& aResult)
+{
+  nsresult rv      = NS_OK;
+  char*    str     = ToNewCString(aSpec);
+  char*    number  = str;
+
+  aResult.SetUnresolved();
+
+  SkipWsp(number);
+
+  if (*number) {
+    if (PL_strstr(number, "indefinite") == number) {
+      aResult.SetIndefinite();
+      number += PL_strlen("indefinite");
+    } else {
+      char      *rest;
+      PRFloat64 value = PR_strtod(number, &rest);
+
+      if (rest != number) {
+        PRInt64 count;
+        value *= 1000;
+
+        LL_D2L(count, value);
+
+        aResult.SetMillis(count);
+
+        if (!LL_GE_ZERO(count) || LL_IS_ZERO(count))
+          rv = NS_ERROR_FAILURE;
+
+        number = rest;
+      } else {
+        rv = NS_ERROR_FAILURE;
+      }
+    }
+
+    SkipWsp(number);
+
+    if (*number)
+      rv = NS_ERROR_FAILURE;
+  } else {
+    /* Empty spec */
+    rv = NS_ERROR_FAILURE;
+  }
+
+  nsMemory::Free(str);
+
+  if (NS_FAILED(rv))
+    aResult.SetUnresolved();
+
+  return rv;
+}
+
+//
+// This method can actually parse more than a clock value as defined in the
+// SMIL Animation specification. It can also parse:
+//  - the + or - before an offset
+//  - the special value "indefinite"
+//  - the special value "media"
+//
+// Because the value "media" cannot be represented as part of an nsSMILTimeValue
+// and has different meanings depending on where it is used, it is passed out as
+// a separate parameter (which can be set to null if the media attribute is not
+// allowed).
+//
+// aResult may be NULL, e.g. to check if the string is a valid clock value
+//
+nsresult
+nsSMILParserUtils::GetClockValue(const nsAString& aStringSpec,
+                                 nsSMILTimeValue* aResult, 
+                                 PRBool aAllowSign,       // = false
+                                 PRBool aAllowIndefinite, // = false
+                                 PRBool aAllowMedia,      // = false
+                                 PRBool* aIsMedia)        // = nsnull
+{
+  PRInt64 offset = LL_Zero();
+  PRFloat64 component = 0.0;
+
+  PRInt8 sign = 0;
+  PRUint8 colonCount = 0;
+
+  PRBool started = PR_FALSE;
+  PRBool isValid = PR_TRUE;
+
+  PRInt32 metricMultiplicand = MSEC_PER_SEC;
+
+  PRBool numIsReal = PR_FALSE;
+  PRBool prevNumCouldBeMin = PR_FALSE;
+  PRBool numCouldBeMin = PR_FALSE;
+  PRBool numCouldBeSec = PR_FALSE;
+  PRBool isIndefinite = PR_FALSE;
+
+  char* spec; 
+  char* str = spec = ToNewCString(aStringSpec);
+
+  if (aIsMedia)
+    *aIsMedia = PR_FALSE;
+
+  while (*str) {
+    if (IsSpace(*str)) {
+      if (started) {
+        ++str;
+        break;
+      }
+      // else, we haven't started yet, ignore initial whitespace
+    } else if (aAllowSign && (*str == '+' || *str == '-')) {
+      if (sign != 0) {
+        // sign has already been set
+        isValid = PR_FALSE;
+        break;
+      }
+
+      if (started) {
+        // sign appears in the middle of the string
+        isValid = PR_FALSE;
+        break;
+      }
+
+      sign = (*str == '+') ? 1 : -1;
+    // The NS_IS_DIGIT etc. macros are not locale-specific
+    } else if (NS_IS_DIGIT(*str)) {
+      char *end;
+
+      prevNumCouldBeMin = numCouldBeMin;
+
+      if (!GetClockComponent(str, &end, component, numIsReal, numCouldBeMin,
+                             numCouldBeSec)) {
+        isValid = PR_FALSE;
+        break;
+      }
+
+      started = PR_TRUE;
+      str = end - 1;
+    } else if (*str == ':') {
+      ++colonCount;
+
+      // Neither minutes nor hours can be reals
+      if (numIsReal) {
+        isValid = PR_FALSE;
+        break;
+      }
+
+      // Clock value can't start with a ':'
+      if (!started) {
+        isValid = PR_FALSE;
+        break;
+      }
+
+      // Can't have more than two colons
+      if (colonCount > 2) {
+        isValid = PR_FALSE;
+        break;
+      }
+
+      // Multiply the offset by 60 and add the last accumulated component
+      PRInt64 component64;
+      LL_D2L(component64, component);
+      LL_MUL(offset, offset, LL_INIT(0,60));
+      LL_ADD(offset, offset, component64);
+
+      component = 0.0l;
+    } else if (NS_IS_ALPHA(*str)) {
+      if (colonCount > 0) {
+        isValid = PR_FALSE;
+        break;
+      }
+
+      char* end;
+      if (PL_strstr(str, "indefinite") == str && aAllowIndefinite) {
+        // We set a separate flag because we don't know what the state of the
+        // passed in time value is and we shouldn't change it in the case of a
+        // bad input string (so we can't initialise it to 0ms for example).
+        isIndefinite = PR_TRUE;
+        if (aResult)
+          aResult->SetIndefinite();
+        end = str + PL_strlen("indefinite");
+      } else if (PL_strstr(str, "media") == str && aAllowMedia) {
+        if (aIsMedia)
+          *aIsMedia = PR_TRUE;
+        end = str + PL_strlen("media");
+      } else if (!GetMetricMultiplicand(str, &end, metricMultiplicand)) {
+        isValid = PR_FALSE;
+        break;
+      }
+
+      str = end;
+
+      // Nothing must come after the string except whitespace
+      break;
+    } else {
+      isValid = PR_FALSE;
+      break;
+    }
+
+    ++str;
+  }
+
+  if (!started) isValid = PR_FALSE;
+
+  // Process remainder of string (if any) to ensure it is only trailing
+  // whitespace (embedded whitespace is not allowed)
+  while (*str && isValid) {
+    if (!IsSpace(*str)) isValid = PR_FALSE;
+    ++str;
+  }
+
+  nsMemory::Free(spec);
+
+  // No more processing required if the value was "indefinite" or "media".
+  if (isIndefinite || (aIsMedia && *aIsMedia))
+    return NS_OK;
+
+  // If there is more than one colon then the previous component must be a
+  // correctly formatted minute (i.e. two digits between 00 and 59) and the
+  // latest component must be a correctly formatted second (i.e. two digits
+  // before the .)
+  if (colonCount > 0 && (!prevNumCouldBeMin || !numCouldBeSec))
+    isValid = PR_FALSE;
+
+  if (isValid) {
+    // Tack on the last component
+    if (colonCount > 0) {
+      LL_MUL(offset, offset, LL_INIT(0,60));
+      LL_MUL(offset, offset, LL_INIT(0,1000));
+      component *= 1000;
+      // rounding
+      component = (component >= 0) ? component + 0.5l : component - 0.5l;
+      PRInt64 component64;
+      LL_D2L(component64, component);
+      LL_ADD(offset, offset, component64);
+    } else {
+      component *= metricMultiplicand;
+      // rounding
+      component = (component >= 0) ? component + 0.5l : component - 0.5l;
+      LL_D2L(offset, component);
+    }
+
+    if (aResult) {
+      PRInt64 millis = offset;
+
+      if (sign == -1)
+        LL_NEG(millis, offset);
+
+      aResult->SetMillis(millis);
+    }
+  }
+
+  return (isValid) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+PRBool
+nsSMILParserUtils::GetClockComponent(const char* aSrc,
+                                     char** aEnd,
+                                     PRFloat64& aResult,
+                                     PRBool& aIsReal,
+                                     PRBool& aCouldBeMin,
+                                     PRBool& aCouldBeSec)
+{
+  char *rest;
+  PRFloat64 value = PR_strtod(aSrc, &rest);
+
+  // Check a number was found
+  if (rest == aSrc)
+    return PR_FALSE;
+
+  // Check it's not expressed in exponential form
+  PRBool isExp = (PL_strnpbrk(aSrc, "eE", rest - aSrc) != nsnull);
+  if (isExp)
+    return PR_FALSE;
+
+  // Don't allow real numbers of the form "23."
+  if (*(rest - 1) == '.')
+    return PR_FALSE;
+
+  // Number looks good
+  aResult = value;
+  *aEnd = rest;
+
+  // Set some flags so we can check this number is valid once we know
+  // whether it's an hour, minute string etc.
+  aIsReal = (PL_strnchr(aSrc, '.', rest - aSrc) != nsnull);
+  aCouldBeMin = (value < 60.0l && ((rest - aSrc) == 2));
+  aCouldBeSec = (value < 60.0l ||
+      (value == 60.0l && aSrc[0] == '5')); // Take care of rounding error
+  aCouldBeSec &= (PL_strlen(aSrc) >= 2 &&
+      (aSrc[2] == '\0' || aSrc[2] == '.' || IsSpace(aSrc[2])));
+
+  return PR_TRUE;
+}
+
+inline PRBool
+nsSMILParserUtils::GetMetricMultiplicand(char* aSrc,
+                                         char** aEnd,
+                                         PRInt32& multiplicand)
+{
+  nsresult result = PR_TRUE;
+  
+  switch (*aSrc)
+  {
+    case 'h':
+      *aEnd = aSrc + 1;
+      multiplicand = MSEC_PER_HOUR;
+      break;
+    case 'm':
+      if (aSrc[1] == 'i' && aSrc[2] == 'n') {
+        *aEnd = aSrc + 3;
+        multiplicand = MSEC_PER_MIN;
+      } else if (aSrc[1] == 's') {
+        *aEnd = aSrc + 2;
+        multiplicand = 1;
+      } else {
+        result = PR_FALSE;
+      }
+      break;
+    case 's':
+      *aEnd = aSrc + 1;
+      multiplicand = MSEC_PER_SEC;
+      break;
+    default:
+      result = PR_FALSE;
+      break;
+  }
+
+  return result;
+}
+
Index: content/smil/src/nsSMILParserUtils.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILParserUtils.h
diff -N content/smil/src/nsSMILParserUtils.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILParserUtils.h	5 Nov 2005 04:39:15 -0000
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_SMILPARSERUTILS_H__
+#define __NS_SMILPARSERUTILS_H__
+
+#include "nscore.h"
+#include "nsCOMArray.h"
+
+class nsAString;
+class nsVoidArray;
+class nsISMILAnimVal;
+class nsISMILAnimAttr;
+class nsSMILTimeValue;
+
+/**
+ * Common parsing utilities for the SMIL module. There is little re-use here, it
+ * simply serves to simplify other classes by moving parsing outside and aid
+ * unit testing.
+ */
+class nsSMILParserUtils
+{
+public:
+  static nsresult   GetKeySplines(const nsAString& aSpec,
+                                  nsVoidArray &aSplineArray);
+
+  static nsresult   GetKeyTimes(const nsAString& aSpec,
+                                nsVoidArray &aTimesArray);
+
+  static nsresult   GetValues(const nsAString& aSpec,
+                              nsCOMArray<nsISMILAnimVal>& aValuesArray,
+                              nsISMILAnimAttr* aAttribute);
+
+  static nsresult   GetRepeatCount(const nsAString& aSpec,
+                                   nsSMILTimeValue& aResult);
+
+  static nsresult   GetClockValue(const nsAString& aStringSpec,
+                                  nsSMILTimeValue* aResult, 
+                                  PRBool aAllowSign = false,
+                                  PRBool aAllowIndefinite = false,
+                                  PRBool aAllowMedia = false,
+                                  PRBool* aIsMedia = nsnull);
+
+
+private:
+  static void   SkipWsp(char*& aStr);
+  static PRBool IsSpace(const char c);
+  static PRBool GetClockComponent(const char* aSrc,
+                                  char** aEnd,
+                                  PRFloat64& aResult,
+                                  PRBool& aIsReal,
+                                  PRBool& aCouldBeMin,
+                                  PRBool& aCouldBeSec);
+
+  static PRBool GetMetricMultiplicand(char* aSrc,
+                                      char** aEnd,
+                                      PRInt32& multiplicand);
+
+  static const PRUint32 MSEC_PER_SEC;
+  static const PRUint32 MSEC_PER_MIN;
+  static const PRUint32 MSEC_PER_HOUR;
+
+};
+
+// NS_IS_SPACE relies on isspace which may return true for \xB and \xC but
+// SMILANIM does not consider these characters to be whitespace.
+inline PRBool
+nsSMILParserUtils::IsSpace(const char c)
+{
+  return (c == 0x9 || c == 0xA || c == 0xD || c == 0x20);
+}
+
+inline void
+nsSMILParserUtils::SkipWsp(char*& aStr)
+{
+  while (*aStr && IsSpace(*aStr))
+    ++aStr;
+}
+
+#endif // __NS_SMILPARSERUTILS_H__
+
Index: content/smil/src/nsSMILTimeValue.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILTimeValue.cpp
diff -N content/smil/src/nsSMILTimeValue.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILTimeValue.cpp	5 Nov 2005 04:39:16 -0000
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSMILTimeValue.h"
+#include "nsDebug.h"
+
+PRInt64 nsSMILTimeValue::mUnresolvedSeconds = LL_MaxInt();
+
+//----------------------------------------------------------------------
+// Implementation
+
+// Default constructor creates an unresolved time
+nsSMILTimeValue::nsSMILTimeValue()
+  : mMilliseconds(LL_MaxInt()),
+    mIndefinite(PR_FALSE),
+    mResolved(PR_FALSE)
+{
+}
+
+//----------------------------------------------------------------------
+// nsSMILTimeValue methods:
+
+void
+nsSMILTimeValue::SetIndefinite()
+{
+  mResolved = PR_FALSE;
+  mIndefinite = PR_TRUE;
+  mMilliseconds = LL_MaxInt();
+}
+
+void
+nsSMILTimeValue::SetUnresolved()
+{
+  mResolved = PR_FALSE;
+  mIndefinite = PR_FALSE;
+  mMilliseconds = LL_MaxInt();
+}
+
+const PRInt64&
+nsSMILTimeValue::GetMillis() const
+{
+  NS_ASSERTION(mResolved, "GetMillis() called for unresolved time.");
+
+  if (!mResolved)
+      return mUnresolvedSeconds;
+
+  return mMilliseconds;
+}
+
+void
+nsSMILTimeValue::SetMillis(const PRInt64& aMillis)
+{
+  mResolved = PR_TRUE;
+  mIndefinite = PR_FALSE;
+  mMilliseconds = aMillis;
+}
+
+PRInt8
+nsSMILTimeValue::CompareTo(const nsSMILTimeValue& aCompare) const
+{
+  PRInt8 result;
+
+  if (mResolved) {
+    result = (aCompare.mResolved)
+           ? CmpLL(mMilliseconds, aCompare.mMilliseconds)
+           : -1;
+  } else if (mIndefinite) {
+    if (aCompare.mResolved)
+      result = 1;
+    else if (aCompare.mIndefinite)
+      result = 0;
+    else
+      result = -1;
+  } else {
+    result = (aCompare.mResolved || aCompare.mIndefinite) ? 1 : 0;
+  }
+
+  return result;
+}
+
Index: content/smil/src/nsSMILTimeValue.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILTimeValue.h
diff -N content/smil/src/nsSMILTimeValue.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILTimeValue.h	5 Nov 2005 04:39:16 -0000
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_SMILTIMEVALUE_H__
+#define __NS_SMILTIMEVALUE_H__
+
+#include "prtypes.h"
+#include "prlong.h"
+
+/**
+ * nsSMILTimeValue class
+ *
+ * Objects of this class may be in one of three orthogonal states:
+ *
+ * 1) The time is resolved and has a millisecond value
+ * 2) The time is indefinite
+ * 3) The time in unresolved
+ *
+ * There is considerable chance for confusion with regards to the indefinite
+ * state. Is it resolved? We adopt the convention that it is NOT resolved (but
+ * nor is it unresolved). This simplifies implementation as you can then write:
+ *
+ * if (time.IsResolved())
+ *    x = time.GetMillis()
+ *
+ * instead of:
+ *
+ * if (time.IsResolved() && !time.IsIndefinite())
+ *    x = time.GetMillis()
+ *
+ * Testing if a time is unresolved becomes more complicated but this is tested
+ * much less often.
+ *
+ * In summary:
+ *
+ * State         |  GetMillis         |  IsResolved        |  IsIndefinite
+ * --------------+--------------------+--------------------+-------------------
+ * Resolved      |  The millisecond   |  PR_TRUE           |  PR_FALSE
+ *               |  time              |                    |
+ * --------------+--------------------+--------------------+-------------------
+ * Indefinite    |  LL_MaxInt         |  PR_FALSE          |  PR_TRUE
+ * --------------+--------------------+--------------------+-------------------
+ * Unresolved    |  LL_MaxInt         |  PR_FALSE          |  PR_FALSE
+ *
+ */
+
+class nsSMILTimeValue
+{
+public:
+  // Creates an unresolved time value
+  nsSMILTimeValue();
+
+  PRBool            IsIndefinite() const;
+  void              SetIndefinite();
+
+  PRBool            IsResolved() const;
+  void              SetUnresolved();
+
+  const PRInt64&    GetMillis() const;
+  void              SetMillis(const PRInt64& aMillis);
+
+  PRInt8            CompareTo(const nsSMILTimeValue& aCompare) const;
+
+private:
+  PRInt8            CmpLL(const PRInt64& a, const PRInt64& b) const;
+
+  static PRInt64    mUnresolvedSeconds;
+
+  PRInt64           mMilliseconds;
+  PRBool            mIndefinite;
+  PRBool            mResolved;
+};
+
+inline PRBool
+nsSMILTimeValue::IsIndefinite() const
+{
+  return mIndefinite;
+}
+
+inline PRBool
+nsSMILTimeValue::IsResolved() const
+{
+  return mResolved;
+}
+
+// A signed comparison of two signed 64-bit integers
+inline PRInt8
+nsSMILTimeValue::CmpLL(const PRInt64& a, const PRInt64& b) const
+{
+  return (LL_EQ(a, b)) ? 0 : (LL_CMP(a, >, b)) ? 1 : -1;
+}
+
+#endif // __NS_SMILTIMEVALUE_H__
+
Index: content/smil/src/nsSMILTimeValueSpec.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILTimeValueSpec.cpp
diff -N content/smil/src/nsSMILTimeValueSpec.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILTimeValueSpec.cpp	5 Nov 2005 04:39:16 -0000
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSMILTimeValueSpec.h"
+#include "nsSMILTimeValue.h"
+#include "nsSMILInstanceTime.h"
+#include "nsSMILParserUtils.h"
+#include "nsString.h"
+#include "nsAutoPtr.h"
+
+//----------------------------------------------------------------------
+// Implementation
+
+already_AddRefed<nsSMILTimeValueSpec>
+NS_NewSMILTimeValueSpec(nsISMILTimedElement* aOwner,
+                        PRBool aIsBegin,
+                        const nsAString& aStringSpec)
+{
+  nsSMILTimeValueSpec* result = new nsSMILTimeValueSpec(aOwner, aIsBegin);
+  NS_ENSURE_TRUE(result, nsnull);
+
+  NS_ADDREF(result); // Need to addref as SetSpec calls getWeakReference
+  nsresult rv = result->SetSpec(aStringSpec);
+  if (NS_FAILED(rv)) {
+    NS_RELEASE(result);
+    return nsnull;
+  }
+  return result;
+}
+
+nsSMILTimeValueSpec::nsSMILTimeValueSpec(nsISMILTimedElement* aOwner,
+                                         PRBool aIsBegin)
+  : mIsBegin(aIsBegin),
+    mOffset() // initalises to zero
+{
+  if (aOwner)
+    mOwner = do_GetWeakReference(aOwner);
+}
+
+//----------------------------------------------------------------------
+// nsISupports
+
+NS_IMPL_ISUPPORTS2(nsSMILTimeValueSpec,
+                   nsSMILTimeValueSpec,
+                   nsISupportsWeakReference)
+
+//----------------------------------------------------------------------
+// nsSMILTimeValueSpec
+
+nsresult
+nsSMILTimeValueSpec::SetSpec(const nsAString& aStringSpec)
+{
+  // XXX Need to parse other specifiers, not just offset type
+  nsSMILTimeValue clockTime;
+  nsresult rv = 
+    nsSMILParserUtils::GetClockValue(aStringSpec,
+                                     &clockTime,
+                                     true,  // allow + or -
+                                     true); // allow 'indefinite'
+
+  if (NS_FAILED(rv) || (!clockTime.IsResolved() && !clockTime.IsIndefinite()))
+    return NS_ERROR_FAILURE;
+  
+  if (clockTime.IsResolved())
+    mOffset = clockTime.GetMillis();
+  
+  if (mOwner) {
+    nsRefPtr<nsSMILInstanceTime> instance = 
+      new nsSMILInstanceTime(clockTime, this);
+    NS_ENSURE_TRUE(instance, NS_ERROR_OUT_OF_MEMORY);
+
+    nsCOMPtr<nsISMILTimedElement> owner = do_QueryReferent(mOwner);
+    NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
+
+    owner->AddInstanceTime(instance, mIsBegin);
+  }
+
+  return rv;
+}
+
Index: content/smil/src/nsSMILTimeValueSpec.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILTimeValueSpec.h
diff -N content/smil/src/nsSMILTimeValueSpec.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILTimeValueSpec.h	5 Nov 2005 04:39:16 -0000
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_SMILTIMEVALUESPEC_H__
+#define __NS_SMILTIMEVALUESPEC_H__
+
+#include "nsISupports.h"
+#include "nsWeakReference.h"
+#include "nsISMILTimedElement.h"
+
+class nsAString;
+class nsSMILTimeValue;
+
+////////////////////////////////////////////////////////////////////////
+// nsSMILTimeValueSpec class
+
+// {39d2f376-6bda-42c0-8510-a93b24828a80}
+#define NS_SMILTIMEVALUESPEC_IID \
+{ 0x39d2f376, 0x6bda, 0x42c0, { 0x85, 0x10, 0xa9, 0x3b, 0x24, 0x82, 0x8a, 0x80 } }
+
+class nsSMILTimeValueSpec : public nsSupportsWeakReference
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_SMILTIMEVALUESPEC_IID)
+  NS_DECL_ISUPPORTS
+
+protected:
+  nsSMILTimeValueSpec(nsISMILTimedElement* aOwner, PRBool aIsBegin);
+
+  friend already_AddRefed<nsSMILTimeValueSpec>
+  NS_NewSMILTimeValueSpec(nsISMILTimedElement* aOwner,
+                          PRBool aIsBegin,
+                          const nsAString& aStringSpec);
+
+  nsresult      SetSpec(const nsAString& aStringSpec);
+
+  nsWeakPtr mOwner;
+  PRBool    mIsBegin;
+  PRInt64   mOffset;
+};
+
+////////////////////////////////////////////////////////////////////////
+// Factory methods
+
+already_AddRefed<nsSMILTimeValueSpec>
+NS_NewSMILTimeValueSpec(nsISMILTimedElement* aOwner,
+                        PRBool aIsBegin,
+                        const nsAString& aStringSpec);
+
+#endif // __NS_SMILTIMEVALUESPEC_H__
Index: content/smil/src/nsSMILTimedDocumentRoot.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILTimedDocumentRoot.cpp
diff -N content/smil/src/nsSMILTimedDocumentRoot.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILTimedDocumentRoot.cpp	5 Nov 2005 04:39:17 -0000
@@ -0,0 +1,287 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSMILTimedDocumentRoot.h"
+#include "nsSMILTimeValue.h"
+
+////////////////////////////////////////////////////////////////////////
+// nsSMILTimedDocumentRoot implementation
+
+nsSMILTimedDocumentRoot::nsSMILTimedDocumentRoot(
+    nsSMILAnimationRegistry* registry)
+:
+  mStartTime(),
+  mAccumulatedOffset(),
+  mAnimationRegistry(registry),
+  mParentPaused(PR_FALSE),
+  mContainerPaused(PR_FALSE)
+{
+  mAnimationLock = PR_NewLock();
+}
+
+nsSMILTimedDocumentRoot::~nsSMILTimedDocumentRoot()
+{
+  // Wait for the lock in case we're in the middle of animating
+  if (mAnimationLock) {
+    PR_Lock(mAnimationLock);
+    PR_Unlock(mAnimationLock);
+    PR_DestroyLock(mAnimationLock);
+  }
+}
+
+//----------------------------------------------------------------------
+// nsISupports methods:
+
+NS_IMPL_ISUPPORTS2(nsSMILTimedDocumentRoot,
+                   nsISMILTimeContainer,
+                   nsISupportsWeakReference);
+
+//----------------------------------------------------------------------
+// nsSMILTimedDocumentRoot methods
+
+PRInt64
+nsSMILTimedDocumentRoot::GetDocumentTime()
+{
+  if (LL_IS_ZERO(mStartTime))
+    return LL_Zero();
+
+  PRInt64 now;
+  LL_DIV(now, PR_Now(), PR_USEC_PER_MSEC);
+  
+  PRInt64 currentTime = (mParentPaused || mContainerPaused)
+                      ? mPauseStart
+                      : now;
+
+  PRInt64 timeSinceStart;
+  LL_SUB(timeSinceStart, currentTime, mStartTime);
+
+  PRInt64 adjustedTime;
+  LL_SUB(adjustedTime, timeSinceStart, mAccumulatedOffset);
+
+  return adjustedTime;
+}
+
+nsSMILTimeValue
+nsSMILTimedDocumentRoot::WallclockToDocumentTime(nsISMILTimeValueSpec*
+                                                   aWallclockSpec)
+{
+  // XXX
+  (void)aWallclockSpec;
+  NS_NOTYETIMPLEMENTED("nsSMILTimedDocumentRoot::SeekToTime");
+  return nsSMILTimeValue();
+}
+
+nsresult
+nsSMILTimedDocumentRoot::SeekToTime(PRInt64 aSeekTo)
+{
+  // XXX
+  (void)aSeekTo;
+  NS_NOTYETIMPLEMENTED("nsSMILTimedDocumentRoot::SeekToTime");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+//----------------------------------------------------------------------
+// nsISMILTimeContainer methods
+
+nsresult
+nsSMILTimedDocumentRoot::Pause()
+{
+  if (!mContainerPaused && !mParentPaused)
+    LL_DIV(mPauseStart, PR_Now(), PR_USEC_PER_MSEC);
+  mContainerPaused = PR_TRUE;
+  return NS_OK;
+}
+
+nsresult
+nsSMILTimedDocumentRoot::Resume()
+{
+  if (mContainerPaused && !mParentPaused) {
+    PRInt64 extraOffset;
+    PRInt64 now;
+    LL_DIV(now, PR_Now(), PR_USEC_PER_MSEC);
+    LL_SUB(extraOffset, now, mPauseStart);
+    LL_ADD(mAccumulatedOffset, extraOffset, mAccumulatedOffset);
+  }
+  mContainerPaused = PR_FALSE;
+  return NS_OK;
+}
+
+PRBool
+nsSMILTimedDocumentRoot::IsPaused()
+{
+  return mContainerPaused;
+}
+
+nsresult
+nsSMILTimedDocumentRoot::ParentPaused()
+{
+  if (!mContainerPaused && !mParentPaused)
+    LL_DIV(mPauseStart, PR_Now(), PR_USEC_PER_MSEC);
+  mParentPaused = PR_TRUE;
+  return NS_OK;
+}
+
+nsresult
+nsSMILTimedDocumentRoot::ParentResumed()
+{
+  if (!mContainerPaused && mParentPaused) {
+    PRInt64 extraOffset;
+    PRInt64 now;
+    LL_DIV(now, PR_Now(), PR_USEC_PER_MSEC);
+    LL_SUB(extraOffset, now, mPauseStart);
+    LL_ADD(mAccumulatedOffset, extraOffset, mAccumulatedOffset);
+  }
+  mParentPaused = PR_FALSE;
+  return NS_OK;
+}
+
+nsresult
+nsSMILTimedDocumentRoot::Reset()
+{
+  mStartTime = LL_Zero();
+  mAccumulatedOffset = LL_Zero();
+  mParentPaused = PR_FALSE;
+  mContainerPaused = PR_FALSE;
+  
+  PR_Lock(mAnimationLock);
+  ResetChildren(PR_TRUE);
+  PR_Unlock(mAnimationLock);
+
+  return NS_OK;
+}
+
+void
+nsSMILTimedDocumentRoot::Sample()
+{
+  if (mParentPaused || mContainerPaused)
+    return;
+
+  PRInt64 now;
+  LL_DIV(now, PR_Now(), PR_USEC_PER_MSEC);
+
+  // If this is the first time, record the document begin time
+  if (LL_IS_ZERO(mStartTime))
+    mStartTime = now;
+  
+  PRInt64 instant;
+  LL_SUB(instant, now, mStartTime);
+  LL_SUB(instant, instant, mAccumulatedOffset);
+
+  if (mAnimationRegistry)
+    mAnimationRegistry->StartSample();
+
+  PR_Lock(mAnimationLock);
+  SampleChildren(instant);
+  PR_Unlock(mAnimationLock);
+
+  if (mAnimationRegistry)
+    mAnimationRegistry->EndSample();
+}
+
+nsresult
+nsSMILTimedDocumentRoot::AddTimedElement(nsISMILTimedElement* aElement)
+{
+  NS_ENSURE_ARG_POINTER(aElement);
+
+  nsresult rv;
+  nsCOMPtr<nsIWeakReference> weakRef(
+      getter_AddRefs(do_GetWeakReference(aElement, &rv)) );
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  PR_Lock(mAnimationLock);
+  rv = (mTimedElements.AppendObject(weakRef)) ? NS_OK : NS_ERROR_FAILURE;
+  PR_Unlock(mAnimationLock);
+
+  aElement->SetDocumentRoot(this);
+
+  return rv;
+}
+
+nsresult
+nsSMILTimedDocumentRoot::RemoveTimedElement(nsISMILTimedElement* aElement)
+{
+  NS_ENSURE_ARG_POINTER(aElement);
+
+  nsresult rv;
+  nsCOMPtr<nsIWeakReference> weakRef(
+      getter_AddRefs(do_GetWeakReference(aElement, &rv)) );
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  PR_Lock(mAnimationLock);
+  rv = (mTimedElements.RemoveObject(weakRef)) ? NS_OK : NS_ERROR_FAILURE;
+  PR_Unlock(mAnimationLock);
+
+  aElement->SetDocumentRoot(nsnull);
+
+  return rv;
+}
+
+//----------------------------------------------------------------------
+// Implementation helpers:
+
+void
+nsSMILTimedDocumentRoot::SampleChildren(PRInt64 aDocumentTime)
+{
+  PRUint32 i = mTimedElements.Count();
+  while (i > 0) {
+    --i;
+    nsCOMPtr<nsISMILTimedElement> 
+      element( do_QueryReferent(mTimedElements[i]) );
+
+    if (element)
+      element->SampleAt(aDocumentTime);
+    else
+      mTimedElements.RemoveObjectAt(i);
+  }
+}
+
+void
+nsSMILTimedDocumentRoot::ResetChildren(PRBool aHardReset)
+{
+  PRUint32 i = mTimedElements.Count();
+  while (i > 0) {
+    --i;
+    nsCOMPtr<nsISMILTimedElement> 
+      element( do_QueryReferent(mTimedElements[i]) );
+
+    if (element)
+      element->Reset(aHardReset);
+    else
+      mTimedElements.RemoveObjectAt(i);
+  }
+}
+
Index: content/smil/src/nsSMILTimedDocumentRoot.h
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILTimedDocumentRoot.h
diff -N content/smil/src/nsSMILTimedDocumentRoot.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILTimedDocumentRoot.h	5 Nov 2005 04:39:17 -0000
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_SMILTIMEDDOCUMENTROOT_H__
+#define __NS_SMILTIMEDDOCUMENTROOT_H__
+
+#include "nsISupports.h"
+#include "nsISMILTimeContainer.h"
+#include "nsSMILAnimationRegistry.h"
+#include "nsWeakReference.h"
+#include "nsCOMArray.h"
+#include "prlock.h"
+
+class nsISMILTimeValueSpec;
+class nsISMILTimedElement;
+class nsSMILTimeValue;
+
+////////////////////////////////////////////////////////////////////////
+// nsSMILTimedDocumentRoot: Timed document root
+
+class nsSMILTimedDocumentRoot : public nsISMILTimeContainer,
+                                public nsSupportsWeakReference
+{
+public:
+  nsSMILTimedDocumentRoot(nsSMILAnimationRegistry* registry);
+  ~nsSMILTimedDocumentRoot();
+
+  NS_DECL_ISUPPORTS
+
+  PRInt64           GetDocumentTime();
+  nsSMILTimeValue   WallclockToDocumentTime(nsISMILTimeValueSpec*
+                                              aWallclockSpec);
+  nsresult          SeekToTime(PRInt64 aSeekTo);
+
+  // nsISMILTimeContainer
+  virtual PRBool    IsPaused();
+  virtual nsresult  Pause();
+  virtual nsresult  Resume();
+  virtual nsresult  ParentPaused();
+  virtual nsresult  ParentResumed();
+  virtual nsresult  Reset();
+  virtual void      Sample();
+  virtual nsresult  AddTimedElement(nsISMILTimedElement* aElement);
+  virtual nsresult  RemoveTimedElement(nsISMILTimedElement* aElement);
+
+protected:
+  void              SampleChildren(PRInt64 aDocumentTime);
+  void              ResetChildren(PRBool aHardReset);
+
+  PRInt64                       mStartTime;
+  PRInt64                       mAccumulatedOffset;
+  nsCOMArray<nsIWeakReference>  mTimedElements;
+  nsSMILAnimationRegistry*      mAnimationRegistry;
+  PRLock*                       mAnimationLock;
+  PRBool                        mParentPaused;
+  PRBool                        mContainerPaused;
+  PRInt64                       mPauseStart;
+};
+
+#endif // __NS_SMILTIMEDDOCUMENTROOT_H__
+
Index: content/smil/src/nsSMILTimedElement.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/smil/src/nsSMILTimedElement.cpp
diff -N content/smil/src/nsSMILTimedElement.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/smil/src/nsSMILTimedElement.cpp	5 Nov 2005 04:39:19 -0000
@@ -0,0 +1,1230 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsISMILTimedElement.h"
+#include "nsIDOMElementTimeControl.h"
+#include "nsWeakReference.h"
+#include "nsSMILTimeValue.h"
+#include "nsSMILTimeValueSpec.h"
+#include "nsSMILInstanceTime.h"
+#include "nsSMILInterval.h"
+#include "nsISMILTimeClient.h"
+#include "nsSMILEnum.h"
+#include "nsSMILAtoms.h"
+#include "nsSMILParserUtils.h"
+#include "nsSMILTimedDocumentRoot.h"
+#include "nsCOMArray.h"
+#include "nsReadableUtils.h"
+#include "nsAutoPtr.h"
+#include "prdtoa.h"
+#include "plstr.h"
+#include "nsAutoLock.h"
+#include "nsString.h"
+
+//----------------------------------------------------------------------
+// Class declaration
+
+class nsSMILTimedElement : public nsISMILTimedElement,
+                           public nsIDOMElementTimeControl,
+                           public nsSupportsWeakReference
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMELEMENTTIMECONTROL
+
+  // nsISMILTimedElement
+  virtual void      AddInstanceTime(nsSMILInstanceTime* aInstanceTime,
+                                    PRBool aIsBegin);
+  virtual void      SetDocumentRoot(nsSMILTimedDocumentRoot* aRoot);
+  virtual void      SetTimeClient(nsISMILTimeClient* aClient);
+  virtual void      SampleAt(const PRInt64& aDocumentTime);
+  virtual void      Reset(PRBool aHardReset = PR_FALSE);
+
+  virtual nsresult  SetBeginSpec(const nsAString& aBeginSpec);
+  virtual nsresult  SetEndSpec(const nsAString& aEndSpec);
+  virtual nsresult  SetSimpleDuration(const nsAString& aDurSpec);
+  virtual nsresult  SetMin(const nsAString& aMinSpec);
+  virtual nsresult  SetMax(const nsAString& aMaxSpec);
+  virtual nsresult  SetRestart(const nsAString& aRestartSpec);
+  virtual nsresult  SetRepeatCount(const nsAString& aRepeatCountSpec);
+  virtual nsresult  SetRepeatDur(const nsAString& aRepeatDurSpec);
+  virtual nsresult  SetFillMode(const nsAString& aFillModeSpec);
+
+  virtual void      UnsetBeginSpec();
+  virtual void      UnsetEndSpec();
+  virtual void      UnsetSimpleDuration();
+  virtual void      UnsetMin();
+  virtual void      UnsetMax();
+  virtual void      UnsetRestart();
+  virtual void      UnsetRepeatCount();
+  virtual void      UnsetRepeatDur();
+  virtual void      UnsetFillMode();
+
+protected:
+  nsSMILTimedElement();
+  ~nsSMILTimedElement();
+  nsresult          Init();
+
+  friend nsISMILTimedElement* NS_NewSMILTimedElement();
+
+  //
+  // Implementation helpers
+  //
+
+  nsresult          SetBeginOrEndSpec(const nsAString& aSpec, PRBool aIsBegin);
+
+  /**
+   * Calculates the first acceptable interval for this element.
+   *
+   * @see SMILANIM 3.6.8
+   */
+  nsresult          GetNextInterval(const nsSMILTimeValue& aBeginAfter,
+                                  PRBool aFirstInstance,
+                                  nsSMILInterval& aResult);
+
+  PRBool            GetNextGreater(const nsCOMArray<nsSMILInstanceTime>& aList,
+                                   const nsSMILTimeValue& aBase,
+                                   PRInt32& aPosition,
+                                   nsSMILTimeValue& aResult);
+  nsSMILTimeValue   CalcActiveEnd(const nsSMILTimeValue& aBegin,
+                                  const nsSMILTimeValue& aEnd);
+  nsSMILTimeValue   GetRepeatDuration();
+  nsSMILTimeValue   ApplyMinAndMax(const nsSMILTimeValue& aDuration);
+  PRInt64           ActiveTimeToSimpleTime(const PRInt64& aActiveTime,
+                                           PRUint32& aRepeatIteration);
+  void              CheckForEarlyEnd(const nsSMILTimeValue &aDocumentTime);
+  void              UpdateCurrentInterval();
+  void              SampleSimpleTime(PRInt64 aActiveTime);
+  void              SampleFillValue();
+  PRInt64           MinLL(const PRInt64& a, const PRInt64& b);
+
+  //
+  // Members
+  //
+  nsCOMArray<nsSMILTimeValueSpec> mBeginSpecs;
+  nsCOMArray<nsSMILTimeValueSpec> mEndSpecs;
+
+  //
+  // We need to distinguish between attempting to set the begin spec and failing
+  // (in which case the mBeginSpecs array will be empty) and not attempting to
+  // set the begin spec at all. In the first case, we should act as if the begin
+  // was indefinite, and in the second, we should act as if begin was 0s.
+  //
+  PRBool                          mBeginSpecSet;
+
+  nsSMILTimeValue                 mSimpleDur;
+
+  /**
+   * The number of iterations of the animation function. We use an
+   * nsSMILTimeValue type where:
+   *
+   * milliseconds = the number of iterations * 1000,
+   * indefinite   = repeating indefinitely, until the document ends, and
+   * unresolved   = the attribute is not set, therefore no repeating.
+   */
+  nsSMILTimeValue                 mRepeatCount;
+  nsSMILTimeValue                 mRepeatDur;
+
+  nsSMILTimeValue                 mMin;
+  nsSMILTimeValue                 mMax;
+
+  enum nsSMILFillMode
+  {
+    fill_remove,
+    fill_freeze
+  };
+  static nsSMILEnumMapping        sFillModeMap[];
+  nsSMILEnum                      mFillMode;
+
+  enum nsSMILRestartMode
+  {
+    restart_always,
+    restart_whennotactive,
+    restart_never
+  };
+  static nsSMILEnumMapping        sRestartModeMap[];
+  nsSMILEnum                      mRestartMode;
+
+  PRBool                          mEndHasEventConditions;
+
+  nsCOMArray<nsSMILInstanceTime>  mBeginInstances;
+  nsCOMArray<nsSMILInstanceTime>  mEndInstances;
+
+  nsCOMPtr<nsISMILTimeClient>     mClient;
+  nsCOMPtr<nsSMILInterval>        mCurrentInterval;
+  nsCOMArray<nsSMILInterval>      mOldIntervals;
+  PRLock*                         mAnimationLock;
+  nsRefPtr<nsSMILTimedDocumentRoot> mDocumentRoot;
+
+  /**
+   * The state of the element in its life-cycle. These states are based on the
+   * element life-cycle described in SMILANIM 3.6.8
+   */
+  enum nsSMILElementState
+  {
+    state_startup,
+    state_waiting,
+    state_active,
+    state_postactive
+  };
+  nsSMILElementState              mElementState;
+};
+
+//----------------------------------------------------------------------
+// Static members
+
+nsSMILEnumMapping nsSMILTimedElement::sFillModeMap[] = {
+      {&nsSMILAtoms::remove, fill_remove},
+      {&nsSMILAtoms::freeze, fill_freeze},
+      {nsnull, 0}
+};
+
+nsSMILEnumMapping nsSMILTimedElement::sRestartModeMap[] = {
+      {&nsSMILAtoms::always, restart_always},
+      {&nsSMILAtoms::whennotactive, restart_whennotactive},
+      {&nsSMILAtoms::never, restart_never},
+      {nsnull, 0}
+};
+
+//----------------------------------------------------------------------
+// Factory method
+
+nsISMILTimedElement* NS_NewSMILTimedElement()
+{
+  nsSMILTimedElement* element = new nsSMILTimedElement();
+
+  if (element && NS_FAILED(element->Init())) {
+      delete element;
+      return nsnull;
+  }
+
+  return element;
+}
+
+//----------------------------------------------------------------------
+// Ctor, dtor
+
+nsSMILTimedElement::nsSMILTimedElement()
+:
+  mBeginSpecs(),
+  mEndSpecs(),
+  mBeginSpecSet(PR_FALSE),
+  mFillMode(fill_remove, sFillModeMap),
+  mRestartMode(restart_always, sRestartModeMap),
+  mEndHasEventConditions(PR_FALSE),
+  mElementState(state_startup)
+{
+  mSimpleDur.SetIndefinite();
+  mMin.SetMillis(LL_Zero());
+  mMax.SetIndefinite();
+}
+
+nsSMILTimedElement::~nsSMILTimedElement()
+{
+  if (mAnimationLock)
+    PR_Lock(mAnimationLock);
+  
+  if (mAnimationLock) {
+    PR_Unlock(mAnimationLock);
+    PR_DestroyLock(mAnimationLock);
+  }
+}
+
+nsresult
+nsSMILTimedElement::Init()
+{
+  mAnimationLock = PR_NewLock();
+  mCurrentInterval = new nsSMILInterval();
+
+  return (mAnimationLock && mCurrentInterval) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+//----------------------------------------------------------------------
+// nsISupports
+
+NS_IMPL_ISUPPORTS3(nsSMILTimedElement,
+                   nsISMILTimedElement,
+                   nsIDOMElementTimeControl,
+                   nsISupportsWeakReference)
+
+//----------------------------------------------------------------------
+// nsIDOMElementTimeControl methods
+//
+// The definition of the ElementTimeControl interface differs between SMIL
+// Animation and SVG 1.1. In SMIL Animation all methods have a void return
+// type and the new instance time is simply added to the list and restart
+// semantics are applied as with any other instance time. In the SVG definition
+// the methods return a bool depending on the restart mode. There are some
+// cases where this is problematic.
+//
+// For example, if a call is made to beginElementAt and the resolved time
+// after including the offset falls outside the current interval then using
+// the SMIL Animation definition an element with restart == whenNotActive
+// would restart with this new instance time. The SVG definition however seems
+// to imply that in this case the implementation should ignore the new
+// instance time if the restart mode == whenNotActive and the element is
+// currently active and return false.
+//
+// It is tempting to try and determine when a new instance time will actually
+// cause a restart but this is not possible as in the meantime a new event may
+// trump the new instance time. We take a compromise of returning true and
+// false according to the SVG definition but adding the instance time to the
+// list regardless. This may produce different results to an implementation that
+// follows strictly the behaviour implied by the SVG spec.
+//
+
+/* boolean beginElement (); */
+NS_IMETHODIMP
+nsSMILTimedElement::BeginElement(PRBool *_retval)
+{
+  return BeginElementAt(0.0, _retval);
+}
+
+/* boolean beginElementAt (in float offset); */
+NS_IMETHODIMP
+nsSMILTimedElement::BeginElementAt(float offset, PRBool *_retval)
+{
+  // Check for restart == never
+  if (mRestartMode.GetIntegerValue() == restart_never &&
+      mElementState == state_active ||
+      mElementState == state_postactive) {
+    *_retval = PR_FALSE;
+  }
+
+  // Check for restart == whenNotActive
+  if (mRestartMode.GetIntegerValue() == restart_whennotactive &&
+      mElementState == state_active) {
+    *_retval = PR_FALSE;
+  }
+
+  if (!mDocumentRoot) {
+    *_retval = PR_FALSE;
+    NS_ERROR("Attempting to begin but there is no document root.");
+    return NS_ERROR_FAILURE;
+  }
+
+  PRInt64 offsetVal;
+  LL_D2L(offsetVal, offset);
+  PRInt64 timeWithOffset;
+  LL_ADD(timeWithOffset, mDocumentRoot->GetDocumentTime(), offsetVal);
+  nsSMILTimeValue timeVal;
+  timeVal.SetMillis(timeWithOffset);
+  nsRefPtr<nsSMILInstanceTime> 
+    instanceTime(new nsSMILInstanceTime(timeVal, nsnull, PR_TRUE));
+  NS_ENSURE_TRUE(instanceTime, NS_ERROR_OUT_OF_MEMORY);
+
+  nsAutoLock lock(mAnimationLock);
+  AddInstanceTime(instanceTime, PR_TRUE);
+
+  *_retval = PR_TRUE;
+  return NS_OK;
+}
+
+/* boolean endElement (); */
+NS_IMETHODIMP
+nsSMILTimedElement::EndElement(PRBool *_retval)
+{
+  return EndElementAt(0.0, _retval);
+}
+
+/* boolean endElementAt (in float offset); */
+NS_IMETHODIMP
+nsSMILTimedElement::EndElementAt(float offset, PRBool *_retval)
+{
+  if (mElementState != state_active)
+    *_retval = PR_FALSE;
+
+  if (!mDocumentRoot) {
+    *_retval = PR_FALSE;
+    NS_ERROR("Attempting to end but there is no document root.");
+    return NS_ERROR_FAILURE;
+  }
+
+  PRInt64 offsetVal;
+  LL_D2L(offsetVal, offset);
+  PRInt64 timeWithOffset;
+  LL_ADD(timeWithOffset, mDocumentRoot->GetDocumentTime(), offsetVal);
+  nsSMILTimeValue timeVal;
+  timeVal.SetMillis(timeWithOffset);
+  nsRefPtr<nsSMILInstanceTime> 
+    instanceTime(new nsSMILInstanceTime(timeVal, nsnull, PR_TRUE));
+  NS_ENSURE_TRUE(instanceTime, NS_ERROR_OUT_OF_MEMORY);
+
+  nsAutoLock lock(mAnimationLock);
+  AddInstanceTime(instanceTime, PR_FALSE);
+
+  *_retval = PR_TRUE;
+  return NS_OK;
+}
+
+//----------------------------------------------------------------------
+// nsISMILTimedElement
+
+void
+nsSMILTimedElement::AddInstanceTime(nsSMILInstanceTime* aInstanceTime,
+                                    PRBool aIsBegin)
+{
+  NS_ASSERTION(aInstanceTime, "NULL instance time");
+
+  if (aIsBegin)
+    mBeginInstances.AppendObject(aInstanceTime);
+  else
+    mEndInstances.AppendObject(aInstanceTime);
+
+  UpdateCurrentInterval();
+}
+
+void
+nsSMILTimedElement::SetDocumentRoot(nsSMILTimedDocumentRoot* aRoot)
+{
+  mDocumentRoot = aRoot;
+}
+
+void
+nsSMILTimedElement::SetTimeClient(nsISMILTimeClient* aClient)
+{
+  //
+  // No need to check for NULL. A NULL parameter simply means to remove the
+  // previous client which we do by setting to NULL anyway.
+  //
+
+  nsAutoLock lock(mAnimationLock);
+  mClient = aClient;
+}
+
+void
+nsSMILTimedElement::SampleAt(const PRInt64& aDocumentTime)
+{
+  PRBool          stateChanged;
+  nsSMILTimeValue docTime;
+  docTime.SetMillis(aDocumentTime);
+
+  nsAutoLock lock(mAnimationLock);
+
+  // XXX Cache previous sample time and if this time is less then perform
+  // backwards seeking behaviour (see SMILANIM 3.6.5 Hyperlinks and timing)
+
+  do {
+    stateChanged = false;
+
+    switch (mElementState)
+    {
+    case state_startup:
+      {
+        nsSMILTimeValue beginAfter;
+        beginAfter.SetMillis(LL_MININT);
+
+        mElementState = 
+          (NS_SUCCEEDED(GetNextInterval(beginAfter, true,
+                                        *mCurrentInterval)))
+          ? state_waiting
+          : state_postactive;
+        stateChanged = true;
+      }
+      break;
+
+    case state_waiting:
+      {
+        if (mCurrentInterval->Begin().CompareTo(docTime) < 1) {
+          mElementState = state_active;
+          if (mClient)
+            mClient->ToActive(mCurrentInterval->Begin().GetMillis());
+          stateChanged = true;
+        }
+      }
+      break;
+
+    case state_active:
+      {
+        CheckForEarlyEnd(docTime);
+        if (mCurrentInterval->End().CompareTo(docTime) < 1) {
+          nsCOMPtr<nsSMILInterval> newInterval(new nsSMILInterval());
+          mElementState = 
+            (NS_SUCCEEDED(GetNextInterval(mCurrentInterval->End(),
+                                          false,
+                                          *newInterval)))
+            ? state_waiting
+            : state_postactive;
+          if (mClient)
+            mClient->ToInactive(mFillMode.GetIntegerValue() == fill_freeze);
+          SampleFillValue();
+          mOldIntervals.AppendObject(mCurrentInterval);
+          mCurrentInterval = newInterval;
+          Reset();
+          stateChanged = true;
+        } else {
+          PRInt64 beginTime = mCurrentInterval->Begin().GetMillis();
+
+          PRInt64 activeTime;
+          LL_SUB(activeTime, aDocumentTime, beginTime);
+
+          SampleSimpleTime(activeTime);
+        }
+      }
+      break;
+
+    case state_postactive:
+      break;
+    }
+  } while (stateChanged);
+}
+
+void
+nsSMILTimedElement::Reset(PRBool aHardReset /* = PR_FALSE */)
+{
+  nsSMILInstanceTime* instance;
+
+  PRInt32    count = mBeginInstances.Count();
+
+  for (PRInt32 i = 0; i < count; ++i) {
+    instance = NS_STATIC_CAST(nsSMILInstanceTime*, mBeginInstances[0]);
+    if (instance->ClearOnReset())
+      mBeginInstances.RemoveObjectAt(0);
+  }
+
+  count = mEndInstances.Count();
+
+  for (PRInt32 j = 0; j < count; ++j) {
+    instance = NS_STATIC_CAST(nsSMILInstanceTime*, mEndInstances[0]);
+    if (instance->ClearOnReset())
+      mEndInstances.RemoveObjectAt(0);
+  }
+
+  if (aHardReset) {
+    mCurrentInterval = new nsSMILInterval();
+    mElementState    = state_startup;
+    mOldIntervals.Clear();
+
+    // Remove any fill
+    if (mClient)
+      mClient->ToInactive(PR_FALSE);
+  }
+}
+
+//----------------------------------------------------------------------
+// Setters and unsetters
+
+nsresult
+nsSMILTimedElement::SetBeginSpec(const nsAString& aBeginSpec)
+{
+  nsAutoLock lock(mAnimationLock);
+  mBeginSpecSet = PR_TRUE;
+  return SetBeginOrEndSpec(aBeginSpec, PR_TRUE);
+}
+
+void
+nsSMILTimedElement::UnsetBeginSpec()
+{
+  nsAutoLock lock(mAnimationLock);
+  mBeginSpecs.Clear();
+  mBeginInstances.Clear();
+  mBeginSpecSet = PR_FALSE;
+  UpdateCurrentInterval();
+}
+
+nsresult
+nsSMILTimedElement::SetEndSpec(const nsAString& aEndSpec)
+{
+  //
+  // When implementing events etc., don't forget to ensure
+  // mEndHasEventConditions is set if the specification contains conditions that
+  // describe event-values, repeat-values or accessKey-values.
+  //
+  nsAutoLock lock(mAnimationLock);
+  return SetBeginOrEndSpec(aEndSpec, PR_FALSE);
+}
+
+void
+nsSMILTimedElement::UnsetEndSpec()
+{
+  nsAutoLock lock(mAnimationLock);
+  mEndSpecs.Clear();
+  mEndInstances.Clear();
+  UpdateCurrentInterval();
+}
+
+nsresult
+nsSMILTimedElement::SetSimpleDuration(const nsAString& aDurSpec)
+{
+  nsSMILTimeValue duration;
+  PRBool isMedia;
+  nsresult rv;
+  
+  rv = nsSMILParserUtils::GetClockValue(aDurSpec,
+                                        &duration,
+                                        false, // don't allow + or -
+                                        true,  // allow indefinite
+                                        true,  // allow media
+                                        &isMedia);
+
+  if (NS_FAILED(rv) || (!duration.IsResolved() && !duration.IsIndefinite()))
+    return NS_ERROR_FAILURE;
+  
+  if (duration.IsResolved() && LL_IS_ZERO(duration.GetMillis()))
+    return NS_ERROR_FAILURE;
+
+  //
+  // SVG-specific: "For SVG's animation elements, if "media" is specified, the
+  // attribute will be ignored." (SVG 1.1, section 19.2.6)
+  //
+  if (isMedia)
+    duration.SetIndefinite();
+
+  nsAutoLock lock(mAnimationLock);
+  mSimpleDur = duration;
+
+  return NS_OK;
+}
+
+void
+nsSMILTimedElement::UnsetSimpleDuration()
+{
+  nsAutoLock lock(mAnimationLock);
+  mSimpleDur.SetIndefinite();
+  UpdateCurrentInterval();
+}
+
+nsresult
+nsSMILTimedElement::SetMin(const nsAString& aMinSpec)
+{
+  nsSMILTimeValue duration;
+  PRBool isMedia;
+  nsresult rv;
+  
+  rv = nsSMILParserUtils::GetClockValue(aMinSpec,
+                                        &duration,
+                                        false, // don't allow + or -
+                                        false, // don't allow indefinite
+                                        true,  // allow media
+                                        &isMedia);
+
+  if (isMedia)
+    duration.SetMillis(LL_Zero());
+
+  nsAutoLock lock(mAnimationLock);
+
+  if (NS_FAILED(rv) || !duration.IsResolved()) {
+    mMin.SetMillis(LL_Zero());
+    return NS_ERROR_FAILURE;
+  }
+  
+  if (!LL_GE_ZERO(duration.GetMillis())) {
+    mMin.SetMillis(LL_Zero());
+    return NS_ERROR_FAILURE;
+  }
+
+  mMin = duration;
+  UpdateCurrentInterval();
+
+  return NS_OK;
+}
+
+void
+nsSMILTimedElement::UnsetMin()
+{
+  nsAutoLock lock(mAnimationLock);
+  mMin.SetMillis(LL_Zero());
+  UpdateCurrentInterval();
+}
+
+nsresult
+nsSMILTimedElement::SetMax(const nsAString& aMaxSpec)
+{
+  nsSMILTimeValue duration;
+  PRBool isMedia;
+  nsresult rv;
+  
+  rv = nsSMILParserUtils::GetClockValue(aMaxSpec,
+                                        &duration,
+                                        false, // don't allow + or -
+                                        true,  // allow indefinite
+                                        true,  // allow media
+                                        &isMedia);
+
+  if (isMedia)
+    duration.SetIndefinite();
+
+  nsAutoLock lock(mAnimationLock);
+
+  if (NS_FAILED(rv) || (!duration.IsResolved() && !duration.IsIndefinite())) {
+    mMax.SetIndefinite();
+    return NS_ERROR_FAILURE;
+  }
+  
+  if (duration.IsResolved() &&
+      (!LL_GE_ZERO(duration.GetMillis()) || LL_IS_ZERO(duration.GetMillis()))) {
+    mMax.SetIndefinite();
+    return NS_ERROR_FAILURE;
+  }
+
+  mMax = duration;
+  UpdateCurrentInterval();
+
+  return NS_OK;
+}
+
+void
+nsSMILTimedElement::UnsetMax()
+{
+  nsAutoLock lock(mAnimationLock);
+  mMax.SetIndefinite();
+  UpdateCurrentInterval();
+}
+
+nsresult
+nsSMILTimedElement::SetRestart(const nsAString& aRestartSpec)
+{
+  nsAutoLock lock(mAnimationLock);
+  nsresult rv = mRestartMode.SetStringValue(aRestartSpec);
+  UpdateCurrentInterval();
+  return rv;
+}
+
+void
+nsSMILTimedElement::UnsetRestart()
+{
+  nsAutoLock lock(mAnimationLock);
+  mRestartMode.SetIntegerValue(restart_always);
+  UpdateCurrentInterval();
+}
+
+nsresult
+nsSMILTimedElement::SetRepeatCount(const nsAString& aRepeatCountSpec)
+{
+  nsSMILTimeValue newRepeatCount;
+  nsresult rv = 
+    nsSMILParserUtils::GetRepeatCount(aRepeatCountSpec, newRepeatCount);
+
+  nsAutoLock lock(mAnimationLock);
+  UpdateCurrentInterval();
+
+  if (NS_SUCCEEDED(rv))
+    mRepeatCount = newRepeatCount;
+  else
+    mRepeatCount.SetUnresolved();
+    
+  return rv;
+}
+
+void
+nsSMILTimedElement::UnsetRepeatCount()
+{
+  nsAutoLock lock(mAnimationLock);
+  mRepeatCount.SetUnresolved();
+  UpdateCurrentInterval();
+}
+
+nsresult
+nsSMILTimedElement::SetRepeatDur(const nsAString& aRepeatDurSpec)
+{
+  nsresult        rv;
+  nsSMILTimeValue duration;
+
+  rv = nsSMILParserUtils::GetClockValue(aRepeatDurSpec,
+                                        &duration,
+                                        false,  // don't allow + or -
+                                        true);  // allow indefinite
+
+  if (NS_FAILED(rv) || (!duration.IsResolved() && !duration.IsIndefinite()))
+    return NS_ERROR_FAILURE;
+  
+  nsAutoLock lock(mAnimationLock);
+  UpdateCurrentInterval();
+  
+  mRepeatDur = duration;
+
+  return NS_OK;
+}
+
+void
+nsSMILTimedElement::UnsetRepeatDur()
+{
+  nsAutoLock lock(mAnimationLock);
+  mRepeatDur.SetUnresolved();
+  UpdateCurrentInterval();
+}
+
+nsresult
+nsSMILTimedElement::SetFillMode(const nsAString& aFillModeSpec)
+{
+  nsAutoLock lock(mAnimationLock);
+
+  PRUint16 previousFillMode = mFillMode.GetIntegerValue();
+  nsresult rv = mFillMode.SetStringValue(aFillModeSpec);
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  if (previousFillMode == mFillMode.GetIntegerValue())
+    return NS_OK;
+
+  if ((mElementState == state_waiting || mElementState == state_postactive) &&
+      mClient)
+      mClient->ToInactive(mFillMode.GetIntegerValue() == fill_freeze);
+
+  return NS_OK;
+}
+
+void
+nsSMILTimedElement::UnsetFillMode()
+{
+  nsAutoLock lock(mAnimationLock);
+  PRUint16 previousFillMode = mFillMode.GetIntegerValue();
+  mFillMode.SetIntegerValue(fill_remove);
+  if ((mElementState == state_waiting || mElementState == state_postactive) &&
+      previousFillMode == fill_freeze &&
+      mClient)
+    mClient->ToInactive(PR_FALSE);
+}
+
+//----------------------------------------------------------------------
+// Implementation helpers
+
+nsresult
+nsSMILTimedElement::SetBeginOrEndSpec(const nsAString& aSpec,
+                                      PRBool aIsBegin)
+{
+  nsRefPtr<nsSMILTimeValueSpec>    spec;
+  nsCOMArray<nsSMILTimeValueSpec>& timeSpecsList = (aIsBegin)
+                                                 ? mBeginSpecs
+                                                 : mEndSpecs;
+  nsCOMArray<nsSMILInstanceTime>&  instancesList = (aIsBegin)
+                                                 ? mBeginInstances
+                                                 : mEndInstances;
+
+  timeSpecsList.Clear();
+  instancesList.Clear();
+
+  PRInt32 start;
+  PRInt32 end = -1;
+  PRInt32 length;
+
+  do {
+    start        = end + 1;
+    end          = aSpec.FindChar(';', start);
+    length       = (end == -1) ? -1 : end - start;
+
+    spec = NS_NewSMILTimeValueSpec(this, aIsBegin,
+                                   Substring(aSpec, start, length));
+
+    if (spec)
+      timeSpecsList.AppendObject(spec);
+  } while (end != -1 && spec);
+
+  if (!spec) {
+    timeSpecsList.Clear();
+    instancesList.Clear();
+    Reset(PR_TRUE);
+    return NS_ERROR_FAILURE;
+  }
+
+  UpdateCurrentInterval();
+
+  return NS_OK;
+}
+
+//
+// This method is based on the pseudocode given in the SMILANIM spec.
+//
+// See:
+// http://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-BeginEnd-LC-Start
+//
+nsresult
+nsSMILTimedElement::GetNextInterval(const nsSMILTimeValue& aBeginAfter,
+                                    PRBool aFirstInterval,
+                                    nsSMILInterval& aResult)
+{
+  static nsSMILTimeValue zeroTime;
+  zeroTime.SetMillis(LL_Zero());
+  
+  nsSMILTimeValue beginAfter = aBeginAfter;
+  nsSMILTimeValue tempBegin;
+  nsSMILTimeValue tempEnd;
+  PRInt32         beginPos = 0;
+  PRInt32         endPos = 0;
+
+  //
+  // This is to handle the special case when a we are calculating the first
+  // interval and we have a non-0-duration interval immediately after
+  // a 0-duration in which case but we have to be careful not to re-use an end
+  // that has already been used in another interval. See the pseudocode in
+  // SMILANIM 3.6.8 for getFirstInterval.
+  //
+  PRInt32         endMaxPos = 0;
+
+  if (mRestartMode.GetIntegerValue() == restart_never && !aFirstInterval)
+    return NS_ERROR_FAILURE;
+
+  mBeginInstances.Sort(nsSMILInstanceTime::ComparisonCallback, nsnull);
+  mEndInstances.Sort(nsSMILInstanceTime::ComparisonCallback, nsnull);
+
+  while (true) {
+    if (!mBeginSpecSet && beginAfter.CompareTo(zeroTime) < 1) {
+      tempBegin.SetMillis(0);
+    } else {
+      PRBool beginFound = GetNextGreater(mBeginInstances, beginAfter,
+                                         beginPos, tempBegin);
+      if (!beginFound)
+        return NS_ERROR_FAILURE;
+    }
+
+    if (mEndSpecs.Count() == 0) {
+      nsSMILTimeValue indefiniteEnd;
+      indefiniteEnd.SetIndefinite();
+
+      tempEnd = CalcActiveEnd(tempBegin, indefiniteEnd);
+    } else {
+      // 
+      // Start searching from the beginning again.
+      //
+      endPos = 0;
+
+      PRBool endFound = GetNextGreater(mEndInstances, tempBegin,
+                                       endPos, tempEnd);
+
+      if (!aFirstInterval && tempEnd.CompareTo(aBeginAfter)==0 ||
+       (aFirstInterval && tempEnd.CompareTo(tempBegin)==0 && endPos<=endMaxPos))
+        endFound = GetNextGreater(mEndInstances, tempBegin, endPos, tempEnd);
+
+      endMaxPos = endPos;
+
+      if (!endFound) {
+        if (mEndHasEventConditions || mEndInstances.Count() == 0)
+          tempEnd.SetUnresolved();
+        else
+          /* 
+           * This is a little counter-intuitive but according to SMILANIM, if
+           * all the end's are after the begin, we _don't_ just assume an
+           * infinite end, it's actually a bad interval. ASV however will just
+           * use an infinite end.
+           */
+          return NS_ERROR_FAILURE;
+      }
+
+      tempEnd = CalcActiveEnd(tempBegin, tempEnd);
+    }
+
+    if (tempEnd.CompareTo(zeroTime) == 1) {
+      aResult.UpdateBegin(tempBegin);
+      aResult.UpdateEnd(tempEnd);
+      return NS_OK;
+    } else if (mRestartMode.GetIntegerValue() == restart_never) {
+      return NS_ERROR_FAILURE;
+    } else {
+      beginAfter = tempEnd;
+    }
+  }
+  NS_NOTREACHED("Hmm... we really shouldn't be here");
+
+  return NS_ERROR_FAILURE;
+}
+
+PRBool
+nsSMILTimedElement::GetNextGreater(const nsCOMArray<nsSMILInstanceTime>& aList,
+                                   const nsSMILTimeValue& aBase,
+                                   PRInt32 &aPosition,
+                                   nsSMILTimeValue& aResult)
+{
+    PRBool              found = PR_FALSE;
+    nsSMILInstanceTime* val;
+    PRInt32             count = aList.Count();
+
+    for (; aPosition < count && !found; ++aPosition) {
+      val = NS_STATIC_CAST(nsSMILInstanceTime*, aList[aPosition]);
+      if (val->Time().CompareTo(aBase) > -1) {
+        aResult = val->Time();
+        found = PR_TRUE;
+      }
+    }
+
+    return found;
+}
+
+inline PRInt64
+nsSMILTimedElement::MinLL(const PRInt64& a, const PRInt64& b)
+{
+  return (LL_CMP(a, <, b)) ? a : b;
+}
+
+/**
+ * @see SMILANIM 3.3.4
+ */
+nsSMILTimeValue
+nsSMILTimedElement::CalcActiveEnd(const nsSMILTimeValue& aBegin,
+                                  const nsSMILTimeValue& aEnd)
+{
+  nsSMILTimeValue result;
+
+  if (!mSimpleDur.IsIndefinite() && !mSimpleDur.IsResolved()) {
+    NS_ERROR("Unresolved simple duration in CalcActiveEnd.");
+    result.SetIndefinite();
+    return result;
+  }
+
+  if (!aBegin.IsResolved() && !aBegin.IsIndefinite()) {
+    NS_ERROR("Unresolved begin time passed to CalcActiveEnd.");
+    result.SetIndefinite();
+    return result;
+  }
+
+  if (mRepeatDur.IsIndefinite() || aBegin.IsIndefinite()) {
+    result.SetIndefinite();
+  } else {
+    result = GetRepeatDuration();
+  }
+
+  if (aEnd.IsResolved() && aBegin.IsResolved()) {
+    PRInt64 activeDur;
+    LL_SUB(activeDur, aEnd.GetMillis(), aBegin.GetMillis());
+
+    if (result.IsResolved())
+      result.SetMillis(MinLL(result.GetMillis(), activeDur));
+    else
+      result.SetMillis(activeDur);
+  }
+
+  result = ApplyMinAndMax(result);
+
+  if (result.IsResolved()) {
+    PRInt64 activeEnd;
+    LL_ADD(activeEnd, result.GetMillis(), aBegin.GetMillis());
+    result.SetMillis(activeEnd);
+  }
+
+  return result;
+}
+
+nsSMILTimeValue
+nsSMILTimedElement::GetRepeatDuration()
+{
+  nsSMILTimeValue result;
+
+  if (mRepeatCount.IsResolved() && mRepeatDur.IsResolved()) {
+    if (mSimpleDur.IsResolved()) {
+      PRInt64 activeDur;
+      LL_MUL(activeDur, mRepeatCount.GetMillis(), mSimpleDur.GetMillis());
+      LL_DIV(activeDur, activeDur, 1000);
+      result.SetMillis(MinLL(activeDur, mRepeatDur.GetMillis()));
+    } else {
+      result = mRepeatDur;
+    }
+  } else if (mRepeatCount.IsResolved() && mSimpleDur.IsResolved()) {
+    PRInt64 activeDur;
+    LL_MUL(activeDur, mRepeatCount.GetMillis(), mSimpleDur.GetMillis());
+    LL_DIV(activeDur, activeDur, 1000);
+    result.SetMillis(activeDur);
+  } else if (mRepeatDur.IsResolved()) {
+    result = mRepeatDur;
+  } else {
+    if (mRepeatCount.IsIndefinite())
+      result.SetIndefinite();
+    else
+      result = mSimpleDur;
+  }
+
+  return result;
+}
+
+nsSMILTimeValue
+nsSMILTimedElement::ApplyMinAndMax(const nsSMILTimeValue& aDuration)
+{
+  if (!aDuration.IsResolved() && !aDuration.IsIndefinite())
+    return aDuration;
+
+  if (mMax.CompareTo(mMin) < 0)
+    return aDuration;
+
+  nsSMILTimeValue result;
+
+  if (aDuration.CompareTo(mMax) > 0) {
+    result = mMax;
+  } else if (aDuration.CompareTo(mMin) < 0) {
+    nsSMILTimeValue repeatDur = GetRepeatDuration();
+    result = (mMin.CompareTo(repeatDur) > 0) ? repeatDur : mMin;
+  } else {
+    result = aDuration;
+  }
+
+  return result;
+}
+
+PRInt64
+nsSMILTimedElement::ActiveTimeToSimpleTime(const PRInt64& aActiveTime,
+                                           PRUint32& aRepeatIteration)
+{
+  PRInt64 result;
+
+  NS_ASSERTION(mSimpleDur.IsResolved() || mSimpleDur.IsIndefinite(),
+      "Trying to calculate active time with unresolved duration");
+
+  if (mSimpleDur.IsIndefinite() || LL_IS_ZERO(mSimpleDur.GetMillis())) {
+    aRepeatIteration = 0;
+    result = aActiveTime;
+  } else {    
+    PRInt64 repeatResult;
+    LL_MOD(result, aActiveTime, mSimpleDur.GetMillis());
+    LL_DIV(repeatResult, aActiveTime, mSimpleDur.GetMillis());
+
+    LL_L2UI(aRepeatIteration, repeatResult);
+  }
+
+  return result;
+}
+
+//
+// Although in many cases it would be possible to check for an early end and
+// adjust the current interval well in advance the SMIL Animation spec seems to
+// indicate that we should only apply an early end at the latest possible
+// moment. In particular, this paragraph from section 3.6.8
+//
+// 'If restart  is set to "always", then the current interval will end early if
+// there is an instance time in the begin list that is before (i.e. earlier
+// than) the defined end for the current interval. Ending in this manner will
+// also send a changed time notice to all time dependents for the current
+// interval end.'
+//
+void
+nsSMILTimedElement::CheckForEarlyEnd(const nsSMILTimeValue& aDocumentTime)
+{
+  if (mRestartMode.GetIntegerValue() != restart_always)
+    return;
+
+  nsSMILTimeValue nextBegin;
+  PRInt32 position = 0;
+
+  // 
+  // Despite its name, GetNextGreater actually gets the next instance time that
+  // is greater than _or_equal_to_ the reference time so we have to loop to make
+  // sure we're getting an instance time that is actually _after_ the interval
+  // begin time
+  //
+  while (GetNextGreater(mBeginInstances, mCurrentInterval->Begin(),
+                        position, nextBegin) &&
+         nextBegin.CompareTo(mCurrentInterval->Begin()) == 0);
+        
+  if (nextBegin.IsResolved() && 
+      nextBegin.CompareTo(mCurrentInterval->Begin()) > 0 &&
+      nextBegin.CompareTo(mCurrentInterval->End()) < 0 &&
+      nextBegin.CompareTo(aDocumentTime) <= 0) {
+    mCurrentInterval->UpdateEnd(nextBegin);
+  }
+}
+
+void
+nsSMILTimedElement::UpdateCurrentInterval()
+{
+  if (mElementState == state_startup)
+    return;
+
+  nsCOMPtr<nsSMILInterval> updatedInterval = new nsSMILInterval();
+  PRBool isFirstInterval = (mOldIntervals.Count() == 0);
+
+  nsSMILTimeValue beginAfter;
+  if (!isFirstInterval)
+    beginAfter = mOldIntervals[mOldIntervals.Count()-1]->End();
+  else
+    beginAfter.SetMillis(LL_MININT);
+
+  nsresult rv = 
+    GetNextInterval(beginAfter, isFirstInterval, *updatedInterval);
+
+  if (NS_SUCCEEDED(rv)) {
+
+    if (mElementState != state_active &&
+        updatedInterval->Begin().CompareTo(mCurrentInterval->Begin())) {
+        mCurrentInterval->UpdateBegin(updatedInterval->Begin());
+    }
+
+    if (updatedInterval->End().CompareTo(mCurrentInterval->End()))
+      mCurrentInterval->UpdateEnd(updatedInterval->End());
+
+    if (mElementState == state_postactive)
+      // XXX notify dependents of new interval
+      mElementState = state_waiting;
+  } else {
+
+    nsSMILTimeValue unresolvedTime;
+    mCurrentInterval->UpdateEnd(unresolvedTime);
+    if (mElementState != state_active)
+      mCurrentInterval->UpdateBegin(unresolvedTime);
+
+    if (mElementState == state_waiting)
+      // XXX notify dependents the current interval has been deleted
+      mElementState = state_postactive;
+
+    if (mElementState == state_active) {
+      // XXX notify dependents the current interval has been deleted
+      mElementState = state_postactive;
+      if (mClient)
+        mClient->ToInactive(PR_FALSE);
+    }
+  }
+}
+
+void
+nsSMILTimedElement::SampleSimpleTime(PRInt64 aActiveTime)
+{
+  if (mClient) {
+    PRUint32 repeatIteration;
+    PRInt64  simpleTime = 
+      ActiveTimeToSimpleTime(aActiveTime, repeatIteration);
+    mClient->SampleAt(simpleTime, mSimpleDur, repeatIteration);
+  }
+}
+
+void
+nsSMILTimedElement::SampleFillValue()
+{
+  if (mFillMode.GetIntegerValue() != fill_freeze)
+    return;
+
+  if (!mClient)
+    return;
+
+  PRUint32 repeatIteration;
+  PRInt64 activeTime;
+  LL_SUB(activeTime,
+         mCurrentInterval->End().GetMillis(),
+         mCurrentInterval->Begin().GetMillis());
+
+  PRInt64  simpleTime = 
+    ActiveTimeToSimpleTime(activeTime, repeatIteration);
+
+  if (LL_IS_ZERO(simpleTime))
+    mClient->SampleLastValue(--repeatIteration);
+  else
+    mClient->SampleAt(simpleTime, mSimpleDur, repeatIteration);
+}
+
Index: content/svg/content/src/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/Makefile.in,v
retrieving revision 1.40
diff -u -r1.40 Makefile.in
--- content/svg/content/src/Makefile.in	13 Sep 2005 22:38:26 -0000	1.40
+++ content/svg/content/src/Makefile.in	5 Nov 2005 04:39:24 -0000
@@ -140,6 +140,10 @@
 CPPSRCS += nsSVGForeignObjectElement.cpp
 endif
 
+ifdef MOZ_SMIL
+CPPSRCS += nsSVGAnimateElement.cpp
+endif
+
 include $(topsrcdir)/config/config.mk
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
@@ -183,3 +187,4 @@
 		$(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
+
Index: content/svg/content/src/nsISVGAnimationElement.h
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsISVGAnimationElement.h
diff -N content/svg/content/src/nsISVGAnimationElement.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/svg/content/src/nsISVGAnimationElement.h	5 Nov 2005 04:39:24 -0000
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SVG project.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_ISVGANIMATIONELEMENT__
+#define __NS_ISVGANIMATIONELEMENT__
+
+#include "nsISupports.h"
+
+//////////////////////////////////////////////////////////////////////////////
+// nsISVGAnimationElement: private interface implemented by animation elements
+
+#define NS_ISVGANIMATIONELEMENT_IID \
+{ 0x70ac6eed, 0x0dba, 0x4c11, { 0xa6, 0xc5, 0x15, 0x73, 0xbc, 0x2f, 0x1a, 0xd8 } }
+
+class nsISVGAnimationElement : public nsISupports
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISVGANIMATIONELEMENT_IID)
+
+  /**
+   * For setting the ordinal position of this animation within the document.
+   */
+  virtual void            SetDocumentPosition(PRUint16 aDocPosition)=0;
+};
+
+#endif // __NS_ISVGANIMATIONELEMENT__
+
Index: content/svg/content/src/nsISVGLength.h
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsISVGLength.h,v
retrieving revision 1.4
diff -u -r1.4 nsISVGLength.h
--- content/svg/content/src/nsISVGLength.h	5 Aug 2004 09:01:09 -0000	1.4
+++ content/svg/content/src/nsISVGLength.h	5 Nov 2005 04:39:24 -0000
@@ -42,6 +42,9 @@
 #include "nsIDOMSVGLength.h"
 
 class nsSVGCoordCtx;
+#ifdef MOZ_SMIL
+class nsISMILAnimVal;
+#endif // MOZ_SMIL
 
 ////////////////////////////////////////////////////////////////////////
 // nsISVGLength: private interface for svg lengths
@@ -56,6 +59,13 @@
   NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISVGLENGTH_IID)
 
   NS_IMETHOD SetContext(nsSVGCoordCtx* ctx)=0;
+#ifdef MOZ_SMIL
+  // This could possibly be done via a tear-off that creates the required object
+  virtual nsISMILAnimVal* GetNewSMILValue()=0;
+  virtual nsISMILAnimVal* GetNewSMILValue(const nsAString& aSpec)=0;
+  virtual nsresult        GetAnimValue(nsISMILAnimVal& aValue)=0;
+  virtual nsresult        SetAnimValue(const nsISMILAnimVal& aNewValue)=0;
+#endif // MOZ_SMIL
 };
 
 
Index: content/svg/content/src/nsISVGSVGElement.h
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsISVGSVGElement.h,v
retrieving revision 1.6
diff -u -r1.6 nsISVGSVGElement.h
--- content/svg/content/src/nsISVGSVGElement.h	25 Aug 2005 21:31:07 -0000	1.6
+++ content/svg/content/src/nsISVGSVGElement.h	5 Nov 2005 04:39:25 -0000
@@ -46,6 +46,9 @@
 class nsSVGCoordCtxProvider;
 class nsIDOMSVGNumber;
 class nsISVGEnum;
+#ifdef MOZ_SMIL
+class nsISMILAnimationRegistry;
+#endif
 
 ////////////////////////////////////////////////////////////////////////
 // nsISVGSVGElement: private interface implemented by <svg>-elements
@@ -89,6 +92,18 @@
   NS_IMETHOD_(float) GetPreviousScale()=0;
   NS_IMETHOD_(float) GetPreviousTranslate_x()=0;
   NS_IMETHOD_(float) GetPreviousTranslate_y()=0;
+  
+#ifdef MOZ_SMIL
+  /**
+   * Get the animation registry object for the outermost svg element.
+   */
+  NS_IMETHOD_(nsISMILAnimationRegistry*) GetAnimationRegistry()=0;
+
+  /**
+   * Walk the tree and give each animation node an ordinal position value.
+   */
+  NS_IMETHOD EnumerateAnimationNodes()=0;
+#endif
 };
 
 #endif // __NS_ISVGSVGELEMENT__
Index: content/svg/content/src/nsSVGAnimateElement.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsSVGAnimateElement.cpp
diff -N content/svg/content/src/nsSVGAnimateElement.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ content/svg/content/src/nsSVGAnimateElement.cpp	5 Nov 2005 04:39:26 -0000
@@ -0,0 +1,545 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SVG project.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsSVGElement.h"
+#include "nsIDOMSVGAnimateElement.h"
+#include "nsIDOMElementTimeControl.h"
+#include "nsISVGAnimationElement.h"
+#include "nsSVGAtoms.h"
+#include "nsISVGSVGElement.h"
+#include "nsIBindingManager.h"
+#include "nsIDocument.h"
+#include "nsISMILTimedElement.h"
+#include "nsISMILAnimationFunction.h"
+#include "nsISMILAnimElement.h"
+#include "nsISMILAnimationRegistry.h"
+#include "nsISMILTimeClient.h"
+#include "nsISMILComposable.h"
+
+typedef nsSVGElement nsSVGAnimateElementBase;
+
+class nsSVGAnimateElement : public nsSVGAnimateElementBase,
+                            public nsIDOMSVGAnimateElement,
+                              // : nsIDOMSVGAnimationElement
+                            public nsIDOMElementTimeControl,
+                            public nsISVGAnimationElement
+{
+protected:
+  friend nsresult NS_NewSVGAnimateElement(nsIContent **aResult,
+                                          nsINodeInfo *aNodeInfo);
+  nsSVGAnimateElement(nsINodeInfo* aNodeInfo);
+  nsresult Init();
+
+public:
+  // interfaces:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIDOMSVGANIMATEELEMENT
+  NS_DECL_NSIDOMSVGANIMATIONELEMENT
+
+  NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsSVGAnimateElementBase::)
+  NS_FORWARD_NSIDOMELEMENT(nsSVGAnimateElementBase::)
+  NS_FORWARD_NSIDOMSVGELEMENT(nsSVGAnimateElementBase::)
+  NS_FORWARD_SAFE_NSIDOMELEMENTTIMECONTROL(mTimeControl)
+
+  // nsISVGAnimationElement
+  virtual void     SetDocumentPosition(PRUint16 aDocPosition);
+
+  // nsISVGContent specializations
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                              nsIContent* aBindingParent,
+                              PRBool aCompileEventHandlers);
+  virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
+                              PRBool aNullParent = PR_TRUE);
+
+  // nsIContent specializations
+  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                           nsIAtom* aPrefix, const nsAString& aValue,
+                           PRBool aNotify);
+  virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
+                             PRBool aNotify);
+
+protected:
+  // Implementation helpers
+  nsISMILAnimationRegistry*          GetAnimationRegistry();
+  nsIContent*                        GetParentElement();
+  void                               UpdateTargetElement();
+  nsISMILAnimAttr*                   GetTargetAttribute();
+  void                               UpdateTargetAttribute();
+  void                               SetAnimationProperties();
+
+  nsWeakPtr                          mTargetElement;
+  nsRefPtr<nsISMILAnimationFunction> mAnimation;
+  nsCOMPtr<nsISMILTimedElement>      mTimedElement;
+  nsCOMPtr<nsIDOMElementTimeControl> mTimeControl; // QI'ed version of the above
+};
+
+NS_IMPL_NS_NEW_SVG_ELEMENT(Animate)
+
+
+//----------------------------------------------------------------------
+// nsISupports methods
+
+NS_IMPL_ADDREF_INHERITED(nsSVGAnimateElement,nsSVGAnimateElementBase)
+NS_IMPL_RELEASE_INHERITED(nsSVGAnimateElement,nsSVGAnimateElementBase)
+
+NS_INTERFACE_MAP_BEGIN(nsSVGAnimateElement)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMElement)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGElement)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimationElement)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimateElement)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMElementTimeControl)
+  NS_INTERFACE_MAP_ENTRY(nsISVGAnimationElement)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGAnimateElement)
+NS_INTERFACE_MAP_END_INHERITING(nsSVGAnimateElementBase)
+
+//----------------------------------------------------------------------
+// Implementation
+
+nsSVGAnimateElement::nsSVGAnimateElement(nsINodeInfo *aNodeInfo)
+  : nsSVGAnimateElementBase(aNodeInfo)
+{
+}
+
+nsresult
+nsSVGAnimateElement::Init()
+{
+  mTimedElement = NS_NewSMILTimedElement();
+  NS_ENSURE_TRUE(mTimedElement, NS_ERROR_FAILURE);
+
+  mTimeControl = do_QueryInterface(mTimedElement);
+  NS_ENSURE_TRUE(mTimeControl, NS_ERROR_FAILURE);
+
+  mAnimation = NS_NewSMILAnimationFunction();
+  NS_ENSURE_TRUE(mAnimation, NS_ERROR_FAILURE);
+
+  return NS_OK;
+}
+
+//----------------------------------------------------------------------
+// nsIDOMSVGAnimationElement methods
+
+/* readonly attribute SVGElement targetElement; */
+NS_IMETHODIMP
+nsSVGAnimateElement::GetTargetElement(nsIDOMSVGElement * *aTarget)
+{
+  if (mTargetElement) {
+    nsCOMPtr<nsIDOMSVGElement> target = do_QueryReferent(mTargetElement);
+    NS_IF_RELEASE(*aTarget);
+    NS_IF_ADDREF(*aTarget = target);
+  } else {
+    *aTarget = nsnull;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSVGAnimateElement::GetStartTime(float* retval)
+{
+  // XXX
+  (void)retval;
+  NS_NOTYETIMPLEMENTED("nsSVGAnimateElement::GetStartTime");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsSVGAnimateElement::GetCurrentTime(float* retval)
+{
+  // XXX
+  (void)retval;
+  NS_NOTYETIMPLEMENTED("nsSVGAnimateElement::GetStartTime");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsSVGAnimateElement::GetSimpleDuration(float* retval)
+{
+  // XXX
+  (void)retval;
+  NS_NOTYETIMPLEMENTED("nsSVGAnimateElement::GetStartTime");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+//----------------------------------------------------------------------
+// nsIDOMNode methods
+
+NS_IMPL_DOM_CLONENODE_WITH_INIT(nsSVGAnimateElement)
+
+//----------------------------------------------------------------------
+// nsISVGAnimationElement methods
+
+void
+nsSVGAnimateElement::SetDocumentPosition(PRUint16 aDocPosition)
+{
+  if (mAnimation->GetTargetAttribute())
+    mAnimation->SetDocumentPosition(aDocPosition);
+}
+
+//----------------------------------------------------------------------
+// nsISVGContent methods
+
+nsresult
+nsSVGAnimateElement::BindToTree(nsIDocument* aDocument,
+                                nsIContent* aParent,
+                                nsIContent* aBindingParent,
+                                PRBool aCompileEventHandlers)
+{
+  nsresult rv = nsSVGAnimateElementBase::BindToTree(aDocument, aParent,
+                                                    aBindingParent,
+                                                    aCompileEventHandlers);
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  nsCOMPtr<nsIDOMSVGSVGElement> ownerDOMSVG;
+  rv = GetOwnerSVGElement(getter_AddRefs(ownerDOMSVG));
+  
+  if (NS_FAILED(rv) || !ownerDOMSVG)
+    // No use proceeding. We don't have an SVG parent (yet) so we won't be able
+    // to register ourselves etc. Maybe next time we'll have more luck.
+    // (This sort of situation will arise a lot when trees are being constructed
+    // piece by piece via script)
+    return NS_OK;
+
+  nsCOMPtr<nsISMILAnimationRegistry> registry = GetAnimationRegistry();
+  if (!registry)
+    // Registry hasn't been created yet. This will be created when the SVG
+    // parent is bound.
+    return NS_OK;
+
+  UpdateTargetElement();
+  
+  nsCOMPtr<nsISVGSVGElement> ownerSVG(do_QueryInterface(ownerDOMSVG, &rv));
+  ownerSVG->EnumerateAnimationNodes();
+  
+  rv = registry->RegisterTimedElement(mTimedElement);
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  return rv;
+}
+
+void
+nsSVGAnimateElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
+{
+  nsCOMPtr<nsISMILAnimationRegistry> registry = GetAnimationRegistry();
+
+  if (mAnimation->GetTargetAttribute()) {
+      if (registry) {
+        nsCOMPtr<nsISMILComposable> composable(do_QueryInterface(mAnimation));
+        registry->UnregisterComposable(composable);
+      }
+      mAnimation->SetTargetAttribute(nsnull);
+  }
+
+  if (registry)
+    registry->UnregisterTimedElement(mTimedElement);
+
+  nsSVGAnimateElementBase::UnbindFromTree(aDeep, aNullParent);
+}
+
+//----------------------------------------------------------------------
+// nsIContent methods
+
+nsresult
+nsSVGAnimateElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                             nsIAtom* aPrefix, const nsAString& aValue,
+                             PRBool aNotify)
+{
+  nsresult rv = nsSVGAnimateElementBase::SetAttr(aNameSpaceID, aName, aPrefix,
+                                                 aValue, aNotify);
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  if (aNameSpaceID != kNameSpaceID_None)
+    return NS_OK;
+  
+  if (aName == nsSVGAtoms::attributeName) {
+    UpdateTargetAttribute();
+    return NS_OK;
+  }
+
+  /*
+   * Animation properties
+   */
+  if (mAnimation->GetTargetAttribute()) {
+    if (aName == nsSVGAtoms::by)
+      return mAnimation->SetBy(aValue);
+    if (aName == nsSVGAtoms::from)
+      return mAnimation->SetFrom(aValue);
+    if (aName == nsSVGAtoms::to)
+      return mAnimation->SetTo(aValue);
+    if (aName == nsSVGAtoms::values)
+      return mAnimation->SetValues(aValue);
+  }
+  if (aName == nsSVGAtoms::accumulate)
+    return mAnimation->SetAccumulate(aValue);
+  if (aName == nsSVGAtoms::additive)
+    return mAnimation->SetAdditive(aValue);
+  if (aName == nsSVGAtoms::calcMode)
+    return mAnimation->SetCalcMode(aValue);
+  if (aName == nsSVGAtoms::keyTimes)
+    return mAnimation->SetKeyTimes(aValue);
+  if (aName == nsSVGAtoms::keySplines)
+    return mAnimation->SetKeySplines(aValue);
+
+  /*
+   * Timing properties
+   */
+  if (aName == nsSVGAtoms::begin)
+    return mTimedElement->SetBeginSpec(aValue);
+  if (aName == nsSVGAtoms::dur)
+    return mTimedElement->SetSimpleDuration(aValue);
+  if (aName == nsSVGAtoms::end)
+    return mTimedElement->SetEndSpec(aValue);
+  if (aName == nsSVGAtoms::fill)
+    return mTimedElement->SetFillMode(aValue);
+  if (aName == nsSVGAtoms::max)
+    return mTimedElement->SetMax(aValue);
+  if (aName == nsSVGAtoms::min)
+    return mTimedElement->SetMin(aValue);
+  if (aName == nsSVGAtoms::repeatCount)
+    return mTimedElement->SetRepeatCount(aValue);
+  if (aName == nsSVGAtoms::repeatDur)
+    return mTimedElement->SetRepeatDur(aValue);
+  if (aName == nsSVGAtoms::restart)
+    return mTimedElement->SetRestart(aValue);
+
+  return rv;
+}
+
+nsresult
+nsSVGAnimateElement::UnsetAttr(PRInt32 aNameSpaceID,
+                               nsIAtom* aAttribute, PRBool aNotify)
+{
+  nsresult rv = nsSVGAnimateElementBase::UnsetAttr(aNameSpaceID, aAttribute,
+                                                   aNotify);
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  if (aNameSpaceID != kNameSpaceID_None)
+    return NS_OK;
+
+  if (aAttribute == nsSVGAtoms::attributeName) {
+    UpdateTargetAttribute();
+    return NS_OK;
+  }
+
+  // 
+  // Animation properties
+  //
+  if (aAttribute == nsSVGAtoms::accumulate)
+    mAnimation->UnsetAccumulate();
+  else if (aAttribute == nsSVGAtoms::additive)
+    mAnimation->UnsetAdditive();
+  else if (aAttribute == nsSVGAtoms::by)
+    mAnimation->UnsetBy();
+  else if (aAttribute == nsSVGAtoms::calcMode)
+    mAnimation->UnsetCalcMode();
+  else if (aAttribute == nsSVGAtoms::from)
+    mAnimation->UnsetFrom();
+  else if (aAttribute == nsSVGAtoms::keyTimes)
+    mAnimation->UnsetKeyTimes();
+  else if (aAttribute == nsSVGAtoms::keySplines)
+    mAnimation->UnsetKeySplines();
+  else if (aAttribute == nsSVGAtoms::to)
+    mAnimation->UnsetTo();
+  else if (aAttribute == nsSVGAtoms::values)
+    mAnimation->UnsetValues();
+
+  //
+  // Timing properties
+  //
+  if (aAttribute == nsSVGAtoms::begin)
+    mTimedElement->UnsetBeginSpec();
+  else if (aAttribute == nsSVGAtoms::dur)
+    mTimedElement->UnsetSimpleDuration();
+  else if (aAttribute == nsSVGAtoms::end)
+    mTimedElement->UnsetEndSpec();
+  else if (aAttribute == nsSVGAtoms::fill)
+    mTimedElement->UnsetFillMode();
+  else if (aAttribute == nsSVGAtoms::max)
+    mTimedElement->UnsetMax();
+  else if (aAttribute == nsSVGAtoms::min)
+    mTimedElement->UnsetMin();
+  else if (aAttribute == nsSVGAtoms::repeatCount)
+    mTimedElement->UnsetRepeatCount();
+  else if (aAttribute == nsSVGAtoms::repeatDur)
+    mTimedElement->UnsetRepeatDur();
+  else if (aAttribute == nsSVGAtoms::restart)
+    mTimedElement->UnsetRestart();
+
+  return NS_OK;
+}
+
+//----------------------------------------------------------------------
+// Implementation helpers
+
+nsISMILAnimationRegistry*
+nsSVGAnimateElement::GetAnimationRegistry()
+{
+  nsISMILAnimationRegistry*     result = nsnull;
+  nsCOMPtr<nsIDOMSVGSVGElement> ownerDOMSVG;
+
+  nsresult rv = GetOwnerSVGElement(getter_AddRefs(ownerDOMSVG));
+
+  if (NS_SUCCEEDED(rv) && ownerDOMSVG) {
+    nsCOMPtr<nsISVGSVGElement> ownerSVG( do_QueryInterface(ownerDOMSVG, &rv) );
+
+    if (ownerSVG)
+      result = ownerSVG->GetAnimationRegistry();
+  }
+
+  return result;
+}
+
+nsIContent*
+nsSVGAnimateElement::GetParentElement()
+{
+  nsIContent*         result = nsnull;
+  nsIBindingManager*  bindingManager = nsnull;
+  nsIDocument*        ownerDoc = GetOwnerDoc();
+
+  if (ownerDoc)
+    bindingManager = ownerDoc->BindingManager();
+
+  if (bindingManager)
+    // we have a binding manager -- do we have an anonymous parent?
+    bindingManager->GetInsertionParent(this, &result);
+
+  if (!result)
+    // if we didn't find an anonymous parent, use the explicit one,
+    // whether it's null or not...
+    result = GetParent();
+
+  return result;
+}
+
+void
+nsSVGAnimateElement::UpdateTargetElement()
+{
+  // XXX Follow xlink:href attributes when provided
+  
+  nsCOMPtr<nsIContent> target = GetParentElement();
+  if (!target)
+    return;
+
+  nsWeakPtr targetElement = do_GetWeakReference(target);
+  if (mTargetElement != targetElement || !mAnimation->GetTargetAttribute()) {
+    mTargetElement = targetElement;
+    UpdateTargetAttribute();
+  }
+}
+
+nsISMILAnimAttr*
+nsSVGAnimateElement::GetTargetAttribute()
+{
+  nsISMILAnimAttr* result = nsnull;
+
+  if (mTargetElement) {
+    nsAutoString attributeName;
+
+    GetAttr(kNameSpaceID_None, nsSVGAtoms::attributeName, attributeName);
+
+    nsCOMPtr<nsIAtom> attributeAtom( do_GetAtom(attributeName) );
+    nsCOMPtr<nsISMILAnimElement> 
+      targetElement(do_QueryReferent(mTargetElement));
+
+    if (targetElement && attributeAtom) {
+      result = 
+        targetElement->GetAnimAttribute(kNameSpaceID_None, attributeAtom);
+    }
+  }
+
+  return result;
+}
+
+void
+nsSVGAnimateElement::UpdateTargetAttribute()
+{
+  // XXX Implement XML vs CSS vs auto attribute types
+  nsresult rv;
+  
+  if (mTargetElement) {
+    nsCOMPtr<nsISMILAnimAttr> targetAttribute = GetTargetAttribute();
+
+    if (targetAttribute) {
+      rv = mAnimation->SetTargetAttribute(targetAttribute);
+      NS_ENSURE_SUCCESS(rv,);
+
+      SetAnimationProperties();
+
+      nsCOMPtr<nsISMILTimeClient> timeClient( do_QueryInterface(mAnimation) );
+      NS_ENSURE_TRUE(timeClient,);
+      mTimedElement->SetTimeClient(timeClient);
+
+      nsCOMPtr<nsISMILAnimationRegistry> registry = GetAnimationRegistry();
+      NS_ENSURE_TRUE(registry,);
+
+      nsCOMPtr<nsISMILComposable> composable( do_QueryInterface(mAnimation) );
+      NS_ENSURE_TRUE(composable,);
+
+      registry->RegisterComposable(targetAttribute, composable);
+    } else {
+      mAnimation->SetTargetAttribute(nsnull);
+      // Attribute doesn't exist or it isn't animatable, mark document in error
+    }
+  }
+}
+
+void
+nsSVGAnimateElement::SetAnimationProperties()
+{
+  nsAutoString result;
+
+  NS_ENSURE_TRUE(mAnimation,);
+  NS_ENSURE_TRUE(mAnimation->GetTargetAttribute(),);
+
+  if (HasAttr(kNameSpaceID_None, nsSVGAtoms::by)) {
+    if (NS_SUCCEEDED(GetAttr(kNameSpaceID_None, nsSVGAtoms::by, result)))
+      mAnimation->SetBy(result);
+  }
+  if (HasAttr(kNameSpaceID_None, nsSVGAtoms::from)) {
+    if (NS_SUCCEEDED(GetAttr(kNameSpaceID_None, nsSVGAtoms::from, result)))
+      mAnimation->SetFrom(result);
+  }
+  if (HasAttr(kNameSpaceID_None, nsSVGAtoms::to)) {
+    if (NS_SUCCEEDED(GetAttr(kNameSpaceID_None, nsSVGAtoms::to, result)))
+      mAnimation->SetTo(result);
+  }
+  if (HasAttr(kNameSpaceID_None, nsSVGAtoms::values)) {
+    if (NS_SUCCEEDED(GetAttr(kNameSpaceID_None, nsSVGAtoms::values, result)))
+      mAnimation->SetValues(result);
+  }
+}
+
Index: content/svg/content/src/nsSVGAnimatedLength.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsSVGAnimatedLength.cpp,v
retrieving revision 1.8
diff -u -r1.8 nsSVGAnimatedLength.cpp
--- content/svg/content/src/nsSVGAnimatedLength.cpp	31 Jan 2005 19:45:10 -0000	1.8
+++ content/svg/content/src/nsSVGAnimatedLength.cpp	5 Nov 2005 04:39:26 -0000
@@ -41,6 +41,10 @@
 #include "nsSVGAnimatedLength.h"
 #include "nsSVGLength.h"
 #include "nsContentUtils.h"
+#ifdef MOZ_SMIL
+#include "nsISMILAnimVal.h"
+#include "nsISMILAnimAttr.h"
+#endif // MOZ_SMIL
 
 
 ////////////////////////////////////////////////////////////////////////
@@ -49,6 +53,9 @@
 class nsSVGAnimatedLength : public nsIDOMSVGAnimatedLength,
                             public nsSVGValue,
                             public nsISVGValueObserver,
+#ifdef MOZ_SMIL
+                            public nsISMILAnimAttr,
+#endif // MOZ_SMIL
                             public nsSupportsWeakReference
 {
 protected:
@@ -74,12 +81,23 @@
                                      modificationType aModType);
   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
                                      modificationType aModType);
+
+#ifdef MOZ_SMIL
+  // nsISMILAnimAttr
+  virtual nsresult GetBaseValue(nsISMILAnimVal& aValue);
+  virtual nsresult SetAnimValue(const nsISMILAnimVal& aValue);
+  virtual nsISMILAnimVal* Create() const;
+  virtual nsISMILAnimVal* CreateFromSpec(const nsAString& aSpec) const;
+#endif // MOZ_SMIL
   
   // nsISupportsWeakReference
   // implementation inherited from nsSupportsWeakReference
   
 protected:
   nsCOMPtr<nsIDOMSVGLength> mBaseVal;
+#ifdef MOZ_SMIL
+  nsCOMPtr<nsISVGLength> mAnimVal;
+#endif // MOZ_SMIL
 };
 
 
@@ -108,6 +126,12 @@
   NS_ASSERTION(val, "baseval needs to implement nsISVGValue interface");
   if (!val) return;
   val->AddObserver(this);
+#ifdef MOZ_SMIL
+  nsCOMPtr<nsISVGLength> length = do_QueryInterface(mBaseVal);
+  NS_ENSURE_TRUE(length,);
+  nsresult rv = NS_NewSVGLength(getter_AddRefs(mAnimVal), *length);
+  NS_ENSURE_SUCCESS(rv,);
+#endif
 }
 
 //----------------------------------------------------------------------
@@ -122,6 +146,9 @@
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedLength)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
+#ifdef MOZ_SMIL
+  NS_INTERFACE_MAP_ENTRY(nsISMILAnimAttr)
+#endif // MOZ_SMIL
   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGAnimatedLength)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
 NS_INTERFACE_MAP_END
@@ -159,7 +186,11 @@
 NS_IMETHODIMP
 nsSVGAnimatedLength::GetAnimVal(nsIDOMSVGLength * *aAnimVal)
 {
+#ifndef MOZ_SMIL
   *aAnimVal = mBaseVal;
+#else
+  *aAnimVal = mAnimVal;
+#endif
   NS_ADDREF(*aAnimVal);
   return NS_OK;
 }
@@ -183,6 +214,45 @@
   return NS_OK;
 }
 
+#ifdef MOZ_SMIL
+//----------------------------------------------------------------------
+// nsISMILAnimAttr methods
+
+nsresult
+nsSVGAnimatedLength::GetBaseValue(nsISMILAnimVal& aValue)
+{
+  nsCOMPtr<nsISVGLength> length( do_QueryInterface(mBaseVal) );
+  NS_ENSURE_TRUE(length, NS_ERROR_FAILURE);
+  length->GetAnimValue(aValue);
+  return NS_OK;
+}
+
+nsresult
+nsSVGAnimatedLength::SetAnimValue(const nsISMILAnimVal& aValue)
+{
+  WillModify(mod_other);
+  mAnimVal->SetAnimValue(aValue);
+  DidModify(mod_other);
+  return NS_OK;
+}
+
+nsISMILAnimVal*
+nsSVGAnimatedLength::Create() const
+{
+  nsCOMPtr<nsISVGLength> length( do_QueryInterface(mBaseVal) );
+  NS_ENSURE_TRUE(length, nsnull);
+  return length->GetNewSMILValue();
+}
+
+nsISMILAnimVal*
+nsSVGAnimatedLength::CreateFromSpec(const nsAString& aSpec) const
+{
+  nsCOMPtr<nsISVGLength> length( do_QueryInterface(mBaseVal) );
+  NS_ENSURE_TRUE(length, nsnull);
+  return length->GetNewSMILValue(aSpec);
+}
+#endif // MOZ_SMIL
+
 ////////////////////////////////////////////////////////////////////////
 // Exported creation functions
 
@@ -205,3 +275,4 @@
   
   return NS_OK;
 }
+
Index: content/svg/content/src/nsSVGAtomList.h
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsSVGAtomList.h,v
retrieving revision 1.26
diff -u -r1.26 nsSVGAtomList.h
--- content/svg/content/src/nsSVGAtomList.h	13 Sep 2005 22:38:26 -0000	1.26
+++ content/svg/content/src/nsSVGAtomList.h	5 Nov 2005 04:39:27 -0000
@@ -55,6 +55,9 @@
  ******/
 
 // tags
+#ifdef MOZ_SMIL
+SVG_ATOM(animate, "animate")
+#endif
 SVG_ATOM(circle, "circle")
 SVG_ATOM(clipPath, "clipPath")
 SVG_ATOM(defs, "defs")
@@ -248,6 +251,29 @@
 SVG_ATOM(y1, "y1")
 SVG_ATOM(y2, "y2")
 SVG_ATOM(zoomAndPan, "zoomAndPan")
+
+// SMIL properties (to be integrated with the others later)
+#ifdef MOZ_SMIL
+SVG_ATOM(accumulate, "accumulate")
+SVG_ATOM(additive, "additive")
+SVG_ATOM(attributeName, "attributeName")
+SVG_ATOM(attributeType, "attributeType")
+SVG_ATOM(begin, "begin")
+SVG_ATOM(by, "by")
+SVG_ATOM(calcMode, "calcMode")
+SVG_ATOM(dur, "dur")
+SVG_ATOM(end, "end")
+SVG_ATOM(from, "from")
+SVG_ATOM(keySplines, "keySplines")
+SVG_ATOM(keyTimes, "keyTimes")
+SVG_ATOM(max, "max")
+SVG_ATOM(min, "min")
+SVG_ATOM(repeatCount, "repeatCount")
+SVG_ATOM(repeatDur, "repeatDur")
+SVG_ATOM(restart, "restart")
+SVG_ATOM(to, "to")
+SVG_ATOM(values, "values")
+#endif
   
 // transformation keywords
 SVG_ATOM(matrix, "matrix")
Index: content/svg/content/src/nsSVGElement.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsSVGElement.cpp,v
retrieving revision 1.83
diff -u -r1.83 nsSVGElement.cpp
--- content/svg/content/src/nsSVGElement.cpp	2 Nov 2005 00:41:45 -0000	1.83
+++ content/svg/content/src/nsSVGElement.cpp	5 Nov 2005 04:39:29 -0000
@@ -92,6 +92,9 @@
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
   NS_INTERFACE_MAP_ENTRY(nsISVGContent)
+#ifdef MOZ_SMIL
+  NS_INTERFACE_MAP_ENTRY(nsISMILAnimElement)
+#endif // MOZ_SMIL
 // provided by nsGenericElement:
 //  NS_INTERFACE_MAP_ENTRY(nsIContent)
 NS_INTERFACE_MAP_END_INHERITING(nsGenericElement)
@@ -764,3 +767,26 @@
 
   return aAttr;
 }
+
+#ifdef MOZ_SMIL
+//----------------------------------------------------------------------
+// nsISMILAnimElement methods
+
+// This should be overridden as necessary, e.g. to ensure some attributes are
+// not animatable
+
+nsISMILAnimAttr*
+nsSVGElement::GetAnimAttribute(PRInt32 aNamespaceID, nsIAtom* aName)
+{
+  NS_ENSURE_TRUE(aName, nsnull);
+
+  nsCOMPtr<nsISMILAnimAttr> result;
+  nsCOMPtr<nsISVGValue> attr = GetMappedAttribute(aNamespaceID, aName);
+
+  if (attr)
+    result = do_QueryInterface(attr);
+
+  return result;
+}
+#endif // MOZ_SMIL
+
Index: content/svg/content/src/nsSVGElement.h
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsSVGElement.h,v
retrieving revision 1.49
diff -u -r1.49 nsSVGElement.h
--- content/svg/content/src/nsSVGElement.h	2 Nov 2005 00:41:45 -0000	1.49
+++ content/svg/content/src/nsSVGElement.h	5 Nov 2005 04:39:29 -0000
@@ -53,10 +53,16 @@
 #include "nsWeakReference.h"
 #include "nsISVGContent.h"
 #include "nsICSSStyleRule.h"
+#ifdef MOZ_SMIL
+#include "nsISMILAnimElement.h"
+#endif // MOZ_SMIL
 
 class nsSVGElement : public nsGenericElement,    // :nsIXMLContent:nsIContent
                      public nsISVGValueObserver, 
                      public nsSupportsWeakReference, // :nsISupportsWeakReference
+#ifdef MOZ_SMIL
+                     public nsISMILAnimElement,
+#endif // MOZ_SMIL
                      public nsISVGContent
 {
 protected:
@@ -114,6 +120,12 @@
 
   // nsISVGContent
   virtual void ParentChainChanged(); 
+
+#ifdef MOZ_SMIL
+  // nsISVGAnimationTarget
+  virtual nsISMILAnimAttr*
+  GetAnimAttribute(PRInt32 aNamespaceID, nsIAtom* aName);
+#endif // MOZ_SMIL
   
 protected:
   virtual nsresult BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
Index: content/svg/content/src/nsSVGElementFactory.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsSVGElementFactory.cpp,v
retrieving revision 1.30
diff -u -r1.30 nsSVGElementFactory.cpp
--- content/svg/content/src/nsSVGElementFactory.cpp	24 Sep 2005 18:43:10 -0000	1.30
+++ content/svg/content/src/nsSVGElementFactory.cpp	5 Nov 2005 04:39:30 -0000
@@ -126,6 +126,10 @@
 NS_NewSVGFEUnimplementedMOZElement(nsIContent **aResult, nsINodeInfo *aNodeInfo);
 nsresult
 NS_NewSVGPatternElement(nsIContent **aResult, nsINodeInfo *aNodeInfo);
+#ifdef MOZ_SMIL
+nsresult
+NS_NewSVGAnimateElement(nsIContent **aResult, nsINodeInfo *aNodeInfo);
+#endif // MOZ_SMIL
 
 nsresult
 NS_NewSVGElement(nsIContent** aResult, nsINodeInfo *aNodeInfo)
@@ -233,6 +237,10 @@
     return NS_NewSVGFEUnimplementedMOZElement(aResult, aNodeInfo);
   if (name == nsSVGAtoms::pattern)
     return NS_NewSVGPatternElement(aResult, aNodeInfo);
+#ifdef MOZ_SMIL
+  if (name == nsSVGAtoms::animate)
+    return NS_NewSVGAnimateElement(aResult, aNodeInfo);
+#endif // MOZ_SMIL
 
   // if we don't know what to create, just create a standard xml element:
   return NS_NewXMLElement(aResult, aNodeInfo);
Index: content/svg/content/src/nsSVGLength.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsSVGLength.cpp,v
retrieving revision 1.21
diff -u -r1.21 nsSVGLength.cpp
--- content/svg/content/src/nsSVGLength.cpp	9 Aug 2005 13:53:00 -0000	1.21
+++ content/svg/content/src/nsSVGLength.cpp	5 Nov 2005 04:39:32 -0000
@@ -49,6 +49,106 @@
 #include "nsISVGValueUtils.h"
 #include "nsWeakReference.h"
 #include "nsContentUtils.h"
+#ifdef MOZ_SMIL
+#include "nsISMILAnimVal.h"
+#include "nsDOMError.h"
+
+class nsSVGLengthAnimVal : public nsISMILAnimVal
+{
+public:
+  nsSVGLengthAnimVal() : mCanonicalValue(0.0f) {}
+
+  NS_DECL_ISUPPORTS
+
+  virtual nsresult  ComputeDistance(const nsISMILAnimVal& aTo,
+                                    PRFloat64& aDistance) const;
+  virtual nsresult  Interpolate(const nsISMILAnimVal& aEndVal,
+                                float aUnitDistance,
+                                nsISMILAnimVal& aResult);
+  virtual nsresult  Add(const nsISMILAnimVal& aAddedVal);
+  virtual nsresult  Set(const nsISMILAnimVal& aNewVal);
+  virtual nsresult  Repeat(PRUint32 aCount,
+                           const nsISMILAnimVal* aRepeatValue /*= nsnull*/);
+
+  // nsWeakPtr mBase;
+  float     mCanonicalValue;
+};
+
+NS_IMPL_ISUPPORTS1(nsSVGLengthAnimVal,
+                   nsISMILAnimVal)
+
+nsresult
+nsSVGLengthAnimVal::ComputeDistance(const nsISMILAnimVal& aTo,
+                                    PRFloat64& aDistance) const
+{
+  (void)aTo;
+  aDistance = 0.0;
+  NS_NOTYETIMPLEMENTED("nsSVGLengthAnimVal::ComputeDistance");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+nsSVGLengthAnimVal::Interpolate(const nsISMILAnimVal& aEndValue,
+                                float aUnitDistance,
+                                nsISMILAnimVal& aResult)
+{
+  // We wouldn't have to cast away const-ness if GetValue was a const member.
+  nsSVGLengthAnimVal* end = (nsSVGLengthAnimVal*)&aEndValue;
+  NS_ENSURE_TRUE(end, NS_ERROR_FAILURE);
+
+  nsSVGLengthAnimVal* length = NS_STATIC_CAST(nsSVGLengthAnimVal*, &aResult);
+  NS_ENSURE_TRUE(length, NS_ERROR_FAILURE);
+
+  nsresult rv = NS_OK;
+
+  const float &startVal = mCanonicalValue;
+  const float &endVal = end->mCanonicalValue;
+
+  length->mCanonicalValue = (startVal + (endVal - startVal) * aUnitDistance);
+
+  return NS_OK;
+}
+
+nsresult
+nsSVGLengthAnimVal::Add(const nsISMILAnimVal& aAddedValue)
+{
+  // We wouldn't have to cast away const-ness if GetValue was a const member.
+  nsSVGLengthAnimVal* add = (nsSVGLengthAnimVal*)&aAddedValue;
+  NS_ENSURE_TRUE(add, NS_ERROR_FAILURE);
+
+  mCanonicalValue += add->mCanonicalValue;
+
+  return NS_OK;
+}
+
+nsresult
+nsSVGLengthAnimVal::Repeat(PRUint32 aCount,
+                           const nsISMILAnimVal* aRepeatValue)
+{
+  float value = mCanonicalValue;
+
+  if (aRepeatValue) {
+    // We wouldn't have to cast away const-ness if GetValue was a const member.
+    nsSVGLengthAnimVal* repeat = (nsSVGLengthAnimVal*)aRepeatValue;
+    NS_ENSURE_TRUE(repeat, NS_ERROR_FAILURE);
+    value = repeat->mCanonicalValue;
+  }
+
+  mCanonicalValue = value * (aCount + 1);
+
+  return NS_OK;
+}
+
+nsresult
+nsSVGLengthAnimVal::Set(const nsISMILAnimVal& aNewValue)
+{
+  nsSVGLengthAnimVal* length = (nsSVGLengthAnimVal*)&aNewValue;
+  NS_ENSURE_TRUE(length, NS_ERROR_FAILURE);
+
+  mCanonicalValue = length->mCanonicalValue;
+  return NS_OK;
+}
+#endif // MOZ_SMIL
 
 ////////////////////////////////////////////////////////////////////////
 // nsSVGLength class
@@ -65,6 +165,11 @@
 
   friend nsresult NS_NewSVGLength(nsISVGLength** result,
                                   const nsAString &value);
+
+#ifdef MOZ_SMIL
+  friend nsresult NS_NewSVGLength(nsISVGLength** result,
+                                  const nsISVGLength& base);
+#endif // MOZ_SMIL
   
   nsSVGLength(float value, PRUint16 unit);
   nsSVGLength();
@@ -79,6 +184,12 @@
 
   // nsISVGLength interface:
   NS_IMETHOD SetContext(nsSVGCoordCtx* context);
+#ifdef MOZ_SMIL
+  virtual nsISMILAnimVal* GetNewSMILValue();
+  virtual nsISMILAnimVal* GetNewSMILValue(const nsAString& aSpec);
+  virtual nsresult        GetAnimValue(nsISMILAnimVal& aValue);
+  virtual nsresult        SetAnimValue(const nsISMILAnimVal& aNewValue);
+#endif // MOZ_SMIL
   
   // nsISVGValue interface:
   NS_IMETHOD SetValueString(const nsAString& aValue);
@@ -95,6 +206,9 @@
   
 protected:
   // implementation helpers:
+  nsresult ParseStringValue(const nsAString &aValueAsString,
+                            float &aValue,
+                            PRUint16 &aUnits);
   float mmPerPixel();
   float AxisLength();
   PRBool IsValidUnitType(PRUint16 unit);
@@ -104,6 +218,10 @@
   float mValueInSpecifiedUnits;
   PRUint16 mSpecifiedUnitType;
   nsRefPtr<nsSVGCoordCtx> mContext;
+#ifdef MOZ_SMIL
+  nsRefPtr<nsSVGLength>   mRefLength;
+  PRPackedBool            mIsAnimated:1;
+#endif // MOZ_SMIL
 };
 
 
@@ -140,16 +258,42 @@
   return NS_OK;
 }  
 
+#ifdef MOZ_SMIL
+nsresult
+NS_NewSVGLength(nsISVGLength** result,
+                const nsISVGLength &ref)
+{
+  *result = nsnull;
+  nsSVGLength *pl = new nsSVGLength();
+  if (!pl)
+    return NS_ERROR_OUT_OF_MEMORY;
+  NS_ADDREF(pl);
+  const nsSVGLength* refLength = NS_STATIC_CAST(const nsSVGLength*, &ref);
+  if (!refLength) {
+    NS_RELEASE(pl);
+    return NS_ERROR_FAILURE;
+  }
+  pl->mRefLength = NS_CONST_CAST(nsSVGLength*, refLength);
+  *result = pl;
+  return NS_OK;
+}
+#endif // MOZ_SMIL
 
 nsSVGLength::nsSVGLength(float value,
                          PRUint16 unit)
     : mValueInSpecifiedUnits(value),
+#ifdef MOZ_SMIL
+      mIsAnimated(PR_FALSE),
+#endif // MOZ_SMIL
       mSpecifiedUnitType(unit)
 {
   // we don't have a context yet, so we don't call MaybeAddAsObserver()
 }
 
 nsSVGLength::nsSVGLength()
+#ifdef MOZ_SMIL
+    : mIsAnimated(PR_FALSE)
+#endif // MOZ_SMIL
 {
 }
 
@@ -215,6 +359,11 @@
 NS_IMETHODIMP
 nsSVGLength::GetUnitType(PRUint16 *aUnitType)
 {
+#ifdef MOZ_SMIL
+  if (mRefLength)
+    return mRefLength->GetUnitType(aUnitType);
+#endif // MOZ_SMIL
+
   *aUnitType = mSpecifiedUnitType;
   return NS_OK;
 }
@@ -223,6 +372,13 @@
 NS_IMETHODIMP
 nsSVGLength::GetValue(float *aValue)
 {
+#ifdef MOZ_SMIL
+  if (mRefLength && !mIsAnimated)
+    return mRefLength->GetValue(aValue);
+  if (mIsAnimated)
+    mSpecifiedUnitType = mRefLength->mSpecifiedUnitType;
+#endif // MOZ_SMIL
+
   switch (mSpecifiedUnitType) {
     case SVG_LENGTHTYPE_NUMBER:
     case SVG_LENGTHTYPE_PX:
@@ -266,6 +422,17 @@
 
   WillModify();
 
+#ifdef MOZ_SMIL
+  if (mRefLength && !mIsAnimated)
+    mIsAnimated = PR_TRUE;
+  if (mIsAnimated)
+    mSpecifiedUnitType = mRefLength->mSpecifiedUnitType;
+
+  // XXX This should really throw a modification not allowed error for animated
+  // values but we currently re-use this method to actually set the animated
+  // value
+#endif // MOZ_SMIL
+
   switch (mSpecifiedUnitType) {
     case SVG_LENGTHTYPE_NUMBER:
     case SVG_LENGTHTYPE_PX:
@@ -310,13 +477,25 @@
 NS_IMETHODIMP
 nsSVGLength::GetValueInSpecifiedUnits(float *aValueInSpecifiedUnits)
 {
+#ifdef MOZ_SMIL
+  if (mIsAnimated && mSpecifiedUnitType != mRefLength->mSpecifiedUnitType)
+    ConvertToSpecifiedUnits(mRefLength->mSpecifiedUnitType);
+#endif // MOZ_SMIL
+
   *aValueInSpecifiedUnits = mValueInSpecifiedUnits;
   return NS_OK;
 }
+
 NS_IMETHODIMP
 nsSVGLength::SetValueInSpecifiedUnits(float aValueInSpecifiedUnits)
 {
   WillModify();
+#ifdef MOZ_SMIL
+  if (mRefLength && mIsAnimated)
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  if (mRefLength)
+    return mRefLength->SetValueInSpecifiedUnits(aValueInSpecifiedUnits);
+#endif // MOZ_SMIL
   mValueInSpecifiedUnits = aValueInSpecifiedUnits;
   DidModify();
   return NS_OK;
@@ -326,6 +505,13 @@
 NS_IMETHODIMP
 nsSVGLength::GetValueAsString(nsAString & aValueAsString)
 {
+#ifdef MOZ_SMIL
+  if (mRefLength && !mIsAnimated)
+    mRefLength->GetValueAsString(aValueAsString);
+  if (mIsAnimated)
+    mSpecifiedUnitType = mRefLength->mSpecifiedUnitType;
+#endif // MOZ_SMIL
+
   PRUnichar buf[24];
   nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
                             NS_LITERAL_STRING("%g").get(),
@@ -379,65 +565,25 @@
 NS_IMETHODIMP
 nsSVGLength::SetValueAsString(const nsAString & aValueAsString)
 {
-  nsresult rv = NS_OK;
-  
-  char *str = ToNewCString(aValueAsString);
+  float    value;
+  PRUint16 unitType;
 
-  char* number = str;
-  while (*number && isspace(*number))
-    ++number;
-
-  if (*number) {
-    char *rest;
-    double value = PR_strtod(number, &rest);
-    if (rest!=number) {
-      const char* unitStr = nsCRT::strtok(rest, "\x20\x9\xD\xA", &rest);
-      PRUint16 unitType = SVG_LENGTHTYPE_UNKNOWN;
-      if (!unitStr || *unitStr=='\0') {
-        unitType = SVG_LENGTHTYPE_NUMBER;
-      }
-      else {
-        nsCOMPtr<nsIAtom> unitAtom = do_GetAtom(unitStr);
-        if (unitAtom == nsSVGAtoms::px)
-          unitType = SVG_LENGTHTYPE_PX;
-        else if (unitAtom == nsSVGAtoms::mm)
-          unitType = SVG_LENGTHTYPE_MM;
-        else if (unitAtom == nsSVGAtoms::cm)
-          unitType = SVG_LENGTHTYPE_CM;
-        else if (unitAtom == nsSVGAtoms::in)
-          unitType = SVG_LENGTHTYPE_IN;
-        else if (unitAtom == nsSVGAtoms::pt)
-          unitType = SVG_LENGTHTYPE_PT;
-        else if (unitAtom == nsSVGAtoms::pc)
-          unitType = SVG_LENGTHTYPE_PC;
-        else if (unitAtom == nsSVGAtoms::ems)
-          unitType = SVG_LENGTHTYPE_EMS;
-        else if (unitAtom == nsSVGAtoms::exs)
-          unitType = SVG_LENGTHTYPE_EXS;
-        else if (unitAtom == nsSVGAtoms::percentage)
-          unitType = SVG_LENGTHTYPE_PERCENTAGE;
-      }
-      if (IsValidUnitType(unitType)){
-        WillModify();
-        mValueInSpecifiedUnits = (float)value;
-        mSpecifiedUnitType     = unitType;
-        DidModify();
-      }
-      else { // parse error
-        // not a valid unit type
-        rv = NS_ERROR_FAILURE;
-        NS_ERROR("invalid length type");
-      }
-    }
-    else { // parse error
-      // no number
-      rv = NS_ERROR_FAILURE;
-    }
-  }
+  nsresult rv = ParseStringValue(aValueAsString, value, unitType);
+  if (NS_FAILED(rv))
+    return rv;
   
-  nsMemory::Free(str);
-    
-  return rv;
+  WillModify();
+#ifdef MOZ_SMIL
+  if (mRefLength && mIsAnimated)
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  if (mRefLength)
+    return mRefLength->SetValueAsString(aValueAsString);
+#endif // MOZ_SMIL
+  mValueInSpecifiedUnits = value;
+  mSpecifiedUnitType     = unitType;
+  DidModify();
+
+  return NS_OK;
 }
 
 /* void newValueSpecifiedUnits (in unsigned short unitType, in float valueInSpecifiedUnits); */
@@ -450,6 +596,12 @@
   PRBool observer_change = (unitType != mSpecifiedUnitType);
 
   WillModify();
+#ifdef MOZ_SMIL
+  if (mRefLength && mIsAnimated)
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  if (mRefLength)
+    return mRefLength->NewValueSpecifiedUnits(unitType, valueInSpecifiedUnits);
+#endif // MOZ_SMIL
   if (observer_change)
     MaybeRemoveAsObserver();
   mValueInSpecifiedUnits = valueInSpecifiedUnits;
@@ -471,6 +623,12 @@
   PRBool observer_change = (unitType != mSpecifiedUnitType);
 
   WillModify();
+#ifdef MOZ_SMIL
+  if (mRefLength && mIsAnimated)
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  if (mRefLength)
+    return mRefLength->ConvertToSpecifiedUnits(unitType);
+#endif // MOZ_SMIL
   if (observer_change)
     MaybeRemoveAsObserver();
   float valueInUserUnits;
@@ -529,10 +687,142 @@
   return NS_OK;
 }
 
+#ifdef MOZ_SMIL
+nsISMILAnimVal*
+nsSVGLength::GetNewSMILValue()
+{
+  nsSVGLengthAnimVal* val = new nsSVGLengthAnimVal();
+  if (!val)
+    return nsnull;
+  GetValue(&(val->mCanonicalValue));
+  return val;
+}
+
+nsISMILAnimVal*
+nsSVGLength::GetNewSMILValue(const nsAString& aSpec)
+{
+  nsSVGLengthAnimVal* val = new nsSVGLengthAnimVal();
+
+  // Look away...
+  float oldValue = mValueInSpecifiedUnits;
+  PRUint16 oldUnits = mSpecifiedUnitType;
+
+  float value;
+  PRUint16 units;
+  nsresult rv = ParseStringValue(aSpec, value, units);
+  if (NS_FAILED(rv))
+  {
+    delete val;
+    return nsnull;
+  }
+
+  mValueInSpecifiedUnits = value;
+  mSpecifiedUnitType = units;
+  GetValue(&(val->mCanonicalValue));
+  mValueInSpecifiedUnits = oldValue;
+  mSpecifiedUnitType = oldUnits;
+  // I warned you!
+  // (This is all temporary code--it's not worth refactoring nsSVGLength to make
+  // this neater until we decide how to support animated values)
+
+  return val;
+}
+
+nsresult
+nsSVGLength::GetAnimValue(nsISMILAnimVal& aValue)
+{
+  nsSVGLengthAnimVal* length = 
+    NS_STATIC_CAST(nsSVGLengthAnimVal*, &aValue);
+  NS_ENSURE_TRUE(length,NS_ERROR_FAILURE);
+  GetValue(&(length->mCanonicalValue));
+
+  return NS_OK;
+}
+
+nsresult
+nsSVGLength::SetAnimValue(const nsISMILAnimVal& aNewValue)
+{
+  const nsSVGLengthAnimVal* length = 
+    NS_STATIC_CAST(const nsSVGLengthAnimVal*, &aNewValue);
+  NS_ENSURE_TRUE(length,NS_ERROR_FAILURE);
+
+  WillModify();
+  mIsAnimated = PR_TRUE;
+  SetValue(length->mCanonicalValue);
+  DidModify();
+
+  return NS_OK;
+}
+#endif // MOZ_SMIL
 
 //----------------------------------------------------------------------
 // Implementation helpers:
 
+nsresult
+nsSVGLength::ParseStringValue(const nsAString & aValueAsString,
+                              float &aValue,
+                              PRUint16 &aUnits)
+{
+  nsresult rv = NS_OK;
+  
+  char *str = ToNewCString(aValueAsString);
+
+  char* number = str;
+  while (*number && isspace(*number))
+    ++number;
+
+  if (*number) {
+    char *rest;
+    double value = PR_strtod(number, &rest);
+    if (rest!=number) {
+      const char* unitStr = nsCRT::strtok(rest, "\x20\x9\xD\xA", &rest);
+      PRUint16 unitType = SVG_LENGTHTYPE_UNKNOWN;
+      if (!unitStr || *unitStr=='\0') {
+        unitType = SVG_LENGTHTYPE_NUMBER;
+      }
+      else {
+        nsCOMPtr<nsIAtom> unitAtom = do_GetAtom(unitStr);
+        if (unitAtom == nsSVGAtoms::px)
+          unitType = SVG_LENGTHTYPE_PX;
+        else if (unitAtom == nsSVGAtoms::mm)
+          unitType = SVG_LENGTHTYPE_MM;
+        else if (unitAtom == nsSVGAtoms::cm)
+          unitType = SVG_LENGTHTYPE_CM;
+        else if (unitAtom == nsSVGAtoms::in)
+          unitType = SVG_LENGTHTYPE_IN;
+        else if (unitAtom == nsSVGAtoms::pt)
+          unitType = SVG_LENGTHTYPE_PT;
+        else if (unitAtom == nsSVGAtoms::pc)
+          unitType = SVG_LENGTHTYPE_PC;
+        else if (unitAtom == nsSVGAtoms::ems)
+          unitType = SVG_LENGTHTYPE_EMS;
+        else if (unitAtom == nsSVGAtoms::exs)
+          unitType = SVG_LENGTHTYPE_EXS;
+        else if (unitAtom == nsSVGAtoms::percentage)
+          unitType = SVG_LENGTHTYPE_PERCENTAGE;
+      }
+      if (IsValidUnitType(unitType)){
+        aValue = (float)value;
+        aUnits = unitType;
+      }
+      else { // parse error
+        // not a valid unit type
+        rv = NS_ERROR_FAILURE;
+        NS_ERROR("invalid length type");
+      }
+    }
+    else { // parse error
+      // no number
+      rv = NS_ERROR_FAILURE;
+    }
+  }
+  
+  nsMemory::Free(str);
+    
+  return rv;
+}
+
+
 float nsSVGLength::mmPerPixel()
 {
   if (!mContext) {
Index: content/svg/content/src/nsSVGLength.h
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsSVGLength.h,v
retrieving revision 1.4
diff -u -r1.4 nsSVGLength.h
--- content/svg/content/src/nsSVGLength.h	17 Apr 2004 21:52:20 -0000	1.4
+++ content/svg/content/src/nsSVGLength.h	5 Nov 2005 04:39:32 -0000
@@ -51,6 +51,12 @@
 NS_NewSVGLength(nsISVGLength** result,
                 const nsAString &value);
 
+#ifdef MOZ_SMIL
+nsresult
+NS_NewSVGLength(nsISVGLength** result,
+                const nsISVGLength &base);
+#endif // MOZ_SMIL
+
 // XXX we'll need this prototype-based stuff to support unsetting:
 //nsresult NS_NewSVGLength(nsIDOMSVGLength** result,
 //                         nsIDOMSVGLength*  prototype);
Index: content/svg/content/src/nsSVGSVGElement.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/svg/content/src/nsSVGSVGElement.cpp,v
retrieving revision 1.59
diff -u -r1.59 nsSVGSVGElement.cpp
--- content/svg/content/src/nsSVGSVGElement.cpp	2 Nov 2005 00:41:45 -0000	1.59
+++ content/svg/content/src/nsSVGSVGElement.cpp	5 Nov 2005 04:39:36 -0000
@@ -71,6 +71,16 @@
 #include "nsISVGChildFrame.h"
 #include "nsGUIEvent.h"
 
+#ifdef MOZ_SMIL
+#include "nsISMILAnimationController.h"
+#include "nsISMILAnimationRegistry.h"
+#include "nsISMILAnimationObserver.h"
+#include "nsISVGAnimationElement.h"
+#include "nsIContentIterator.h"
+
+nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult);
+#endif // MOZ_SMIL
+
 typedef nsSVGStylableElement nsSVGSVGElementBase;
 
 class nsSVGSVGElement : public nsSVGSVGElementBase,
@@ -78,6 +88,9 @@
                         public nsIDOMSVGFitToViewBox,
                         public nsIDOMSVGLocatable,
                         public nsIDOMSVGZoomAndPan,
+#ifdef MOZ_SMIL
+                        public nsISMILAnimationObserver,
+#endif
                         public nsSVGCoordCtxProvider
 {
 protected:
@@ -111,22 +124,54 @@
   NS_IMETHOD_(float) GetPreviousTranslate_x();
   NS_IMETHOD_(float) GetPreviousTranslate_y();
   NS_IMETHOD_(float) GetPreviousScale();
+#ifdef MOZ_SMIL
+  NS_IMETHOD_(nsISMILAnimationRegistry*) GetAnimationRegistry();
+  NS_IMETHOD EnumerateAnimationNodes();
+#endif // MOZ_SMIL
 
   // nsIContent interface
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
 
+  
+  // nsIContent specializations
+  virtual nsresult HandleDOMEvent(nsPresContext* aPresContext,
+                                  nsEvent* aEvent,
+                                  nsIDOMEvent** aDOMEvent,
+                                  PRUint32 aFlags,
+                                  nsEventStatus* aEventStatus);
+
   // nsISVGValueObserver
   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
                                      nsISVGValue::modificationType aModType);
   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
                                      nsISVGValue::modificationType aModType);
 
+#ifdef MOZ_SMIL
+  // nsISMILAnimationObserver interface
+  virtual void StartSample() {}
+  virtual void StartCompositing();
+  virtual void EndCompositing();
+  virtual void EndSample() {}
+#endif // MOZ_SMIL
+
 protected:
   // nsSVGElement overrides
   PRBool IsEventName(nsIAtom* aName);
+#ifdef MOZ_SMIL
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                              nsIContent* aBindingParent,
+                              PRBool aCompileEventHandlers);
+  virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
+                              PRBool aNullParent = PR_TRUE);
+#endif // MOZ_SMIL
 
   // implementation helpers:
   void GetOffsetToAncestor(nsIContent* ancestor, float &x, float &y);
+#ifdef MOZ_SMIL
+  nsISMILAnimationController*
+  GetAnimationController(nsIDocument* aDocument, PRBool aCreate = PR_FALSE);
+  void DoEnumerateAnimationNodes();
+#endif // MOZ_SMIL
 
   nsCOMPtr<nsIDOMSVGAnimatedLength> mWidth;
   nsCOMPtr<nsIDOMSVGAnimatedLength> mHeight;
@@ -147,6 +192,12 @@
   float                             mPreviousScale;
   PRBool                            mDispatchEvent;
 
+#ifdef MOZ_SMIL
+  // animation
+  nsCOMPtr<nsISMILAnimationRegistry>   mAnimationRegistry;
+  PRBool                               mAnimationEnumerationRequired;
+#endif // MOZ_SMIL
+  
   PRInt32 mRedrawSuspendCount;
 };
 
@@ -170,6 +221,9 @@
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGZoomAndPan)
   NS_INTERFACE_MAP_ENTRY(nsISVGSVGElement)
   NS_INTERFACE_MAP_ENTRY(nsSVGCoordCtxProvider)
+#ifdef MOZ_SMIL
+  NS_INTERFACE_MAP_ENTRY(nsISMILAnimationObserver)
+#endif
   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGSVGElement)
 NS_INTERFACE_MAP_END_INHERITING(nsSVGSVGElementBase)
 
@@ -177,7 +231,11 @@
 // Implementation
 
 nsSVGSVGElement::nsSVGSVGElement(nsINodeInfo* aNodeInfo)
-  : nsSVGSVGElementBase(aNodeInfo), mRedrawSuspendCount(0)
+  : nsSVGSVGElementBase(aNodeInfo), 
+#ifdef MOZ_SMIL
+    mAnimationEnumerationRequired(PR_FALSE),
+#endif
+    mRedrawSuspendCount(0)
 {
 }
 
@@ -620,40 +678,69 @@
 NS_IMETHODIMP
 nsSVGSVGElement::PauseAnimations()
 {
+#ifdef MOZ_SMIL
+  NS_ENSURE_TRUE(mAnimationRegistry,NS_ERROR_FAILURE);
+  mAnimationRegistry->Pause();
+  return NS_OK;
+#else
   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::PauseAnimations");
   return NS_ERROR_NOT_IMPLEMENTED;
+#endif // MOZ_SMIL
 }
 
 /* void unpauseAnimations (); */
 NS_IMETHODIMP
 nsSVGSVGElement::UnpauseAnimations()
 {
+#ifdef MOZ_SMIL
+  NS_ENSURE_TRUE(mAnimationRegistry,NS_ERROR_FAILURE);
+  mAnimationRegistry->Unpause();
+  return NS_OK;
+#else
   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::UnpauseAnimations");
   return NS_ERROR_NOT_IMPLEMENTED;
+#endif // MOZ_SMIL
 }
 
 /* boolean animationsPaused (); */
 NS_IMETHODIMP
 nsSVGSVGElement::AnimationsPaused(PRBool *_retval)
 {
+#ifdef MOZ_SMIL
+  NS_ENSURE_TRUE(mAnimationRegistry,NS_ERROR_FAILURE);
+  *_retval = mAnimationRegistry->IsPaused();
+  return NS_OK;
+#else
   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::AnimationsPaused");
   return NS_ERROR_NOT_IMPLEMENTED;
+#endif // MOZ_SMIL
 }
 
 /* float getCurrentTime (); */
 NS_IMETHODIMP
 nsSVGSVGElement::GetCurrentTime(float *_retval)
 {
+#ifdef MOZ_SMIL
+  NS_ENSURE_TRUE(mAnimationRegistry,NS_ERROR_FAILURE);
+  *_retval = mAnimationRegistry->GetCurrentTime();
+  return NS_OK;
+#else
   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetCurrentTime");
   return NS_ERROR_NOT_IMPLEMENTED;
+#endif // MOZ_SMIL
 }
 
 /* void setCurrentTime (in float seconds); */
 NS_IMETHODIMP
 nsSVGSVGElement::SetCurrentTime(float seconds)
 {
+#ifdef MOZ_SMIL
+  NS_ENSURE_TRUE(mAnimationRegistry,NS_ERROR_FAILURE);
+  return mAnimationRegistry->SetCurrentTime(seconds);
+#else
   NS_NOTYETIMPLEMENTED("nsSVGSVGElement::SetCurrentTime");
   return NS_ERROR_NOT_IMPLEMENTED;
+#endif
 }
 
 /* nsIDOMNodeList getIntersectionList (in nsIDOMSVGRect rect, in nsIDOMSVGElement referenceElement); */
@@ -1424,6 +1511,50 @@
   return mPreviousScale;
 }
 
+#ifdef MOZ_SMIL
+nsISMILAnimationRegistry*
+nsSVGSVGElement::GetAnimationRegistry()
+{
+  nsISMILAnimationRegistry* result = nsnull;
+
+  if (mAnimationRegistry) {
+    result = mAnimationRegistry;
+  } else {
+    // We must not be the outermost SVG element, try to find it
+    nsCOMPtr<nsIDOMSVGSVGElement> outerSVGDOM;
+
+    nsresult rv = GetOwnerSVGElement(getter_AddRefs(outerSVGDOM));
+
+    if (NS_SUCCEEDED(rv) && outerSVGDOM) {
+      nsCOMPtr<nsISVGSVGElement> outerSVG( do_QueryInterface(outerSVGDOM) );
+      result = outerSVG->GetAnimationRegistry();
+    }
+  }
+
+  return result;
+}
+
+NS_IMETHODIMP
+nsSVGSVGElement::EnumerateAnimationNodes()
+{
+  nsresult rv = NS_OK;
+
+  // This operation should be performed from the outermost SVG element
+  nsCOMPtr<nsIDOMSVGSVGElement> outerSVGDOM;
+  rv = GetOwnerSVGElement(getter_AddRefs(outerSVGDOM));
+
+  if (NS_SUCCEEDED(rv) && outerSVGDOM) {
+    nsCOMPtr<nsISVGSVGElement> outerSVG( do_QueryInterface(outerSVGDOM) );
+    rv = outerSVG->EnumerateAnimationNodes();
+  } else {
+    // We must be the outermost SVG element -- use lazy enumeration
+    mAnimationEnumerationRequired = PR_TRUE;
+  }
+
+  return rv;
+}
+#endif // MOZ_SMIL
+
 //----------------------------------------------------------------------
 // nsIContent methods
 
@@ -1443,6 +1574,43 @@
 }
 
 //----------------------------------------------------------------------
+// nsIContent methods:
+
+nsresult
+nsSVGSVGElement::HandleDOMEvent(nsPresContext* aPresContext,
+                                nsEvent* aEvent,
+                                nsIDOMEvent** aDOMEvent,
+                                PRUint32 aFlags,
+                                nsEventStatus* aEventStatus)
+{
+  //
+  // XXX Starting animation by using the SVGLoad event means that no extra work
+  // is required to provide the correct behaviour when externalResourcesRequired
+  // is supported but it means that the 'deferred tree' test case fails. In this
+  // test case an SVG tree is constructed entirely via script and no SVGLoad
+  // event is fired.
+  //
+  // I think we will need to address this when we come to
+  // externalResourcesRequired anyway as I suppose we should still fire the
+  // SVGLoad event even for trees added entirely by script?
+  //
+  // We could always start the animation registry in BindToTree if we can
+  // somehow detect when we're being added by script and when we're being loaded
+  // as part of the document but I don't know how to do this. I'm leaving it
+  // broken for now.
+  //
+#ifdef MOZ_SMIL
+  if (aEvent->message == NS_SVG_LOAD) {
+    if (mAnimationRegistry)
+      mAnimationRegistry->Start();
+  }
+#endif
+
+  return nsSVGSVGElementBase::HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
+                                             aFlags, aEventStatus);
+}
+
+//----------------------------------------------------------------------
 // nsISVGValueObserver methods:
 
 NS_IMETHODIMP
@@ -1559,6 +1727,74 @@
          aName == nsSVGAtoms::onzoom;
 }
 
+#ifdef MOZ_SMIL
+nsresult
+nsSVGSVGElement::BindToTree(nsIDocument* aDocument,
+                            nsIContent* aParent,
+                            nsIContent* aBindingParent,
+                            PRBool aCompileEventHandlers)
+{
+  nsCOMPtr<nsIDOMSVGSVGElement> outerSVG;
+
+  GetOwnerSVGElement(getter_AddRefs(outerSVG));
+
+  PRBool outermost = (outerSVG == nsnull);
+
+  if (!mAnimationRegistry && outermost) {
+    // We are now the outermost SVG element
+    mAnimationRegistry = NS_NewSMILAnimationRegistry();
+    NS_ENSURE_TRUE(mAnimationRegistry, NS_ERROR_FAILURE);
+    mAnimationRegistry->SetObserver(this);
+  } else if (mAnimationRegistry && !outermost) {
+    mAnimationRegistry = nsnull;
+  }
+
+  nsresult rv = nsSVGSVGElementBase::BindToTree(aDocument, aParent,
+                                                aBindingParent,
+                                                aCompileEventHandlers);
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  nsCOMPtr<nsISMILAnimationController> smilController = 
+    GetAnimationController(aDocument, PR_TRUE);
+
+  if (mAnimationRegistry && smilController)
+    rv = mAnimationRegistry->SetController(smilController);
+
+  return rv;
+}
+
+void
+nsSVGSVGElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
+{
+  if (mAnimationRegistry)
+    mAnimationRegistry->SetController(nsnull);
+
+  nsSVGSVGElementBase::UnbindFromTree(aDeep, aNullParent);
+}
+
+//----------------------------------------------------------------------
+// nsISMILAnimationObserver
+
+void
+nsSVGSVGElement::StartCompositing()
+{
+  PRUint32 retval;
+  SuspendRedraw(0, &retval);
+
+  if (mAnimationEnumerationRequired) {
+    DoEnumerateAnimationNodes();
+    mAnimationEnumerationRequired = PR_FALSE;
+  }
+}
+
+void
+nsSVGSVGElement::EndCompositing()
+{
+  UnsuspendRedraw(0);
+}
+
+#endif // MOZ_SMIL
+
 //----------------------------------------------------------------------
 // implementation helpers
 
@@ -1598,3 +1834,54 @@
     y = point.y * context->TwipsToPixels();
   }
 }
+
+#ifdef MOZ_SMIL
+nsISMILAnimationController*
+nsSVGSVGElement::GetAnimationController(nsIDocument* aDocument,
+                                        PRBool aCreate /* = PR_FALSE */)
+{
+  nsISMILAnimationController* result = nsnull;
+
+  NS_ENSURE_TRUE(aDocument, nsnull);
+
+  nsIPresShell* presShell = aDocument->GetShellAt(0);
+  if (!presShell)
+    return nsnull;
+
+  nsPresContext* context = presShell->GetPresContext();
+  NS_ENSURE_TRUE(context, nsnull);
+
+  nsIAnimationController* controller = context->GetAnimationController();
+
+  if (controller) {
+    nsresult rv = CallQueryInterface(controller, &result);
+    NS_ENSURE_SUCCESS(rv, nsnull);
+  } else if (aCreate) {
+    result = NS_NewSMILAnimationController(aDocument);
+    context->SetAnimationController(result);
+  }
+
+  return result;
+}
+
+void
+nsSVGSVGElement::DoEnumerateAnimationNodes()
+{
+  PRUint16 position = 0;
+  nsCOMPtr<nsIContentIterator> iter;
+  NS_NewContentIterator(getter_AddRefs(iter));
+  iter->Init(NS_STATIC_CAST(nsIContent*, this));
+
+  while (!iter->IsDone()) {
+    nsIContent* content = iter->GetCurrentNode();
+    nsIAtom* tag = content->Tag();
+    if (tag == nsSVGAtoms::animate) {
+      nsCOMPtr<nsISVGAnimationElement> element( do_QueryInterface(content) );
+      if (element)
+        element->SetDocumentPosition(++position);
+    }
+    iter->Next();
+  }
+}
+#endif // MOZ_SMIL
+
Index: content/xml/document/src/nsXMLContentSink.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/xml/document/src/nsXMLContentSink.cpp,v
retrieving revision 1.374
diff -u -r1.374 nsXMLContentSink.cpp
--- content/xml/document/src/nsXMLContentSink.cpp	28 Oct 2005 11:25:13 -0000	1.374
+++ content/xml/document/src/nsXMLContentSink.cpp	5 Nov 2005 04:39:41 -0000
@@ -1017,7 +1017,7 @@
 
 #ifdef MOZ_SVG
   if (content->GetNameSpaceID() == kNameSpaceID_SVG &&
-      content->HasAttr(kNameSpaceID_None, nsSVGAtoms::onload)) {
+      content->Tag() == nsSVGAtoms::svg) {
     nsEventStatus status = nsEventStatus_eIgnore;
     nsEvent event(PR_TRUE, NS_SVG_LOAD);
     event.eventStructType = NS_SVG_EVENT;
Index: content/base/src/nsGenericElement.cpp
===================================================================
RCS file: /cvsroot/mozilla/content/base/src/nsGenericElement.cpp,v
retrieving revision 3.423
diff -u -r3.423 nsGenericElement.cpp
--- content/base/src/nsGenericElement.cpp	2 Nov 2005 02:42:38 -0000	3.423
+++ content/base/src/nsGenericElement.cpp	5 Nov 2005 04:39:52 -0000
@@ -1263,6 +1263,13 @@
     }
   }
 #endif /* MOZ_SVG */
+#ifdef MOZ_SMIL
+  else if (PL_strcasecmp(f, "TimeControl") == 0) {
+    if (aVersion.IsEmpty() || PL_strcmp(v, "1.0") == 0) {
+      *aReturn = PR_TRUE;
+    }
+  }
+#endif /* MOZ_SMIL */
   else {
     nsCOMPtr<nsIDOMNSFeatureFactory> factory =
       GetDOMFeatureFactory(aFeature, aVersion);
Index: content/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/content/Makefile.in,v
retrieving revision 1.10
diff -u -r1.10 Makefile.in
--- content/Makefile.in	18 Apr 2005 06:33:19 -0000	1.10
+++ content/Makefile.in	5 Nov 2005 04:39:54 -0000
@@ -53,6 +53,10 @@
 DIRS            += xtf
 endif
 
+ifdef MOZ_SMIL
+DIRS			+= smil
+endif
+
 DIRS           += events
 
 include $(topsrcdir)/config/rules.mk
Index: dom/public/nsIDOMClassInfo.h
===================================================================
RCS file: /cvsroot/mozilla/dom/public/nsIDOMClassInfo.h,v
retrieving revision 1.73
diff -u -r1.73 nsIDOMClassInfo.h
--- dom/public/nsIDOMClassInfo.h	21 Oct 2005 22:30:36 -0000	1.73
+++ dom/public/nsIDOMClassInfo.h	5 Nov 2005 04:39:57 -0000
@@ -248,6 +248,9 @@
   eDOMClassInfo_SVGDocument_id,
 
   // SVG element classes
+#ifdef MOZ_SMIL
+  eDOMClassInfo_SVGAnimateElement_id,
+#endif // MOZ_SMIL
   eDOMClassInfo_SVGCircleElement_id,
   eDOMClassInfo_SVGClipPathElement_id,
   eDOMClassInfo_SVGDefsElement_id,
Index: dom/public/idl/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/dom/public/idl/Makefile.in,v
retrieving revision 1.13
diff -u -r1.13 Makefile.in
--- dom/public/idl/Makefile.in	18 Apr 2005 06:33:17 -0000	1.13
+++ dom/public/idl/Makefile.in	5 Nov 2005 04:40:05 -0000
@@ -62,5 +62,9 @@
 DIRS += svg
 endif
 
+ifdef MOZ_SMIL
+DIRS += smil
+endif
+
 include $(topsrcdir)/config/rules.mk
 
Index: dom/public/idl/svg/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/dom/public/idl/svg/Makefile.in,v
retrieving revision 1.22
diff -u -r1.22 Makefile.in
--- dom/public/idl/svg/Makefile.in	13 Sep 2005 22:38:34 -0000	1.22
+++ dom/public/idl/svg/Makefile.in	5 Nov 2005 04:40:06 -0000
@@ -121,4 +121,10 @@
 		nsIDOMSVGZoomEvent.idl \
 		$(NULL)
 
+ifdef MOZ_SMIL
+XPIDLSRCS += nsIDOMSVGAnimateElement.idl \
+			 nsIDOMSVGAnimationElement.idl \
+			 $(NULL)
+endif
+
 include $(topsrcdir)/config/rules.mk
Index: dom/public/idl/svg/nsIDOMSVGAnimateElement.idl
===================================================================
RCS file: /cvsroot/mozilla/dom/public/idl/svg/nsIDOMSVGAnimateElement.idl
diff -N dom/public/idl/svg/nsIDOMSVGAnimateElement.idl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dom/public/idl/svg/nsIDOMSVGAnimateElement.idl	5 Nov 2005 04:40:07 -0000
@@ -0,0 +1,42 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SVG project.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsIDOMSVGAnimationElement.idl"
+
+[scriptable, uuid(0c4297e8-68d0-471d-a933-64132ccc5b97)]
+interface nsIDOMSVGAnimateElement : nsIDOMSVGAnimationElement {};
+
Index: dom/public/idl/svg/nsIDOMSVGAnimationElement.idl
===================================================================
RCS file: /cvsroot/mozilla/dom/public/idl/svg/nsIDOMSVGAnimationElement.idl
diff -N dom/public/idl/svg/nsIDOMSVGAnimationElement.idl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dom/public/idl/svg/nsIDOMSVGAnimationElement.idl	5 Nov 2005 04:40:07 -0000
@@ -0,0 +1,63 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SVG project.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsIDOMSVGElement.idl"
+
+[scriptable, uuid(8f2ccf31-5544-4a9d-8927-ef35d242039e)]
+interface nsIDOMSVGAnimationElement
+  : nsIDOMSVGElement
+/*
+        The SVG DOM makes use of multiple interface inheritance.
+        Since XPCOM only supports single interface inheritance,
+        the best thing that we can do is to promise that whenever
+        an object implements _this_ interface it will also
+        implement the following interfaces. (We then have to QI to
+        hop between them.)
+        
+    nsIDOMSVGTests,
+    nsIDOMSVGExternalResourcesRequired,
+    smil::nsIDOMElementTimeControl,
+    events::nsIDOMEventTarget
+*/
+{ 
+  readonly attribute nsIDOMSVGElement targetElement;
+  float getStartTime ( );
+  float getCurrentTime ( );
+  float getSimpleDuration ( );
+          // raises (nsIDOMDOMException)
+};
+
Index: dom/public/idl/smil/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/dom/public/idl/smil/Makefile.in
diff -N dom/public/idl/smil/Makefile.in
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dom/public/idl/smil/Makefile.in	5 Nov 2005 04:40:09 -0000
@@ -0,0 +1,54 @@
+#!nmake
+#
+# ***** 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 module.
+#
+# The Initial Developer of the Original Code is Brian Birtles.
+# Portions created by the Initial Developer are Copyright (C) 2005
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# 	Brian Birtles <birtles@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of 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 *****
+
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= dom
+XPIDL_MODULE	= dom_smil
+
+XPIDLSRCS	= \
+		nsIDOMElementTimeControl.idl \
+		$(NULL)
+
+include $(topsrcdir)/config/rules.mk
Index: dom/public/idl/smil/nsIDOMElementTimeControl.idl
===================================================================
RCS file: /cvsroot/mozilla/dom/public/idl/smil/nsIDOMElementTimeControl.idl
diff -N dom/public/idl/smil/nsIDOMElementTimeControl.idl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dom/public/idl/smil/nsIDOMElementTimeControl.idl	5 Nov 2005 04:40:09 -0000
@@ -0,0 +1,59 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsIDOMSVGElement.idl"
+
+/*
+ * The definitions of this interface in SMIL Animation and SVG 1.1 differ in the
+ * return type and semantics. Returning a boolean shouldn't present a problem
+ * for anyone expecting the method to have a void return type so we use the SVG
+ * definition of the interface here (boolean return types).
+ */
+
+[scriptable, uuid(276a6678-7844-4d5e-8dfe-938c46089b84)]
+interface nsIDOMElementTimeControl : nsISupports
+{ 
+  boolean beginElement ( );
+          // raises (nsIDOMDOMException)
+  boolean beginElementAt ( in float offset );
+          // raises (nsIDOMDOMException)
+  boolean endElement ( );
+          // raises (nsIDOMDOMException)
+  boolean endElementAt ( in float offset );
+          // raises (nsIDOMDOMException)
+};
+
Index: dom/src/base/nsDOMClassInfo.cpp
===================================================================
RCS file: /cvsroot/mozilla/dom/src/base/nsDOMClassInfo.cpp,v
retrieving revision 1.327
diff -u -r1.327 nsDOMClassInfo.cpp
--- dom/src/base/nsDOMClassInfo.cpp	27 Oct 2005 02:39:18 -0000	1.327
+++ dom/src/base/nsDOMClassInfo.cpp	5 Nov 2005 04:40:31 -0000
@@ -329,6 +329,11 @@
 #include "nsIDOMSVGAnimPresAspRatio.h"
 #include "nsIDOMSVGAnimatedRect.h"
 #include "nsIDOMSVGAnimatedString.h"
+#ifdef MOZ_SMIL
+#include "nsIDOMSVGAnimateElement.h"
+#include "nsIDOMSVGAnimationElement.h"
+#include "nsIDOMElementTimeControl.h"
+#endif // MOZ_SMIL
 #include "nsIDOMSVGAnimTransformList.h"
 #include "nsIDOMSVGCircleElement.h"
 #include "nsIDOMSVGClipPathElement.h"
@@ -863,6 +868,10 @@
                            DOCUMENT_SCRIPTABLE_FLAGS)
 
   // SVG element classes
+#ifdef MOZ_SMIL
+  NS_DEFINE_CLASSINFO_DATA(SVGAnimateElement, nsElementSH,
+                           ELEMENT_SCRIPTABLE_FLAGS)
+#endif // MOZ_SMIL
   NS_DEFINE_CLASSINFO_DATA(SVGCircleElement, nsElementSH,
                            ELEMENT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGClipPathElement, nsElementSH,
@@ -2439,6 +2448,15 @@
 
   // SVG element classes
 
+#ifdef MOZ_SMIL
+  DOM_CLASSINFO_MAP_BEGIN(SVGAnimateElement, nsIDOMSVGAnimateElement)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGAnimationElement)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGAnimateElement)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMElementTimeControl)
+    DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+#endif // MOZ_SMIL
+
   DOM_CLASSINFO_MAP_BEGIN(SVGCircleElement, nsIDOMSVGCircleElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGCircleElement)
     DOM_CLASSINFO_SVG_GRAPHIC_ELEMENT_MAP_ENTRIES
Index: layout/base/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/layout/base/Makefile.in,v
retrieving revision 1.22
diff -u -r1.22 Makefile.in
--- layout/base/Makefile.in	21 Sep 2005 19:14:29 -0000	1.22
+++ layout/base/Makefile.in	5 Nov 2005 04:40:32 -0000
@@ -92,6 +92,7 @@
 		nsFrameManager.h \
 		nsFrameManagerBase.h \
 		nsFrameTraversal.h \
+		nsIAnimationController.h \
 		nsICaret.h \
 		nsIDocumentViewer.h \
 		nsIFrameSelection.h \
Index: layout/base/nsIAnimationController.h
===================================================================
RCS file: /cvsroot/mozilla/layout/base/nsIAnimationController.h
diff -N layout/base/nsIAnimationController.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ layout/base/nsIAnimationController.h	5 Nov 2005 04:40:32 -0000
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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 the Mozilla SMIL module.
+ *
+ * The Initial Developer of the Original Code is Brian Birtles.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Birtles <birtles@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef __NS_IANIMATIONCONTROLLER_H__
+#define __NS_IANIMATIONCONTROLLER_H__
+
+#include "nsISupports.h"
+
+////////////////////////////////////////////////////////////////////////
+// nsIAnimationController: Animation controller
+
+// {7aa203ea-e6e1-4cca-84af-a29f0eaedef5}
+#define NS_IANIMATIONCONTROLLER_IID \
+{ 0x7aa203ea, 0xe6e1, 0x4cca, { 0x84, 0xaf, 0xa2, 0x9f, 0x0e, 0xae, 0xde, 0xf5 } }
+
+class nsIAnimationController : public nsISupports
+{
+public:
+  NS_DEFINE_STATIC_IID_ACCESSOR(NS_IANIMATIONCONTROLLER_IID)
+
+  virtual nsresult  Pause()=0;
+  virtual nsresult  Resume()=0;
+  virtual nsresult  Reset()=0;
+};
+
+#endif // __NS_IANIMATIONCONTROLLER_H__
+
Index: layout/base/nsPresContext.cpp
===================================================================
RCS file: /cvsroot/mozilla/layout/base/nsPresContext.cpp,v
retrieving revision 3.290
diff -u -r3.290 nsPresContext.cpp
--- layout/base/nsPresContext.cpp	23 Aug 2005 23:52:16 -0000	3.290
+++ layout/base/nsPresContext.cpp	5 Nov 2005 04:40:35 -0000
@@ -73,6 +73,7 @@
 #include "nsIDOMDocument.h"
 #include "nsAutoPtr.h"
 #include "nsEventStateManager.h"
+#include "nsIAnimationController.h"
 #ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
 #endif // IBMBIDI
@@ -267,6 +268,10 @@
   NS_IF_RELEASE(mDeviceContext);
   NS_IF_RELEASE(mLookAndFeel);
   NS_IF_RELEASE(mLangGroup);
+
+#ifdef MOZ_SMIL
+  NS_IF_RELEASE(mAnimationController);
+#endif
 }
 
 NS_IMPL_ISUPPORTS2(nsPresContext, nsPresContext, nsIObserver)
@@ -915,6 +920,24 @@
     }
   }
 
+#ifdef MOZ_SMIL
+  if (mAnimationController) {
+    switch (aMode)
+    {
+      case imgIContainer::kNormalAnimMode:
+      case imgIContainer::kLoopOnceAnimMode:
+        if (mImageAnimationMode == imgIContainer::kDontAnimMode)
+          mAnimationController->Resume();
+        break;
+
+      case imgIContainer::kDontAnimMode:
+        if (mImageAnimationMode != imgIContainer::kDontAnimMode)
+          mAnimationController->Pause();
+        break;
+    }
+  }
+#endif // MOZ_SMIL
+
   mImageAnimationMode = aMode;
 }
 
@@ -1302,6 +1325,21 @@
   return PR_FALSE;
 }
 
+#ifdef MOZ_SMIL
+void
+nsPresContext::SetAnimationController(nsIAnimationController* aController)
+{
+    NS_IF_ADDREF(aController);
+    nsIAnimationController* temp = mAnimationController;
+    mAnimationController = aController;
+    if (mAnimationController && 
+        mImageAnimationMode == imgIContainer::kDontAnimMode) {
+      mAnimationController->Pause();
+    }
+    NS_IF_RELEASE(temp);
+}
+#endif // MOZ_SMIL
+
 nsresult
 NS_NewPresContext(nsPresContext::nsPresContextType aType,
                   nsPresContext** aInstancePtrResult)
Index: layout/base/nsPresContext.h
===================================================================
RCS file: /cvsroot/mozilla/layout/base/nsPresContext.h,v
retrieving revision 3.152
diff -u -r3.152 nsPresContext.h
--- layout/base/nsPresContext.h	23 Aug 2005 23:52:16 -0000	3.152
+++ layout/base/nsPresContext.h	5 Nov 2005 04:40:37 -0000
@@ -56,6 +56,7 @@
 #include "nsCRT.h"
 #include "nsIPrintSettings.h"
 #include "nsPropertyTable.h"
+
 #ifdef IBMBIDI
 class nsBidiPresUtils;
 #endif // IBMBIDI
@@ -77,7 +78,7 @@
 class nsIURI;
 class nsILookAndFeel;
 class nsICSSPseudoComparator;
-class nsIAtom;
+class nsIAnimationController;
 struct nsStyleStruct;
 struct nsStyleBackground;
 
@@ -626,6 +627,15 @@
    */
   const nscoord* GetBorderWidthTable() { return mBorderWidthTable; }
 
+#ifdef MOZ_SMIL
+  nsIAnimationController* GetAnimationController()
+  {
+    return mAnimationController;
+  }
+
+  void SetAnimationController(nsIAnimationController* aController);
+#endif // MOZ_SMIL
+
 protected:
   NS_HIDDEN_(void) SetImgAnimations(nsIContent *aParent, PRUint16 aMode);
   NS_HIDDEN_(void) GetDocumentColorPreferences();
@@ -669,6 +679,10 @@
   nsBidiPresUtils*      mBidiUtils;
 #endif
 
+#ifdef MOZ_SMIL
+  nsIAnimationController* mAnimationController; // [STRONG]
+#endif
+
   nsCOMPtr<nsITheme> mTheme;
   nsCOMPtr<nsILanguageAtomService> mLangService;
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
Index: layout/build/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/layout/build/Makefile.in,v
retrieving revision 1.129
diff -u -r1.129 Makefile.in
--- layout/build/Makefile.in	16 Sep 2005 02:25:36 -0000	1.129
+++ layout/build/Makefile.in	5 Nov 2005 04:40:39 -0000
@@ -193,6 +193,12 @@
 endif
 endif
 
+ifdef MOZ_SMIL
+SHARED_LIBRARY_LIBS += \
+				$(DIST)/lib/$(LIB_PREFIX)gkconsmil_s.$(LIB_SUFFIX) \
+				$(NULL)
+endif
+
 EXTRA_DSO_LDOPTS = \
 		$(LIBS_DIR) \
 		$(EXTRA_DSO_LIBS) \
Index: config/autoconf.mk.in
===================================================================
RCS file: /cvsroot/mozilla/config/autoconf.mk.in,v
retrieving revision 3.370
diff -u -r3.370 autoconf.mk.in
--- config/autoconf.mk.in	2 Nov 2005 17:34:12 -0000	3.370
+++ config/autoconf.mk.in	5 Nov 2005 04:40:41 -0000
@@ -196,6 +196,7 @@
 MOZ_LIBART_CFLAGS = @MOZ_LIBART_CFLAGS@
 MOZ_ENABLE_CANVAS = @MOZ_ENABLE_CANVAS@
 MOZ_CAIRO_CFLAGS = @MOZ_CAIRO_CFLAGS@
+MOZ_SMIL = @MOZ_SMIL@
 MOZ_XSLT_STANDALONE = @MOZ_XSLT_STANDALONE@
 
 # Mac's don't like / in a #include, so we include the libart
Index: allmakefiles.sh
===================================================================
RCS file: /cvsroot/mozilla/allmakefiles.sh,v
retrieving revision 1.588
diff -u -r1.588 allmakefiles.sh
--- allmakefiles.sh	22 Oct 2005 15:54:44 -0000	1.588
+++ allmakefiles.sh	5 Nov 2005 04:41:14 -0000
@@ -1341,6 +1341,15 @@
 "
 fi
 
+# smil
+if [ "$MOZ_SMIL" ]; then
+    MAKEFILES_content="$MAKEFILES_content
+	content/smil/Makefile
+	content/smil/public/Makefile
+	content/smil/src/Makefile
+"
+fi
+
 # xtf
 if [ "$MOZ_XTF" ]; then
     MAKEFILES_content="$MAKEFILES_content
Index: configure.in
===================================================================
RCS file: /cvsroot/mozilla/configure.in,v
retrieving revision 1.1543
diff -u -r1.1543 configure.in
--- configure.in	2 Nov 2005 20:25:32 -0000	1.1543
+++ configure.in	5 Nov 2005 04:41:33 -0000
@@ -5123,6 +5123,17 @@
 dnl fi
 
 dnl ========================================================
+dnl SMIL
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(smil,
+[  --enable-smil            Enable SMIL animation support],
+    MOZ_SMIL=1,
+    MOZ_SMIL= )
+if test -n "$MOZ_SMIL"; then
+  AC_DEFINE(MOZ_SMIL)
+fi
+
+dnl ========================================================
 dnl Installer
 dnl ========================================================
 case "$target_os" in
@@ -6722,6 +6733,7 @@
 AC_SUBST(MOZ_SVG_RENDERER_GDIPLUS)
 AC_SUBST(MOZ_SVG_RENDERER_LIBART)
 AC_SUBST(MOZ_SVG_RENDERER_CAIRO)
+AC_SUBST(MOZ_SMIL)
 AC_SUBST(MOZ_XSLT_STANDALONE)
 AC_SUBST(MOZ_JS_LIBS)
 AC_SUBST(MOZ_PSM)
