Merge mozilla-central to tracemonkey.
authorRobert Sayre <sayrer@gmail.com>
Mon, 06 Dec 2010 13:17:56 -0500
changeset 58725 0d6d19884ccd0ba5214856f41d026c70f843143f
parent 58724 16a2d28ad4b4099306f0e262bf06cb6602b13f5b (current diff)
parent 58654 a722e6bdd0037fa89274e9ffd05a42d8c5b109dc (diff)
child 58726 25af9b539829ef7c04ba38515492a947c0c5aed9
child 58745 68de0c5b62557117a2abe16d752306958a3d0a9f
push id17407
push userrsayre@mozilla.com
push dateMon, 06 Dec 2010 22:03:37 +0000
treeherdermozilla-central@2f96714fd6d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to tracemonkey.
browser/base/content/pageReportFirstTime.xul
browser/locales/en-US/chrome/browser/pageReportFirstTime.dtd
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
content/base/src/nsNodeUtils.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
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
js/src/jsapi.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
services/crypto/tests/unit/test_crypto_keypair.js
services/crypto/tests/unit/test_crypto_rewrap.js
services/crypto/tests/unit/test_crypto_verify.js
services/sync/modules/base_records/keys.js
services/sync/tests/unit/test_records_cryptometa.js
services/sync/tests/unit/test_records_keys.js
services/sync/tests/unit/test_service_passphraseUTF8.js
testing/mozmill/tests/firefox/restartTests/testDefaultBookmarks/test1.js
toolkit/themes/pinstripe/global/icons/console-close.png
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -77,16 +77,17 @@ CPPSRCS = \
   nsTextEquivUtils.cpp \
   nsTextAttrs.cpp \
   $(NULL)
 
 EXPORTS = \
   a11yGeneric.h \
   nsAccessible.h \
   nsAccessNode.h \
+  nsARIAMap.h \
   $(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -33,19 +33,23 @@
  * 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 "nsARIAMap.h"
+
 #include "nsIAccessibleRole.h"
 #include "nsIAccessibleStates.h"
 
+#include "nsAccessibilityAtoms.h"
+#include "nsIContent.h"
+
 /**
  *  This list of WAI-defined roles are currently hardcoded.
  *  Eventually we will most likely be loading an RDF resource that contains this information
  *  Using RDF will also allow for role extensibility. See bug 280138.
  *
  *  Definition of nsRoleMapEntry and nsStateMapEntry contains comments explaining this table.
  *
  *  When no nsIAccessibleRole enum mapping exists for an ARIA role, the
--- a/accessible/src/base/nsARIAMap.h
+++ b/accessible/src/base/nsARIAMap.h
@@ -36,19 +36,19 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsARIAMap_H_
 #define _nsARIAMap_H_
 
 #include "prtypes.h"
-#include "nsAccessibilityAtoms.h"
 
-#include "nsIContent.h"
+class nsIAtom;
+class nsIContent;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Value constants
 
 /**
  * Used to define if role requires to expose nsIAccessibleValue.
  */
 enum EValueRule
--- 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/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -39,17 +39,16 @@
 
 #include "nsAccessible.h"
 
 #include "nsIXBLAccessible.h"
 
 #include "AccGroupInfo.h"
 #include "AccIterator.h"
 #include "nsAccUtils.h"
-#include "nsARIAMap.h"
 #include "nsDocAccessible.h"
 #include "nsEventShell.h"
 
 #include "nsAccEvent.h"
 #include "nsAccessibilityService.h"
 #include "nsAccTreeWalker.h"
 #include "nsRelUtils.h"
 #include "nsTextEquivUtils.h"
@@ -1819,21 +1818,20 @@ nsAccessible::GetKeyBindings(PRUint8 aAc
   if (!defaultKey.IsEmpty())
     keyBindings->Add(defaultKey);
 
   NS_ADDREF(*aKeyBindings = keyBindings);
   return NS_OK;
 }
 
 PRUint32
-nsAccessible::Role()
+nsAccessible::ARIARoleInternal()
 {
-  // No ARIA role or it doesn't suppress role from native markup.
-  if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
-    return NativeRole();
+  NS_PRECONDITION(mRoleMapEntry && mRoleMapEntry->roleRule == kUseMapRole,
+                  "ARIARoleInternal should only be called when ARIA role overrides!");
 
   // XXX: these unfortunate exceptions don't fit into the ARIA table. This is
   // where the accessible role depends on both the role and ARIA state.
   if (mRoleMapEntry->role == nsIAccessibleRole::ROLE_PUSHBUTTON) {
     if (nsAccUtils::HasDefinedARIAToken(mContent,
                                         nsAccessibilityAtoms::aria_pressed)) {
       // For simplicity, any existing pressed attribute except "" or "undefined"
       // indicates a toggle.
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -43,16 +43,17 @@
 
 #include "nsIAccessible.h"
 #include "nsIAccessibleHyperLink.h"
 #include "nsIAccessibleSelectable.h"
 #include "nsIAccessibleValue.h"
 #include "nsIAccessibleRole.h"
 #include "nsIAccessibleStates.h"
 
+#include "nsARIAMap.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 #include "nsRefPtrHashtable.h"
 
 class AccGroupInfo;
 class EmbeddedObjCollector;
 class nsAccessible;
 class AccEvent;
@@ -140,17 +141,35 @@ public:
    *                           explicitly (see nsIAccessible::name attribute for
    *                           details)
    */
   virtual nsresult GetNameInternal(nsAString& aName);
 
   /**
    * Return enumerated accessible role (see constants in nsIAccessibleRole).
    */
-  virtual PRUint32 Role();
+  inline PRUint32 Role()
+  {
+    if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
+      return NativeRole();
+
+    return ARIARoleInternal();
+  }
+
+  /**
+   * Return accessible role specified by ARIA (see constants in
+   * nsIAccessibleRole).
+   */
+  inline PRUint32 ARIARole()
+  {
+    if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
+      return nsIAccessibleRole::ROLE_NOTHING;
+
+    return ARIARoleInternal();
+  }
 
   /**
    * Returns enumerated accessible role from native markup (see constants in
    * nsIAccessibleRole). Doesn't take into account ARIA roles.
    */
   virtual PRUint32 NativeRole();
 
   /**
@@ -200,17 +219,16 @@ public:
   /**
    * Set the ARIA role map entry for a new accessible.
    * For a newly created accessible, specify which role map entry should be used.
    *
    * @param aRoleMapEntry The ARIA nsRoleMapEntry* for the accessible, or 
    *                      nsnull if none.
    */
   virtual void SetRoleMapEntry(nsRoleMapEntry *aRoleMapEntry);
-  const nsRoleMapEntry* GetRoleMapEntry() const { return mRoleMapEntry; }
 
   /**
    * Cache children if necessary. Return true if the accessible is defunct.
    */
   PRBool EnsureChildren();
 
   /**
    * Set the child count to -1 (unknown) and null out cached child pointers.
@@ -437,16 +455,21 @@ protected:
    * Return sibling accessible at the given offset.
    */
   virtual nsAccessible* GetSiblingAtOffset(PRInt32 aOffset,
                                            nsresult *aError = nsnull);
 
   //////////////////////////////////////////////////////////////////////////////
   // Miscellaneous helpers
 
+  /**
+   * Return ARIA role (helper method).
+   */
+  PRUint32 ARIARoleInternal();
+
   virtual nsIFrame* GetBoundsFrame();
   virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
   PRBool IsVisible(PRBool *aIsOffscreen); 
 
   //////////////////////////////////////////////////////////////////////////////
   // Name helpers
 
   /**
--- a/accessible/src/base/nsApplicationAccessible.cpp
+++ b/accessible/src/base/nsApplicationAccessible.cpp
@@ -374,22 +374,16 @@ nsApplicationAccessible::IsPrimaryForNod
 
 nsresult
 nsApplicationAccessible::GetARIAState(PRUint32 *aState, PRUint32 *aExtraState)
 {
   return NS_OK;
 }
 
 PRUint32
-nsApplicationAccessible::Role()
-{
-  return NativeRole();
-}
-
-PRUint32
 nsApplicationAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_APP_ROOT;
 }
 
 nsresult
 nsApplicationAccessible::GetStateInternal(PRUint32 *aState,
                                           PRUint32 *aExtraState)
--- a/accessible/src/base/nsApplicationAccessible.h
+++ b/accessible/src/base/nsApplicationAccessible.h
@@ -121,17 +121,16 @@ public:
   // nsAccessNode
   virtual PRBool IsDefunct();
   virtual PRBool Init();
   virtual void Shutdown();
   virtual bool IsPrimaryForNode() const;
 
   // nsAccessible
   virtual nsresult GetARIAState(PRUint32 *aState, PRUint32 *aExtraState);
-  virtual PRUint32 Role();
   virtual PRUint32 NativeRole();
   virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
 
   virtual void InvalidateChildren();
 
 protected:
 
   // nsAccessible
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -1492,18 +1492,17 @@ nsDocAccessible::UpdateTree(nsIContent* 
 
   // Check to see if change occurred inside an alert, and fire an EVENT_ALERT
   // if it did.
   if (aIsInsert && !(updateFlags & eAlertAccessible)) {
     // XXX: tree traversal is perf issue, accessible should know if they are
     // children of alert accessible to avoid this.
     nsAccessible* ancestor = container;
     while (ancestor) {
-      const nsRoleMapEntry* roleMapEntry = ancestor->GetRoleMapEntry();
-      if (roleMapEntry && roleMapEntry->role == nsIAccessibleRole::ROLE_ALERT) {
+      if (ancestor->ARIARole() == nsIAccessibleRole::ROLE_ALERT) {
         FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT,
                                    ancestor->GetNode(), AccEvent::eRemoveDupes,
                                    fromUserInput);
         break;
       }
 
       // Don't climb above this document.
       if (ancestor == this)
@@ -1918,42 +1917,59 @@ nsDocAccessible::UpdateTreeInternal(nsAc
       updateFlags |= UpdateTreeInternal(aContainer, node->GetFirstChild(),
                                         nsnull, aIsInsert, aFireAllEvents,
                                         aFromUserInput);
       continue;
     }
 
     updateFlags |= eAccessible;
 
+    if (!aIsInsert) {
+      // Fire menupopup end event before hide event if a menu goes away.
+
+      // XXX: We don't look into children of hidden subtree to find hiding
+      // menupopup (as we did prior bug 570275) because we don't do that when
+      // menu is showing (and that's impossible until bug 606924 is fixed).
+      // Nevertheless we should do this at least because layout coalesces
+      // the changes before our processing and we may miss some menupopup
+      // events. Now we just want to be consistent in content insertion/removal
+      // handling.
+      if (accessible->ARIARole() == nsIAccessibleRole::ROLE_MENUPOPUP) {
+        nsRefPtr<AccEvent> event =
+          new AccEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END, accessible);
+
+        if (event)
+          FireDelayedAccessibleEvent(event);
+      }
+    }
+
     // Fire show/hide event.
     if (aFireAllEvents) {
       nsRefPtr<AccEvent> event;
       if (aIsInsert)
         event = new AccShowEvent(accessible, node, aFromUserInput);
       else
         event = new AccHideEvent(accessible, node, aFromUserInput);
 
       if (event)
         FireDelayedAccessibleEvent(event);
     }
 
     if (aIsInsert) {
-      const nsRoleMapEntry* roleMapEntry = accessible->GetRoleMapEntry();
-      if (roleMapEntry) {
-        if (roleMapEntry->role == nsIAccessibleRole::ROLE_MENUPOPUP) {
-          // Fire EVENT_MENUPOPUP_START if ARIA menu appears.
-          FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
-                                     node, AccEvent::eRemoveDupes, aFromUserInput);
+      PRUint32 ariaRole = accessible->ARIARole();
+      if (ariaRole == nsIAccessibleRole::ROLE_MENUPOPUP) {
+        // Fire EVENT_MENUPOPUP_START if ARIA menu appears.
+        FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
+                                   node, AccEvent::eRemoveDupes, aFromUserInput);
 
-        } else if (roleMapEntry->role == nsIAccessibleRole::ROLE_ALERT) {
-          // Fire EVENT_ALERT if ARIA alert appears.
-          updateFlags = eAlertAccessible;
-          FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT, node,
-                                     AccEvent::eRemoveDupes, aFromUserInput);
-        }
+      } else if (ariaRole == nsIAccessibleRole::ROLE_ALERT) {
+        // Fire EVENT_ALERT if ARIA alert appears.
+        updateFlags = eAlertAccessible;
+        FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT, node,
+                                   AccEvent::eRemoveDupes, aFromUserInput);
       }
 
       // If focused node has been shown then it means its frame was recreated
       // while it's focused. Fire focus event on new focused accessible. If
       // the queue contains focus event for this node then it's suppressed by
       // this one.
       if (node == gLastFocusedNode) {
         FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_FOCUS,
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -222,17 +222,17 @@ nsRootAccessible::GetStateInternal(PRUin
     *aExtraState |= nsIAccessibleStates::EXT_STATE_MODAL;
   }
 #endif
 
   return NS_OK;
 }
 
 const char* const docEvents[] = {
-#ifdef DEBUG
+#ifdef DEBUG_DRAGDROPSTART
   // Capture mouse over events and fire fake DRAGDROPSTART event to simplify
   // debugging a11y objects with event viewers
   "mouseover",
 #endif
   // capture DOM focus and DOM blur events 
   "focus",
   "blur",
   // capture Form change events 
@@ -616,23 +616,16 @@ nsRootAccessible::HandleEvent(nsIDOMEven
       nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION,
                               treeItemAccessible);
       return NS_OK;
     }
   }
   else
 #endif
   if (eventType.EqualsLiteral("focus")) {
-    if (targetNode == mDocument && mDocument != gLastFocusedNode) {
-      // Got focus event for the window, we will make sure that an accessible
-      // focus event for initial focus is fired. We do this on a short timer
-      // because the initial focus may not have been set yet.
-      NS_DISPATCH_RUNNABLEMETHOD(FireCurrentFocusEvent, this)
-    }
-
     // Keep a reference to the target node. We might want to change
     // it to the individual radio button or selected item, and send
     // the focus event to that.
     nsCOMPtr<nsINode> focusedItem = targetNode;
     if (!treeItemAccessible) {
       nsCOMPtr<nsIDOMXULSelectControlElement> selectControl =
         do_QueryInterface(targetNode);
       if (selectControl) {
@@ -739,17 +732,17 @@ nsRootAccessible::HandleEvent(nsIDOMEven
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_END,
                             accessible, eFromUserInput);
     FireCurrentFocusEvent();
   }
   else if (eventType.EqualsLiteral("ValueChange")) {
     FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
                                targetNode, AccEvent::eRemoveDupes);
   }
-#ifdef DEBUG
+#ifdef DEBUG_DRAGDROPSTART
   else if (eventType.EqualsLiteral("mouseover")) {
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START,
                             accessible);
   }
 #endif
   return NS_OK;
 }
 
--- 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,84 +5,211 @@
 
   <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">
-    function showMenu(aID, aViaDisplayStyle)
+    const kViaDisplayStyle = 0;
+    const kViaVisibilityStyle = 1;
+
+    function focusMenu(aMenuBarID, aMenuID)
     {
-      this.DOMNode = getNode(aID);
+      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, getNode(aParentMenuID))
+      ];
 
       this.invoke = function showMenu_invoke()
       {
-        if (aViaDisplayStyle)
-          this.DOMNode.style.display = "block";
+        if (aHow == kViaDisplayStyle)
+          this.menuNode.style.display = "block";
         else
-          this.DOMNode.style.visibility = "visible";
+          this.menuNode.style.visibility = "visible";
       };
 
       this.getID = function showMenu_getID()
       {
-        return "Show ARIA menu " + aID + " by " +
-          (aViaDisplayStyle ? "display" : "visibility") + " style tricks";
+        return "Show ARIA menu " + aMenuID + " by " +
+          (aHow == kViaDisplayStyle ? "display" : "visibility") +
+          " style tricks";
       };
     }
 
+    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, getNode(aParentMenuID))
+      ];
+
+      this.invoke = function closeMenu_invoke()
+      {
+        // Store menu accessible reference while menu is still open.
+        this.menu = getAccessible(this.menuNode);
+
+        // Hide menu.
+        if (aHow == kViaDisplayStyle)
+          this.menuNode.style.display = "none";
+        else
+          this.menuNode.style.visibility = "hidden";
+      }
+
+      this.getID = function closeMenu_getID()
+      {
+        return "Close ARIA menu " + aMenuID + " by " +
+          (aHow == kViaDisplayStyle ? "display" : "visibility") +
+          " style tricks";
+      }
+
+      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(EVENT_MENUPOPUP_START);
+      gQueue = new eventQueue();
 
-      gQueue.push(new showMenu("menu1", true));
-      gQueue.push(new showMenu("menu2", false));
+      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>
 
 <body>
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=606207"
      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/hyperlink/Makefile.in
+++ b/accessible/tests/mochitest/hyperlink/Makefile.in
@@ -41,14 +41,15 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = accessible/hyperlink
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
+		hyperlink.js \
 		test_general.html \
 		test_general.xul \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/hyperlink/hyperlink.js
@@ -0,0 +1,48 @@
+/**
+ * Focus hyperlink invoker.
+ *
+ * @param aID             [in] hyperlink identifier
+ * @param aSelectedAfter  [in] specifies if hyperlink is selected/focused after
+ *                          the focus
+ */
+function focusLink(aID, aSelectedAfter)
+{
+  this.node = getNode(aID);
+  this.accessible = getAccessible(this.node);
+
+  this.eventSeq = [];
+  this.unexpectedEventSeq = [];
+
+  var checker = new invokerChecker(EVENT_FOCUS, this.accessible);
+  if (aSelectedAfter)
+    this.eventSeq.push(checker);
+  else
+    this.unexpectedEventSeq.push(checker);
+
+  this.invoke = function focusLink_invoke()
+  {
+    is(this.accessible.selected, false,
+       "Wrong selected state before focus for ID " + prettyName(aID) + "!");
+
+    var expectedStates = (aSelectedAfter ? STATE_FOCUSABLE : 0);
+    var unexpectedStates = (!aSelectedAfter ? STATE_FOCUSABLE : 0) | STATE_FOCUSED;
+    testStates(aID, expectedStates, 0, unexpectedStates, 0);
+
+    this.node.focus();
+  }
+
+  this.finalCheck = function focusLink_finalCheck()
+  {
+    is(this.accessible.selected, aSelectedAfter,
+       "Wrong seleccted state after focus for ID " + prettyName(aID) + "!");
+
+    var expectedStates = (aSelectedAfter ? STATE_FOCUSABLE | STATE_FOCUSED : 0);
+    var unexpectedStates = (!aSelectedAfter ? STATE_FOCUSABLE | STATE_FOCUSED : 0);
+    testStates(aID, expectedStates, 0, unexpectedStates, 0);
+  }
+
+  this.getID = function focusLink_getID()
+  {
+    return "focus hyperlink " + prettyName(aID);
+  }
+}
--- a/accessible/tests/mochitest/hyperlink/test_general.html
+++ b/accessible/tests/mochitest/hyperlink/test_general.html
@@ -13,16 +13,21 @@ https://bugzilla.mozilla.org/show_bug.cg
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript"
+          src="hyperlink.js"></script>
 
   <script type="application/javascript">
     function testThis(aID, aAcc, aRole, aAnchors, aName, aValid, aStartIndex,
                       aEndIndex)
     {
       testRole(aAcc, aRole);
       is(aAcc.anchorCount, aAnchors, "Wrong number of anchors for ID "
                                       + aID + "!");
@@ -31,84 +36,62 @@ https://bugzilla.mozilla.org/show_bug.cg
       is(aAcc.valid, aValid, "No correct valid state for ID "
                              + aID + "!");
       is(aAcc.startIndex, aStartIndex, "Wrong startIndex value for ID "
                                        + aID + "!");
       is(aAcc.endIndex, aEndIndex, "Wrong endIndex value for ID "
                                    + aID + "!");
     }
 
-    function testFocus(aID, aAcc, aSelectedBefore, aSelectedAfter)
-    {
-      is(aAcc.selected, aSelectedBefore,
-         "Wrong selected state before focus for ID " + aID + "!");
-      document.getElementById(aID).focus();
-      is(aAcc.selected, aSelectedAfter,
-         "Wrong seleccted state after focus for ID " + aID + "!");
-    }
-
     function testAction(aId, aAcc, aActionName)
     {
       var numActions = aActionName ? 1 : 0;
       is(aAcc.numActions, numActions,
          "Wrong actions number for ID " + aId);
       try {
         is(aAcc.getActionName(0), aActionName,
            "Wrong action name for ID " + aId);
       } catch (e) {
         if (numActions)
           ok(false, "Exception on action name getting for ID " + aId);
         else
           ok(true, "Correct action name for ID " + aId);
       }
     }
 
+    //gA11yEventDumpToConsole = true; // debug stuff
+
+    var gQueue = null;
     function doTest()
     {
       //////////////////////////////////////////////////////////////////////////
       // normal hyperlink
       var normalHyperlinkAcc = getAccessible("NormalHyperlink",
                                              [nsIAccessibleHyperLink]);
       testThis("NormalHyperlink", normalHyperlinkAcc, ROLE_LINK, 1,
                "Mozilla Foundation", true, 17, 18);
       is(normalHyperlinkAcc.getURI(0).spec, "http://www.mozilla.org/", 
          "URI wrong for normalHyperlinkElement!");
-      testStates(normalHyperlinkAcc,
-                 (STATE_FOCUSABLE | STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
-      testFocus("NormalHyperlink", normalHyperlinkAcc, false, true);
-      testStates(normalHyperlinkAcc,
-                 (STATE_FOCUSABLE | STATE_FOCUSED | STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
+      testStates(normalHyperlinkAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
 
       //////////////////////////////////////////////////////////////////////////
       // ARIA hyperlink
       var ariaHyperlinkAcc = getAccessible("AriaHyperlink",
                                            [nsIAccessibleHyperLink]);
       testThis("AriaHyperlink", ariaHyperlinkAcc, ROLE_LINK, 1,
                "Mozilla Foundation Home", true, 30, 31);
-      testStates(ariaHyperlinkAcc,
-                 (STATE_FOCUSABLE | STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
-      testFocus("AriaHyperlink", ariaHyperlinkAcc, false, true);
-      testStates(ariaHyperlinkAcc,
-                 (STATE_FOCUSABLE | STATE_FOCUSED | STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
+      testStates(ariaHyperlinkAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
       testAction("AriaHyperlink", ariaHyperlinkAcc, "click");
 
       //////////////////////////////////////////////////////////////////////////
       // ARIA hyperlink with status invalid
       var invalidAriaHyperlinkAcc = getAccessible("InvalidAriaHyperlink",
                                                   [nsIAccessibleHyperLink]);
       is(invalidAriaHyperlinkAcc.valid, false, "Should not be valid!");
-      testStates(invalidAriaHyperlinkAcc,
-                 (STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL), (STATE_FOCUSABLE));
-      testFocus("InvalidAriaHyperlink", invalidAriaHyperlinkAcc,
-                false, false);
+      testStates(invalidAriaHyperlinkAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
 
       //////////////////////////////////////////////////////////////////////////
       // image map and its link children
       var imageMapHyperlinkAcc = getAccessible("imgmap",
                                                [nsIAccessibleHyperLink]);
       testThis("imgmap", imageMapHyperlinkAcc, ROLE_IMAGE_MAP, 2, "b", true,
                79, 80);
       is(imageMapHyperlinkAcc.getURI(0).spec,
@@ -146,23 +129,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       //////////////////////////////////////////////////////////////////////////
       // normal hyperlink with embedded span
       var hyperlinkWithSpanAcc = getAccessible("LinkWithSpan",
                                                [nsIAccessibleHyperLink]);
       testThis("LinkWithSpan", hyperlinkWithSpanAcc, ROLE_LINK, 1,
                "Heise Online", true, 119, 120);
       is(hyperlinkWithSpanAcc.getURI(0).spec, "http://www.heise.de/", 
          "URI wrong for hyperlinkElementWithSpan!");
-      testStates(hyperlinkWithSpanAcc,
-                 (STATE_FOCUSABLE | STATE_LINKED),
-               (EXT_STATE_HORIZONTAL));
-      testFocus("LinkWithSpan", hyperlinkWithSpanAcc, false, true);
-      testStates(hyperlinkWithSpanAcc,
-                 (STATE_FOCUSABLE | STATE_FOCUSED | STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
+      testStates(hyperlinkWithSpanAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
       testAction("LinkWithSpan", hyperlinkWithSpanAcc, "jump");
 
       //////////////////////////////////////////////////////////////////////////
       // Named anchor, should never have state_linked
       var namedAnchorAcc = getAccessible("namedAnchor",
                                          [nsIAccessibleHyperLink]);
       testThis("namedAnchor", namedAnchorAcc, ROLE_LINK, 1,
                "This should never be of state_linked", true, 196, 197);
@@ -242,17 +219,26 @@ https://bugzilla.mozilla.org/show_bug.cg
       testAction(id, linkAcc, "jump");
 
       //////////////////////////////////////////////////////////////////////////
       // Text accessible shouldn't implement nsIAccessibleHyperLink
       var res = isAccessible(getNode("namedAnchor").firstChild,
                              [nsIAccessibleHyperLink]);
       ok(!res, "Text accessible shouldn't implement nsIAccessibleHyperLink");
 
-      SimpleTest.finish();
+      //////////////////////////////////////////////////////////////////////////
+      // Test focus
+      gQueue = new eventQueue();
+
+      gQueue.push(new focusLink("NormalHyperlink", true));
+      gQueue.push(new focusLink("AriaHyperlink", true));
+      gQueue.push(new focusLink("InvalidAriaHyperlink", false));
+      gQueue.push(new focusLink("LinkWithSpan", true));
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body><a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418368">Mozilla Bug 418368</a
   ><p id="display"></p
--- a/accessible/tests/mochitest/hyperlink/test_general.xul
+++ b/accessible/tests/mochitest/hyperlink/test_general.xul
@@ -12,67 +12,70 @@
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
 
   <script type="application/javascript"
           src="../common.js" />
   <script type="application/javascript"
           src="../role.js" />
   <script type="application/javascript"
           src="../states.js" />
+  <script type="application/javascript"
+          src="../events.js" />
+
+  <script type="application/javascript"
+          src="hyperlink.js" />
 
   <script type="application/javascript">
   <![CDATA[
     function testThis(aID, aAcc, aRole, aAnchorCount, aAnchorName, aURI,
-                      aStartIndex, aEndIndex, aValid, aSelectedBefore,
-                      aSelectedAfter)
+                      aStartIndex, aEndIndex, aValid)
     {
       testRole(aID, aRole);
       is(aAcc.anchorCount, aAnchorCount, "Wrong number of anchors for ID " 
          + aID + "!");
       is(aAcc.getAnchor(0).name, aAnchorName, "Wrong name for ID " + aID + "!");
       is(aAcc.getURI(0).spec, aURI, "URI wrong for ID " + aID + "!");
       is(aAcc.startIndex, aStartIndex, "Wrong startIndex value for ID " + aID 
          + "!");
       is(aAcc.endIndex, aEndIndex, "Wrong endIndex value for ID " + aID + "!");
       is(aAcc.valid, aValid, "Wrong valid state for ID " + aID + "!");      
-
-      is(aAcc.selected, aSelectedBefore, "Wrong focused state before focus for "
-         + aID + "!");
-      document.getElementById(aID).focus();
-      is(aAcc.selected, aSelectedAfter, "Wrong selected state after focus for "
-         + aID + "!");
     }
 
+    var gQueue = null;
     function doTest()
     {
       var linkedLabelAcc = getAccessible("linkedLabel",
                                          [nsIAccessibleHyperLink]);
       testThis("linkedLabel", linkedLabelAcc, ROLE_LINK, 1,
                "Mozilla Foundation home", "http://www.mozilla.org/", 1, 2,
-               true, false, true);
-      testStates(linkedLabelAcc,
-                 (STATE_FOCUSABLE | STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
+               true);
+      testStates(linkedLabelAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
 
       var labelWithValueAcc = getAccessible("linkLabelWithValue",
                                             [nsIAccessibleHyperLink]);
       testThis("linkLabelWithValue", labelWithValueAcc, ROLE_LINK, 1,
                "Mozilla Foundation", "http://www.mozilla.org/", 2, 3, true,
                false, true);
-      testStates(labelWithValueAcc,
-                 (STATE_FOCUSABLE | STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
+      testStates(labelWithValueAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
 
       var normalLabelAcc = getAccessible("normalLabel");
       testRole(normalLabelAcc, ROLE_LABEL);
       is(normalLabelAcc.name, "This label should not be a link",
          "Wrong name for normal label!");
       testStates(normalLabelAcc, 0, 0, (STATE_FOCUSABLE | STATE_LINKED));
 
-      SimpleTest.finish();
+      //////////////////////////////////////////////////////////////////////////
+      // Test focus
+
+      gQueue = new eventQueue();
+
+      gQueue.push(new focusLink("linkedLabel", true));
+      gQueue.push(new focusLink("linkLabelWithValue", true));
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   ]]>
   </script>
 
   <body xmlns="http://www.w3.org/1999/xhtml">
--- 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/states/test_doc.html
+++ b/accessible/tests/mochitest/states/test_doc.html
@@ -1,66 +1,103 @@
 <!DOCTYPE html>
 <html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=454997
-https://bugzilla.mozilla.org/show_bug.cgi?id=467387
-https://bugzilla.mozilla.org/show_bug.cgi?id=509696
--->
 <head>
   <title>states of document</title>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+  <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="../common.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
 
   <script type="application/javascript">
+    function designModeOn()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, document)
+      ];
+
+      this.invoke = function designModeOn_invoke()
+      {
+        document.designMode = "on";
+      }
+
+      this.finalCheck = function designModeOn_finalCheck()
+      {
+        testStates(document, 0, EXT_STATE_EDITABLE);
+        testStates("p", 0, EXT_STATE_EDITABLE);
+        testStates("document", 0, EXT_STATE_EDITABLE);
+        testStates("editable_document", 0, EXT_STATE_EDITABLE);
+      }
+
+      this.getID = function designModeOn_getID()
+      {
+        return "design mode on";
+      }
+    }
+
+    function designModeOff()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, document)
+      ];
+
+      this.invoke = function designModeOn_invoke()
+      {
+        document.designMode = "off";
+      }
+
+      this.finalCheck = function designModeOn_finalCheck()
+      {
+        testStates(document, STATE_READONLY);
+        testStates("document", STATE_READONLY);
+        testStates("editable_document", 0, EXT_STATE_EDITABLE);
+      }
+
+      this.getID = function designModeOn_getID()
+      {
+        return "design mode off";
+      }
+    }
+
+    var gQueue = null;
     function doTest()
     {
       // Bug 566542: root accesible should expose active state when focused.
       testStates(getRootAccessible(), 0, EXT_STATE_ACTIVE);
 
-      // Bug 509696
+      // Bug 509696, 607219.
       testStates(document, STATE_READONLY); // role=""
-      todo(false, "enable commented tests when we support body role changes");
-/*
+
       document.body.setAttribute("role","banner"); // no platform mapping
       testStates(document, STATE_READONLY);
       document.body.setAttribute("role","foo"); // bogus role
       testStates(document, STATE_READONLY);
       document.body.removeAttribute("role");
       testStates(document, STATE_READONLY);
-*/
-      
+
       // Bugs 454997 and 467387
       testStates(document, STATE_READONLY);
       testStates("document", STATE_READONLY);
       testStates("editable_document", 0, EXT_STATE_EDITABLE);
 
-      document.designMode = "on";
-
-      testStates(document, 0, EXT_STATE_EDITABLE);
-      testStates("p", 0, EXT_STATE_EDITABLE);
-      testStates("document", 0, EXT_STATE_EDITABLE);
-      testStates("editable_document", 0, EXT_STATE_EDITABLE);
-
-      document.designMode = "off";
-
-      testStates(document, STATE_READONLY);
-      testStates("document", STATE_READONLY);
-      testStates("editable_document", 0, EXT_STATE_EDITABLE);
-
-      SimpleTest.finish();
+      // Design mode on/off trigger document accessible subtree recreation.
+      gQueue = new eventQueue();
+      gQueue.push(new designModeOn());
+      gQueue.push(new designModeOff());
+      gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 
 <body role="">
@@ -72,16 +109,19 @@ https://bugzilla.mozilla.org/show_bug.cg
      title="nsIAccessible states tests of editable document"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=467387">Mozilla Bug 467387</a>
    <a target="_blank"
      title="Role attribute on body with empty string causes DocAccessible not to have read-only state."
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=509696">Mozilla Bug 509696</a>
   <a target="_blank"
      title="Frame for firefox does not implement the state "active" when firefox is the active frame"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=566542">Mozilla Bug 566542</a>
+  <a target="_blank"
+     title="Dynamic role attribute change on body doesn't affect on document role"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=607219">Mozilla Bug 607219</a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <p id="p">hello</p>
 
--- a/accessible/tests/mochitest/states/test_docarticle.html
+++ b/accessible/tests/mochitest/states/test_docarticle.html
@@ -9,45 +9,87 @@
           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="../common.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
 
   <script type="application/javascript">
-    function doTest()
+    function designModeOn()
     {
-      var docAcc = getAccessible(document, [nsIAccessibleDocument]);
-      if (docAcc) {
-        testStates(docAcc, STATE_READONLY);
-        testStates("aria_article", STATE_READONLY);
-        testStates("editable_aria_article", 0, EXT_STATE_EDITABLE);
-        testStates("article", STATE_READONLY);
-        testStates("editable_article", 0, EXT_STATE_EDITABLE);
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, document)
+      ];
 
+      this.invoke = function designModeOn_invoke()
+      {
         document.designMode = "on";
+      }
 
-        testStates(docAcc, 0, EXT_STATE_EDITABLE);
+      this.finalCheck = function designModeOn_finalCheck()
+      {
+        testStates(document, 0, EXT_STATE_EDITABLE);
         testStates("aria_article", 0, EXT_STATE_EDITABLE);
         testStates("editable_aria_article", 0, EXT_STATE_EDITABLE);
         testStates("article", 0, EXT_STATE_EDITABLE);
         testStates("editable_article", 0, EXT_STATE_EDITABLE);
-  
+      }
+
+      this.getID = function designModeOn_getID()
+      {
+        return "design mode on";
+      }
+    }
+
+    function designModeOff()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, document)
+      ];
+
+      this.invoke = function designModeOn_invoke()
+      {
         document.designMode = "off";
+      }
 
-        testStates(docAcc, STATE_READONLY);
+      this.finalCheck = function designModeOn_finalCheck()
+      {
+        testStates(document, STATE_READONLY);
         testStates("aria_article", STATE_READONLY);
         testStates("editable_aria_article", 0, EXT_STATE_EDITABLE);
         testStates("article", STATE_READONLY);
         testStates("editable_article", 0, EXT_STATE_EDITABLE);
       }
-      SimpleTest.finish();
+
+      this.getID = function designModeOn_getID()
+      {
+        return "design mode off";
+      }
+    }
+
+    var gQueue = null;
+
+    function doTest()
+    {
+      testStates(document, STATE_READONLY);
+      testStates("aria_article", STATE_READONLY);
+      testStates("editable_aria_article", 0, EXT_STATE_EDITABLE);
+      testStates("article", STATE_READONLY);
+      testStates("editable_article", 0, EXT_STATE_EDITABLE);
+
+      // Design mode on/off trigger document accessible subtree recreation.
+      gQueue = new eventQueue();
+      gQueue.push(new designModeOn());
+      gQueue.push(new designModeOff());
+      gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 
 <body role="article">
--- a/accessible/tests/mochitest/test_editabletext_1.html
+++ b/accessible/tests/mochitest/test_editabletext_1.html
@@ -1,25 +1,29 @@
 <!DOCTYPE html>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=452161
 -->
 <head>
   <title>nsIAccessibleEditableText chrome tests</title>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+  <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="common.js"></script>
   <script type="application/javascript"
           src="editabletext.js"></script>
+  <script type="application/javascript"
+          src="events.js"></script>
 
   <script type="application/javascript">
     var gParagraphAcc;
 
     function testEditable(aID)
     {
       var et = new nsEditableText(aID);
 
@@ -55,26 +59,32 @@ https://bugzilla.mozilla.org/show_bug.cg
 
       //////////////////////////////////////////////////////////////////////////
 //      // cutNPasteText
 //      et.cutNPasteText(0, 1, 1, "ehhelloo");
 //      et.cutNPasteText(1, 2, 0, "hehelloo");
 //      et.cutNPasteText(7, 8, 8, "hehelloo");
     }
 
+    function testDocEditableNFinishTest(aDoc)
+    {
+      testEditable(aDoc);
+      SimpleTest.finish();
+    }
+
     function doTest()
     {
       testEditable("input");
       // testEditable("div"); XXX: bug 452599
 
-      var frame = document.getElementById("frame");
+      // Design mode on/off trigger document accessible subtree recreation.
+      var frame = getNode("frame");
+      waitForEvent(EVENT_REORDER, frame.contentDocument,
+                   testDocEditableNFinishTest, null, frame.contentDocument);
       frame.contentDocument.designMode = "on";
-      testEditable(frame.contentDocument);
-
-      SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
 
--- 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/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -432,17 +432,16 @@ pref("dom.disable_window_open_feature.lo
 // allow JS to move and resize existing windows
 pref("dom.disable_window_move_resize",            false);
 // prevent JS from monkeying with window focus, etc
 pref("dom.disable_window_flip",                   true);
 
 // popups.policy 1=allow,2=reject
 pref("privacy.popups.policy",               1);
 pref("privacy.popups.usecustom",            true);
-pref("privacy.popups.firstTime",            true);
 pref("privacy.popups.showBrowserMessage",   true);
 
 pref("privacy.item.cookies",                false);
 
 pref("privacy.clearOnShutdown.history",     true);
 pref("privacy.clearOnShutdown.formdata",    true);
 pref("privacy.clearOnShutdown.passwords",   false);
 pref("privacy.clearOnShutdown.downloads",   true);
--- a/browser/base/content/browser-appmenu.inc
+++ b/browser/base/content/browser-appmenu.inc
@@ -41,42 +41,36 @@
 <menupopup id="appmenu-popup"
 #ifdef MOZ_SERVICES_SYNC
            onpopupshowing="updateEditUIVisibility();gSyncUI.updateUI();">
 #else
            onpopupshowing="updateEditUIVisibility();">
 #endif
   <hbox>
     <vbox id="appmenuPrimaryPane">
-      <hbox flex="1"
-            class="split-menuitem">
-        <menuitem id="appmenu_newTab"
-                  class="menuitem-tooltip split-menuitem-item"
-                  flex="1"
-                  label="&tabCmd.label;"
-                  command="cmd_newNavigatorTab"
-                  key="key_newNavigatorTab"/>
-        <menu class="split-menuitem-menu">
+      <splitmenu id="appmenu_newTab"
+                 label="&tabCmd.label;"
+                 command="cmd_newNavigatorTab"
+                 key="key_newNavigatorTab">
           <menupopup>
             <menuitem id="appmenu_newTab_popup"
                       label="&tabCmd.label;"
                       command="cmd_newNavigatorTab"
                       key="key_newNavigatorTab"/>
             <menuitem id="appmenu_newNavigator"
                       label="&newNavigatorCmd.label;"
                       command="cmd_newNavigator"
                       key="key_newNavigator"/>
             <menuseparator/>
             <menuitem id="appmenu_openFile"
                       label="&openFileCmd.label;"
                       command="Browser:OpenFile"
                       key="openFileKb"/>
           </menupopup>
-        </menu>
-      </hbox>
+      </splitmenu>
       <menuitem id="appmenu_privateBrowsing"
                 class="menuitem-iconic menuitem-iconic-tooltip"
                 label="&privateBrowsingCmd.start.label;"
                 startlabel="&privateBrowsingCmd.start.label;"
                 stoplabel="&privateBrowsingCmd.stop.label;"
                 command="Tools:PrivateBrowsing"
                 key="key_privatebrowsing"/>
       <menuitem label="&goOfflineCmd.label;"
@@ -114,40 +108,35 @@
       <menuitem id="appmenu_savePage"
                 class="menuitem-tooltip"
                 label="&savePageCmd.label;"
                 command="Browser:SavePage"
                 key="key_savePage"/>
       <menuitem id="appmenu_sendLink"
                 label="&sendPageCmd.label;"
                 command="Browser:SendLink"/>
-      <hbox flex="1"
-            class="split-menuitem">
-        <menuitem id="appmenu_print"
-                  class="menuitem-iconic menuitem-iconic-tooltip split-menuitem-item"
-                  flex="1"
-                  label="&printCmd.label;"
-                  command="cmd_print"
-                  key="printKb"/>
-        <menu class="split-menuitem-menu">
+      <splitmenu id="appmenu_print"
+                 iconic="true"
+                 label="&printCmd.label;"
+                 command="cmd_print"
+                 key="printKb">
           <menupopup>
             <menuitem id="appmenu_print_popup"
                       class="menuitem-iconic"
                       label="&printCmd.label;"
                       command="cmd_print"
                       key="printKb"/>
             <menuitem id="appmenu_printPreview"
                       label="&printPreviewCmd.label;"
                       command="cmd_printPreview"/>
             <menuitem id="appmenu_printSetup"
                       label="&printSetupCmd.label;"
                       command="cmd_pageSetup"/>
           </menupopup>
-        </menu>
-      </hbox>
+      </splitmenu>
       <menuseparator class="appmenu-menuseparator"/>
       <menu id="appmenu_webDeveloper"
             label="&appMenuWebDeveloper.label;">
         <menupopup id="appmenu_webDeveloper_popup">
           <menuitem id="appmenu_webConsole"
                     label="&webConsoleCmd.label;"
                     oncommand="HUDConsoleUI.toggleHUD();"
                     key="key_webConsole"/>
@@ -188,38 +177,34 @@
 #ifdef XP_WIN
                 label="&quitApplicationCmdWin.label;"
 #else
                 label="&quitApplicationCmd.label;"
 #endif
                 command="cmd_quitApplication"/>
     </vbox>
     <vbox id="appmenuSecondaryPane">
-      <hbox class="split-menuitem">
-        <menuitem id="appmenu_bookmarks"
-                  class="menuitem-iconic menuitem-iconic-tooltip split-menuitem-item"
-                  flex="1"
-                  label="&bookmarksMenu.label;"
-                  command="Browser:ShowAllBookmarks"
-                  key="manBookmarkKb"/>
-        <menu id="appmenu_bookmarksMenu"
-              class="split-menuitem-menu">
+      <splitmenu id="appmenu_bookmarks"
+                 iconic="true"
+                 label="&bookmarksMenu.label;"
+                 command="Browser:ShowAllBookmarks"
+                 key="manBookmarkKb">
           <menupopup id="appmenu_bookmarksPopup"
                      placespopup="true"
                      context="placesContext"
                      openInTabs="children"
                      oncommand="BookmarksEventHandler.onCommand(event);"
                      onclick="BookmarksEventHandler.onClick(event);"
                      onpopupshowing="BookmarksMenuButton.onPopupShowing(event);
                                      if (!this.parentNode._placesView)
                                        new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
                      tooltip="bhTooltip"
                      popupsinherittooltip="true">
             <menuitem id="appmenu_showAllBookmarks"
-                      label="&showAllBookmarks.label;"
+                      label="&showAllBookmarks2.label;"
                       command="Browser:ShowAllBookmarks"
                       context=""
                       key="manBookmarkKb"/>
             <menuseparator/>
             <menuitem id="appmenu_bookmarkThisPage"
                       class="menuitem-iconic"
                       label="&bookmarkThisPageCmd.label;"
                       command="Browser:AddBookmarkAs"
@@ -255,27 +240,22 @@
             <!-- Bookmarks menu items -->
             <menuseparator builder="end"
                            class="hide-if-empty-places-result"/>
             <menuitem id="appmenu_unsortedBookmarks"
                       label="&appMenuUnsorted.label;"
                       oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"
                       class="menuitem-iconic"/>
           </menupopup>
-        </menu>
-      </hbox>
-      <hbox class="split-menuitem">
-        <menuitem id="appmenu_history"
-                  class="menuitem-iconic menuitem-iconic-tooltip split-menuitem-item"
-                  flex="1"
-                  label="&historyMenu.label;"
-                  command="Browser:ShowAllHistory"
-                  key="showAllHistoryKb"/>
-        <menu id="appmenu_historyMenu"
-              class="split-menuitem-menu">
+      </splitmenu>
+      <splitmenu id="appmenu_history"
+                 iconic="true"
+                 label="&historyMenu.label;"
+                 command="Browser:ShowAllHistory"
+                 key="showAllHistoryKb">
           <menupopup id="appmenu_historyMenupopup"
                      placespopup="true"
                      oncommand="this.parentNode._placesView._onCommand(event);"
                      onclick="checkForMiddleClick(this, event);"
                      onpopupshowing="if (!this.parentNode._placesView)
                                        new HistoryMenu(event);"
                      tooltip="bhTooltip"
                      popupsinherittooltip="true">
@@ -294,80 +274,69 @@
                       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>
-        </menu>
-      </hbox>
+      </splitmenu>
       <menuitem id="appmenu_downloads"
                 class="menuitem-tooltip"
                 label="&downloads.label;"
                 command="Tools:Downloads"
                 key="key_openDownloads"/>
       <spacer id="appmenuSecondaryPane-spacer"/>
       <menuitem id="appmenu_addons"
                 class="menuitem-iconic menuitem-iconic-tooltip"
                 label="&addons.label;"
                 command="Tools:Addons"
                 key="key_openAddons"/>
-      <hbox class="split-menuitem">
-        <menuitem id="appmenu_customize"
+      <splitmenu id="appmenu_customize"
 #ifdef XP_UNIX
-                  label="&preferencesCmdUnix.label;"
+                 label="&preferencesCmdUnix.label;"
 #else
-                  label="&preferencesCmd.label;"
+                 label="&preferencesCmd2.label;"
 #endif
-                  class="split-menuitem-item"
-                  flex="1"
-                  oncommand="openPreferences();"/>
-        <menu class="split-menuitem-menu"
-              label="&preferencesCmd.label;">
+                 oncommand="openPreferences();">
           <menupopup id="appmenu_customizeMenu"
                      onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('appmenu_toggleTabsOnTop').previousSibling);">
             <menuitem id="appmenu_preferences"
 #ifdef XP_UNIX
                       label="&preferencesCmdUnix.label;"
 #else
-                      label="&preferencesCmd.label;"
+                      label="&preferencesCmd2.label;"
 #endif
                       oncommand="openPreferences();"/>
             <menuseparator/>
             <menuseparator/>
             <menuitem id="appmenu_toggleTabsOnTop"
                       label="&viewTabsOnTop.label;"
                       type="checkbox"
                       command="cmd_ToggleTabsOnTop"/>
             <menuitem id="appmenu_toolbarLayout"
                       label="&appMenuToolbarLayout.label;"
                       command="cmd_CustomizeToolbars"/>
           </menupopup>
-        </menu>
-      </hbox>
-      <hbox class="split-menuitem">
-        <menuitem id="appmenu_help"
-                  class="split-menuitem-item"
-                  flex="1"
-                  label="&helpMenu.label;"
-                  oncommand="openHelpLink('firefox-help')"/>
-        <menu class="split-menuitem-menu">
+      </splitmenu>
+      <splitmenu id="appmenu_help"
+                 label="&helpMenu.label;"
+                 oncommand="openHelpLink('firefox-help')">
           <menupopup id="appmenu_helpMenupopup">
             <menuitem id="appmenu_openHelp"
                       label="&helpMenu.label;"
                       oncommand="openHelpLink('firefox-help')"
                       onclick="checkForMiddleClick(this, event);"/>
             <menuitem id="appmenu_gettingStarted"
                       label="&appMenuGettingStarted.label;"
                       oncommand="gBrowser.loadOneTab('http://www.mozilla.com/firefox/central/', {inBackground: false});"
@@ -385,18 +354,17 @@
                       accesskey="&appMenuSafeMode.accesskey;"
                       label="&appMenuSafeMode.label;"
                       oncommand="safeModeRestart();"/>
             <menuseparator/>
             <menuitem id="appmenu_about"
                       label="&aboutProduct.label;"
                       oncommand="openAboutDialog();"/>
           </menupopup>
-        </menu>
-      </hbox>
+      </splitmenu>
 #ifdef MOZ_SERVICES_SYNC
       <spacer flex="1"/>
       <!-- only one of sync-setup or sync-syncnow will be showing at once -->
       <menuitem id="sync-setup-appmenu"
                 label="&syncSetup.label;"
                 observes="sync-setup-state"
                 oncommand="gSyncUI.openSetup()"/>
       <menuitem id="sync-syncnowitem-appmenu"
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -457,17 +457,17 @@
                    oncommand="return FeedHandler.subscribeToFeed(null, event);"
                    onclick="checkForMiddleClick(this, event);"/>
       </menu>
       <menuitem id="menu_bookmarkAllTabs"
                 label="&addCurPagesCmd.label;"
                 command="Browser:BookmarkAllTabs"
                 key="bookmarkAllTabsKb"/>
       <menuitem id="bookmarksShowAll"
-                label="&showAllBookmarks.label;"
+                label="&showAllBookmarks2.label;"
                 command="Browser:ShowAllBookmarks"
                 key="manBookmarkKb"/>
       <menuseparator id="organizeBookmarksSeparator"/>
       <menu id="bookmarksToolbarFolderMenu"
             class="menu-iconic bookmark-item"
             label="&personalbarCmd.label;"
             container="true">
         <menupopup id="bookmarksToolbarFolderPopup"  
@@ -558,18 +558,18 @@
               <menuitem id="sanitizeItem"
                         accesskey="&clearRecentHistory.accesskey;"
                         label="&clearRecentHistory.label;"
                         key="key_sanitize"
                         command="Tools:Sanitize"/>
 #ifndef XP_UNIX
               <menuseparator id="prefSep"/>
               <menuitem id="menu_preferences"
-                        label="&preferencesCmd.label;"
-                        accesskey="&preferencesCmd.accesskey;"
+                        label="&preferencesCmd2.label;"
+                        accesskey="&preferencesCmd2.accesskey;"
                         oncommand="openPreferences();"/>
 #endif
               </menupopup>
             </menu>
 
 #ifdef XP_MACOSX
           <menu id="windowMenu" />
 #endif
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -224,17 +224,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) {
@@ -342,17 +342,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");
   },
@@ -839,21 +840,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.css
+++ b/browser/base/content/browser.css
@@ -131,16 +131,25 @@ toolbar[mode="icons"] > #reload-button[d
 }
 %endif
 
 #browser-bottombox[lwthemefooter="true"] {
   background-repeat: no-repeat;
   background-position: bottom left;
 }
 
+splitmenu {
+  -moz-binding: url("chrome://browser/content/urlbarBindings.xml#splitmenu");
+}
+
+.split-menuitem-item {
+  list-style-image: inherit;
+  -moz-image-region: inherit;
+}
+
 .split-menuitem-menu > .menu-text,
 .split-menuitem-menu > .menu-accel-container {
   display: none;
 }
 
 .menuitem-tooltip {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#menuitem-tooltip");
 }
@@ -439,17 +448,17 @@ window[chromehidden~="toolbar"] toolbar:
 
 #notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
 #notification-popup-box[anchorid="indexedDB-notification-icon"] > #indexedDB-notification-icon,
 #notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon,
 #notification-popup-box[anchorid="password-notification-icon"] > #password-notification-icon {
   display: -moz-box;
 }
 
-#invalid-form-popup {
+#invalid-form-popup > description {
   max-width: 280px;
 }
 
 #geolocation-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#geolocation-notification");
 }
 
 /* override hidden="true" for the status bar compatibility shim
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -580,37 +580,19 @@ const gPopupBlockerObserver = {
     }
     else
       window.openDialog("chrome://browser/content/preferences/permissions.xul",
                         "_blank", "resizable,dialog=no,centerscreen", params);
   },
 
   dontShowMessage: function ()
   {
-#if 0 
-    // Disabled until bug 594294 is fixed.
     var showMessage = gPrefService.getBoolPref("privacy.popups.showBrowserMessage");
-    var firstTime = gPrefService.getBoolPref("privacy.popups.firstTime");
-
-    // If the info message is showing at the top of the window, and the user has never
-    // hidden the message before, show an info box telling the user where the info
-    // will be displayed.
-    if (showMessage && firstTime)
-      this._displayPageReportFirstTime();
-
     gPrefService.setBoolPref("privacy.popups.showBrowserMessage", !showMessage);
-#endif
-
     gBrowser.getNotificationBox().removeCurrentNotification();
-  },
-
-  _displayPageReportFirstTime: function ()
-  {
-    window.openDialog("chrome://browser/content/pageReportFirstTime.xul", "_blank",
-                      "dependent");
   }
 };
 
 const gXPInstallObserver = {
   _findChildShell: function (aDocShell, aSoughtShell)
   {
     if (aDocShell == aSoughtShell)
       return aDocShell;
@@ -1241,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();
@@ -1528,19 +1513,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
@@ -2900,17 +2882,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");
@@ -2943,29 +2925,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 = {};
@@ -2977,17 +2959,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);
@@ -3004,17 +2986,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);
@@ -6799,16 +6781,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;
 }
@@ -7279,17 +7262,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);
@@ -7510,21 +7493,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
@@ -164,21 +164,22 @@
 
     <!-- for search and content formfill/pw manager -->
     <panel type="autocomplete" id="PopupAutoComplete" noautofocus="true" hidden="true"/>
 
     <!-- for url bar autocomplete -->
     <panel type="autocomplete-richlistbox" id="PopupAutoCompleteRichResult" noautofocus="true" hidden="true"/>
 
     <!-- for invalid form error message -->
-    <panel id="invalid-form-popup" noautofocus="true" hidden="true" level="parent">
+    <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"
@@ -619,17 +623,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);
@@ -639,17 +643,17 @@
             <menuitem id="BMB_viewBookmarksToolbar"
                       placesanonid="view-toolbar"
                       toolbarId="PersonalToolbar"
                       type="checkbox"
                       oncommand="onViewToolbarCommand(event)"
                       label="&viewBookmarksToolbar.label;"/>
             <menuseparator/>
             <menuitem id="BMB_bookmarksShowAll"
-                      label="&showAllBookmarks.label;"
+                      label="&showAllBookmarks2.label;"
                       command="Browser:ShowAllBookmarks"
                       key="manBookmarkKb"/>
             <menuseparator/>
             <menuitem id="BMB_bookmarkThisPage"
 #ifndef XP_MACOSX
                       class="menuitem-iconic"
 #endif
                       label="&bookmarkThisPageCmd.label;"
@@ -808,17 +812,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">
@@ -855,40 +859,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;"
deleted file mode 100644
--- a/browser/base/content/pageReportFirstTime.xul
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0"?> 
-# ***** 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 Communicator client code, released
-# March 31, 1998.
-#
-# The Initial Developer of the Original Code is
-# Netscape Communications Corporation.
-# Portions created by the Initial Developer are Copyright (C) 1998-1999
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#   David Hyatt (hyatt@apple.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 *****
-
-<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
-
-<!DOCTYPE dialog [
-  <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
-  %brandDTD;
-  <!ENTITY % pageReportFirstTimeDTD SYSTEM "chrome://browser/locale/pageReportFirstTime.dtd" >
-  %pageReportFirstTimeDTD;
-]>            
- 
-<dialog id="pageReportFirstTime"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        title="&caption.label;"
-        onload="setTimeout(function() { window.sizeToContent(); }, 100);"
-        style="width: 40em;"
-        buttons="accept"
-        persist="screenX screenY"
-        screenX="24" screenY="24">
-              
-  <description>
-    &startDescriptionText.label;
-  </description>
-
-  <separator class="thin"/>
-
-  <hbox pack="center">
-    <!-- insert example here! (bug 594294) -->
-  </hbox>
-
-  <separator class="thin"/>
-
-  <description>
-    &endDescription.label;
-  </description>
-
- </dialog>
--- a/browser/base/content/syncGenericChange.js
+++ b/browser/base/content/syncGenericChange.js
@@ -94,19 +94,20 @@ let Change = {
           document.getElementById("passphraseBackupButtons").hidden = true;
           document.getElementById("generatePassphraseButton").hidden = true;
           document.title = this._str("new.synckey.title");
           introText.textContent = this._str("new.synckey.introText");
           this._dialog.getButton("accept")
               .setAttribute("label", this._str("new.synckey.acceptButton"));
         }
         else {
+          this._passphraseBox.setAttribute("readonly", "true");
           let pp = Weave.Service.passphrase;
-          if (pp.length == 20)
-            pp = gSyncUtils.hyphenatePassphrase(pp);
+          if (Weave.Utils.isPassphrase(pp))
+             pp = Weave.Utils.hyphenatePassphrase(pp);
           document.getElementById("passphraseBox").value = pp;
           document.title = this._str("change.synckey.title");
           introText.innerHTML = this._str("change.synckey.introText");
           introText2.innerHTML = this._str("change.synckey.introText2");
           warningText.innerHTML = this._str("change.synckey2.warningText");
           this._dialog.getButton("accept")
               .setAttribute("label", this._str("change.synckey.acceptButton"));
         }
@@ -143,17 +144,16 @@ let Change = {
   },
 
   _updateStatus: function Change__updateStatus(str, state) {
      this._updateStatusWithString(this._str(str), state);
   },
   
   _updateStatusWithString: function Change__updateStatusWithString(string, state) {
     this._statusRow.hidden = false;
-    document.getElementById("passphraseStrengthRow").hidden = true;
     this._status.value = string;
     this._statusIcon.setAttribute("status", state);
 
     let error = state == "error";
     this._dialog.getButton("cancel").setAttribute("disabled", !error);
     this._dialog.getButton("accept").setAttribute("disabled", !error);
     document.getElementById("printSyncKeyButton").disabled = !error;
     document.getElementById("saveSyncKeyButton").disabled = !error;
@@ -170,25 +170,24 @@ let Change = {
         break;
       case "ChangePassword":
         return this.doChangePassword();
         break;
     }
   },
 
   doGeneratePassphrase: function () {
-    let passphrase = gSyncUtils.generatePassphrase();
+    let passphrase = Weave.Utils.generatePassphrase();
     let el = document.getElementById("passphraseBox");
-    el.value = gSyncUtils.hyphenatePassphrase(passphrase);
-    document.getElementById("passphraseStrengthRow").hidden = true;
+    el.value = Weave.Utils.hyphenatePassphrase(passphrase);
     this._dialog.getButton("accept").disabled = false;
   },
 
   doChangePassphrase: function Change_doChangePassphrase() {
-    let pp = gSyncUtils.normalizePassphrase(this._passphraseBox.value);
+    let pp = Weave.Utils.normalizePassphrase(this._passphraseBox.value);
     if (this._updatingPassphrase) {
       Weave.Service.passphrase = pp;
       if (Weave.Service.login()) {
         this._updateStatus("change.synckey2.success", "success");
         Weave.Service.persistLogin();
       }
       else {
         this._updateStatus("new.passphrase.status.incorrect", "error");
@@ -224,56 +223,42 @@ let Change = {
         this._updateStatus("change.password.status.success", "success");
       else
         this._updateStatus("change.password.status.error", "error");
     }
 
     return false;
   },
 
-  validate: function () {
+  validate: function (event) {
     let valid = false;
     let errorString = "";
 
     if (this._dialogType == "ChangePassword") {
       if (this._currentPasswordInvalid)
         [valid, errorString] = gSyncUtils.validatePassword(this._firstBox);
       else
         [valid, errorString] = gSyncUtils.validatePassword(this._firstBox, this._secondBox);
     }
     else {
-      if (this._updatingPassphrase) {
-        [valid, errorString] = gSyncUtils.validatePassphrase(this._passphraseBox);
-      } else {
-        [valid, errorString] = gSyncUtils.validatePassphrase(this._passphraseBox, true);
-        if (valid)
-          this.displayPassphraseStrength();
-      }
+      if (!this._updatingPassphrase)
+        return;
+
+      if (event.keyCode != event.DOM_VK_BACK_SPACE) {
+        this._passphraseBox.value = Weave.Utils.hyphenatePartialPassphrase(
+          this._passphraseBox.value);
+       }
+      valid = Weave.Utils.isPassphrase(this._passphraseBox.value);
     }
 
     if (errorString == "")
       this._clearStatus();
     else
       this._updateStatusWithString(errorString, "error");
 
     this._statusRow.hidden = valid;
     this._dialog.getButton("accept").disabled = !valid;
   },
 
-  displayPassphraseStrength: function () {
-    let bits = Weave.Utils.passphraseStrength(this._passphraseBox.value);
-    let meter = document.getElementById("passphraseStrength");
-    meter.value = bits;
-    // The generated 20 character passphrase has an entropy of 94 bits
-    // which we consider "strong".
-    if (bits > 94)
-      meter.className = "strong";
-    else if (bits > 47)
-      meter.className = "medium";
-    else
-      meter.className = "";
-    document.getElementById("passphraseStrengthRow").hidden = false;
-  },
-
   _str: function Change__string(str) {
     return this._stringBundle.GetStringFromName(str);
   }
 };
--- a/browser/base/content/syncGenericChange.xul
+++ b/browser/base/content/syncGenericChange.xul
@@ -93,50 +93,31 @@
           <label id="textBox2Label" control="textBox2"/>
           <textbox id="textBox2" type="password" oninput="Change.validate()"/>
           <spacer/>
         </row>
         <row id="passphraseRow" align="center">
           <label id="passphraseLabel" control="passphraseBox"/>
           <textbox id="passphraseBox"
                    onfocus="this.select()"
-                   oninput="Change.validate()"/>
+                   onkeyup="Change.validate(event)"/>
           <label id="generatePassphraseButton"
                  value="&syncKeyGenerate.label;"
                  class="text-link inline-link"
                  onclick="event.stopPropagation();
                           Change.doGeneratePassphrase();"/>
         </row>
       </rows>
     </grid>
 
     <vbox id="feedback" pack="center">
       <hbox id="statusRow" align="center">
         <image id="statusIcon" class="statusIcon"/>
         <label id="status" class="status" value=" "/>
       </hbox>
-
-      <vbox id="passphraseStrengthRow" hidden="true" pack="end">
-        <hbox>
-          <label id="passphraseStrengthLabel"
-                 control="passphraseStrength"
-                 value="&syncKeyStrength.label;"/>
-          <progressmeter id="passphraseStrength"
-                         aria-labelledby="passphraseStrengthLabel"
-                         max="128"
-                         value="0"
-                         flex="1"/>
-        </hbox>
-        <hbox align="right" flex="1">
-          <label class="text-link inline-link"
-                 onclick="event.stopPropagation();
-                          gSyncUtils.openSyncKeyHelp();"
-                 value="&syncKeyHelp.label;"/>
-        </hbox>
-      </vbox>
     </vbox>
 
     <hbox id="passphraseBackupButtons" pack="center">
       <button id="printSyncKeyButton"
               label="&button.syncKeyBackup.print.label;"
               accesskey="&button.syncKeyBackup.print.accesskey;"
               oncommand="gSyncUtils.passphrasePrint('passphraseBox');"/>
       <button id="saveSyncKeyButton"
--- a/browser/base/content/syncSetup.js
+++ b/browser/base/content/syncSetup.js
@@ -70,17 +70,16 @@ var gSyncSetup = {
   _disabledSites: [],
   _remoteSites: [Weave.Service.serverURL, "https://api-secure.recaptcha.net"],
 
   status: {
     password: false,
     email: false,
     server: false
   },
-  _haveSyncKeyBackup: false,
 
   get _usingMainServers() {
     if (this._settingUpNew)
       return document.getElementById("serverType").selectedItem.value == "main";
 
     return document.getElementById("existingServerType").selectedItem.value == "main";
   },
 
@@ -138,17 +137,18 @@ var gSyncSetup = {
   },
 
   useExistingAccount: function () {
     this._settingUpNew = false;
     this.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
   },
 
   onResetPassphrase: function () {
-    document.getElementById("existingPassphrase").value = Weave.Service.passphrase;
+    document.getElementById("existingPassphrase").value = 
+      Weave.Utils.hyphenatePassphrase(Weave.Service.passphrase);
     this.wizard.advance();
   },
 
   onLoginStart: function () {
     this.toggleLoginFeedback(false);
   },
 
   onLoginEnd: function () {
@@ -194,16 +194,24 @@ var gSyncSetup = {
         // otherwise, fall through
       case "wipeClient":
       case "wipeRemote":
         Weave.Svc.Prefs.set("firstSync", action);
         break;
     }
   },
 
+  onPassphraseKeyUp: function (event) {
+    if (event.keyCode != event.DOM_VK_BACK_SPACE) {
+      let el = event.target;
+      el.value = Weave.Utils.hyphenatePartialPassphrase(el.value);
+    }
+    this.checkFields();
+  },
+
   // fun with validation!
   checkFields: function () {
     this.wizard.canAdvance = this.readyToAdvance();
   },
 
   readyToAdvance: function () {
     switch (this.wizard.pageIndex) {
       case INTRO_PAGE:
@@ -212,31 +220,30 @@ var gSyncSetup = {
         for (i in this.status) {
           if (!this.status[i])
             return false;
         }
         if (this._usingMainServers)
           return document.getElementById("tos").checked;
 
         return true;
-      case NEW_ACCOUNT_PP_PAGE:
-        return this._haveSyncKeyBackup && this.checkPassphrase();
       case EXISTING_ACCOUNT_LOGIN_PAGE:
         let hasUser = document.getElementById("existingAccountName").value != "";
         let hasPass = document.getElementById("existingPassword").value != "";
         if (hasUser && hasPass) {
           if (this._usingMainServers)
             return true;
 
           if (this._validateServer(document.getElementById("existingServerURL"), false))
             return true;
         }
         return false;
       case EXISTING_ACCOUNT_PP_PAGE:
-        return document.getElementById("existingPassphrase").value != "";
+        let el = document.getElementById("existingPassphrase");
+        return Weave.Utils.isPassphrase(el.value);
     }
     // we probably shouldn't get here
     return true;
   },
 
   onEmailInput: function () {
     // Check account validity when the user stops typing for 1 second.
     if (this._checkAccountTimer)
@@ -295,90 +302,21 @@ var gSyncSetup = {
 
     let feedback = document.getElementById("passwordFeedbackRow");
     this._setFeedback(feedback, valid, errorString);
 
     this.status.password = valid;
     this.checkFields();
   },
 
-  onPassphraseChange: function () {
-    // Ignore if there's no actual change from the generated one.
-    let el = document.getElementById("weavePassphrase");
-    if (gSyncUtils.normalizePassphrase(el.value) == Weave.Service.passphrase) {
-      el = document.getElementById("generatePassphraseButton");
-      el.hidden = true;
-      this._haveCustomSyncKey = false;
-      return;
-    }
-
-    this._haveSyncKeyBackup = true;
-    this._haveCustomSyncKey = true;
-    el = document.getElementById("generatePassphraseButton");
-    el.hidden = false;
-    this.checkFields();
-  },
-
   onPassphraseGenerate: function () {
-    let passphrase = gSyncUtils.generatePassphrase();
+    let passphrase = Weave.Utils.generatePassphrase();
     Weave.Service.passphrase = passphrase;
     let el = document.getElementById("weavePassphrase");
-    el.value = gSyncUtils.hyphenatePassphrase(passphrase);
-
-    el = document.getElementById("generatePassphraseButton");
-    el.hidden = true;
-    document.getElementById("passphraseStrengthRow").hidden = true;
-    let feedback = document.getElementById("passphraseFeedbackRow");
-    this._setFeedback(feedback, true, "");
-  },
-
-  afterBackup: function () {
-    this._haveSyncKeyBackup = true;
-    this.checkFields();
-  },
-
-  checkPassphrase: function () {
-    let el1 = document.getElementById("weavePassphrase");
-    let valid, str;
-    // xxxmpc - hack, sigh
-    if (el1.value == document.getElementById("weavePassword").value) {
-      valid = false;
-      str = Weave.Utils.getErrorString("change.synckey.sameAsPassword");
-    }
-    else {
-      [valid, str] = gSyncUtils.validatePassphrase(el1);
-    }
-
-    let feedback = document.getElementById("passphraseFeedbackRow");
-    this._setFeedback(feedback, valid, str);
-    if (!valid) {
-      // Hide strength meter if we're displaying an error.
-      document.getElementById("passphraseStrengthRow").hidden = true;
-      return valid;
-    }
-
-    // No passphrase strength meter for the generated key.
-    if (!this._haveCustomSyncKey)
-      return valid;
-
-    // Display passphrase strength
-    let pp = document.getElementById("weavePassphrase").value;
-    let bits = Weave.Utils.passphraseStrength(pp);
-    let meter = document.getElementById("passphraseStrength");
-    meter.value = bits;
-    // The generated 20 character passphrase has an entropy of 94 bits
-    // which we consider "strong".
-    if (bits > 94)
-      meter.className = "strong";
-    else if (bits > 47)
-      meter.className = "medium";
-    else
-      meter.className = "";
-    document.getElementById("passphraseStrengthRow").hidden = false;
-    return valid;
+    el.value = Weave.Utils.hyphenatePassphrase(passphrase);
   },
 
   onPageShow: function() {
     switch (this.wizard.pageIndex) {
       case INTRO_PAGE:
         this.wizard.getButton("next").hidden = true;
         this.wizard.getButton("back").hidden = true;
         this.wizard.getButton("extra1").hidden = true;
@@ -396,16 +334,19 @@ var gSyncSetup = {
         // fall through
       case EXISTING_ACCOUNT_LOGIN_PAGE:
         this.checkFields();
         this.wizard.getButton("next").hidden = false;
         this.wizard.getButton("back").hidden = false;
         this.wizard.getButton("extra1").hidden = false;
         this.wizard.canRewind = true;
         break;
+      case EXISTING_ACCOUNT_PP_PAGE:
+        this.checkFields();
+        break;
       case SETUP_SUCCESS_PAGE:
         this.wizard.canRewind = false;
         this.wizard.getButton("back").hidden = true;
         this.wizard.getButton("next").hidden = true;
         this.wizard.getButton("cancel").hidden = true;
         this.wizard.getButton("finish").hidden = false;
         this._handleSuccess();
         break;
@@ -481,41 +422,41 @@ var gSyncSetup = {
           this.wizard.pageIndex = SETUP_SUCCESS_PAGE;
           return false;
         }
 
         image.setAttribute("status", "error");
         label.value = Weave.Utils.getErrorString(error);
         return false;
       case NEW_ACCOUNT_PP_PAGE:
-        if (this._haveCustomSyncKey)
-          Weave.Service.passphrase = document.getElementById("weavePassphrase").value;
         // Time to load the captcha.
         // First check for NoScript and whitelist the right sites.
         this._handleNoScript(true);
         this.captchaBrowser.loadURI(Weave.Service.miscAPI + "captcha_html");
         break;
       case EXISTING_ACCOUNT_LOGIN_PAGE:
         Weave.Service.account = document.getElementById("existingAccountName").value;
         Weave.Service.password = document.getElementById("existingPassword").value;
-        Weave.Service.passphrase = document.getElementById("existingPassphrase").value;
+        Weave.Service.passphrase = Weave.Utils.normalizePassphrase(
+            document.getElementById("existingPassphrase").value);
+
         // verifyLogin() will likely return false because we probably don't
         // have a passphrase yet (unless the user already entered it
         // and hit the back button).
         if (!Weave.Service.verifyLogin()
             && Weave.Status.login != Weave.LOGIN_FAILED_NO_PASSPHRASE
             && Weave.Status.login != Weave.LOGIN_FAILED_INVALID_PASSPHRASE) {
           let feedback = document.getElementById("existingPasswordFeedbackRow");
           this._setFeedbackMessage(feedback, false, Weave.Status.login);
           return false;
         }
         break;
       case EXISTING_ACCOUNT_PP_PAGE:
         let pp = document.getElementById("existingPassphrase").value;
-        Weave.Service.passphrase = gSyncUtils.normalizePassphrase(pp);
+        Weave.Service.passphrase = Weave.Utils.normalizePassphrase(pp);
         if (Weave.Service.login())
           this.wizard.pageIndex = SETUP_SUCCESS_PAGE;
         return false;
       case OPTIONS_PAGE:
         let desc = document.getElementById("mergeChoiceRadio").selectedIndex;
         // No confirmation needed on new account setup or merge option
         // with existing account.
         if (this._settingUpNew || (!this._resettingSync && desc == 0))
--- a/browser/base/content/syncSetup.xul
+++ b/browser/base/content/syncSetup.xul
@@ -198,76 +198,35 @@
               onextra1="gSyncSetup.onSyncOptions()"
               onpageshow="gSyncSetup.onPageShow();">
     <description>
       &setup.newSyncKeyPage.description.label;
     </description>
     <spacer/>
 
     <groupbox>
-      <hbox>
-        <label value="&syncKeyEntry.label;"
-               accesskey="&syncKeyEntry.accesskey;"
-               control="weavePassphrase"/>
-        <spacer flex="1" />
-        <label id="generatePassphraseButton"
-               value="&syncKeyGenerate.label;"
-               class="text-link inline-link"
-               onclick="event.stopPropagation();
-                        gSyncSetup.onPassphraseGenerate();"/>
-      </hbox>
+      <label value="&syncKeyEntry.label;"
+             accesskey="&syncKeyEntry.accesskey;"
+             control="weavePassphrase"/>
       <textbox id="weavePassphrase"
-               onkeyup="gSyncSetup.onPassphraseChange()"
-               onchange="gSyncSetup.onPassphraseChange()"
-               onfocus="this.select();
-                        gSyncSetup.afterBackup();"/>
-
-      <vbox id="passphraseFeedback" pack="center">
-        <hbox id="passphraseFeedbackRow" hidden="true" align="center">
-          <spacer/>
-          <hbox>
-            <image class="statusIcon"/>
-            <label class="status" value=" "/>
-          </hbox>
-        </hbox>
-
-        <vbox id="passphraseStrengthRow" hidden="true" pack="end">
-          <hbox>
-            <label id="passphraseStrengthLabel"
-                   control="passphraseStrength"
-                   value="&syncKeyStrength.label;"/>
-            <progressmeter id="passphraseStrength"
-                           aria-labelledby="passphraseStrengthLabel"
-                           max="128"
-                           value="0"
-                           flex="1"/>
-          </hbox>
-          <hbox align="right" flex="1">
-            <label class="text-link inline-link"
-                   onclick="event.stopPropagation();
-                            gSyncUtils.openSyncKeyHelp();"
-                   value="&syncKeyHelp.label;"/>
-          </hbox>
-        </vbox>
-      </vbox>
+               readonly="true"
+               onfocus="this.select();"/>
     </groupbox>
 
     <groupbox align="center">
       <description>&syncKeyBackup.description;</description>
       <hbox>
         <button id="printSyncKeyButton"
                 label="&button.syncKeyBackup.print.label;"
                 accesskey="&button.syncKeyBackup.print.accesskey;"
-                oncommand="gSyncUtils.passphrasePrint('weavePassphrase');
-                           gSyncSetup.afterBackup();"/>
+                oncommand="gSyncUtils.passphrasePrint('weavePassphrase');"/>
         <button id="saveSyncKeyButton"
                 label="&button.syncKeyBackup.save.label;"
                 accesskey="&button.syncKeyBackup.save.accesskey;"
-                oncommand="gSyncUtils.passphraseSave('weavePassphrase');
-                           gSyncSetup.afterBackup();"/>
+                oncommand="gSyncUtils.passphraseSave('weavePassphrase');"/>
       </hbox>
     </groupbox>
   </wizardpage>
 
   <wizardpage label="&setup.captchaPage2.title.label;"
               onextra1="gSyncSetup.onSyncOptions()">
     <vbox flex="1" align="center">
       <browser height="150"
@@ -355,22 +314,23 @@
               <label value="&connecting.label;"/>
           </hbox>
           </row>
         </rows>
       </grid>
   </wizardpage>
 
   <wizardpage id="existingPassphraseEntry"
+              label="&setup.existingSyncKeyPage.title;"
               onextra1="gSyncSetup.onSyncOptions()"
-              label="&setup.existingSyncKeyPage.title;">
+              onpageshow="gSyncSetup.onPageShow()">
     <description>&setup.existingSyncKeyPage.description;</description>
     <textbox id="existingPassphrase"
-             onkeyup="gSyncSetup.checkFields(event)"
-             onchange="gSyncSetup.checkFields(event)"/>
+             onkeyup="gSyncSetup.onPassphraseKeyUp(event)"
+             onchange="gSyncSetup.checkFields()"/>
     <hbox id="passphrase-throbber" hidden="true">
       <image/>
       <label value="&verifying.label;"/>
     </hbox>
     <hbox align="left" id="existingPassphraseFeedbackBox">
       <spacer/>
       <hbox>
         <image class="statusIcon"/>
--- a/browser/base/content/syncUtils.js
+++ b/browser/base/content/syncUtils.js
@@ -100,65 +100,30 @@ let gSyncUtils = {
   openToS: function () {
     this._openLink(Weave.Svc.Prefs.get("termsURL"));
   },
 
   openPrivacyPolicy: function () {
     this._openLink(Weave.Svc.Prefs.get("privacyURL"));
   },
 
-  openSyncKeyHelp: function () {
-    this._openLink(Weave.Svc.Prefs.get("syncKeyHelpURL"));
-  },
-
   // xxxmpc - fix domain before 1.3 final (bug 583652)
   _baseURL: "http://www.mozilla.com/firefox/sync/",
 
   openFirstClientFirstrun: function () {
     let url = this._baseURL + "firstrun.html";
     this._openLink(url);
   },
 
   openAddedClientFirstrun: function () {
     let url = this._baseURL + "secondrun.html";
     this._openLink(url);
   },
 
   /**
-   * Generate 20 random characters a-z
-   */
-  generatePassphrase: function() {
-    let rng = Cc["@mozilla.org/security/random-generator;1"]
-                .createInstance(Ci.nsIRandomGenerator);
-    let bytes = rng.generateRandomBytes(20);
-    return [String.fromCharCode(97 + Math.floor(byte * 26 / 256))
-            for each (byte in bytes)].join("");
-  },
-
-  /**
-   * Hyphenate a 20 character passphrase in 4 groups of 5.
-   */
-  hyphenatePassphrase: function(passphrase) {
-    return passphrase.slice(0, 5) + '-'
-         + passphrase.slice(5, 10) + '-'
-         + passphrase.slice(10, 15) + '-'
-         + passphrase.slice(15, 20);
-  },
-
-  /**
-   * Remove hyphens as inserted by hyphenatePassphrase().
-   */
-  normalizePassphrase: function(pp) {
-    if (pp.length == 23 && pp[5] == '-' && pp[11] == '-' && pp[17] == '-')
-      return pp.slice(0, 5) + pp.slice(6, 11)
-           + pp.slice(12, 17) + pp.slice(18, 23);
-    return pp;
-  },
-
-  /**
    * Prepare an invisible iframe with the passphrase backup document.
    * Used by both the print and saving methods.
    *
    * @param elid : ID of the form element containing the passphrase.
    * @param callback : Function called once the iframe has loaded.
    */
   _preparePPiframe: function(elid, callback) {
     let pp = document.getElementById(elid).value;
@@ -279,41 +244,10 @@ let gSyncUtils = {
         valid = true;
       else if (val1.length < Weave.MIN_PASS_LENGTH)
         error = "change.password.tooShort";
       else if (val1 != val2)
         error = "change.password.mismatch";
     }
     let errorString = error ? Weave.Utils.getErrorString(error) : "";
     return [valid, errorString];
-  },
-
-  /**
-   * validatePassphrase
-   *
-   * @param el : the textbox element
-   * @param change : indicate whether this signifies a passphrase change
-   * 
-   * returns [valid, errorString]
-   */
-  validatePassphrase: function (el, change) {
-    let valid = false;
-    let val = el.value;
-    let error = "";
-
-    if (val.length < Weave.MIN_PP_LENGTH)
-      error = "change.synckey.tooShort";
-    else if (val == Weave.Service.username)
-      error = "change.synckey.sameAsUsername";
-    else if (val == Weave.Service.account)
-      error = "change.synckey.sameAsEmail";
-    else if (val == Weave.Service.password)
-      error = "change.synckey.sameAsPassword";
-    else if (change && val == Weave.Service.passphrase)
-      error = "change.synckey.sameAsSyncKey";
-    else
-      valid = true;
-
-    let errorString = error ? Weave.Utils.getErrorString(error) : "";
-    return [valid, errorString];
   }
-}
-
+};
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1305,23 +1305,24 @@
               let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
               if (aAllowThirdPartyFixup)
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
               if (aFromExternal)
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL;
               try {
                 b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData);
 
-                // We start our browsers out as inactive, and then maintain
-                // activeness in the tab switcher.
-                b.docShell.isActive = false;
               }
               catch (ex) { }
             }
 
+            // We start our browsers out as inactive, and then maintain
+            // activeness in the tab switcher.
+            b.docShell.isActive = false;
+
             // Check if we're opening a tab related to the current tab and
             // move it to after the current tab.
             // aReferrerURI is null or undefined if the tab is opened from
             // an external application or bookmark, i.e. somewhere other
             // than the current tab.
             if ((aRelatedToCurrent == null ? aReferrerURI : aRelatedToCurrent) &&
                 Services.prefs.getBoolPref("browser.tabs.insertRelatedAfterCurrent")) {
               let newTabPos = (this._lastRelatedTab ||
@@ -3288,17 +3289,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/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -1836,17 +1836,17 @@ let GroupItems = {
       gBrowser.visibleTabs.some(function(tab) {
         if (!tab.pinned && tab != tabItem.tab) {
           otherTab = tab;
           return true;
         }
         return false;
       });
 
-      if (otherTab) {
+      if (otherTab && otherTab.tabItem) {
         // the first visible tab belongs to a group, add the new tabItem into 
         // that group
         if (otherTab.tabItem.parent) {
           let groupItem = otherTab.tabItem.parent;
           groupItem.add(tabItem);
           this.setActiveGroupItem(groupItem);
           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/tabitems.js
+++ b/browser/base/content/tabview/tabitems.js
@@ -63,18 +63,19 @@ function TabItem(tab, options) {
     .addClass('tab')
     .html("<div class='thumb'>" +
           "<img class='cached-thumb' style='display:none'/><canvas/></div>" +
           "<div class='favicon'><img/></div>" +
           "<span class='tab-title'>&nbsp;</span>"
     )
     .appendTo('body');
 
+  this._cachedImageData = null;
+  this.shouldHideCachedData = false;
   this.canvasSizeForced = false;
-  this.isShowingCachedData = false;
   this.favEl = (iQ('.favicon', $div))[0];
   this.favImgEl = (iQ('.favicon>img', $div))[0];
   this.nameEl = (iQ('.tab-title', $div))[0];
   this.thumbEl = (iQ('.thumb', $div))[0];
   this.canvasEl = (iQ('.thumb canvas', $div))[0];
   this.cachedThumbEl = (iQ('img.cached-thumb', $div))[0];
 
   this.tabCanvas = new TabCanvas(this.tab, this.canvasEl);
@@ -238,54 +239,85 @@ TabItem.prototype = Utils.extend(new Ite
   // size of thumbnail on screen. Note that this call does not nest, unlike
   // <TabItems.resumePainting>; if you call forceCanvasSize multiple
   // times, you just need a single unforce to clear them all.
   unforceCanvasSize: function TabItem_unforceCanvasSize() {
     this.canvasSizeForced = false;
   },
 
   // ----------
+  // Function: isShowingCachedData
+  // Returns a boolean indicates whether the cached data is being displayed or
+  // not. 
+  isShowingCachedData: function() {
+    return (this._cachedImageData != null);
+  },
+
+  // ----------
   // Function: showCachedData
   // Shows the cached data i.e. image and title.  Note: this method should only
   // be called at browser startup with the cached data avaliable.
+  //
+  // Parameters:
+  //   tabData - the tab data
   showCachedData: function TabItem_showCachedData(tabData) {
-    this.isShowingCachedData = true;
-    var $nameElement = iQ(this.nameEl);
-    var $canvasElement = iQ(this.canvasEl);
-    var $cachedThumbElement = iQ(this.cachedThumbEl);
-    $cachedThumbElement.attr("src", tabData.imageData).show();
+    if (!this._cachedImageData) {
+      TabItems.cachedDataCounter++;
+      this.tab.linkedBrowser._tabViewTabItemWithCachedData = this;
+      if (TabItems.cachedDataCounter == 1)
+        gBrowser.addTabsProgressListener(TabItems.tabsProgressListener);
+    }
+    this._cachedImageData = tabData.imageData;
+    let $nameElement = iQ(this.nameEl);
+    let $canvasElement = iQ(this.canvasEl);
+    let $cachedThumbElement = iQ(this.cachedThumbEl);
+    $cachedThumbElement.attr("src", this._cachedImageData).show();
     $canvasElement.css({opacity: 0.0});
     $nameElement.text(tabData.title ? tabData.title : "");
   },
 
   // ----------
   // Function: hideCachedData
   // Hides the cached data i.e. image and title and show the canvas.
   hideCachedData: function TabItem_hideCachedData() {
-    var $canvasElement = iQ(this.canvasEl);
-    var $cachedThumbElement = iQ(this.cachedThumbEl);
+    let $canvasElement = iQ(this.canvasEl);
+    let $cachedThumbElement = iQ(this.cachedThumbEl);
     $cachedThumbElement.hide();
     $canvasElement.css({opacity: 1.0});
-    this.isShowingCachedData = false;
+    if (this._cachedImageData) {
+      TabItems.cachedDataCounter--;
+      this._cachedImageData = null;
+      this.tab.linkedBrowser._tabViewTabItemWithCachedData = null;
+      if (TabItems.cachedDataCounter == 0)
+        gBrowser.removeTabsProgressListener(TabItems.tabsProgressListener);
+    }
   },
 
   // ----------
   // Function: getStorageData
   // Get data to be used for persistent storage of this object.
   //
   // Parameters:
   //   getImageData - true to include thumbnail pixels (and page title as well); default false
   getStorageData: function TabItem_getStorageData(getImageData) {
+    let imageData = null;
+
+    if (getImageData) { 
+      if (this._cachedImageData)
+        imageData = this._cachedImageData;
+      else if (this.tabCanvas)
+        imageData = this.tabCanvas.toImageData();
+    }
+
     return {
       bounds: this.getBounds(),
       userSize: (Utils.isPoint(this.userSize) ? new Point(this.userSize) : null),
       url: this.tab.linkedBrowser.currentURI.spec,
       groupID: (this.parent ? this.parent.id : 0),
-      imageData: (getImageData && this.tabCanvas ?
-                  this.tabCanvas.toImageData() : null),
+      imageData: imageData,
       title: getImageData && this.tab.label || null
     };
   },
 
   // ----------
   // Function: save
   // Store persistent for this object.
   //
@@ -706,39 +738,53 @@ TabItem.prototype = Utils.extend(new Ite
 // Singleton for managing <TabItem>s
 let TabItems = {
   minTabWidth: 40,
   tabWidth: 160,
   tabHeight: 120,
   fontSize: 9,
   items: [],
   paintingPaused: 0,
+  cachedDataCounter: 0,  // total number of cached data being displayed.
+  tabsProgressListener: null,
   _tabsWaitingForUpdate: [],
   _heartbeatOn: false, // see explanation at startHeartbeat() below
   _heartbeatTiming: 100, // milliseconds between _checkHeartbeat() calls
   _lastUpdateTime: Date.now(),
   _eventListeners: [],
   tempCanvas: null,
 
   // ----------
   // Function: init
   // Set up the necessary tracking to maintain the <TabItems>s.
   init: function TabItems_init() {
     Utils.assert(window.AllTabs, "AllTabs must be initialized first");
-    var self = this;
+    let self = this;
 
     let $canvas = iQ("<canvas>");
     $canvas.appendTo(iQ("body"));
     $canvas.hide();
     this.tempCanvas = $canvas[0];
     // 150 pixels is an empirical size, below which FF's drawWindow()
     // algorithm breaks down
     this.tempCanvas.width = 150;
     this.tempCanvas.height = 150;
 
+    this.tabsProgressListener = {
+      onStateChange: function(browser, webProgress, request, stateFlags, status) {
+        if ((stateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
+            (stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)) {
+          // browser would only has _tabViewTabItemWithCachedData if 
+          // it's showing cached data.
+          if (browser._tabViewTabItemWithCachedData)
+            browser._tabViewTabItemWithCachedData.shouldHideCachedData = true;
+        }
+      }
+    };
+
     // When a tab is opened, create the TabItem
     this._eventListeners["open"] = function(tab) {
       if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
         return;
 
       self.link(tab);
     }
     // When a tab's content is loaded, show the canvas and hide the cached data
@@ -768,16 +814,19 @@ let TabItems = {
       self.link(tab, {immediately: true});
       self.update(tab);
     });
   },
 
   // ----------
   // Function: uninit
   uninit: function TabItems_uninit() {
+    if (this.tabsProgressListener)
+      gBrowser.removeTabsProgressListener(this.tabsProgressListener);
+
     for (let name in this._eventListeners) {
       AllTabs.unregister(name, this._eventListeners[name]);
     }
     this.items.forEach(function(tabItem) {
       for (let x in tabItem) {
         if (typeof tabItem[x] == "object")
           tabItem[x] = null;
       }
@@ -800,17 +849,17 @@ let TabItems = {
 
       let shouldDefer = (
         this.isPaintingPaused() ||
         this._tabsWaitingForUpdate.length ||
         Date.now() - this._lastUpdateTime < this._heartbeatTiming
       );
 
       let isCurrentTab = (
-        !UI._isTabViewVisible() &&
+        !UI.isTabViewVisible() &&
         tab == gBrowser.selectedTab
       );
 
       if (shouldDefer && !isCurrentTab) {
         if (this._tabsWaitingForUpdate.indexOf(tab) == -1)
           this._tabsWaitingForUpdate.push(tab);
         this.startHeartbeat();
       } else
@@ -854,17 +903,17 @@ let TabItems = {
           this.reconnect(tabItem);
 
         tabItem.save();
       }
 
       // ___ label
       let label = tab.label;
       let $name = iQ(tabItem.nameEl);
-      if (!tabItem.isShowingCachedData && $name.text() != label)
+      if (!tabItem.isShowingCachedData() && $name.text() != label)
         $name.text(label);
 
       // ___ thumbnail
       let $canvas = iQ(tabItem.canvasEl);
       if (!tabItem.canvasSizeForced) {
         let w = $canvas.width();
         let h = $canvas.height();
         if (w != tabItem.canvasEl.width || h != tabItem.canvasEl.height) {
@@ -874,18 +923,17 @@ let TabItems = {
       }
 
       this._lastUpdateTime = Date.now();
       tabItem._lastTabUpdateTime = this._lastUpdateTime;
 
       tabItem.tabCanvas.paint();
 
       // ___ cache
-      // TODO: this logic needs to be better; hiding too soon now
-      if (tabItem.isShowingCachedData && !tab.hasAttribute("busy"))
+      if (tabItem.isShowingCachedData() && tabItem.shouldHideCachedData)
         tabItem.hideCachedData();
     } catch(e) {
       Utils.log(e);
     }
   },
 
   // ----------
   // Function: link
@@ -1094,26 +1142,18 @@ let TabItems = {
             // if it matches the selected tab or no active tab and the browser 
             // tab is hidden, the active group item would be set.
             if (item.tab == gBrowser.selectedTab || 
                 (!GroupItems.getActiveGroupItem() && !item.tab.hidden))
               GroupItems.setActiveGroupItem(item.parent);
           }
         }
 
-        if (tabData.imageData) {
+        if (tabData.imageData)
           item.showCachedData(tabData);
-          // the code in the progress listener doesn't fire sometimes because
-          // tab is being restored so need to catch that.
-          setTimeout(function() {
-            if (item && item.isShowingCachedData) {
-              item.hideCachedData();
-            }
-          }, 15000);
-        }
 
         item.reconnected = true;
         found = {addedToGroup: tabData.groupID};
       } else {
         // We should never have any orphaned tabs. Therefore, item is not 
         // connected if it has no parent and GroupItems.newTab() would handle 
         // the group creation.
         item.reconnected = (item.parent != null);
--- 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);
@@ -198,17 +201,17 @@ let UI = {
       iQ(window).resize(function() {
         self._resize();
       });
 
       // ___ setup observer to save canvas images
       var observer = {
         observe : function(subject, topic, data) {
           if (topic == "quit-application-requested") {
-            if (self._isTabViewVisible()) {
+            if (self.isTabViewVisible()) {
               GroupItems.removeHiddenGroups();
               TabItems.saveAll(true);
             }
             self._save();
           }
         }
       };
       Services.obs.addObserver(observer, "quit-application-requested", false);
@@ -367,19 +370,19 @@ let UI = {
         self._activeTab = null;
       });
 
       this._activeTab.makeActive();
     }
   },
 
   // ----------
-  // Function: _isTabViewVisible
+  // Function: isTabViewVisible
   // Returns true if the TabView UI is currently shown.
-  _isTabViewVisible: function UI__isTabViewVisible() {
+  isTabViewVisible: function UI_isTabViewVisible() {
     return gTabViewDeck.selectedIndex == 1;
   },
 
   // ---------
   // Function: _initPageDirection
   // Initializes the page base direction
   _initPageDirection: function UI__initPageDirection() {
     let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
@@ -390,17 +393,17 @@ let UI = {
   },
 
   // ----------
   // Function: showTabView
   // Shows TabView and hides the main browser UI.
   // Parameters:
   //   zoomOut - true for zoom out animation, false for nothing.
   showTabView: function UI_showTabView(zoomOut) {
-    if (this._isTabViewVisible())
+    if (this.isTabViewVisible())
       return;
 
     // initialize the direction of the page
     this._initPageDirection();
 
     var self = this;
     var currentTab = this._currentTab;
     var item = null;
@@ -456,17 +459,17 @@ let UI = {
 
     TabItems.resumePainting();
   },
 
   // ----------
   // Function: hideTabView
   // Hides TabView and shows the main browser UI.
   hideTabView: function UI_hideTabView() {
-    if (!this._isTabViewVisible())
+    if (!this.isTabViewVisible())
       return;
 
     // another tab might be select if user decides to stay on a page when
     // a onclose confirmation prompts.
     GroupItems.removeHiddenGroups();
     TabItems.pausePainting();
 
     this._reorderTabsOnHide.forEach(function(groupItem) {
@@ -552,18 +555,18 @@ let UI = {
     // don't reenter Panorama due to all of the session restore tab
     // manipulation (which otherwise we might). When transitioning away from
     // PB, we reenter Panorama if we had been there directly before PB.
     function pbObserver(aSubject, aTopic, aData) {
       if (aTopic == "private-browsing") {
         self._privateBrowsing.transitionStage = 3;
         if (aData == "enter") {
           // If we are in Tab View, exit. 
-          self._privateBrowsing.wasInTabView = self._isTabViewVisible();
-          if (self._isTabViewVisible())
+          self._privateBrowsing.wasInTabView = self.isTabViewVisible();
+          if (self.isTabViewVisible())
             self.goToTab(gBrowser.selectedTab);
         }
       } else if (aTopic == "private-browsing-change-granted") {
         if (aData == "enter" || aData == "exit") {
           self._privateBrowsing.transitionStage = 1;
           self._privateBrowsing.transitionMode = aData;
         }
       }
@@ -591,17 +594,17 @@ let UI = {
     this._eventListeners.close = function(tab) {
       if (tab.ownerDocument.defaultView != gWindow)
         return;
 
       // if it's an app tab, remove it from all the group items
       if (tab.pinned)
         GroupItems.removeAppTab(tab);
         
-      if (self._isTabViewVisible()) {
+      if (self.isTabViewVisible()) {
         // just closed the selected tab in the TabView interface.
         if (self._currentTab == tab)
           self._closedSelectedTabInTabView = true;
       } else {
         // If we're currently in the process of entering private browsing,
         // we don't want to go to the Tab View UI. 
         if (self._privateBrowsing.transitionStage > 0)
           return; 
@@ -704,42 +707,53 @@ 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)) {
+    if (this.isTabViewVisible() &&
+        (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())
+    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.
@@ -774,31 +788,31 @@ let UI = {
 
   // ----------
   // Function: setReorderTabsOnHide
   // Sets the groupItem which the tab items' tabs should be re-ordered when
   // switching to the main browser UI.
   // Parameters:
   //   groupItem - the groupItem which would be used for re-ordering tabs.
   setReorderTabsOnHide: function UI_setReorderTabsOnHide(groupItem) {
-    if (this._isTabViewVisible()) {
+    if (this.isTabViewVisible()) {
       var index = this._reorderTabsOnHide.indexOf(groupItem);
       if (index == -1)
         this._reorderTabsOnHide.push(groupItem);
     }
   },
 
   // ----------
   // Function: setReorderTabItemsOnShow
   // Sets the groupItem which the tab items should be re-ordered when
   // switching to the tab view UI.
   // Parameters:
   //   groupItem - the groupItem which would be used for re-ordering tab items.
   setReorderTabItemsOnShow: function UI_setReorderTabItemsOnShow(groupItem) {
-    if (!this._isTabViewVisible()) {
+    if (!this.isTabViewVisible()) {
       var index = this._reorderTabItemsOnShow.indexOf(groupItem);
       if (index == -1)
         this._reorderTabItemsOnShow.push(groupItem);
     }
   },
   
   // ----------
   updateTabButton: function UI__updateTabButton() {
@@ -1093,17 +1107,17 @@ let UI = {
     if (typeof force == "undefined")
       force = false;
 
     if (!this._pageBounds)
       return;
 
     // If TabView isn't focused and is not showing, don't perform a resize.
     // This resize really slows things down.
-    if (!force && !this._isTabViewVisible())
+    if (!force && !this.isTabViewVisible())
       return;
 
     var oldPageBounds = new Rect(this._pageBounds);
     var newPageBounds = Items.getPageBounds();
     if (newPageBounds.equals(oldPageBounds))
       return;
 
     var items = Items.getTopLevelItems();
@@ -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/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -193,16 +193,17 @@ endif
                  browser_sanitize-sitepermissions.js \
                  browser_sanitize-timespans.js \
                  browser_sanitizeDialog.js \
                  browser_scope.js \
                  browser_selectTabAtIndex.js \
                  browser_tab_dragdrop2.js \
                  browser_tab_dragdrop2_frame1.xul \
                  browser_tabfocus.js \
+                 browser_tabs_isActive.js \
                  browser_tabs_owner.js \
                  browser_visibleFindSelection.js \
                  browser_visibleTabs.js \
                  browser_visibleTabs_contextMenu.js \
                  browser_visibleTabs_bookmarkAllPages.js \
                  browser_visibleTabs_bookmarkAllTabs.js \
                  browser_visibleTabs_tabPreview.js \
                  bug592338.html \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_tabs_isActive.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  test_tab("about:blank");
+  test_tab("about:license");
+}
+
+function test_tab(url) {
+  let originalTab = gBrowser.selectedTab;
+  let newTab = gBrowser.addTab(url, {skipAnimation: true});
+  is(tabIsActive(newTab), false, "newly added " + url + " tab is not active");
+  is(tabIsActive(originalTab), true, "original tab is active initially");
+
+  gBrowser.selectedTab = newTab;
+  is(tabIsActive(newTab), true, "newly added " + url + " tab is active after selection");
+  is(tabIsActive(originalTab), false, "original tab is not active while unselected");
+
+  gBrowser.selectedTab = originalTab;
+  is(tabIsActive(newTab), false, "newly added " + url + " tab is not active after switch back");
+  is(tabIsActive(originalTab), true, "original tab is active again after switch back");
+  
+  gBrowser.removeTab(newTab);
+}
+
+function tabIsActive(tab) {
+  let browser = tab.linkedBrowser;
+  return browser.docShell.isActive;
+}
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -58,21 +58,24 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug594176.js \
                  browser_tabview_bug595191.js \
                  browser_tabview_bug595518.js \
                  browser_tabview_bug595521.js \
                  browser_tabview_bug595560.js \
                  browser_tabview_bug595804.js \
                  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 \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug597248.js
@@ -0,0 +1,214 @@
+/* ***** 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 tabview bug 597248 test.
+ *
+ * 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 newWin;
+let restoredWin;
+let newTabOne;
+let newTabTwo;
+let restoredNewTabOneLoaded = false;
+let restoredNewTabTwoLoaded = false;
+let frameInitialized = false;
+
+function test() {
+  waitForExplicitFinish();
+
+  // open a new window 
+  newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
+  newWin.addEventListener("load", function(event) {
+    newWin.removeEventListener("load", arguments.callee, false);
+    setupOne();
+  }, false);
+}
+
+function setupOne() {
+  let loadedCount = 0;
+  let allLoaded = function() {
+    if (++loadedCount == 2) {
+      newWin.addEventListener("tabviewshown", setupTwo, false);
+      newWin.TabView.toggle();
+    }
+  }
+  
+  newTabOne = newWin.gBrowser.tabs[0];
+  newTabTwo = newWin.gBrowser.addTab();
+  load(newTabOne, "http://mochi.test:8888/", allLoaded);
+  load(newTabTwo, "http://mochi.test:8888/browser/browser/base/content/test/tabview/dummy_page.html", allLoaded);
+}
+
+function setupTwo() {
+  newWin.removeEventListener("tabviewshown", setupTwo, false);
+
+  let contentWindow = newWin.document.getElementById("tab-view").contentWindow;
+
+  let tabItems = contentWindow.TabItems.getItems();
+  is(tabItems.length, 2, "There should be 2 tab items before closing");
+
+  // force all canvas to update
+  tabItems.forEach(function(tabItem) {
+    contentWindow.TabItems._update(tabItem.tab);
+  });
+
+  let checkDataAndCloseWindow = function() {
+    // check the storage for stored image data.
+    tabItems.forEach(function(tabItem) {
+      let tabData = contentWindow.Storage.getTabData(tabItem.tab);
+      ok(tabData && tabData.imageData, "TabItem has stored image data before closing");
+    });
+
+    // close the new window and restore it.
+    newWin.addEventListener("unload", function(event) {
+      newWin.removeEventListener("unload", arguments.callee, false);
+      newWin = null;
+
+      // restore window and test it
+      restoredWin = undoCloseWindow();
+      restoredWin.addEventListener("load", function(event) {
+        restoredWin.removeEventListener("load", arguments.callee, false);
+
+        // setup tab variables and listen to the load progress.
+        newTabOne = restoredWin.gBrowser.tabs[0];
+        newTabTwo = restoredWin.gBrowser.tabs[1];
+        restoredWin.gBrowser.addTabsProgressListener(gTabsProgressListener);
+
+        // execute code when the frame isninitialized.
+        restoredWin.addEventListener("tabviewframeinitialized", onTabViewFrameInitialized, false);
+      }, false);
+    }, false);
+
+    newWin.close();
+  }
+
+  // stimulate a quit application requested so the image data gets stored.
+  let quitRequestObserver = function(aSubject, aTopic, aData) {
+    ok(aTopic == "quit-application-requested" &&
+        aSubject instanceof Ci.nsISupportsPRBool,
+        "Received a quit request and going to deny it");
+    Services.obs.removeObserver(quitRequestObserver, "quit-application-requested", false);
+
+    aSubject.data = true;
+    // save all images is execuated when "quit-application-requested" topic is 
+    // announced so executeSoon is used to avoid racing condition.
+    executeSoon(checkDataAndCloseWindow);
+  }
+  Services.obs.addObserver(quitRequestObserver, "quit-application-requested", false);
+  ok(!Application.quit(), "Tried to quit and canceled it");
+}
+
+let gTabsProgressListener = {
+  onStateChange: function(browser, webProgress, request, stateFlags, status) {
+    if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
+         stateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
+      if (newTabOne.linkedBrowser == browser)
+        restoredNewTabOneLoaded = true;
+      else if (newTabTwo.linkedBrowser == browser)
+        restoredNewTabTwoLoaded = 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) {
+        if (frameInitialized) {
+          // since a tabs progress listener is used in the code to set 
+          // tabItem.shouldHideCachedData, executeSoon is used to avoid a racing
+          // condition.
+          executeSoon(updateAndCheck); 
+        }
+        restoredWin.gBrowser.removeTabsProgressListener(gTabsProgressListener);
+      }
+    }
+  }
+};
+
+function onTabViewFrameInitialized() {
+  restoredWin.removeEventListener("tabviewframeinitialized", onTabViewFrameInitialized, false);
+
+  let contentWindow = restoredWin.document.getElementById("tab-view").contentWindow;
+
+  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;
+  }
+
+  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) {
+    contentWindow.TabItems._update(tabItem.tab);
+    ok(!tabItem.isShowingCachedData(), "Tab item is not showing cached data anymore");
+  });
+
+  // clean up and finish
+  restoredWin.close();
+  finish();
+}
+
+function load(tab, url, callback) {
+  tab.linkedBrowser.addEventListener("load", function (event) {
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
+    callback();
+  }, true);
+  tab.linkedBrowser.loadURI(url);
+}
+
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"
@@ -1020,16 +1020,41 @@
         link.value = gNavigatorBundle.getString("geolocation.learnMore");
         
         let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter);
         link.href = formatter.formatURLPref("browser.geolocation.warning.infoURL");
       ]]></constructor>
     </implementation>
   </binding>
 
+  <binding id="splitmenu">
+    <content>
+      <xul:menuitem anonid="item" flex="1"
+                    class="menuitem-tooltip split-menuitem-item"
+                    xbl:inherits="label,key"/>
+      <xul:menu anonid="menu" class="split-menuitem-menu"
+                oncommand="event.stopPropagation();">
+        <children includes="menupopup"/>
+      </xul:menu>
+    </content>
+
+    <implementation>
+      <constructor><![CDATA[
+        if (this.getAttribute("iconic") == "true") {
+          this.item.classList.remove("menuitem-tooltip");
+          this.item.classList.add("menuitem-iconic-tooltip");
+          this.item.classList.add("menuitem-iconic");
+        }
+      ]]></constructor>
+      <field name="item" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "item");
+      </field>
+    </implementation>
+  </binding>
+
   <binding id="menuitem-tooltip" extends="chrome://global/content/bindings/menu.xml#menuitem">
     <implementation>
       <constructor><![CDATA[
         this.setAttribute("tooltiptext", this.getAttribute("acceltext"));
         // TODO: Simplify this to this.setAttribute("acceltext", "") once bug
         // 592424 is fixed
         document.getAnonymousElementByAttribute(this, "anonid", "accel").firstChild.setAttribute("value", "");
       ]]></constructor>
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -33,17 +33,16 @@ browser.jar:
 *       content/browser/pageinfo/pageInfo.css         (content/pageinfo/pageInfo.css)
 *       content/browser/pageinfo/pageInfo.xml         (content/pageinfo/pageInfo.xml)
 *       content/browser/pageinfo/feeds.js             (content/pageinfo/feeds.js)
 *       content/browser/pageinfo/feeds.xml            (content/pageinfo/feeds.xml)
 *       content/browser/pageinfo/permissions.js       (content/pageinfo/permissions.js)
 *       content/browser/pageinfo/security.js          (content/pageinfo/security.js)
 *       content/browser/openLocation.js               (content/openLocation.js)
 *       content/browser/openLocation.xul              (content/openLocation.xul)
-*       content/browser/pageReportFirstTime.xul       (content/pageReportFirstTime.xul)
 *       content/browser/safeMode.js                   (content/safeMode.js)
 *       content/browser/safeMode.xul                  (content/safeMode.xul)
 *       content/browser/sanitize.js                   (content/sanitize.js)
 *       content/browser/sanitize.xul                  (content/sanitize.xul)
 *       content/browser/sanitizeDialog.js             (content/sanitizeDialog.js)
         content/browser/sanitizeDialog.css            (content/sanitizeDialog.css)
 *       content/browser/tabbrowser.css                (content/tabbrowser.css)
 *       content/browser/tabbrowser.xml                (content/tabbrowser.xml)
--- 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
@@ -400,16 +400,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/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -98,17 +98,17 @@ can reach it easily. -->
 
 <!ENTITY bookmarksMenu.label "Bookmarks">
 <!ENTITY bookmarksMenu.accesskey "B">
 <!ENTITY bookmarkThisPageCmd.label "Bookmark This Page">
 <!ENTITY bookmarkThisPageCmd.commandkey "d">
 <!ENTITY subscribeToPageMenupopup.label "Subscribe to This Page">
 <!ENTITY subscribeToPageMenuitem.label "Subscribe to This Page…">
 <!ENTITY addCurPagesCmd.label "Bookmark All Tabs…">
-<!ENTITY showAllBookmarks.label "Show All Bookmarks…">
+<!ENTITY showAllBookmarks2.label "Show All Bookmarks">
 <!ENTITY bookmarkAllCmd.label "Bookmark All Tabs…">
 <!ENTITY bookmarksToolbarChevron.tooltip "Show more bookmarks">
 
 <!ENTITY backCmd.label                "Back">
 <!ENTITY backCmd.accesskey            "B">
 <!ENTITY backButton.tooltip           "Go back one page">
 <!ENTITY forwardCmd.label             "Forward">
 <!ENTITY forwardCmd.accesskey         "F">
@@ -232,18 +232,18 @@ can reach it easily. -->
 <!ENTITY pasteCmd.key           "V">  
 <!ENTITY pasteCmd.accesskey         "P"> 
 <!ENTITY deleteCmd.label          "Delete">  
 <!ENTITY deleteCmd.key            "D">  
 <!ENTITY deleteCmd.accesskey        "D"> 
 <!ENTITY selectAllCmd.label         "Select All">  
 <!ENTITY selectAllCmd.key         "A">  
 <!ENTITY selectAllCmd.accesskey       "A"> 
-<!ENTITY preferencesCmd.label       "Options…">
-<!ENTITY preferencesCmd.accesskey     "O"> 
+<!ENTITY preferencesCmd2.label       "Options">
+<!ENTITY preferencesCmd2.accesskey     "O">
 <!ENTITY preferencesCmdUnix.label       "Preferences">
 <!ENTITY preferencesCmdUnix.accesskey     "n"> 
 
 <!ENTITY clearRecentHistory.label               "Clear Recent History…">
 <!ENTITY clearRecentHistory.accesskey           "H">
 
 <!-- LOCALIZATION NOTE : These two strings can share an access key beause they never appear together on the menu -->
 <!ENTITY privateBrowsingCmd.start.label         "Start Private Browsing">
deleted file mode 100644
--- a/browser/locales/en-US/chrome/browser/pageReportFirstTime.dtd
+++ /dev/null
@@ -1,7 +0,0 @@
-<!ENTITY startDescriptionText.label        "A web site has attempted to open a pop-up window without your permission. &brandShortName; has automatically closed the pop-up window.">
-
-<!ENTITY endDescription.label              "You can click on this icon to see which sites &brandShortName; blocked and to allow those sites to open pop-ups if they are required for the site to function correctly.">
-
-<!ENTITY caption.label                     "About Pop-up Blocking">
-
-<!ENTITY done.label "Done">
--- a/browser/locales/en-US/chrome/browser/syncSetup.dtd
+++ b/browser/locales/en-US/chrome/browser/syncSetup.dtd
@@ -38,18 +38,16 @@
 <!ENTITY setup.tosAgree2.accesskey  "">
 
 <!-- New Account Page 2: Sync Key -->
 <!ENTITY setup.newSyncKeyPage.title.label "&brandShortName; Cares About Your Privacy">
 <!ENTITY setup.newSyncKeyPage.description.label "To ensure your total privacy, all of your data is encrypted prior to being uploaded. The Sync Key which is necessary to decrypt your data is not uploaded.">
 <!ENTITY syncKeyEntry.label        "Your Sync Key">
 <!ENTITY syncKeyEntry.accesskey    "K">
 <!ENTITY syncKeyGenerate.label     "Generate">
-<!ENTITY syncKeyStrength.label     "Strength:">
-<!ENTITY syncKeyHelp.label         "What does the strength mean?">
 <!ENTITY syncKeyBackup.description "Your Sync Key is required to access &syncBrand.fullName.label; on other machines. Please create a backup copy. We cannot help you recover your Sync Key.">
 
 <!ENTITY button.syncKeyBackup.print.label     "Print…">
 <!ENTITY button.syncKeyBackup.print.accesskey "P">
 <!ENTITY button.syncKeyBackup.save.label      "Save…">
 <!ENTITY button.syncKeyBackup.save.accesskey  "S">
 
 <!-- New Account Page 3: Captcha -->
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -14,17 +14,16 @@
 *   locale/browser/browser.dtd                     (%chrome/browser/browser.dtd)
     locale/browser/baseMenuOverlay.dtd             (%chrome/browser/baseMenuOverlay.dtd)
     locale/browser/browser.properties              (%chrome/browser/browser.properties)
     locale/browser/inspector.properties            (%chrome/browser/inspector.properties)
     locale/browser/openLocation.dtd                (%chrome/browser/openLocation.dtd)
     locale/browser/openLocation.properties         (%chrome/browser/openLocation.properties)
 *   locale/browser/pageInfo.dtd                    (%chrome/browser/pageInfo.dtd)
     locale/browser/pageInfo.properties             (%chrome/browser/pageInfo.properties)
-    locale/browser/pageReportFirstTime.dtd         (%chrome/browser/pageReportFirstTime.dtd)
     locale/browser/quitDialog.properties           (%chrome/browser/quitDialog.properties)
 *   locale/browser/safeMode.dtd                    (%chrome/browser/safeMode.dtd)
     locale/browser/sanitize.dtd                    (%chrome/browser/sanitize.dtd)
     locale/browser/search.properties               (%chrome/browser/search.properties)
     locale/browser/searchbar.dtd                   (%chrome/browser/searchbar.dtd)
     locale/browser/engineManager.dtd               (%chrome/browser/engineManager.dtd)
     locale/browser/engineManager.properties        (%chrome/browser/engineManager.properties)
     locale/browser/setDesktopBackground.dtd        (%chrome/browser/setDesktopBackground.dtd)
--- a/browser/locales/shipped-locales
+++ b/browser/locales/shipped-locales
@@ -1,62 +1,70 @@
 af
 ak
 ar
 be
 bg
 bn-BD
+bn-IN
 br
 ca
 cs
 da
 de
 el
 en-GB
 en-US
 en-ZA
 eo
 es-AR
+es-CL
 es-ES
 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/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -1111,17 +1111,16 @@ toolbar[iconsize="small"] #feed-button {
   padding: 10px;
 }
 
 /* Invalid form popup */
 #invalid-form-popup {
   -moz-appearance: none;
   background-color: #fffcd6;
   border: 1px solid #dad8b6;
-  padding: 5px 5px 5px 5px;
   font-weight: bold;
 }
 
 /* Notification popup */
 #notification-popup {
   margin: 4px 0;
   min-width: 280px;
   padding: 10px;
--- a/browser/themes/gnomestripe/browser/syncCommon.css
+++ b/browser/themes/gnomestripe/browser/syncCommon.css
@@ -35,30 +35,11 @@ dialog#change-dialog {
 image#syncIcon {
   list-style-image: url("chrome://browser/skin/sync-32.png");
 }
 
 #introText {
   margin-top: 2px;
 }
 
-#feedback,
-#passphraseFeedback {
-  height: 4em;
-}
-
-#passphraseStrength {
-  -moz-appearance: none;
-  height: 10px;
-  margin: 4px 0;
+#feedback {
+  height: 2em;
 }
-
-#passphraseStrength > .progress-bar {
-  background-color: #ff0000;
-}
-
-#passphraseStrength.medium > .progress-bar {
-  background-color: #ffcc33;
-}
-
-#passphraseStrength.strong > .progress-bar {
-  background-color: #00ff00;
-}
--- 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,41 +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;
-}
-
-/* Invalid form popup */
-#invalid-form-popup {
-  -moz-appearance: none;
-  background-color: #fffcd6;
-  border: 1px solid #dad8b6;
-  padding: 5px 5px 5px 5px;
-  font-weight: bold;
-}
-
-#notification-popup {
-  margin-left: -16px;
-  margin-right: -16px;
-}
-
 #notification-popup-box {
   margin: 0 3px;
 }
 
 .notification-anchor-icon {
   width: 16px;
   height: 16px;
   margin: 0 2px;
@@ -2104,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/syncCommon.css
+++ b/browser/themes/pinstripe/browser/syncCommon.css
@@ -35,31 +35,11 @@ dialog#change-dialog {
 image#syncIcon {
   list-style-image: url("chrome://browser/skin/sync-32.png");
 }
 
 #introText {
   margin-top: 2px;
 }
 
-#feedback,
-#passphraseFeedback {
-  height: 4em;
-}
-
-#passphraseStrength {
-  -moz-binding: url("chrome://global/content/bindings/progressmeter.xml#progressmeter");
-  -moz-appearance: none;
-  height: 10px;
-  margin: 4px 0;
+#feedback {
+  height: 2em;
 }
-
-#passphraseStrength > .progress-bar {
-  background-color: #ff0000;
-}
-
-#passphraseStrength.medium > .progress-bar {
-  background-color: #ffcc33;
-}
-
-#passphraseStrength.strong > .progress-bar {
-  background-color: #00ff00;
-}
--- 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;
@@ -200,23 +185,23 @@
   }
 
   .tabbrowser-tab:not(:-moz-lwtheme) {
     text-shadow: none;
   }
 
   .tabbrowser-tab:not(:-moz-lwtheme):not([selected="true"]),
   .tabs-newtab-button:not(:-moz-lwtheme) {
-    background-image: -moz-linear-gradient(hsla(214,15%,80%,.8), hsla(214,15%,65%,.8) 50%);
+    background-image: -moz-linear-gradient(hsl(214,15%,80%), hsl(214,15%,65%) 50%);
     color: black;
   }
 
   .tabbrowser-tab:not(:-moz-lwtheme):not([selected="true"]):hover,
   .tabs-newtab-button:not(:-moz-lwtheme):hover {
-    background-image: -moz-linear-gradient(hsla(214,15%,90%,.8), hsla(214,15%,75%,.8) 50%);
+    background-image: -moz-linear-gradient(hsl(214,15%,90%), hsl(214,15%,75%) 50%);
   }
 
   #allTabs-panel,
   #ctrlTab-panel {
     background: transparent;
     -moz-appearance: -moz-win-glass;
     border-radius: 0;
     border: none;
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -203,17 +203,17 @@
 #appmenuPrimaryPane {
   -moz-border-end: 1px solid ThreeDShadow;
 }
 
 @media all and (-moz-windows-default-theme) {
   #appmenu-popup {
     -moz-appearance: none;
     background: white;
-    border: 1px solid rgba(0,0,0,.5);
+    border: 1px solid ThreeDShadow;
   }
   #appmenuPrimaryPane {
     background-color: rgba(255,255,255,0.5);
     padding: 2px;
   }
   #appmenuSecondaryPane {
     background-color: #f1f5fb;
     box-shadow: 1px 0 2px rgb(204,214,234) inset;
@@ -222,16 +222,61 @@
     padding-top: 2px;
     padding-bottom: 2px;
     font-family: "Segoe UI Semibold", "Segoe UI", sans-serif;
   }
   #appmenuSecondaryPane:-moz-locale-dir(rtl) {
     box-shadow: -1px 0 2px rgb(204,214,234) inset;
   }
 
+%ifdef WINSTRIPE_AERO
+  #appmenuPrimaryPane menupopup {
+    -moz-appearance: none;
+    background-image: -moz-linear-gradient(left, white 26px, ThreeDLightShadow 26px,
+                                           ThreeDLightShadow 27px, ThreeDHighlight 27px,
+                                           ThreeDHighlight 28px, white 28px);
+    border: 3px solid;
+    -moz-border-top-colors: ThreeDShadow white;
+    -moz-border-bottom-colors: ThreeDShadow white;
+    -moz-border-left-colors: ThreeDShadow white;
+    -moz-border-right-colors: ThreeDShadow white;
+  }
+%endif
+
+  #appmenuSecondaryPane menupopup {
+    -moz-appearance: none;
+%ifdef WINSTRIPE_AERO
+    background-image: -moz-linear-gradient(left, #f1f5fb 26px, ThreeDLightShadow 26px,
+                                           ThreeDLightShadow 27px, ThreeDHighlight 27px,
+                                           ThreeDHighlight 28px, #f1f5fb 28px);
+    border: 3px solid;
+    -moz-border-top-colors: ThreeDShadow #f1f5fb;
+    -moz-border-bottom-colors: ThreeDShadow #f1f5fb;
+    -moz-border-left-colors: ThreeDShadow #f1f5fb;
+    -moz-border-right-colors: ThreeDShadow #f1f5fb;
+%else
+    background-color: #f1f5fb;
+    border: 1px solid ThreeDShadow;
+    padding: 2px;
+%endif
+  }
+
+%ifdef WINSTRIPE_AERO
+  #appmenuPrimaryPane menupopup:-moz-locale-dir(rtl) {
+    background-image: -moz-linear-gradient(right, white 26px, ThreeDLightShadow 26px,
+                                           ThreeDLightShadow 27px, ThreeDHighlight 27px,
+                                           ThreeDHighlight 28px, white 28px);
+  }
+  #appmenuSecondaryPane menupopup:-moz-locale-dir(rtl) {
+    background-image: -moz-linear-gradient(right, #f1f5fb 26px, ThreeDLightShadow 26px,
+                                           ThreeDLightShadow 27px, ThreeDHighlight 27px,
+                                           ThreeDHighlight 28px, #f1f5fb 28px);
+  }
+%endif
+
   .appmenu-menuseparator {
     -moz-appearance: none;
     margin-top: 3px;
     margin-bottom: 3px;
 %ifdef WINSTRIPE_AERO
     -moz-margin-start: 30px;
 %else
     -moz-margin-start: -moz-calc(1.45em + 4px);
@@ -1316,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");
@@ -1803,36 +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;
-}
-
-/* Invalid form popup */
-#invalid-form-popup {
-  -moz-appearance: none;
-  background-color: #fffcd6;
-  border: 1px solid #dad8b6;
-  padding: 5px 5px 5px 5px;
-  font-weight: bold;
-}
-
-/* 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);
@@ -1889,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/syncCommon.css
+++ b/browser/themes/winstripe/browser/syncCommon.css
@@ -35,30 +35,11 @@ dialog#change-dialog {
 image#syncIcon {
   list-style-image: url("chrome://browser/skin/sync-32.png");
 }
 
 #introText {
   margin-top: 2px;
 }
 
-#feedback,
-#passphraseFeedback {
-  height: 4em;
-}
-
-#passphraseStrength {
-  -moz-appearance: none;
-  height: 10px;
-  margin: 4px 0;
+#feedback {
+  height: 2em;
 }
-
-#passphraseStrength > .progress-bar {
-  background-color: #ff0000;
-}
-
-#passphraseStrength.medium > .progress-bar {
-  background-color: #ffcc33;
-}
-
-#passphraseStrength.strong > .progress-bar {
-  background-color: #00ff00;
-}
--- 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/chrome/src/nsChromeRegistry.cpp
+++ b/chrome/src/nsChromeRegistry.cpp
@@ -172,23 +172,16 @@ nsChromeRegistry::GetService()
   }
   NS_ADDREF(gChromeRegistry);
   return gChromeRegistry;
 }
 
 nsresult
 nsChromeRegistry::Init()
 {
-  // Check to see if necko and the JAR protocol handler are registered yet
-  // if not, somebody is doing work during XPCOM registration that they
-  // shouldn't be doing. See bug 292549, where JS components are trying
-  // to call Components.utils.import("chrome:///") early in registration
-  NS_ASSERTION(nsCOMPtr<nsIIOService>(mozilla::services::GetIOService()),
-               "I/O service not registered or available early enough?");
-
   if (!mOverrideTable.Init())
     return NS_ERROR_FAILURE;
 
   // This initialization process is fairly complicated and may cause reentrant
   // getservice calls to resolve chrome URIs (especially locale files). We
   // don't want that, so we inform the protocol handler about our existence
   // before we are actually fully initialized.
   gChromeRegistry = this;
@@ -551,16 +544,17 @@ nsChromeRegistry::FlushAllCaches()
   obsSvc->NotifyObservers((nsIChromeRegistry*) this,
                           NS_CHROME_FLUSH_TOPIC, nsnull);
 }  
 
 // xxxbsmedberg Move me to nsIWindowMediator
 NS_IMETHODIMP
 nsChromeRegistry::ReloadChrome()
 {
+  UpdateSelectedLocale();
   FlushAllCaches();
   // Do a reload of all top level windows.
   nsresult rv = NS_OK;
 
   // Get the window mediator
   nsCOMPtr<nsIWindowMediator> windowMediator
     (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
   if (windowMediator) {
--- a/chrome/src/nsChromeRegistry.h
+++ b/chrome/src/nsChromeRegistry.h
@@ -109,16 +109,20 @@ public:
   static nsChromeRegistry* gChromeRegistry;
 
   static nsresult Canonify(nsIURL* aChromeURL);
 
 protected:
   void FlushSkinCaches();
   void FlushAllCaches();
 
+  // Update the selected locale used by the chrome registry, and fire a
+  // notification about this change
+  virtual void UpdateSelectedLocale() = 0;
+
   static void LogMessage(const char* aMsg, ...);
   static void LogMessageWithContext(nsIURI* aURL, PRUint32 aLineNumber, PRUint32 flags,
                                     const char* aMsg, ...);
 
   virtual nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
                                         const nsCString& aProvider,
                                         const nsCString& aPath) = 0;
   virtual nsresult GetFlagsFromPackage(const nsCString& aPackage,
--- a/chrome/src/nsChromeRegistryChrome.cpp
+++ b/chrome/src/nsChromeRegistryChrome.cpp
@@ -345,16 +345,19 @@ nsChromeRegistryChrome::SelectLocaleFrom
   else {
     nsXPIDLCString provider;
     rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
     if (NS_SUCCEEDED(rv)) {
       mSelectedLocale = provider;
     }
   }
 
+  if (NS_FAILED(rv))
+    NS_ERROR("Couldn't select locale from pref!");
+
   return rv;
 }
 
 NS_IMETHODIMP
 nsChromeRegistryChrome::Observe(nsISupports *aSubject, const char *aTopic,
                                 const PRUnichar *someData)
 {
   nsresult rv = NS_OK;
@@ -362,25 +365,28 @@ nsChromeRegistryChrome::Observe(nsISuppo
   if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
     nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
     NS_ASSERTION(prefs, "Bad observer call!");
 
     NS_ConvertUTF16toUTF8 pref(someData);
 
     if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
         pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
-      rv = SelectLocaleFromPref(prefs);
-      if (NS_SUCCEEDED(rv) && mProfileLoaded)
-        FlushAllCaches();
+      if (!mProfileLoaded) {
+        rv = SelectLocaleFromPref(prefs);
+        if (NS_FAILED(rv))
+          return rv;
+      }
+      FlushAllCaches();
     }
     else if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
       nsXPIDLCString provider;
       rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
       if (NS_FAILED(rv)) {
-        NS_ERROR("Couldn't get new locale pref!");
+        NS_ERROR("Couldn't get new skin pref!");
         return rv;
       }
 
       mSelectedSkin = provider;
       RefreshSkins();
     } else {
       NS_ERROR("Unexpected pref!");
     }
@@ -417,16 +423,31 @@ nsChromeRegistryChrome::CheckForNewChrom
   mOverlayHash.Clear();
   mStyleHash.Clear();
   mOverrideTable.Clear();
 
   nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
   return NS_OK;
 }
 
+void nsChromeRegistryChrome::UpdateSelectedLocale()
+{
+  nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
+  if (prefs) {
+    nsresult rv = SelectLocaleFromPref(prefs);
+    if (NS_SUCCEEDED(rv)) {
+      nsCOMPtr<nsIObserverService> obsSvc =
+        mozilla::services::GetObserverService();
+      NS_ASSERTION(obsSvc, "Couldn't get observer service.");
+      obsSvc->NotifyObservers((nsIChromeRegistry*) this,
+                              "selected-locale-has-changed", nsnull);
+    }
+  }
+}
+
 #ifdef MOZ_IPC
 static void
 SerializeURI(nsIURI* aURI,
              SerializedURI& aSerializedURI)
 {
   if (!aURI)
     return;
 
--- a/chrome/src/nsChromeRegistryChrome.h
+++ b/chrome/src/nsChromeRegistryChrome.h
@@ -82,16 +82,17 @@ class nsChromeRegistryChrome : public ns
  private:
 #ifdef MOZ_IPC
   static PLDHashOperator CollectPackages(PLDHashTable *table,
                                          PLDHashEntryHdr *entry,
                                          PRUint32 number, void *arg);
 #endif
 
   nsresult SelectLocaleFromPref(nsIPrefBranch* prefs);
+  NS_OVERRIDE void UpdateSelectedLocale();
   NS_OVERRIDE nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
                                              const nsCString& aProvider,
                                              const nsCString& aPath);
   NS_OVERRIDE nsresult GetFlagsFromPackage(const nsCString& aPackage,
                                            PRUint32* aFlags);
 
   static const PLDHashTableOps kTableOps;
   static PLDHashNumber HashKey(PLDHashTable *table, const void *key);
--- a/chrome/src/nsChromeRegistryContent.cpp
+++ b/chrome/src/nsChromeRegistryContent.cpp
@@ -262,16 +262,21 @@ nsChromeRegistryContent::GetStyleOverlay
 
 NS_IMETHODIMP
 nsChromeRegistryContent::GetXULOverlays(nsIURI *aChromeURL,
                                         nsISimpleEnumerator **aResult)
 {
   CONTENT_NOT_IMPLEMENTED();
 }
 
+void nsChromeRegistryContent::UpdateSelectedLocale()
+{
+  CONTENT_NOTREACHED();
+}
+
 void
 nsChromeRegistryContent::ManifestContent(ManifestProcessingContext& cx,
                                          int lineno, char *const * argv,
                                          bool platform, bool contentaccessible)
 {
   CONTENT_NOTREACHED();
 }
 
--- a/chrome/src/nsChromeRegistryContent.h
+++ b/chrome/src/nsChromeRegistryContent.h
@@ -83,16 +83,17 @@ class nsChromeRegistryContent : public n
     nsCOMPtr<nsIURI> skinBaseURI;
     PRUint32         flags;
   };
   
   void RegisterPackage(const ChromePackage& aPackage);
   void RegisterResource(const ResourceMapping& aResource);
   void RegisterOverride(const OverrideMapping& aOverride);
 
+  NS_OVERRIDE void UpdateSelectedLocale();
   NS_OVERRIDE nsIURI* GetBaseURIFromPackage(const nsCString& aPackage,
                                  const nsCString& aProvider,
                                  const nsCString& aPath);
   NS_OVERRIDE nsresult GetFlagsFromPackage(const nsCString& aPackage, PRUint32* aFlags);
 
   nsClassHashtable<nsCStringHashKey, PackageEntry> mPackagesHash;
 
   virtual void ManifestContent(ManifestProcessingContext& cx, int lineno,
--- a/chrome/test/unit/data/test_bug519468.manifest
+++ b/chrome/test/unit/data/test_bug519468.manifest
@@ -1,2 +1,3 @@
 locale testmatchos en-US jar:en-US.jar!/locale/en-US/global/
 locale testmatchos fr-FR jar:en-US.jar!/locale/en-US/global/
+locale testmatchos de-DE jar:en-US.jar!/locale/en-US/global/
--- a/chrome/test/unit/test_bug519468.js
+++ b/chrome/test/unit/test_bug519468.js
@@ -35,47 +35,61 @@
  *
  * ***** END LICENSE BLOCK *****
  */
 
 var MANIFESTS = [
   do_get_file("data/test_bug519468.manifest")
 ];
 
+do_test_pending()
 registerManifests(MANIFESTS);
 
 var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
                 .getService(Ci.nsIXULChromeRegistry)
                 .QueryInterface(Ci.nsIToolkitChromeRegistry);
 chromeReg.checkForNewChrome();
 
 var localeService = Cc["@mozilla.org/intl/nslocaleservice;1"]
                     .getService(Ci.nsILocaleService);
 
 var prefService = Cc["@mozilla.org/preferences-service;1"]
                   .getService(Ci.nsIPrefService)
                   .QueryInterface(Ci.nsIPrefBranch);
+var os = Cc["@mozilla.org/observer-service;1"]
+         .getService(Ci.nsIObserverService);
+
+var systemLocale = localeService.getLocaleComponentForUserAgent();
+var count = 0;
+var testsLocale = [
+  {matchOS: false, selected: null, locale: "en-US"},
+  {matchOS: true, selected: null, locale: systemLocale},
+  {matchOS: true, selected: "fr-FR", locale: systemLocale},
+  {matchOS: false, selected: "fr-FR", locale: "fr-FR"},
+  {matchOS: false, selected: "de-DE", locale: "de-DE"},
+  {matchOS: true, selected: null, locale: systemLocale}
+];
 
 function test_locale(aTest) {
   prefService.setBoolPref("intl.locale.matchOS", aTest.matchOS);
   prefService.setCharPref("general.useragent.locale", aTest.selected || "en-US");
 
-  var selectedLocale = chromeReg.getSelectedLocale("testmatchos");
-  do_check_eq(selectedLocale, aTest.locale);
+  chromeReg.reloadChrome();
 }
 
-function run_test()
-{
-  var systemLocale = localeService.getLocaleComponentForUserAgent();
+function checkValidity() {
+  var selectedLocale = chromeReg.getSelectedLocale("testmatchos");
+  do_check_eq(selectedLocale, testsLocale[count].locale);
 
-  var tests = [
-    {matchOS: false, selected: null, locale: "en-US"},
-    {matchOS: true, selected: null, locale: systemLocale},
-    {matchOS: true, selected: "fr-FR", locale: systemLocale},
-    {matchOS: false, selected: "fr-FR", locale: "fr-FR"},
-    {matchOS: true, selected: null, locale: systemLocale}
-  ];
-
-  for (var i = 0; i < tests.length; ++ i) {
-    var test = tests[i];
-    test_locale(test);
+  count++;
+  if (count >= testsLocale.length) {
+    os.removeObserver(checkValidity, "selected-locale-has-changed");
+    do_test_finished();
+  }
+  else {
+    test_locale(testsLocale[count]);
   }
 }
+
+function run_test() {
+  os.addObserver(checkValidity, "selected-locale-has-changed", false);
+  test_locale(testsLocale[count]);
+}
--- a/config/Makefile.in
+++ b/config/Makefile.in
@@ -120,16 +120,17 @@ else
 endif
 
 ifdef WRAP_SYSTEM_INCLUDES
 export::
 	if test ! -d system_wrappers; then mkdir system_wrappers; fi
 	$(PERL) $(topsrcdir)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) \
 		-DBUILD_STATIC_LIBS=$(BUILD_STATIC_LIBS) \
 		-DMOZ_TREE_CAIRO=$(MOZ_TREE_CAIRO) \
+		-DMOZ_TREE_PIXMAN=$(MOZ_TREE_PIXMAN) \
 		-DMOZ_ENABLE_LIBXUL=$(MOZ_ENABLE_LIBXUL) \
 		-DMOZ_NATIVE_HUNSPELL=$(MOZ_NATIVE_HUNSPELL) \
 		-DMOZ_NATIVE_BZ2=$(MOZ_NATIVE_BZ2) \
 		-DMOZ_NATIVE_ZLIB=$(MOZ_NATIVE_ZLIB) \
 		-DMOZ_NATIVE_PNG=$(MOZ_NATIVE_PNG) \
 		-DMOZ_NATIVE_JPEG=$(MOZ_NATIVE_JPEG) \
 		-DMOZ_NATIVE_LIBEVENT=$(MOZ_NATIVE_LIBEVENT) \
 		-DMOZ_NATIVE_LIBVPX=$(MOZ_NATIVE_LIBVPX) \
--- 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)
 
@@ -8593,16 +8644,17 @@ if test "$MOZ_TREE_CAIRO"; then
     AC_SUBST(WIN32_D2D_SURFACE_FEATURE)
     AC_SUBST(QUARTZ_FONT_FEATURE)
     AC_SUBST(PNG_FUNCTIONS_FEATURE)
     AC_SUBST(QT_SURFACE_FEATURE)
 
     MOZ_CAIRO_LIBS='$(call EXPAND_LIBNAME_PATH,mozcairo,$(DEPTH)/gfx/cairo/cairo/src)'" $CAIRO_FT_LIBS"
 
     if test "$MOZ_TREE_PIXMAN"; then
+        AC_DEFINE(MOZ_TREE_PIXMAN)
         MOZ_CAIRO_LIBS="$MOZ_CAIRO_LIBS"' $(call EXPAND_LIBNAME_PATH,mozlibpixman,$(DEPTH)/gfx/cairo/libpixman/src)'
     else
         PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.19.2)
         MOZ_CAIRO_CFLAGS="$MOZ_CAIRO_CFLAGS $PIXMAN_CFLAGS"
         MOZ_CAIRO_LIBS="$MOZ_CAIRO_LIBS $PIXMAN_LIBS"
     fi
 
     if test "$MOZ_X11"; then
@@ -8914,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
@@ -187,30 +187,28 @@ struct nsShortcutCandidate {
 class nsContentUtils
 {
   typedef mozilla::dom::Element Element;
 
 public:
   static nsresult Init();
 
   /**
-   * Get a scope from aOldDocument and one from aNewDocument. Also get a
-   * context through one of the scopes, from the stack or the safe context.
+   * Get a scope from aNewDocument. Also get a context through the scope of one
+   * of the documents, from the stack or the safe context.
    *
-   * @param aOldDocument The document to get aOldScope from.
+   * @param aOldDocument The document to try to get a context from. May be null.
    * @param aNewDocument The document to get aNewScope from.
    * @param aCx [out] Context gotten through one of the scopes, from the stack
    *                  or the safe context.
-   * @param aOldScope [out] Scope gotten from aOldDocument.
    * @param aNewScope [out] Scope gotten from aNewDocument.
    */
-  static nsresult GetContextAndScopes(nsIDocument *aOldDocument,
-                                      nsIDocument *aNewDocument,
-                                      JSContext **aCx, JSObject **aOldScope,
-                                      JSObject **aNewScope);
+  static nsresult GetContextAndScope(nsIDocument *aOldDocument,
+                                     nsIDocument *aNewDocument,
+                                     JSContext **aCx, JSObject **aNewScope);
 
   /**
    * When a document's scope changes (e.g., from document.open(), call this
    * function to move all content wrappers from the old scope to the new one.
    */
   static nsresult ReparentContentWrappersInScope(nsIScriptGlobalObject *aOldScope,
                                                  nsIScriptGlobalObject *aNewScope);
 
@@ -1515,16 +1513,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/public/nsIXMLHttpRequest.idl
+++ b/content/base/public/nsIXMLHttpRequest.idl
@@ -237,18 +237,18 @@ interface nsIXMLHttpRequest : nsISupport
    *              be thrown.
    * @param user (optional) A username for authentication if necessary.
    *             The default value is the empty string
    * @param password (optional) A password for authentication if necessary.
    *                 The default value is the empty string
    */
   [optional_argc] void open(in AUTF8String method, in AUTF8String url,
                             [optional] in boolean async,
-                            [optional] in DOMString user,
-                            [optional] in DOMString password);
+                            [optional,Undefined(Empty)] in DOMString user,
+                            [optional,Undefined(Empty)] in DOMString password);
 
   /**
    * Sends the request. If the request is asynchronous, returns
    * immediately after sending the request. If it is synchronous
    * returns only after the response has been received.
    *
    * All event listeners must be set before calling send().
    *
--- 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
@@ -1366,74 +1366,57 @@ nsContentUtils::InProlog(nsINode *aNode)
 
   nsIDocument* doc = static_cast<nsIDocument*>(parent);
   nsIContent* root = doc->GetRootElement();
 
   return !root || doc->IndexOf(aNode) < doc->IndexOf(root);
 }
 
 static JSContext *
-GetContextFromDocument(nsIDocument *aDocument, JSObject** aGlobalObject)
+GetContextFromDocument(nsIDocument *aDocument)
 {
   nsIScriptGlobalObject *sgo = aDocument->GetScopeObject();
   if (!sgo) {
     // No script global, no context.
-
-    *aGlobalObject = nsnull;
-
     return nsnull;
   }
 
-  *aGlobalObject = sgo->GetGlobalJSObject();
-
   nsIScriptContext *scx = sgo->GetContext();
   if (!scx) {
-    // No context left in the old scope...
+    // No context left in the scope...
 
     return nsnull;
   }
 
   return (JSContext *)scx->GetNativeContext();
 }
 
 // static
 nsresult
-nsContentUtils::GetContextAndScopes(nsIDocument *aOldDocument,
-                                    nsIDocument *aNewDocument, JSContext **aCx,
-                                    JSObject **aOldScope, JSObject **aNewScope)
+nsContentUtils::GetContextAndScope(nsIDocument *aOldDocument,
+                                   nsIDocument *aNewDocument, JSContext **aCx,
+                                   JSObject **aNewScope)
 {
   *aCx = nsnull;
-  *aOldScope = nsnull;
   *aNewScope = nsnull;
 
-  JSObject *newScope = nsnull;
-  nsIScriptGlobalObject *newSGO = aNewDocument->GetScopeObject();
-  if (!newSGO || !(newScope = newSGO->GetGlobalJSObject())) {
-    return NS_OK;
+  JSObject *newScope = aNewDocument->GetWrapper();
+  JSObject *global;
+  if (!newScope) {
+    nsIScriptGlobalObject *newSGO = aNewDocument->GetScopeObject();
+    if (!newSGO || !(global = newSGO->GetGlobalJSObject())) {
+      return NS_OK;
+    }
   }
 
   NS_ENSURE_TRUE(sXPConnect, NS_ERROR_NOT_INITIALIZED);
 
-  // Make sure to get our hands on the right scope object, since
-  // GetWrappedNativeOfNativeObject doesn't call PreCreate and hence won't get
-  // the right scope if we pass in something bogus.  The right scope lives on
-  // the script global of the old document.
-  // XXXbz note that if GetWrappedNativeOfNativeObject did call PreCreate it
-  // would get the wrong scope (that of the _new_ document), so we should be
-  // glad it doesn't!
-  JSObject *oldScope = nsnull;
-  JSContext *cx = GetContextFromDocument(aOldDocument, &oldScope);
-
-  if (!oldScope) {
-    return NS_OK;
-  }
-
+  JSContext *cx = aOldDocument ? GetContextFromDocument(aOldDocument) : nsnull;
   if (!cx) {
-    JSObject *dummy;
-    cx = GetContextFromDocument(aNewDocument, &dummy);
+    cx = GetContextFromDocument(aNewDocument);
 
     if (!cx) {
       // No context reachable from the old or new document, use the
       // calling context, or the safe context if no caller can be
       // found.
 
       sThreadJSContextStack->Peek(&cx);
 
@@ -1445,18 +1428,25 @@ nsContentUtils::GetContextAndScopes(nsID
           NS_WARNING("No context reachable in GetContextAndScopes()!");
 
           return NS_ERROR_NOT_AVAILABLE;
         }
       }
     }
   }
 
+  if (!newScope && cx) {
+    jsval v;
+    nsresult rv = WrapNative(cx, global, aNewDocument, aNewDocument, &v);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    newScope = JSVAL_TO_OBJECT(v);
+  }
+
   *aCx = cx;
-  *aOldScope = oldScope;
   *aNewScope = newScope;
 
   return NS_OK;
 }
 
 nsresult
 nsContentUtils::ReparentContentWrappersInScope(nsIScriptGlobalObject *aOldScope,
                                                nsIScriptGlobalObject *aNewScope)
@@ -5207,28 +5197,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;
@@ -5238,21 +5220,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);
 }
 
@@ -6513,8 +6511,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/nsDOMDocumentType.cpp
+++ b/content/base/src/nsDOMDocumentType.cpp
@@ -263,26 +263,25 @@ nsDOMDocumentType::BindToTree(nsIDocumen
     nsCOMPtr<nsINodeInfo> newNodeInfo;
     newNodeInfo = nimgr->GetNodeInfo(mNodeInfo->NameAtom(),
                                      mNodeInfo->GetPrefixAtom(),
                                      mNodeInfo->NamespaceID());
     NS_ENSURE_TRUE(newNodeInfo, NS_ERROR_OUT_OF_MEMORY);
 
     mNodeInfo.swap(newNodeInfo);
 
-    nsCOMPtr<nsIDocument> oldOwnerDoc =
-      do_QueryInterface(nsContentUtils::GetDocumentFromContext());
-    nsIDocument *newOwnerDoc = nimgr->GetDocument();
-    if (oldOwnerDoc && newOwnerDoc) {
+    JSObject *oldScope = GetWrapper();
+    if (oldScope) {
       nsIXPConnect *xpc = nsContentUtils::XPConnect();
 
       JSContext *cx = nsnull;
-      JSObject *oldScope = nsnull, *newScope = nsnull;
-      nsresult rv = nsContentUtils::GetContextAndScopes(oldOwnerDoc, newOwnerDoc, &cx,
-                                                        &oldScope, &newScope);
+      JSObject *newScope = nsnull;
+      nsresult rv = nsContentUtils::GetContextAndScope(nsnull,
+                                                       nimgr->GetDocument(),
+                                                       &cx, &newScope);
       if (cx && xpc) {
         nsISupports *node = NS_ISUPPORTS_CAST(nsIContent*, this);
         nsCOMPtr<nsIXPConnectJSObjectHolder> oldWrapper;
         rv = xpc->ReparentWrappedNativeIfFound(cx, oldScope, newScope, node,
                                                getter_AddRefs(oldWrapper));
       }
 
       if (NS_FAILED(rv)) {
--- 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,27 +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 = nsnull;
   JSObject *newScope = nsnull;
-  if (!sameDocument && oldDocument) {
-    rv = nsContentUtils::GetContextAndScopes(oldDocument, this, &cx, &oldScope,
-                                             &newScope);
+  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
@@ -1090,41 +1090,40 @@ nsIContent::IsEqual(nsIContent* aOther)
 
       if (!element2->AttrValueIs(attrName1->NamespaceID(),
                                  attrName1->LocalName(),
                                  string1,
                                  eCaseMatters)) {
         return PR_FALSE;
       }
     }
-
-    // Child nodes count.
-    PRUint32 childCount = GetChildCount();
-    if (childCount != element2->GetChildCount()) {
-      return PR_FALSE;
-    }
-
-    // Iterate over child nodes.
-    for (PRUint32 i = 0; i < childCount; ++i) {
-      if (!GetChildAt(i)->IsEqual(element2->GetChildAt(i))) {
-        return PR_FALSE;
-      }
-    }
   } else {
     // Node value check.
     nsCOMPtr<nsIDOMNode> domNode1 = do_QueryInterface(this);
     nsCOMPtr<nsIDOMNode> domNode2 = do_QueryInterface(aOther);
     NS_ASSERTION(domNode1 && domNode2, "How'd we get nsIContent without nsIDOMNode?");
     domNode1->GetNodeValue(string1);
     domNode2->GetNodeValue(string2);
     if (!string1.Equals(string2)) {
       return PR_FALSE;
     }
   }
 
+  // Child nodes count.
+  PRUint32 childCount = GetChildCount();
+  if (childCount != aOther->GetChildCount()) {
+    return PR_FALSE;
+  }
+
+  // Iterate over child nodes.
+  for (PRUint32 i = 0; i < childCount; ++i) {
+    if (!GetChildAt(i)->IsEqual(aOther->GetChildAt(i))) {
+      return PR_FALSE;
+    }
+  }
   return PR_TRUE;
 }
 
 PRBool
 nsIContent::IsEqualNode(nsINode* aOther)
 {
   if (!aOther || !aOther->IsNodeOfType(eCONTENT))
     return PR_FALSE;
@@ -4002,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
@@ -439,36 +439,36 @@ 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;
-  if (aCx) {
+  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;
@@ -577,39 +577,37 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
       if (imageContent)
         imageContent->NotifyOwnerDocumentChanged(oldDoc);
     }
 
     if (elem) {
       elem->RecompileScriptEventListeners();
     }
 
-    if (aCx) {
+    if (aCx && wrapper) {
       nsIXPConnect *xpc = nsContentUtils::XPConnect();
       if (xpc) {
-        nsWrapperCache *cache;
-        CallQueryInterface(aNode, &cache);
         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 (cache && cache->PreservingWrapper()) {
-          preservedWrapper = cache->GetWrapper();
-          nsContentUtils::ReleaseWrapper(aNode, cache);
+        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, cache);
+          nsContentUtils::PreserveWrapper(aNode, aNode);
         }
 
         if (NS_FAILED(rv)) {
           aNode->mNodeInfo.swap(nodeInfo);
 
           return rv;
         }
       }
@@ -643,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
@@ -365,27 +365,27 @@ include $(topsrcdir)/config/rules.mk
 		test_bug503481b.html \
 		file_bug503481b_inner.html \
 		test_viewport_scroll.html \
 		test_CSP.html \
 		file_CSP.sjs \
 		file_CSP_main.html \
 		file_CSP_main.html^headers^ \
 		file_CSP_main.js \
- 		test_CSP_frameancestors.html \
- 		file_CSP_frameancestors.sjs \
- 		file_CSP_frameancestors_main.html \
- 		file_CSP_frameancestors_main.js \
- 		test_CSP_inlinescript.html \
- 		file_CSP_inlinescript_main.html \
- 		file_CSP_inlinescript_main.html^headers^ \
- 		test_CSP_evalscript.html \
- 		file_CSP_evalscript_main.html \
- 		file_CSP_evalscript_main.html^headers^ \
- 		file_CSP_evalscript_main.js \
+		test_CSP_frameancestors.html \
+		file_CSP_frameancestors.sjs \
+		file_CSP_frameancestors_main.html \
+		file_CSP_frameancestors_main.js \
+		test_CSP_inlinescript.html \
+		file_CSP_inlinescript_main.html \
+		file_CSP_inlinescript_main.html^headers^ \
+		test_CSP_evalscript.html \
+		file_CSP_evalscript_main.html \
+		file_CSP_evalscript_main.html^headers^ \
+		file_CSP_evalscript_main.js \
 		test_bug540854.html \
 		bug540854.sjs \
 		test_bug548463.html \
 		test_bug545644.html \
 		test_bug545644.xhtml \
 		test_bug553896.xhtml \
 		test_bug515401.html \
 		test_bug541937.html \
@@ -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 \
@@ -439,16 +440,17 @@ include $(topsrcdir)/config/rules.mk
 		file_bug604660-2.xsl \
 		file_bug604660-3.js \
 		file_bug604660-4.js \
 		file_bug604660-5.xml \
 		file_bug604660-6.xsl \
 		test_bug605982.html \
 		test_bug606729.html \
 		test_treewalker_nextsibling.xml \
+		test_bug614058.html \
 		$(NULL)
 
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 windows,$(MOZ_WIDGET_TOOLKIT)))
 _TEST_FILES2 += 	test_copyimage.html \
 		$(NULL)
 endif
 
--- a/content/base/test/file_CrossSiteXHR_inner.html
+++ b/content/base/test/file_CrossSiteXHR_inner.html
@@ -11,17 +11,22 @@
 window.addEventListener("message", function(e) {
 
   sendData = null;
 
   req = eval(e.data);
   var res = {
     didFail: false,
     events: [],
-    progressEvents: 0
+    progressEvents: 0,
+    status: 0,
+    responseText: "",
+    statusText: "",
+    responseXML: null,
+    sendThrew: false
   };
   
   var xhr = new XMLHttpRequest();
   for each(type in ["load", "abort", "error", "loadstart"]) {
     xhr.addEventListener(type, function(e) {
       res.events.push(e.type);
     }, false);
   }
@@ -46,16 +51,17 @@ window.addEventListener("message", funct
   xhr.onload = xhr.onerror = function (event) {
     if (event.type == "error") {
       res.didFail = true;
     }
     res.status = xhr.status;
     try {
       res.statusText = xhr.statusText;
     } catch (e) {
+      delete(res.statusText);
     }
     res.responseXML = xhr.responseXML ?
       (new XMLSerializer()).serializeToString(xhr.responseXML) :
       null;
     res.responseText = xhr.responseText;
 
     res.responseHeaders = {};
     for (responseHeader in req.responseHeaders) {
@@ -67,24 +73,38 @@ window.addEventListener("message", funct
   }
 
   if (req.withCred)
     xhr.withCredentials = true;
   if (req.body)
     sendData = req.body;
 
   res.events.push("opening");
-  xhr.open(req.method, req.url, true);
+  // Allow passign in falsy usernames/passwords so we can test them
+  try {
+    xhr.open(req.method, req.url, true,
+             ("username" in req) ? req.username : "",
+             ("password" in req) ? req.password : "aa");
+  } catch (ex) {
+    res.didFail = true;
+    post(e, res);
+  }
 
   for (header in req.headers) {
     xhr.setRequestHeader(header, req.headers[header]);
   }
 
   res.events.push("sending");
-  xhr.send(sendData);
+  try {
+    xhr.send(sendData);
+  } catch (ex) {
+    res.didFail = true;
+    res.sendThrew = true;
+    post(e, res);
+  }
 
 }, false);
 
 function post(e, res) {
   e.source.postMessage(res.toSource(), "http://mochi.test:8888");
 }
 
 </script>
--- a/content/base/test/test_CrossSiteXHR.html
+++ b/content/base/test/test_CrossSiteXHR.html
@@ -44,16 +44,47 @@ function runTest() {
   yield;
 
   tests =     [// Plain request
                { pass: 1,
                  method: "GET",
                  noAllowPreflight: 1,
                },
 
+               // undefined username
+               { pass: 1,
+                 method: "GET",
+                 noAllowPreflight: 1,
+                 username: undefined
+               },
+
+               // undefined username and password
+               { pass: 1,
+                 method: "GET",
+                 noAllowPreflight: 1,
+                 username: undefined,
+                 password: undefined
+               },
+
+               // nonempty username
+               { pass: 0,
+                 method: "GET",
+                 noAllowPreflight: 1,
+                 username: "user",
+               },
+
+               // nonempty password
+               // XXXbz this passes for now, because we ignore passwords
+               // without usernames in most cases.
+               { pass: 1,
+                 method: "GET",
+                 noAllowPreflight: 1,
+                 password: "password",
+               },
+
                // Default allowed headers
                { pass: 1,
                  method: "GET",
                  headers: { "Content-Type": "text/plain",
                             "Accept": "foo/bar",
                             "Accept-Language": "sv-SE" },
                  noAllowPreflight: 1,
                },
@@ -552,16 +583,24 @@ function runTest() {
       responseHeaders: test.responseHeaders,
     };
 
     if (test.pass) {
        req.url += "&origin=" + escape(origin) +
                   "&requestMethod=" + test.method;
     }
 
+    if ("username" in test) {
+      req.username = test.username;
+    }
+
+    if ("password" in test) {
+      req.password = test.password;
+    }
+
     if (test.noAllowPreflight)
       req.url += "&noAllowPreflight";
 
     if (test.pass && "headers" in test) {
       function isUnsafeHeader(name) {
         lName = name.toLowerCase();
         return lName != "accept" &&
                lName != "accept-language" &&
@@ -643,24 +682,26 @@ function runTest() {
           }
         }
       }
     }
     else {
       is(res.didFail, true,
         "should have failed in test for " + test.toSource());
       is(res.status, 0, "wrong status in test for " + test.toSource());
-      is(res.statusText, "", "wrong status in test for " + test.toSource());
+      is(res.statusText, "", "wrong status text for " + test.toSource());
       is(res.responseXML, null,
          "wrong responseXML in test for " + test.toSource());
       is(res.responseText, "",
          "wrong responseText in test for " + test.toSource());
-      is(res.events.join(","),
-         "opening,rs1,sending,rs1,loadstart,rs2,rs4,error",
-         "wrong events in test for " + test.toSource());
+      if (!res.sendThrew) {
+        is(res.events.join(","),
+           "opening,rs1,sending,rs1,loadstart,rs2,rs4,error",
+           "wrong events in test for " + test.toSource());
+      }
       is(res.progressEvents, 0,
          "wrong events in test for " + test.toSource());
       if (test.responseHeaders) {
         for (header in test.responseHeaders) {
           is(res.responseHeaders[header], null,
              "wrong response header (" + header + ") in test for " +
              test.toSource());
         }
@@ -783,17 +824,17 @@ function runTest() {
       is(res.events.join(","),
          "opening,rs1,sending,rs1,loadstart,rs2,rs3,rs4,load",
          "wrong responseText in test for " + test.toSource());
     }
     else {
       is(res.didFail, true,
         "should have failed in test for " + test.toSource());
       is(res.status, 0, "wrong status in test for " + test.toSource());
-      is(res.statusText, "", "wrong status in test for " + test.toSource());
+      is(res.statusText, "", "wrong status text for " + test.toSource());
       is(res.responseXML, null,
          "wrong responseXML in test for " + test.toSource());
       is(res.responseText, "",
          "wrong responseText in test for " + test.toSource());
       is(res.events.join(","),
          "opening,rs1,sending,rs1,loadstart,rs2,rs4,error",
          "wrong events in test for " + test.toSource());
       is(res.progressEvents, 0,
@@ -1052,17 +1093,17 @@ function runTest() {
       is(res.events.join(","),
          "opening,rs1,sending,rs1,loadstart,rs2,rs3,rs4,load",
          "wrong responseText in test for " + test.toSource());
     }
     else {
       is(res.didFail, true,
         "should have failed in test for " + test.toSource());
       is(res.status, 0, "wrong status in test for " + test.toSource());
-      is(res.statusText, "", "wrong status in test for " + test.toSource());
+      is(res.statusText, "", "wrong status text for " + test.toSource());
       is(res.responseXML, null,
          "wrong responseXML in test for " + test.toSource());
       is(res.responseText, "",
          "wrong responseText in test for " + test.toSource());
       is(res.events.join(","),
          "opening,rs1,sending,rs1,loadstart,rs2,rs4,error",
          "wrong events in test for " + test.toSource());
       is(res.progressEvents, 0,
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>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug614058.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=614058
+-->
+<head>
+  <title>Test for Bug 614058</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=614058">Mozilla Bug 614058</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 614058 **/
+var f1 = document.createDocumentFragment(); 
+f2 = f1.cloneNode(true); 
+f1.appendChild(document.createElement("foo"));
+is(f1.isEqualNode(f2), false, "Fragments have different kids!");
+
+</script>
+</pre>
+</body>
+</html>
--- 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
@@ -118,22 +118,16 @@ WebGLProgram::GetUniformLocationObject(G
         return nsnull;
     }
 
     nsRefPtr<WebGLUniformLocation> loc = new WebGLUniformLocation(mContext, this, glLocation);
     mMapUniformLocations.Put(glLocation, loc);
     return loc.forget();
 }
 
-static PRBool
-InternalFormatHasAlpha(WebGLenum aInternalFormat) {
-    return aInternalFormat == LOCAL_GL_RGBA4 ||
-        aInternalFormat == LOCAL_GL_RGB5_A1;
-}
-
 //
 //  WebGL API
 //
 
 
 /* void GlActiveTexture (in GLenum texture); */
 NS_IMETHODIMP
 WebGLContext::ActiveTexture(WebGLenum texture)
@@ -2696,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);