Merge mozilla-central into Places
authorShawn Wilsher <me@shawnwilsher.com>
Mon, 06 Dec 2010 09:48:54 -0800
changeset 59381 c22fccf2af093e90bc762091f372317b2fabd724
parent 59380 0b18344e65cae381c10dce99a4a2d2c6f6c6c4d8 (current diff)
parent 58657 8bc10b6a22223c8e9ad1c0070329cebdffe7ad69 (diff)
child 59382 f0110c8264c8d12112628b188be75df9aefa27a9
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
milestone2.0b8pre
Merge mozilla-central into Places
browser/base/content/browser-places.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/tabbrowser.xml
browser/installer/package-manifest.in
browser/themes/pinstripe/browser/hud-panel.png
browser/themes/pinstripe/browser/hud-style-button-middle-background.png
browser/themes/pinstripe/browser/hud-style-new-folder-bar-background-active.png
browser/themes/pinstripe/browser/hud-style-new-folder-bar-background.gif
browser/themes/pinstripe/browser/hud-style-new-folder-bar-background.png
configure.in
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/svg/content/src/nsSVGAnimatedNumberList.cpp
content/svg/content/src/nsSVGAnimatedNumberList.h
content/svg/content/src/nsSVGNumber.cpp
content/svg/content/src/nsSVGNumber.h
content/svg/content/src/nsSVGNumberList.cpp
content/svg/content/src/nsSVGNumberList.h
dom/ipc/ContentParent.cpp
gfx/angle/angle-nspr.patch
gfx/angle/fix-compile.patch
gfx/angle/generated/glslang.cpp
gfx/angle/generated/glslang_tab.cpp
gfx/angle/generated/glslang_tab.h
gfx/angle/src/compiler/tools/COPYING.bison
gfx/angle/src/compiler/tools/COPYING.flex
gfx/angle/src/compiler/tools/README
gfx/angle/src/compiler/tools/bison.exe
gfx/angle/src/compiler/tools/bison.hairy
gfx/angle/src/compiler/tools/bison.simple
gfx/angle/src/compiler/tools/flex.exe
gfx/thebes/gfxThebesUtils.cpp
gfx/thebes/gfxThebesUtils.h
--- a/Makefile.in
+++ b/Makefile.in
@@ -187,17 +187,20 @@ ifdef MOZ_CRASHREPORTER
 	  $(DIST)/crashreporter-symbols                                   \
 	  $(MAKE_SYM_STORE_PATH) >                                        \
 	  $(DIST)/crashreporter-symbols/$(SYMBOL_INDEX_NAME)
 	echo packing symbols
 	$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
 	cd $(DIST)/crashreporter-symbols && \
           zip -r9D "../$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip" .
 	cd $(DIST)/crashreporter-symbols && \
-          zip -r9D "../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip" . -i "*.sym"
+	grep "sym" $(SYMBOL_INDEX_NAME) > $(SYMBOL_INDEX_NAME).tmp && \
+	  mv $(SYMBOL_INDEX_NAME).tmp $(SYMBOL_INDEX_NAME)
+	cd $(DIST)/crashreporter-symbols && \
+          zip -r9D "../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip" . -i "*.sym" -i "*.txt"
 else
 ifdef WINCE
 ifdef SYMBOLSTORE_PATH
 	echo building symbol store with symstore.exe
 	$(RM) -rf $(DIST)/symbols
 	$(RM) -f "$(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip"
 	$(NSINSTALL) -D $(DIST)/symbols
 	$(SYMBOLSTORE_PATH) add -r -f "$(subst /,\,$(shell pwd -W))\*.PDB" \
--- a/accessible/src/base/nsAccDocManager.cpp
+++ b/accessible/src/base/nsAccDocManager.cpp
@@ -486,27 +486,35 @@ nsAccDocManager::CreateDocOrRootAccessib
   AddListeners(aDocument, isRootDoc);
   return docAcc;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccDocManager static
 
 PLDHashOperator
-nsAccDocManager::ClearDocCacheEntry(const nsIDocument* aKey,
-                                    nsRefPtr<nsDocAccessible>& aDocAccessible,
-                                    void* aUserArg)
+nsAccDocManager::GetFirstEntryInDocCache(const nsIDocument* aKey,
+                                         nsDocAccessible* aDocAccessible,
+                                         void* aUserArg)
 {
   NS_ASSERTION(aDocAccessible,
-               "Calling ClearDocCacheEntry with a NULL pointer!");
+               "No doc accessible for the object in doc accessible cache!");
+  *reinterpret_cast<nsDocAccessible**>(aUserArg) = aDocAccessible;
+
+  return PL_DHASH_STOP;
+}
 
-  if (aDocAccessible)
-    aDocAccessible->Shutdown();
-
-  return PL_DHASH_REMOVE;
+void
+nsAccDocManager::ClearDocCache()
+{
+  nsDocAccessible* docAcc = nsnull;
+  while (mDocAccessibleCache.EnumerateRead(GetFirstEntryInDocCache, static_cast<void*>(&docAcc))) {
+    if (docAcc)
+      docAcc->Shutdown();
+  }
 }
 
 PLDHashOperator
 nsAccDocManager::SearchAccessibleInDocCache(const nsIDocument* aKey,
                                             nsDocAccessible* aDocAccessible,
                                             void* aUserArg)
 {
   NS_ASSERTION(aDocAccessible,
--- a/accessible/src/base/nsAccDocManager.h
+++ b/accessible/src/base/nsAccDocManager.h
@@ -147,30 +147,27 @@ private:
    * Create document or root accessible.
    */
   nsDocAccessible *CreateDocOrRootAccessible(nsIDocument *aDocument);
 
   typedef nsRefPtrHashtable<nsPtrHashKey<const nsIDocument>, nsDocAccessible>
     nsDocAccessibleHashtable;
 
   /**
-   * Shutdown and remove the document accessible from cache.
+   * Get first entry of the document accessible from cache.
    */
   static PLDHashOperator
-    ClearDocCacheEntry(const nsIDocument* aKey,
-                       nsRefPtr<nsDocAccessible>& aDocAccessible,
-                       void* aUserArg);
+    GetFirstEntryInDocCache(const nsIDocument* aKey,
+                            nsDocAccessible* aDocAccessible,
+                            void* aUserArg);
 
   /**
    * Clear the cache and shutdown the document accessibles.
    */
-  void ClearDocCache()
-  {
-    mDocAccessibleCache.Enumerate(ClearDocCacheEntry, static_cast<void*>(this));
-  }
+  void ClearDocCache();
 
   struct nsSearchAccessibleInCacheArg
   {
     nsAccessible *mAccessible;
     nsINode* mNode;
   };
 
   static PLDHashOperator
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -3,16 +3,18 @@
 
 const EVENT_ALERT = nsIAccessibleEvent.EVENT_ALERT;
 const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
 const EVENT_DOCUMENT_RELOAD = nsIAccessibleEvent.EVENT_DOCUMENT_RELOAD;
 const EVENT_DOCUMENT_LOAD_STOPPED = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_STOPPED;
 const EVENT_HIDE = nsIAccessibleEvent.EVENT_HIDE;
 const EVENT_FOCUS = nsIAccessibleEvent.EVENT_FOCUS;
 const EVENT_NAME_CHANGE = nsIAccessibleEvent.EVENT_NAME_CHANGE;
+const EVENT_MENU_START = nsIAccessibleEvent.EVENT_MENU_START;
+const EVENT_MENU_END = nsIAccessibleEvent.EVENT_MENU_END;
 const EVENT_MENUPOPUP_START = nsIAccessibleEvent.EVENT_MENUPOPUP_START;
 const EVENT_MENUPOPUP_END = nsIAccessibleEvent.EVENT_MENUPOPUP_END;
 const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
 const EVENT_SCROLLING_START = nsIAccessibleEvent.EVENT_SCROLLING_START;
 const EVENT_SELECTION_ADD = nsIAccessibleEvent.EVENT_SELECTION_ADD;
 const EVENT_SELECTION_WITHIN = nsIAccessibleEvent.EVENT_SELECTION_WITHIN;
 const EVENT_SHOW = nsIAccessibleEvent.EVENT_SHOW;
 const EVENT_STATE_CHANGE = nsIAccessibleEvent.EVENT_STATE_CHANGE;
@@ -31,16 +33,21 @@ const EVENT_VALUE_CHANGE = nsIAccessible
 var gA11yEventDumpID = "";
 
 /**
  * Set up this variable to dump event processing into console.
  */
 var gA11yEventDumpToConsole = false;
 
 /**
+ * Set up this variable to dump event processing into error console.
+ */
+var gA11yEventDumpToAppConsole = false;
+
+/**
  * Executes the function when requested event is handled.
  *
  * @param aEventType  [in] event type
  * @param aTarget     [in] event target
  * @param aFunc       [in] function to call when event is handled
  * @param aContext    [in, optional] object in which context the function is
  *                    called
  * @param aArg1       [in, optional] argument passed into the function
@@ -265,20 +272,22 @@ function eventQueue(aEventType)
         SimpleTest.finish();
 
       return;
     }
 
     // Start processing of next invoker.
     invoker = this.getNextInvoker();
 
-    this.setEventHandler(invoker);
+    if (gLogger.isEnabled()) {
+      gLogger.logToConsole("Event queue: \n  invoke: " + invoker.getID());
+      gLogger.logToDOM("EQ: invoke: " + invoker.getID(), true);
+    }
 
-    if (gA11yEventDumpToConsole)
-      dump("\nEvent queue: \n  invoke: " + invoker.getID() + "\n");
+    this.setEventHandler(invoker);
 
     if (invoker.invoke() == INVOKER_ACTION_FAILED) {
       // Invoker failed to prepare action, fail and finish tests.
       this.processNextInvoker();
       return;
     }
 
     if (this.areAllEventsUnexpected())
@@ -397,16 +406,32 @@ function eventQueue(aEventType)
     this.mEventSeqIdx = -1;
 
     // Register event listeners
     if (this.mEventSeq) {
       aInvoker.wasCaught = new Array(this.mEventSeq.length);
 
       for (var idx = 0; idx < this.mEventSeq.length; idx++) {
         var eventType = this.getEventType(idx);
+
+        if (gLogger.isEnabled()) {
+          var strEventType = (typeof eventType == "string") ? eventType :
+            eventTypeToString(eventType);
+
+          var msg = "registered";
+          if (this.isEventUnexpected(idx))
+            msg += " unexpected";
+
+          msg += ": event type: " + strEventType + ", target: " +
+            prettyName(this.getEventTarget(idx));
+
+          gLogger.logToConsole(msg);
+          gLogger.logToDOM(msg, true);
+        }
+
         if (typeof eventType == "string") {
           // DOM event
           var target = this.getEventTarget(idx);
           var phase = this.getEventPhase(idx);
           target.ownerDocument.addEventListener(eventType, this, phase);
 
         } else {
           // A11y event
@@ -461,16 +486,21 @@ function eventQueue(aEventType)
     var eventItem = this.mEventSeq[aIdx];
     if ("getID" in eventItem)
       return eventItem.getID();
     
     var invoker = this.getInvoker();
     return invoker.getID();
   }
 
+  this.isEventUnexpected = function eventQueue_isEventUnexpected(aIdx)
+  {
+    return this.mEventSeq[aIdx].unexpected;
+  }
+
   this.compareEvents = function eventQueue_compareEvents(aIdx, aEvent)
   {
     var eventType1 = this.getEventType(aIdx);
 
     var eventType2 = (aEvent instanceof nsIDOMEvent) ?
       aEvent.type : aEvent.eventType;
 
     if (eventType1 != eventType2)
@@ -521,64 +551,49 @@ function eventQueue(aEventType)
 
     return true;
   }
 
   this.dumpEventToDOM = function eventQueue_dumpEventToDOM(aOrigEvent,
                                                            aExpectedEventIdx,
                                                            aMatch)
   {
-    if (!gA11yEventDumpID) // debug stuff
+    if (!gLogger.isEnabled()) // debug stuff
       return;
 
     // Dump DOM event information. Skip a11y event since it is dumped by
     // gA11yEventObserver.
     if (aOrigEvent instanceof nsIDOMEvent) {
       var info = "Event type: " + aOrigEvent.type;
       info += ". Target: " + prettyName(aOrigEvent.originalTarget);
-      dumpInfoToDOM(info);
+      gLogger.logToDOM(info);
     }
 
     var currType = this.getEventType(aExpectedEventIdx);
     var currTarget = this.getEventTarget(aExpectedEventIdx);
 
-    var containerTagName = document instanceof nsIDOMHTMLDocument ?
-      "div" : "description";
-    var inlineTagName = document instanceof nsIDOMHTMLDocument ?
-      "span" : "description";
-
-    var container = document.createElement(containerTagName);
-    container.setAttribute("style", "padding-left: 10px;");
+    var msg = "EQ: ";
+    var emphText = "";
+    if (aMatch) {
+      emphText = "matched ";
 
-    var text1 = document.createTextNode("EQ: ");
-    container.appendChild(text1);
-
-    var styledNode = document.createElement(inlineTagName);
-    if (aMatch) {
-      styledNode.setAttribute("style", "color: blue;");
-      styledNode.textContent = "matched";
-
-      // Dump matched events into console.
-      if (gA11yEventDumpToConsole)
-        dump("\n*****\nEQ matched: " + eventTypeToString(currType) + "\n*****\n");
+      var consoleMsg =
+        "*****\nEQ matched: " + eventTypeToString(currType) + "\n*****";
+      gLogger.logToConsole(consoleMsg);
 
     } else {
-      styledNode.textContent = "expected";
+      msg += "expected";
     }
-    container.appendChild(styledNode);
 
-    var info = " event, type: ";
-    info += (typeof currType == "string") ?
+    msg += " event, type: ";
+    msg += (typeof currType == "string") ?
       currType : eventTypeToString(currType);
-    info += ". Target: " + prettyName(currTarget);
+    msg += ", target: " + prettyName(currTarget);
 
-    var text1 = document.createTextNode(info);
-    container.appendChild(text1);
-
-    dumpInfoToDOM(container);
+    gLogger.logToDOM(msg, true, emphText);
   }
 
   this.mDefEventType = aEventType;
 
   this.mInvokers = new Array();
   this.mIndex = -1;
 
   this.mEventSeq = null;
@@ -635,32 +650,33 @@ function sequence()
   this.idx = -1;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Event queue invokers
 
 /**
- * Invokers defined below take a checker object implementing 'check' method
- * which will be called when proper event is handled. Invokers listen default
- * event type registered in event queue object until it is passed explicetly.
+ * Invokers defined below take a checker object (or array of checker objects)
+ * implementing 'check' method which will be called when proper event is
+ * handled. Invokers listen default event type registered in event queue object
+ * until it is passed explicetly.
  *
- * Note, checker object is optional.
+ * Note, checker object or array of checker objects is optional.
  * Note, you don't need to initialize 'target' and 'type' members of checker
  * object. The 'target' member will be initialized by invoker object and you are
  * free to use it in 'check' method.
  */
 
 /**
  * Click invoker.
  */
-function synthClick(aNodeOrID, aChecker, aEventType)
+function synthClick(aNodeOrID, aCheckerOrEventSeq, aEventType)
 {
-  this.__proto__ = new synthAction(aNodeOrID, aChecker, aEventType);
+  this.__proto__ = new synthAction(aNodeOrID, aCheckerOrEventSeq, aEventType);
 
   this.invoke = function synthClick_invoke()
   {
     // Scroll the node into view, otherwise synth click may fail.
     if (this.DOMNode instanceof nsIDOMNSHTMLElement)
       this.DOMNode.scrollIntoView(true);
 
     synthesizeMouse(this.DOMNode, 1, 1, {});
@@ -670,38 +686,38 @@ function synthClick(aNodeOrID, aChecker,
   {
     return prettyName(aNodeOrID) + " click"; 
   }
 }
 
 /**
  * Mouse move invoker.
  */
-function synthMouseMove(aNodeOrID, aChecker, aEventType)
+function synthMouseMove(aNodeOrID, aCheckerOrEventSeq, aEventType)
 {
-  this.__proto__ = new synthAction(aNodeOrID, aChecker, aEventType);
+  this.__proto__ = new synthAction(aNodeOrID, aCheckerOrEventSeq, aEventType);
 
   this.invoke = function synthMouseMove_invoke()
   {
     synthesizeMouse(this.DOMNode, 1, 1, { type: "mousemove" });
     synthesizeMouse(this.DOMNode, 2, 2, { type: "mousemove" });
   }
 
   this.getID = function synthMouseMove_getID()
   {
     return prettyName(aNodeOrID) + " mouse move"; 
   }
 }
 
 /**
  * General key press invoker.
  */
-function synthKey(aNodeOrID, aKey, aArgs, aChecker, aEventType)
+function synthKey(aNodeOrID, aKey, aArgs, aCheckerOrEventSeq, aEventType)
 {
-  this.__proto__ = new synthAction(aNodeOrID, aChecker, aEventType);
+  this.__proto__ = new synthAction(aNodeOrID, aCheckerOrEventSeq, aEventType);
 
   this.invoke = function synthKey_invoke()
   {
     synthesizeKey(this.mKey, this.mArgs);
   }
 
   this.getID = function synthKey_getID()
   {
@@ -710,126 +726,126 @@ function synthKey(aNodeOrID, aKey, aArgs
 
   this.mKey = aKey;
   this.mArgs = aArgs ? aArgs : {};
 }
 
 /**
  * Tab key invoker.
  */
-function synthTab(aNodeOrID, aChecker, aEventType)
+function synthTab(aNodeOrID, aCheckerOrEventSeq, aEventType)
 {
   this.__proto__ = new synthKey(aNodeOrID, "VK_TAB", { shiftKey: false },
-                                aChecker, aEventType);
+                                aCheckerOrEventSeq, aEventType);
 
   this.getID = function synthTab_getID() 
   { 
     return prettyName(aNodeOrID) + " tab";
   }
 }
 
 /**
  * Shift tab key invoker.
  */
-function synthShiftTab(aNodeOrID, aChecker, aEventType)
+function synthShiftTab(aNodeOrID, aCheckerOrEventSeq, aEventType)
 {
   this.__proto__ = new synthKey(aNodeOrID, "VK_TAB", { shiftKey: true },
-                                aChecker, aEventType);
+                                aCheckerOrEventSeq, aEventType);
 
   this.getID = function synthTabTest_getID() 
   { 
     return prettyName(aNodeOrID) + " shift tab";
   }
 }
 
 /**
  * Down arrow key invoker.
  */
-function synthDownKey(aNodeOrID, aChecker, aEventType)
+function synthDownKey(aNodeOrID, aCheckerOrEventSeq, aEventType)
 {
-  this.__proto__ = new synthKey(aNodeOrID, "VK_DOWN", null, aChecker,
+  this.__proto__ = new synthKey(aNodeOrID, "VK_DOWN", null, aCheckerOrEventSeq,
                                 aEventType);
 
   this.getID = function synthDownKey_getID()
   {
     return prettyName(aNodeOrID) + " key down";
   }
 }
 
 /**
  * Right arrow key invoker.
  */
-function synthRightKey(aNodeOrID, aChecker, aEventType)
+function synthRightKey(aNodeOrID, aCheckerOrEventSeq, aEventType)
 {
-  this.__proto__ = new synthKey(aNodeOrID, "VK_RIGHT", null, aChecker,
+  this.__proto__ = new synthKey(aNodeOrID, "VK_RIGHT", null, aCheckerOrEventSeq,
                                 aEventType);
 
   this.getID = function synthRightKey_getID()
   {
     return prettyName(aNodeOrID) + " key right";
   }
 }
 
 /**
  * Home key invoker.
  */
-function synthHomeKey(aNodeOrID, aChecker, aEventType)
+function synthHomeKey(aNodeOrID, aCheckerOrEventSeq, aEventType)
 {
-  this.__proto__ = new synthKey(aNodeOrID, "VK_HOME", null, aChecker,
+  this.__proto__ = new synthKey(aNodeOrID, "VK_HOME", null, aCheckerOrEventSeq,
                                 aEventType);
   
   this.getID = function synthHomeKey_getID()
   {
     return prettyName(aNodeOrID) + " key home";
   }
 }
 
 /**
  * Focus invoker.
  */
-function synthFocus(aNodeOrID, aChecker, aEventType)
+function synthFocus(aNodeOrID, aCheckerOrEventSeq, aEventType)
 {
-  this.__proto__ = new synthAction(aNodeOrID, aChecker, aEventType);
+  this.__proto__ = new synthAction(aNodeOrID, aCheckerOrEventSeq, aEventType);
 
   this.invoke = function synthFocus_invoke()
   {
     this.DOMNode.focus();
   }
 
   this.getID = function synthFocus_getID() 
   { 
     return prettyName(aNodeOrID) + " focus";
   }
 }
 
 /**
  * Focus invoker. Focus the HTML body of content document of iframe.
  */
-function synthFocusOnFrame(aNodeOrID, aChecker, aEventType)
+function synthFocusOnFrame(aNodeOrID, aCheckerOrEventSeq, aEventType)
 {
   this.__proto__ = new synthAction(getNode(aNodeOrID).contentDocument,
-                                   aChecker, aEventType);
+                                   aCheckerOrEventSeq, aEventType);
   
   this.invoke = function synthFocus_invoke()
   {
     this.DOMNode.body.focus();
   }
   
   this.getID = function synthFocus_getID() 
   { 
     return prettyName(aNodeOrID) + " frame document focus";
   }
 }
 
 /**
  * Select all invoker.
  */
-function synthSelectAll(aNodeOrID, aChecker, aEventType)
+function synthSelectAll(aNodeOrID, aCheckerOrEventSeq, aEventType)
 {
-  this.__proto__ = new synthAction(aNodeOrID, aChecker, aEventType);
+  this.__proto__ = new synthAction(aNodeOrID, aCheckerOrEventSeq, aEventType);
 
   this.invoke = function synthSelectAll_invoke()
   {
     if (this.DOMNode instanceof Components.interfaces.nsIDOMHTMLInputElement)
       this.DOMNode.select();
     else
       window.getSelection().selectAllChildren(this.DOMNode);
   }
@@ -906,46 +922,46 @@ var gA11yEventObserver =
       // Remove the leftover observer, otherwise it "leaks" to all the following tests.
       this.observerService.removeObserver(this, "accessible-event");
       // Forward the exception, with added explanation.
       throw "[accessible/events.js, gA11yEventObserver.observe] This is expected if a previous test has been aborted... Initial exception was: [ " + ex + " ]";
     }
     var listenersArray = gA11yEventListeners[event.eventType];
 
     var eventFromDumpArea = false;
-    if (gA11yEventDumpID) { // debug stuff
+    if (gLogger.isEnabled()) { // debug stuff
       eventFromDumpArea = true;
 
       var target = event.DOMNode;
-      var dumpElm = document.getElementById(gA11yEventDumpID);
+      var dumpElm = gA11yEventDumpID ?
+        document.getElementById(gA11yEventDumpID) : null;
 
-      var parent = target;
-      while (parent && parent != dumpElm)
-        parent = parent.parentNode;
+      if (dumpElm) {
+        var parent = target;
+        while (parent && parent != dumpElm)
+          parent = parent.parentNode;
+      }
 
-      if (parent != dumpElm) {
+      if (!dumpElm || parent != dumpElm) {
         var type = eventTypeToString(event.eventType);
         var info = "Event type: " + type;
 
         if (event instanceof nsIAccessibleTextChangeEvent) {
           info += ", start: " + event.start + ", length: " + event.length +
             ", " + (event.isInserted() ? "inserted" : "removed") +
             " text: " + event.modifiedText;
         }
 
         info += ". Target: " + prettyName(event.accessible);
 
         if (listenersArray)
           info += ". Listeners count: " + listenersArray.length;
 
         eventFromDumpArea = false;
-
-        if (gA11yEventDumpToConsole)
-          dump("\n" + info + "\n");
-        dumpInfoToDOM(info);
+        gLogger.log(info);
       }
     }
 
     // Do not notify listeners if event is result of event log changes.
     if (!listenersArray || eventFromDumpArea)
       return;
 
     for (var index = 0; index < listenersArray.length; index++)
@@ -993,45 +1009,103 @@ function removeA11yEventListener(aEventT
     gA11yEventListeners[aEventType] = null;
     delete gA11yEventListeners[aEventType];
   }
 
   return true;
 }
 
 /**
- * Dumps message to DOM.
- *
- * @param aInfo      [in] the message or DOM node to dump
- * @param aDumpNode  [in, optional] host DOM node for dumped message, if ommited
- *                    then global variable gA11yEventDumpID is used
+ * Used to dump debug information.
  */
-function dumpInfoToDOM(aInfo, aDumpNode)
+var gLogger =
 {
-  var dumpID = gA11yEventDumpID ? gA11yEventDumpID : aDumpNode;
-  if (!dumpID)
-    return;
-  
-  var dumpElm = document.getElementById(dumpID);
-  if (!dumpElm) {
-    ok(false, "No dump element '" + dumpID + "' within the document!");
-    return;
-  }
-  
-  var containerTagName = document instanceof nsIDOMHTMLDocument ?
-    "div" : "description";
+  /**
+   * Return true if dump is enabled.
+   */
+  isEnabled: function debugOutput_isEnabled()
+  {
+    return gA11yEventDumpID || gA11yEventDumpToConsole ||
+      gA11yEventDumpToAppConsole;
+  },
+
+  /**
+   * Dump information into DOM and console if applicable.
+   */
+  log: function logger_log(aMsg)
+  {
+    this.logToConsole(aMsg);
+    this.logToAppConsole(aMsg);
+    this.logToDOM(aMsg);
+  },
+
+  /**
+   * Log message to DOM.
+   *
+   * @param aMsg          [in] the primary message
+   * @param aHasIndent    [in, optional] if specified the message has an indent
+   * @param aPreEmphText  [in, optional] the text is colored and appended prior
+   *                        primary message
+   */
+  logToDOM: function logger_logToDOM(aMsg, aHasIndent, aPreEmphText)
+  {
+    if (gA11yEventDumpID == "")
+      return;
+
+    var dumpElm = document.getElementById(gA11yEventDumpID);
+    if (!dumpElm) {
+      ok(false,
+         "No dump element '" + gA11yEventDumpID + "' within the document!");
+      return;
+    }
+
+    var containerTagName = document instanceof nsIDOMHTMLDocument ?
+      "div" : "description";
 
-  var container = document.createElement(containerTagName);
-  if (aInfo instanceof nsIDOMNode)
-    container.appendChild(aInfo);
-  else
-    container.textContent = aInfo;
+    var container = document.createElement(containerTagName);
+    if (aHasIndent)
+      container.setAttribute("style", "padding-left: 10px;");
+
+    if (aPreEmphText) {
+      var inlineTagName = document instanceof nsIDOMHTMLDocument ?
+        "span" : "description";
+      var emphElm = document.createElement(inlineTagName);
+      emphElm.setAttribute("style", "color: blue;");
+      emphElm.textContent = aPreEmphText;
+
+      container.appendChild(emphElm);
+    }
+
+    var textNode = document.createTextNode(aMsg);
+    container.appendChild(textNode);
+
+    dumpElm.appendChild(container);
+  },
 
-  dumpElm.appendChild(container);
-}
+  /**
+   * Log message to console.
+   */
+  logToConsole: function logger_logToConsole(aMsg)
+  {
+    if (gA11yEventDumpToConsole)
+      dump("\n" + aMsg + "\n");
+  },
+
+  /**
+   * Log message to error console.
+   */
+  logToAppConsole: function logger_logToAppConsole(aMsg)
+  {
+    if (gA11yEventDumpToAppConsole)
+      consoleService.logStringMessage("events: " + aMsg);
+  },
+
+  consoleService: Components.classes["@mozilla.org/consoleservice;1"].
+    getService(Components.interfaces.nsIConsoleService)
+};
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Sequence
 
 /**
  * Base class of sequence item.
  */
@@ -1068,25 +1142,33 @@ function sequenceItem(aProcessor, aEvent
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Event queue invokers
 
 /**
  * Invoker base class for prepare an action.
  */
-function synthAction(aNodeOrID, aChecker, aEventType)
+function synthAction(aNodeOrID, aCheckerOrEventSeq, aEventType)
 {
   this.DOMNode = getNode(aNodeOrID);
-  if (aChecker)
-    aChecker.target = this.DOMNode;
+
+  this.checker = null;
+  if (aCheckerOrEventSeq) {
+    if (aCheckerOrEventSeq instanceof Array) {
+      this.eventSeq = aCheckerOrEventSeq;
+    } else {
+      this.checker = aCheckerOrEventSeq;
+      this.checker.target = this.DOMNode;
+    }
+  }
 
   if (aEventType)
     this.eventSeq = [ new invokerChecker(aEventType, this.DOMNode) ];
 
   this.check = function synthAction_check(aEvent)
   {
-    if (aChecker)
-      aChecker.check(aEvent);
+    if (this.checker)
+      this.checker.check(aEvent);
   }
 
   this.getID = function synthAction_getID() { return aNodeOrID + " action"; }
 }
--- a/accessible/tests/mochitest/events/Makefile.in
+++ b/accessible/tests/mochitest/events/Makefile.in
@@ -60,16 +60,17 @@ include $(topsrcdir)/config/rules.mk
 		test_docload.html \
 		test_docload.xul \
 		test_dragndrop.html \
 		test_flush.html \
 		test_focus.html \
 		test_focus.xul \
 		test_focus_name.html \
 		test_focusdoc.html \
+		test_menu.xul \
 		test_mutation.html \
 		test_scroll.xul \
 		test_selection.html \
 		test_statechange.html \
 		test_text.html \
 		test_textattrchange.html \
 		test_tree.xul \
 		test_valuechange.html \
--- a/accessible/tests/mochitest/events/test_aria_menu.html
+++ b/accessible/tests/mochitest/events/test_aria_menu.html
@@ -5,36 +5,56 @@
 
   <link rel="stylesheet" type="text/css"
         href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript"
           src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
   <script type="application/javascript"
           src="../events.js"></script>
 
   <script type="application/javascript">
     const kViaDisplayStyle = 0;
     const kViaVisibilityStyle = 1;
 
-    function showMenu(aMenuID, aHow)
+    function focusMenu(aMenuBarID, aMenuID)
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_MENU_START, getNode(aMenuBarID)),
+        new invokerChecker(EVENT_FOCUS, getNode(aMenuID)),
+      ];
+
+      this.invoke = function focusMenu_invoke()
+      {
+        getNode(aMenuID).focus();
+      }
+
+      this.getID = function focusMenu_getID()
+      {
+        return "focus menu '" + aMenuID + "'";
+      }
+    }
+
+    function showMenu(aMenuID, aParentMenuID, aHow)
     {
       this.menuNode = getNode(aMenuID);
 
       this.eventSeq = [
         new invokerChecker(EVENT_SHOW, this.menuNode),
         new invokerChecker(EVENT_MENUPOPUP_START, this.menuNode),
-        new invokerChecker(EVENT_REORDER, document)
+        new invokerChecker(EVENT_REORDER, getNode(aParentMenuID))
       ];
 
       this.invoke = function showMenu_invoke()
       {
         if (aHow == kViaDisplayStyle)
           this.menuNode.style.display = "block";
         else
           this.menuNode.style.visibility = "visible";
@@ -43,25 +63,25 @@
       this.getID = function showMenu_getID()
       {
         return "Show ARIA menu " + aMenuID + " by " +
           (aHow == kViaDisplayStyle ? "display" : "visibility") +
           " style tricks";
       };
     }
 
-    function closeMenu(aMenuID, aHow)
+    function closeMenu(aMenuID, aParentMenuID, aHow)
     {
       this.menuNode = getNode(aMenuID);
       this.menu = null;
 
       this.eventSeq = [
         new invokerChecker(EVENT_MENUPOPUP_END, getMenu, this),
         new invokerChecker(EVENT_HIDE, getMenu, this),
-        new invokerChecker(EVENT_REORDER, document),
+        new invokerChecker(EVENT_REORDER, getNode(aParentMenuID))
       ];
 
       this.invoke = function closeMenu_invoke()
       {
         // Store menu accessible reference while menu is still open.
         this.menu = getAccessible(this.menuNode);
 
         // Hide menu.
@@ -79,31 +99,71 @@
       }
 
       function getMenu(aThisObj)
       {
         return aThisObj.menu;
       }
     }
 
+    function focusInsideMenu(aMenuID, aMenuBarID)
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_FOCUS, getNode(aMenuID))
+      ];
+
+      this.unexpectedEventSeq = [
+        new invokerChecker(EVENT_MENU_END, getNode(aMenuBarID))
+      ];
+
+      this.invoke = function focusInsideMenu_invoke()
+      {
+        getNode(aMenuID).focus();
+      }
+
+      this.getID = function focusInsideMenu_getID()
+      {
+        return "focus menu '" + aMenuID + "'";
+      }
+    }
+
+    function blurMenu(aMenuBarID)
+    {
+      var eventSeq = [
+        new invokerChecker(EVENT_MENU_END, getNode(aMenuBarID)),
+        new invokerChecker(EVENT_FOCUS, getNode("outsidemenu"))
+      ];
+
+      this.__proto__ = new synthClick("outsidemenu", eventSeq);
+
+      this.getID = function blurMenu_getID()
+      {
+        return "blur menu";
+      }
+    }
+
     ////////////////////////////////////////////////////////////////////////////
     // Do tests
 
     var gQueue = null;
 
     //gA11yEventDumpID = "eventdump";
+    //gA11yEventDumpToConsole = true;
 
     function doTests()
     {
       gQueue = new eventQueue();
 
-      gQueue.push(new showMenu("menu1", kViaDisplayStyle));
-      gQueue.push(new closeMenu("menu1", kViaDisplayStyle));
-      gQueue.push(new showMenu("menu2", kViaVisibilityStyle));
-      gQueue.push(new closeMenu("menu2", kViaVisibilityStyle));
+      gQueue.push(new focusMenu("menubar", "menu-file"));
+      gQueue.push(new showMenu("menupopup-file", "menu-file", kViaDisplayStyle));
+      gQueue.push(new closeMenu("menupopup-file", "menu-file", kViaDisplayStyle));
+      gQueue.push(new showMenu("menupopup-edit", "menu-edit", kViaVisibilityStyle));
+      gQueue.push(new closeMenu("menupopup-edit", "menu-edit", kViaVisibilityStyle));
+      gQueue.push(new focusInsideMenu("menu-edit", "menubar"));
+      gQueue.push(new blurMenu("menubar"));
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
@@ -115,27 +175,41 @@
      title="Dojo dropdown buttons are broken">
     Mozilla Bug 606207
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=614829"
      title="Menupopup end event isn't fired for ARIA menus">
     Mozilla Bug 614829
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=615189"
+     title="Clean up FireAccessibleFocusEvent">
+    Mozilla Bug 615189
+  </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
-  <div id="menu1" role="menu" style="display: none;">
-    <div role="menuitem">menuitem1.1</div>
-    <div role="menuitem">menuitem1.2</div>
+  <div id="menubar" role="menubar">
+    <div id="menu-file" role="menuitem" tabindex="0">
+      File
+      <div id="menupopup-file" role="menu" style="display: none;">
+        <div id="menuitem-newtab" role="menuitem" tabindex="0">New Tab</div>
+        <div id="menuitem-newwindow" role="menuitem" tabindex="0">New Window</div>
+      </div>
+    </div>
+    <div id="menu-edit" role="menuitem" tabindex="0">
+      Edit
+      <div id="menupopup-edit" role="menu" style="visibility: hidden;">
+        <div id="menuitem-undo" role="menuitem" tabindex="0">Undo</div>
+        <div id="menuitem-redo" role="menuitem" tabindex="0">Redo</div>
+      </div>
+    </div>
   </div>
-  <div id="menu2" role="menu" style="visibility: hidden;">
-    <div role="menuitem">menuitem2.1</div>
-    <div role="menuitem">menuitem2.2</div>
-  </div>
+  <div tabindex="0" id="outsidemenu">outsidemenu</div>
 
   <div id="eventdump"></div>
 
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/events/test_menu.xul
@@ -0,0 +1,204 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="Accessible menu events testing for XUL menu">
+
+  <script type="application/javascript" 
+          src="chrome://mochikit/content/MochiKit/packed.js" />
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+  <script type="application/javascript"
+          src="../common.js" />
+  <script type="application/javascript"
+          src="../events.js" />
+
+  <script type="application/javascript">
+    function openFileMenu()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_MENU_START, getNode("menubar")),
+        new invokerChecker(EVENT_MENUPOPUP_START, getNode("menupopup-file"))
+        // new invokerChecker(EVENT_FOCUS, getNode("menuitem-newtab")) intermitent failure
+      ];
+
+      this.invoke = function openFileMenu_invoke()
+      {
+        synthesizeKey("F", { altKey: true, shiftKey: true });
+      }
+
+      this.getID = function openFileMenu_getID()
+      {
+        return "open file menu by alt+F press";
+      }
+    }
+
+    function openEditMenu()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_MENUPOPUP_END, getNode("menupopup-file")),
+        new invokerChecker(EVENT_MENUPOPUP_START, getNode("menupopup-edit"))
+        // new invokerChecker(EVENT_FOCUS, getNode("menuitem-undo")) intermitent failure
+      ];
+
+      this.invoke = function openEditMenu_invoke()
+      {
+        synthesizeKey("VK_RIGHT", { });
+      }
+
+      this.getID = function openEditMenu_getID()
+      {
+        return "open edit menu by lef arrow press";
+      }
+    }
+
+    function closeEditMenu()
+    {
+      this.eventSeq = [
+        //new invokerChecker(EVENT_FOCUS, document), intermitent failure
+        new invokerChecker(EVENT_MENUPOPUP_END, getNode("menupopup-edit")),
+        new invokerChecker(EVENT_MENU_END, getNode("menubar"))
+      ];
+
+      this.invoke = function closeEditMenu_invoke()
+      {
+        synthesizeKey("VK_ESCAPE", { });
+      }
+
+      this.getID = function closeEditMenu_getID()
+      {
+        return "close edit menu, leave menubar";
+      }
+    }
+
+    function focusFileMenu()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_MENU_START, getNode("menubar")),
+        new invokerChecker(EVENT_FOCUS, getNode("menuitem-file"))
+      ];
+
+      this.invoke = function focusFileMenu_invoke()
+      {
+        synthesizeKey("VK_ALT", { });
+      }
+
+      this.getID = function focusFileMenu_getID()
+      {
+        return "activate menubar, focus file menu (atl press)";
+      }
+    }
+
+    function focusEditMenu()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_FOCUS, getNode("menuitem-edit"))
+      ];
+
+      this.invoke = function focusEditMenu_invoke()
+      {
+        synthesizeKey("VK_RIGHT", { });
+      }
+
+      this.getID = function focusEditMenu_getID()
+      {
+        return "focus edit menu";
+      }
+    }
+
+    function leaveMenubar()
+    {
+      this.eventSeq = [
+        //new invokerChecker(EVENT_FOCUS, document), intermitent failure
+        new invokerChecker(EVENT_MENU_END, getNode("menubar"))
+      ];
+
+      this.invoke = function leaveMenubar_invoke()
+      {
+        synthesizeKey("VK_ESCAPE", { });
+      }
+
+      this.getID = function leaveMenubar_getID()
+      {
+        return "leave menubar";
+      }
+    }
+
+    /**
+     * Do tests.
+     */
+
+    //gA11yEventDumpID = "eventdump";
+    gA11yEventDumpToConsole = true;
+
+    var gQueue = null;
+
+    function doTests()
+    {
+      if (!WIN) {
+        todo(false, "Enable this test on other platforms.");
+        SimpleTest.finish();
+        return;
+      }
+
+      todo(false,
+           "Fix intermitent failures. Focus may randomly occur before or after menupopup events!");
+
+      gQueue = new eventQueue();
+
+      gQueue.push(new openFileMenu());
+      gQueue.push(new openEditMenu());
+      gQueue.push(new closeEditMenu());
+
+      // Alt key is used to active menubar and focus menu item on Windows,
+      // other platforms requires setting a ui.key.menuAccessKeyFocuses
+      // preference.
+      if (WIN) {
+        gQueue.push(new focusFileMenu());
+        gQueue.push(new focusEditMenu());
+        gQueue.push(new leaveMenubar());
+      }
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTests);
+  </script>
+
+  <hbox flex="1" style="overflow: auto;">
+    <body xmlns="http://www.w3.org/1999/xhtml">
+      <a target="_blank"
+         href="https://bugzilla.mozilla.org/show_bug.cgi?id=615189"
+         title="Clean up FireAccessibleFocusEvent">
+        Mozilla Bug 615189
+      </a>
+      <p id="display"></p>
+      <div id="content" style="display: none"></div>
+      <pre id="test">
+      </pre>
+    </body>
+
+    <vbox flex="1">
+      <menubar id="menubar">
+        <menu id="menuitem-file" label="File" accesskey="F">
+          <menupopup id="menupopup-file">
+            <menuitem id="menuitem-newtab" label="New Tab"/>
+          </menupopup>
+        </menu>
+        <menu id="menuitem-edit" label="Edit" accesskey="E">
+          <menupopup id="menupopup-edit">
+            <menuitem id="menuitem-undo" label="Undo"/>
+          </menupopup>
+        </menu>
+      </menubar>
+
+      <vbox id="eventdump" role="log"/>
+    </vbox>
+  </hbox>
+</window>
--- a/accessible/tests/mochitest/name/markup.js
+++ b/accessible/tests/mochitest/name/markup.js
@@ -1,15 +1,19 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Name tests described by "markuprules.xml" file.
 
 var gNameRulesFileURL = "markuprules.xml";
 
 var gRuleDoc = null;
 
+// Debuggin stuff.
+var gDumpToConsole = false;
+gA11yEventDumpToConsole = gDumpToConsole;
+
 /**
  * Start name tests. Run through markup elements and test names for test
  * element (see namerules.xml for details).
  */
 function testNames()
 {
   var request = new XMLHttpRequest();
   request.open("get", gNameRulesFileURL, false);
@@ -56,20 +60,26 @@ var gTestIterator =
     this.ruleIdx++;
     if (this.ruleIdx == this.ruleElms.length) {
       this.markupIdx++;
       if (this.markupIdx == this.markupElms.length) {
         SimpleTest.finish();
         return;
       }
 
-      document.body.removeChild(this.container);
+      this.ruleIdx = -1;
 
-      this.ruleIdx = -1;
-      testNamesForMarkup(this.markupElms[this.markupIdx]);
+      if (gDumpToConsole) {
+        dump("\nPend next markup processing. Wait for reorder event on " +
+             prettyName(document) + "'\n");
+      }
+      waitForEvent(EVENT_REORDER, document, testNamesForMarkup,
+                   null, this.markupElms[this.markupIdx]);
+
+      document.body.removeChild(this.container);
       return;
     }
 
     testNameForRule(this.elm, this.ruleElms[this.ruleIdx]);
   },
 
   markupElms: null,
   markupIdx: -1,
@@ -80,34 +90,44 @@ var gTestIterator =
 };
 
 /**
  * Process every 'markup' element and test names for it. Used by testNames
  * function.
  */
 function testNamesForMarkup(aMarkupElm)
 {
+  if (gDumpToConsole)
+    dump("\nProcessing markup '" + aMarkupElm.getAttribute("id") + "'\n");
+
   var div = document.createElement("div");
   div.setAttribute("id", "test");
 
   var child = aMarkupElm.firstChild;
   while (child) {
     var newChild = document.importNode(child, true);
     div.appendChild(newChild);
     child = child.nextSibling;
   }
 
+  if (gDumpToConsole) {
+    dump("\nProcessing markup. Wait for reorder event on " +
+         prettyName(document) + "'\n");
+  }
   waitForEvent(EVENT_REORDER, document, testNamesForMarkupRules,
                 null, aMarkupElm, div);
 
   document.body.appendChild(div);
 }
 
 function testNamesForMarkupRules(aMarkupElm, aContainer)
 {
+  if (gDumpToConsole)
+    dump("\nProcessing markup rules '" + aMarkupElm.getAttribute("id") + "'\n");
+
   ensureAccessibleTree(aContainer);
 
   var serializer = new XMLSerializer();
 
   var expr = "//html/body/div[@id='test']/" + aMarkupElm.getAttribute("ref");
   var elms = evaluateXPath(document, expr, htmlDocResolver);
 
   var ruleId = aMarkupElm.getAttribute("ruleset");
@@ -117,22 +137,39 @@ function testNamesForMarkupRules(aMarkup
 }
 
 /**
  * Test name for current rule and current 'markup' element. Used by
  * testNamesForMarkup function.
  */
 function testNameForRule(aElm, aRuleElm)
 {
-  if (aRuleElm.hasAttribute("attr"))
+  if (aRuleElm.hasAttribute("attr")) {
+    if (gDumpToConsole) {
+      dump("\nProcessing rule { attr: " + aRuleElm.getAttribute("attr") +" }\n");
+    }
+
     testNameForAttrRule(aElm, aRuleElm);
-  else if (aRuleElm.hasAttribute("elm") && aRuleElm.hasAttribute("elmattr"))
+
+  } else if (aRuleElm.hasAttribute("elm") && aRuleElm.hasAttribute("elmattr")) {
+    if (gDumpToConsole) {
+      dump("\nProcessing rule { elm: " + aRuleElm.getAttribute("elm") +
+           ", elmattr: " + aRuleElm.getAttribute("elmattr") +" }\n");
+    }
+
     testNameForElmRule(aElm, aRuleElm);
-  else if (aRuleElm.getAttribute("fromsubtree") == "true")
+
+  } else if (aRuleElm.getAttribute("fromsubtree") == "true") {
+    if (gDumpToConsole) {
+      dump("\nProcessing rule { fromsubtree: " +
+           aRuleElm.getAttribute("fromsubtree") +" }\n");
+    }
+
     testNameForSubtreeRule(aElm, aRuleElm);
+  }
 }
 
 function testNameForAttrRule(aElm, aRule)
 {
   var name = "";
 
   var attr = aRule.getAttribute("attr");
   var attrValue = aElm.getAttribute(attr);
@@ -182,27 +219,36 @@ function testNameForElmRule(aElm, aRule)
   var treeWalker = document.createTreeWalker(document.body,
                                              NodeFilter.SHOW_ELEMENT,
                                              filter, false);
   var labelElm = treeWalker.nextNode();
   var msg = "Element '" + elm + "' test.";
   testName(aElm, labelElm.getAttribute("a11yname"), msg);
 
   var parentNode = labelElm.parentNode;
+
+  if (gDumpToConsole) {
+    dump("\nProcessed elm rule. Wait for reorder event on " +
+         prettyName(parentNode) + "'\n");
+  }
   waitForEvent(EVENT_REORDER, parentNode,
                gTestIterator.iterateNext, gTestIterator);
 
   parentNode.removeChild(labelElm);
 }
 
 function testNameForSubtreeRule(aElm, aRule)
 {
   var msg = "From subtree test.";
   testName(aElm, aElm.getAttribute("a11yname"), msg);
 
+  if (gDumpToConsole) {
+    dump("\nProcessed from subtree rule. Wait for reorder event on " +
+         prettyName(aElm) + "\n");
+  }
   waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
 
   while (aElm.firstChild)
     aElm.removeChild(aElm.firstChild);
 }
 
 /**
  * Return array of 'rule' elements. Used in conjunction with
--- a/accessible/tests/mochitest/name/markuprules.xml
+++ b/accessible/tests/mochitest/name/markuprules.xml
@@ -119,57 +119,59 @@
       <rule fromsubtree="true"/>
       <rule attr="title" type="string"/>
     </ruleset>
 
   </ruledfn>
 
   <rulesample>
 
-    <markup ref="html:button" ruleset="htmlctrl">
+    <markup ref="html:button" ruleset="htmlctrl" id="markup1test">
       <html:span id="l1" a11yname="test2">test2</html:span>
       <html:span id="l2" a11yname="test3">test3</html:span>
       <html:label for="btn" a11yname="test4">test4</html:label>
       <html:button id="btn"
                    aria-label="test1"
                    aria-labelledby="l1 l2"
                    title="test5"
                    a11yname="press me">press me</html:button>
     </markup>
 
-    <markup ref="html:input" ruleset="htmlinputbutton">
+    <markup ref="html:input" ruleset="htmlinputbutton" id="markup2test">
       <html:span id="l1" a11yname="test2">test2</html:span>
       <html:span id="l2" a11yname="test3">test3</html:span>
       <html:label for="btn" a11yname="test4">test4</html:label>
       <html:input id="btn"
                   type="button"
                   aria-label="test1"
                   aria-labelledby="l1 l2"
                   value="test5"
                   alt="test6"
                   src="test7"
                   data="test8"
                   title="test9"/>
     </markup>
 
-    <markup ref="html:select/html:option[1]" ruleset="htmloption">
+    <markup ref="html:select/html:option[1]" ruleset="htmloption"
+            id="markup3test">
       <html:span id="l1" a11yname="test2">test2</html:span>
       <html:span id="l2" a11yname="test3">test3</html:span>
       <html:select>
         <html:option id="opt"
                      aria-label="test1"
                      aria-labelledby="l1 l2"
                      label="test4"
                      title="test5"
                      a11yname="option1">option1</html:option>
         <html:option>option2</html:option>
       </html:select>
     </markup>
 
-    <markup ref="html:table/html:tr/html:td" ruleset="htmlelm">
+    <markup ref="html:table/html:tr/html:td" ruleset="htmlelm"
+            id="markup4test">
       <html:span id="l1" a11yname="test2">test2</html:span>
       <html:span id="l2" a11yname="test3">test3</html:span>
       <html:label for="tc" a11yname="test4">test4</html:label>
       <html:table>
         <html:tr>
           <html:td id="tc"
                    aria-label="test1"
                    aria-labelledby="l1 l2"
@@ -179,17 +181,18 @@
             <html:ul>
               <html:li>This is a list</html:li>
             </html:ul>
           </html:td>
         </html:tr>
       </html:table>
     </markup>
 
-    <markup ref="html:table/html:tr/html:td" ruleset="htmlctrl">
+    <markup ref="html:table/html:tr/html:td" ruleset="htmlctrl"
+            id="markup5test">
       <html:span id="l1" a11yname="test2">test2</html:span>
       <html:span id="l2" a11yname="test3">test3</html:span>
       <html:label for="gc" a11yname="test4">test4</html:label>
       <html:table>
         <html:tr>
           <html:td id="gc"
                    role="gridcell"
                    aria-label="test1"
--- a/accessible/tests/mochitest/test_keys.html
+++ b/accessible/tests/mochitest/test_keys.html
@@ -1,11 +1,12 @@
 <html>
 
 <head>
+  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
   <title>Keyboard shortcuts tests</title>
   <link rel="stylesheet" type="text/css"
         href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript"
           src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
@@ -22,17 +23,17 @@
 
       is(acc.keyboardShortcut, aKey,
          "Wrong keyboard shortcut on " + prettyName(aAccOrElmOrID));
     }
 
     function doTest()
     {
       testKeyboardShortcut("input1", "");
-      testKeyboardShortcut("input2", "Alt+Shift+b");
+      testKeyboardShortcut("input2", MAC ? "⌃b" : "Alt+Shift+b");
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 
--- a/browser/base/content/browser-appmenu.inc
+++ b/browser/base/content/browser-appmenu.inc
@@ -274,24 +274,24 @@
                       label="&historyRestoreLastSession.label;"
                       oncommand="restoreLastSession();"
                       disabled="true"/>
             <menu id="appmenu_recentlyClosedTabsMenu"
                   class="recentlyClosedTabsMenu"
                   label="&historyUndoMenu.label;"
                   disabled="true">
               <menupopup id="appmenu_recentlyClosedTabsMenupopup"
-                         onpopupshowing="document.getElementById('appmenu_historyMenu')._placesView.populateUndoSubmenu();"/>
+                         onpopupshowing="document.getElementById('appmenu_history')._placesView.populateUndoSubmenu();"/>
             </menu>
             <menu id="appmenu_recentlyClosedWindowsMenu"
                   class="recentlyClosedWindowsMenu"
                   label="&historyUndoWindowMenu.label;"
                   disabled="true">
               <menupopup id="appmenu_recentlyClosedWindowsMenupopup"
-                         onpopupshowing="document.getElementById('appmenu_historyMenu')._placesView.populateUndoWindowSubmenu();"/>
+                         onpopupshowing="document.getElementById('appmenu_history')._placesView.populateUndoWindowSubmenu();"/>
             </menu>
             <menuseparator/>
           </menupopup>
       </splitmenu>
       <menuitem id="appmenu_downloads"
                 class="menuitem-tooltip"
                 label="&downloads.label;"
                 command="Tools:Downloads"
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -225,17 +225,17 @@ var StarUI = {
     this._element("editBookmarkPanelStarIcon").removeAttribute("unstarred");
 
     this._itemId = aItemId !== undefined ? aItemId : this._itemId;
     this.beginBatch();
 
     // Consume dismiss clicks, see bug 400924
     this.panel.popupBoxObject
         .setConsumeRollupEvent(Ci.nsIPopupBoxObject.ROLLUP_CONSUME);
-    this.panel.openPopup(aAnchorElement, aPosition, -1, -1);
+    this.panel.openPopup(aAnchorElement, aPosition);
 
     gEditItemOverlay.initPanel(this._itemId,
                                { hiddenRows: ["description", "location",
                                               "loadInSidebar", "keyword"] });
   },
 
   panelShown:
   function SU_panelShown(aEvent) {
@@ -343,17 +343,18 @@ var PlacesCommandHook = {
 
     // dock the panel to the star icon when possible, otherwise dock
     // it to the content area
     if (aBrowser.contentWindow == window.content) {
       var starIcon = aBrowser.ownerDocument.getElementById("star-button");
       if (starIcon && isElementVisible(starIcon)) {
         // Make sure the bookmark properties dialog hangs toward the middle of
         // the location bar in RTL builds
-        var position = (getComputedStyle(gNavToolbox, "").direction == "rtl") ? 'after_start' : 'after_end';
+        var position = (getComputedStyle(gNavToolbox, "").direction == "rtl") ?
+          'bottomcenter topleft' : 'bottomcenter topright';
         if (aShowEditUI)
           StarUI.showEditBookmarkPopup(itemId, starIcon, position);
         return;
       }
     }
 
     StarUI.showEditBookmarkPopup(itemId, aBrowser, "overlap");
   },
@@ -840,21 +841,21 @@ var PlacesMenuDNDHandler = {
       event.target.lastChild.setAttribute("autoopened", "true");
       event.target.lastChild.showPopup(event.target.lastChild);
     }, this._springLoadDelay, Ci.nsITimer.TYPE_ONE_SHOT);
     event.preventDefault();
     event.stopPropagation();
   },
 
   /**
-   * Handles dragleave on the <menu> element.
+   * Handles dragexit on the <menu> element.
    * @returns true if the element is a container element (menu or 
    *          menu-toolbarbutton), false otherwise.
    */
-  onDragLeave: function PMDH_onDragLeave(event) {
+  onDragExit: function PMDH_onDragExit(event) {
     // Closing menus in a Places popup is handled by the view itself.
     if (!this._isStaticContainer(event.target))
       return;
 
     if (this._loadTimer) {
       this._loadTimer.cancel();
       this._loadTimer = null;
     }
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -243,10 +243,17 @@ let TabView = {
 
         self._initFrame(function() {
           let tabItem = self._window.GroupItems.getNextGroupItemTab(event.shiftKey);
           if (tabItem)
             window.gBrowser.selectedTab = tabItem.tab;
         });
       }
     }, true);
+  },
+  
+  // ----------
+  // Prepares the tab view for undo close tab.
+  prepareUndoCloseTab: function() {
+    if (this._window)
+      this._window.UI.restoredClosedTab = true;
   }
 };
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1223,16 +1223,19 @@ function BrowserStartup() {
   CombinedStopReload.init();
 
   allTabs.readPref();
 
   TabsOnTop.syncCommand();
 
   BookmarksMenuButton.init();
 
+  // initialize the private browsing UI
+  gPrivateBrowsingUI.init();
+
   setTimeout(delayedStartup, 0, isLoadingBlank, mustLoadSidebar);
 }
 
 function HandleAppCommandEvent(evt) {
   evt.stopPropagation();
   switch (evt.command) {
   case "Back":
     BrowserBack();
@@ -1508,19 +1511,16 @@ function delayedStartup(isLoadingBlank, 
 
 #ifndef XP_MACOSX
   updateEditUIVisibility();
   let placesContext = document.getElementById("placesContext");
   placesContext.addEventListener("popupshowing", updateEditUIVisibility, false);
   placesContext.addEventListener("popuphiding", updateEditUIVisibility, false);
 #endif
 
-  // initialize the private browsing UI
-  gPrivateBrowsingUI.init();
-
   gBrowser.mPanelContainer.addEventListener("InstallBrowserTheme", LightWeightThemeWebInstaller, false, true);
   gBrowser.mPanelContainer.addEventListener("PreviewBrowserTheme", LightWeightThemeWebInstaller, false, true);
   gBrowser.mPanelContainer.addEventListener("ResetBrowserThemePreview", LightWeightThemeWebInstaller, false, true);
 
   if (Win7Features)
     Win7Features.onOpenWindow();
 
   // called when we go into full screen, even if it is
@@ -2880,17 +2880,17 @@ var homeButtonObserver = {
       setTimeout(openHomeDialog, 0, browserDragAndDrop.drop(aEvent, { }));
     },
 
   onDragOver: function (aEvent)
     {
       browserDragAndDrop.dragOver(aEvent, "droponhomebutton");
       aEvent.dropEffect = "link";
     },
-  onDragLeave: function (aEvent)
+  onDragExit: function (aEvent)
     {
       XULWindowBrowser.setStatusText("");
     }
 }
 
 function openHomeDialog(aURL)
 {
   var promptTitle = gNavigatorBundle.getString("droponhometitle");
@@ -2923,29 +2923,29 @@ var bookmarksButtonObserver = {
   },
 
   onDragOver: function (aEvent)
   {
     browserDragAndDrop.dragOver(aEvent, "droponbookmarksbutton");
     aEvent.dropEffect = "link";
   },
 
-  onDragLeave: function (aEvent)
+  onDragExit: function (aEvent)
   {
     XULWindowBrowser.setStatusText("");
   }
 }
 
 var newTabButtonObserver = {
   onDragOver: function (aEvent)
   {
     browserDragAndDrop.dragOver(aEvent, "droponnewtabbutton");
   },
 
-  onDragLeave: function (aEvent)
+  onDragExit: function (aEvent)
   {
     XULWindowBrowser.setStatusText("");
   },
 
   onDrop: function (aEvent)
   {
     let url = browserDragAndDrop.drop(aEvent, { });
     var postData = {};
@@ -2957,17 +2957,17 @@ var newTabButtonObserver = {
   }
 }
 
 var newWindowButtonObserver = {
   onDragOver: function (aEvent)
   {
     browserDragAndDrop.dragOver(aEvent, "droponnewwindowbutton");
   },
-  onDragLeave: function (aEvent)
+  onDragExit: function (aEvent)
   {
     XULWindowBrowser.setStatusText("");
   },
   onDrop: function (aEvent)
   {
     let url = browserDragAndDrop.drop(aEvent, { });
     var postData = {};
     url = getShortcutOrURI(url, postData);
@@ -2984,17 +2984,17 @@ var DownloadsButtonDNDObserver = {
     XULWindowBrowser.setStatusText(gNavigatorBundle.getString("dropondownloadsbutton"));
     var types = aEvent.dataTransfer.types;
     if (types.contains("text/x-moz-url") ||
         types.contains("text/uri-list") ||
         types.contains("text/plain"))
       aEvent.preventDefault();
   },
 
-  onDragLeave: function (aEvent)
+  onDragExit: function (aEvent)
   {
     XULWindowBrowser.setStatusText("");
   },
 
   onDrop: function (aEvent)
   {
     let name = { };
     let url = browserDragAndDrop.drop(aEvent, name);
@@ -6779,16 +6779,17 @@ function undoCloseTab(aIndex) {
       !gPrefService.getBoolPref("browser.tabs.autoHide") &&
       isTabEmpty(gBrowser.selectedTab))
     blankTabToRemove = gBrowser.selectedTab;
 
   var tab = null;
   var ss = Cc["@mozilla.org/browser/sessionstore;1"].
            getService(Ci.nsISessionStore);
   if (ss.getClosedTabCount(window) > (aIndex || 0)) {
+    TabView.prepareUndoCloseTab();
     tab = ss.undoCloseTab(window, aIndex || 0);
 
     if (blankTabToRemove)
       gBrowser.removeTab(blankTabToRemove);
   }
 
   return tab;
 }
@@ -7259,17 +7260,17 @@ var gIdentityHandler = {
     this._identityPopup.popupBoxObject
         .setConsumeRollupEvent(Ci.nsIPopupBoxObject.ROLLUP_CONSUME);
 
     // Update the popup strings
     this.setPopupMessages(this._identityBox.className);
 
     // Make sure the identity popup hangs toward the middle of the location bar
     // in RTL builds
-    var position = (getComputedStyle(gNavToolbox, "").direction == "rtl") ? 'after_end' : 'after_start';
+    var position = (getComputedStyle(gNavToolbox, "").direction == "rtl") ? 'bottomcenter topright' : 'bottomcenter topleft';
 
     // Add the "open" attribute to the identity box for styling
     this._identityBox.setAttribute("open", "true");
     var self = this;
     this._identityPopup.addEventListener("popuphidden", function (e) {
       e.currentTarget.removeEventListener("popuphidden", arguments.callee, false);
       self._identityBox.removeAttribute("open");
     }, false);
@@ -7490,21 +7491,18 @@ let gPrivateBrowsingUI = {
     if (aTopic == "private-browsing") {
       if (aData == "enter")
         this.onEnterPrivateBrowsing();
       else if (aData == "exit")
         this.onExitPrivateBrowsing();
     }
     else if (aTopic == "private-browsing-transition-complete") {
       if (this._disableUIOnToggle) {
-        // use setTimeout here in order to make the code testable
-        setTimeout(function() {
-          document.getElementById("Tools:PrivateBrowsing")
-                  .removeAttribute("disabled");
-        }, 0);
+        document.getElementById("Tools:PrivateBrowsing")
+                .removeAttribute("disabled");
       }
     }
   },
 
   _shouldEnter: function PBUI__shouldEnter() {
     try {
       // Never prompt if the session is not going to be closed, or if user has
       // already requested not to be prompted.
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -169,16 +169,17 @@
     <panel type="autocomplete-richlistbox" id="PopupAutoCompleteRichResult" noautofocus="true" hidden="true"/>
 
     <!-- for invalid form error message -->
     <panel id="invalid-form-popup" type="arrow" orient="vertical" noautofocus="true" hidden="true" level="parent">
       <description/>
     </panel>
 
     <panel id="editBookmarkPanel"
+           type="arrow"
            orient="vertical"
            ignorekeys="true"
            hidden="true"
            onpopupshown="StarUI.panelShown(event);"
            aria-labelledby="editBookmarkPanelTitle">
       <row id="editBookmarkPanelHeader" align="center" hidden="true">
         <vbox align="center">
           <image id="editBookmarkPanelStarIcon"/>
@@ -329,20 +330,23 @@
                                return gContextMenu.shouldDisplay;"
                onpopuphiding="if (event.target == this) { gContextMenu = null; updateEditUIVisibility(); }">
 #include browser-context.inc
     </menupopup>
 
     <menupopup id="placesContext"/>
 
     <panel id="notification-popup" type="arrow" position="after_start"
-           noautofocus="true" hidden="true" orient="vertical"/>
+           hidden="true" orient="vertical"/>
 
     <!-- Popup for site identity information -->
-    <panel id="identity-popup" position="after_start" hidden="true" noautofocus="true"
+    <panel id="identity-popup"
+           type="arrow"
+           hidden="true"
+           noautofocus="true"
            onpopupshown="document.getElementById('identity-popup-more-info-button').focus();"
            level="top">
       <hbox id="identity-popup-container" align="top">
         <image id="identity-popup-icon"/>
         <vbox id="identity-popup-content-box">
           <label id="identity-popup-connectedToLabel"
                  class="identity-popup-label"
                  value="&identity.connectedTo;"/>
@@ -510,17 +514,17 @@
       </toolbaritem>
 
       <toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      persist="class" removable="true"
                      label="&homeButton.label;"
                      ondragover="homeButtonObserver.onDragOver(event)"
                      ondragenter="homeButtonObserver.onDragOver(event)"
                      ondrop="homeButtonObserver.onDrop(event)"
-                     ondragleave="homeButtonObserver.onDragLeave(event)"
+                     ondragexit="homeButtonObserver.onDragExit(event)"
                      onclick="BrowserGoHome(event);"
                      aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
 
       <toolbaritem id="urlbar-container" align="center" flex="400" persist="width" combined="true"
                    title="&locationItem.title;" class="chromeclass-location" removable="true">
         <textbox id="urlbar" flex="1"
                  placeholder="&urlbar.placeholder;"
                  type="autocomplete"
@@ -620,17 +624,17 @@
                    title="&bookmarksMenuButton.label;">
         <toolbarbutton id="bookmarks-menu-button"
                        type="menu"
                        class="toolbarbutton-1"
                        label="&bookmarksMenuButton.label;"
                        tooltiptext="&bookmarksMenuButton.tooltip;"
                        ondragenter="PlacesMenuDNDHandler.onDragEnter(event);"
                        ondragover="PlacesMenuDNDHandler.onDragOver(event);"
-                       ondragleave="PlacesMenuDNDHandler.onDragLeave(event);"
+                       ondragexit="PlacesMenuDNDHandler.onDragExit(event);"
                        ondrop="PlacesMenuDNDHandler.onDrop(event);">
           <menupopup id="BMB_bookmarksPopup"
                      placespopup="true"
                      context="placesContext"
                      openInTabs="children"
                      oncommand="BookmarksEventHandler.onCommand(event);"
                      onclick="BookmarksEventHandler.onClick(event);"
                      onpopupshowing="BookmarksMenuButton.onPopupShowing(event);
@@ -809,17 +813,17 @@
                      class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&tabCmd.label;"
                      command="cmd_newNavigatorTab"
                      onclick="checkForMiddleClick(this, event);"
                      tooltiptext="&newTabButton.tooltip;"
                      ondrop="newTabButtonObserver.onDrop(event)"
                      ondragover="newTabButtonObserver.onDragOver(event)"
                      ondragenter="newTabButtonObserver.onDragOver(event)"
-                     ondragleave="newTabButtonObserver.onDragLeave(event)"
+                     ondragexit="newTabButtonObserver.onDragExit(event)"
                      removable="true"/>
 
       <toolbarbutton id="alltabs-button"
                      class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button"
                      type="menu"
                      label="&listAllTabs.label;"
                      tooltiptext="&listAllTabs.label;"
                      removable="true">
@@ -856,40 +860,40 @@
         <image/>
       </toolbaritem>
 
       <toolbarbutton id="downloads-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      observes="Tools:Downloads"
                      ondrop="DownloadsButtonDNDObserver.onDrop(event)"
                      ondragover="DownloadsButtonDNDObserver.onDragOver(event)"
                      ondragenter="DownloadsButtonDNDObserver.onDragOver(event)"
-                     ondragleave="DownloadsButtonDNDObserver.onDragLeave(event)"
+                     ondragexit="DownloadsButtonDNDObserver.onDragExit(event)"
                      label="&downloads.label;"
                      tooltiptext="&downloads.tooltip;"/>
 
       <toolbarbutton id="history-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      observes="viewHistorySidebar" label="&historyButton.label;"
                      tooltiptext="&historyButton.tooltip;"/>
 
       <toolbarbutton id="bookmarks-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      observes="viewBookmarksSidebar"
                      tooltiptext="&bookmarksButton.tooltip;"
                      ondrop="bookmarksButtonObserver.onDrop(event)"
                      ondragover="bookmarksButtonObserver.onDragOver(event)"
                      ondragenter="bookmarksButtonObserver.onDragOver(event)"
-                     ondragleave="bookmarksButtonObserver.onDragLeave(event)"/>
+                     ondragexit="bookmarksButtonObserver.onDragExit(event)"/>
 
       <toolbarbutton id="new-window-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&newNavigatorCmd.label;"
                      command="key_newNavigator"
                      tooltiptext="&newWindowButton.tooltip;"
                      ondrop="newWindowButtonObserver.onDrop(event)"
                      ondragover="newWindowButtonObserver.onDragOver(event)"
                      ondragenter="newWindowButtonObserver.onDragOver(event)"
-                     ondragleave="newWindowButtonObserver.onDragLeave(event)"/>
+                     ondragexit="newWindowButtonObserver.onDragExit(event)"/>
 
       <toolbarbutton id="cut-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&cutCmd.label;"
                      command="cmd_cut"
                      tooltiptext="&cutButton.tooltip;"/>
 
       <toolbarbutton id="copy-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&copyCmd.label;"
--- a/browser/base/content/inspector.js
+++ b/browser/base/content/inspector.js
@@ -1420,23 +1420,23 @@ XPCOMUtils.defineLazyGetter(InspectorUI,
 });
 
 XPCOMUtils.defineLazyGetter(InspectorUI, "strings", function () {
   return Services.strings.createBundle("chrome://browser/locale/inspector.properties");
 });
 
 XPCOMUtils.defineLazyGetter(InspectorUI, "PropertyTreeView", function () {
   var obj = {};
-  Cu.import("resource://gre/modules/PropertyPanel.jsm", obj);
+  Cu.import("resource:///modules/PropertyPanel.jsm", obj);
   return obj.PropertyTreeView;
 });
 
 XPCOMUtils.defineLazyGetter(InspectorUI, "PropertyPanel", function () {
   var obj = {};
-  Cu.import("resource://gre/modules/PropertyPanel.jsm", obj);
+  Cu.import("resource:///modules/PropertyPanel.jsm", obj);
   return obj.PropertyPanel;
 });
 
 XPCOMUtils.defineLazyGetter(InspectorUI, "style", function () {
   var obj = {};
   Cu.import("resource:///modules/stylePanel.jsm", obj);
   obj.style.initialize();
   return obj.style;
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3293,17 +3293,17 @@
             return;
         }
 
         var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
         this.tabbrowser.replaceTabWithWindow(draggedTab);
         event.stopPropagation();
       ]]></handler>
 
-      <handler event="dragleave"><![CDATA[
+      <handler event="dragexit"><![CDATA[
         this._dragTime = 0;
 
         // This does not work at all (see bug 458613)
         var target = event.relatedTarget;
         while (target && target != this)
           target = target.parentNode;
         if (target)
           return;
--- a/browser/base/content/tabview/search.js
+++ b/browser/base/content/tabview/search.js
@@ -319,17 +319,18 @@ SearchEventHandlerClass.prototype = {
   // ----------
   // Function: init
   // Initializes the searchbox to be focused, and everything
   // else to be hidden, and to have everything have the appropriate
   // event handlers;
   init: function () {
     var self = this;
     iQ("#searchbox")[0].focus(); 
-    iQ("#search").hide().click(function(event) {
+    iQ("#search").hide();
+    iQ("#searchshade").hide().click(function(event) {
       if ( event.target.id != "searchbox")
         hideSearch();
     });
     
     iQ("#searchbox").keyup(function() {
       performSearch();
     });
     
@@ -359,16 +360,17 @@ SearchEventHandlerClass.prototype = {
     this.switchToInMode();
     ensureSearchShown(event);
   },
 
   // ----------
   // Function: inSearchKeyHandler
   // Handles all keypresses while search mode.
   inSearchKeyHandler: function (event) {
+    let term = iQ("#searchbox").val();
     if ((event.keyCode == event.DOM_VK_ESCAPE) || 
         (event.keyCode == event.DOM_VK_BACK_SPACE && term.length <= 1)) {
       hideSearch(event);
       return;
     }
 
     let matcher = createSearchTabMacher();
     let matches = matcher.matched();
@@ -457,44 +459,47 @@ var TabHandlers = {
       
     index != 0 ? item.addClass("notMainMatch") : item.removeClass("notMainMatch");      
     item.appendTo("#results");
     iQ("#otherresults").show();    
   },
   
   _hideHandler: function(event){
     iQ("#search").fadeOut();
+    iQ("#searchshade").fadeOut();
     TabHandlers._mouseDownLocation = {x:event.clientX, y:event.clientY};
   },
   
   _showHandler: function(event){
     // If the user clicks on a tab without moving the mouse then
     // they are zooming into the tab and we need to exit search
     // mode.
     if (TabHandlers._mouseDownLocation.x == event.clientX &&
         TabHandlers._mouseDownLocation.y == event.clientY){
       hideSearch();
       return;
     }
 
+    iQ("#searchshade").show();    
     iQ("#search").show();
     iQ("#searchbox")[0].focus();
     // Marshal the search.
     setTimeout(performSearch, 0);
   },
   
   _mouseDownLocation: null
 };
 
 function createSearchTabMacher() {
   return new TabMatcher(iQ("#searchbox").val());
 }
 
 function hideSearch(event){
   iQ("#searchbox").val("");
+  iQ("#searchshade").hide();
   iQ("#search").hide();
 
   iQ("#searchbutton").css({ opacity:.8 });
 
   let mainWindow = gWindow.document.getElementById("main-window");
   mainWindow.setAttribute("activetitlebarcolor", "#C4C4C4");
 
   performSearch();
@@ -523,33 +528,34 @@ function performSearch() {
   iQ("#otherresults").hide();
   iQ("#otherresults>.label").text(tabviewString("search.otherWindowTabs"));
 
   matcher.doSearch(TabHandlers.onMatch, TabHandlers.onUnmatch, TabHandlers.onOther);
 }
 
 function ensureSearchShown(event){
   var $search = iQ("#search");
+  var $searchShade = iQ("#searchshade");
   var $searchbox = iQ("#searchbox");
   iQ("#searchbutton").css({ opacity: 1 });
 
   if (!isSearchEnabled()) {
+    $searchShade.show();
     $search.show();
     var mainWindow = gWindow.document.getElementById("main-window");
     mainWindow.setAttribute("activetitlebarcolor", "#717171");       
 
     // Marshal the focusing, otherwise you end up with
     // a race condition where only sometimes would the
     // first keystroke be registered by the search box.
     // When you marshal it never gets registered, so we
     // manually 
     setTimeout(function focusSearch() {
       $searchbox[0].focus();
       $searchbox[0].val = '0';
-      $searchbox.css({"z-index":"1015"});
       if (event != null)
         $searchbox.val(String.fromCharCode(event.charCode));        
 
       let newEvent = document.createEvent("Events");
       newEvent.initEvent("tabviewsearchenabled", false, false);
       dispatchEvent(newEvent);
     }, 0);
   }
@@ -558,10 +564,9 @@ function ensureSearchShown(event){
 function isSearchEnabled() {
   return iQ("#search").css("display") != "none";
 }
 
 var SearchEventHandler = new SearchEventHandlerClass();
 
 // Features to add:
 // (1) Make sure this looks good on Windows. Bug 594429
-// (2) Make sure that we don't put the matched tab over the search box. Bug 594433
-// (3) Group all of the highlighted tabs into a group? Bug 594434
+// (2) Group all of the highlighted tabs into a group? Bug 594434
\ No newline at end of file
--- a/browser/base/content/tabview/tabview.css
+++ b/browser/base/content/tabview/tabview.css
@@ -194,33 +194,40 @@ body {
 ----------------------------------*/
 #exit-button {
   position: absolute;
   z-index: 1000;
 }
 
 /* Search
 ----------------------------------*/
+#searchshade{
+  position: absolute;
+  top: 0px;
+  left: 0px;
+  z-index: 1000;
+}
+
 #search{
   position: absolute;
   top: 0px;
   left: 0px;
-  z-index: 1000;  
+  pointer-events: none;
+  z-index: 1050;
 }
 
 html[dir=rtl] #search {
   left: auto;
   right: 0;
 }
 
 #searchbox{
   position: absolute;
   right: 20px;
   top: 20px;
-  z-index: 1050;
 }
 
 html[dir=rtl] #searchbox {
   right: auto;
   left: 20px;
 }
 
 #actions{
--- a/browser/base/content/tabview/tabview.html
+++ b/browser/base/content/tabview/tabview.html
@@ -5,23 +5,25 @@
   <title>&nbsp;</title>
   <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
   <link rel="stylesheet" href="tabview.css" type="text/css"/>
   <link rel="stylesheet" href="chrome://browser/skin/tabview/tabview.css" type="text/css"/>
 </head>
 
 <body transparent="true">
   <div id="content">
+    <div id="bg">
+    </div>
     <input id="exit-button" type="image" alt="" groups="0" />
     <div id="actions">
       <input id="searchbutton" type="button"/>
     </div>
-    <div id="bg" />
-  </div>
-  
+  </div>  
+
+  <div id="searchshade"></div>
   <div id="search">
     <input id="searchbox" type="text"/>
     <div id="otherresults">
       <span class="label"></span>
       <span id="results"></span>
     </div>
   </div>
 
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -60,16 +60,20 @@ let UI = {
   // Variable: _closedLastVisibleTab
   // If true, the last visible tab has just been closed in the tab strip.
   _closedLastVisibleTab : false,
 
   // Variable: _closedSelectedTabInTabView
   // If true, a select tab has just been closed in TabView.
   _closedSelectedTabInTabView : false,
 
+  // Variable: restoredClosedTab
+  // If true, a closed tab has just been restored.
+  restoredClosedTab : false,
+
   // Variable: _reorderTabItemsOnShow
   // Keeps track of the <GroupItem>s which their tab items' tabs have been moved
   // and re-orders the tab items when switching to TabView.
   _reorderTabItemsOnShow : [],
 
   // Variable: _reorderTabsOnHide
   // Keeps track of the <GroupItem>s which their tab items have been moved in
   // TabView UI and re-orders the tabs when switcing back to main browser.
@@ -164,17 +168,16 @@ let UI = {
 
       // ___ setup key handlers
       this._setTabViewFrameKeyHandlers();
 
       // ___ add tab action handlers
       this._addTabActionHandlers();
 
       // ___ Storage
-
       GroupItems.pauseArrange();
       GroupItems.init();
 
       let firstTime = true;
       if (gPrefBranch.prefHasUserValue("experienced_first_run"))
         firstTime = !gPrefBranch.getBoolPref("experienced_first_run");
       let groupItemsData = Storage.readGroupItemsData(gWindow);
       let groupItemData = Storage.readGroupItemData(gWindow);
@@ -705,41 +708,52 @@ let UI = {
   // Function: onTabSelect
   // Called when the user switches from one tab to another outside of the TabView UI.
   onTabSelect: function UI_onTabSelect(tab) {
     let currentTab = this._currentTab;
     this._currentTab = tab;
 
     // if the last visible tab has just been closed, don't show the chrome UI.
     if (this.isTabViewVisible() &&
-        (this._closedLastVisibleTab || this._closedSelectedTabInTabView)) {
+        (this._closedLastVisibleTab || this._closedSelectedTabInTabView ||
+         this.restoredClosedTab)) {
+      if (this.restoredClosedTab) {
+        // when the tab view UI is being displayed, update the thumb for the 
+        // restored closed tab after the page load
+        tab.linkedBrowser.addEventListener("load", function (event) {
+          tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
+          TabItems._update(tab);
+        }, true);
+      }
       this._closedLastVisibleTab = false;
       this._closedSelectedTabInTabView = false;
+      this.restoredClosedTab = false;
       return;
     }
     // reset these vars, just in case.
     this._closedLastVisibleTab = false;
     this._closedSelectedTabInTabView = false;
+    this.restoredClosedTab = false;
 
     // if TabView is visible but we didn't just close the last tab or
     // selected tab, show chrome.
     if (this.isTabViewVisible())
       this.hideTabView();
 
     // another tab might be selected when hideTabView() is invoked so a
     // validation is needed.
     if (this._currentTab != tab)
       return;
 
     let oldItem = null;
     let newItem = null;
 
     if (currentTab && currentTab.tabItem)
       oldItem = currentTab.tabItem;
-      
+
     // update the tab bar for the new tab's group
     if (tab && tab.tabItem) {
       newItem = tab.tabItem;
       GroupItems.updateActiveGroupItemAndTabBar(newItem);
     } else {
       // No tabItem; must be an app tab. Base the tab bar on the current group.
       // If no current group or orphan tab, figure it out based on what's
       // already in the tab bar.
@@ -1188,26 +1202,61 @@ let UI = {
       if (matches.length > 0) {
         matches[0].zoomIn();
         zoomedIn = true;
       }
       hideSearch(null);
     }
 
     if (!zoomedIn) {
+      let unhiddenGroups = GroupItems.groupItems.filter(function(groupItem) {
+        return (!groupItem.hidden && groupItem.getChildren().length > 0);
+      });
+      // no visible groups, no orphaned tabs and no apps tabs, open a new group
+      // with a blank tab
+      if (unhiddenGroups.length == 0 && GroupItems.getOrphanedTabs().length == 0 &&
+          gBrowser._numPinnedTabs == 0) {
+        let box = new Rect(20, 20, 250, 200);
+        let groupItem = new GroupItem([], { bounds: box, immediately: true });
+        groupItem.newTab();
+        return;
+      }
+
       // If there's an active TabItem, zoom into it. If not (for instance when the
       // selected tab is an app tab), just go there.
       let activeTabItem = this.getActiveTab();
-      if (!activeTabItem)
-        activeTabItem = gBrowser.selectedTab.tabItem;
+      if (!activeTabItem) {
+        let tabItem = gBrowser.selectedTab.tabItem;
+        if (tabItem) {
+          if (!tabItem.parent || !tabItem.parent.hidden) {
+            activeTabItem = tabItem;
+          } else { // set active tab item if there is at least one unhidden group
+            if (unhiddenGroups.length > 0)
+              activeTabItem = unhiddenGroups[0].getActiveTab();
+          }
+        }
+      }
 
-      if (activeTabItem)
+      if (activeTabItem) {
         activeTabItem.zoomIn();
-      else
-        self.goToTab(gBrowser.selectedTab);
+      } else {
+        if (gBrowser._numPinnedTabs > 0) {
+          if (gBrowser.selectedTab.pinned) {
+            self.goToTab(gBrowser.selectedTab);
+          } else {
+            Array.some(gBrowser.tabs, function(tab) {
+              if (tab.pinned) {
+                self.goToTab(tab);
+                return true;
+              }
+              return false
+            });
+          }
+        }
+      }
     }
   },
 
   // ----------
   // Function: storageSanity
   // Given storage data for this object, returns true if it looks valid.
   _storageSanity: function UI__storageSanity(data) {
     if (Utils.isEmptyObject(data))
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -64,16 +64,18 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug595930.js \
                  browser_tabview_bug595943.js \
                  browser_tabview_bug597248.js \
                  browser_tabview_bug597399.js \
                  browser_tabview_bug598600.js \
                  browser_tabview_bug599626.js \
                  browser_tabview_bug600645.js \
                  browser_tabview_bug606905.js \
+                 browser_tabview_bug608037.js \
+                 browser_tabview_bug608158.js \
                  browser_tabview_dragdrop.js \
                  browser_tabview_exit_button.js \
                  browser_tabview_group.js \
                  browser_tabview_launch.js \
                  browser_tabview_orphaned_tabs.js \
                  browser_tabview_privatebrowsing.js \
                  browser_tabview_rtl.js \
                  browser_tabview_search.js \
--- a/browser/base/content/test/tabview/browser_tabview_bug597248.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug597248.js
@@ -152,29 +152,46 @@ let gTabsProgressListener = {
   }
 };
 
 function onTabViewFrameInitialized() {
   restoredWin.removeEventListener("tabviewframeinitialized", onTabViewFrameInitialized, false);
 
   let contentWindow = restoredWin.document.getElementById("tab-view").contentWindow;
 
-  let tabItems = contentWindow.TabItems.getItems();
-  tabItems.forEach(function(tabItem) {
-    ok(tabItem.isShowingCachedData(), "Tab item is showing cached data");
-  });
+  let nextStep = function() {
+    // since we are not sure whether the frame is initialized first or two tabs
+    // compete loading first so we need this.
+    if (restoredNewTabOneLoaded && restoredNewTabTwoLoaded) {
+      // executeSoon is used to ensure tabItem.shouldHideCachedData is set
+      // because tabs progress listener might run at the same time as this test code.
+      executeSoon(updateAndCheck);
+    } else
+      frameInitialized = true;
+  }
 
-  // since we are not sure whether the frame is initialized first or two tabs
-  // compete loading first so we need this.
-  if (restoredNewTabOneLoaded && restoredNewTabTwoLoaded) {
-    // executeSoon is used to ensure tabItem.shouldHideCachedData is set
-    // because tabs progress listener might run at the same time as this test code.
-    executeSoon(updateAndCheck);
-  } else
-    frameInitialized = true;
+  let tabItems = contentWindow.TabItems.getItems();
+  let count = tabItems.length;
+  tabItems.forEach(function(tabItem) {
+    // tabitem might not be connected so use subscriber for those which are not
+    // connected.
+    if (tabItem.reconnected) {
+      ok(tabItem.isShowingCachedData(), "Tab item is showing cached data");
+      count--;
+      if (count == 0)
+        nextStep();
+    } else {
+      tabItem.addSubscriber(tabItem, "reconnected", function() {
+        tabItem.removeSubscriber(tabItem, "reconnected");
+        count--;
+        if (count == 0)
+          nextStep();
+      });
+    }
+  });
 }
 
 function updateAndCheck() {
   // force all canvas to update
   let contentWindow = restoredWin.document.getElementById("tab-view").contentWindow;
 
   let tabItems = contentWindow.TabItems.getItems();
   tabItems.forEach(function(tabItem) {
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug608037.js
@@ -0,0 +1,99 @@
+/* ***** 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 a test for bug 608037.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Raymond Lee <raymond@appcoast.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+let tabOne;
+let tabTwo;
+
+function test() {
+  waitForExplicitFinish();
+
+  tabOne = gBrowser.addTab("http://mochi.test:8888/");
+  tabTwo = gBrowser.addTab("http://mochi.test:8888/browser/browser/base/content/test/tabview/dummy_page.html");
+
+  // make sure our tabs are loaded so their titles are right
+  let stillToLoad = 0;
+  let onLoad = function(event) {
+    event.target.removeEventListener("load", onLoad, true);
+
+    stillToLoad--;
+    if (!stillToLoad) {
+      // show the tab view
+      window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
+      ok(!TabView.isVisible(), "Tab View is hidden");
+
+      // make sure the tab one is selected because undoCloseTab() would remove
+      // the selected tab if it's a blank tab.
+      gBrowser.selectedTab = tabOne;
+
+      TabView.toggle();
+    }
+  }
+
+  let newTabs = [ tabOne, tabTwo ];
+  newTabs.forEach(function(tab) {
+    stillToLoad++; 
+    tab.linkedBrowser.addEventListener("load", onLoad, true);
+  });
+}
+
+function onTabViewWindowLoaded() {
+  window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
+
+  let contentWindow = document.getElementById("tab-view").contentWindow;
+  let groupItems = contentWindow.GroupItems.groupItems;
+  is(groupItems.length, 1, "There is only one group");
+  is(groupItems[0].getChildren().length, 3, "The group has three tab items");
+
+  gBrowser.removeTab(tabTwo);
+  ok(TabView.isVisible(), "Tab View is still visible after removing a tab");
+  is(groupItems[0].getChildren().length, 2, "The group has two tab items");
+
+  tabTwo = undoCloseTab(0);
+  ok(TabView.isVisible(), "Tab View is still visible after restoring a tab");
+  is(groupItems[0].getChildren().length, 3, "The group has three tab items");
+
+  // clean up and finish
+  let endGame = function() {
+    window.removeEventListener("tabviewhidden", endGame, false);
+
+    gBrowser.removeTab(tabOne);
+    gBrowser.removeTab(tabTwo);
+    finish();
+  }
+  window.addEventListener("tabviewhidden", endGame, false);
+  TabView.toggle();
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug608158.js
@@ -0,0 +1,73 @@
+/* ***** 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 a test for bug 608158.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Raymond Lee <raymond@appcoast.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function test() {
+  waitForExplicitFinish();
+
+  window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
+  TabView.toggle();
+}
+
+function onTabViewWindowLoaded() {
+  window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
+
+  let contentWindow = document.getElementById("tab-view").contentWindow;
+
+  is(contentWindow.GroupItems.groupItems.length, 1, 
+     "There is one group item on startup");
+  is(gBrowser.tabs.length, 1, "There is one tab on startup");
+  let groupItem = contentWindow.GroupItems.groupItems[0];
+
+  groupItem.addSubscriber(groupItem, "groupHidden", function() {
+    groupItem.removeSubscriber(groupItem, "groupHidden");
+
+    let onTabViewHidden = function() {
+      window.removeEventListener("tabviewhidden", onTabViewHidden, false);
+      is(contentWindow.GroupItems.groupItems.length, 1, 
+         "There is still one group item");
+      isnot(groupItem, contentWindow.GroupItems.groupItems[0], 
+            "The initial group item is not the same as the final group item");
+      is(gBrowser.tabs.length, 1, "There is only one tab");
+      ok(!TabView.isVisible(), "Tab View is hidden");
+      finish();
+    };
+    window.addEventListener("tabviewhidden", onTabViewHidden, false);
+
+    TabView.hide();
+  });
+  groupItem.closeAll();
+}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -993,17 +993,17 @@
   </binding>
 
   <binding id="geolocation-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
     <content>
       <xul:image class="popup-notification-icon"
                  xbl:inherits="popupid"/>
       <xul:vbox>
         <xul:description class="popup-notification-description"
-                         xbl:inherits="value=label"/>
+                         xbl:inherits="xbl:text=label"/>
         <xul:spacer flex="1"/>
         <xul:hbox pack="end">
           <xul:label anonid="learnmore" class="text-link geolocation-text-link"/>
           <xul:spacer flex="1"/>
           <xul:button anonid="button"
                       class="popup-notification-menubutton"
                       xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey,type=buttontype">
             <xul:menupopup anonid="menupopup"
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -814,17 +814,17 @@ function PlacesToolbar(aPlace) {
   this._addEventListeners(window, ["resize", "unload"], false);
 
   PlacesViewBase.call(this, aPlace);
 }
 
 PlacesToolbar.prototype = {
   __proto__: PlacesViewBase.prototype,
 
-  _cbEvents: ["dragstart", "dragover", "dragleave", "dragend", "drop",
+  _cbEvents: ["dragstart", "dragover", "dragexit", "dragend", "drop",
 #ifdef XP_UNIX
 #ifndef XP_MACOSX
               "mousedown", "mouseup",
 #endif
 #endif
               "mousemove", "mouseover", "mouseout"],
 
   QueryInterface: function PT_QueryInterface(aIID) {
@@ -986,18 +986,18 @@ PlacesToolbar.prototype = {
         this.updateChevron();
         break;
       case "dragstart":
         this._onDragStart(aEvent);
         break;
       case "dragover":
         this._onDragOver(aEvent);
         break;
-      case "dragleave":
-        this._onDragLeave(aEvent);
+      case "dragexit":
+        this._onDragExit(aEvent);
         break;
       case "dragend":
         this._onDragEnd(aEvent);
         break;
       case "drop":
         this._onDrop(aEvent);
         break;
       case "mouseover":
@@ -1528,17 +1528,17 @@ PlacesToolbar.prototype = {
       PlacesControllerDragHelper.onDrop(dropPoint.ip, aEvent.dataTransfer)
       aEvent.preventDefault();
     }
 
     this._cleanupDragDetails();
     aEvent.stopPropagation();
   },
 
-  _onDragLeave: function PT__onDragLeave(aEvent) {
+  _onDragExit: function PT__onDragExit(aEvent) {
     PlacesControllerDragHelper.currentDropTarget = null;
 
     // Set timer to turn off indicator bar (if we turn it off
     // here, dragenter might be called immediately after, creating
     // flicker).
     if (this._ibTimer)
       this._ibTimer.cancel();
     this._ibTimer = this._setTimer(10);
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -485,17 +485,17 @@
         newMarginTop += sbo.y - this._scrollBox.boxObject.y;
         this._indicatorBar.firstChild.style.marginTop = newMarginTop + "px";
         this._indicatorBar.hidden = false;
 
         event.preventDefault();
         event.stopPropagation();
       ]]></handler>
 
-      <handler event="dragleave"><![CDATA[
+      <handler event="dragexit"><![CDATA[
         PlacesControllerDragHelper.currentDropTarget = null;
         this.removeAttribute("dragover");
 
         // If we have not moved to a valid new target clear the drop indicator
         // this happens when moving out of the popup.
         let target = event.relatedTarget;
         if (!target)
           this._indicatorBar.hidden = true;
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_fastswitch.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_fastswitch.js
@@ -43,42 +43,50 @@ function test() {
   let pb = Cc["@mozilla.org/privatebrowsing;1"].
            getService(Ci.nsIPrivateBrowsingService);
   let pbCmd = document.getElementById("Tools:PrivateBrowsing");
   waitForExplicitFinish();
 
   let pass = 1;
   function observer(aSubject, aTopic, aData) {
     switch (aTopic) {
-      case "private-browsing":
-        setTimeout(function () {
-          ok(document.getElementById("Tools:PrivateBrowsing").hasAttribute("disabled"),
-             "The private browsing command should be disabled immediately after the mode switch");
-        }, 0);
-        break;
-
       case "private-browsing-transition-complete":
         if (pass++ == 1) {
           setTimeout(function () {
             ok(!pbCmd.hasAttribute("disabled"),
                "The private browsing command should be re-enabled after entering the private browsing mode");
 
             pb.privateBrowsingEnabled = false;
           }, 100);
         }
         else {
           setTimeout(function () {
             ok(!pbCmd.hasAttribute("disabled"),
                "The private browsing command should be re-enabled after exiting the private browsing mode");
 
-            Services.obs.removeObserver(observer, "private-browsing");
-            Services.obs.removeObserver(observer, "private-browsing-transition-complete");
             finish();
           }, 100);
         }
         break;
     }
+    Services.obs.removeObserver(observer, "private-browsing-transition-complete");
   }
-  Services.obs.addObserver(observer, "private-browsing", false);
-  Services.obs.addObserver(observer, "private-browsing-transition-complete", false);
+  let originalOnEnter = gPrivateBrowsingUI.onEnterPrivateBrowsing;
+  gPrivateBrowsingUI.onEnterPrivateBrowsing = function() {
+    originalOnEnter.apply(gPrivateBrowsingUI, arguments);
+    ok(pbCmd.hasAttribute("disabled"),
+       "The private browsing command should be disabled right after entering the private browsing mode");
+    Services.obs.addObserver(observer, "private-browsing-transition-complete", false);
+  };
+  let originalOnExit = gPrivateBrowsingUI.onExitPrivateBrowsing;
+  gPrivateBrowsingUI.onExitPrivateBrowsing = function() {
+    originalOnExit.apply(gPrivateBrowsingUI, arguments);
+    ok(pbCmd.hasAttribute("disabled"),
+       "The private browsing command should be disabled right after exiting the private browsing mode");
+    Services.obs.addObserver(observer, "private-browsing-transition-complete", false);
+  };
+  registerCleanupFunction(function() {
+    gPrivateBrowsingUI.onEnterPrivateBrowsing = originalOnEnter;
+    gPrivateBrowsingUI.onExitPrivateBrowsing = originalOnExit;
+  });
 
   pb.privateBrowsingEnabled = true;
 }
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newwindow_stopcmd.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newwindow_stopcmd.js
@@ -42,22 +42,21 @@ function test() {
   // initialization
   let pb = Cc["@mozilla.org/privatebrowsing;1"].
            getService(Ci.nsIPrivateBrowsingService);
   waitForExplicitFinish();
 
   pb.privateBrowsingEnabled = true;
 
   let win = OpenBrowserWindow();
-  Services.obs.addObserver(function(subject, topic, data) {
-    Services.obs.removeObserver(arguments.callee, "browser-delayed-startup-finished");
-    var notifiedWin = subject.QueryInterface(Ci.nsIDOMWindow);
-    is(win, notifiedWin, "sanity check");
+  win.addEventListener("load", function() {
+    win.removeEventListener("load", arguments.callee, false);
+    executeSoon(function() {
+      let cmd = win.document.getElementById("Tools:PrivateBrowsing");
+      ok(!cmd.hasAttribute("disabled"),
+         "The Private Browsing command in a new window should be enabled");
 
-    let cmd = win.document.getElementById("Tools:PrivateBrowsing");
-    ok(!cmd.hasAttribute("disabled"),
-       "The Private Browsing command in a new window should be enabled");
-
-    win.close();
-    pb.privateBrowsingEnabled = false;
-    finish();
-  }, "browser-delayed-startup-finished", false);
+      win.close();
+      pb.privateBrowsingEnabled = false;
+      finish();
+    });
+  }, false);
 }
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js
@@ -88,29 +88,24 @@ function test() {
         is(document.title, expected_title, "The window title for " + url +
            " is correct (" + (insidePB ? "inside" : "outside") +
            " private browsing mode)");
 
         let win = gBrowser.replaceTabWithWindow(tab);
         win.addEventListener("load", function() {
           win.removeEventListener("load", arguments.callee, false);
 
-          // ensure that the test is run after delayedStartup
-          let _delayedStartup = win.delayedStartup;
-          win.delayedStartup = function() {
-            _delayedStartup.apply(win, arguments);
-            win.delayedStartup = _delayedStartup;
-
+          executeSoon(function() {
             is(win.document.title, expected_title, "The window title for " + url +
                " detached tab is correct (" + (insidePB ? "inside" : "outside") +
                " private browsing mode)");
             win.close();
 
             setTimeout(funcNext, 0);
-          };
+          });
         }, false);
       });
     }, false);
 
     browser.loadURI(url);
   }
 
   function cleanup() {
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -2489,16 +2489,20 @@ SessionStoreService.prototype = {
 
       tabData._tabStillLoading = true;
 
       // keep the data around to prevent dataloss in case
       // a tab gets closed before it's been properly restored
       browser.__SS_data = tabData;
       browser.__SS_restoreState = TAB_STATE_NEEDS_RESTORE;
 
+      // Make sure that set/getTabValue will set/read the correct data by
+      // wiping out any current value in tab.__SS_extdata.
+      delete tab.__SS_extdata;
+
       if (!tabData.entries || tabData.entries.length == 0) {
         // make sure to blank out this tab's content
         // (just purging the tab's history won't be enough)
         browser.contentDocument.location = "about:blank";
         continue;
       }
 
       browser.stop(); // in case about:blank isn't done yet
@@ -2694,25 +2698,33 @@ SessionStoreService.prototype = {
       }
     }
 
     // Handle userTypedValue. Setting userTypedValue seems to update gURLbar
     // as needed. Calling loadURI will cancel form filling in restoreDocument
     if (tabData.userTypedValue) {
       browser.userTypedValue = tabData.userTypedValue;
       if (tabData.userTypedClear) {
+        // Make it so that we'll enter restoreDocument on page load. We will
+        // fire SSTabRestored from there. We don't have any form data to restore
+        // so we can just set the URL to null.
+        browser.__SS_restore_data = { url: null };
+        browser.__SS_restore_tab = aTab;
         didStartLoad = true;
         browser.loadURI(tabData.userTypedValue, null, null, true);
       }
     }
 
     // If we didn't start a load, then we won't reset this tab through the usual
-    // channel (via the progress listener), so reset the tab ourselves.
-    if (!didStartLoad)
+    // channel (via the progress listener), so reset the tab ourselves. We will
+    // also send SSTabRestored since this tab has technically been restored.
+    if (!didStartLoad) {
+      this._sendTabRestoredNotification(aTab);
       this._resetTabRestoringState(aTab);
+    }
 
     return didStartLoad;
   },
 
   /**
    * This _attempts_ to restore the next available tab. If the restore fails,
    * then we will attempt the next one.
    * There are conditions where this won't do anything:
@@ -2957,23 +2969,21 @@ SessionStoreService.prototype = {
     }
 
     // don't restore text data and scrolling state if the user has navigated
     // away before the loading completed (except for in-page navigation)
     if (hasExpectedURL(aEvent.originalTarget, aBrowser.__SS_restore_data.url)) {
       var content = aEvent.originalTarget.defaultView;
       restoreTextDataAndScrolling(content, aBrowser.__SS_restore_data, "");
       aBrowser.markupDocumentViewer.authorStyleDisabled = selectedPageStyle == "_nostyle";
-
-      // notify the tabbrowser that this document has been completely restored
-      var event = aBrowser.ownerDocument.createEvent("Events");
-      event.initEvent("SSTabRestored", true, false);
-      aBrowser.__SS_restore_tab.dispatchEvent(event);
     }
 
+    // notify the tabbrowser that this document has been completely restored
+    this._sendTabRestoredNotification(aBrowser.__SS_restore_tab);
+
     delete aBrowser.__SS_restore_data;
     delete aBrowser.__SS_restore_pageStyle;
     delete aBrowser.__SS_restore_tab;
   },
 
   /**
    * Restore visibility and dimension features to a window
    * @param aWindow
@@ -3631,16 +3641,26 @@ SessionStoreService.prototype = {
           this._browserSetState ? NOTIFY_BROWSER_STATE_RESTORED : NOTIFY_WINDOWS_RESTORED,
           "");
         this._browserSetState = false;
       }
     }
   },
 
   /**
+   * Dispatch the SSTabRestored event for the given tab.
+   * @param aTab the which has been restored
+   */
+  _sendTabRestoredNotification: function sss__sendTabRestoredNotification(aTab) {
+      let event = aTab.ownerDocument.createEvent("Events");
+      event.initEvent("SSTabRestored", true, false);
+      aTab.dispatchEvent(event);
+  },
+
+  /**
    * @param aWindow
    *        Window reference
    * @returns whether this window's data is still cached in _statesToRestore
    *          because it's not fully loaded yet
    */
   _isWindowLoaded: function sss_isWindowLoaded(aWindow) {
     return !aWindow.__SS_restoreID;
   },
--- a/browser/components/sessionstore/test/browser/browser_394759.js
+++ b/browser/components/sessionstore/test/browser/browser_394759.js
@@ -93,18 +93,23 @@ function test() {
             // reopen the closed window and ensure its integrity
             let newWin2 = ss.undoCloseWindow(0);
 
             ok(newWin2 instanceof ChromeWindow,
                "undoCloseWindow actually returned a window");
             is(ss.getClosedWindowCount(), closedWindowCount,
                "The reopened window was removed from Recently Closed Windows");
 
+            // SSTabRestored will fire more than once, so we need to make sure we count them
+            let restoredTabs = 0;
+            let expectedTabs = data.tabs.length;
             newWin2.addEventListener("load", function(aEvent) {
               newWin2.gBrowser.tabContainer.addEventListener("SSTabRestored", function(aEvent) {
+                if (++restoredTabs < expectedTabs)
+                  return;
                 newWin2.gBrowser.tabContainer.removeEventListener("SSTabRestored", arguments.callee, true);
 
                 is(newWin2.gBrowser.tabs.length, 2,
                    "The window correctly restored 2 tabs");
                 is(newWin2.gBrowser.currentURI.spec, testURL,
                    "The window correctly restored the URL");
 
                 let textbox = newWin2.content.document.getElementById("textbox");
--- a/browser/components/sessionstore/test/browser/browser_522545.js
+++ b/browser/components/sessionstore/test/browser/browser_522545.js
@@ -51,25 +51,23 @@ function test() {
 
   waitForExplicitFinish();
   requestLongerTimeout(2);
 
   let ss = Cc["@mozilla.org/browser/sessionstore;1"].
            getService(Ci.nsISessionStore);
 
   function waitForBrowserState(aState, aSetStateCallback) {
-    var locationChanges = 0;
-    gBrowser.addTabsProgressListener({
-      onLocationChange: function (aBrowser) {
-        if (++locationChanges == aState.windows[0].tabs.length) {
-          gBrowser.removeTabsProgressListener(this);
-          executeSoon(aSetStateCallback);
-        }
+    let tabsRestored = 0;
+    gBrowser.tabContainer.addEventListener("SSTabRestored", function() {
+      if (++tabsRestored == aState.windows[0].tabs.length) {
+        gBrowser.tabContainer.removeEventListener("SSTabRestored", arguments.callee, true);
+        executeSoon(aSetStateCallback);
       }
-    });
+    }, true);
     ss.setBrowserState(JSON.stringify(aState));
   }
 
   // This tests the following use case:
   // User opens a new tab which gets focus. The user types something into the
   // address bar, then crashes or quits.
   function test_newTabFocused() {
     let state = {
@@ -280,37 +278,28 @@ function test() {
     let state = {
       windows: [{
         tabs: [
           { entries: [], userTypedValue: "http://example.com", userTypedClear: 2 }
         ]
       }]
     };
 
-    // Set state here and listen for load event because waitForBrowserState
-    // doesn't guarantee all the tabs have loaded, so the test could continue
-    // before we're in a testable state. This is important here because of the
-    // distinction between "http://example.com" and "http://example.com/".
-    ss.setBrowserState(JSON.stringify(state));
-    gBrowser.addEventListener("load", function(aEvent) {
-      if (gBrowser.currentURI.spec == "about:blank")
-        return;
-      gBrowser.removeEventListener("load", arguments.callee, true);
-
+    waitForBrowserState(state, function() {
       let browser = gBrowser.selectedBrowser;
       is(browser.currentURI.spec, "http://example.com/",
          "userTypedClear=2 caused userTypedValue to be loaded");
       is(browser.userTypedValue, null,
          "userTypedValue was null after loading a URI");
       is(browser.userTypedClear, 0,
          "userTypeClear reset to 0");
       is(gURLBar.value, "http://example.com/",
          "Address bar's value set after loading URI");
       runNextTest();
-    }, true);
+    });
   }
 
 
   let tests = [test_newTabFocused, test_newTabNotFocused,
                test_existingSHEnd_noClear, test_existingSHMiddle_noClear,
                test_getBrowserState_lotsOfTabsOpening,
                test_getBrowserState_userTypedValue, test_userTypedClearLoadURI];
   let originalState = ss.getBrowserState();
--- a/browser/components/sessionstore/test/browser/browser_590268.js
+++ b/browser/components/sessionstore/test/browser/browser_590268.js
@@ -49,16 +49,17 @@ function test() {
   waitForExplicitFinish();
 
   let startedTest = false;
 
   // wasLoaded will be used to keep track of tabs that have already had SSTabRestoring
   // fired for them.
   let wasLoaded = { };
   let restoringTabsCount = 0;
+  let restoredTabsCount = 0;
   let uniq2 = { };
   let uniq2Count = 0;
   let state = { windows: [{ tabs: [] }] };
   // We're going to put a bunch of tabs into this state
   for (let i = 0; i < NUM_TABS; i++) {
     let uniq = r();
     let tabData = {
       entries: [{ url: "http://example.com/#" + i }],
@@ -69,24 +70,40 @@ function test() {
   }
 
 
   function onSSTabRestoring(aEvent) {
     restoringTabsCount++;
     let uniq = ss.getTabValue(aEvent.originalTarget, "uniq");
     wasLoaded[uniq] = true;
 
+    is(ss.getTabValue(aEvent.originalTarget, "foo"), "",
+       "There is no value for 'foo'");
+
     // On the first SSTabRestoring we're going to run the the real test.
     // We'll keep this listener around so we can keep marking tabs as restored.
     if (restoringTabsCount == 1)
       onFirstSSTabRestoring();
     else if (restoringTabsCount == NUM_TABS)
       onLastSSTabRestoring();
   }
 
+  function onSSTabRestored(aEvent) {
+    if (++restoredTabsCount < NUM_TABS)
+      return;
+    cleanup();
+  }
+
+  function onTabOpen(aEvent) {
+    // To test bug 614708, we'll just set a value on the tab here. This value
+    // would previously cause us to not recognize the values in extData until
+    // much later. So testing "uniq" failed.
+    ss.setTabValue(aEvent.originalTarget, "foo", "bar");
+  }
+
   // This does the actual testing. SSTabRestoring should be firing on tabs from
   // left to right, so we're going to start with the rightmost tab.
   function onFirstSSTabRestoring() {
     info("onFirstSSTabRestoring...");
     for (let i = gBrowser.tabs.length - 1; i >= 0; i--) {
       let tab = gBrowser.tabs[i];
       let actualUniq = ss.getTabValue(tab, "uniq");
       let expectedUniq = state.windows[0].tabs[i].extData["uniq"];
@@ -115,33 +132,36 @@ function test() {
 
       // Look to see if we set a uniq2 value for this uniq value
       if (uniq in uniq2) {
         is(ss.getTabValue(tab, "uniq2"), uniq2[uniq], "tab " + i + " has correct uniq2 value");
         checked++;
       }
     }
     is(checked, uniq2Count, "checked the same number of uniq2 as we set");
-    cleanup();
   }
 
   function cleanup() {
     // remove the event listener and clean up before finishing
     gBrowser.tabContainer.removeEventListener("SSTabRestoring", onSSTabRestoring, false);
+    gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, true);
+    gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, false);
     // Put this in an executeSoon because we still haven't called restoreNextTab
     // in sessionstore for the last tab (we'll call it after this). We end up
     // trying to restore the tab (since we then add a closed tab to the array).
     executeSoon(function() {
       ss.setBrowserState(stateBackup);
       executeSoon(finish);
     });
   }
 
-  // Add the event listener
+  // Add the event listeners
   gBrowser.tabContainer.addEventListener("SSTabRestoring", onSSTabRestoring, false);
+  gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored, true);
+  gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, false);
   // Restore state
   ss.setBrowserState(JSON.stringify(state));
 }
 
 // Helper function to create a random value
 function r() {
   return "" + Date.now() + Math.random();
 }
--- a/browser/components/sessionstore/test/browser/browser_600545.js
+++ b/browser/components/sessionstore/test/browser/browser_600545.js
@@ -57,46 +57,49 @@ function testBug600545() {
     Services.obs.addObserver(function() {
       Services.obs.removeObserver(arguments.callee, topic, false);
       executeSoon(aSaveStateCallback);
     }, topic, false);
   };
 
   // Need to wait for all tabs to be restored before reading browser state
   function waitForBrowserState(aState, aSetStateCallback) {
-    let locationChanges = 0;
-    let tabsRestored = getStateTabCount(aState);
+    let tabsRestored = 0;
+    let expectedTabs = getStateTabCount(aState);
+
+    // We know that there are only 2 windows total, so just be specific
+    let newWin;
 
     // Used to determine when tabs have been restored
-    let progressListener = {
-      onLocationChange: function (aBrowser) {
-        if (++locationChanges == tabsRestored) {
-          // Remove the progress listener from this window, it will be removed from
-          // theWin when that window is closed (in setBrowserState).
-          window.gBrowser.removeTabsProgressListener(this);
-          executeSoon(aSetStateCallback);
-        }
+    function onTabRestored(aEvent) {
+      if (++tabsRestored == expectedTabs) {
+        gBrowser.tabContainer.removeEventListener("SSTabRestored", onTabRestored, true);
+        newWin.gBrowser.tabContainer.removeEventListener("SSTabRestored", onTabRestored, true);
+        executeSoon(aSetStateCallback);
       }
     }
 
     // We also want to catch the 2nd window, so we need to observe domwindowopened
     function windowObserver(aSubject, aTopic, aData) {
       let theWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
       if (aTopic == "domwindowopened") {
         theWin.addEventListener("load", function() {
           theWin.removeEventListener("load", arguments.callee, false);
 
+          // So we can remove the event listener in onTabRestored
+          newWin = theWin;
+
           Services.ww.unregisterNotification(windowObserver);
-          theWin.gBrowser.addTabsProgressListener(progressListener);
+          theWin.gBrowser.tabContainer.addEventListener("SSTabRestored", onTabRestored, true);
         }, false);
       }
     }
 
     Services.ww.registerNotification(windowObserver);
-    window.gBrowser.addTabsProgressListener(progressListener);
+    gBrowser.tabContainer.addEventListener("SSTabRestored", onTabRestored, true);
     ss.setBrowserState(JSON.stringify(aState));
   }
 
   // This tests the following use case:
   // When multiple windows are open and browser.sessionstore.resume_from_crash
   // preference is false, tab session data for non-active window is stripped for
   // non-pinned tabs.  This occurs after "sessionstore-state-write" fires which
   // will only fire in this case if there is at least one pinned tab.
@@ -145,9 +148,9 @@ function done() {
 }
 
 // Count up the number of tabs in the state data
 function getStateTabCount(aState) {
   let tabCount = 0;
   for (let i in aState.windows)
     tabCount += aState.windows[i].tabs.length;
   return tabCount;
-}
\ No newline at end of file
+}
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -399,16 +399,24 @@
 @BINPATH@/components/nsUrlClassifierLib.js
 @BINPATH@/components/url-classifier.xpt
 
 ; GNOME hooks
 #ifdef MOZ_ENABLE_GNOME_COMPONENT
 @BINPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@
 #endif
 
+; ANGLE on Win32
+#ifdef XP_WIN32
+#ifndef HAVE_64BIT_OS
+@BINPATH@/libEGL.dll
+@BINPATH@/libGLESv2.dll
+#endif
+#endif
+
 ; [Browser Chrome Files]
 @BINPATH@/chrome/browser@JAREXT@
 @BINPATH@/chrome/browser.manifest
 @BINPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf
 @BINPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/icon.png
 @BINPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/preview.png
 #if MOZ_UPDATE_CHANNEL == beta
 @BINPATH@/extensions/testpilot@labs.mozilla.com/*
--- a/browser/locales/shipped-locales
+++ b/browser/locales/shipped-locales
@@ -1,14 +1,15 @@
 af
 ak
 ar
 be
 bg
 bn-BD
+bn-IN
 br
 ca
 cs
 da
 de
 el
 en-GB
 en-US
@@ -21,44 +22,49 @@ et
 eu
 fi
 fr
 fy-NL
 ga-IE
 gd
 gu-IN
 he
+hr
 hu
 hy-AM
 id
 is
 it
 ja linux win32
 ja-JP-mac osx
 kn
 ko
 ku
 lg
 lt
 lv
 mk
+ml
 nb-NO
 nl
 nn-NO
 nso
 or
 pa-IN
 pl
 pt-BR
 pt-PT
 rm
 ro
 ru
 si
 sk
+sl
 son
 sq
 sv-SE
+ta-LK
+te
 th
 tr
 uk
 zh-CN
 zh-TW
--- a/browser/themes/gnomestripe/browser/tabview/tabview.css
+++ b/browser/themes/gnomestripe/browser/tabview/tabview.css
@@ -537,20 +537,25 @@ html[dir=rtl] .iq-resizable-se {
 
 html[dir=rtl] #exit-button {
   right: auto;
   left: 0;
 }
 
 /* Search
 ----------------------------------*/
-#search{
+#searchshade{
   background-color: rgba(0,0,0,.42);
   width: 100%;
-  height: 100%;  
+  height: 100%;
+}
+
+#search{
+  width: 100%;
+  height: 100%;
 }
 
 #searchbox{
   width: 270px;
   height: 30px;
   box-shadow: 0px 1px 0px rgba(255,255,255,.5), 0px -1px 0px rgba(0,0,0,1), 0px 0px 9px rgba(0,0,0,.8);
   color: white;
   border: none;
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -1044,136 +1044,119 @@ richlistitem[type~="action"][actiontype=
   width: 48px;
   height: 48px;
 }
 
 #editBookmarkPanelStarIcon[unstarred] {
   list-style-image: url("chrome://browser/skin/places/unstarred48.png");
 }
 
-#editBookmarkPanel {
-  -moz-appearance: none;
-  -moz-window-shadow: none;
-  -moz-border-image: url(chrome://browser/skin/hud-panel.png) 26 50 22 18 / 26px 50px 22px 18px repeat;
-  margin-right: -27px;
-  margin-top: 1px;
-  padding-top: 8px;
-  color: #ffffff;
-  background-color: transparent;
-}
-
 #editBookmarkPanelTitle {
   font-size: 130%;
   font-weight: bold;
 }
 
-#editBookmarkPanelContent,
-#editBookmarkPanelBottomButtons {
-  margin-right: -30px;
-}
-
 /**** HUD style buttons ****/
 
 .editBookmarkPanelHeaderButton,
 .editBookmarkPanelBottomButton {
   @hudButton@
-  padding: 0 9px;
   margin: 6px;
   min-width: 79px;
   min-height: 22px;
 }
 
 .editBookmarkPanelHeaderButton:hover:active,
 .editBookmarkPanelBottomButton:hover:active {
-  background-color: #86888B;
+  @hudButtonPressed@
 }
 
-.editBookmarkPanelHeaderButton:focus,
-.editBookmarkPanelBottomButton:focus {
-  outline: 2px solid -moz-mac-focusring;
-  outline-offset: -2px;
-  -moz-outline-radius: 10000px;
+.editBookmarkPanelHeaderButton:-moz-focusring,
+.editBookmarkPanelBottomButton:-moz-focusring {
+  @hudButtonFocused@
 }
 
 .editBookmarkPanelBottomButton[default="true"] {
   background-color: #666;
 }
 
 #editBookmarkPanelHeader {
   margin-bottom: 6px;
 }
 
 /* The following elements come from editBookmarkOverlay.xul. Styling that's
    specific to the editBookmarkPanel should be in browser.css. Styling that
    should be shared by all editBookmarkOverlay.xul consumers should be in
    editBookmarkOverlay.css. */
 
 #editBMPanel_newFolderBox {
-  background-image: url("chrome://browser/skin/hud-style-new-folder-bar-background.png");
-  background-repeat: repeat-x;
-  border: 0;
-  border-width: 1px 0 1px 0;
-  border-style: solid;
-  border-top-color: #212121;
-  border-bottom-color: #212121;
+  background-image: -moz-linear-gradient(rgb(90,90,90), rgb(40,40,40));
+  background-origin: padding-box;
+  background-clip: padding-box;
+  border-radius: 0 0 3px 3px;
+  border: 1px solid rgba(0,0,0,.3);
+  border-top: none;
+  box-shadow: inset 0 -1px 2px rgba(0,0,0,.2),
+              inset 0 1px 0 rgba(255,255,255,.15),
+              0 1px 0 rgba(255,255,255,.15);
   padding: 0;
   margin-left: 4px;
   margin-right: 4px;
   margin-bottom: 8px !important;
   height:  20px;
 }
 
 #editBMPanel_newFolderButton {
   -moz-appearance: none;
   background-color: transparent !important;
   border: 0;
   -moz-border-end-width: 3px;
   border-style: solid;
-  -moz-border-right-colors: rgba(255,255,255,0.15) rgba(0,0,0,0.5) rgba(255,255,255,0.15);
-  -moz-border-left-colors: rgba(255,255,255,0.15) rgba(0,0,0,0.5) rgba(255,255,255,0.15);
+  -moz-border-right-colors: rgba(255,255,255,.1) rgba(0,0,0,.5) rgba(255,255,255,.1);
+  -moz-border-left-colors: rgba(255,255,255,.1) rgba(0,0,0,.5) rgba(255,255,255,.1);
   padding: 0 9px;
   margin: 0;
   min-width: 21px;
   min-height: 20px;
   height:  20px;
-  color: #ffffff;
+  color: #fff;
   list-style-image: url("chrome://browser/skin/hud-style-new-folder-plus-sign.png") !important;
+  position: relative;
 }
 
 #editBMPanel_newFolderButton:hover:active {
-  background-color: #86888B;
+  background: -moz-linear-gradient(rgba(40,40,40,.9), rgba(70,70,70,.9));
+  box-shadow: inset 0 0 3px rgba(0,0,0,.2), inset 0 1px 7px rgba(0,0,0,.4);
 }
 
-#editBMPanel_newFolderButton:focus {
-  outline: 2px solid -moz-mac-focusring;
-  outline-offset: -2px;
-  -moz-outline-radius: 1px;
+#editBMPanel_newFolderButton:-moz-focusring {
+  box-shadow: 0 0 1px -moz-mac-focusring inset,
+              0 0 4px 1px -moz-mac-focusring,
+              0 0 2px 1px -moz-mac-focusring;
 }
 
 #editBMPanel_newFolderButton .button-text {
   display: none !important;
 }
 
 #editBMPanel_folderMenuList {
   @hudButton@
-  border-radius: 5px;
-  margin: 0 3px !important;
+  border-radius: 3px;
   min-height: 22px;
-  -moz-padding-start: 2px;
+  -moz-padding-start: 4px;
+  -moz-padding-end: 0;
 }
 
-#editBMPanel_folderMenuList:focus {
-  outline: 2px solid -moz-mac-focusring;
-  outline-offset: -2px;
-  -moz-outline-radius: 5px;
+#editBMPanel_folderMenuList:-moz-focusring {
+  @hudButtonFocused@
 }
 
 #editBMPanel_folderMenuList[open="true"],
 #editBMPanel_folderMenuList:hover:active {
-  background-image: url("chrome://browser/skin/hud-style-button-middle-background-active.png");
+  @hudButtonPressed@
 }
 
 #editBMPanel_folderMenuList > .menulist-dropmarker {
   -moz-appearance: none;
   display: -moz-box;
   background-color: transparent;
   border: 0;
   margin: 0;
@@ -1183,28 +1166,30 @@ richlistitem[type~="action"][actiontype=
 #editBMPanel_folderMenuList > .menulist-dropmarker > .dropmarker-icon {
   list-style-image: url("chrome://browser/skin/hud-style-dropmarker-double-arrows.png");
 }
 
 /**** folder tree ****/
 
 #editBMPanel_folderTree {
   -moz-appearance: none;
-  background-color: #333333;
-  border-top: 2px solid;
-  -moz-border-top-colors: rgba(0,0,0,0.35) rgba(255,255,255,0.15);
-  color: #ffffff;
+  border-radius: 2px 2px 0 0;
+  background-color: rgba(50,50,50,.9);
+  border: 1px solid rgba(0,0,0,.3);
+  border-bottom: none;
+  box-shadow: inset 0 1px 2px rgba(0,0,0,.15);
+  color: #fff;
   /* Implements editBookmarkPanel resizing on folderTree un-collapse. */
   min-width: 27em;
+  position: relative;
 }
 
-#editBMPanel_folderTree:focus {
-  outline: 2px solid -moz-mac-focusring;
-  outline-offset: -1px;
-  -moz-outline-radius: 1px;
+#editBMPanel_folderTree:-moz-focusring {
+  box-shadow: 0 0 4px 1px -moz-mac-focusring,
+              0 0 2px 1px -moz-mac-focusring;
 }
 
 #editBMPanel_folderTree > treechildren::-moz-tree-twisty {
   -moz-appearance: none;
   list-style-image: url("chrome://browser/skin/hud-style-twisties.png");
   -moz-image-region: rect(0px, 10px, 10px, 0px);
   margin-top: 1px;
   -moz-margin-end: 1px;
@@ -1219,47 +1204,46 @@ richlistitem[type~="action"][actiontype=
 }
 
 #editBMPanel_folderTree > treechildren::-moz-tree-twisty(selected, open) {
   -moz-image-region: rect(0px, 40px, 10px, 30px);
 }
 
 #editBMPanel_tagsSelector {
   -moz-appearance: none;
-  background-color: #333333;
-  border-top: 2px solid !important;
-  border-right: 0 !important;
-  border-bottom: 2px solid !important;
-  border-left: 0 !important;
-  -moz-border-top-colors: rgba(0,0,0,0.35) rgba(255,255,255,0.15);
-  -moz-border-bottom-colors: rgba(255,255,255,0.30) rgba(0,0,0,0.35) ;
-  color: #ffffff !important;
+  border-radius: 2px;
+  background-color: rgba(50,50,50,1);
+  border: 1px solid rgba(0,0,0,.3);
+  border-bottom: none;
+  box-shadow: inset 0 1px 2px rgba(0,0,0,.15),
+              0 1px 0 rgba(255,255,255,.15);
+  color: #fff;
 }
 
-#editBMPanel_tagsSelector:focus {
-  outline: 2px solid -moz-mac-focusring;
-  outline-offset: -2px;
-  -moz-outline-radius: 1px;
+#editBMPanel_tagsSelector:-moz-focusring {
+  box-shadow: 0 0 1px -moz-mac-focusring inset,
+              0 0 4px 1px -moz-mac-focusring,
+              0 0 2px 1px -moz-mac-focusring;
 }
 
 #editBMPanel_tagsSelector .listcell-check {
   -moz-appearance: none !important;
   background-color: transparent;
   border: 0;
   list-style-image: url("chrome://browser/skin/hud-style-check-box-empty.png");
   min-height: 14px;
   min-width: 14px;
 }
 
 #editBMPanel_tagsSelector .listcell-check[checked="true"] {
   list-style-image: url("chrome://browser/skin/hud-style-check-box-checked.png");
 }
 
 #editBMPanel_folderTree treechildren::-moz-tree-row {
-  color: #ffffff !important;
+  color: #fff !important;
   background-color: transparent !important;
   border: none !important;
 }
 
 #editBMPanel_folderTree treechildren::-moz-tree-row(selected) {
   background-color: #b3b3b3 !important;
 }
 
@@ -1277,82 +1261,74 @@ richlistitem[type~="action"][actiontype=
   background-color: #b3b3b3;
 }
 
 /**** expanders ****/
 
 #editBookmarkPanel .expander-up,
 #editBookmarkPanel .expander-down {
   @hudButton@
-  border-radius: 5px;
+  border-radius: 3px;
   -moz-margin-start: 4px;
   -moz-margin-end: 2px;
   padding: 0;
   -moz-padding-start: 4px;
   min-width: 10px;
-  min-height: 22px;
+  min-height: 20px;
+}
+
+#editBookmarkPanel .expander-up:-moz-focusring,
+#editBookmarkPanel .expander-down:-moz-focusring {
+  @hudButtonFocused@
 }
 
-#editBookmarkPanel .expander-up:focus,
-#editBookmarkPanel .expander-down:focus {
-  outline: 2px solid -moz-mac-focusring;
-  outline-offset: -2px;
-  -moz-outline-radius: 5px;
+#editBookmarkPanel .expander-up:hover:active,
+#editBookmarkPanel .expander-down:hover:active {
+  @hudButtonPressed@
 }
 
-#editBookmarkPanel .expander-up {
+#editBookmarkPanel .expander-up,
+#editBookmarkPanel .expander-down:hover:active {
   list-style-image: url("chrome://browser/skin/hud-style-expander-open.png") !important;
 }
 
-#editBookmarkPanel .expander-down {
+#editBookmarkPanel .expander-down,
+#editBookmarkPanel .expander-up:hover:active {
   list-style-image: url("chrome://browser/skin/hud-style-expander-closed.png") !important;
 }
 
-#editBookmarkPanel .expander-down:hover:active {
-  list-style-image: url("chrome://browser/skin/hud-style-expander-open.png") !important;
-  background-image: url("chrome://browser/skin/hud-style-button-middle-background-active.png") !important;
-  background-repeat: repeat-x !important;
-}
-
-#editBookmarkPanel .expander-up:hover:active {
-  list-style-image: url("chrome://browser/skin/hud-style-expander-closed.png") !important;
-  background-image: url("chrome://browser/skin/hud-style-button-middle-background-active.png") !important;
-  background-repeat: repeat-x !important;
-}
-
-
 /**** name picker ****/
 
 #editBMPanel_tagsField,
 #editBMPanel_namePicker[droppable="false"] > .menulist-editable-box {
   -moz-appearance: none !important;
-  margin: 2px 4px !important;
-  border: 2px solid !important;
-  -moz-border-top-colors: #1c1c1c #545454 !important;
-  -moz-border-right-colors: #1c1c1c #636363 !important;
-  -moz-border-bottom-colors: #1c1c1c #797979 !important;
-  -moz-border-left-colors: #1c1c1c #636363 !important;
-  border-radius: 1px !important;
+  -moz-padding-start: 3px !important;
+  margin: 2px !important;
+  border: 1px solid rgba(0,0,0,.5) !important;
+  box-shadow: inset 0 1px 0 rgba(0,0,0,.3);
   background-color: #666 !important;
+  background-clip: padding-box;
+  background-origin: padding-box;
   color: #fff !important;
+  min-height: 20px;
 }
 
 #editBMPanel_namePicker[droppable="false"] > .menulist-editable-box > html|*.menulist-editable-input {
   color: inherit;
 }
 
 #editBMPanel_tagsField > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input:-moz-placeholder {
   color: #bbb !important;
 }
 
 #editBMPanel_tagsField[focused="true"],
 #editBMPanel_namePicker[droppable="false"][focused="true"] > .menulist-editable-box {
-  outline: 2px solid -moz-mac-focusring;
-  outline-offset: -1px;
-  -moz-outline-radius: 1px;
+  box-shadow: 0 0 1px -moz-mac-focusring inset,
+              0 0 4px 1px -moz-mac-focusring,
+              0 0 2px 1px -moz-mac-focusring;
   background-color: #eee !important;
   color: #000 !important;
 }
 
 #editBMPanel_namePicker[droppable="false"][disabled="true"] > .menulist-editable-box {
   color: #fff !important;
 }
 
@@ -1973,17 +1949,16 @@ toolbarbutton.chevron > .toolbarbutton-m
 
 #identity-popup.verifiedIdentity > #identity-popup-container > #identity-popup-icon {
   -moz-image-region: rect(128px, 64px, 192px, 0px);
 }
 
 /* Popup Body Text */
 .identity-popup-description {
   white-space: pre-wrap;
-  color: #ffffff;
   -moz-padding-start: 15px;
   margin: 2px 0 4px;
 }
 
 .identity-popup-label {
   white-space: pre-wrap;
   -moz-padding-start: 15px;
   margin: 0;
@@ -2015,32 +1990,16 @@ toolbarbutton.chevron > .toolbarbutton-m
 }
 
 #identity-popup-content-box.verifiedIdentity > #identity-popup-encryption > vbox > #identity-popup-encryption-icon ,
 #identity-popup-content-box.verifiedDomain > #identity-popup-encryption > vbox > #identity-popup-encryption-icon {
   margin-top: 5px;
   list-style-image: url("chrome://browser/skin/Secure-Glyph-White.png");
 }
 
-/* Popup Bounding Box */
-#identity-popup {
-  -moz-appearance: none;
-  -moz-window-shadow: none;
-  background-color: transparent;
-  margin-top: -3px;
-  margin-left: -23px;
-  min-width: 280px;
-  -moz-border-image: url(chrome://browser/skin/hud-panel.png) 26 18 22 50 / 26px 18px 22px 50px repeat;
-}
-
-#notification-popup {
-  margin-left: -16px;
-  margin-right: -16px;
-}
-
 #notification-popup-box {
   margin: 0 3px;
 }
 
 .notification-anchor-icon {
   width: 16px;
   height: 16px;
   margin: 0 2px;
@@ -2095,45 +2054,29 @@ toolbarbutton.chevron > .toolbarbutton-m
   list-style-image: url(chrome://global/skin/icons/question-64.png);
 }
 
 .popup-notification-icon[popupid="password-save"],
 .popup-notification-icon[popupid="password-change"] {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
 }
 
-#identity-popup-container,
-#identity-popup-notification-container {
-  margin: 4px 3px 2px -30px;
-  color: #fff;
-}
-
-#identity-popup-content-box {
-  margin-top: 4px;
-}
-
-#identity-popup.verifiedDomain,
-#identity-popup.verifiedIdentity {
-  margin-left: -20px;
-}
-
 /* Popup Buttons */
 #identity-popup-more-info-button {
   @hudButton@
-  padding: 1px 9px;
   margin: 10px 0 0;
   min-height: 0px;
 }
 
-#identity-popup-more-info-button > .button-box > .button-text {
-  margin: 0 !important;
+#identity-popup-more-info-button:focus {
+  @hudButtonFocused@
 }
 
 #identity-popup-more-info-button:hover:active {
-  background-color: #86888B;
+  @hudButtonPressed@
 }
 
 #download-monitor {
   list-style-image: url("chrome://mozapps/skin/downloads/downloadStatusIcon.png");
 }
 
 /* ::::: Keyboard UI Panel ::::: */
 
deleted file mode 100644
index 6cce3dd185150e6b645d7b481f6937c61439887c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 9367c6a919a6aa00c1a6bde08594375a86df7293..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 1a7ed7d2281eec53d76c1933323458d2034bd939..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 509b0be0a02ae3f6130226f13b5aa8b357ece73d..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 1a6ee66f65fdf891292a4a27adb1d8fd189f2c6c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/pinstripe/browser/jar.mn
+++ b/browser/themes/pinstripe/browser/jar.mn
@@ -13,26 +13,21 @@ browser.jar:
 * skin/classic/browser/browser.css                          (browser.css)
 * skin/classic/browser/effects.svg                          (effects.svg)
 * skin/classic/browser/engineManager.css                    (engineManager.css)
   skin/classic/browser/fullscreen-video.css
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/Go-arrow.png
   skin/classic/browser/home.png
-  skin/classic/browser/hud-panel.png
-  skin/classic/browser/hud-style-button-middle-background.png
   skin/classic/browser/hud-style-check-box-checked.png
   skin/classic/browser/hud-style-check-box-empty.png
   skin/classic/browser/hud-style-dropmarker-double-arrows.png
   skin/classic/browser/hud-style-expander-closed.png
   skin/classic/browser/hud-style-expander-open.png
-  skin/classic/browser/hud-style-new-folder-bar-background-active.png
-  skin/classic/browser/hud-style-new-folder-bar-background.gif
-  skin/classic/browser/hud-style-new-folder-bar-background.png
   skin/classic/browser/hud-style-new-folder-plus-sign.png
   skin/classic/browser/hud-style-twisties.png
   skin/classic/browser/identity.png
   skin/classic/browser/Info.png
   skin/classic/browser/KUI-background.png
   skin/classic/browser/KUI-close.png
   skin/classic/browser/menu-back.png
   skin/classic/browser/menu-forward.png
--- a/browser/themes/pinstripe/browser/shared.inc
+++ b/browser/themes/pinstripe/browser/shared.inc
@@ -1,4 +1,6 @@
 %include ../../../../toolkit/themes/pinstripe/global/shared.inc
 %include ../../browserShared.inc
 
-%define hudButton -moz-appearance: none; background: url("chrome://browser/skin/hud-style-button-middle-background.png") repeat-x #464646 center center; border: 3px solid; -moz-border-top-colors: rgba(0,0,0,0.35) rgba(26,26,26,0.5) rgba(255,255,255,0.4); -moz-border-right-colors: rgba(53,53,53,1) rgba(53,53,53,1) rgba(162,162,162,1); -moz-border-bottom-colors: rgba(128,128,128,0.35) rgba(0,0,0,0.5) rgba(255,255,255,0.15); -moz-border-left-colors: rgba(0,0,0,0.35) rgba(26,26,26,0.5) rgba(255,255,255,0.4); border-radius: 20px; color: #fff;
+%define hudButton -moz-appearance: none; color: #fff; text-shadow: 0 -1px 0 rgba(0,0,0,.5); border-radius: 12px; border: 1px solid rgba(0,0,0,.65); background: -moz-linear-gradient(rgba(110,110,110,.9), rgba(70,70,70,.9) 49%, rgba(50,50,50,.9) 51%, rgba(40,40,40,.9)); box-shadow: inset 0 1px 0 rgba(255,255,255,.2), inset 0 0 1px rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1); background-clip: padding-box; background-origin: padding-box; padding: 2px 9px;
+%define hudButtonPressed background: -moz-linear-gradient(rgba(40,40,40,.9), rgba(70,70,70,.9)); box-shadow: inset 0 0 3px rgba(0,0,0,.2), inset 0 1px 7px rgba(0,0,0,.4), 0 1px 0 rgba(255,255,255,.1);
+%define hudButtonFocused box-shadow: 0 0 1px -moz-mac-focusring inset, 0 0 4px 1px -moz-mac-focusring, 0 0 2px 1px -moz-mac-focusring;
--- a/browser/themes/pinstripe/browser/tabview/tabview.css
+++ b/browser/themes/pinstripe/browser/tabview/tabview.css
@@ -529,22 +529,27 @@ html[dir=rtl] .iq-resizable-se {
 
 html[dir=rtl] #exit-button {
   right: auto;
   left: 0;
 }
 
 /* Search
 ----------------------------------*/
-#search {
+#searchshade{
   background-color: rgba(0,0,0,.42);
   width: 100%;
   height: 100%;
 }
 
+#search{
+  width: 100%;
+  height: 100%;
+}
+
 #searchbox {
   width: 270px;
   height: 30px;
   box-shadow: 0px 1px 0px rgba(255,255,255,.5), 0px -1px 0px rgba(0,0,0,1), 0px 0px 13px rgba(0,0,0,.8);
   color: white;
   border: none;
   background-color: #272727;
   border-radius: 0.4em;
--- a/browser/themes/winstripe/browser/browser-aero.css
+++ b/browser/themes/winstripe/browser/browser-aero.css
@@ -40,31 +40,16 @@
     -moz-border-right-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
   }
 
   #appmenu-popup {
     margin-top: -1px;
     -moz-margin-start: 1px;
   }
 
-  /* Bug 413060, comment 16: Vista Aero is a special case where we use a
-     tooltip appearance for the address bar popup panels */
-  #identity-popup,
-  #editBookmarkPanel {
-    -moz-appearance: tooltip;
-    color: InfoText;
-  }
-
-  /* Make the left and right paddings smaller, to compensate for the horizontal
-     space added by the tooltip appearance, see bug 432529. */
-  #identity-popup-container {
-    -moz-padding-start: 6px;
-    -moz-padding-end: 6px;
-  }
-
   #sidebar-splitter {
     border: 0;
     -moz-border-end: 1px solid #A9B7C9;
     min-width: 0;
     width: 3px;
     background-color: transparent;
     -moz-margin-start: -3px;
     position: relative;
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -1361,23 +1361,16 @@ richlistitem[type~="action"][actiontype=
   -moz-image-region: rect(0px 48px 16px 32px);
 }
 
 #star-button[starred="true"] {
   list-style-image: url("chrome://browser/skin/places/editBookmark.png");
 }
 
 /* bookmarking panel */
-
-#editBookmarkPanel {
-  -moz-appearance: menupopup;
-  color: MenuText;
-  padding: 4px;
-}
-
 #editBookmarkPanelStarIcon {
   list-style-image: url("chrome://browser/skin/places/starred48.png");
   width: 48px;
   height: 48px;
 }
 
 #editBookmarkPanelStarIcon[unstarred] {
   list-style-image: url("chrome://browser/skin/places/unstarred48.png");
@@ -1848,27 +1841,16 @@ toolbarbutton.bookmark-item[dragover="tr
 }
 
 #identity-popup-more-info-button {
   margin-top: 6px;
   margin-bottom: 0;
   -moz-margin-end: 0;
 }
 
-/* Popup Bounding Box */
-#identity-popup {
-  -moz-appearance: menupopup;
-  color: MenuText;
-}
-
-/* Notification popup */
-#notification-popup {
-  padding: 10px;
-}
-
 .popup-notification-icon {
   width: 64px;
   height: 64px;
   -moz-margin-end: 10px;
 }
 
 .popup-notification-icon[popupid="geolocation"] {
   list-style-image: url(chrome://browser/skin/Geolocation-64.png);
@@ -1925,17 +1907,16 @@ toolbarbutton.bookmark-item[dragover="tr
 }
 
 #password-notification-icon {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
 }
 
 #identity-popup-container {
   min-width: 280px;
-  padding: 9px;
 }
 
 #download-monitor {
   list-style-image: url("chrome://browser/skin/Toolbar.png");
   -moz-image-region: rect(0, 108px, 18px, 90px);
 }
 
 /* Bookmarks roots menu-items */
--- a/browser/themes/winstripe/browser/tabview/tabview.css
+++ b/browser/themes/winstripe/browser/tabview/tabview.css
@@ -556,20 +556,25 @@ html[dir=rtl] .iq-resizable-se {
 
 html[dir=rtl] #exit-button {
   right: auto;
   left: 0;
 }
 
 /* Search
 ----------------------------------*/
-#search{
+#searchshade{
   background-color: rgba(0,0,0,.42);
   width: 100%;
-  height: 100%;  
+  height: 100%;
+}
+
+#search{
+  width: 100%;
+  height: 100%;
 }
 
 #searchbox{
   width: 270px;
   height: 30px;
   box-shadow: 0px 1px 0px rgba(255,255,255,.5), 0px -1px 0px rgba(0,0,0,1), 0px 0px 9px rgba(0,0,0,.8);
   color: white;
   border: none;
--- a/build/pgo/profileserver.py.in
+++ b/build/pgo/profileserver.py.in
@@ -42,38 +42,50 @@ import SimpleHTTPServer
 import SocketServer
 import socket
 import threading
 import os
 import sys
 import shutil
 from datetime import datetime
 from automation import Automation
+from automationutils import getDebuggerInfo, addCommonOptions
 
 PORT = 8888
 SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
 PROFILE_DIRECTORY = os.path.abspath(os.path.join(SCRIPT_DIR, "./pgoprofile"))
 MOZ_JAR_LOG_DIR = os.path.abspath(os.path.join(os.path.join(os.getenv("OBJDIR"), "dist"), "jarlog"))
 os.chdir(SCRIPT_DIR)
 
 class EasyServer(SocketServer.TCPServer):
   allow_reuse_address = True
 
 if __name__ == '__main__':
+  from optparse import OptionParser
   automation = Automation()
+
+  parser = OptionParser()
+  addCommonOptions(parser)
+
+  options, args = parser.parse_args()
+
+  debuggerInfo = getDebuggerInfo(".", options.debugger, options.debuggerArgs,
+          options.debuggerInteractive)
+
   httpd = EasyServer(("", PORT), SimpleHTTPServer.SimpleHTTPRequestHandler)
   t = threading.Thread(target=httpd.serve_forever)
   t.setDaemon(True) # don't hang on exit
   t.start()
   
   automation.setServerInfo("localhost", PORT)
   automation.initializeProfile(PROFILE_DIRECTORY)
   browserEnv = automation.environment()
   browserEnv["XPCOM_DEBUG_BREAK"] = "warn"
   browserEnv["MOZ_JAR_LOG_DIR"] = MOZ_JAR_LOG_DIR
 
   url = "http://localhost:%d/index.html" % PORT
   appPath = os.path.join(SCRIPT_DIR, automation.DEFAULT_APP)
   status = automation.runApp(url, browserEnv, appPath, PROFILE_DIRECTORY, {},
+                             debuggerInfo=debuggerInfo,
                              # the profiling HTML doesn't output anything,
                              # so let's just run this without a timeout
                              timeout = None)
   sys.exit(status)
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -172,16 +172,18 @@ VPX_X86_ASM = @VPX_X86_ASM@
 VPX_ARM_ASM = @VPX_ARM_ASM@
 NS_PRINTING = @NS_PRINTING@
 MOZ_PDF_PRINTING = @MOZ_PDF_PRINTING@
 MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@
 MOZ_HELP_VIEWER = @MOZ_HELP_VIEWER@
 MOC= @MOC@
 MOZ_NSS_PATCH = @MOZ_NSS_PATCH@
 MOZ_WEBGL = @MOZ_WEBGL@
+MOZ_ANGLE = @MOZ_ANGLE@
+MOZ_DIRECTX_SDK_PATH = @MOZ_DIRECTX_SDK_PATH@
 
 MOZ_JAVAXPCOM = @MOZ_JAVAXPCOM@
 JAVA_INCLUDE_PATH="@JAVA_INCLUDE_PATH@"
 JAVA="@JAVA@"
 JAVAC="@JAVAC@"
 JAR="@JAR@"
 
 TAR=@TAR@
@@ -587,16 +589,18 @@ STATIC_LIBIDL = @STATIC_LIBIDL@
 
 MOZ_NATIVE_MAKEDEPEND	= @SYSTEM_MAKEDEPEND@
 
 export CL_INCLUDES_PREFIX = @CL_INCLUDES_PREFIX@
 
 MOZ_AUTO_DEPS	= @MOZ_AUTO_DEPS@
 COMPILER_DEPEND = @COMPILER_DEPEND@
 MDDEPDIR        := @MDDEPDIR@
+CC_WRAPPER = @CC_WRAPPER@
+CXX_WRAPPER = @CXX_WRAPPER@
 
 MOZ_DEMANGLE_SYMBOLS = @MOZ_DEMANGLE_SYMBOLS@
 
 # XXX - these need to be cleaned up and have real checks added -cls
 CM_BLDTYPE=dbg
 AWT_11=1
 OS_TARGET=@OS_TARGET@
 OS_ARCH=@OS_ARCH@
--- a/config/config.mk
+++ b/config/config.mk
@@ -165,29 +165,16 @@ JEMALLOC_LIBS = $(MKSHLIB_FORCE_ALL) $(c
 # If we are linking jemalloc into a program, we want the jemalloc symbols
 # to be exported
 ifneq (,$(SIMPLE_PROGRAMS)$(PROGRAM))
 JEMALLOC_LIBS += $(MOZ_JEMALLOC_STANDALONE_GLUE_LDOPTS)
 endif
 endif
 endif
 
-ifndef NO_CXX_WRAPPER
-ifdef _MSC_VER
-ifndef .PYMAKE
-CC_WRAPPER = $(PYTHON) -O $(topsrcdir)/build/cl.py
-CXX_WRAPPER = $(PYTHON) -O $(topsrcdir)/build/cl.py
-else
-PYCOMMANDPATH += $(topsrcdir)/build
-CC_WRAPPER = %cl InvokeClWithDependencyGeneration
-CXX_WRAPPER = %cl InvokeClWithDependencyGeneration
-endif # .PYMAKE
-endif # _MSC_VER
-endif # NO_CXX_WRAPPER
-
 CC := $(CC_WRAPPER) $(CC)
 CXX := $(CXX_WRAPPER) $(CXX)
 
 # determine debug-related options
 _DEBUG_CFLAGS :=
 _DEBUG_LDFLAGS :=
 
 ifdef MOZ_DEBUG
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -139,25 +139,25 @@ endif
 ifdef EXTRA_DSO_LIBS
 EXTRA_DSO_LIBS	:= $(call EXPAND_MOZLIBNAME,$(EXTRA_DSO_LIBS))
 endif
 
 ################################################################################
 # Testing frameworks support
 ################################################################################
 
+testxpcobjdir = $(DEPTH)/_tests/xpcshell
+
 ifdef ENABLE_TESTS
 
 ifdef XPCSHELL_TESTS
 ifndef relativesrcdir
 $(error Must define relativesrcdir when defining XPCSHELL_TESTS.)
 endif
 
-testxpcobjdir = $(DEPTH)/_tests/xpcshell
-
 # Test file installation
 ifneq (,$(filter WINNT os2-emx,$(HOST_OS_ARCH)))
 # Windows and OS/2 nsinstall can't recursively copy directories, so use nsinstall.py
 TEST_INSTALLER = $(PYTHON) $(topsrcdir)/config/nsinstall.py
 else
 TEST_INSTALLER = $(INSTALL)
 endif
 
--- a/configure.in
+++ b/configure.in
@@ -791,17 +791,17 @@ EOF
                 AC_TRY_COMPILE([#include <exception>],
                             [std::_Throw(std::exception()); return 0;],
                             ac_cv_have_std__Throw="yes",
                             ac_cv_have_std__Throw="no")
                 CXXFLAGS="$_SAVE_CXXFLAGS"
                 AC_LANG_RESTORE
             ])
 
-        if test "$ac_cv_have_std__Throw" == "yes"; then
+        if test "$ac_cv_have_std__Throw" = "yes"; then
             AC_CACHE_CHECK(for |class __declspec(dllimport) exception| bug,
                            ac_cv_have_dllimport_exception_bug,
                 [
                     AC_LANG_SAVE
                     AC_LANG_CPLUSPLUS
                     _SAVE_CXXFLAGS="$CXXFLAGS"
                     CXXFLAGS="${CXXFLAGS} -D_HAS_EXCEPTIONS=0"
                     AC_TRY_LINK([#include <vector>],
@@ -1044,17 +1044,17 @@ from building Mozilla. Upgrade to Xcode 
     dnl /usr/bin/g(cc|++)-$GCC_VERSION.
     MOZ_PATH_PROGS(PBBUILD, pbbuild xcodebuild pbxbuild)
 
     case "$PBBUILD" in
       *xcodebuild*)
         changequote(,)
         XCODEBUILD_VERSION=`$PBBUILD -version 2>/dev/null | xargs | sed -e 's/.*DevToolsCore-\([0-9]*\).*/\1/'`
         changequote([,])
-        if test -n "$XCODEBUILD_VERSION" -a "$XCODEBUILD_VERSION" -ge 620 ; then
+        if test -n "$XCODEBUILD_VERSION" && test "$XCODEBUILD_VERSION" -ge 620 ; then
           HAS_XCODE_2_1=1;
         fi
       ;;
     esac
 
     dnl sdp was formerly in /Developer/Tools.  As of Mac OS X 10.4 (Darwin 8),
     dnl it has moved into /usr/bin.
     MOZ_PATH_PROG(SDP, sdp, :, [$PATH:/usr/bin:/Developer/Tools])
@@ -3807,17 +3807,17 @@ if test "$ac_cv_have_clock_monotonic" = 
     REALTIME_LIBS=-lrt
     AC_DEFINE(HAVE_CLOCK_MONOTONIC)
     AC_SUBST(HAVE_CLOCK_MONOTONIC)
     AC_SUBST(REALTIME_LIBS)
 fi
 
 dnl check for wcrtomb/mbrtowc
 dnl =======================================================================
-if test -z "$MACOS_DEPLOYMENT_TARGET" -o "$MACOS_DEPLOYMENT_TARGET" -ge "100300"; then
+if test -z "$MACOS_DEPLOYMENT_TARGET" || test "$MACOS_DEPLOYMENT_TARGET" -ge "100300"; then
 AC_LANG_SAVE
 AC_LANG_CPLUSPLUS
 AC_CACHE_CHECK(for wcrtomb,
     ac_cv_have_wcrtomb,
     [AC_TRY_LINK([#include <wchar.h>],
                  [mbstate_t ps={0};wcrtomb(0,'f',&ps);],
                  ac_cv_have_wcrtomb="yes",
                  ac_cv_have_wcrtomb="no")])
@@ -6310,16 +6310,61 @@ if test -n "${MOZ_JAVAXPCOM}"; then
     esac
     if test ! -f "$JAVA_INCLUDE_PATH/jni.h"; then
       AC_MSG_ERROR([The header jni.h was not found.  Set \$JAVA_HOME to your java sdk directory, use --with-java-bin-path={java-bin-dir}, or reconfigure with --disable-javaxpcom.])
     fi
   fi
 fi
 
 dnl ========================================================
+dnl = ANGLE OpenGL->D3D translator for WebGL
+dnl = * only applies to win32
+dnl = * enabled by default (shipping build); requires explicit --disable to disable
+dnl ========================================================
+MOZ_ANGLE=
+MOZ_DIRECTX_SDK_PATH=
+case "$target_os" in
+    *msvc*|*mks*|*cygwin*|*mingw*)
+        MOZ_ANGLE=1
+        ;;
+esac
+
+if test -n "$MOZ_ANGLE"; then
+MOZ_ARG_DISABLE_BOOL(angle,
+[  --disable-angle     Disable building of ANGLE for WebGL->D3D translation],
+    MOZ_ANGLE=,
+    MOZ_ANGLE=1)
+
+if test -n "$MOZ_ANGLE"; then
+  if test -z "$_WIN32_MSVC"; then
+    AC_MSG_ERROR([Building ANGLE requires MSVC.  To build without ANGLE, reconfigure with --disable-angle.])
+  fi
+
+  AC_CHECK_HEADER(d3dx9.h, [], [MOZ_ANGLE=])
+
+  if test -z "$MOZ_ANGLE"; then
+    # Try again, but try to get the SDK path from the registry.  We're going to hardcode
+    # the February 2010 SDK, since that's the one that's installed on the tinderboxen.
+    MOZ_DIRECTX_SDK_PATH=`reg query 'HKLM\Software\Microsoft\DirectX\Microsoft DirectX SDK (February 2010)' //v InstallPath | grep REG_SZ | sed 's,  *, ,g' | cut -d' ' -f4`
+    if test -n "$MOZ_DIRECTX_SDK_PATH" ; then
+      if test -f "$MOZ_DIRECTX_SDK_PATH"/include/d3dx9.h && test -f "$MOZ_DIRECTX_SDK_PATH"/lib/x86/dxguid.lib ; then
+        AC_MSG_WARN([Found DirectX SDK in registry, using $MOZ_DIRECTX_SDK])
+        MOZ_ANGLE=1
+      fi
+    fi
+  fi
+
+  if test -z "$MOZ_ANGLE"; then
+    AC_MSG_WARN([Couldn't find d3dx9.h in your INCLUDE path, needed for ANGLE.  Please install the February 2010 DirectX SDK, or make another version available in your LIB and INCLUDE path env variables.  To explicitly build without ANGLE, reconfigure with --disable-angle.])
+    AC_MSG_WARN([This will become an error in the future.])
+  fi
+fi
+fi
+
+dnl ========================================================
 dnl = Breakpad crash reporting (on by default on supported platforms)
 dnl ========================================================
 
 case $target in
 i?86-*-mingw*|x86_64-*-mingw*)
   MOZ_CRASHREPORTER=1
   ;;
 i?86-apple-darwin*|powerpc-apple-darwin*|x86_64-apple-darwin*)
@@ -6552,24 +6597,24 @@ if test -n "$MOZ_INSTALLER" -a "$OS_ARCH
     MIN_NSIS_MINOR_VER=33
     MOZ_PATH_PROGS(MAKENSISU, $MAKENSISU makensisu-2.46 makensisu makensis)
     if test -z "$MAKENSISU" -o "$MAKENSISU" = ":"; then
         AC_MSG_ERROR([To build the installer you must have the latest MozillaBuild or Unicode NSIS with a major version of $REQ_NSIS_MAJOR_VER and a minimum minor version of $MIN_NSIS_MINOR_VER in your path. To build without the installer reconfigure using --disable-installer.])
     fi
     changequote(,)
     MAKENSISU_VER=`"$MAKENSISU" -version 2>/dev/null | sed -e '/-Unicode/!s/.*//g' -e 's/^v\([0-9]\+\.[0-9]\+\)\-Unicode$/\1/g'`
     changequote([,])
-    if test ! "$MAKENSISU_VER" == ""; then
+    if test ! "$MAKENSISU_VER" = ""; then
         MAKENSISU_MAJOR_VER=`echo $MAKENSISU_VER | $AWK -F\. '{ print $1 }'`
         MAKENSISU_MINOR_VER=`echo $MAKENSISU_VER | $AWK -F\. '{ print $2 }'`
     fi
     AC_MSG_CHECKING([for Unicode NSIS with major version == $REQ_NSIS_MAJOR_VER and minor version >= $MIN_NSIS_MINOR_VER])
-    if test "$MAKENSISU_VER" == "" -o \
-       ! "$MAKENSISU_MAJOR_VER" == "$REQ_NSIS_MAJOR_VER" -o \
-       ! "$MAKENSISU_MINOR_VER" -ge $MIN_NSIS_MINOR_VER; then
+    if test "$MAKENSISU_VER" = "" ||
+       test ! "$MAKENSISU_MAJOR_VER" = "$REQ_NSIS_MAJOR_VER" -o \
+            ! "$MAKENSISU_MINOR_VER" -ge $MIN_NSIS_MINOR_VER; then
         AC_MSG_RESULT([no])
         AC_MSG_ERROR([To build the installer you must have the latest MozillaBuild or Unicode NSIS with a major version of $REQ_NSIS_MAJOR_VER and a minimum minor version of $MIN_NSIS_MINOR_VER in your path. To build without the installer reconfigure using --disable-installer.])
     fi
     AC_MSG_RESULT([yes])
     MAKENSISU="${CYGWIN_WRAPPER} $MAKENSISU"
 fi
 
 AC_SUBST(MOZ_INSTALLER)
@@ -8151,25 +8196,31 @@ else
     changequote(,)
     CL_INCLUDES_PREFIX=`"${CC}" -showIncludes -c -Fonul dummy-hello.c 2>&1 | sed -ne 's/^\([^:]*:[^:]*:\).*stdio.h$/\1/p'`
     changequote([,])
     if test -z "$CL_INCLUDES_PREFIX"; then
         AC_MSG_ERROR([Cannot find cl -showIncludes prefix.])
     fi
     AC_SUBST(CL_INCLUDES_PREFIX)
     rm -f dummy-hello.c
+    _topsrcdirwin=`cd \`dirname $0\`; pwd -W`
     dnl cl.py provides dependency generation for MSVC
+    CC_WRAPPER="$PYTHON -O $_topsrcdirwin/build/cl.py"
+    CXX_WRAPPER="$PYTHON -O $_topsrcdirwin/build/cl.py"
     COMPILER_DEPEND=1
   fi
 fi
 fi # MOZ_AUTO_DEPS
 MDDEPDIR='.deps'
 AC_SUBST(MOZ_AUTO_DEPS)
 AC_SUBST(COMPILER_DEPEND)
 AC_SUBST(MDDEPDIR)
+AC_SUBST(CC_WRAPPER)
+AC_SUBST(CXX_WRAPPER)
+
 
 dnl ========================================================
 dnl =
 dnl = Static Build Options
 dnl =
 dnl ========================================================
 MOZ_ARG_HEADER(Static build options)
 
@@ -8915,16 +8966,18 @@ AC_SUBST(ENABLE_TESTS)
 AC_SUBST(IBMBIDI)
 AC_SUBST(MOZ_UNIVERSALCHARDET)
 AC_SUBST(ACCESSIBILITY)
 AC_SUBST(MOZ_VIEW_SOURCE)
 AC_SUBST(MOZ_SPELLCHECK)
 AC_SUBST(MOZ_USER_DIR)
 AC_SUBST(MOZ_CRASHREPORTER)
 AC_SUBST(MOZ_UPDATER)
+AC_SUBST(MOZ_ANGLE)
+AC_SUBST(MOZ_DIRECTX_SDK_PATH)
 
 AC_SUBST(ENABLE_STRIP)
 AC_SUBST(PKG_SKIP_STRIP)
 AC_SUBST(USE_ELF_DYNSTR_GC)
 AC_SUBST(INCREMENTAL_LINKER)
 AC_SUBST(MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS)
 AC_SUBST(MOZ_JEMALLOC_STANDALONE_GLUE_LDOPTS)
 AC_SUBST(MOZ_COMPONENT_NSPR_LIBS)
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1507,16 +1507,18 @@ public:
   static void ASCIIToLower(const nsAString& aSource, nsAString& aDest);
 
   /**
    * Convert ASCII a-z to A-Z.
    */
   static void ASCIIToUpper(nsAString& aStr);
   static void ASCIIToUpper(const nsAString& aSource, nsAString& aDest);
 
+  // Returns NS_OK for same origin, error (NS_ERROR_DOM_BAD_URI) if not.
+  static nsresult CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel);
   static nsIInterfaceRequestor* GetSameOriginChecker();
 
   static nsIThreadJSContextStack* ThreadJSContextStack()
   {
     return sThreadJSContextStack;
   }
   
 
--- a/content/base/public/nsIContentUtils.h
+++ b/content/base/public/nsIContentUtils.h
@@ -68,25 +68,27 @@ public:
 
     virtual already_AddRefed<nsIDocumentLoaderFactory>
     FindInternalContentViewer(const char* aType,
                               ContentViewerType* aLoaderType = NULL);
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIContentUtils, NS_ICONTENTUTILS_IID)
 
-// {60083ad4-f7ed-488b-a706-bacb378fe1a5}
+// {c7193287-3e3d-467f-b6da-47b914eb4c83}
 #define NS_ICONTENTUTILS2_IID \
-{ 0x60083ad4, 0xf7ed, 0x488b, \
-{ 0xa7, 0x06, 0xba, 0xcb, 0x37, 0x8f, 0xe1, 0xa5 } }
+{ 0xc7193287, 0x3e3d, 0x467f, \
+{ 0xb6, 0xda, 0x47, 0xb9, 0x14, 0xeb, 0x4c, 0x83 } }
 
 class nsIContentUtils2 : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTUTILS2_IID)
   NS_DECL_ISUPPORTS
 
   virtual nsIInterfaceRequestor* GetSameOriginChecker();
+  // Returns NS_OK for same origin, error (NS_ERROR_DOM_BAD_URI) if not.
+  virtual nsresult CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel);
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIContentUtils2, NS_ICONTENTUTILS2_IID)
 
 #endif /* nsIContentUtils_h__ */
--- a/content/base/src/nsAttrValue.cpp
+++ b/content/base/src/nsAttrValue.cpp
@@ -440,19 +440,18 @@ nsAttrValue::ToString(nsAString& aResult
     case eSVGValue:
     {
       GetMiscContainer()->mSVGValue->GetValueString(aResult);
       break;
     }
 #endif
     case eFloatValue:
     {
-      nsAutoString str;
-      str.AppendFloat(GetFloatValue());
-      aResult = str;
+      aResult.Truncate();
+      aResult.AppendFloat(GetFloatValue());
       break;
     }
     default:
     {
       aResult.Truncate();
       break;
     }
   }
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5188,28 +5188,20 @@ nsContentUtils::GetSameOriginChecker()
 {
   if (!sSameOriginChecker) {
     sSameOriginChecker = new nsSameOriginChecker();
     NS_IF_ADDREF(sSameOriginChecker);
   }
   return sSameOriginChecker;
 }
 
-
-NS_IMPL_ISUPPORTS2(nsSameOriginChecker,
-                   nsIChannelEventSink,
-                   nsIInterfaceRequestor)
-
-NS_IMETHODIMP
-nsSameOriginChecker::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
-                                            nsIChannel *aNewChannel,
-                                            PRUint32 aFlags,
-                                            nsIAsyncVerifyRedirectCallback *cb)
-{
-  NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
+/* static */
+nsresult
+nsContentUtils::CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel)
+{
   if (!nsContentUtils::GetSecurityManager())
     return NS_ERROR_NOT_AVAILABLE;
 
   nsCOMPtr<nsIPrincipal> oldPrincipal;
   nsContentUtils::GetSecurityManager()->
     GetChannelPrincipal(aOldChannel, getter_AddRefs(oldPrincipal));
 
   nsCOMPtr<nsIURI> newURI;
@@ -5219,21 +5211,37 @@ nsSameOriginChecker::AsyncOnChannelRedir
 
   NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
 
   nsresult rv = oldPrincipal->CheckMayLoad(newURI, PR_FALSE);
   if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
     rv = oldPrincipal->CheckMayLoad(newOriginalURI, PR_FALSE);
   }
 
-  if (NS_FAILED(rv))
-      return rv;
-
-  cb->OnRedirectVerifyCallback(NS_OK);
-  return NS_OK;
+  return rv;
+}
+
+NS_IMPL_ISUPPORTS2(nsSameOriginChecker,
+                   nsIChannelEventSink,
+                   nsIInterfaceRequestor)
+
+NS_IMETHODIMP
+nsSameOriginChecker::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
+                                            nsIChannel *aNewChannel,
+                                            PRUint32 aFlags,
+                                            nsIAsyncVerifyRedirectCallback *cb)
+{
+  NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
+
+  nsresult rv = nsContentUtils::CheckSameOrigin(aOldChannel, aNewChannel);
+  if (NS_SUCCEEDED(rv)) {
+    cb->OnRedirectVerifyCallback(NS_OK);
+  }
+
+  return rv;
 }
 
 NS_IMETHODIMP
 nsSameOriginChecker::GetInterface(const nsIID & aIID, void **aResult)
 {
   return QueryInterface(aIID, aResult);
 }
 
@@ -6494,8 +6502,14 @@ nsIContentUtils::FindInternalContentView
 
 NS_IMPL_ISUPPORTS1(nsIContentUtils2, nsIContentUtils2)
 
 nsIInterfaceRequestor*
 nsIContentUtils2::GetSameOriginChecker()
 {
   return nsContentUtils::GetSameOriginChecker();
 }
+
+nsresult
+nsIContentUtils2::CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel)
+{
+  return nsContentUtils::CheckSameOrigin(aOldChannel, aNewChannel);
+}
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -4346,31 +4346,38 @@ nsDocument::CreateElement(const nsAStrin
 }
 
 NS_IMETHODIMP
 nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
                             const nsAString& aQualifiedName,
                             nsIDOMElement** aReturn)
 {
   *aReturn = nsnull;
-
+  nsCOMPtr<nsIContent> content;
+  nsresult rv = CreateElementNS(aNamespaceURI, aQualifiedName,
+                                getter_AddRefs(content));
+  NS_ENSURE_SUCCESS(rv, rv);
+  return CallQueryInterface(content, aReturn);
+}
+
+nsresult
+nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
+                            const nsAString& aQualifiedName,
+                            nsIContent** aReturn)
+{
   nsCOMPtr<nsINodeInfo> nodeInfo;
   nsresult rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI,
                                                      aQualifiedName,
                                                      mNodeInfoManager,
                                                      getter_AddRefs(nodeInfo));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIContent> content;
   PRInt32 ns = nodeInfo->NamespaceID();
-  rv = NS_NewElement(getter_AddRefs(content), ns, nodeInfo.forget(),
-                     NOT_FROM_PARSER);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return CallQueryInterface(content, aReturn);
+  return NS_NewElement(aReturn, ns,
+                       nodeInfo.forget(), NOT_FROM_PARSER);
 }
 
 NS_IMETHODIMP
 nsDocument::CreateTextNode(const nsAString& aData, nsIDOMText** aReturn)
 {
   *aReturn = nsnull;
   nsCOMPtr<nsIContent> content;
   nsresult rv = CreateTextNode(aData, getter_AddRefs(content));
@@ -6070,26 +6077,25 @@ nsDocument::AdoptNode(nsIDOMNode *aAdopt
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
   }
 
   nsIDocument *oldDocument = adoptedNode->GetOwnerDoc();
   PRBool sameDocument = oldDocument == this;
 
   JSContext *cx = nsnull;
-  JSObject *oldScope = adoptedNode->GetWrapper();
   JSObject *newScope = nsnull;
-  if (oldScope && !sameDocument) {
+  if (!sameDocument) {
     rv = nsContentUtils::GetContextAndScope(oldDocument, this, &cx, &newScope);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMArray<nsINode> nodesWithProperties;
   rv = nsNodeUtils::Adopt(adoptedNode, sameDocument ? nsnull : mNodeInfoManager,
-                          cx, oldScope, newScope, nodesWithProperties);
+                          cx, newScope, nodesWithProperties);
   if (NS_FAILED(rv)) {
     // Disconnect all nodes from their parents, since some have the old document
     // as their ownerDocument and some have this as their ownerDocument.
     BlastSubtreeToPieces(adoptedNode);
 
     if (!sameDocument && oldDocument) {
       PRUint32 count = nodesWithProperties.Count();
       for (PRUint32 j = 0; j < oldDocument->GetPropertyTableCount(); ++j) {
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -854,16 +854,19 @@ public:
 
   virtual nsresult CreateElem(const nsAString& aName, nsIAtom *aPrefix,
                               PRInt32 aNamespaceID,
                               PRBool aDocumentDefaultType,
                               nsIContent **aResult);
 
   nsresult CreateElement(const nsAString& aTagName,
                          nsIContent** aReturn);
+  nsresult CreateElementNS(const nsAString& aNamespaceURI,
+                           const nsAString& aQualifiedName,
+                           nsIContent** aReturn);
 
   nsresult CreateTextNode(const nsAString& aData, nsIContent** aReturn);
 
   virtual NS_HIDDEN_(nsresult) Sanitize();
 
   virtual NS_HIDDEN_(void) EnumerateSubDocuments(nsSubDocEnumFunc aCallback,
                                                  void *aData);
 
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -4001,24 +4001,22 @@ nsGenericElement::FireNodeInserted(nsIDo
 nsresult
 nsINode::ReplaceOrInsertBefore(PRBool aReplace, nsINode* aNewChild,
                                nsINode* aRefChild)
 {
   if (!aNewChild || (aReplace && !aRefChild)) {
     return NS_ERROR_NULL_POINTER;
   }
 
-  if (IsNodeOfType(eDATA_NODE)) {
+  if (!IsNodeOfType(eDOCUMENT) &&
+      !IsNodeOfType(eDOCUMENT_FRAGMENT) &&
+      !IsElement()) {
     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
   }
 
-  if (IsNodeOfType(eATTRIBUTE)) {
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
-
   nsIContent* refContent;
   nsresult res = NS_OK;
   PRInt32 insPos;
 
   mozAutoDocConditionalContentUpdateBatch batch(GetCurrentDoc(), PR_TRUE);
 
   // Figure out which index to insert at
   if (aRefChild) {
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -1,9 +1,10 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=99: */
 /* ***** 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/
  *
@@ -59,16 +60,17 @@
 #include "nsBindingManager.h"
 #include "nsGenericHTMLElement.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif // MOZ_MEDIA
 #include "nsImageLoadingContent.h"
 #include "jsobj.h"
 #include "jsgc.h"
+#include "xpcpublic.h"
 
 using namespace mozilla::dom;
 
 // This macro expects the ownerDocument of content_ to be in scope as
 // |nsIDocument* doc|
 // NOTE: AttributeChildRemoved doesn't use this macro but has a very similar use.
 // If you change how this macro behave please update AttributeChildRemoved.
 #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_)      \
@@ -437,35 +439,40 @@ nsNodeUtils::CloneNodeImpl(nsINode *aNod
 
   return NS_OK;
 }
 
 /* static */
 nsresult
 nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
                            nsNodeInfoManager *aNewNodeInfoManager,
-                           JSContext *aCx, JSObject *aOldScope,
-                           JSObject *aNewScope,
+                           JSContext *aCx, JSObject *aNewScope,
                            nsCOMArray<nsINode> &aNodesWithProperties,
                            nsINode *aParent, nsINode **aResult)
 {
   NS_PRECONDITION((!aClone && aNewNodeInfoManager) || !aCx,
                   "If cloning or not getting a new nodeinfo we shouldn't "
                   "rewrap");
-  NS_PRECONDITION(!aCx || (aOldScope && aNewScope), "Must have scopes");
+  NS_PRECONDITION(!aCx || aNewScope, "Must have new scope");
   NS_PRECONDITION(!aParent || aNode->IsNodeOfType(nsINode::eCONTENT),
                   "Can't insert document or attribute nodes into a parent");
 
   *aResult = nsnull;
 
   // First deal with aNode and walk its attributes (and their children). Then,
   // if aDeep is PR_TRUE, deal with aNode's children (and recurse into their
   // attributes and children).
 
   nsresult rv;
+  JSObject *wrapper;
+  if (aCx && (wrapper = aNode->GetWrapper())) {
+      rv = xpc_MorphSlimWrapper(aCx, aNode);
+      NS_ENSURE_SUCCESS(rv, rv);
+  }
+
   nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager;
 
   // aNode.
   nsINodeInfo *nodeInfo = aNode->mNodeInfo;
   nsCOMPtr<nsINodeInfo> newNodeInfo;
   if (nodeInfoManager) {
 
     // Don't allow importing/adopting nodes from non-privileged "scriptable"
@@ -511,21 +518,16 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
       isDeepDocumentClone = PR_TRUE;
       // After cloning the document itself, we want to clone the children into
       // the cloned document (somewhat like cloning and importing them into the
       // cloned document).
       nodeInfoManager = clone->mNodeInfo->NodeInfoManager();
     }
   }
   else if (nodeInfoManager) {
-    // FIXME Bug 601803 Need to support adopting a node cross-compartment
-    if (aCx && aOldScope->compartment() != aNewScope->compartment()) {
-      return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-    }
-
     nsIDocument* oldDoc = aNode->GetOwnerDoc();
     PRBool wasRegistered = PR_FALSE;
     if (oldDoc && aNode->IsElement()) {
       Element* element = aNode->AsElement();
       oldDoc->ClearBoxObjectFor(element);
       wasRegistered = oldDoc->UnregisterFreezableElement(element);
     }
 
@@ -575,22 +577,39 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
       if (imageContent)
         imageContent->NotifyOwnerDocumentChanged(oldDoc);
     }
 
     if (elem) {
       elem->RecompileScriptEventListeners();
     }
 
-    if (aCx) {
+    if (aCx && wrapper) {
       nsIXPConnect *xpc = nsContentUtils::XPConnect();
       if (xpc) {
+        JSObject *preservedWrapper = nsnull;
+
+        // If reparenting moves us to a new compartment, preserving causes
+        // problems. In that case, we release ourselves and re-preserve after
+        // reparenting so we're sure to have the right JS object preserved.
+        // We use a JSObject stack copy of the wrapper to protect it from GC
+        // under ReparentWrappedNativeIfFound.
+        if (aNode->PreservingWrapper()) {
+          preservedWrapper = wrapper;
+          nsContentUtils::ReleaseWrapper(aNode, aNode);
+        }
+
         nsCOMPtr<nsIXPConnectJSObjectHolder> oldWrapper;
-        rv = xpc->ReparentWrappedNativeIfFound(aCx, aOldScope, aNewScope, aNode,
+        rv = xpc->ReparentWrappedNativeIfFound(aCx, wrapper, aNewScope, aNode,
                                                getter_AddRefs(oldWrapper));
+
+        if (preservedWrapper) {
+          nsContentUtils::PreserveWrapper(aNode, aNode);
+        }
+
         if (NS_FAILED(rv)) {
           aNode->mNodeInfo.swap(nodeInfo);
 
           return rv;
         }
       }
     }
   }
@@ -622,18 +641,18 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
   }
   // XXX End of workaround for broken attribute nodes.
   else if (aDeep || aNode->IsNodeOfType(nsINode::eATTRIBUTE)) {
     // aNode's children.
     PRUint32 i, length = aNode->GetChildCount();
     for (i = 0; i < length; ++i) {
       nsCOMPtr<nsINode> child;
       rv = CloneAndAdopt(aNode->GetChildAt(i), aClone, PR_TRUE, nodeInfoManager,
-                         aCx, aOldScope, aNewScope, aNodesWithProperties,
-                         clone, getter_AddRefs(child));
+                         aCx, aNewScope, aNodesWithProperties, clone,
+                         getter_AddRefs(child));
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   // XXX setting document on some nodes not in a document so XBL will bind
   // and chrome won't break. Make XBL bind to document-less nodes!
   // XXXbz Once this is fixed, fix up the asserts in all implementations of
   // BindToTree to assert what they would like to assert, and fix the
--- a/content/base/src/nsNodeUtils.h
+++ b/content/base/src/nsNodeUtils.h
@@ -167,17 +167,17 @@ public:
    * @param aResult *aResult will contain the cloned node.
    */
   static nsresult Clone(nsINode *aNode, PRBool aDeep,
                         nsNodeInfoManager *aNewNodeInfoManager,
                         nsCOMArray<nsINode> &aNodesWithProperties,
                         nsIDOMNode **aResult)
   {
     return CloneAndAdopt(aNode, PR_TRUE, aDeep, aNewNodeInfoManager, nsnull,
-                         nsnull, nsnull, aNodesWithProperties, aResult);
+                         nsnull, aNodesWithProperties, aResult);
   }
 
   /**
    * Walks aNode, its attributes and descendant nodes. If aNewNodeInfoManager is
    * not null, it is used to create new nodeinfos for the nodes. Also reparents
    * the XPConnect wrappers for the nodes in aNewScope if aCx is not null.
    * aNodesWithProperties will be filled with all the nodes that have
    * properties.
@@ -185,28 +185,26 @@ public:
    * @param aNode Node to adopt.
    * @param aNewNodeInfoManager The nodeinfo manager to use to create new
    *                            nodeinfos for aNode and its attributes and
    *                            descendants. May be null if the nodeinfos
    *                            shouldn't be changed.
    * @param aCx Context to use for reparenting the wrappers, or null if no
    *            reparenting should be done. Must be null if aNewNodeInfoManager
    *            is null.
-   * @param aOldScope Old scope for the wrappers. May be null if aCx is null.
    * @param aNewScope New scope for the wrappers. May be null if aCx is null.
    * @param aNodesWithProperties All nodes (from amongst aNode and its
    *                             descendants) with properties.
    */
   static nsresult Adopt(nsINode *aNode, nsNodeInfoManager *aNewNodeInfoManager,
-                        JSContext *aCx, JSObject *aOldScope,
-                        JSObject *aNewScope,
+                        JSContext *aCx, JSObject *aNewScope,
                         nsCOMArray<nsINode> &aNodesWithProperties)
   {
     nsresult rv = CloneAndAdopt(aNode, PR_FALSE, PR_TRUE, aNewNodeInfoManager,
-                                aCx, aOldScope, aNewScope, aNodesWithProperties,
+                                aCx, aNewScope, aNodesWithProperties,
                                 nsnull);
 
     nsMutationGuard::DidMutate();
 
     return rv;
   }
 
   /**
@@ -272,39 +270,37 @@ private:
    *              descendants of the node
    * @param aNewNodeInfoManager The nodeinfo manager to use to create new
    *                            nodeinfos for aNode and its attributes and
    *                            descendants. May be null if the nodeinfos
    *                            shouldn't be changed.
    * @param aCx Context to use for reparenting the wrappers, or null if no
    *            reparenting should be done. Must be null if aClone is PR_TRUE or
    *            if aNewNodeInfoManager is null.
-   * @param aOldScope Old scope for the wrappers. May be null if aCx is null.
    * @param aNewScope New scope for the wrappers. May be null if aCx is null.
    * @param aNodesWithProperties All nodes (from amongst aNode and its
    *                             descendants) with properties. If aClone is
    *                             PR_TRUE every node will be followed by its
    *                             clone.
    * @param aResult If aClone is PR_FALSE then aResult must be null, else
    *                *aResult will contain the cloned node.
    */
   static nsresult CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
                                 nsNodeInfoManager *aNewNodeInfoManager,
-                                JSContext *aCx, JSObject *aOldScope,
-                                JSObject *aNewScope,
+                                JSContext *aCx, JSObject *aNewScope,
                                 nsCOMArray<nsINode> &aNodesWithProperties,
                                 nsIDOMNode **aResult)
   {
     NS_ASSERTION(!aClone == !aResult,
                  "aResult must be null when adopting and non-null when "
                  "cloning");
 
     nsCOMPtr<nsINode> clone;
     nsresult rv = CloneAndAdopt(aNode, aClone, aDeep, aNewNodeInfoManager,
-                                aCx, aOldScope, aNewScope, aNodesWithProperties,
+                                aCx, aNewScope, aNodesWithProperties,
                                 nsnull, getter_AddRefs(clone));
     NS_ENSURE_SUCCESS(rv, rv);
 
     return clone ? CallQueryInterface(clone, aResult) : NS_OK;
   }
 
   /**
    * See above for arguments that aren't described here.
@@ -312,15 +308,14 @@ private:
    * @param aParent If aClone is PR_TRUE the cloned node will be appended to
    *                aParent's children. May be null. If not null then aNode
    *                must be an nsIContent.
    * @param aResult If aClone is PR_TRUE then *aResult will contain the cloned
    *                node.
    */
   static nsresult CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
                                 nsNodeInfoManager *aNewNodeInfoManager,
-                                JSContext *aCx, JSObject *aOldScope,
-                                JSObject *aNewScope,
+                                JSContext *aCx, JSObject *aNewScope,
                                 nsCOMArray<nsINode> &aNodesWithProperties,
                                 nsINode *aParent, nsINode **aResult);
 };
 
 #endif // nsNodeUtils_h___
--- a/content/base/src/nsTextNode.cpp
+++ b/content/base/src/nsTextNode.cpp
@@ -233,17 +233,17 @@ nsTextNode::UnbindFromAttribute()
 #ifdef DEBUG
 void
 nsTextNode::List(FILE* out, PRInt32 aIndent) const
 {
   PRInt32 index;
   for (index = aIndent; --index >= 0; ) fputs("  ", out);
 
   fprintf(out, "Text@%p", static_cast<const void*>(this));
-  fprintf(out, " intrinsicstate=[%11x]", IntrinsicState().GetInternalValue());
+  fprintf(out, " intrinsicstate=[%llx]", IntrinsicState().GetInternalValue());
   fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
   fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
   fprintf(out, " refcount=%d<", mRefCnt.get());
 
   nsAutoString tmp;
   ToCString(tmp, 0, mText.GetLength());
   fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
 
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -1316,18 +1316,16 @@ nsXMLHttpRequest::GetStatus(PRUint32 *aS
 /* readonly attribute AUTF8String statusText; */
 NS_IMETHODIMP
 nsXMLHttpRequest::GetStatusText(nsACString& aStatusText)
 {
   nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
 
   aStatusText.Truncate();
 
-  nsresult rv = NS_OK;
-
   if (httpChannel) {
     if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
       // Make sure we don't leak status information from denied cross-site
       // requests.
       if (mChannel) {
         nsresult status;
         mChannel->GetStatus(&status);
         if (NS_FAILED(status)) {
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -416,16 +416,17 @@ include $(topsrcdir)/config/rules.mk
 		file_ws_basic_tests_wsh.py \
 		test_websocket.html \
 		file_websocket_wsh.py \
 		file_websocket_http_resource.txt \
 		test_x-frame-options.html \
 		file_x-frame-options_main.html \
 		file_x-frame-options_page.sjs \
 		test_createHTMLDocument.html \
+		test_bug564047.html \
 		test_bug567350.html \
 		test_bug574596.html \
 		test_bug578096.html \
 		test_bug598877.html \
 		test_bug599588.html \
 		test_bug600466.html \
 		test_bug600468.html \
 		test_bug600471.html \
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug564047.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=564047
+-->
+<head>
+  <title>Test for Bug 564047</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=564047">Mozilla Bug 564047</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 564047 **/
+try {
+  document.doctype.appendChild(document.createTextNode("test"));
+  ok(false, "Should have thrown an exception");
+} catch (e) {
+  ok(e instanceof DOMException, "Should be a DOMException");
+  is(e.code, DOMException.HIERARCHY_REQUEST_ERR);
+}
+</script>
+</pre>
+</body>
+</html>
--- a/content/base/test/test_bug601803.html
+++ b/content/base/test/test_bug601803.html
@@ -17,17 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 601803 **/
 SimpleTest.waitForExplicitFinish();
 
 window.onmessage = function (event) {
-    todo(event.data == "false", "Shouldn't throw when adopting a node cross-compartment");
+    is(event.data, "false", "Shouldn't throw when adopting a node cross-compartment");
     SimpleTest.finish();
 }
 
 document.getElementById("frame").src = "http://example.org/tests/content/base/test/file_bug601803a.html";
 
 
 
 </script>
--- a/content/canvas/src/CustomQS_Canvas2D.h
+++ b/content/canvas/src/CustomQS_Canvas2D.h
@@ -327,16 +327,33 @@ nsIDOMCanvasRenderingContext2D_PutImageD
         return JS_FALSE;
 
     if (wi <= 0 || hi <= 0)
         return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
 
     uint32 w = (uint32) wi;
     uint32 h = (uint32) hi;
 
+    // the optional dirty rect
+    PRBool hasDirtyRect = PR_FALSE;
+    int32 dirtyX = 0,
+          dirtyY = 0,
+          dirtyWidth = w,
+          dirtyHeight = h;
+
+    if (argc >= 7) {
+        if (!JS_ValueToECMAInt32(cx, argv[3], &dirtyX) ||
+            !JS_ValueToECMAInt32(cx, argv[4], &dirtyY) ||
+            !JS_ValueToECMAInt32(cx, argv[5], &dirtyWidth) ||
+            !JS_ValueToECMAInt32(cx, argv[6], &dirtyHeight))
+            return JS_FALSE;
+
+        hasDirtyRect = PR_TRUE;
+    }
+
     if (!JS_GetProperty(cx, dataObject, "data", tv.jsval_addr()) ||
         JSVAL_IS_PRIMITIVE(tv.jsval_value()))
         return JS_FALSE;
     darray = JSVAL_TO_OBJECT(tv.jsval_value());
 
     js::AutoValueRooter tsrc_tvr(cx);
 
     js::TypedArray *tsrc = NULL;
@@ -353,15 +370,15 @@ nsIDOMCanvasRenderingContext2D_PutImageD
         *tsrc_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj);
         tsrc = js::TypedArray::fromJSObject(nobj);
     } else {
         // yeah, no.
         return xpc_qsThrow(cx, NS_ERROR_DOM_TYPE_MISMATCH_ERR);
     }
 
     // make the call
-    rv = self->PutImageData_explicit(x, y, w, h, (PRUint8*) tsrc->data, tsrc->byteLength);
+    rv = self->PutImageData_explicit(x, y, w, h, (PRUint8*) tsrc->data, tsrc->byteLength, hasDirtyRect, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
     if (NS_FAILED(rv))
         return xpc_qsThrowMethodFailed(cx, rv, vp);
 
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -69,32 +69,26 @@ ifdef MOZ_WEBGL
 
 CPPSRCS += \
 	WebGLContext.cpp \
 	WebGLContextGL.cpp \
 	WebGLContextUtils.cpp \
 	WebGLContextValidate.cpp \
 	$(NULL)
 
-# We can't build ANGLE on linux-64 until build bug 560894 and related
+# We can't build ANGLE on linux until build bug 560894 and related
 # are fixed.
-ifneq ($(OS_ARCH)_$(OS_TEST),Linux_x86_64)
+ifneq ($(OS_ARCH),Linux)
 DEFINES += -DUSE_ANGLE
+USE_ANGLE=1
+else
+ifdef FORCE_BUILD_ANGLE
+DEFINES += -DUSE_ANGLE
+USE_ANGLE=1
 endif
-
-ifndef MOZ_ENABLE_LIBXUL
-
-ifdef USE_ANGLE
-
-SHARED_LIBRARY_LIBS += \
-	$(DEPTH)/gfx/angle/$(LIB_PREFIX)angle.$(LIB_SUFFIX) \
-	$(NULL)
-
-endif
-
 endif
 
 else
 
 CPPSRCS += WebGLContextNotSupported.cpp
 
 endif
 
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -311,22 +311,24 @@ WebGLContext::SetContextOptions(nsIPrope
     if (!GetBoolFromPropertyBag(aOptions, "premultipliedAlpha", &newOpts.premultipliedAlpha))
         newOpts.premultipliedAlpha = true;
 
     GetBoolFromPropertyBag(aOptions, "antialiasHint", &newOpts.antialiasHint);
 
     // enforce that if stencil is specified, we also give back depth
     newOpts.depth |= newOpts.stencil;
 
+#if 0
     LogMessage("aaHint: %d stencil: %d depth: %d alpha: %d premult: %d\n",
                newOpts.antialiasHint ? 1 : 0,
                newOpts.stencil ? 1 : 0,
                newOpts.depth ? 1 : 0,
                newOpts.alpha ? 1 : 0,
                newOpts.premultipliedAlpha ? 1 : 0);
+#endif
 
     if (mOptionsFrozen && newOpts != mOptions) {
         // Error if the options are already frozen, and the ones that were asked for
         // aren't the same as what they were originally.
         return NS_ERROR_FAILURE;
     }
 
     mOptions = newOpts;
@@ -393,18 +395,24 @@ WebGLContext::SetDimensions(PRInt32 widt
 
     PRBool verbose = PR_FALSE;
     prefService->GetBoolPref("webgl.verbose", &verbose);
     mVerbose = verbose;
 
     // Get some prefs for some preferred/overriden things
     PRBool forceOSMesa = PR_FALSE;
     PRBool preferEGL = PR_FALSE;
+    PRBool preferOpenGL = PR_FALSE;
     prefService->GetBoolPref("webgl.force_osmesa", &forceOSMesa);
     prefService->GetBoolPref("webgl.prefer_egl", &preferEGL);
+    prefService->GetBoolPref("webgl.prefer_gl", &preferOpenGL);
+
+    if (PR_GetEnv("MOZ_WEBGL_PREFER_EGL")) {
+        preferEGL = PR_TRUE;
+    }
 
     // Ask GfxInfo about what we should use
     PRBool useOpenGL = PR_TRUE;
     PRBool useANGLE = PR_TRUE;
 
     nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
     if (gfxInfo) {
         PRInt32 status;
@@ -419,45 +427,36 @@ WebGLContext::SetDimensions(PRInt32 widt
             if (status == nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION ||
                 status == nsIGfxInfo::FEATURE_BLOCKED_DEVICE)
             {
                 useANGLE = PR_FALSE;
             }
         }
     }
 
+    // allow forcing GL and not EGL/ANGLE
+    if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) {
+        preferEGL = PR_FALSE;
+        useANGLE = PR_FALSE;
+        useOpenGL = PR_TRUE;
+    }
+
     // if we're forcing osmesa, do it first
     if (forceOSMesa) {
         gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
         if (!gl || !InitAndValidateGL()) {
             LogMessage("OSMesa forced, but creating context failed -- aborting!");
             return NS_ERROR_FAILURE;
         }
         LogMessage("Using software rendering via OSMesa (THIS WILL BE SLOW)");
     }
 
 #ifdef XP_WIN
-    // On Windows, we may have a choice of backends, including straight
-    // OpenGL, D3D through ANGLE via EGL, or straight EGL/GLES2.
-    // We don't differentiate the latter two yet, but we allow for
-    // a env var to try EGL first, instead of last; there's also a pref,
-    // the env var being set overrides the pref
-    if (PR_GetEnv("MOZ_WEBGL_PREFER_EGL")) {
-        preferEGL = PR_TRUE;
-    }
-
-    // force opengl instead of EGL/ANGLE
-    if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) {
-        preferEGL = PR_FALSE;
-        useANGLE = PR_FALSE;
-        useOpenGL = PR_TRUE;
-    }
-
-    // if we want EGL, try it first
-    if (!gl && (preferEGL || useANGLE)) {
+    // if we want EGL, try it now
+    if (!gl && (preferEGL || useANGLE) && !preferOpenGL) {
         gl = gl::GLContextProviderEGL::CreateOffscreen(gfxIntSize(width, height), format);
         if (gl && !InitAndValidateGL()) {
             gl = nsnull;
         }
     }
 
     // if it failed, then try the default provider, whatever that is
     if (!gl && useOpenGL) {
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -2690,17 +2690,17 @@ WebGLContext::RenderbufferStorage(WebGLe
         // is otherwise provided by EXT_packed_depth_stencil and OES_packed_depth_stencil extensions
         // which means it's supported on most GL and GL ES systems already.
         //
         // So we just use it hoping that it's available (perhaps as an extension) and if it's not available,
         // we just let the GL generate an error and don't do anything about it ourselves.
         internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
         break;
     default:
-        ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
+        return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
     }
 
     gl->fRenderbufferStorage(target, internalformatForGL, width, height);
 
     mBoundRenderbuffer->SetInternalFormat(internalformat);
     mBoundRenderbuffer->setDimensions(width, height);
     mBoundRenderbuffer->SetInitialized(PR_FALSE);
 
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -943,19 +943,17 @@ nsCanvasRenderingContext2D::StyleColorTo
                                         NS_GET_B(aColor)),
                         aStr);
     } else {
         CopyUTF8toUTF16(nsPrintfCString(100, "rgba(%d, %d, %d, ",
                                         NS_GET_R(aColor),
                                         NS_GET_G(aColor),
                                         NS_GET_B(aColor)),
                         aStr);
-        nsString tmp;
-        tmp.AppendFloat(nsStyleUtil::ColorComponentToFloat(NS_GET_A(aColor)));
-        aStr.Append(tmp);
+        aStr.AppendFloat(nsStyleUtil::ColorComponentToFloat(NS_GET_A(aColor)));
         aStr.Append(')');
     }
 }
 
 void
 nsCanvasRenderingContext2D::DirtyAllStyles()
 {
     for (int i = 0; i < STYLE_MAX; i++) {
@@ -2796,19 +2794,21 @@ nsCanvasRenderingContext2D::DrawOrMeasur
             ShadowFinalize(blur);
         }
 
         processor.mThebes = mThebes;
     }
 
     gfxContextPathAutoSaveRestore pathSR(mThebes, PR_FALSE);
 
-    // back up path if stroking
-    if (aOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE)
+    // back up and clear path if stroking
+    if (aOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE) {
         pathSR.Save();
+        mThebes->NewPath();
+    }
     // doUseIntermediateSurface is mutually exclusive to op == STROKE
     else {
         if (doUseIntermediateSurface) {
             mThebes->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
 
             // don't want operators to be applied twice
             mThebes->SetOperator(gfxContext::OPERATOR_SOURCE);
         }
@@ -3879,26 +3879,69 @@ NS_IMETHODIMP
 nsCanvasRenderingContext2D::PutImageData()
 {
     /* Should never be called -- PutImageData_explicit is the QS entry point */
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 w, PRUint32 h,
-                                                  unsigned char *aData, PRUint32 aDataLen)
+                                                  unsigned char *aData, PRUint32 aDataLen,
+                                                  PRBool hasDirtyRect, PRInt32 dirtyX, PRInt32 dirtyY,
+                                                  PRInt32 dirtyWidth, PRInt32 dirtyHeight)
 {
     if (!mValid)
         return NS_ERROR_FAILURE;
 
     if (w == 0 || h == 0)
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    if (!CanvasUtils::CheckSaneSubrectSize (x, y, w, h, mWidth, mHeight))
-        return NS_ERROR_DOM_SYNTAX_ERR;
+    gfxRect dirtyRect;
+    gfxRect imageDataRect(0, 0, w, h);
+
+    if (hasDirtyRect) {
+        // fix up negative dimensions
+        if (dirtyWidth < 0) {
+            NS_ENSURE_TRUE(dirtyWidth != INT_MIN, NS_ERROR_DOM_INDEX_SIZE_ERR);
+
+            CheckedInt32 checkedDirtyX = CheckedInt32(dirtyX) + dirtyWidth;
+
+            if (!checkedDirtyX.valid())
+                return NS_ERROR_DOM_INDEX_SIZE_ERR;
+
+            dirtyX = checkedDirtyX.value();
+            dirtyWidth = -(int32)dirtyWidth;
+        }
+
+        if (dirtyHeight < 0) {
+            NS_ENSURE_TRUE(dirtyHeight != INT_MIN, NS_ERROR_DOM_INDEX_SIZE_ERR);
+
+            CheckedInt32 checkedDirtyY = CheckedInt32(dirtyY) + dirtyHeight;
+
+            if (!checkedDirtyY.valid())
+                return NS_ERROR_DOM_INDEX_SIZE_ERR;
+
+            dirtyY = checkedDirtyY.value();
+            dirtyHeight = -(int32)dirtyHeight;
+        }
+
+        // bound the dirty rect within the imageData rectangle
+        dirtyRect = imageDataRect.Intersect(gfxRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight));
+
+        if (dirtyRect.Width() <= 0 || dirtyRect.Height() <= 0)
+            return NS_OK;
+    } else {
+        dirtyRect = imageDataRect;
+    }
+
+    dirtyRect.MoveBy(gfxPoint(x, y));
+    dirtyRect = gfxRect(0, 0, mWidth, mHeight).Intersect(dirtyRect);
+
+    if (dirtyRect.Width() <= 0 || dirtyRect.Height() <= 0)
+        return NS_OK;
 
     PRUint32 len = w * h * 4;
     if (aDataLen != len)
         return NS_ERROR_DOM_SYNTAX_ERR;
 
     nsRefPtr<gfxImageSurface> imgsurf = new gfxImageSurface(gfxIntSize(w, h),
                                                             gfxASurface::ImageFormatARGB32);
     if (!imgsurf || imgsurf->CairoStatus())
@@ -3934,24 +3977,23 @@ nsCanvasRenderingContext2D::PutImageData
 
     gfxContextPathAutoSaveRestore pathSR(mThebes);
     gfxContextAutoSaveRestore autoSR(mThebes);
 
     // ignore clipping region, as per spec
     mThebes->ResetClip();
 
     mThebes->IdentityMatrix();
-    mThebes->Translate(gfxPoint(x, y));
     mThebes->NewPath();
-    mThebes->Rectangle(gfxRect(0, 0, w, h));
-    mThebes->SetSource(imgsurf, gfxPoint(0, 0));
+    mThebes->Rectangle(dirtyRect);
+    mThebes->SetSource(imgsurf, gfxPoint(x, y));
     mThebes->SetOperator(gfxContext::OPERATOR_SOURCE);
     mThebes->Fill();
 
-    return Redraw(gfxRect(x, y, w, h));
+    return Redraw(dirtyRect);
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
 {
     if (!mSurface) {
         *surface = nsnull;
         return NS_ERROR_NOT_AVAILABLE;
--- a/content/canvas/test/test_canvas.html
+++ b/content/canvas/test/test_canvas.html
@@ -8406,17 +8406,17 @@ isPixel(ctx, 50,25, 0,255,0,255, 2);
 isPixel(ctx, 35,25, 0,255,0,255, 2);
 isPixel(ctx, 65,25, 0,255,0,255, 2);
 isPixel(ctx, 50,15, 0,255,0,255, 2);
 isPixel(ctx, 50,45, 0,255,0,255, 2);
 
 } catch (e) {
     _thrown_outer = true;
 }
-todo(!_thrown_outer, 'should not throw exception');
+ok(!_thrown_outer, 'should not throw exception');
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.put.dirty.outside.html ]]] -->
 
 <p>Canvas test: 2d.imageData.put.dirty.outside</p>
@@ -8452,17 +8452,17 @@ isPixel(ctx, 98,25, 0,255,0,255, 2);
 isPixel(ctx, 98,45, 0,255,0,255, 2);
 isPixel(ctx, 1,5, 0,255,0,255, 2);
 isPixel(ctx, 1,25, 0,255,0,255, 2);
 isPixel(ctx, 1,45, 0,255,0,255, 2);
 
 } catch (e) {
     _thrown_outer = true;
 }
-todo(!_thrown_outer, 'should not throw exception');
+ok(!_thrown_outer, 'should not throw exception');
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.put.dirty.rect1.html ]]] -->
 
 <p>Canvas test: 2d.imageData.put.dirty.rect1</p>
@@ -8496,17 +8496,17 @@ isPixel(ctx, 50,25, 0,255,0,255, 2);
 isPixel(ctx, 35,25, 0,255,0,255, 2);
 isPixel(ctx, 65,25, 0,255,0,255, 2);
 isPixel(ctx, 50,15, 0,255,0,255, 2);
 isPixel(ctx, 50,45, 0,255,0,255, 2);
 
 } catch (e) {
     _thrown_outer = true;
 }
-todo(!_thrown_outer, 'should not throw exception');
+ok(!_thrown_outer, 'should not throw exception');
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.put.dirty.rect2.html ]]] -->
 
 <p>Canvas test: 2d.imageData.put.dirty.rect2</p>
@@ -8540,17 +8540,17 @@ isPixel(ctx, 50,25, 0,255,0,255, 2);
 isPixel(ctx, 35,25, 0,255,0,255, 2);
 isPixel(ctx, 65,25, 0,255,0,255, 2);
 isPixel(ctx, 50,15, 0,255,0,255, 2);
 isPixel(ctx, 50,45, 0,255,0,255, 2);
 
 } catch (e) {
     _thrown_outer = true;
 }
-todo(!_thrown_outer, 'should not throw exception');
+ok(!_thrown_outer, 'should not throw exception');
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.put.dirty.zero.html ]]] -->
 
 <p>Canvas test: 2d.imageData.put.dirty.zero</p>
@@ -8566,17 +8566,17 @@ var canvas = document.getElementById('c2
 var ctx = canvas.getContext('2d');
 
 ctx.fillStyle = '#f00';
 ctx.fillRect(0, 0, 100, 50)
 var imgdata = ctx.getImageData(0, 0, 100, 50);
 ctx.fillStyle = '#0f0';
 ctx.fillRect(0, 0, 100, 50)
 ctx.putImageData(imgdata, 0, 0, 0, 0, 0, 0);
-todo_isPixel(ctx, 50,25, 0,255,0,255, 2);
+isPixel(ctx, 50,25, 0,255,0,255, 2);
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.put.modified.html ]]] -->
 
 <p>Canvas test: 2d.imageData.put.modified</p>
--- a/content/canvas/test/webgl/README.mozilla
+++ b/content/canvas/test/webgl/README.mozilla
@@ -1,11 +1,11 @@
 This is a local copy of the WebGL conformance suite.
 
-  SVN revision: 12905
+  SVN revision: 13113
 
 The canonical location for this testsuite is:
 
   https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/tests/
 
 All files and directories in this directory, with the exceptions listed below, come from
 upstream and should not be modified without corresponding upstream fixes and/or a
 patch file in the "patches" directory. The exceptions (the Mozilla-specific files) are:
--- a/content/canvas/test/webgl/conformance/gl-teximage.html
+++ b/content/canvas/test/webgl/conformance/gl-teximage.html
@@ -34,17 +34,25 @@ var imgURLs = [
   'resources/gray-ramp-gamma1.0.png',
   'resources/gray-ramp-gamma2.0.png',
   'resources/gray-ramp-gamma4.0.png',
   'resources/gray-ramp-gamma9.0.png',
   'resources/gray-ramp.png',
   'resources/zero-alpha.png',
   'resources/3x3.png',
   'resources/blue-1x1.jpg',
-  'resources/green-2x2-16bit.png'];
+  'resources/green-2x2-16bit.png',
+  'resources/small-square-with-colorspin-profile.jpg',
+  'resources/small-square-with-colorspin-profile.png',
+  'resources/small-square-with-cie-rgb-profile.png',
+  'resources/small-square-with-colormatch-profile.png',
+  'resources/small-square-with-e-srgb-profile.png',
+  'resources/small-square-with-smpte-c-profile.png',
+  'resources/small-square-with-srgb-iec61966-2.1-profile.png'];
+
 
 wtu.loadImagesAsync(imgURLs, runTests);
 
 function runTests(imgs) {
   var loc = gl.getUniformLocation(program, "tex");
   gl.uniform1i(loc, 0);
 
   gl.disable(gl.BLEND);
@@ -281,34 +289,77 @@ function runTests(imgs) {
   debug("check uploading of images with no alpha channel works");
   gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
   gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
                 imgs['resources/blue-1x1.jpg']);
   glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
   wtu.drawQuad(gl);
   gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
-
   checkPixelRange(buf, middle, center, [   0,   0, 255, 255], 10);
-
   glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
 
   debug("");
   debug("check uploading of 16-bit images");
   gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
   gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
                 imgs['resources/green-2x2-16bit.png']);
   glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
   wtu.drawQuad(gl);
   gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+  checkPixelRange(buf, middle, center, [   15, 121,   0, 255], 10);
+  glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
 
-  checkPixelRange(buf, middle, center, [   15, 121,   0, 255], 10);
+  debug("");
+  debug("check uploading of images with ICC profiles");
+  gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
+  gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+
+  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
+                imgs['resources/small-square-with-colorspin-profile.jpg']);
+  glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
+  wtu.drawQuad(gl);
+  gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+  // The image is red.  However, if we ignore the color profile, it is blue.
+  checkPixelRange(buf, middle, center, [ 0, 0, 255, 255], 10);
+
+  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
+                imgs['resources/small-square-with-colorspin-profile.png']);
+  glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
+  wtu.drawQuad(gl);
+  gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+  // The image is red.  However, if we ignore the color profile, it is blue.
+  checkPixelRange(buf, middle, center, [ 0, 0, 255, 255], 10);
 
-  glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
+  var iccPNGs = [
+    'resources/small-square-with-cie-rgb-profile.png',
+    'resources/small-square-with-colormatch-profile.png',
+    'resources/small-square-with-e-srgb-profile.png',
+    'resources/small-square-with-smpte-c-profile.png',
+    'resources/small-square-with-srgb-iec61966-2.1-profile.png'];
+  for (var ii = 0; ii < iccPNGs.length; ++ii) {
+    var buf2 = new Uint8Array(width * height * 4);
+    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
+                  imgs[iccPNGs[ii]]);
+    glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
+    wtu.drawQuad(gl);
+    gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf2);
+    glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
+    var same = true;
+    for (var jj = 0; jj < buf.length; ++jj) {
+      if (buf[jj] != buf2[jj]) {
+        same = false;
+        break;
+      }
+    }
+    assertMsg(same, "uploading PNGs with same data but various ICC profiles should generate the same results");
+  }
+
   debug("");
   successfullyParsed = true;
   shouldBeTrue("successfullyParsed");
   debug('<br /><span class="pass">TEST COMPLETE</span>');
   notifyFinishedToHarness();
 }
 </script>
 </body>
--- a/content/canvas/test/webgl/conformance/glsl-conformance.html
+++ b/content/canvas/test/webgl/conformance/glsl-conformance.html
@@ -456,30 +456,33 @@ if (!gl) {
     { vShaderId: 'vshaderWithLineDirective',
       vShaderSuccess: false,
       vShaderTest: (function() { return wtu.getLastError().indexOf("124") >= 0; }),
       fShaderId: 'fshader',
       fShaderSuccess: true,
       linkSuccess: false,
       passMsg: 'vertex shader uses #line directive should report correct line',
     },
+// TODO(zmo): adding these tests back once the limit is added to WebGL spec.
+/*
     { vShaderId: 'vshader',
       vShaderSuccess: true,
       fShaderId: 'fshaderWith256CharacterIdentifier',
       fShaderSuccess: true,
       linkSuccess: true,
       passMsg: 'shared that uses 256 character identifier should succeed',
     },
     { vShaderId: 'vshader',
       vShaderSuccess: true,
       fShaderId: 'fshaderWith257CharacterIdentifier',
       fShaderSuccess: false,
       linkSuccess: false,
       passMsg: 'shared that uses 257 character identifier should fail',
     },
+*/
   ];
 
   // Read in all the shader source.
   for (var ii = 0; ii < shaderInfo.length; ++ii) {
     var si = shaderInfo[ii];
     si.vShaderSource = document.getElementById(si.vShaderId).text;
     si.fShaderSource = document.getElementById(si.fShaderId).text;
   }
--- a/content/canvas/test/webgl/conformance/read-pixels-test.html
+++ b/content/canvas/test/webgl/conformance/read-pixels-test.html
@@ -1,25 +1,25 @@
 <!--
 Copyright (c) 2009 The Chromium Authors. All rights reserved.
 Use of this source code is governed by a BSD-style license that can be
 found in the LICENSE file.
  -->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
 <html>
-  <head>
-    <title>WebGL ReadPixels conformance test.</title>
-    <link rel="stylesheet" href="../resources/js-test-style.css"/>
-    <script src="../resources/js-test-pre.js"></script>
-    <script src="resources/webgl-test.js"> </script>
-    <script src="resources/webgl-test-utils.js"> </script>
+<head>
+<title>WebGL ReadPixels conformance test.</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"> </script>
+<script src="resources/webgl-test-utils.js"> </script>
 </head>
 <body>
-<canvas id="example" width="200" height="200"></canvas>
+<canvas id="example" width="200" height="200" style="width: 20px; height: 20px"></canvas>
 <div id="description"></div>
 <div id="console"></div>
 <script>
 description("Checks that ReadPixels works as expected.");
 
 var wtu = WebGLTestUtils;
 var canvas = document.getElementById("example");
 var gl = create3DContext(canvas);
@@ -65,33 +65,31 @@ var tests = [
 for (var tt = 0; tt < tests.length; ++tt) {
   var test = tests[tt];
   debug("");
   debug("checking: " + test.msg);
   checkBuffer(test.checkColor, test.x, test.y,
               test.oneColor, test.oneX, test.oneY);
 }
 
-glErrorShouldBe(gl, gl.NO_ERROR,
-          "there should be no GL errors");
+glErrorShouldBe(gl, gl.NO_ERROR, "there should be no GL errors");
 
 function checkBuffer(checkColor, x, y, oneColor, oneX, oneY) {
   var buf = new Uint8Array(width * height * 4);
   gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
   for (var yy = 0; yy < height; ++yy) {
     for (var xx = 0; xx < width; ++xx) {
       var offset = (yy * width + xx) * 4;
       var expectedColors = (oneX == xx && oneY == yy) ? oneColor : checkColor;
       for (var cc = 0; cc < 4; ++cc) {
         var expectedColor = expectedColors[cc] * 255;
         var color = buf[offset + cc];
         var diff = Math.abs(expectedColor - color);
         assertMsg(diff < 3,
-                  "color pixel at " + xx + ", " + yy + " should be about " +
-                  expectedColor + " was " + color);
+                  "color pixel at " + xx + ", " + yy + " should be about " + expectedColor);
       }
     }
   }
 }
 
 var badFormats = [
   {
     format: gl.RGB,
@@ -123,34 +121,75 @@ var badFormats = [
     type: gl.UNSIGNED_BYTE,
     dest: new Uint8Array(1) },
   {
     format: gl.LUMINANCE_ALPHA,
     type: gl.UNSIGNED_BYTE,
     dest: new Uint8Array(2)
   }
 ];
+debug("");
+debug("check disallowed formats");
 for (var tt = 0; tt < badFormats.length; ++ tt) {
   var info = badFormats[tt]
   var format = info.format;
   var type = info.type;
   var dest = info.dest;
   gl.readPixels(0, 0, 1, 1, format, type, dest);
   // note that the GL error is INVALID_OPERATION if both format and type are invalid, but
   // INVALID_ENUM if only one is.
   glErrorShouldBe(
       gl, (format == gl.RGBA || type == gl.UNSIGNED_BYTE) ? gl.INVALID_ENUM : gl.INVALID_OPERATION,
       "Should not be able to read as " + wtu.glEnumToString(gl, format) +
       " / " + wtu.glEnumToString(gl, type));
 }
 
 debug("");
+debug("check reading with lots of drawing");
+width = 1024;
+height = 1024;
+canvas.width = width;
+canvas.height = height;
+gl.viewport(0, 0, 1024, 1024);
+var program = wtu.setupTexturedQuad(gl);
+var loc = gl.getUniformLocation(program, "tex");
+gl.disable(gl.BLEND);
+gl.disable(gl.DEPTH_TEST);
+var colors = [[255, 0, 0, 1], [0, 255, 0, 1], [0, 0, 255, 1]];
+var textures = [];
+var results = [];
+for (var ii = 0; ii < colors.length; ++ii) {
+  gl.activeTexture(gl.TEXTURE0 + ii);
+  var tex = gl.createTexture();
+  wtu.fillTexture(gl, tex, 1, 1, colors[ii]);
+  textures.push(tex);
+}
+for (var ii = 0; ii < colors.length; ++ii) {
+  for (var jj = 0; jj < 300 + ii + 1; ++jj) {
+    gl.uniform1i(loc, jj % 3);
+    gl.drawArrays(gl.TRIANGLES, 0, 6);
+  }
+  var buf = new Uint8Array(4);
+  gl.readPixels(512, 512, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+  results.push(buf);
+  for (var kk = 0; kk < 99; ++kk) {
+    gl.uniform1i(loc, (jj + kk) % 3);
+    gl.drawArrays(gl.TRIANGLES, 0, 6);
+  }
+}
+var actual;
+var expected;
+for (var ii = 0; ii < colors.length; ++ii) {
+  var buf = results[ii];
+  var color = colors[ii];
+  actual = [buf[0], buf[1], buf[2], buf[3]];
+  expected = [color[0], color[1], color[2], color[3] * 255];
+  shouldBe("actual", "expected");
+}
+glErrorShouldBe(gl, gl.NO_ERROR, "there should be no GL errors");
+
+debug("");
 successfullyParsed = true;
 </script>
-</body>
 <script src="../resources/js-test-post.js"></script>
-
-<script>
-</script>
-
 </body>
 </html>
 
--- a/content/canvas/test/webgl/conformance/renderbuffer-initialization.html
+++ b/content/canvas/test/webgl/conformance/renderbuffer-initialization.html
@@ -4,57 +4,51 @@ Use of this source code is governed by a
 found in the LICENSE file.
  -->
 <html>
 <head>
 <link rel="stylesheet" href="../resources/js-test-style.css"/>
 <script src="../resources/js-test-pre.js"></script>
 <script src="resources/webgl-test.js"></script>
 <script>
-function runTest()
+function runTest(gl, width, height)
 {
-    var canvas = document.getElementById("testbed");
-    var gl = create3DContext(canvas);
-    if (!gl) {
-        testFailed('canvas.getContext() failed');
-        return false;
-    }
 
     debug('Test whether the WebGL internal buffers have been initialized to 0.');
-    var buf = new Uint8Array(500 * 500 * 4);
-    gl.readPixels(0, 0, 500, 500, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+    var totalBytes = width * height * 4;
+    var buf = new Uint8Array(totalBytes);
+    gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
     if (gl.getError() != gl.NO_ERROR) {
         testFailed('GL error detected after readPixels().');
         return false;
     }
-    var totalBytes = 500 * 500 * 4;
     for (var i = 0; i < totalBytes; ++i) {
         if (buf[i] != 0) {
             testFailed('WebGL internal buffers are dirty.');
             return false;
         }
     }
     testPassed('Buffers have been initialized to 0.');
 
     debug('Test whether user created buffers have been initialized to 0.');
     var fbo = gl.createFramebuffer();
     gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
     var colorbuffer = gl.createRenderbuffer();
     gl.bindRenderbuffer(gl.RENDERBUFFER, colorbuffer);
-    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 500, 500);
+    gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, width, height);
     if (gl.getError() != gl.NO_ERROR) {
         testFailed('GL error detected after renderbufferStorage(internalformat = RGBA4).');
         return false;
     }
     gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorbuffer);
     if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
         testFailed('Framebuffer incomplete.');
         return false;
     }
-    gl.readPixels(0, 0, 500, 500, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+    gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
     if (gl.getError() != gl.NO_ERROR) {
         testFailed('GL error detected after readPixels().');
         return false;
     }
     for (var i = 0; i < totalBytes; ++i) {
         if (buf[i] != 0) {
             testFailed('User created buffers are dirty.');
             return false;
@@ -62,23 +56,39 @@ function runTest()
     }
 
     testPassed('Buffers have been initialized to 0.');
     return true;
 }
 </script>
 </head>
 <body>
-<canvas id="testbed" width="500px" height="500px"></canvas>
+<canvas id="testbed" width="400px" height="400px"></canvas>
 <div id="description"></div>
 <div id="console"></div>
 <script>
 var successfullyParsed = false;
 
 description('Verify renderbuffers are initialized to 0 before being read in WebGL');
 
-runTest();
+var canvas = document.getElementById("testbed");
+var gl = canvas.getContext("experimental-webgl");
+if (!gl) {
+    testFailed('canvas.getContext() failed');
+} else {
+    runTest(gl, canvas.width, canvas.height);
 
-successfullyParsed = true;
+    // Testing that canvas resizing will clear the buffers with 0 instead of the current clear values.
+    gl.clearColor(1, 0, 0, 1);
+    canvas.width += 1;
+    canvas.height += 1;
+    runTest(gl, canvas.width, canvas.height);
+
+    // Testing buffer clearing won't change the clear values.
+    var clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE);
+    shouldBe("clearColor", "[1, 0, 0, 1]");
+
+    successfullyParsed = true;
+}
 </script>
 <script src="../resources/js-test-post.js"></script>
 </body>
 </html>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7fcb96960e142ccca49f44755d6294352caf0e42
GIT binary patch
literal 134
zc%17D@N?(olHy`uVBq!ia0vp^Odu=(BG<aO82~BH0*}aIAngIhZYQ(tK!Rljj_EMf
z3|TsL4M2vnr;B3<$MxhVA}j75KXBl~?1${k%)+M=`}}!$a?0xKjDf~QGO@e!7o<o5
Pl{0v{`njxgN@xNAnL-{h
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..aa8bf377179eb9abb443514c73e1c1fb02ec71e5
GIT binary patch
literal 868
zc$@)b1DpJbP)<h;3K|Lk000e1NJLTq001ih001Hg0ssI2Nierx00009a7bBm001r{
z001r{0eGc9b^rhYGHF9YP*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-pOzze>YU6o<bX
z1dBouybo}ff}ldEZca&CN<pMVha_8*hA7e`++6<@d<@^f#l_Xh*-20+IQa<9PC^}G
ztxh8N!GZ7mhQr|;u-2Tm+p$()lo{=HUF8R%T706$GOKK}Gl<K=>GyX5vOG)piGa6f
z1i)m|X}cZ%#!_5p1H1#xVN%8*Y#=%_g#mF1$mqB*Ag%$a54;wLJD{Fc{s7dY%3pxG
z_Ja__D<D%p2*Co7QRNblCOJ0%t-KiPqx8_Irfu8G8Rk)<_Q$13My2XyajuJ84@@!y
zs{H_{wR#=pbzS}&KM2+AvY#ctvTwvE`gHaKYwP!ZKI7sFHg2cW>CHUb8^NRj3*kIl
zzXuxd*!Td+*iNkt{rC?6001CkNK#Dz0D>_90D>_90UsOy0B3^$0BZ;U0T>ei06{wd
z00V@F<r`7}00FE?L_t(|+O$_kmc=j#lX%|E{jY1y0w-}xarxe)ycjSNf{=d#AfZ?>
zyB7dZxIT;NfifuqJijGCl7}@CCIKMmj{xLvND}}UMwXi(nZNt8@jRgFvyMctve$!X
z-2(_?Rs=*hLu^{%DP`3?R5&J7e^3E*!9?gTg11Z(AfPLMg%5UJjxFnZ?J}^T65|FG
z>>ULiBsBJzp&vxhqCg&Xn5A8Nm}sA>7?&t*U*RPIb;5bcLa!EnfWjL_dupL36Z?9T
zoFzWWN&3vh6F6l?e3_;+v2`#3!VxrwBhV%$rd(>A2i(*OB<0vGF;QGg!)kZtWG(oX
zNC*-XhEPz`HYZg1oRNHRTFQZ8G6w|;>QhX8CR#Ba=v5CI!q~CJu38v6L)^o}c~vH}
z_Q*Xga!Qe6OraB`Esh9NisUTbBv4@#1;3<YYr~8*g@Uw)gcS;}g<Vvm3!?T#@Z?@u
z;YE*wK36>F%6jq=iF`Qth5`#;^3hp+HAss4J0@l);+Nk4<@a{DJM+sSZNP9?r_$MG
u&dMCB&~V?0@23(Kzp#}gNE&K3{{sM`l)Htd=@Xy;0000<MNUMnLSTY%)Np?Q
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..63454ec0dd7ced88d82c82ae7a72c86993da4342
GIT binary patch
literal 871
zc$@)e1DO1YP)<h;3K|Lk000e1NJLTq001ih001Hg0ssI2Nierx00009a7bBm001r{
z001r{0eGc9b^rhYHEBabP*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-pOzze>YU6o<cC
zp^8IP$fm<ZaTKb9P`9M5RZu9=A<5RHp)Iw!;pY0MtIy#BIO;pNii4tyqmLk+92}wq
zClUOn@BD_t;ryUdbDD0evIyhUXs_)`KM3XQ165`Kpd06z)9D-lq$*ALiGb-d0^o7O
zX}T@`#(bP<1AG8my(Eu8)PUi+$qa}qz>Y?l0dWJ^`q*oLxC5+y;ZJ}S75)ZT+7Chy
z?||L+gAginfE^XS0@x<GFaQmeP4uuoFmkhAuS=(=qC_4|a+8d6xu3>LXG(WX(gTY7
z09a_K6QvKkCLTzy?eg#VK`0BGzJC38r_4&?Q+@W`g}DEHE_YmxU^j;9cA0r=a6N(L
zmoi)3gQa!2m7hvQQbYs9dSw6r03c&XQcVB=hYA1yj0yk%_7(sDgwFr~b2|V4>{9>$
zI+p+d9ZUN2WtRW|0jx<xK~#9!v{y%##V`nyc;3zZuWQW$Cvi)0`QD_w7%&ookbeRo
zp;$4y7XVPWK8xvrGARN)za>DDhcyx=0U+p)0OW5-695=SmYX1%zx%TBJfP~cjzqAs
z*Mn%?0|;YQ1VlGOY+B(dWz{`YI3`qoPyuwoMCdMpw@eZspeuic4|ZLSE$e&jGO(c%
z;|3J$9R(dEH1?RGA4JfiKpu6NrCocNXrHPWmndyt;Uxie!g<L;uNHoQ!W%|=YM~|*
z`+Ad{B|geY`pm==IAunBnWi+cbua<K5j2M*&?Y9PTxy&L+|&vr<=8DTQCv&IYIo*j
zE%=s52oe;AP*Br0Csg^Ik$iAk%7I}r2L%f1Q%rp(S}`5yRSz1%*s;Z~S{OP*+{46q
zRVK6c$UQA`N|9nrp%bJnjtEnV<SgDKP+=4WzocVp!;CbAg0zQ(6$-C~T~wnBqV`4b
z<X&0fMUR6%S3Kv+dh!y9d^q@q0t;XA(OG>pNQ(PACT1t%m)`&7_jb5D^UEP^z;IZn
x(%ELt${ecDaNmjVrxF#vu$3f88frHG0|26wyM?Cd6QBS9002ovPDHLkV1gW|c8CA~
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a9186968fbd03385fde3d278ca80a5b1d8166ac3
GIT binary patch
literal 9145
zc%1DyYj{-EwfoFWCX)wAh6D-TmJY)s)J!sS9`kHtoJ<mk5(ty<@~XM>I5U|znKPL=
zlZ2>65EX4dDWFoVB_g20S3e&WQSYs(f~4)&-U<W|{k#a;V&HNCF&I%eckMmTU=(}5
zd;8~R<=bo4Ua!6OI&1HJ&W`l1^dTy`vA&@mQ8J3sQ96XAWAZ2KdICO#8XM7d2q6{9
zrY0geP!#+j>ROaVXoTF<Kc(n)YIZ_L28hNOeGgiMVhCLV?V<YvNRiOr3hf<KvG;X^
z%8HV|cCX;(HBD`TC`8+Yu*T8MX_f>+UZFdR7z1sv(X@>=YiQ2K8f-=*xIpqJsra~(
zgwT_+l>hQ4<tbW=;-IADi5Qic^Pr}t=RwWNoQI4``k*RhDc`d8gul57|KwN7%q8Xl
zS2~UI$(&jpjiB*gsDSj4_ikeGK3a|PRVr1EDnBPDU!9kmr=C=ppI<nsw77UuadD|S
zpFrYgY@jCO<xMD<P*hM*R8mk-P=ZlGN!&#JT^vZiLuwVIs9a8IkxWg=)s*xBOjR!J
zp{gOuEQ&y4%5s>TB1@UA%E`^6t`tJf<Vj%>q7;-|rjTW2D^*$Yd=`XixnkNxI?KM$
zRjln?$tX+KZGN$4`ix1=H{C23S+&oRJ#&5Y*<<HCQR6jFy>!p4+6^t<y0^B7rpfyk
z9p^v&&Fb9;VjrEaFMD|Fy)QqqXYk|Cw(WfT;9rLq`?~IX^yydj9{Sq_^PDCA?)x`B
zvuoh+iO<zYCWB}dB&KX-mXU-ojh?802s*XJS<K3HB{+gNo%_zRGu+1_tJXW3CwZdW
zxtU5FK=v%-Tl*o1Et9=<i%cSaJQcz>M^KgyL3$76%gLB(RE<tJ8)iP#I^Wqa<MF3&
z*gpHAk`2Ajos^LDPNtyIxv+h`u;{m~(!LYUTiiE&?~NxeG#oBn-@fVKj+@prn0Nfg
z^U@LNw91`cBW$GsS!x;@6*I{*C_+~NmdQ`YWmLIz1h3-cFR`0NWCdx9>bv7siV38P
zt9~l!PZ`~ppC|pCq#Z@9%Hk2^qGVObi0*J=#pr!LkOToM6Gm~)=EojSaTtPc#w#|#
zF%n#n<`ADFgbu?x8x!Q8VDbOHjO0R<$~N8+Ziu&pY-%b`@&2`B<=l~qJ`Q+SDu*^5
zMNtQGp&<NK0NsgV(2F1*dfh01MAQb92MHh-fFFe!2T%xjVdx3S2fZL@qg2K-A(K~*
z(tF{U3P~tR^Fy&<5I;m5yjzHcywL^jc28RF^oVqFvMo@KK_TQ%x|zrO#LRw;D0C$H
zBn+p&Eh)#LDWk!FhmS4}&WmFIqsGZ1G9V^G%O;(M+6>>>{)i9@k76l>NWdQm@u64;
z^z!SPvC#s;gZ>0pOcdtuAwJ>~c`u26d6-Wq=f;&W2TK|{{F;Bj{N=Gou%&Kk%jo2f
z<}^nA{3wpn6%<=s{!zRF4-a;HkJu2M+tN7CEeJs@P$k);lylmINUuE@@Fz1>7@z#y
zBpYYf%lllhporDG_=q@$`r;&ew0fS~?+}7QBqO=%xIxXFlmLe@UkKsf98m}_h>1}?
zGjX{=NaWYJ`EEgkgno^m2amYzN_DahXUFZJ$*RwyG{1z9<a8%}tbt_rB~p}JHLD@?
zHRSX!9Y5{S_-X$SI_*hCP9qs#gtLy*Ux@6;3tPV%wtWq1f&)T;V?uzV0aI`wqT;J)
zXpjRnBMv1`ZAJWK%0{aA7}7EIoo%8Rw(0euXr&9+aivG-(D%5)db-k}M?bFa3A;SE
z^P<Mh!;V^|J@c>qT1~)PrCnldG&F`Cd|O~{Z-j5|o!{c=z1?H=YOAl;{J6)~(-H3A
zMVF?hBN&R>daAU<xeaK{)@wCHMZCRA8~++u+SsIV2oYYxRWg-Kg~woGHAc3QH8LiK
z(`guk!J;>q^{k<Sw%BOKMq4xq(872Tug~VJtxt>wy((>DTHW2<mECNm5b^72tJSJE
zFnWfm0F8?1@{s82sR%`<Cq2~iQBNcg76U>^gZnNx3B)R`HaUroaLVnN*-9#UJt@5~
zZ1!YuuSd@Z`3^oLMnRWO>4uYUcw@UxiAN0pku)}bdn_FtDeb6O*Cl?tb`<Z=dM6(h
zVi6Bt*9BotPnwGXpKokyEEyFS4<D3ct71t?HEeT4c$WyL0vuV%0vPjiFhiTKg;u4-
z--i`6T|t{$Xx3)5+BmMlV6hntan(k_8}Kdvx@zK6a+E66q1Pq4uBz<y*nC2y!v#4E
zbh!MyzCFzQwVKqUv5^xFMg})*CcnYqXo?8FKoA5(r#T!5k--}qZ4IHQ=nCQYn<_1E
zDgyzpt=4ETn=DqwYN}^y>uI{iPCG1|owXROHH@8QleV>jCx%NYY3s$d+;_8$zZ$uM
z|1%%>kz*HN=)&uyN=ql0OL6rCV{s;9#lY!lg8^rdC@j00LR!8k6o6zi3I2Q-sf(`-
z`1vU28cjOJXohBiX4S#|pkvG&G~ih{osl&_qk#s#h1J1ibgY5av9tx6RcB<Nu?+CQ
zkJ$hXbj`SL1UWR8W0@Zr>S|byvzr)(Gg*zb29ueqsjFjXdu<(8YoZ|&xT0-MfgV1%
zv^D^VjFNeAqa@2RBrKPZBr3t>fvPYWjjS=jA3aUhWHE6%&R{he2!;umX(o;t!ii%R
zI7T|I!|AY<nP3Z<2uCn*IE&FhFhj7BU`ULag|uO8A=rws#XvAkFhej)Fh{VFU}6iY
z<!BD17;^;2Ic9<_7+V>FiH_9>*vwc6wqgtqi=(X;Bf%zu%>-Kr#yVCj(XrA5GX%2)
za|9Dx90@F8lMWuJ4vIi$(wTJ@omB^^p=lk>=xA0)b2@myphTN>Pz?;|LXAL)K=l}*
zkf08rWS|m$WU-rT7;BA@wwui6TDGQ^f%33B>T2u`j&@ir_{4}Wr@4VBY-Gz5CrC5j
znV^CJ4cT{XE>FDTJ!BK}Y7^|hSj+#a%P(%*-NuK$b;pXUMFpSO?TYYrKdjbo-)8mS
z7_|_>Ujpg4!>))6PH;XFt<w4;LWd^4C5A(OjVNd`_Q!8@8Fh7CB@I{I1^=(okg)Ky
zxk7#(-f{F~7W(v))nED0^;f(%Bw6q>Le!J*LDy@>VI0O`9L8ZB#^L`Tq;FFA5WHG+
zYpbu9j#DS$8?m*?xuCvbULCpgq26n3u5XbQA=D8PBhEQBnx)Hb)?^<<xo9FPLNcUq
zd7@!^Q`0<ha~!`;%>?jq;ZXe2_ka%jLVq9Rc)}5UrHgM)XL;ex23(c`?d=xBz^Cp6
zx+DTY0sV7K`{OkJPj87kPQOZYTAU7`{{(b_KZAB>&?4W1$3hMvyqw(U;)@=mW-cF!
z1U#{*rqSgO#iB4ciGx6H>P!0XoY>U>=Q&QDcar>3*Ze8Xb8kdw*Zl~U9!c|NY(l7T
zHA1iKPV<D#2w8>^lK<Qji*zMiQ`Da`?ul<e$$MhzyMrtZ@)V4cQ<;+Q2pRXp>dbp$
zrL>273c^&%<Qe}s%2p|}6gl!-8HMtIt(2#4iJ_OJkY~$OR1U)T#4<{*pyYBKkxZEr
zqhxZ0I%}eGT6VD(spt|rGksFd!kTMbGuX+_&XuL^bu%5CUpzaDi{wsubDy#7ShH!>
zx%E%gwnXdd&2v1n7cE|L?MrX%KmMur9&y8Je#>umANc5p7T@{UbynNlh8rRM{<c7S
zS9j0y-h1!6f6W6AKK#g|8-MZG<6E~q{mir5cf7pwm0hpC_WGW;_YVC24}Tmyc<AuE
zN8bDRuYWu7$<WEqhA(_R^2J3p4jJDoXDJj4r827nLRKrLP0XT|NLy@Qn9aCKI#o3*
zr>~pj-0Z%F&3SRgoBJG*vy+dl;%2UIF7?!&d+McG#wjhPI&WES^qvj%B93<vA6sl*
zeJ=_4{12~vc<amfg87m74fE_dOMI5pC3E_Yd+yS<o;AOC_SN6N`^kv4VOe1L1CMQg
z?GHzWzPQeI<IU~84?e!*^*_FM^5W>L=)v0-oL=#qgw$uw+<WKiyVvcB$(n`F4@;=H
z^YX5p<@=xg>Y~4IQ_n>S?UK+xU+Ui(*uACn-v&0`;<>0F=^OdwiamF{cz!5&OQEyw
zv@q~W;WPEO@7_Lj_<)2y%Wjq48NBt2gO|S?0_UCcU--E5`}Peh2Sy~cc4ywewuR@a
z*aerWZEy6SmeABgWd%QTZ{PmusR!?xd}+l<U)S(ZaM^(K;oBti(-nLBxBuYq`x6GX
z7>^xV(L1zwZQmm{Y2V<jBNdkijviH6vVU!v@=TNW;)*vU^x)d|$!l-?==e|m{jrnP
z)qP6_m%e}MGKpK&|0~;veRUFQy<GOerQX&;^@ZVz>Z2=m$-lbmg`Q168~m5yUw+WL
zXsd)KZ@jp+RoXx3vkzAvlF%9X(WA1nrzRXe``OX51DE>0JoA^G<pbL~VFH7jda4&!
z-(CIuhj%P}!XkQ9Z!frI`fGUu=+cUJ`?{{bOMlOrFMA(-qVMygs|sH}@xUkhs;YYb
zeCC7lQ__LK_5~x)_y2bI{HX~8)B&*%#{KnOJ8r8gUweFLlW_2hOLK;Xzq(ZQ-2CrP
zdHZ+6d#eWypC6Xct#9;ybjJUeZ7<w;)8MO@`~S1>%cI1v<@xsywf<zNwN*Ou-xyxD
A5dZ)H
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..59226273768e5095f230a39dcbc35df973bdec1a
GIT binary patch
literal 841
zc$@)A1GfB$P)<h;3K|Lk000e1NJLTq001ih001Hg0ssI2Nierx00009a7bBm001r{
z001r{0eGc9b^rhY7imL7P*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-pOzy-LGS07lQP
zg4jWe1nGDOadIev;HrV@V4x%!l59;HVnCB{bK?&<3a;JU1i@!ech@?Jf<A>HIy(eO
z9R<&HIMW9oh&RjWyR8l!W?I=h+tTv`IrmJPB|5a29Y$rbH5lvxWO)|z8v$Q02!N+G
z%jvuPjrpih8h8g*M{yZ}=mMi-U1$(zfT27;05JxPr1l%Y2y4Fw4CUG;hzYQeOnErv
zIzG_=W?r1CG}+g3z1Q22yK$z{s4As3OtPwkdItb)Ge5|cQ=}RHi{}TjwhtQth~-Js
z!b`ZjfbMJ4R<2<29Bv<)mS4l>C(MkaN*(=tA|Ag1K&wZ`UA-Xi0000WV@Og>004R=
z004l4004C`008P=0026d000+n008;{004mKpl}9*00053Nkl<Zc-pjAN0!Af2$Oi;
z&Hb-y%>pNJOL6($q`Vj~5`vI_0wAGSF}oK4P`Eye>47pS0zAJZK$3?w5+(s4=#K#8
zZ%7jW7)F+xAeq1Wvhh5i>a&hSu(H>KXx#${V^#!2H$!Y%;VEU+JybX*RDVzbbiqXE
zE`qmA5+I-}e}xZrU5+j5d+jo?p%UW;6zm-Z9V9gNn4up;(4s&db(p1HdzfgSsu-6j
zZC~Lf0d>N8$wIFdet^OoMtf?ZCKLO5lbj_!%1Qdn#1lAWMtqs3G_iFs0m2b9ha=D?
zCZ=3!oCn<03MA#&EiqACOT%h+=437SmPiN^6oybx(>5nm`J9n_a9YZNVKN5=3hGl#
zeI{Bl9q3gL8p7DI#jaWyIz!yU#CcUFv-Ze6EpkecVoaeEq%DpJQ;Os)-Xu_A6a~Me
zV{5~VG=+k+hlCXhuZ3MyqYI+;MeyWaS>Z*GgFaV0=gNBW5{Y~`_=W-tU-HpeeKkmm
z`#UCPC*qgh|K;~~xI6R9A#K2LSf|q2X3okSs?c!XiSMTp6~C~RBuE-+Hva<vqLjOZ
Trs)%)00000NkvXXu0mjf2dG;$
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2792b0ac5703f306856d228f135f4ac92ff97371
GIT binary patch
literal 1985
zc$@*j2R`_TP)<h;3K|Lk000e1NJLTq001ih001Hg0ssI2Nierx00009a7bBm001r{
z001r{0eGc9b^rhck7+|gP*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-rmPYc!O390&04
z7`KWjmlC$gB}IxMmoXR5FsNiBQL?oRQVi3~NVZm6C#TD5lP=qBBhrPoi)=|3>4uUM
zHkGVPv203GRHFaB=<Jbp+wDc?Y%iYQtKa`Q&+~iE^E{vP|DFdhHly5yB4q%Q7=_Hw
zQ^=Y<Cy1q1iNVkU03bvxmr^rkc;lao0d!Y`0RUCjl)F&mm%61XP|0`Lz3ZmuwR46y
z;oobBSSnKh40Ql8Vc~Kyz*q`kT)aZ602t{2bVH-03V@LZKvx_Y5(Y3z08F6RLK}eb
z98ld(v4!k+dRss}8BpCWWK%YPmKmT1A)8{q)7t|2W`G(b(Q)Gb=Yd9e%&eIJ`~Voi
z4Y80S0WvJa0z^Uq7TB<X4cK6TLKtEZig2(n6A6$*fpAD52MbdW12JMDgA}olAp{D9
zBMcw9p9TOUgu@zg_`wsx*>i$eZ%^xg$Nk5c`T)}oP}(Ptuw%cSrXc`SY6*EZ7Ent8
z`cesby_b-_41ie+Tv#ljge(AHG64WA0PX-3e|->foNUQ|^}sjfK=cw|oHxMV50pLz
zhUoyzhk#)qP^v>n;Z8!%O(vwIrT<z607jHjrLvt$ifXGmXVBWg6&m`QvxcT<UD56y
zZmKg?SE84!pEaUj<aLAFqv{MBjp~i>eo;QUkd-rLvq`*ZfSIkix_QmmgBG%JPUCvU
zpR$x%jkUTxVYRijb>&3)B<)GrHUgUp+j+LF>=^b_JE>ipeW-o)WRJ-w9E==RIW#%C
zIqq@ncADn&lT(|sgL9(uC5|%3jkAK2&uMoV<KpX*=yJ%V!lj#Qz;)&Za%J3PZU*-h
zx0HL2+s*@TIM0md!1Lk-@uGQ&yj0#HUJ<XB_lj@8cj3?Hui+o(*9kNQ0)awsSkU5X
z?i%5m?b=CksdZG1aH23t*x<%@OLJFtk9NN!@)8wz*m~r6j`z&=vhg}SMKq;)>Y{1P
zX=&a9?+4Sr_i^-T`Eu6`e_w6in|@no&hxkO@0(Q_a5!-NY{?w|Ai>;8!KPms%`=!k
z>T6brRVYX76Sg3Hb;SM!WsxrySwsa#Z<SQV>PzP>&XM&hX2u<fAG%bYP`7OQ@}fk}
ziu{$_RhL)$B{i*CzRqC%ndHzPv^HMY6u;SiOV_ru+t=<4+HJc>Gp&8^t;~yAc?WV1
z9n8u8IrnJc@yZizCkN$Q7X+M5I)D1YvrBeY5{fTh(<_TEFR8GsO0C8nMa|>iB=w#5
zzil4clJ!vdsOiauPVV!L7dbuAeQZK#3$z8=0&U@a3!f&J5^{m4Wq?IHz}Evx3;^vm
zfY}Hbjs%J+LW-sna{d(|*Mez(v_E<;qAk!CXbT_AB_Z{pT-pwx_M>u1iBU4(uUCmt
z{NB2R5MoLQF(QPxeauWHC8dEQ07P^|bVPLcyo}tG^W%t@msifc09-Xqk0iv=Vo_YH
znp4S9qvL8@^5=_oXl)D1d^FJcXIm2)jm$kN5o(-4hC>Exs%z;FbI@6+mpf8-REn|X
z=oXVQ^ZM~t6VBMA+jluP2?{(-{N&LAOI=pnNXlRT%SN5e*tT^?^X|U1=8Sz=)Pcfm
zlf#lD8OJW=R^?TmEXvO;SbA1?juf6K3clETdCOJP;_On(Ynf$wH&&Mae$%5Oy|U|9
z(XEZu)pthR^{?4*?_%w<I#&IZhS<hU_m4d&Yie%pY0+#o{=@R2eH-@?_1LZ5{R!2<
zd+N|>{mkUKZkI~e^X`Th*I(wn+ST*jYjLlr&-@MZO#?YYKC7ZF&=zP5w1xNU)8wCO
z!oaZl`<js6210r-64K{S=O68y-t%Y+v<2G2|6P9q+i7ICMI#iy0000WV@Og>004R?
z004l600000004Zn0003_00D(j000000000AS0<is00053Nkl<Zc-pjAN0!Af2$Oi;
z&Hb-y%>pNJOL6($q`Vj~5`vI_0wAGSF}oK4P`Eye>47pS0zAJZK$3?w5+(s4=#K#8
zZ%7jW7)F+xAeq1Wvhh5i>a&hSu(H>KXx#${V^#!2H$!Y%;VEU+JybX*RDVzbbiqXE
zE`qmA5+I-}e}xZrU5+j5d+jo?p%UW;6zm-Z9V9gNn4up;(4s&db(p1HdzfgSsu-6j
zZC~Lf0d>N8$wIFdet^OoMtf?ZCKLO5lbj_!%1Qdn#1lAWMtqs3G_iFs0m2b9ha=D?
zCZ=3!oCn<03MA#&EiqACOT%h+=437SmPiN^6oybx(>5nm`J9n_a9YZNVKN5=3hGl#
zeI{Bl9q3gL8p7DI#jaWyIz!yU#CcUFv-Ze6EpkecVoaeEq%DpJQ;Os)-Xu_A6a~Me
zV{5~VG=+k+hlCXhuZ3MyqYI+;MeyWaS>Z*GgFaV0=gNBW5{Y~`_=W-tU-HpeeKkmm
z`#UCPC*qgh|K;~~xI6R9A#K2LSf|q2X3okSs?c!XiSMTp6~C~RBuE-+Hva<vqLjOZ
Trs)%)00000NkvXXu0mjfce|p_
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2904e895235c885a2fdaab2469751e873a9df243
GIT binary patch
literal 871
zc$@)e1DO1YP)<h;3K|Lk000e1NJLTq001ih001Hg0ssI2Nierx00009a7bBm001r{
z001r{0eGc9b^rhYHEBabP*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-pOzJ4?f06hO}x
z2TO$@H0b(mx)ef{;+j4XL8Z1Gl5EX``k+bp^7-h}A0cl30o@%O9Q*+t1i{Il;3haZ
zI0Ok!B6y~A&v3bL!B}@Xt*)^QlSHfjc1yaRFBhMvutbd}o1-w#oL+AiAW4&$p9uJP
zK>$40oldLE->8O}(!eLsh~hj1VFSUr&NPTCzzR+>4dMo{)Ue+M@c@|P!smb)6#fdB
z%JqB@Z-6y+Js%7JD=6FoEFE8HfOeWq)zSD+%Z6>+(uvX_mV;@o<4G=ek}y?Sszy4F
zfZ{#?Ducb=uv>5Q-?*MH3wu960AgicwvzBvoqhkn*!X=ecN|~B)*~#;$`;+iT@_YG
zWm~(3S`+T~zW{l7P3hm<SepO<03c&XQcVB=dL;k=fP(-4_80&FgwX&1c^Loz=xhK0
zJc|GT8(6zMik<)f0jx<xK~#9!v{y%##V`nyc;3zZuWQW$Cvi)0`QD_w7%&ookbeRo
zp;$4y7XVPWK8xvrGARN)za>DDhcyx=0U+p)0OW5-695=SmYX1%zx%TBJfP~cjzqAs
z*Mn%?0|;YQ1VlGOY+B(dWz{`YI3`qoPyuwoMCdMpw@eZspeuic4|ZLSE$e&jGO(c%
z;|3J$9R(dEH1?RGA4JfiKpu6NrCocNXrHPWmndyt;Uxie!g<L;uNHoQ!W%|=YM~|*
z`+Ad{B|geY`pm==IAunBnWi+cbua<K5j2M*&?Y9PTxy&L+|&vr<=8DTQCv&IYIo*j
zE%=s52oe;AP*Br0Csg^Ik$iAk%7I}r2L%f1Q%rp(S}`5yRSz1%*s;Z~S{OP*+{46q
zRVK6c$UQA`N|9nrp%bJnjtEnV<SgDKP+=4WzocVp!;CbAg0zQ(6$-C~T~wnBqV`4b
z<X&0fMUR6%S3Kv+dh!y9d^q@q0t;XA(OG>pNQ(PACT1t%m)`&7_jb5D^UEP^z;IZn
x(%ELt${ecDaNmjVrxF#vu$3f88frHG0|26wyM?Cd6QBS9002ovPDHLkV1g?RZ~_1T
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a0201f113fdc8e971faa17dbff8954192ea866fd
GIT binary patch
literal 3201
zc$@)&41V*8P)<h;3K|Lk000e1NJLTq001ih001Hg0ssI2Nierx00009a7bBm001r{
z001r{0eGc9b^rhhPiaF#P*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-oy)XH-+^7Crag
z^g>IBfRsybQWXdwQbLP>6p<z>Aqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uh<iVD~V
z<RPMtgQJLw%KPDaqifc@_vX$1wbwr9tn;0-&j-K=43<bUQ8j=JsX`tR;Dg7+#^K~H
zK!FM*Z~zbpvt%K2{UZSY_<lS*D<Z%Lz5oGu(+dayz)hRLFdT>f59&ghTmgWD0l;*T
zI7<kC6aYYajzXpYKt=(8otP$50H6c_V9R4-;{Z@C0AMG7=F<Rxo%or10RUT+Ar%3j
zkpLhQWr#!oXgdI`&sK^>09Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p
z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-<?i
z0%4j!F2Z@488U%158(66005wo6%pWr^Zj_v4zAA5HjcIqUoGmt2LB>rV&neh&#Q1i
z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_<lS*MWK+n+1cgf
z<k(8YLR(?VSAG6x!e78w{cQPuJpA|d;J)G{fihizM+Erb!p!tcr5w+a34~(Y=8s4G
zw+sLL9n&JjNn*KJDiq^U5^;`1nvC-@r6P$!k}1U{(*I=Q-z@tBKHoI}uxdU5dyy@u
zU1J0GOD7Ombim^G008p4Z^6_k2m^p<gW=D2|L;HjN1!DDfM!XOaR2~bL?kX$%CkSm
z2mk;?pn)o|K^yeJ7%adB9Ki+L!3+FgHiSYX#KJ-lLJDMn9CBbOtb#%)hRv`YDqt_v
zKpix|QD}yfa1JiQRk#j4a1Z)n2%f<xynzV>LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW
zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_Ifq<Ex{*7`05XF7hP+2Hl!3BQJ=6@fL%FCo
z8iYoo3(#bAF`ADSpqtQgv>H8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X
zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ<AYmRsNLWl*PS{AOARHt#5!wki2?K;t
z!Y3k=s7tgax)J%r7-BLphge7~Bi0g+6E6^Zh(p9TBoc{3GAFr^0!gu?RMHaCM$&Fl
zBk3%un>0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4
z<uv66WtcKSRim0x-Ke2d5jBrmLam{;Qm;{ms1r1GnmNsb7D-E`t)i9F8fX`2_i3-_
zbh;7Ul^#x)&{xvS=|||7=mYe33=M`AgU5(xC>fg=2N-7=cNnjjOr{yriy6mMFgG#l
znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U
zt5vF<Q0r40Q)j6=sE4X&sBct1q<&fbi3VB2Ov6t@q*0);U*o*SAPZv|vv@2aYYnT0
zb%8a+Cb7-ge0D0knEf5Qi#@8Tp*ce{N;6lpQuCB%KL_KOarm5cP6_8Ir<e17iry6O
zDdH&`rZh~sF=bq9s+O0QSgS~@QL9Jmy*94xr=6y~MY~!1fet~(N+(<=M`w@D1)b+p
z*;C!83a1uLJv#NSE~;y#8=<>IcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya?
z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y
zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB
zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt
z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a<fJbF^|4I#xQ~n$Dc=
zKYhjYmgz5NSkDm8*fZm{6U!;YX`NG>(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C
z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB
zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe
zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0
z?2xS?_ve_-k<Mujg;0Lz*3buG=3$G&ehepthlN*$KaOySSQ^nWmo<0M+(UEUMEXRQ
zMBbZcF;6+KElM>iKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$
z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4
z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu
zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu
z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E
ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw
zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX
z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i&
z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01
z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R
z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw
zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD
zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3|
zawq-H%e&ckC+@AhPrP6BK<z=<L*0kfKU@CX*zeqbYQT4(^U>T#_XdT7&;F71j}Joy
zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z
zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot<a{81DF0~rvGr5Xr~8u`lav1h
z1DNytV>2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F}
z00053Nkl<Zc-pjAN0!Af2$Oi;&Hb-y%>pNJOL6($q`Vj~5`vI_0wAGSF}oK4P`Eye
z>47pS0zAJZK$3?w5+(s4=#K#8Z%7jW7)F+xAeq1Wvhh5i>a&hSu(H>KXx#${V^#!2
zH$!Y%;VEU+JybX*RDVzbbiqXEE`qmA5+I-}e}xZrU5+j5d+jo?p%UW;6zm-Z9V9gN
zn4up;(4s&db(p1HdzfgSsu-6jZC~Lf0d>N8$wIFdet^OoMtf?ZCKLO5lbj_!%1Qdn
z#1lAWMtqs3G_iFs0m2b9ha=D?CZ=3!oCn<03MA#&EiqACOT%h+=437SmPiN^6oybx
z(>5nm`J9n_a9YZNVKN5=3hGl#eI{Bl9q3gL8p7DI#jaWyIz!yU#CcUFv-Ze6Epkec
zVoaeEq%DpJQ;Os)-Xu_A6a~MeV{5~VG=+k+hlCXhuZ3MyqYI+;MeyWaS>Z*GgFaV0
z=gNBW5{Y~`_=W-tU-HpeeKkmm`#UCPC*qgh|K;~~xI6R9A#K2LSf|q2X3okSs?c!X
niSMTp6~C~RBuE-+Hva<vqLjOZrs)%)00000NkvXXu0mjf>D%Yb
--- a/content/canvas/test/webgl/conformance/resources/webgl-test-utils.js
+++ b/content/canvas/test/webgl/conformance/resources/webgl-test-utils.js
@@ -279,17 +279,17 @@ var fillTexture = function(gl, tex, widt
  * @param {number} width The width of the texture to create.
  * @param {number} height The height of the texture to create.
  * @param {!Array.<number>} color The color to fill with. A 4 element array
  *        where each element is in the range 0 to 255.
  * @return {!WebGLTexture}
  */
 var createColoredTexture = function(gl, width, height, color) {
   var tex = gl.createTexture();
-  fillTexture(gl, text, width, height, color);
+  fillTexture(gl, tex, width, height, color);
   return tex;
 };
 
 /**
  * Draws a previously setup quad.
  * @param {!WebGLContext} gl The WebGLContext to use.
  * @param {!Array.<number>} opt_color The color to fill clear with before
  *        drawing. A 4 element array where each element is in the range 0 to
@@ -373,30 +373,25 @@ var loadTexture = function(gl, url, call
 };
 
 /**
  * Creates a webgl context.
  * @param {!Canvas} opt_canvas The canvas tag to get context from. If one is not
  *     passed in one will be created.
  * @return {!WebGLContext} The created context.
  */
-var create3DContext = function(opt_canvas) {
+var create3DContext = function(opt_canvas, opt_attributes) {
   opt_canvas = opt_canvas || document.createElement("canvas");
   var context = null;
   try {
-    context = opt_canvas.getContext("experimental-webgl");
+    context = opt_canvas.getContext("webgl", opt_attributes);
   } catch(e) {}
   if (!context) {
     try {
-      context = opt_canvas.getContext("webkit-3d");
-    } catch(e) {}
-  }
-  if (!context) {
-    try {
-      context = opt_canvas.getContext("moz-webgl");
+      context = opt_canvas.getContext("experimental-webgl", opt_attributes);
     } catch(e) {}
   }
   if (!context) {
     testFailed("Unable to fetch WebGL rendering context for Canvas");
   }
   return context;
 }
 
--- a/content/canvas/test/webgl/conformance/resources/webgl-test.js
+++ b/content/canvas/test/webgl/conformance/resources/webgl-test.js
@@ -39,26 +39,21 @@ function webglTestLog(msg) {
 // Returns the WebGLRenderingContext for any known implementation.
 //
 function create3DContext(canvas, attributes)
 {
     if (!canvas)
         canvas = document.createElement("canvas");
     var context = null;
     try {
-        context = canvas.getContext("experimental-webgl", attributes);
+        context = canvas.getContext("webgl", attributes);
     } catch(e) {}
     if (!context) {
         try {
-            context = canvas.getContext("webkit-3d", attributes);
-        } catch(e) {}
-    }
-    if (!context) {
-        try {
-            context = canvas.getContext("moz-webgl", attributes);
+            context = canvas.getContext("experimental-webgl", attributes);
         } catch(e) {}
     }
     if (!context) {
         throw "Unable to fetch WebGL rendering context for Canvas";
     }
     return context;
 }
 
@@ -146,65 +141,65 @@ function glErrorShouldBe(gl, glError, op
 // createProgram
 //
 // Create and return a program object, attaching each of the given shaders.
 //
 // If attribs are given, bind an attrib with that name at that index.
 //
 function createProgram(gl, vshaders, fshaders, attribs)
 {
-    if (typeof(vshaders) == "string")
-  vshaders = [vshaders];
-    if (typeof(fshaders) == "string")
-  fshaders = [fshaders];
+  if (typeof(vshaders) == "string")
+    vshaders = [vshaders];
+  if (typeof(fshaders) == "string")
+    fshaders = [fshaders];
 
-    var shaders = [];
-    var i;
+  var shaders = [];
+  var i;
 
-    for (i = 0; i < vshaders.length; ++i) {
-  var shader = loadShader(gl, vshaders[i], gl.VERTEX_SHADER);
-  if (!shader)
+  for (i = 0; i < vshaders.length; ++i) {
+    var shader = loadShader(gl, vshaders[i], gl.VERTEX_SHADER);
+    if (!shader)
       return null;
-  shaders.push(shader);
-    }
+    shaders.push(shader);
+  }
 
-    for (i = 0; i < fshaders.length; ++i) {
-  var shader = loadShader(gl, fshaders[i], gl.FRAGMENT_SHADER);
-  if (!shader)
+  for (i = 0; i < fshaders.length; ++i) {
+    var shader = loadShader(gl, fshaders[i], gl.FRAGMENT_SHADER);
+    if (!shader)
       return null;
-  shaders.push(shader);
-    }
+    shaders.push(shader);
+  }
 
-    var prog = gl.createProgram();
-    for (i = 0; i < shaders.length; ++i) {
-  gl.attachShader(prog, shaders[i]);
-    }
+  var prog = gl.createProgram();
+  for (i = 0; i < shaders.length; ++i) {
+    gl.attachShader(prog, shaders[i]);
+  }
 
-    if (attribs) {
-        for (var i in attribs) {
-            gl.bindAttribLocation (prog, i, attribs[i]);
+  if (attribs) {
+    for (var i in attribs) {
+      gl.bindAttribLocation(prog, parseInt(i), attribs[i]);
+    }
   }
-    }
 
-    gl.linkProgram(prog);
+  gl.linkProgram(prog);
 
-    // Check the link status
-    var linked = gl.getProgramParameter(prog, gl.LINK_STATUS);
-    if (!linked) {
-        // something went wrong with the link
-        var error = gl.getProgramInfoLog(prog);
-        webglTestLog("Error in program linking:" + error);
+  // Check the link status
+  var linked = gl.getProgramParameter(prog, gl.LINK_STATUS);
+  if (!linked) {
+    // something went wrong with the link
+    var error = gl.getProgramInfoLog(prog);
+    webglTestLog("Error in program linking:" + error);
 
-        gl.deleteProgram(prog);
-  for (i = 0; i < shaders.length; ++i)
+    gl.deleteProgram(prog);
+    for (i = 0; i < shaders.length; ++i)
       gl.deleteShader(shaders[i]);
-        return null;
-    }
+    return null;
+  }
 
-    return prog;
+  return prog;
 }
 
 //
 // initWebGL
 //
 // Initialize the Canvas element with the passed name as a WebGL object and return the
 // WebGLRenderingContext.
 //
--- a/content/canvas/test/webgl/conformance/tex-image-and-sub-image-2d-with-video.html
+++ b/content/canvas/test/webgl/conformance/tex-image-and-sub-image-2d-with-video.html
@@ -52,16 +52,18 @@ function runOneIteration(videoElement, u
     // Disable any writes to the alpha channel
     gl.colorMask(1, 1, 1, 0);
     var texture = gl.createTexture();
     // Bind the texture to texture unit 0
     gl.bindTexture(gl.TEXTURE_2D, texture);
     // Set up texture parameters
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
     // Set up pixel store parameters
     gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
     gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
     // Upload the videoElement into the texture
     if (useTexSubImage2D) {
         // Initialize the texture to black first
         gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,
                       videoElement.videoWidth, videoElement.videoHeight, 0,
@@ -115,17 +117,17 @@ function finish() {
     }
 }
 </script>
 </head>
 <body onload="init()">
 <canvas id="example" width="32px" height="32px"></canvas>
 <div id="description"></div>
 <div id="console"></div>
-<video width="640" height="228" id="vid" controls autoplay>
+<video width="640" height="228" id="vid" controls>
   <source src="resources/red-green.mp4"  type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
   <source src="resources/red-green.webmvp8.webm" type='video/webm; codecs="vp8, vorbis"' />
   <source src="resources/red-green.theora.ogv"  type='video/ogg; codecs="theora, vorbis"' />
 </video>
 </body>
 </html>
 
 
--- a/content/canvas/test/webgl/conformance/uninitialized-test.html
+++ b/content/canvas/test/webgl/conformance/uninitialized-test.html
@@ -1,32 +1,31 @@
 <!doctype html>
 <html>
 <head>
-	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-	<title>WebGL Uninitialized GL Resources Tests</title>
-	<link rel="stylesheet" href="../resources/js-test-style.css"/>
-	<script src="../resources/js-test-pre.js"></script>
-	<script src="resources/webgl-test.js"></script>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL Uninitialized GL Resources Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
 </head>
 <body>
 <div id="description"></div>
 <div id="console"></div>
 <canvas id="canvas" width="2" height="2"> </canvas>
 <script>
 description("Tests to check user code cannot access uninitialized data from GL resources.");
 
 var canvas = document.getElementById("canvas");
 var gl = create3DContext(canvas);
 if (!gl)
   testFailed("Context created.");
 else
   testPassed("Context created.");
 
-
 debug("Reading an uninitialized texture should succeed with all bytes set to 0.");
 
 var width = 512;
 var height = 512;
 var bpp = 4;
 var expectedDataLength = width*height*bpp;
 
 var tex = gl.createTexture();
@@ -58,39 +57,35 @@ gl.framebufferTexture2D(gl.FRAMEBUFFER, 
 data = new Uint8Array(width * height * 4);
 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
 
 if (data.length != expectedDataLength) {
     testFailed("expected data length " + expectedDataLength + " but got " + data.length + " instead.");
 } else {
     var k = 0;
     for (var i = 0; i < data.length; ++i) {
-	if (data[i] != 0) {
-	    k++;
-	}
+        if (data[i] != 0) {
+            k++;
+        }
     }
 
     if (k) {
-	testFailed("Found " + k + " non-zero bytes");
+        testFailed("Found " + k + " non-zero bytes");
     } else {
-	testPassed("All data initialized");
+        testPassed("All data initialized");
     }
 }
 
 glErrorShouldBe(gl, gl.NO_ERROR);
 
 //TODO: uninitialized vertex array buffer
 //TODO: uninitialized vertex elements buffer
 //TODO: uninitialized framebuffer? (implementations would need to do a GL clear at first binding?)
 //TODO: uninitialized renderbuffer? (implementations would need to do a GL clear at first binding?)
 //TODO: uninitialized uniform arrays?
 
-
 debug("");
 successfullyParsed = true;
 </script>
 <script src="../resources/js-test-post.js"></script>
-<script>
-</script>
-
 </body>
 </html>
 
--- a/content/canvas/test/webgl/extra/big-fbos-example.html
+++ b/content/canvas/test/webgl/extra/big-fbos-example.html
@@ -3,182 +3,195 @@ Copyright (c) 2009 The Chromium Authors.
 Use of this source code is governed by a BSD-style license that can be
 found in the LICENSE file.
  -->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-<title>WebGL FBO Lost Context Test</title>
+<title>WebGL Big FBO Test</title>
 <link rel="stylesheet" href="../resources/js-test-style.css"/>
 <script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
 <script src="../../debug/webgl-debug.js"></script>
 <script src="../resources/js-test-pre.js"></script>
 <script src="../conformance/resources/webgl-test.js"></script>
 </head>
 <body>
 <div id="description"></div>
 <div id="console"></div>
-    <script id="vshader" type="x-shader/x-vertex">
-        attribute vec4 vPosition;
-        attribute vec2 texCoord0;
-        uniform mat4 world;
-        varying vec2 texCoord;
-        void main()
-        {
-            gl_Position = vPosition * world;
-            texCoord = texCoord0;
-        }
-    </script>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+attribute vec2 texCoord0;
+uniform mat4 world;
+varying vec2 texCoord;
+void main()
+{
+    gl_Position = vPosition * world;
+    texCoord = texCoord0;
+}
+</script>
 
-    <script id="fshader" type="x-shader/x-fragment">
-    uniform sampler2D tex;
-        varying vec2 texCoord;
-        void main()
-        {
-            gl_FragColor = texture2D(tex, texCoord);
-        }
-    </script>
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+uniform sampler2D tex;
+varying vec2 texCoord;
+void main()
+{
+    gl_FragColor = texture2D(tex, texCoord);
+}
+</script>
 <canvas id="canvas" width="1024" height="1024"> </canvas>
 <script>
-description("This test is to help see if an WebGL app *can* get lost context.");
+window.onload = init;
+debug("Tests the performance of using lots of large FBOs");
+
+function init() {
+  if (confirm(
+      "after clicking ok your machine may be come unresponsive or crash")) {
+    main();
+  } else {
+    debug("cancelled");
+  }
+}
 
-debug("");
-debug("Canvas.getContext");
-var g_worldLoc;
-var g_texLoc;
-var g_textures = [];
-gl = initWebGL("canvas", "vshader", "fshader", [ "vPosition", "texCoord0"], [ 0, 0, 0, 1 ], 1);
-if (!gl) {
-  testFailed("context does not exist");
-} else {
-  testPassed("context exists");
+function main() {
+  debug("");
+  debug("Canvas.getContext");
+  var g_worldLoc;
+  var g_texLoc;
+  var g_textures = [];
+  gl = initWebGL("canvas", "vshader", "fshader", [ "vPosition", "texCoord0"], [ 0, 0, 0, 1 ], 1);
+  if (!gl) {
+    testFailed("context does not exist");
+  } else {
+    testPassed("context exists");
 
-  debug("");
-  debug("Checking for out of memory handling.");
+    debug("");
+    debug("Checking for out of memory handling.");
+
+    var size = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
+    debug("max render buffer size: " + size);
+    size = size / 2;
+    debug("size used: " + size);
+
+    var allocateFramebuffers = true;
+    var intervalId = 0;
+    var count = 0;
+
+    WebGLDebugUtils.init(gl);
 
-  var size = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
-  debug("max render buffer size: " + size);
-  size = size / 2;
-  debug("size used: " + size);
+    function createFBO() {
+      var tex = gl.createTexture();
+      gl.bindTexture(gl.TEXTURE_2D, tex);
+      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+      gl.texImage2D(gl.TEXTURE_2D,
+                    0,                 // level
+                    gl.RGBA,           // internalFormat
+                    size,              // width
+                    size,              // height
+                    0,                 // border
+                    gl.RGBA,           // format
+                    gl.UNSIGNED_BYTE,  // type
+                    null);             // data
+      var fb = gl.createFramebuffer();
+      gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+      gl.framebufferTexture2D(
+          gl.FRAMEBUFFER,
+          gl.COLOR_ATTACHMENT0,
+          gl.TEXTURE_2D,
+          tex,
+          0);
+      var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+      if (status != gl.FRAMEBUFFER_COMPLETE) {
+        testFailed("gl.checkFramebufferStatus() returned " + WebGLDebugUtils.glEnumToString(status));
+        return;
+      }
+      var err = gl.getError();
+      if (err != gl.NO_ERROR) {
+        if (err != gl.OUT_OF_MEMORY) {
+          testFailed("gl.getError returned " + err);
+        }
+        return;
+      }
+      return { fb: fb, tex: tex };
+    }
+
+    gl.disable(gl.DEPTH_TEST);
 
-  var allocateFramebuffers = true;
-  var intervalId = 0;
-  var count = 0;
+    var maxFBOs = 2;
+    for (var ii = 0; ii < maxFBOs; ++ii) {
+      createFBO();
+      var t = createFBO();
+      if (!t) {
+        break;
+      }
+      tex = t.tex;
+      fb = t.fb;
 
-  WebGLDebugUtils.init(gl);
+      gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+      gl.scissor(0, 0, size, size);
+      gl.clearColor(0, ii / maxFBOs, 1 - ii / maxFBOs, 1);
+      gl.clear(gl.COLOR_BUFFER_BIT);
+      g_textures.push(tex);
+    }
+
+    debug("fbos allocated:" + g_textures.length);
+    gl.scissor(0, 0, 1024, 1024);
+    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+    var vertexObject = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+       -1,1,0, 1,1,0, -1,-1,0,
+       -1,-1,0, 1,1,0, 1,-1,0
+     ]), gl.STATIC_DRAW);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
 
-  function createFBO() {
-    var tex = gl.createTexture();
-    gl.bindTexture(gl.TEXTURE_2D, tex);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+    var vertexObject = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0, 1,0, 0,1,
+       0,1, 1,0, 1,1
+     ]), gl.STATIC_DRAW);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
+
+    g_texLoc = gl.getUniformLocation(gl.program, "tex");
+    gl.uniform1i(g_texLoc, 0);
+    g_worldLoc = gl.getUniformLocation(gl.program, "world");
+    gl.uniformMatrix4fv(g_worldLoc, false, [
+       0, 0, 0, 0,
+       0, 0, 0, 0,
+       0, 0, 1, 0,
+       0, 0, 0, 1]);
+
+    setInterval(render, 1000/60);
+  }
+
+  var g_angle = 0;
+  var g_texIndex = 0;
+  function render() {
+    g_angle += 0.1;
+    g_texIndex++;
+    if (g_texIndex >= g_textures.length) {
+      g_texIndex = 0;
+    }
+    gl.bindTexture(gl.TEXTURE_2D, g_textures[g_texIndex]);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
-    gl.texImage2D(gl.TEXTURE_2D,
-                  0,                 // level
-                  gl.RGBA,           // internalFormat
-                  size,              // width
-                  size,              // height
-                  0,                 // border
-                  gl.RGBA,           // format
-                  gl.UNSIGNED_BYTE,  // type
-                  null);             // data
-    var fb = gl.createFramebuffer();
-    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
-    gl.framebufferTexture2D(
-        gl.FRAMEBUFFER,
-        gl.COLOR_ATTACHMENT0,
-        gl.TEXTURE_2D,
-        tex,
-        0);
-    var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
-    if (status != gl.FRAMEBUFFER_COMPLETE) {
-      testFailed("gl.checkFramebufferStatus() returned " + WebGLDebugUtils.glEnumToString(status));
-      return;
-    }
-    var err = gl.getError();
-    if (err != gl.NO_ERROR) {
-      if (err != gl.OUT_OF_MEMORY) {
-        testFailed("gl.getError returned " + err);
-      }
-      return;
-    }
-    return { fb: fb, tex: tex };
-  }
-
-  gl.disable(gl.DEPTH_TEST);
-
-  var maxFBOs = 128;
-  for (var ii = 0; ii < maxFBOs; ++ii) {
-    createFBO();
-    var t = createFBO();
-    if (!t) {
-      break;
-    }
-    tex = t.tex;
-    fb = t.fb;
-
-    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
-    gl.scissor(0, 0, size, size);
-    gl.clearColor(0, ii / maxFBOs, 1 - ii / maxFBOs, 1);
-    gl.clear(gl.COLOR_BUFFER_BIT);
-    g_textures.push(tex);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+    gl.uniformMatrix4fv(g_worldLoc, false, rotationZ(g_angle));
+    gl.clearColor(1,0,0,1);
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+    gl.drawArrays(gl.TRIANGLES, 0, 6);
   }
-
-  debug("fbos allocated:" + g_textures.length);
-  gl.scissor(0, 0, 1024, 1024);
-  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
-
-  var vertexObject = gl.createBuffer();
-  gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
-  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-     -1,1,0, 1,1,0, -1,-1,0,
-     -1,-1,0, 1,1,0, 1,-1,0
-   ]), gl.STATIC_DRAW);
-  gl.enableVertexAttribArray(0);
-  gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
-
-  var vertexObject = gl.createBuffer();
-  gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
-  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0, 1,0, 0,1,
-     0,1, 1,0, 1,1
-   ]), gl.STATIC_DRAW);
-  gl.enableVertexAttribArray(1);
-  gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
-
-  g_texLoc = gl.getUniformLocation(gl.program, "tex");
-  gl.uniform1i(g_texLoc, 0);
-  g_worldLoc = gl.getUniformLocation(gl.program, "world");
-  gl.uniformMatrix4fv(g_worldLoc, false, [
-     0, 0, 0, 0,
-     0, 0, 0, 0,
-     0, 0, 1, 0,
-     0, 0, 0, 1]);
-
-  setInterval(render, 1000/60);
-}
-
-var g_angle = 0;
-var g_texIndex = 0;
-function render() {
-  g_angle += 0.1;
-  g_texIndex++;
-  if (g_texIndex >= g_textures.length) {
-    g_texIndex = 0;
-  }
-  gl.bindTexture(gl.TEXTURE_2D, g_textures[g_texIndex]);
-  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
-  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
-  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
-  gl.uniformMatrix4fv(g_worldLoc, false, rotationZ(g_angle));
-  gl.clearColor(1,0,0,1);
-  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
-  gl.drawArrays(gl.TRIANGLES, 0, 6);
 }
 
 /**
  * Creates a 4-by-4 matrix which rotates around the z-axis by the given angle.
  * @param {number} angle The angle by which to rotate (in radians).
  * @return {!o3djs.math.Matrix4} The rotation matrix.
  */
 function rotationZ(angle) {
--- a/content/canvas/test/webgl/extra/canvas-compositing-test.html
+++ b/content/canvas/test/webgl/extra/canvas-compositing-test.html
@@ -24,17 +24,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 -->
 
 <!DOCTYPE html>
 <html>
   <head>
     <title>Canvas Compositing Test</title>
     <link rel="stylesheet" href="../resources/js-test-style.css"/>
     <script src="../resources/js-test-pre.js"></script>
-    <script src="../fast/resources/webgl-test.js"> </script>
+    <script src="../conformance/resources/webgl-test.js"> </script>
 </head>
 <body>
 Below are 2 50x50 pixel canvas but using CSS to display them at 100x100 pixels. <br/>
 They are solid black with a red triangle<br/>
 They each have a 10px CSS solid black border around them.<br/>
 Depending on how the browser composites the canvas with the page  they will get
 a white outline<hr/>
 <div>
--- a/content/canvas/test/webgl/extra/fbo-lost-context.html
+++ b/content/canvas/test/webgl/extra/fbo-lost-context.html
@@ -8,41 +8,42 @@ found in the LICENSE file.
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <title>WebGL FBO Lost Context Test</title>
 <link rel="stylesheet" href="../resources/js-test-style.css"/>
 <script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
 <script src="../../debug/webgl-debug.js"></script>
 <script src="../resources/js-test-pre.js"></script>
-<script src="../fast/resources/webgl-test.js"></script>
+<script src="../conformance/resources/webgl-test.js"></script>
 </head>
 <body>
 <div id="description"></div>
 <div id="console"></div>
-    <script id="vshader" type="x-shader/x-vertex">
-        attribute vec4 vPosition;
-        attribute vec2 texCoord0;
-        uniform mat4 world;
-        varying vec2 texCoord;
-        void main()
-        {
-            gl_Position = vPosition * world;
-            texCoord = texCoord0;
-        }
-    </script>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+attribute vec2 texCoord0;
+uniform mat4 world;
+varying vec2 texCoord;
+void main()
+{
+    gl_Position = vPosition * world;
+    texCoord = texCoord0;
+}
+</script>
 
-    <script id="fshader" type="x-shader/x-fragment">
-    uniform sampler2D tex;
-        varying vec2 texCoord;
-        void main()
-        {
-            gl_FragColor = texture2D(tex, texCoord);
-        }
-    </script>
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+uniform sampler2D tex;
+varying vec2 texCoord;
+void main()
+{
+    gl_FragColor = texture2D(tex, texCoord);
+}
+</script>
 <canvas id="canvas" width="1024" height="1024"> </canvas>
 <script>
 description("This test is to help see if an WebGL app *can* get lost context.");
 
 debug("");
 debug("Canvas.getContext");
 var g_worldLoc;
 var g_texLoc;
--- a/content/canvas/test/webgl/extra/lots-of-polys-example.html
+++ b/content/canvas/test/webgl/extra/lots-of-polys-example.html
@@ -13,64 +13,72 @@ found in the LICENSE file.
 <script src="../conformance/resources/webgl-test-utils.js"> </script>
 </head>
 <body>
 <canvas id="example" width="1024" height="1024" style="width: 40px; height: 40px;">
 </canvas>
 <div id="description"></div>
 <div id="console"></div>
 <script>
-var wtu = WebGLTestUtils;
-var canvas = document.getElementById("example");
-var gl = wtu.create3DContext(canvas);
-var program = wtu.setupTexturedQuad(gl);
+window.onload = init;
+debug("Tests a WebGL program that draws a bunch of large polygons");
 
-assertMsg(gl.getError() == gl.NO_ERROR, "Should be no errors from setup.");
-
-var tex = gl.createTexture();
-gl.enable(gl.BLEND);
-gl.disable(gl.DEPTH_TEST);
+function init() {
+  if (confirm(
+      "after clicking ok your machine may be come unresponsive or crash")) {
+    main();
+  } else {
+    debug("cancelled");
+  }
+}
 
-wtu.fillTexture(gl, tex, 4096, 4096, [0, 192, 128, 255], 0);
-wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after creating texture");
+function main() {
+  var wtu = WebGLTestUtils;
+  var canvas = document.getElementById("example");
+  var gl = wtu.create3DContext(canvas);
+  var program = wtu.setupTexturedQuad(gl);
 
-gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
-gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
-gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
-gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
-wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after setting texture params");
+  assertMsg(gl.getError() == gl.NO_ERROR, "Should be no errors from setup.");
 
-var loc = gl.getUniformLocation(program, "tex");
-wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after getting tex locations");
-gl.uniform1i(loc, 0);
-wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after setting tex uniform");
+  var tex = gl.createTexture();
+  gl.enable(gl.BLEND);
+  gl.disable(gl.DEPTH_TEST);
+
+  wtu.fillTexture(gl, tex, 4096, 4096, [0, 192, 128, 255], 0);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after creating texture");
 
-var numQuads = 100000;
-var indexBuf = new ArrayBuffer(numQuads * 6);
-var indices = new Uint8Array(indexBuf);
-for (var ii = 0; ii < numQuads; ++ii) {
-  var offset = ii * 6;
-  indices[offset + 0] = 0;
-  indices[offset + 1] = 1;
-  indices[offset + 2] = 2;
-  indices[offset + 3] = 3;
-  indices[offset + 4] = 4;
-  indices[offset + 5] = 5;
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after setting texture params");
+
+  var loc = gl.getUniformLocation(program, "tex");
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after getting tex locations");
+  gl.uniform1i(loc, 0);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after setting tex uniform");
+
+  var numQuads = 100000;
+  var indexBuf = new ArrayBuffer(numQuads * 6);
+  var indices = new Uint8Array(indexBuf);
+  for (var ii = 0; ii < numQuads; ++ii) {
+    var offset = ii * 6;
+    indices[offset + 0] = 0;
+    indices[offset + 1] = 1;
+    indices[offset + 2] = 2;
+    indices[offset + 3] = 3;
+    indices[offset + 4] = 4;
+    indices[offset + 5] = 5;
+  }
+  var indexBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after creating index buffer");
+  gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_BYTE, 0);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after drawing");
+
+  successfullyParsed = true;
 }
-var indexBuffer = gl.createBuffer();
-gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
-gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
-wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after creating index buffer");
-gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_BYTE, 0);
-wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after drawing");
-
-successfullyParsed = true;
 </script>
 </body>
-<script src="../resources/js-test-post.js"></script>
-
-<script>
-</script>
-
-</body>
 </html>
 
 
--- a/content/canvas/test/webgl/extra/out-of-memory.html
+++ b/content/canvas/test/webgl/extra/out-of-memory.html
@@ -3,28 +3,28 @@ Copyright (c) 2009 The Chromium Authors.
 Use of this source code is governed by a BSD-style license that can be
 found in the LICENSE file.
 -->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-<title>WebGL Out Of Memory Conformance Tests</title>
+<title>WebGL Out Of Memory Test</title>
 <link rel="stylesheet" href="../resources/js-test-style.css"/>
 <script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
 <script src="../resources/js-test-pre.js"></script>
-<script src="../fast/resources/webgl-test.js"></script>
+<script src="../conformance/resources/webgl-test.js"></script>
 </head>
 <body>
 <div id="description"></div>
 <div id="console"></div>
 <canvas id="canvas" width="2" height="2"> </canvas>
 <script>
-description("This tests WebGL running out of memory.");
+debug("This tests WebGL running out of memory.");
 
 debug("");
 debug("Canvas.getContext");
 
 var gl = create3DContext(document.getElementById("canvas"));
 if (!gl) {
   testFailed("context does not exist");
 } else {
--- a/content/canvas/test/webgl/extra/out-of-resources.html
+++ b/content/canvas/test/webgl/extra/out-of-resources.html
@@ -8,94 +8,102 @@ found in the LICENSE file.
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <title>WebGL Out Of Resources Test</title>
 <link rel="stylesheet" href="../resources/js-test-style.css"/>
 <script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
 <script src="../../debug/webgl-debug.js"></script>
 <script src="../resources/js-test-pre.js"></script>
-<script src="../fast/resources/webgl-test.js"></script>
+<script src="../conformance/resources/webgl-test.js"></script>
 </head>
 <body>
 <div id="description"></div>
 <div id="console"></div>
 <canvas id="canvas" width="2" height="2"> </canvas>
 <canvas id="canvas2" width="2" height="2"> </canvas>
 <script>
-description("This test is to check what happens if a WebGL program tries to use all of vram.");
-
-debug("");
-debug("Canvas.getContext");
-
-var gl = create3DContext(document.getElementById("canvas"));
-if (!gl) {
-  testFailed("context does not exist");
-} else {
-  testPassed("context exists");
-
-  debug("");
-  debug("Checking for out of memory handling.");
-
-  var size = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
-  debug("max render buffer size: " + size);
-
-  var allocateFramebuffers = true;
-  var itervalId;
-  var count = 0;
-
-  gl = WebGLDebugUtils.makeDebugContext(gl, function(err, functionName, args) {
-        window.clearInterval(intervalId);
-        assertMsg(err == gl.OUT_OF_MEMORY,
-                  "correctly returns gl.OUT_OF_MEMORY when out of memory");
-        finish();
-      });
+window.onload = init;
+debug("Tests a WebGL program that tries to use all of vram.");
 
-  intervalId = window.setInterval(function() {
-    ++count;
-    var mem = count * size * size * 4;
-    debug("#" + count + " : memory allocated so far " + (mem / 1024 / 1024) + "MB");
-    var tex = gl.createTexture();
-    gl.bindTexture(gl.TEXTURE_2D, tex);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
-    gl.texImage2D(gl.TEXTURE_2D,
-                  0,                 // level
-                  gl.RGBA,           // internalFormat
-                  size,              // width
-                  size,              // height
-                  0,                 // border
-                  gl.RGBA,           // format
-                  gl.UNSIGNED_BYTE,  // type
-                  null);             // data
-    if (allocateFrameBuffers) {
-      var fb = gl.createFramebuffer();
-      gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
-      gl.framebufferTexture2D(
-          gl.FRAMEBUFFER,
-          gl.COLOR_ATTACHMENT0,
-          gl.TEXTURE_2D,
-          tex,
-          0);
-      var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
-      if (status != gl.FRAMEBUFFER_COMPLETE) {
-        testFailed("gl.checkFramebufferStatus() returned " + WebGLDebugUtils.glEnumToString(status) +
-                   " should have gotten gl.OUT_OF_MEMORY before getting this.");
-        window.clearInterval(intervalId);
-        finish();
-      }
-    }
-  }, 1000/10);
+function init() {
+  if (confirm(
+      "after clicking ok your machine may be come unresponsive or crash")) {
+    main();
+  } else {
+    debug("cancelled");
+  }
 }
 
-function finish() {
+function main() {
   debug("");
-  successfullyParsed = true;
-}
+  debug("Canvas.getContext");
+
+  var gl = create3DContext(document.getElementById("canvas"));
+  if (!gl) {
+    testFailed("context does not exist");
+  } else {
+    testPassed("context exists");
+
+    debug("");
+    debug("Checking for out of memory handling.");
+
+    var size = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
+    debug("max render buffer size: " + size);
+
+    var allocateFramebuffers = true;
+    var itervalId;
+    var count = 0;
+
+    gl = WebGLDebugUtils.makeDebugContext(gl, function(err, functionName, args) {
+          window.clearInterval(intervalId);
+          assertMsg(err == gl.OUT_OF_MEMORY,
+                    "correctly returns gl.OUT_OF_MEMORY when out of memory");
+          finish();
+        });
 
+    intervalId = window.setInterval(function() {
+      ++count;
+      var mem = count * size * size * 4;
+      debug("#" + count + " : memory allocated so far " + (mem / 1024 / 1024) + "MB");
+      var tex = gl.createTexture();
+      gl.bindTexture(gl.TEXTURE_2D, tex);
+      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+      gl.texImage2D(gl.TEXTURE_2D,
+                    0,                 // level
+                    gl.RGBA,           // internalFormat
+                    size,              // width
+                    size,              // height
+                    0,                 // border
+                    gl.RGBA,           // format
+                    gl.UNSIGNED_BYTE,  // type
+                    null);             // data
+      if (allocateFrameBuffers) {
+        var fb = gl.createFramebuffer();
+        gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+        gl.framebufferTexture2D(
+            gl.FRAMEBUFFER,
+            gl.COLOR_ATTACHMENT0,
+            gl.TEXTURE_2D,
+            tex,
+            0);
+        var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+        if (status != gl.FRAMEBUFFER_COMPLETE) {
+          testFailed("gl.checkFramebufferStatus() returned " + WebGLDebugUtils.glEnumToString(status) +
+                     " should have gotten gl.OUT_OF_MEMORY before getting this.");
+          window.clearInterval(intervalId);
+          finish();
+        }
+      }
+    }, 1000/10);
+  }
+
+  function finish() {
+    debug("");
+    successfullyParsed = true;
+  }
+}
 </script>
-<script>
-</script>
-
 </body>
 </html>
--- a/content/canvas/test/webgl/extra/slow-shader-example.html
+++ b/content/canvas/test/webgl/extra/slow-shader-example.html
@@ -23,16 +23,19 @@ precision mediump float;
 #endif
 uniform sampler2D tex;
 varying vec2 texCoord;
 void main() {
   gl_FragColor = texture2D(tex, texture2D(tex, texture2D(tex, texCoord).xy).xy);
 }
 </script>
 <script>
+window.onload = main;
+
+debug("Tests drawing a very slow shader.");
 var wtu = WebGLTestUtils;
 var canvas = document.getElementById("example");
 var gl = wtu.create3DContext(canvas);
 var texSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
 debug("Max Texture size: " + texSize);
 var shaderSource =
     document.getElementById("slow").text.replace(/\$size/g, texSize + ".0");
 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after getting a context");
@@ -88,24 +91,25 @@ for (var ii = 0; ii < numQuads; ++ii) {
   indices[offset + 3] = 3;
   indices[offset + 4] = 4;
   indices[offset + 5] = 5;
 }
 var indexBuffer = gl.createBuffer();
 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after setting up indices");
-alert("click to draw");
-gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_BYTE, 0);
-wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after drawing");
+
+function main () {
+  if (confirm(
+      "after clicking ok your machine may be come unresponsive or crash")) {
+    gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_BYTE, 0);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after drawing");
+  } else {
+    debug("cancelled");
+  }
+}
 
 successfullyParsed = true;
 </script>
 </body>
-<script src="../resources/js-test-post.js"></script>
-
-<script>
-</script>
-
-</body>
 </html>
 
 
--- a/content/canvas/test/webgl/more/util.js
+++ b/content/canvas/test/webgl/more/util.js
@@ -1225,17 +1225,17 @@ Sphere = {
     }
   }
 }
 
 Sphere.create();
 
 initGL_CONTEXT_ID = function(){
   var c = document.createElement('canvas');
-  var contextNames = ['experimental-webgl'];
+  var contextNames = ['webgl', 'experimental-webgl'];
   GL_CONTEXT_ID = null;
   for (var i=0; i<contextNames.length; i++) {
     try {
       if (c.getContext(contextNames[i])) {
         GL_CONTEXT_ID = contextNames[i];
         break;
       }
     } catch (e) {}
--- a/content/canvas/test/webgl/resources/js-test-pre.js
+++ b/content/canvas/test/webgl/resources/js-test-pre.js
@@ -85,21 +85,25 @@ function testPassed(msg)
 function testFailed(msg)
 {
     reportTestResultsToHarness(false, msg);
     debug('<span><span class="fail">FAIL</span> ' + escapeHTML(msg) + '</span>');
 }
 
 function areArraysEqual(_a, _b)
 {
-    if (_a.length !== _b.length)
+    try {
+        if (_a.length !== _b.length)
+            return false;
+        for (var i = 0; i < _a.length; i++)
+            if (_a[i] !== _b[i])
+                return false;
+    } catch (ex) {
         return false;
-    for (var i = 0; i < _a.length; i++)
-        if (_a[i] !== _b[i])
-            return false;
+    }
     return true;
 }
 
 function isMinusZero(n)
 {
     // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
     // -Infinity instead of Infinity
     return n === 0 && 1/n < 0;
@@ -134,16 +138,17 @@ function evalAndLog(_a)
   debug(_a);
 
   var _av;
   try {
      _av = eval(_a);
   } catch (e) {
     testFailed(_a + " threw exception " + e);
   }
+  return _av;
 }
 
 function shouldBe(_a, _b)
 {
   if (typeof _a != "string" || typeof _b != "string")
     debug("WARN: shouldBe() expects string arguments");
   var exception;
   var _av;
@@ -261,16 +266,54 @@ function shouldBeUndefined(_a)
   if (exception)
     testFailed(_a + " should be undefined. Threw exception " + exception);
   else if (typeof _av == "undefined")
     testPassed(_a + " is undefined.");
   else
     testFailed(_a + " should be undefined. Was " + _av);
 }
 
+function shouldBeDefined(_a)
+{
+  var exception;
+  var _av;
+  try {
+     _av = eval(_a);
+  } catch (e) {
+     exception = e;
+  }
+
+  if (exception)
+    testFailed(_a + " should be defined. Threw exception " + exception);
+  else if (_av !== undefined)
+    testPassed(_a + " is defined.");
+  else
+    testFailed(_a + " should be defined. Was " + _av);
+}
+
+function shouldBeGreaterThanOrEqual(_a, _b) {
+    if (typeof _a != "string" || typeof _b != "string")
+        debug("WARN: shouldBeGreaterThanOrEqual expects string arguments");
+
+    var exception;
+    var _av;
+    try {
+        _av = eval(_a);
+    } catch (e) {
+        exception = e;
+    }
+    var _bv = eval(_b);
+
+    if (exception)
+        testFailed(_a + " should be >= " + _b + ". Threw exception " + exception);
+    else if (typeof _av == "undefined" || _av < _bv)
+        testFailed(_a + " should be >= " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
+    else
+        testPassed(_a + " is >= " + _b);
+}
 
 function shouldThrow(_a, _e)
 {
   var exception;
   var _av;
   try {
      _av = eval(_a);
   } catch (e) {
--- a/content/canvas/test/webgl/webgl-conformance-tests.html
+++ b/content/canvas/test/webgl/webgl-conformance-tests.html
@@ -33,28 +33,22 @@ function start() {
 
   function create3DContext(canvas)
   {
     if (!canvas) {
       canvas = document.createElement("canvas");
     }
     var context = null;
     try {
-        context = canvas.getContext("experimental-webgl");
+        context = canvas.getContext("webgl");
     } catch(e) {
     }
-    if (!context) {
+		if (!context) {
       try {
-        context = canvas.getContext("webkit-3d");
-      } catch(e) {
-      }
-    }
-    if (!context) {
-      try {
-        context = canvas.getContext("moz-webgl");
+          context = canvas.getContext("experimental-webgl");
       } catch(e) {
       }
     }
     return context;
   }
 
   var reportType = WebGLTestHarnessModule.TestHarness.reportType;
 
@@ -236,17 +230,17 @@ function start() {
         break;
     };
   };
 
   var reporter = new Reporter();
   var iframe = document.getElementById("testframe");
   var testHarness = new WebGLTestHarnessModule.TestHarness(
       iframe,
-      '00_testFIXME_list.txt',
+      '00_test_list.txt',
       function(type, msg, success) {
         return reporter.reportFunc(type, msg, success);
       });
   window.webglTestHarness = testHarness;
   var button = document.getElementById("runTestsButton");
   button.onclick = function() {
     testHarness.runTests();
   };
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -3822,50 +3822,55 @@ nsEventStateManager::GenerateDragDropEnt
                                                nsGUIEvent* aEvent)
 {
   //Hold onto old target content through the event and reset after.
   nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
 
   switch(aEvent->message) {
   case NS_DRAGDROP_OVER:
     {
+      // when dragging from one frame to another, events are fired in the
+      // order: dragexit, dragenter, dragleave
       if (mLastDragOverFrame != mCurrentTarget) {
         //We'll need the content, too, to check if it changed separately from the frames.
         nsCOMPtr<nsIContent> lastContent;
         nsCOMPtr<nsIContent> targetContent;
         mCurrentTarget->GetContentForEvent(aPresContext, aEvent, getter_AddRefs(targetContent));
 
         if (mLastDragOverFrame) {
           //The frame has changed but the content may not have. Check before dispatching to content
           mLastDragOverFrame->GetContentForEvent(aPresContext, aEvent, getter_AddRefs(lastContent));
 
-          FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_LEAVE_SYNTH,
-                              targetContent, lastContent, mLastDragOverFrame);
           FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_EXIT_SYNTH,
                               targetContent, lastContent, mLastDragOverFrame);
         }
 
         FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_ENTER,
                             lastContent, targetContent, mCurrentTarget);
 
+        if (mLastDragOverFrame) {
+          FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_LEAVE_SYNTH,
+                              targetContent, lastContent, mLastDragOverFrame);
+        }
+
         mLastDragOverFrame = mCurrentTarget;
       }
     }
     break;
 
   case NS_DRAGDROP_EXIT:
     {
       //This is actually the window mouse exit event.
       if (mLastDragOverFrame) {
         nsCOMPtr<nsIContent> lastContent;
         mLastDragOverFrame->GetContentForEvent(aPresContext, aEvent, getter_AddRefs(lastContent));
 
-        FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_LEAVE_SYNTH,
+        FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_EXIT_SYNTH,
                             nsnull, lastContent, mLastDragOverFrame);
-        FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_EXIT_SYNTH,
+        FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_LEAVE_SYNTH,
                             nsnull, lastContent, mLastDragOverFrame);
 
         mLastDragOverFrame = nsnull;
       }
     }
     break;
   }
 
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -1624,18 +1624,18 @@ nsGenericHTMLElement::ParseScrollingValu
 {
   return aResult.ParseEnumValue(aString, kScrollingTable, PR_FALSE);
 }
 
 /**
  * Handle attributes common to all html elements
  */
 void
-nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttributes,
-                                              nsRuleData* aData)
+nsGenericHTMLElement::MapCommonAttributesExceptHiddenInto(const nsMappedAttributes* aAttributes,
+                                                          nsRuleData* aData)
 {
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(UserInterface)) {
     nsRuleDataUserInterface *ui = aData->mUserInterfaceData;
     if (ui->mUserModify.GetUnit() == eCSSUnit_Null) {
       const nsAttrValue* value =
         aAttributes->GetAttr(nsGkAtoms::contenteditable);
       if (value) {
         if (value->Equals(nsGkAtoms::_empty, eCaseMatters) ||
@@ -1653,16 +1653,23 @@ nsGenericHTMLElement::MapCommonAttribute
 
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Visibility)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::lang);
     if (value && value->Type() == nsAttrValue::eString) {
       aData->mDisplayData->mLang.SetStringValue(value->GetStringValue(),
                                                 eCSSUnit_Ident);
     }
   }
+}
+
+void
+nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttributes,
+                                              nsRuleData* aData)
+{
+  nsGenericHTMLElement::MapCommonAttributesExceptHiddenInto(aAttributes, aData);
 
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
     nsRuleDataDisplay* disp = aData->mDisplayData;
     if (disp->mDisplay.GetUnit() == eCSSUnit_Null) {
       if (aAttributes->IndexOfAttr(nsGkAtoms::hidden, kNameSpaceID_None) >= 0) {
         disp->mDisplay.SetIntValue(NS_STYLE_DISPLAY_NONE, eCSSUnit_Enumerated);
       }
     }
@@ -1945,26 +1952,25 @@ nsGenericHTMLElement::MapBackgroundInto(
         nsIDocument* doc = presContext->Document();
         nsCOMPtr<nsIURI> uri;
         nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
             getter_AddRefs(uri), spec, doc, doc->GetDocBaseURI());
         if (NS_SUCCEEDED(rv)) {
           // Note that this should generally succeed here, due to the way
           // |spec| is created.  Maybe we should just add an nsStringBuffer
           // accessor on nsAttrValue?
-          nsStringBuffer* buffer = nsCSSValue::BufferFromString(spec);
-          if (NS_LIKELY(buffer != 0)) {
+          nsRefPtr<nsStringBuffer> buffer = nsCSSValue::BufferFromString(spec);
+          if (NS_LIKELY(buffer)) {
             // XXXbz it would be nice to assert that doc->NodePrincipal() is
             // the same as the principal of the node (which we'd need to store
             // in the mapped attrs or something?)
             nsCSSValue::Image *img =
               new nsCSSValue::Image(uri, buffer, doc->GetDocumentURI(),
                                     doc->NodePrincipal(), doc);
-            buffer->Release();
-            if (NS_LIKELY(img != 0)) {
+            if (NS_LIKELY(img)) {
               nsCSSValueList* list =
                 aData->mColorData->mBackImage.SetListValue();
               list->mValue.SetImageValue(img);
             }
           }
         }
       }
       else if (presContext->CompatibilityMode() == eCompatibility_NavQuirks) {
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -326,16 +326,25 @@ public:
    * dir and lang, could handle others.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapCommonAttributesInto(const nsMappedAttributes* aAttributes, 
                                       nsRuleData* aRuleData);
+
+  /**
+   * This method is used by embed elements because they should ignore the hidden
+   * attribute for the moment.
+   * TODO: This should be removed when bug 614825 will be fixed.
+   */
+  static void MapCommonAttributesExceptHiddenInto(const nsMappedAttributes* aAttributes,
+                                                  nsRuleData* aRuleData);
+
   static const MappedAttributeEntry sCommonAttributeMap[];
   static const MappedAttributeEntry sImageMarginSizeAttributeMap[];
   static const MappedAttributeEntry sImageBorderAttributeMap[];
   static const MappedAttributeEntry sImageAlignAttributeMap[];
   static const MappedAttributeEntry sDivAlignAttributeMap[];
   static const MappedAttributeEntry sBackgroundAttributeMap[];
   static const MappedAttributeEntry sBackgroundColorAttributeMap[];
   static const MappedAttributeEntry sScrollingAttributeMap[];
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -438,18 +438,18 @@ AsyncClickHandler::Run()
   // Set new selected files
   if (newFiles.Count()) {
     // The text control frame (if there is one) isn't going to send a change
     // event because it will think this is done by a script.
     // So, we can safely send one by ourself.
     mInput->SetFiles(newFiles, true);
     nsContentUtils::DispatchTrustedEvent(mInput->GetOwnerDoc(),
                                          static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
-                                         NS_LITERAL_STRING("change"), PR_FALSE,
-                                         PR_FALSE);
+                                         NS_LITERAL_STRING("change"), PR_TRUE,
+                                         PR_TRUE);
   }
 
   return NS_OK;
 }
 
 #define CPS_PREF_NAME NS_LITERAL_STRING("browser.upload.lastDir")
 
 NS_IMPL_ISUPPORTS2(UploadLastDir, nsIObserver, nsISupportsWeakReference)
--- a/content/html/content/src/nsHTMLSharedObjectElement.cpp
+++ b/content/html/content/src/nsHTMLSharedObjectElement.cpp
@@ -415,16 +415,31 @@ MapAttributesIntoRule(const nsMappedAttr
 {
   nsGenericHTMLElement::MapImageBorderAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
   nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
+static void
+EmbedMapAttributesIntoRule(const nsMappedAttributes *aAttributes,
+                           nsRuleData *aData)
+{
+  // NOTE: this should call the exact some methods than MapAttributesIntoRule
+  // except that MapCommonAttributesExceptHiddenInto is called instead of
+  // MapCommonAttributesInto.
+  // TODO: This method should be removed when bug 614825 will be fixed.
+  nsGenericHTMLElement::MapImageBorderAttributeInto(aAttributes, aData);
+  nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aData);
+  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData);
+  nsGenericHTMLElement::MapCommonAttributesExceptHiddenInto(aAttributes, aData);
+}
+
 NS_IMETHODIMP_(PRBool)
 nsHTMLSharedObjectElement::IsAttributeMapped(const nsIAtom *aAttribute) const
 {
   static const MappedAttributeEntry* const map[] = {
     sCommonAttributeMap,
     sImageMarginSizeAttributeMap,
     sImageBorderAttributeMap,
     sImageAlignAttributeMap,
@@ -432,16 +447,20 @@ nsHTMLSharedObjectElement::IsAttributeMa
 
   return FindAttributeDependence(aAttribute, map, NS_ARRAY_LENGTH(map));
 }
 
 
 nsMapRuleToAttributesFunc
 nsHTMLSharedObjectElement::GetAttributeMappingFunction() const
 {
+  if (mNodeInfo->Equals(nsGkAtoms::embed)) {
+    return &EmbedMapAttributesIntoRule;
+  }
+
   return &MapAttributesIntoRule;
 }
 
 void
 nsHTMLSharedObjectElement::StartObjectLoad(PRBool aNotify)
 {
   nsCAutoString type;
   GetTypeAttrValue(type);
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -244,12 +244,13 @@ include $(topsrcdir)/config/rules.mk
 		reflect.js \
 		test_bug611189.html \
 		test_bug613113.html \
 		test_bug605124-1.html \
 		test_bug605124-2.html \
 		test_bug605125-1.html \
 		test_bug605125-2.html \
 		test_bug612730.html \
+		test_bug613722.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
--- a/content/html/content/test/test_bug592802.html
+++ b/content/html/content/test/test_bug592802.html
@@ -180,16 +180,18 @@ SimpleTest.waitForFocus(function() {
   synthesizeMouse(b2, 2, 2, {});
 
   // Now, we can launch tests when file picker isn't canceled.
   var b = document.getElementById('b');
   b.focus(); // Be sure the element is visible.
 
   document.getElementById('a').addEventListener("change", function(aEvent) {
     ok(true, "change event correctly sent");
+    ok(aEvent.bubbles, "change event should bubble");
+    todo(!aEvent.cancelable, "change event should not be cancelable");
     testCounter++;
 
     if (testCounter >= testNb) {
       aEvent.target.removeEventListener("change", arguments.callee, false);
       SimpleTest.executeSoon(finished);
     } else {
       var data = testData[testCounter];
       var a = document.getElementById('a');
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug613722.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=613722
+-->
+<head>
+  <title>Test for Bug 613722</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613722">Mozilla Bug 613722</a>
+<p id="display"></p>
+<div id="content">
+  <embed src="test_plugin.tst" hidden>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 613722 **/
+
+/**
+ * TODO: this test should be removed when bug 614825 will be fixed.
+ */
+
+var rect = document.getElementsByTagName('embed')[0].getBoundingClientRect();
+
+var hasFrame = rect.left != 0 || rect.right != 0 || rect.top != 0 ||
+               rect.bottom != 0;
+
+ok(hasFrame, "embed should have a frame with hidden set");
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_plugin.tst
@@ -0,0 +1,1 @@
+foobar
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -2971,17 +2971,17 @@ public:
   DeferredContentEditableCountChangeEvent(nsHTMLDocument *aDoc,
                                           nsIContent *aElement)
     : mDoc(aDoc)
     , mElement(aElement)
   {
   }
 
   NS_IMETHOD Run() {
-    if (mElement->GetOwnerDoc() == mDoc) {
+    if (mElement && mElement->GetOwnerDoc() == mDoc) {
       mDoc->DeferredContentEditableCountChange(mElement);
     }
     return NS_OK;
   }
 
 private:
   nsRefPtr<nsHTMLDocument> mDoc;
   nsCOMPtr<nsIContent> mElement;
--- a/content/html/document/src/nsHTMLFragmentContentSink.cpp
+++ b/content/html/document/src/nsHTMLFragmentContentSink.cpp
@@ -808,18 +808,19 @@ public:
 
 protected:
   nsresult NameFromType(const nsHTMLTag aTag,
                         nsIAtom **aResult);
 
   nsresult NameFromNode(const nsIParserNode& aNode,
                         nsIAtom **aResult);
 
-  void SanitizeStyleRule(nsICSSStyleRule *aRule, nsAutoString &aRuleText);
-  
+  // The return value will be true if we have sanitized the rule
+  PRBool SanitizeStyleRule(nsICSSStyleRule *aRule, nsAutoString &aRuleText);
+
   PRPackedBool mSkip; // used when we descend into <style> or <script>
   PRPackedBool mProcessStyle; // used when style is explicitly white-listed
   PRPackedBool mInStyle; // whether we're inside a style element
   PRPackedBool mProcessComments; // used when comments are allowed
 
   // Use nsTHashTable as a hash set for our whitelists
   static nsTHashtable<nsISupportsHashKey>* sAllowedTags;
   static nsTHashtable<nsISupportsHashKey>* sAllowedAttributes;
@@ -1043,18 +1044,22 @@ nsHTMLParanoidFragmentSink::AddAttribute
       nsCOMPtr<nsICSSStyleRule> rule;
       rv = parser.ParseStyleAttribute(aNode.GetValueAt(i),
                                       mTargetDocument->GetDocumentURI(),
                                       baseURI,
                                       mTargetDocument->NodePrincipal(),
                                       getter_AddRefs(rule));
       if (NS_SUCCEEDED(rv)) {
         nsAutoString cleanValue;
-        SanitizeStyleRule(rule, cleanValue);
-        aContent->SetAttr(kNameSpaceID_None, keyAtom, cleanValue, PR_FALSE);
+        PRBool didSanitize = SanitizeStyleRule(rule, cleanValue);
+        if (didSanitize) {
+          aContent->SetAttr(kNameSpaceID_None, keyAtom, cleanValue, PR_FALSE);
+        } else {
+          aContent->SetAttr(kNameSpaceID_None, keyAtom, v, PR_FALSE);
+        }
       } else {
         // we couldn't sanitize the style attribute, ignore it
         continue;
       }
     } else if (nodeType == eHTMLTag_a && keyAtom == nsGkAtoms::name) {
       NS_ConvertUTF16toUTF8 cname(v);
       NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting()));
       // Add attribute to content
@@ -1134,16 +1139,17 @@ nsHTMLParanoidFragmentSink::CloseContain
 
     // sanitizedStyleText will hold the permitted CSS text.
     // We use a white-listing approach, so we explicitly allow
     // the CSS style and font-face rule types.  We also clear
     // -moz-binding CSS properties.
     nsAutoString sanitizedStyleText;
     nsIContent* style = GetCurrentContent();
     if (style) {
+      PRBool didSanitize = PR_FALSE;
       // styleText will hold the text inside the style element.
       nsAutoString styleText;
       nsContentUtils::GetNodeTextContent(style, PR_FALSE, styleText);
       // Create a unichar input stream for the CSS parser.
       nsCOMPtr<nsIUnicharInputStream> uin;
       rv = nsSimpleUnicharStreamFactory::GetInstance()->
         CreateInstanceFromString(styleText, getter_AddRefs(uin));
       if (NS_SUCCEEDED(rv)) {
@@ -1174,16 +1180,17 @@ nsHTMLParanoidFragmentSink::CloseContain
                 continue;
               NS_ASSERTION(rule, "We should have a rule by now");
               switch (rule->GetType()) {
                 case nsICSSRule::UNKNOWN_RULE:
                 case nsICSSRule::CHARSET_RULE:
                 case nsICSSRule::IMPORT_RULE:
                 case nsICSSRule::MEDIA_RULE:
                 case nsICSSRule::PAGE_RULE:
+                  didSanitize = PR_TRUE;
                   // Ignore these rule types.
                   break;
                 case nsICSSRule::NAMESPACE_RULE:
                 case nsICSSRule::FONT_FACE_RULE: {
                   // Append @namespace and @font-face rules verbatim.
                   nsAutoString cssText;
                   nsCOMPtr<nsIDOMCSSRule> styleRule = do_QueryInterface(rule);
                   if (styleRule) {
@@ -1195,45 +1202,50 @@ nsHTMLParanoidFragmentSink::CloseContain
                   break;
                 }
                 case nsICSSRule::STYLE_RULE: {
                   // For style rules, we will just look for and remove the
                   // -moz-binding properties.
                   nsCOMPtr<nsICSSStyleRule> styleRule = do_QueryInterface(rule);
                   NS_ASSERTION(styleRule, "Must be a style rule");
                   nsAutoString decl;
-                  SanitizeStyleRule(styleRule, decl);
+                  didSanitize = SanitizeStyleRule(styleRule, decl) || didSanitize;
                   rv = styleRule->GetCssText(decl);
                   // Only add the rule when sanitized.
                   if (NS_SUCCEEDED(rv)) {
                     sanitizedStyleText.Append(decl);
                   }
                 }
               }
             }
           }
         }
       }
-      // Replace the style element content with its sanitized style text
-      nsContentUtils::SetNodeTextContent(style, sanitizedStyleText, PR_TRUE);
+      if (didSanitize) {
+        // Replace the style element content with its sanitized style text
+        nsContentUtils::SetNodeTextContent(style, sanitizedStyleText, PR_TRUE);
+      }
     }
   }
 
   return nsHTMLFragmentContentSink::CloseContainer(aTag);
 }
 
-void
+PRBool
 nsHTMLParanoidFragmentSink::SanitizeStyleRule(nsICSSStyleRule *aRule, nsAutoString &aRuleText)
 {
+  PRBool didSanitize = PR_FALSE;
   aRuleText.Truncate();
   css::Declaration *style = aRule->GetDeclaration();
   if (style) {
+    didSanitize = style->HasProperty(eCSSProperty_binding);
     style->RemoveProperty(eCSSProperty_binding);
     style->ToString(aRuleText);
   }
+  return didSanitize;
 }
 
 NS_IMETHODIMP
 nsHTMLParanoidFragmentSink::AddLeaf(const nsIParserNode& aNode)
 {
   NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_NOT_INITIALIZED);
   
   nsresult rv = NS_OK;
--- a/content/html/document/src/nsImageDocument.cpp
+++ b/content/html/document/src/nsImageDocument.cpp
@@ -265,17 +265,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mImageContent)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ADDREF_INHERITED(nsImageDocument, nsMediaDocument)
 NS_IMPL_RELEASE_INHERITED(nsImageDocument, nsMediaDocument)
 
 DOMCI_NODE_DATA(ImageDocument, nsImageDocument)
 
-NS_INTERFACE_TABLE_HEAD(nsImageDocument)
+NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsImageDocument)
   NS_HTML_DOCUMENT_INTERFACE_TABLE_BEGIN(nsImageDocument)
     NS_INTERFACE_TABLE_ENTRY(nsImageDocument, nsIImageDocument)
     NS_INTERFACE_TABLE_ENTRY(nsImageDocument, imgIDecoderObserver)
     NS_INTERFACE_TABLE_ENTRY(nsImageDocument, imgIContainerObserver)
     NS_INTERFACE_TABLE_ENTRY(nsImageDocument, nsIDOMEventListener)
   NS_OFFSET_AND_INTERFACE_TABLE_END
   NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ImageDocument)
--- a/content/html/document/src/nsPluginDocument.cpp
+++ b/content/html/document/src/nsPluginDocument.cpp
@@ -184,18 +184,22 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsPluginD
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsPluginDocument, nsMediaDocument)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPluginContent)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsPluginDocument, nsMediaDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPluginContent)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-NS_IMPL_ISUPPORTS_INHERITED1(nsPluginDocument, nsMediaDocument,
-                             nsIPluginDocument)
+NS_IMPL_ADDREF_INHERITED(nsPluginDocument, nsMediaDocument)
+NS_IMPL_RELEASE_INHERITED(nsPluginDocument, nsMediaDocument)
+
+NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsPluginDocument)
+  NS_INTERFACE_TABLE_INHERITED1(nsPluginDocument, nsIPluginDocument)
+NS_INTERFACE_TABLE_TAIL_INHERITING(nsMediaDocument)
 
 void
 nsPluginDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
 {
   // Set the script global object on the superclass before doing
   // anything that might require it....
   nsMediaDocument::SetScriptGlobalObject(aScriptGlobalObject);
 
--- a/content/media/nsMediaCache.cpp
+++ b/content/media/nsMediaCache.cpp
@@ -614,17 +614,17 @@ nsMediaCache::Flush()
   gMediaCache->FlushInternal();
 }
 
 void
 nsMediaCache::FlushInternal()
 {
   nsAutoMonitor mon(mMonitor);
 
-  for (PRInt32 blockIndex = 0; blockIndex < mIndex.Length(); ++blockIndex) {
+  for (PRUint32 blockIndex = 0; blockIndex < mIndex.Length(); ++blockIndex) {
     FreeBlock(blockIndex);
   }
 
   // Truncate file, close it, and reopen
   Truncate();
   NS_ASSERTION(mIndex.Length() == 0, "Blocks leaked?");
   if (mFD) {
     PR_Close(mFD);
--- a/content/smil/nsSMILAnimationFunction.cpp
+++ b/content/smil/nsSMILAnimationFunction.cpp
@@ -251,19 +251,19 @@ nsSMILAnimationFunction::ComposeResult(c
   // animation function in the sandwich that should replace it but that function
   // failed unexpectedly.
   PRBool isAdditive = IsAdditive();
   if (isAdditive && aResult.IsNull())
     return;
 
   nsSMILValue result;
 
-  if (mSimpleDuration.IsIndefinite() ||
-      (values.Length() == 1 && TreatSingleValueAsStatic())) {
-    // Indefinite duration or only one value set: Always set the first value
+  if (values.Length() == 1 && !IsToAnimation()) {
+
+    // Single-valued animation
     result = values[0];
 
   } else if (mLastValue) {
 
     // Sampling last value
     const nsSMILValue& last = values[values.Length() - 1];
     result = last;
 
@@ -374,38 +374,47 @@ nsSMILAnimationFunction::UpdateCachedTar
 //----------------------------------------------------------------------
 // Implementation helpers
 
 nsresult
 nsSMILAnimationFunction::InterpolateResult(const nsSMILValueArray& aValues,
                                            nsSMILValue& aResult,
                                            nsSMILValue& aBaseValue)
 {
-  nsresult rv = NS_OK;
-  const nsSMILTime& dur = mSimpleDuration.GetMillis();
-
-  // Sanity Checks
-  NS_ABORT_IF_FALSE(mSampleTime >= 0.0f, "Sample time should not be negative");
-  NS_ABORT_IF_FALSE(dur >= 0.0f, "Simple duration should not be negative");
-
-  if (mSampleTime >= dur || mSampleTime < 0.0f) {
-    NS_ERROR("Animation sampled outside interval");
-    return NS_ERROR_FAILURE;
-  }
-
+  // Sanity check animation values
   if ((!IsToAnimation() && aValues.Length() < 2) ||
       (IsToAnimation()  && aValues.Length() != 1)) {
     NS_ERROR("Unexpected number of values");
     return NS_ERROR_FAILURE;
   }
-  // End Sanity Checks
+
+  // Get the normalised progress through the simple duration.
+  //
+  // If we have an indefinite simple duration, just set the progress to be
+  // 0 which will give us the expected behaviour of the animation being fixed at
+  // its starting point.
+  double simpleProgress = 0.0;
+
+  if (mSimpleDuration.IsResolved()) {
+    nsSMILTime dur = mSimpleDuration.GetMillis();
 
-  // Get the normalised progress through the simple duration
-  const double simpleProgress = dur > 0.0 ? (double)mSampleTime / dur : 0.0;
+    NS_ABORT_IF_FALSE(dur >= 0, "Simple duration should not be negative");
+    NS_ABORT_IF_FALSE(mSampleTime >= 0, "Sample time should not be negative");
 
+    if (mSampleTime >= dur || mSampleTime < 0) {
+      NS_ERROR("Animation sampled outside interval");
+      return NS_ERROR_FAILURE;
+    }
+
+    if (dur > 0) {
+      simpleProgress = (double)mSampleTime / dur;
+    } // else leave simpleProgress at 0.0 (e.g. if mSampleTime == dur == 0)
+  }
+
+  nsresult rv = NS_OK;
   nsSMILCalcMode calcMode = GetCalcMode();
   if (calcMode != CALC_DISCRETE) {
     // Get the normalised progress between adjacent values
     const nsSMILValue* from = nsnull;
     const nsSMILValue* to = nsnull;
     // Init to -1 to make sure that if we ever forget to set this, the
     // NS_ABORT_IF_FALSE that tests that intervalProgress is in range will fail.
     double intervalProgress = -1.f;
@@ -419,36 +428,35 @@ nsSMILAnimationFunction::InterpolateResu
           // Note: key[Times/Splines/Points] are ignored for calcMode="paced"
           intervalProgress = simpleProgress;
         } else {
           double scaledSimpleProgress =
             ScaleSimpleProgress(simpleProgress, calcMode);
           intervalProgress = ScaleIntervalProgress(scaledSimpleProgress, 0);
         }
       }
-    } else {
-      if (calcMode == CALC_PACED) {
-        rv = ComputePacedPosition(aValues, simpleProgress,
-                                  intervalProgress, from, to);
-        // Note: If the above call fails, we'll skip the "from->Interpolate"
-        // call below, and we'll drop into the CALC_DISCRETE section
-        // instead. (as the spec says we should, because our failure was
-        // presumably due to the values being non-additive)
-      } else { // calcMode == CALC_LINEAR or calcMode == CALC_SPLINE
-        double scaledSimpleProgress =
-          ScaleSimpleProgress(simpleProgress, calcMode);
-        PRUint32 index = (PRUint32)floor(scaledSimpleProgress *
-                                         (aValues.Length() - 1));
-        from = &aValues[index];
-        to = &aValues[index + 1];
-        intervalProgress =
-          scaledSimpleProgress * (aValues.Length() - 1) - index;
-        intervalProgress = ScaleIntervalProgress(intervalProgress, index);
-      }
+    } else if (calcMode == CALC_PACED) {
+      rv = ComputePacedPosition(aValues, simpleProgress,
+                                intervalProgress, from, to);
+      // Note: If the above call fails, we'll skip the "from->Interpolate"
+      // call below, and we'll drop into the CALC_DISCRETE section
+      // instead. (as the spec says we should, because our failure was
+      // presumably due to the values being non-additive)
+    } else { // calcMode == CALC_LINEAR or calcMode == CALC_SPLINE
+      double scaledSimpleProgress =
+        ScaleSimpleProgress(simpleProgress, calcMode);
+      PRUint32 index = (PRUint32)floor(scaledSimpleProgress *
+                                       (aValues.Length() - 1));
+      from = &aValues[index];
+      to = &aValues[index + 1];
+      intervalProgress =
+        scaledSimpleProgress * (aValues.Length() - 1) - index;
+      intervalProgress = ScaleIntervalProgress(intervalProgress, index);
     }
+
     if (NS_SUCCEEDED(rv)) {
       NS_ABORT_IF_FALSE(from, "NULL from-value during interpolation");
       NS_ABORT_IF_FALSE(to, "NULL to-value during interpolation");
       NS_ABORT_IF_FALSE(0.0f <= intervalProgress && intervalProgress < 1.0f,
                       "Interval progress should be in the range [0, 1)");
       rv = from->Interpolate(*to, intervalProgress, aResult);
     }
   }
@@ -538,17 +546,21 @@ nsSMILAnimationFunction::ComputePacedPos
   // interval-distances in an array, but maybe that's excessive.
   for (PRUint32 i = 0; i < aValues.Length() - 1; i++) {
     // Note: The following assertion is valid because remainingDist should
     // start out non-negative, and this loop never shaves off more than its
     // current value.
     NS_ASSERTION(remainingDist >= 0, "distance values must be non-negative");
 
     double curIntervalDist;
-    nsresult rv = aValues[i].ComputeDistance(aValues[i+1], curIntervalDist);
+
+#ifdef DEBUG
+    nsresult rv =
+#endif
+      aValues[i].ComputeDistance(aValues[i+1], curIntervalDist);
     NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv),
                       "If we got through ComputePacedTotalDistance, we should "
                       "be able to recompute each sub-distance without errors");
 
     NS_ASSERTION(curIntervalDist >= 0, "distance values must be non-negative");
     // Clamp distance value at 0, just in case ComputeDistance is evil.
     curIntervalDist = NS_MAX(curIntervalDist, 0.0);
 
--- a/content/smil/nsSMILAnimationFunction.h
+++ b/content/smil/nsSMILAnimationFunction.h
@@ -333,24 +333,17 @@ protected:
 
   virtual nsresult GetValues(const nsISMILAttr& aSMILAttr,
                              nsSMILValueArray& aResult);
 
   virtual void CheckValueListDependentAttrs(PRUint32 aNumValues);
   void         CheckKeyTimes(PRUint32 aNumValues);
   void         CheckKeySplines(PRUint32 aNumValues);
 
-  // When GetValues() returns a single-value array, this method indicates
-  // whether that single value can be understood to be a static value, to be
-  // set for the full animation duration.
-  virtual PRBool TreatSingleValueAsStatic() const {
-    return HasAttr(nsGkAtoms::values);
-  }
-
-  inline PRBool IsToAnimation() const {
+  virtual PRBool IsToAnimation() const {
     return !HasAttr(nsGkAtoms::values) &&
             HasAttr(nsGkAtoms::to) &&
            !HasAttr(nsGkAtoms::from);
   }
 
   inline PRBool IsAdditive() const {
     /*
      * Animation is additive if:
--- a/content/smil/nsSMILMappedAttribute.cpp
+++ b/content/smil/nsSMILMappedAttribute.cpp
@@ -121,17 +121,18 @@ nsSMILMappedAttribute::SetAnimValue(cons
   // Convert nsSMILValue to string
   nsAutoString valStr;
   if (!nsSMILCSSValueType::ValueToString(aValue, valStr)) {
     NS_WARNING("Failed to convert nsSMILValue for mapped attr into a string");
     return NS_ERROR_FAILURE;
   }
 
   // Set the string as this mapped attribute's animated value.
-  nsStringBuffer* valStrBuf = nsCSSValue::BufferFromString(nsString(valStr));
+  nsStringBuffer* valStrBuf =
+    nsCSSValue::BufferFromString(nsString(valStr)).get();
   nsRefPtr<nsIAtom> attrName = GetAttrNameAtom();
   nsresult rv = mElement->SetProperty(SMIL_MAPPED_ATTR_ANIMVAL,
                                       attrName, valStrBuf,
                                       ReleaseStringBufferPropertyValue);
   if (rv == NS_PROPTABLE_PROP_OVERWRITTEN) {
     rv = NS_OK;
   }
   FlushChangesToTargetAttr();
--- a/content/smil/nsSMILSetAnimationFunction.h
+++ b/content/smil/nsSMILSetAnimationFunction.h
@@ -69,21 +69,22 @@ public:
    * Unsets the given attribute.
    *
    * @returns PR_TRUE if aAttribute is a recognized animation-related
    *          attribute; PR_FALSE otherwise.
    */
   NS_OVERRIDE virtual PRBool UnsetAttr(nsIAtom* aAttribute);
 
 protected:
-  // <set> uses the "to" attribute as its only source of animation values
-  // (which gives us a single value in our values array), and we want to use
-  // that value whenever the animation is active (no interpolation or anything).
-  NS_OVERRIDE virtual PRBool TreatSingleValueAsStatic() const {
-    return PR_TRUE;
+  // Although <set> animation might look like to-animation, unlike to-animation,
+  // it never interpolates values.
+  // Returning PR_FALSE here will mean this animation function gets treated as
+  // a single-valued function and no interpolation will be attempted.
+  NS_OVERRIDE virtual PRBool IsToAnimation() const {
+    return PR_FALSE;
   }
   NS_OVERRIDE virtual PRBool             HasAttr(nsIAtom* aAttName) const;
   NS_OVERRIDE virtual const nsAttrValue* GetAttr(nsIAtom* aAttName) const;
   NS_OVERRIDE virtual PRBool             GetAttr(nsIAtom* aAttName,
                                                  nsAString& aResult) const;
   NS_OVERRIDE virtual PRBool WillReplace() const;
 
   PRBool IsDisallowedAttribute(const nsIAtom* aAttribute) const;
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGAnimatedNumberList.cpp
@@ -0,0 +1,160 @@
+/* -*- 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 SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "DOMSVGAnimatedNumberList.h"
+#include "DOMSVGNumberList.h"
+#include "SVGAnimatedNumberList.h"
+#include "nsSVGElement.h"
+#include "nsCOMPtr.h"
+#include "nsSVGAttrTearoffTable.h"
+
+// See the architecture comment in this file's header.
+
+using namespace mozilla;
+
+static nsSVGAttrTearoffTable<SVGAnimatedNumberList, DOMSVGAnimatedNumberList>
+  sSVGAnimatedNumberListTearoffTable;
+
+NS_SVG_VAL_IMPL_CYCLE_COLLECTION(DOMSVGAnimatedNumberList, mElement)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGAnimatedNumberList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGAnimatedNumberList)
+
+DOMCI_DATA(SVGAnimatedNumberList, DOMSVGAnimatedNumberList)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGAnimatedNumberList)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedNumberList)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedNumberList)
+NS_INTERFACE_MAP_END
+
+NS_IMETHODIMP
+DOMSVGAnimatedNumberList::GetBaseVal(nsIDOMSVGNumberList **_retval)
+{
+  if (!mBaseVal) {
+    mBaseVal = new DOMSVGNumberList(this, InternalAList().GetBaseValue());
+  }
+  NS_ADDREF(*_retval = mBaseVal);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGAnimatedNumberList::GetAnimVal(nsIDOMSVGNumberList **_retval)
+{
+  if (!mAnimVal) {
+    mAnimVal = new DOMSVGNumberList(this, InternalAList().GetAnimValue());
+  }
+  NS_ADDREF(*_retval = mAnimVal);
+  return NS_OK;
+}
+
+/* static */ already_AddRefed<DOMSVGAnimatedNumberList>
+DOMSVGAnimatedNumberList::GetDOMWrapper(SVGAnimatedNumberList *aList,
+                                        nsSVGElement *aElement,
+                                        PRUint8 aAttrEnum)
+{
+  DOMSVGAnimatedNumberList *wrapper =
+    sSVGAnimatedNumberListTearoffTable.GetTearoff(aList);
+  if (!wrapper) {
+    wrapper = new DOMSVGAnimatedNumberList(aElement, aAttrEnum);
+    sSVGAnimatedNumberListTearoffTable.AddTearoff(aList, wrapper);
+  }
+  NS_ADDREF(wrapper);
+  return wrapper;
+}
+
+/* static */ DOMSVGAnimatedNumberList*
+DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(SVGAnimatedNumberList *aList)
+{
+  return sSVGAnimatedNumberListTearoffTable.GetTearoff(aList);
+}
+
+DOMSVGAnimatedNumberList::~DOMSVGAnimatedNumberList()
+{
+  // Script no longer has any references to us, to our base/animVal objects, or
+  // to any of their list items.
+  sSVGAnimatedNumberListTearoffTable.RemoveTearoff(&InternalAList());
+}
+
+void
+DOMSVGAnimatedNumberList::InternalBaseValListWillChangeTo(const SVGNumberList& aNewValue)
+{
+  // When the number of items in our internal counterpart's baseVal changes,
+  // we MUST keep our baseVal in sync. If we don't, script will either see a
+  // list that is too short and be unable to access indexes that should be
+  // valid, or else, MUCH WORSE, script will see a list that is too long and be
+  // able to access "items" at indexes that are out of bounds (read/write to
+  // bad memory)!!
+
+  if (mBaseVal) {
+    mBaseVal->InternalListLengthWillChange(aNewValue.Length());
+  }
+
+  // If our attribute is not animating, then our animVal mirrors our baseVal
+  // and we must sync its length too. (If our attribute is animating, then the
+  // SMIL engine takes care of calling InternalAnimValListWillChangeTo() if
+  // necessary.)
+
+  if (!IsAnimating()) {
+    InternalAnimValListWillChangeTo(aNewValue);
+  }
+}
+
+void
+DOMSVGAnimatedNumberList::InternalAnimValListWillChangeTo(const SVGNumberList& aNewValue)
+{
+  if (mAnimVal) {
+    mAnimVal->InternalListLengthWillChange(aNewValue.Length());
+  }
+}
+
+PRBool
+DOMSVGAnimatedNumberList::IsAnimating() const
+{
+  return InternalAList().IsAnimating();
+}
+
+SVGAnimatedNumberList&
+DOMSVGAnimatedNumberList::InternalAList()
+{
+  return *mElement->GetAnimatedNumberList(mAttrEnum);
+}
+
+const SVGAnimatedNumberList&
+DOMSVGAnimatedNumberList::InternalAList() const
+{
+  return *mElement->GetAnimatedNumberList(mAttrEnum);
+}
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGAnimatedNumberList.h
@@ -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 Mozilla SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MOZILLA_DOMSVGANIMATEDNUMBERLIST_H__
+#define MOZILLA_DOMSVGANIMATEDNUMBERLIST_H__
+
+#include "nsIDOMSVGAnimatedNumberList.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsAutoPtr.h"
+#include "nsTArray.h"
+
+class nsSVGElement;
+
+namespace mozilla {
+
+class SVGAnimatedNumberList;
+class SVGNumberList;
+class DOMSVGNumberList;
+
+/**
+ * Class DOMSVGAnimatedNumberList
+ *
+ * This class is used to create the DOM tearoff objects that wrap internal
+ * SVGAnimatedNumberList objects.
+ *
+ * See the architecture comment in DOMSVGAnimatedLengthList.h (that's
+ * LENGTH list). The comment for that class largly applies to this one too
+ * and will go a long way to helping you understand the architecture here.
+ *
+ * This class is strongly intertwined with DOMSVGNumberList and DOMSVGNumber.
+ * Our DOMSVGNumberList base and anim vals are friends and take care of nulling
+ * out our pointers to them when they die (making our pointers to them true
+ * weak refs).
+ */
+class DOMSVGAnimatedNumberList : public nsIDOMSVGAnimatedNumberList
+{
+  friend class DOMSVGNumberList;
+
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGAnimatedNumberList)
+  NS_DECL_NSIDOMSVGANIMATEDNUMBERLIST
+
+  /**
+   * Factory method to create and return a DOMSVGAnimatedNumberList wrapper
+   * for a given internal SVGAnimatedNumberList object. The factory takes care
+   * of caching the object that it returns so that the same object can be
+   * returned for the given SVGAnimatedNumberList each time it is requested.
+   * The cached object is only removed from the cache when it is destroyed due
+   * to there being no more references to it or to any of its descendant
+   * objects. If that happens, any subsequent call requesting the DOM wrapper
+   * for the SVGAnimatedNumberList will naturally result in a new
+   * DOMSVGAnimatedNumberList being returned.
+   */
+  static already_AddRefed<DOMSVGAnimatedNumberList>
+    GetDOMWrapper(SVGAnimatedNumberList *aList,
+                  nsSVGElement *aElement,
+                  PRUint8 aAttrEnum);
+
+  /**
+   * This method returns the DOMSVGAnimatedNumberList wrapper for an internal
+   * SVGAnimatedNumberList object if it currently has a wrapper. If it does
+   * not, then nsnull is returned.
+   */
+  static DOMSVGAnimatedNumberList*
+    GetDOMWrapperIfExists(SVGAnimatedNumberList *aList);
+
+  /**
+   * Called by internal code to notify us when we need to sync the length of
+   * our baseVal DOM list with its internal list. This is called just prior to
+   * the length of the internal baseVal list being changed so that any DOM list
+   * items that need to be removed from the DOM list can first get their values
+   * from their internal counterpart.
+   *
+   * The only time this method could fail is on OOM when trying to increase the
+   * length of the DOM list. If that happens then this method simply clears the
+   * list and returns. Callers just proceed as normal, and we simply accept
+   * that the DOM list will be empty (until successfully set to a new value).
+   */
+  void InternalBaseValListWillChangeTo(const SVGNumberList& aNewValue);
+  void InternalAnimValListWillChangeTo(const SVGNumberList& aNewValue);
+
+  /**
+   * Returns true if our attribute is animating (in which case our animVal is
+   * not simply a mirror of our baseVal).
+   */
+  PRBool IsAnimating() const;
+
+private:
+
+  /**
+   * Only our static GetDOMWrapper() factory method may create objects of our
+   * type.
+   */
+  DOMSVGAnimatedNumberList(nsSVGElement *aElement, PRUint8 aAttrEnum)
+    : mBaseVal(nsnull)
+    , mAnimVal(nsnull)
+    , mElement(aElement)
+    , mAttrEnum(aAttrEnum)
+  {}
+
+  ~DOMSVGAnimatedNumberList();
+
+  /// Get a reference to this DOM wrapper object's internal counterpart.
+  SVGAnimatedNumberList& InternalAList();
+  const SVGAnimatedNumberList& InternalAList() const;
+
+  // Weak refs to our DOMSVGNumberList baseVal/animVal objects. These objects
+  // are friends and take care of clearing these pointers when they die, making
+  // these true weak references.
+  DOMSVGNumberList *mBaseVal;
+  DOMSVGNumberList *mAnimVal;
+
+  // Strong ref to our element to keep it alive. We hold this not only for
+  // ourself, but also for our base/animVal and all of their items.
+  nsRefPtr<nsSVGElement> mElement;
+
+  PRUint8 mAttrEnum;
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_DOMSVGANIMATEDNUMBERLIST_H__
--- a/content/svg/content/src/DOMSVGLength.cpp
+++ b/content/svg/content/src/DOMSVGLength.cpp
@@ -83,37 +83,30 @@ DOMSVGLength::DOMSVGLength(DOMSVGLengthL
                            PRUint8 aIsAnimValItem)
   : mList(aList)
   , mListIndex(aListIndex)
   , mAttrEnum(aAttrEnum)
   , mIsAnimValItem(aIsAnimValItem)
   , mUnit(nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER)
   , mValue(0.0f)
 {
-#ifdef DEBUG
-  // These shifts are in sync with the flag member's in the header.
+  // These shifts are in sync with the members in the header.
   NS_ABORT_IF_FALSE(aList &&
                     aAttrEnum < (1 << 22) &&
                     aListIndex < (1 << 4) &&
                     aIsAnimValItem < (1 << 1), "bad arg");
-  if (aIsAnimValItem &&
-      mListIndex >= Element()->GetAnimatedLengthList(mAttrEnum)->GetAnimValue().Length() ||
-      !aIsAnimValItem &&
-      mListIndex >= Element()->GetAnimatedLengthList(mAttrEnum)->GetBaseValue().Length()) {
-    NS_ABORT_IF_FALSE(0, "Bad aListIndex!");
-    mList = nsnull;
-  }
-#endif
+
+  NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGNumber!");
 }
 
 DOMSVGLength::DOMSVGLength()
   : mList(nsnull)
   , mListIndex(0)
   , mAttrEnum(0)
-  , mIsAnimValItem(0)
+  , mIsAnimValItem(PR_FALSE)
   , mUnit(nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER)
   , mValue(0.0f)
 {
 }
 
 NS_IMETHODIMP
 DOMSVGLength::GetUnitType(PRUint16* aUnit)
 {
@@ -316,35 +309,32 @@ DOMSVGLength::ConvertToSpecifiedUnits(PR
 
 void
 DOMSVGLength::InsertingIntoList(DOMSVGLengthList *aList,
                                 PRUint32 aAttrEnum,
                                 PRUint8 aListIndex,
                                 PRUint8 aIsAnimValItem)
 {
   NS_ASSERTION(!HasOwner(), "Inserting item that is already in a list");
-  NS_ASSERTION(mIsAnimValItem &&
-               aListIndex < aList->Element()->GetAnimatedLengthList(aAttrEnum)->GetAnimValue().Length() ||
-               !aIsAnimValItem &&
-               aListIndex < aList->Element()->GetAnimatedLengthList(aAttrEnum)->GetBaseValue().Length(),
-               "mListIndex too big");
 
   mList = aList;
   mAttrEnum = aAttrEnum;
   mListIndex = aListIndex;
   mIsAnimValItem = aIsAnimValItem;
+
+  NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGLength!");
 }
 
 void
 DOMSVGLength::RemovingFromList()
 {
   mValue = InternalItem().GetValueInCurrentUnits();
   mUnit  = InternalItem().GetUnit();
   mList = nsnull;
-  mIsAnimValItem = 0;
+  mIsAnimValItem = PR_FALSE;
 }
 
 SVGLength
 DOMSVGLength::ToSVGLength()
 {
   if (HasOwner()) {
     return SVGLength(InternalItem().GetValueInCurrentUnits(),
                      InternalItem().GetUnit());
@@ -356,9 +346,21 @@ SVGLength&
 DOMSVGLength::InternalItem()
 {
   SVGAnimatedLengthList *alist = Element()->GetAnimatedLengthList(mAttrEnum);
   return mIsAnimValItem && alist->mAnimVal ?
     (*alist->mAnimVal)[mListIndex] :
     alist->mBaseVal[mListIndex];
 }
 
+#ifdef DEBUG
+PRBool
+DOMSVGLength::IndexIsValid()
+{
+  SVGAnimatedLengthList *alist = Element()->GetAnimatedLengthList(mAttrEnum);
+  return (mIsAnimValItem &&
+          mListIndex < alist->GetAnimValue().Length()) ||
+         (!mIsAnimValItem &&
+          mListIndex < alist->GetBaseValue().Length());
+}
+#endif
+
 } // namespace mozilla
--- a/content/svg/content/src/DOMSVGLength.h
+++ b/content/svg/content/src/DOMSVGLength.h
@@ -165,17 +165,17 @@ public:
   void UpdateListIndex(PRUint8 aListIndex) {
     mListIndex = aListIndex;
   }
 
   /**
    * This method is called to notify this DOM object that it is about to be
    * removed from its current DOM list so that it can first make a copy of its
    * internal counterpart's values. (If it didn't do this, then it would
-   * "loose" its value on being removed.)
+   * "lose" its value on being removed.)
    */
   void RemovingFromList();
 
   SVGLength ToSVGLength();
 
 private:
 
   nsSVGElement* Element() {
@@ -193,23 +193,27 @@ private:
   PRUint8 Axis() const {
     return mList->Axis();
   }
 
   /**
    * Get a reference to the internal SVGLength list item that this DOM wrapper
    * object currently wraps.
    *
-   * To simplyfy the code we just have this one method for obtaining both
+   * To simplify the code we just have this one method for obtaining both
    * baseVal and animVal internal items. This means that animVal items don't
    * get const protection, but then our setter methods guard against changing
    * animVal items.
    */
   SVGLength& InternalItem();
 
+#ifdef DEBUG
+  PRBool IndexIsValid();
+#endif
+
   nsRefPtr<DOMSVGLengthList> mList;
 
   // Bounds for the following are checked in the ctor, so be sure to update
   // that if you change the capacity of any of the following.
 
   PRUint32 mListIndex:22; // supports > 4 million list items
   PRUint32 mAttrEnum:4; // supports up to 16 attributes
   PRUint32 mIsAnimValItem:1;
--- a/content/svg/content/src/DOMSVGLengthList.h
+++ b/content/svg/content/src/DOMSVGLengthList.h
@@ -130,17 +130,17 @@ private:
   /// Used to determine if this list is the baseVal or animVal list.
   PRBool IsAnimValList() const {
     return this == mAList->mAnimVal;
   }
 
   /**
    * Get a reference to this object's corresponding internal SVGLengthList.
    *
-   * To simplyfy the code we just have this one method for obtaining both
+   * To simplify the code we just have this one method for obtaining both
    * baseVal and animVal internal lists. This means that animVal lists don't
    * get const protection, but our setter methods guard against changing
    * animVal lists.
    */
   SVGLengthList& InternalList();
 
   /// Creates a DOMSVGLength for aIndex, if it doesn't already exist.
   void EnsureItemAt(PRUint32 aIndex);
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGNumber.cpp
@@ -0,0 +1,190 @@
+/* -*- 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 SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "DOMSVGNumber.h"
+#include "DOMSVGNumberList.h"
+#include "DOMSVGAnimatedNumberList.h"
+#include "SVGAnimatedNumberList.h"
+#include "nsSVGElement.h"
+#include "nsIDOMSVGNumber.h"
+#include "nsDOMError.h"
+
+// See the architecture comment in DOMSVGAnimatedNumberList.h.
+
+using namespace mozilla;
+
+// We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
+// clear our list's weak ref to us to be safe. (The other option would be to
+// not unlink and rely on the breaking of the other edges in the cycle, as
+// NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
+NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGNumber)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGNumber)
+  // We may not belong to a list, so we must null check tmp->mList.
+  if (tmp->mList) {
+    tmp->mList->mItems[tmp->mListIndex] = nsnull;
+  }
+NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mList)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGNumber)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mList)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGNumber)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGNumber)
+
+DOMCI_DATA(SVGNumber, DOMSVGNumber)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGNumber)
+  NS_INTERFACE_MAP_ENTRY(DOMSVGNumber) // pseudo-interface
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGNumber)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGNumber)
+NS_INTERFACE_MAP_END
+
+DOMSVGNumber::DOMSVGNumber(DOMSVGNumberList *aList,
+                           PRUint32 aAttrEnum,
+                           PRUint8 aListIndex,
+                           PRUint8 aIsAnimValItem)
+  : mList(aList)
+  , mListIndex(aListIndex)
+  , mAttrEnum(aAttrEnum)
+  , mIsAnimValItem(aIsAnimValItem)
+  , mValue(0.0f)
+{
+  // These shifts are in sync with the members in the header.
+  NS_ABORT_IF_FALSE(aList &&
+                    aAttrEnum < (1 << 27) &&
+                    aListIndex < (1 << 4) &&
+                    aIsAnimValItem < (1 << 1), "bad arg");
+
+  NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGNumber!");
+}
+
+DOMSVGNumber::DOMSVGNumber()
+  : mList(nsnull)
+  , mListIndex(0)
+  , mAttrEnum(0)
+  , mIsAnimValItem(PR_FALSE)
+  , mValue(0.0f)
+{
+}
+
+NS_IMETHODIMP
+DOMSVGNumber::GetValue(float* aValue)
+{
+#ifdef MOZ_SMIL
+  if (mIsAnimValItem && HasOwner()) {
+    Element()->FlushAnimations(); // May make HasOwner() == PR_FALSE
+  }
+#endif
+  *aValue = HasOwner() ? InternalItem() : mValue;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGNumber::SetValue(float aValue)
+{
+  if (mIsAnimValItem) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  NS_ENSURE_FINITE(aValue, NS_ERROR_ILLEGAL_VALUE);
+
+  if (HasOwner()) {
+    InternalItem() = aValue;
+    Element()->DidChangeNumberList(mAttrEnum, PR_TRUE);
+#ifdef MOZ_SMIL
+    if (mList->mAList->IsAnimating()) {
+      Element()->AnimationNeedsResample();
+    }
+#endif
+    return NS_OK;
+  }
+  mValue = aValue;
+  return NS_OK;
+}
+
+void
+DOMSVGNumber::InsertingIntoList(DOMSVGNumberList *aList,
+                                PRUint32 aAttrEnum,
+                                PRUint8 aListIndex,
+                                PRUint8 aIsAnimValItem)
+{
+  NS_ASSERTION(!HasOwner(), "Inserting item that is already in a list");
+
+  mList = aList;
+  mAttrEnum = aAttrEnum;
+  mListIndex = aListIndex;
+  mIsAnimValItem = aIsAnimValItem;
+
+  NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGNumber!");
+}
+
+void
+DOMSVGNumber::RemovingFromList()
+{
+  mValue = InternalItem();
+  mList = nsnull;
+  mIsAnimValItem = PR_FALSE;
+}
+
+float
+DOMSVGNumber::ToSVGNumber()
+{
+  return HasOwner() ? InternalItem() : mValue;
+}
+
+float&
+DOMSVGNumber::InternalItem()
+{
+  SVGAnimatedNumberList *alist = Element()->GetAnimatedNumberList(mAttrEnum);
+  return mIsAnimValItem && alist->mAnimVal ?
+    (*alist->mAnimVal)[mListIndex] :
+    alist->mBaseVal[mListIndex];
+}
+
+#ifdef DEBUG
+PRBool
+DOMSVGNumber::IndexIsValid()
+{
+  SVGAnimatedNumberList *alist = Element()->GetAnimatedNumberList(mAttrEnum);
+  return (mIsAnimValItem &&
+          mListIndex < alist->GetAnimValue().Length()) ||
+         (!mIsAnimValItem &&
+          mListIndex < alist->GetBaseValue().Length());
+}
+#endif
+
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGNumber.h
@@ -0,0 +1,194 @@
+/* -*- 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 SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MOZILLA_DOMSVGNUMBER_H__
+#define MOZILLA_DOMSVGNUMBER_H__
+
+#include "nsIDOMSVGNumber.h"
+#include "DOMSVGNumberList.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsAutoPtr.h"
+
+class nsSVGElement;
+
+// We make DOMSVGNumber a pseudo-interface to allow us to QI to it in order to
+// check that the objects that scripts pass to DOMSVGNumberList methods are our
+// *native* number objects.
+//
+// {2CA92412-2E1F-4DDB-A16C-52B3B582270D}
+#define MOZILLA_DOMSVGNUMBER_IID \
+  { 0x2CA92412, 0x2E1F, 0x4DDB, \
+    { 0xA1, 0x6C, 0x52, 0xB3, 0xB5, 0x82, 0x27, 0x0D } }
+
+namespace mozilla {
+
+/**
+ * Class DOMSVGNumber
+ *
+ * This class creates the DOM objects that wrap internal SVGNumber objects that
+ * are in an SVGNumberList. It is also used to create the objects returned by
+ * SVGSVGElement.createSVGNumber().
+ *
+ * For the DOM wrapper classes for non-list SVGNumber, see nsSVGNumber2.h.
+ *
+ * See the architecture comment in DOMSVGAnimatedNumberList.h.
+ *
+ * See the comment in DOMSVGLength.h (yes, LENGTH), which applies here too.
+ */
+class DOMSVGNumber : public nsIDOMSVGNumber
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOMSVGNUMBER_IID)
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGNumber)
+  NS_DECL_NSIDOMSVGNUMBER
+
+  /**
+   * Generic ctor for DOMSVGNumber objects that are created for an attribute.
+   */
+  DOMSVGNumber(DOMSVGNumberList *aList,
+               PRUint32 aAttrEnum,
+               PRUint8 aListIndex,
+               PRUint8 aIsAnimValItem);
+
+  /**
+   * Ctor for creating the objects returned by SVGSVGElement.createSVGNumber(),
+   * which do not initially belong to an attribute.
+   */
+  DOMSVGNumber();
+
+  ~DOMSVGNumber() {
+    // Our mList's weak ref to us must be nulled out when we die. If GC has
+    // unlinked us using the cycle collector code, then that has already
+    // happened, and mList is null.
+    if (mList) {
+      mList->mItems[mListIndex] = nsnull;
+    }
+  };
+
+  /**
+   * Create an unowned copy. The caller is responsible for the first AddRef().
+   */
+  DOMSVGNumber* Clone() {
+    DOMSVGNumber *clone = new DOMSVGNumber();
+    clone->mValue = ToSVGNumber();
+    return clone;
+  }
+
+  PRBool IsInList() const {
+    return !!mList;
+  }
+
+  /**
+   * In future, if this class is used for non-list numbers, this will be
+   * different to IsInList().
+   */
+  PRBool HasOwner() const {
+    return !!mList;
+  }
+
+  /**
+   * This method is called to notify this DOM object that it is being inserted
+   * into a list, and give it the information it needs as a result.
+   *
+   * This object MUST NOT already belong to a list when this method is called.
+   * That's not to say that script can't move these DOM objects between
+   * lists - it can - it's just that the logic to handle that (and send out
+   * the necessary notifications) is located elsewhere (in DOMSVGNumberList).)
+   */
+  void InsertingIntoList(DOMSVGNumberList *aList,
+                         PRUint32 aAttrEnum,
+                         PRUint8 aListIndex,
+                         PRUint8 aIsAnimValItem);
+
+  /// This method is called to notify this object that its list index changed.
+  void UpdateListIndex(PRUint8 aListIndex) {
+    mListIndex = aListIndex;
+  }
+
+  /**
+   * This method is called to notify this DOM object that it is about to be
+   * removed from its current DOM list so that it can first make a copy of its
+   * internal counterpart's value. (If it didn't do this, then it would
+   * "lose" its value on being removed.)
+   */
+  void RemovingFromList();
+
+  float ToSVGNumber();
+
+private:
+
+  nsSVGElement* Element() {
+    return mList->Element();
+  }
+
+  PRUint8 AttrEnum() const {
+    return mAttrEnum;
+  }
+
+  /**
+   * Get a reference to the internal SVGNumber list item that this DOM wrapper
+   * object currently wraps.
+   *
+   * To simplify the code we just have this one method for obtaining both
+   * baseVal and animVal internal items. This means that animVal items don't
+   * get const protection, but then our setter methods guard against changing
+   * animVal items.
+   */
+  float& InternalItem();
+
+#ifdef DEBUG
+  PRBool IndexIsValid();
+#endif
+
+  nsRefPtr<DOMSVGNumberList> mList;
+
+  // Bounds for the following are checked in the ctor, so be sure to update
+  // that if you change the capacity of any of the following.
+
+  PRUint32 mListIndex:27; // supports > 134 million list items
+  PRUint32 mAttrEnum:4; // supports up to 16 attributes
+  PRUint32 mIsAnimValItem:1;
+
+  // The following member is only used when we're not in a list:
+  float mValue;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(DOMSVGNumber, MOZILLA_DOMSVGNUMBER_IID)
+
+} // namespace mozilla
+
+#endif // MOZILLA_DOMSVGNUMBER_H__
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGNumberList.cpp
@@ -0,0 +1,327 @@
+/* -*- 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 SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsSVGElement.h"
+#include "DOMSVGNumberList.h"
+#include "DOMSVGNumber.h"
+#include "nsDOMError.h"
+#include "SVGAnimatedNumberList.h"
+#include "nsCOMPtr.h"
+
+// See the comment in this file's header.
+
+using namespace mozilla;
+
+// We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
+// clear our DOMSVGAnimatedNumberList's weak ref to us to be safe. (The other
+// option would be to not unlink and rely on the breaking of the other edges in
+// the cycle, as NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
+NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGNumberList)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGNumberList)
+  // No need to null check tmp - script/SMIL can't detach us from mAList
+  ( tmp->IsAnimValList() ? tmp->mAList->mAnimVal : tmp->mAList->mBaseVal ) = nsnull;
+NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAList)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGNumberList)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAList)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGNumberList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGNumberList)
+
+DOMCI_DATA(SVGNumberList, DOMSVGNumberList)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGNumberList)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGNumberList)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGNumberList)
+NS_INTERFACE_MAP_END
+
+
+void
+DOMSVGNumberList::InternalListLengthWillChange(PRUint32 aNewLength)
+{
+  PRUint32 oldLength = mItems.Length();
+
+  // If our length will decrease, notify the items that will be removed:
+  for (PRUint32 i = aNewLength; i < oldLength; ++i) {
+    if (mItems[i]) {
+      mItems[i]->RemovingFromList();
+    }
+  }
+
+  if (!mItems.SetLength(aNewLength)) {
+    // We silently ignore SetLength OOM failure since being out of sync is safe
+    // so long as we have *fewer* items than our internal list.
+    mItems.Clear();
+    return;
+  }
+
+  // If our length has increased, null out the new pointers:
+  for (PRUint32 i = oldLength; i < aNewLength; ++i) {
+    mItems[i] = nsnull;
+  }
+}
+
+SVGNumberList&
+DOMSVGNumberList::InternalList()
+{
+  SVGAnimatedNumberList *alist = Element()->GetAnimatedNumberList(AttrEnum());
+  return IsAnimValList() && alist->mAnimVal ? *alist->mAnimVal : alist->mBaseVal;
+}
+
+// ----------------------------------------------------------------------------
+// nsIDOMSVGNumberList implementation:
+
+NS_IMETHODIMP
+DOMSVGNumberList::GetNumberOfItems(PRUint32 *aNumberOfItems)
+{
+#ifdef MOZ_SMIL
+  if (IsAnimValList()) {
+    Element()->FlushAnimations();
+  }
+#endif
+  *aNumberOfItems = Length();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGNumberList::Clear()
+{
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  if (Length() > 0) {
+    // Notify any existing DOM items of removal *before* truncating the lists
+    // so that they can find their SVGNumber internal counterparts and copy
+    // their values:
+    mAList->InternalBaseValListWillChangeTo(SVGNumberList());
+
+    mItems.Clear();
+    InternalList().Clear();
+    Element()->DidChangeNumberList(AttrEnum(), PR_TRUE);
+#ifdef MOZ_SMIL
+    if (mAList->IsAnimating()) {
+      Element()->AnimationNeedsResample();
+    }
+#endif
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGNumberList::Initialize(nsIDOMSVGNumber *newItem,
+                             nsIDOMSVGNumber **_retval)
+{
+  *_retval = nsnull;
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  // If newItem is already in a list we should insert a clone of newItem, and
+  // for consistency, this should happen even if *this* is the list that
+  // newItem is currently in. Note that in the case of newItem being in this
+  // list, the Clear() call before the InsertItemBefore() call would remove it
+  // from this list, and so the InsertItemBefore() call would not insert a
+  // clone of newItem, it would actually insert newItem. To prevent that from
+  // happening we have to do the clone here, if necessary.
+
+  nsCOMPtr<DOMSVGNumber> domItem = do_QueryInterface(newItem);
+  if (!domItem) {
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
+  if (domItem->HasOwner()) {
+    newItem = domItem->Clone();
+  }
+
+  Clear();
+  return InsertItemBefore(newItem, 0, _retval);
+}
+
+NS_IMETHODIMP
+DOMSVGNumberList::GetItem(PRUint32 index,
+                          nsIDOMSVGNumber **_retval)
+{
+#ifdef MOZ_SMIL
+  if (IsAnimValList()) {
+    Element()->FlushAnimations();
+  }
+#endif
+  if (index < Length()) {
+    EnsureItemAt(index);
+    NS_ADDREF(*_retval = mItems[index]);
+    return NS_OK;
+  }
+  *_retval = nsnull;
+  return NS_ERROR_DOM_INDEX_SIZE_ERR;
+}
+
+NS_IMETHODIMP
+DOMSVGNumberList::InsertItemBefore(nsIDOMSVGNumber *newItem,
+                                   PRUint32 index,
+                                   nsIDOMSVGNumber **_retval)
+{
+  *_retval = nsnull;
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  nsCOMPtr<DOMSVGNumber> domItem = do_QueryInterface(newItem);
+  if (!domItem) {
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
+  index = NS_MIN(index, Length());
+  float value = domItem->ToSVGNumber(); // get before setting domItem
+  if (domItem->HasOwner()) {
+    domItem = new DOMSVGNumber();
+  }
+  PRBool ok = !!InternalList().InsertItem(index, value);
+  if (!ok) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
+  ok = !!mItems.InsertElementAt(index, domItem.get());
+  if (!ok) {
+    InternalList().RemoveItem(index);
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  for (PRUint32 i = index + 1; i < Length(); ++i) {
+    if (mItems[i]) {
+      mItems[i]->UpdateListIndex(i);
+    }
+  }
+  Element()->DidChangeNumberList(AttrEnum(), PR_TRUE);
+#ifdef MOZ_SMIL
+  if (mAList->IsAnimating()) {
+    Element()->AnimationNeedsResample();
+  }
+#endif
+  *_retval = domItem.forget().get();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGNumberList::ReplaceItem(nsIDOMSVGNumber *newItem,
+                              PRUint32 index,
+                              nsIDOMSVGNumber **_retval)
+{
+  *_retval = nsnull;
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  nsCOMPtr<DOMSVGNumber> domItem = do_QueryInterface(newItem);
+  if (!domItem) {
+    return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
+  }
+  if (index >= Length()) {
+    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  }
+  float length = domItem->ToSVGNumber(); // get before setting domItem
+  if (domItem->HasOwner()) {
+    domItem = new DOMSVGNumber();
+  }
+  if (mItems[index]) {
+    // Notify any existing DOM item of removal *before* modifying the lists so
+    // that the DOM item can copy the *old* value at its index:
+    mItems[index]->RemovingFromList();
+  }
+  InternalList()[index] = length;
+  domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
+  mItems[index] = domItem;
+
+  Element()->DidChangeNumberList(AttrEnum(), PR_TRUE);
+#ifdef MOZ_SMIL
+  if (mAList->IsAnimating()) {
+    Element()->AnimationNeedsResample();
+  }
+#endif
+  NS_ADDREF(*_retval = domItem.get());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGNumberList::RemoveItem(PRUint32 index,
+                             nsIDOMSVGNumber **_retval)
+{
+  *_retval = nsnull;
+  if (IsAnimValList()) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  if (index >= Length()) {
+    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  }
+  // We have to return the removed item, so make sure it exists:
+  EnsureItemAt(index);
+
+  // Notify the DOM item of removal *before* modifying the lists so that the
+  // DOM item can copy its *old* value:
+  mItems[index]->RemovingFromList();
+
+  InternalList().RemoveItem(index);
+
+  NS_ADDREF(*_retval = mItems[index]);
+  mItems.RemoveElementAt(index);
+  for (PRUint32 i = index; i < Length(); ++i) {
+    if (mItems[i]) {
+      mItems[i]->UpdateListIndex(i);
+    }
+  }
+  Element()->DidChangeNumberList(AttrEnum(), PR_TRUE);
+#ifdef MOZ_SMIL
+  if (mAList->IsAnimating()) {
+    Element()->AnimationNeedsResample();
+  }
+#endif
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMSVGNumberList::AppendItem(nsIDOMSVGNumber *newItem,
+                             nsIDOMSVGNumber **_retval)
+{
+  return InsertItemBefore(newItem, Length(), _retval);
+}
+
+void
+DOMSVGNumberList::EnsureItemAt(PRUint32 aIndex)
+{
+  if (!mItems[aIndex]) {
+    mItems[aIndex] = new DOMSVGNumber(this, AttrEnum(), aIndex, IsAnimValList());
+  }
+}
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/DOMSVGNumberList.h
@@ -0,0 +1,153 @@
+/* -*- 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 SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MOZILLA_DOMSVGNUMBERLIST_H__
+#define MOZILLA_DOMSVGNUMBERLIST_H__
+
+#include "nsIDOMSVGNumberList.h"
+#include "SVGNumberList.h"
+#include "DOMSVGAnimatedNumberList.h"
+#include "nsCOMArray.h"
+#include "nsAutoPtr.h"
+
+class nsSVGElement;
+
+namespace mozilla {
+
+class DOMSVGNumber;
+
+/**
+ * Class DOMSVGNumberList
+ *
+ * This class is used to create the DOM tearoff objects that wrap internal
+ * SVGNumberList objects.
+ *
+ * See the architecture comment in DOMSVGAnimatedNumberList.h.
+ *
+ * This class is strongly intertwined with DOMSVGAnimatedNumberList and
+ * DOMSVGNumber. We are a friend of DOMSVGAnimatedNumberList, and are
+ * responsible for nulling out our DOMSVGAnimatedNumberList's pointer to us
+ * when we die, essentially making its pointer to us a weak pointer. Similarly,
+ * our DOMSVGNumber items are friends of us and responsible for nulling out our
+ * pointers to them.
+ *
+ * Our DOM items are created lazily on demand as and when script requests them.
+ */
+class DOMSVGNumberList : public nsIDOMSVGNumberList
+{
+  friend class DOMSVGNumber;
+
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGNumberList)
+  NS_DECL_NSIDOMSVGNUMBERLIST
+
+  DOMSVGNumberList(DOMSVGAnimatedNumberList *aAList,
+                   const SVGNumberList &aInternalList)
+    : mAList(aAList)
+  {
+    // We can NOT use InternalList() here - it depends on IsAnimValList, which
+    // in turn depends on this object having been assigned to either aAList's
+    // mBaseVal or mAnimVal. At this point we haven't been assigned to either!
+    // This is why our caller must pass in aInternalList.
+
+    InternalListLengthWillChange(aInternalList.Length()); // Initialize mItems
+  }
+
+  ~DOMSVGNumberList() {
+    // Our mAList's weak ref to us must be nulled out when we die. If GC has
+    // unlinked us using the cycle collector code, then that has already
+    // happened, and mAList is null.
+    if (mAList) {
+      ( IsAnimValList() ? mAList->mAnimVal : mAList->mBaseVal ) = nsnull;
+    }
+  }
+
+  /**
+   * This will normally be the same as InternalList().Length(), except if we've
+   * hit OOM in which case our length will be zero.
+   */
+  PRUint32 Length() const {
+    NS_ABORT_IF_FALSE(mItems.Length() == 0 ||
+                      mItems.Length() ==
+                        const_cast<DOMSVGNumberList*>(this)->InternalList().Length(),
+                      "DOM wrapper's list length is out of sync");
+    return mItems.Length();
+  }
+
+  /// Called to notify us to syncronize our length and detach excess items.
+  void InternalListLengthWillChange(PRUint32 aNewLength);
+
+private:
+
+  nsSVGElement* Element() {
+    return mAList->mElement;
+  }
+
+  PRUint8 AttrEnum() const {
+    return mAList->mAttrEnum;
+  }
+
+  /// Used to determine if this list is the baseVal or animVal list.
+  PRBool IsAnimValList() const {
+    NS_ABORT_IF_FALSE(this == mAList->mBaseVal || this == mAList->mAnimVal,
+                      "Calling IsAnimValList() too early?!");
+    return this == mAList->mAnimVal;
+  }
+
+  /**
+   * Get a reference to this object's corresponding internal SVGNumberList.
+   *
+   * To simplify the code we just have this one method for obtaining both
+   * baseVal and animVal internal lists. This means that animVal lists don't
+   * get const protection, but our setter methods guard against changing
+   * animVal lists.
+   */
+  SVGNumberList& InternalList();
+
+  /// Creates a DOMSVGNumber for aIndex, if it doesn't already exist.
+  void EnsureItemAt(PRUint32 aIndex);
+
+  // Weak refs to our DOMSVGNumber items. The items are friends and take care
+  // of clearing our pointer to them when they die.
+  nsTArray<DOMSVGNumber*> mItems;
+
+  nsRefPtr<DOMSVGAnimatedNumberList> mAList;
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_DOMSVGNUMBERLIST_H__
--- a/content/svg/content/src/Makefile.in
+++ b/content/svg/content/src/Makefile.in
@@ -45,26 +45,28 @@ VPATH		= @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= content
 LIBRARY_NAME	= gkcontentsvg_s
 LIBXUL_LIBRARY	= 1
 
 CPPSRCS		= \
 		DOMSVGAnimatedLengthList.cpp \
+		DOMSVGAnimatedNumberList.cpp \
 		DOMSVGLength.cpp \
 		DOMSVGLengthList.cpp \
+		DOMSVGNumber.cpp \
+		DOMSVGNumberList.cpp \
 		DOMSVGPathSeg.cpp \
 		DOMSVGPathSegList.cpp \
 		nsDOMSVGZoomEvent.cpp \
 		nsDOMSVGEvent.cpp \
 		nsSVGAElement.cpp \
 		nsSVGAltGlyphElement.cpp \
 		nsSVGAngle.cpp \
-		nsSVGAnimatedNumberList.cpp \
 		nsSVGAnimatedTransformList.cpp \
 		nsSVGBoolean.cpp \
 		nsSVGCircleElement.cpp \
 		nsSVGClipPathElement.cpp \
 		nsSVGDataParser.cpp \
 		nsSVGDefsElement.cpp \
 		nsSVGDescElement.cpp \
 		nsSVGElement.cpp \
@@ -81,19 +83,17 @@ CPPSRCS		= \
 		nsSVGImageElement.cpp \
 		nsSVGInteger.cpp \
 		nsSVGLength2.cpp \
 		nsSVGLineElement.cpp \
 		nsSVGMarkerElement.cpp \
 		nsSVGMaskElement.cpp \
 		nsSVGMatrix.cpp \
 		nsSVGMetadataElement.cpp \
-		nsSVGNumber.cpp \
 		nsSVGNumber2.cpp \
-		nsSVGNumberList.cpp \
 		nsSVGPathDataParser.cpp \
 		nsSVGPathElement.cpp \
 		nsSVGPathGeometryElement.cpp \
 		nsSVGPatternElement.cpp \
 		nsSVGPoint.cpp \
 		nsSVGPointList.cpp \
 		nsSVGPolyElement.cpp \
 		nsSVGPolygonElement.cpp \
@@ -118,19 +118,21 @@ CPPSRCS		= \
 		nsSVGTitleElement.cpp \
 		nsSVGTransform.cpp \
 		nsSVGTransformList.cpp \
 		nsSVGTransformListParser.cpp \
 		nsSVGUseElement.cpp \
 		nsSVGValue.cpp \
 		nsSVGViewBox.cpp \
 		SVGAnimatedLengthList.cpp \
+		SVGAnimatedNumberList.cpp \
 		SVGAnimatedPathSegList.cpp \
 		SVGLength.cpp \
 		SVGLengthList.cpp \
+		SVGNumberList.cpp \
 		SVGPathData.cpp \
 		SVGPathSegUtils.cpp \
 		$(NULL)
 
 ifdef MOZ_SMIL
 CPPSRCS += nsSVGAnimateElement.cpp \
            nsSVGAnimateTransformElement.cpp \
            nsSVGAnimateMotionElement.cpp \
@@ -139,33 +141,33 @@ CPPSRCS += nsSVGAnimateElement.cpp \
            nsSVGSetElement.cpp \
            nsSVGTransformSMILType.cpp \
            nsSVGTransformSMILAttr.cpp \
            SVGLengthListSMILType.cpp \
            SVGMotionSMILType.cpp \
            SVGMotionSMILAttr.cpp \
            SVGMotionSMILAnimationFunction.cpp \
            SVGMotionSMILPathUtils.cpp \
+           SVGNumberListSMILType.cpp \
            SVGOrientSMILType.cpp \
            SVGPathSegListSMILType.cpp \
            SVGViewBoxSMILType.cpp \
            $(NULL)
 endif
 
 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
 
 EXPORTS =  			\
 	nsISVGValue.h              \
 	nsISVGValueObserver.h      \
 	nsISVGValueUtils.h         \
 	nsSVGFeatures.h            \
-	nsSVGNumber.h              \
 	nsSVGRect.h                \
 	nsSVGPoint.h               \
 	nsSVGMatrix.h              \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES += 	\
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGAnimatedNumberList.cpp
@@ -0,0 +1,215 @@
+/* -*- 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 SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "SVGAnimatedNumberList.h"
+#include "DOMSVGAnimatedNumberList.h"
+#include "nsSVGElement.h"
+#include "nsSVGAttrTearoffTable.h"
+#ifdef MOZ_SMIL
+#include "nsSMILValue.h"
+#include "SVGNumberListSMILType.h"
+#endif // MOZ_SMIL
+
+using namespace mozilla;
+
+nsresult
+SVGAnimatedNumberList::SetBaseValueString(const nsAString& aValue)
+{
+  SVGNumberList newBaseValue;
+  nsresult rv = newBaseValue.SetValueFromString(aValue);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  DOMSVGAnimatedNumberList *domWrapper =
+    DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this);
+  if (domWrapper) {
+    // We must send this notification *before* changing mBaseVal! If the length
+    // of our baseVal is being reduced, our baseVal's DOM wrapper list may have
+    // to remove DOM items from itself, and any removed DOM items need to copy
+    // their internal counterpart values *before* we change them.
+    //
+    domWrapper->InternalBaseValListWillChangeTo(newBaseValue);
+  }
+
+  // We don't need to call DidChange* here - we're only called by
+  // nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
+  // which takes care of notifying.
+
+  rv = mBaseVal.CopyFrom(newBaseValue);
+  if (NS_FAILED(rv)) {
+    // Attempting to increase mBaseVal's length failed - reduce domWrapper
+    // back to the same length:
+    domWrapper->InternalBaseValListWillChangeTo(mBaseVal);
+  }
+  return rv;
+}
+
+void
+SVGAnimatedNumberList::ClearBaseValue(PRUint32 aAttrEnum)
+{
+  DOMSVGAnimatedNumberList *domWrapper =
+    DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this);
+  if (domWrapper) {
+    // We must send this notification *before* changing mBaseVal! (See above.)
+    domWrapper->InternalAnimValListWillChangeTo(SVGNumberList());
+  }
+  mBaseVal.Clear();
+  // Caller notifies
+}
+
+nsresult
+SVGAnimatedNumberList::SetAnimValue(const SVGNumberList& aNewAnimValue,
+                                    nsSVGElement *aElement,
+                                    PRUint32 aAttrEnum)
+{
+  DOMSVGAnimatedNumberList *domWrapper =
+    DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this);
+  if (domWrapper) {
+    // A new animation may totally change the number of items in the animVal
+    // list, replacing what was essentially a mirror of the baseVal list, or
+    // else replacing and overriding an existing animation. When this happens
+    // we must try and keep our animVal's DOM wrapper in sync (see the comment
+    // in DOMSVGAnimatedNumberList::InternalBaseValListWillChangeTo).
+    //
+    // It's not possible for us to reliably distinguish between calls to this
+    // method that are setting a new sample for an existing animation, and
+    // calls that are setting the first sample of an animation that will
+    // override an existing animation. Happily it's cheap to just blindly
+    // notify our animVal's DOM wrapper of its internal counterpart's new value
+    // each time this method is called, so that's what we do.
+    //
+    // Note that we must send this notification *before* setting or changing
+    // mAnimVal! (See the comment in SetBaseValueString above.)
+    //
+    domWrapper->InternalAnimValListWillChangeTo(aNewAnimValue);
+  }
+  if (!mAnimVal) {
+    mAnimVal = new SVGNumberList();
+  }
+  nsresult rv = mAnimVal->CopyFrom(aNewAnimValue);
+  if (NS_FAILED(rv)) {
+    // OOM. We clear the animation, and, importantly, ClearAnimValue() ensures
+    // that mAnimVal and its DOM wrapper (if any) will have the same length!
+    ClearAnimValue(aElement, aAttrEnum);
+    return rv;
+  }
+  aElement->DidAnimateNumberList(aAttrEnum);
+  return NS_OK;
+}
+
+void
+SVGAnimatedNumberList::ClearAnimValue(nsSVGElement *aElement,
+                                      PRUint32 aAttrEnum)
+{
+  DOMSVGAnimatedNumberList *domWrapper =
+    DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this);
+  if (domWrapper) {
+    // When all animation ends, animVal simply mirrors baseVal, which may have
+    // a different number of items to the last active animated value. We must
+    // keep the length of our animVal's DOM wrapper list in sync, and again we
+    // must do that before touching mAnimVal. See comments above.
+    //
+    domWrapper->InternalAnimValListWillChangeTo(mBaseVal);
+  }
+  mAnimVal = nsnull;
+  aElement->DidAnimateNumberList(aAttrEnum);
+}
+
+#ifdef MOZ_SMIL
+nsISMILAttr*
+SVGAnimatedNumberList::ToSMILAttr(nsSVGElement *aSVGElement,
+                                  PRUint8 aAttrEnum)
+{
+  return new SMILAnimatedNumberList(this, aSVGElement, aAttrEnum);
+}
+
+nsresult
+SVGAnimatedNumberList::
+  SMILAnimatedNumberList::ValueFromString(const nsAString& aStr,
+                               const nsISMILAnimationElement* /*aSrcElement*/,
+                               nsSMILValue& aValue,
+                               PRBool& aPreventCachingOfSandwich) const
+{
+  nsSMILValue val(&SVGNumberListSMILType::sSingleton);
+  SVGNumberListAndInfo *nlai = static_cast<SVGNumberListAndInfo*>(val.mU.mPtr);
+  nsresult rv = nlai->SetValueFromString(aStr);
+  if (NS_SUCCEEDED(rv)) {
+    nlai->SetInfo(mElement);
+    aValue.Swap(val);
+  }
+  return rv;
+}
+
+nsSMILValue
+SVGAnimatedNumberList::SMILAnimatedNumberList::GetBaseValue() const
+{
+  // To benefit from Return Value Optimization and avoid copy constructor calls
+  // due to our use of return-by-value, we must return the exact same object
+  // from ALL return points. This function must only return THIS variable:
+  nsSMILValue val;
+
+  nsSMILValue tmp(&SVGNumberListSMILType::sSingleton);
+  SVGNumberListAndInfo *nlai = static_cast<SVGNumberListAndInfo*>(tmp.mU.mPtr);
+  nsresult rv = nlai->CopyFrom(mVal->mBaseVal);
+  if (NS_SUCCEEDED(rv)) {
+    nlai->SetInfo(mElement);
+    val.Swap(tmp);
+  }
+  return val;
+}
+
+nsresult
+SVGAnimatedNumberList::SMILAnimatedNumberList::SetAnimValue(const nsSMILValue& aValue)
+{
+  NS_ASSERTION(aValue.mType == &SVGNumberListSMILType::sSingleton,
+               "Unexpected type to assign animated value");
+  if (aValue.mType == &SVGNumberListSMILType::sSingleton) {
+    mVal->SetAnimValue(*static_cast<SVGNumberListAndInfo*>(aValue.mU.mPtr),
+                       mElement,
+                       mAttrEnum);
+  }
+  return NS_OK;
+}
+
+void
+SVGAnimatedNumberList::SMILAnimatedNumberList::ClearAnimValue()
+{
+  if (mVal->mAnimVal) {
+    mVal->ClearAnimValue(mElement, mAttrEnum);
+  }
+}
+#endif // MOZ_SMIL
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGAnimatedNumberList.h
@@ -0,0 +1,151 @@
+/* -*- 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 SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MOZILLA_SVGANIMATEDNUMBERLIST_H__
+#define MOZILLA_SVGANIMATEDNUMBERLIST_H__
+
+#include "SVGNumberList.h"
+
+class nsSVGElement;
+
+#ifdef MOZ_SMIL
+#include "nsISMILAttr.h"
+#endif // MOZ_SMIL
+
+namespace mozilla {
+
+/**
+ * Class SVGAnimatedNumberList
+ *
+ * This class is very different to the SVG DOM interface of the same name found
+ * in the SVG specification. This is a lightweight internal class - see
+ * DOMSVGAnimatedNumberList for the heavier DOM class that wraps instances of
+ * this class and implements the SVG specification's SVGAnimatedNumberList DOM
+ * interface.
+ *
+ * Except where noted otherwise, this class' methods take care of keeping the
+ * appropriate DOM wrappers in sync (see the comment in
+ * DOMSVGAnimatedNumberList::InternalBaseValListWillChangeTo) so that their
+ * consumers don't need to concern themselves with that.
+ */
+class SVGAnimatedNumberList
+{
+  // friends so that they can get write access to mBaseVal
+  friend class DOMSVGNumber;
+  friend class DOMSVGNumberList;
+
+public:
+  SVGAnimatedNumberList() {}
+
+  /**
+   * Because it's so important that mBaseVal and its DOMSVGNumberList wrapper
+   * (if any) be kept in sync (see the comment in
+   * DOMSVGAnimatedNumberList::InternalBaseValListWillChangeTo), this method
+   * returns a const reference. Only our friend classes may get mutable
+   * references to mBaseVal.
+   */
+  const SVGNumberList& GetBaseValue() const {
+    return mBaseVal;
+  }
+
+  nsresult SetBaseValueString(const nsAString& aValue);
+
+  void ClearBaseValue(PRUint32 aAttrEnum);
+
+  const SVGNumberList& GetAnimValue() const {
+    return mAnimVal ? *mAnimVal : mBaseVal;
+  }
+
+  nsresult SetAnimValue(const SVGNumberList& aValue,
+                        nsSVGElement *aElement,
+                        PRUint32 aAttrEnum);
+
+  void ClearAnimValue(nsSVGElement *aElement,
+                      PRUint32 aAttrEnum);
+
+  PRBool IsAnimating() const {
+    return !!mAnimVal;
+  }
+
+#ifdef MOZ_SMIL
+  /// Callers own the returned nsISMILAttr
+  nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement, PRUint8 aAttrEnum);
+#endif // MOZ_SMIL
+
+private:
+
+  // mAnimVal is a pointer to allow us to determine if we're being animated or
+  // not. Making it a non-pointer member and using mAnimVal.IsEmpty() to check
+  // if we're animating is not an option, since that would break animation *to*
+  // the empty string (<set to="">).
+
+  SVGNumberList mBaseVal;
+  nsAutoPtr<SVGNumberList> mAnimVal;
+
+#ifdef MOZ_SMIL
+  struct SMILAnimatedNumberList : public nsISMILAttr
+  {
+  public:
+    SMILAnimatedNumberList(SVGAnimatedNumberList* aVal,
+                           nsSVGElement* aSVGElement,
+                           PRUint8 aAttrEnum)
+      : mVal(aVal)
+      , mElement(aSVGElement)
+      , mAttrEnum(aAttrEnum)
+    {}
+
+    // These will stay alive because a nsISMILAttr only lives as long
+    // as the Compositing step, and DOM elements don't get a chance to
+    // die during that.
+    SVGAnimatedNumberList* mVal;
+    nsSVGElement* mElement;
+    PRUint8 mAttrEnum;
+
+    // nsISMILAttr methods
+    virtual nsresult ValueFromString(const nsAString& aStr,
+                                     const nsISMILAnimationElement* aSrcElement,
+                                     nsSMILValue& aValue,
+                                     PRBool& aPreventCachingOfSandwich) const;
+    virtual nsSMILValue GetBaseValue() const;
+    virtual void ClearAnimValue();
+    virtual nsresult SetAnimValue(const nsSMILValue& aValue);
+  };
+#endif // MOZ_SMIL
+};
+
+} // namespace mozilla
+
+#endif // MOZILLA_SVGANIMATEDNUMBERLIST_H__
--- a/content/svg/content/src/SVGLength.cpp
+++ b/content/svg/content/src/SVGLength.cpp
@@ -81,16 +81,20 @@ SVGLength::SetValueFromString(const nsAS
   if (unit != str && NS_FloatIsFinite(tmpValue)) {
     char *theRest = unit;
     if (*unit != '\0' && !IsSVGWhitespace(*unit)) {
       while (*theRest != '\0' && !IsSVGWhitespace(*theRest)) {
         ++theRest;
       }
       nsCAutoString unitStr(unit, theRest - unit);
       tmpUnit = GetUnitTypeForString(unitStr.get());
+      if (tmpUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN) {
+        // nsSVGUtils::ReportToConsole
+        return PR_FALSE;
+      }
     } else {
       tmpUnit = nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER;
     }
     while (*theRest && IsSVGWhitespace(*theRest)) {
       ++theRest;
     }
     if (!*theRest) {
       mValue = tmpValue;
@@ -267,13 +271,12 @@ GetUnitTypeForString(const char* unitStr
 
   nsCOMPtr<nsIAtom> unitAtom = do_GetAtom(unitStr);
 
   for (PRUint32 i = 1 ; i < NS_ARRAY_LENGTH(unitMap) ; i++) {
     if (unitMap[i] && *unitMap[i] == unitAtom) {
       return i;
     }
   }
-  NS_NOTREACHED("Returning unknown unit type");
   return nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN;
 }
 
 } // namespace mozilla
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
@@ -179,22 +179,18 @@ SVGMotionSMILAnimationFunction::
   NS_ABORT_IF_FALSE(mPathVertices.IsEmpty(),
                     "regenerating when we already have vertices");
 
   if (aContextElem->GetNameSpaceID() != kNameSpaceID_SVG) {
     NS_ERROR("Uh oh, SVG animateMotion element targeting a non-SVG node");
     return;
   }
 
-  // NOTE: We have to cast away constness on context node, since the
-  // nsSVGLength2 methods that need it for unit-conversion
-  // (e.g. nsSVGLength2::GetBaseValue) aren't const-correct.
-  nsSVGElement* svgCtx =
-    static_cast<nsSVGElement*>(const_cast<nsIContent*>(aContextElem));
-  SVGMotionSMILPathUtils::PathGenerator pathGenerator(svgCtx);
+  SVGMotionSMILPathUtils::PathGenerator
+    pathGenerator(static_cast<const nsSVGElement*>(aContextElem));
 
   PRBool success = PR_FALSE;
   if (HasAttr(nsGkAtoms::values)) {
     // Generate path based on our values array
     mPathSourceType = ePathSourceType_ValuesAttr;
     const nsAString& valuesStr = GetAttr(nsGkAtoms::values)->GetStringValue();
     SVGMotionSMILPathUtils::MotionValueParser parser(&pathGenerator,
                                                      &mPathVertices);
--- a/content/svg/content/src/SVGMotionSMILPathUtils.cpp
+++ b/content/svg/content/src/SVGMotionSMILPathUtils.cpp
@@ -32,17 +32,17 @@
  * 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 "SVGMotionSMILPathUtils.h"
 #include "nsSVGElement.h"
-#include "nsSVGLength2.h"
+#include "SVGLength.h"
 #include "nsContentCreatorFunctions.h" // For NS_NewSVGElement
 #include "nsCharSeparatedTokenizer.h"
 
 namespace mozilla {
 
 //----------------------------------------------------------------------
 // PathGenerator methods
 
@@ -121,41 +121,40 @@ PRBool
 SVGMotionSMILPathUtils::PathGenerator::
   ParseCoordinatePair(const nsAString& aCoordPairStr,
                       float& aXVal, float& aYVal)
 {
   nsCharSeparatedTokenizer
     tokenizer(aCoordPairStr, ',',
               nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
 
-  nsSVGLength2 x, y;
-  nsresult rv;
+  SVGLength x, y;
 
-  if (!tokenizer.hasMoreTokens()) { // No 1st token
-    return PR_FALSE;
-  }
-  // Parse X value
-  x.Init();
-  rv = x.SetBaseValueString(tokenizer.nextToken(), nsnull, PR_FALSE);
-  if (NS_FAILED(rv) ||                // 1st token failed to parse.
-      !tokenizer.hasMoreTokens()) {   // No 2nd token.
+  if (!tokenizer.hasMoreTokens() ||
+      !x.SetValueFromString(tokenizer.nextToken())) {
     return PR_FALSE;
   }
 
-  // Parse Y value
-  y.Init();
-  rv = y.SetBaseValueString(tokenizer.nextToken(), nsnull, PR_FALSE);
-  if (NS_FAILED(rv) ||                           // 2nd token failed to parse.
-      tokenizer.lastTokenEndedWithSeparator() || // Trailing comma.
+  if (!tokenizer.hasMoreTokens() ||
+      !y.SetValueFromString(tokenizer.nextToken())) { 
+    return PR_FALSE;
+  }
+
+  if (tokenizer.lastTokenEndedWithSeparator() || // Trailing comma.
       tokenizer.hasMoreTokens()) {               // More text remains
     return PR_FALSE;
   }
 
-  aXVal = x.GetBaseValue(mSVGElement);
-  aYVal = y.GetBaseValue(mSVGElement);
+  float xRes = x.GetValueInUserUnits(mSVGElement, nsSVGUtils::X);
+  float yRes = y.GetValueInUserUnits(mSVGElement, nsSVGUtils::Y);
+
+  NS_ENSURE_FINITE2(xRes, yRes, PR_FALSE);
+
+  aXVal = xRes;
+  aYVal = yRes;
   return PR_TRUE;
 }
 
 //----------------------------------------------------------------------
 // MotionValueParser methods
 nsresult
 SVGMotionSMILPathUtils::MotionValueParser::
   Parse(const nsAString& aValueStr)
--- a/content/svg/content/src/SVGMotionSMILPathUtils.h
+++ b/content/svg/content/src/SVGMotionSMILPathUtils.h
@@ -57,17 +57,17 @@ class nsAString;
 namespace mozilla {
 
 class SVGMotionSMILPathUtils {
 public:
   // Class to assist in generating a gfxFlattenedPath, based on
   // coordinates in the <animateMotion> from/by/to/values attributes.
   class PathGenerator {
   public:
-    PathGenerator(nsSVGElement* aSVGElement)
+    PathGenerator(const nsSVGElement* aSVGElement)
       : mSVGElement(aSVGElement),
         mGfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface()),
         mHaveReceivedCommands(PR_FALSE)
     {}
 
     // Methods for adding various path commands to output path.
     // Note: aCoordPairStr is expected to be a whitespace and/or
     // comma-separated x,y coordinate-pair -- see description of
@@ -86,17 +86,17 @@ public:
     already_AddRefed<gfxFlattenedPath> GetResultingPath();
 
   protected:
     // Helper methods
     PRBool ParseCoordinatePair(const nsAString& aStr,
                                float& aXVal, float& aYVal);
 
     // Member data
-    nsSVGElement* mSVGElement; // context for converting out of relative units
+    const nsSVGElement* mSVGElement; // context for converting to user units
     gfxContext    mGfxContext;
     PRPackedBool  mHaveReceivedCommands;
   };
 
   // Class to assist in passing each subcomponent of a |values| attribute to
   // a PathGenerator, for generating a corresponding gfxFlattenedPath.
   class MotionValueParser : public nsSMILParserUtils::GenericValueParser
   {
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/SVGNumberList.cpp
@@ -0,0 +1,110 @@
+/* -*- 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 SVG Project code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "SVGNumberList.h"
+#include "SVGAnimatedNumberList.h"
+#include "nsSVGElement.h"
+#include "nsISVGValueUtils.h"
+#include "nsDOMError.h"
+#include "nsContentUtils.h"
+#include "nsString.h"
+#include "nsSVGUtils.h"
+#include "string.h"
+#include "prdtoa.h"
+#include "nsTextFormatter.h"
+#include "nsCharSeparatedTokenizer.h"
+
+using namespace mozilla;
+
+nsresult
+SVGNumberList::CopyFrom(const SVGNumberList& rhs)
+{
+  if (!mNumbers.SetCapacity(rhs.Length())) {