Merge TM -> JM
authorBrian Hackett <bhackett1024@gmail.com>
Mon, 06 Jun 2011 16:47:40 -0700
changeset 75147 09d3a39c186a098ab626e21c2c94abf5c037e673
parent 75146 1b5429edb553cab294f7648036cfb8981a6989d8 (current diff)
parent 70977 cc612a118e7c0cd3a64dd7123a9ab8876efc7d8f (diff)
child 75148 58be28e45a2695b1872413bc404b750f27ef584a
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone7.0a1
Merge TM -> JM
accessible/tests/mochitest/test_elm_media.html
accessible/tests/mochitest/test_nsIAccessible_comboboxes.xul
browser/base/content/browser.js
browser/base/content/test/browser_bug420160.js
browser/base/content/test/browser_webdev_menu.js
browser/themes/pinstripe/browser/Secure-background.gif
config/static-config.mk
config/static-rules.mk
content/base/test/test_bug414796.html
content/events/test/Makefile.in
content/html/content/src/nsHTMLDelElement.cpp
content/html/content/src/nsImageMapUtils.cpp
content/html/content/src/nsImageMapUtils.h
content/html/document/src/nsImageDocument.cpp
content/html/document/src/nsMediaDocument.cpp
content/html/document/src/nsMediaDocument.h
content/html/document/src/nsPluginDocument.cpp
content/html/document/src/nsVideoDocument.cpp
content/xslt/public/txDouble.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsJSEnvironment.cpp
dom/interfaces/core/nsIDOM3Text.idl
dom/interfaces/core/nsIDOM3TypeInfo.idl
dom/interfaces/core/nsIDOMEntity.idl
dom/interfaces/core/nsIDOMEntityReference.idl
dom/interfaces/core/nsIDOMNSDocument.idl
dom/interfaces/core/nsIDOMNotation.idl
dom/interfaces/events/nsIDOM3DocumentEvent.idl
dom/interfaces/events/nsIDOMDocumentEvent.idl
dom/interfaces/html/nsIDOMNSHTMLDocument.idl
dom/interfaces/html/nsIDOMNSHTMLFormElement.idl
dom/interfaces/html/nsIDOMNSHTMLHRElement.idl
dom/interfaces/stylesheets/nsIDOMDocumentStyle.idl
dom/interfaces/stylesheets/nsIDOMNSDocumentStyle.idl
gfx/angle/angle-fixes.patch
gfx/angle/angle-pbuffers.patch
gfx/angle/angle-shared.patch
gfx/thebes/gfxDllDeps.cpp
js/src/Makefile.in
js/src/config/autoconf.mk.in
js/src/configure.in
js/src/jsatom.cpp
js/src/jsparse.cpp
js/src/jsval.h
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/xpconnect/shell/xpcshell.cpp
js/src/xpconnect/wrappers/WrapperFactory.cpp
layout/reftests/table-background/rainbowhb.gif
layout/reftests/table-background/rainbowvb.gif
mobile/chrome/content/bindings/setting.xml
mobile/chrome/content/checkerboard.png
mobile/chrome/content/content.css
mobile/themes/core/gingerbread/images/appmenu-addons-hdpi-xxx.png
mobile/themes/core/gingerbread/images/check-selected-30.png
mobile/themes/core/gingerbread/images/check-unselected-30.png
mobile/themes/core/gingerbread/images/panelrow-active-hdpi.png
mobile/themes/core/gingerbread/images/panelrow-default-hdpi.png
mobile/themes/core/gingerbread/images/panelrow-selected-hdpi.png
mobile/themes/core/gingerbread/images/popup-bg-hdpi.png
mobile/themes/core/gingerbread/images/sidebarbutton-active-hdpi.png
mobile/themes/core/honeycomb/images/appmenu-addons-hdpi-xxx.png
modules/libpref/src/init/all.js
modules/libpref/src/nsPrefService.cpp
modules/libpref/src/nsPrefService.h
services/sync/tests/unit/test_utils_lazy.js
services/sync/tests/unit/test_utils_lazy2.js
services/sync/tests/unit/test_utils_lazySvc.js
services/sync/tests/unit/test_utils_queryAsync.js
services/sync/tests/unit/test_utils_status.js
xpcom/build/dlldeps.cpp
--- a/.hgtags
+++ b/.hgtags
@@ -58,8 +58,11 @@ 138f593553b66c9f815e8f57870c19d6347f7702
 e56ecd8b3a68c158025207c5fd081d043e28f5ce GECKO_2_0_BASE
 e273946b74c8d631ed86bd74ba9afe0e67b12378 GECKO_2_1_BASE
 b70744835d94e54eec97b8fd186c96da5708a506 PRE_MOBILE_MERGE
 b70744835d94e54eec97b8fd186c96da5708a506 PRE_MOBILE_MERGE_20110406
 a71bd564ebf5bf4f93d13e84114f759c263130b0 MOBILE_MERGE_DONE
 a71bd564ebf5bf4f93d13e84114f759c263130b0 MOBILE_MERGE_DONE_20110406
 a95d426422816513477e5863add1b00ac7041dcb AURORA_BASE_20110412
 138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R14
+9eae975b3d6fb7748fe5a3c0113d449b1c7cc0b2 AURORA_BASE_20110524
+138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R14
+462c726144bc1fb45b61e774f64ac5d61b4e047c UPDATE_PACKAGING_R14
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -472,17 +472,18 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] 
   },
   {
     "tab",
     nsIAccessibleRole::ROLE_PAGETAB,
     kUseMapRole,
     eNoValue,
     eSwitchAction,
     eNoLiveAttr,
-    kNoReqStates
+    kNoReqStates,
+    eARIASelectable
   },
   {
     "tablist",
     nsIAccessibleRole::ROLE_PAGETABLIST,
     kUseMapRole,
     eNoValue,
     eNoAction,
     ePoliteLiveAttr,
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -50,19 +50,16 @@
 #include "nsApplicationAccessibleWrap.h"
 #include "nsIAccessibleDocument.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocument.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
-#include "nsIDOMHTMLDocument.h"
-#include "nsIDOMHTMLElement.h"
-#include "nsIDOMNSDocument.h"
 #include "nsIDOMNSHTMLElement.h"
 #include "nsIDOMWindow.h"
 #include "nsPIDOMWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIFrame.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsPresContext.h"
@@ -130,16 +127,22 @@ void nsAccessNode::LastRelease()
   }
   // ... then die.
   delete this;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode public
 
+bool
+nsAccessNode::IsDefunct() const
+{
+  return !mContent;
+}
+
 PRBool
 nsAccessNode::Init()
 {
   return PR_TRUE;
 }
 
 
 void
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -116,31 +116,31 @@ public:
    * Return focused node within accessible window.
    *
    * XXX: it shouldn't break us if we return focused node not depending on
    * window so that we can turn this method into util method.
    */
   already_AddRefed<nsINode> GetCurrentFocus();
 
   /**
-   * Returns true when the accessible is defunct.
-   */
-  virtual PRBool IsDefunct() { return !mContent; }
-
-  /**
    * Initialize the access node object, add it to the cache.
    */
   virtual PRBool Init();
 
   /**
    * Shutdown the access node object.
    */
   virtual void Shutdown();
 
   /**
+   * Returns true when the accessible is defunct.
+   */
+  virtual bool IsDefunct() const;
+
+  /**
    * Return frame for the given access node object.
    */
   virtual nsIFrame* GetFrame() const;
 
   /**
    * Return DOM node associated with this accessible.
    */
   already_AddRefed<nsIDOMNode> GetDOMNode() const
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -102,17 +102,16 @@
 
 #ifndef DISABLE_XFORMS_HOOKS
 #include "nsXFormsFormControlsAccessible.h"
 #include "nsXFormsWidgetsAccessible.h"
 #endif
 
 #include "mozilla/FunctionTimer.h"
 #include "mozilla/dom/Element.h"
-#include "nsImageMapUtils.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService
 ////////////////////////////////////////////////////////////////////////////////
 
 nsAccessibilityService *nsAccessibilityService::gAccessibilityService = nsnull;
 PRBool nsAccessibilityService::gIsShutdown = PR_TRUE;
 
@@ -270,18 +269,20 @@ nsAccessibilityService::CreateHTMLCombob
 already_AddRefed<nsAccessible>
 nsAccessibilityService::CreateHTMLImageAccessible(nsIContent* aContent,
                                                   nsIPresShell* aPresShell)
 {
   nsAutoString mapElmName;
   aContent->GetAttr(kNameSpaceID_None,
                     nsAccessibilityAtoms::usemap,
                     mapElmName);
-  nsCOMPtr<nsIDOMHTMLMapElement> mapElm =
-    nsImageMapUtils::FindImageMap(aContent->GetCurrentDoc(), mapElmName);
+  nsCOMPtr<nsIDOMHTMLMapElement> mapElm;
+  if (nsIDocument* document = aContent->GetCurrentDoc()) {
+    mapElm = do_QueryInterface(document->FindImageMap(mapElmName));
+  }
 
   nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aPresShell));
   nsAccessible* accessible = mapElm ?
     new nsHTMLImageMapAccessible(aContent, weakShell, mapElm) :
     new nsHTMLImageAccessibleWrap(aContent, weakShell);
   NS_IF_ADDREF(accessible);
   return accessible;
 }
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -70,46 +70,48 @@
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsPIDOMWindow.h"
 
 #include "nsIDocument.h"
 #include "nsIContent.h"
 #include "nsIForm.h"
 #include "nsIFormControl.h"
 
+#include "nsLayoutUtils.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIFrame.h"
 #include "nsIView.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIScrollableFrame.h"
 #include "nsFocusManager.h"
 
 #include "nsXPIDLString.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
 #include "prdtoa.h"
 #include "nsIAtom.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
 #include "nsIURI.h"
 #include "nsArrayUtils.h"
 #include "nsIMutableArray.h"
 #include "nsIObserverService.h"
 #include "nsIServiceManager.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsAttrName.h"
 #include "nsNetUtil.h"
 #include "nsEventStates.h"
 
 #ifdef NS_DEBUG
 #include "nsIDOMCharacterData.h"
 #endif
 
 #include "mozilla/unused.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible. nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsAccessible)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsAccessible, nsAccessNode)
@@ -333,57 +335,49 @@ nsAccessible::Description(nsString& aDes
 #define NS_MODIFIER_ALT      4
 #define NS_MODIFIER_META     8
 
 // returns the accesskey modifier mask used in the given node's context
 // (i.e. chrome or content), or 0 if an error occurs
 static PRInt32
 GetAccessModifierMask(nsIContent* aContent)
 {
-  nsCOMPtr<nsIPrefBranch> prefBranch =
-    do_GetService(NS_PREFSERVICE_CONTRACTID);
-  if (!prefBranch)
-    return 0;
-
   // use ui.key.generalAccessKey (unless it is -1)
-  PRInt32 accessKey;
-  nsresult rv = prefBranch->GetIntPref("ui.key.generalAccessKey", &accessKey);
-  if (NS_SUCCEEDED(rv) && accessKey != -1) {
-    switch (accessKey) {
-      case nsIDOMKeyEvent::DOM_VK_SHIFT:   return NS_MODIFIER_SHIFT;
-      case nsIDOMKeyEvent::DOM_VK_CONTROL: return NS_MODIFIER_CONTROL;
-      case nsIDOMKeyEvent::DOM_VK_ALT:     return NS_MODIFIER_ALT;
-      case nsIDOMKeyEvent::DOM_VK_META:    return NS_MODIFIER_META;
-      default:                             return 0;
-    }
+  switch (Preferences::GetInt("ui.key.generalAccessKey", -1)) {
+    case -1:                             break;
+    case nsIDOMKeyEvent::DOM_VK_SHIFT:   return NS_MODIFIER_SHIFT;
+    case nsIDOMKeyEvent::DOM_VK_CONTROL: return NS_MODIFIER_CONTROL;
+    case nsIDOMKeyEvent::DOM_VK_ALT:     return NS_MODIFIER_ALT;
+    case nsIDOMKeyEvent::DOM_VK_META:    return NS_MODIFIER_META;
+    default:                             return 0;
   }
 
   // get the docShell to this DOMNode, return 0 on failure
   nsCOMPtr<nsIDocument> document = aContent->GetCurrentDoc();
   if (!document)
     return 0;
   nsCOMPtr<nsISupports> container = document->GetContainer();
   if (!container)
     return 0;
   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(container));
   if (!treeItem)
     return 0;
 
   // determine the access modifier used in this context
+  nsresult rv = NS_ERROR_FAILURE;
   PRInt32 itemType, accessModifierMask = 0;
   treeItem->GetItemType(&itemType);
   switch (itemType) {
-
-  case nsIDocShellTreeItem::typeChrome:
-    rv = prefBranch->GetIntPref("ui.key.chromeAccess", &accessModifierMask);
-    break;
-
-  case nsIDocShellTreeItem::typeContent:
-    rv = prefBranch->GetIntPref("ui.key.contentAccess", &accessModifierMask);
-    break;
+    case nsIDocShellTreeItem::typeChrome:
+      rv = Preferences::GetInt("ui.key.chromeAccess", &accessModifierMask);
+      break;
+
+    case nsIDocShellTreeItem::typeContent:
+      rv = Preferences::GetInt("ui.key.contentAccess", &accessModifierMask);
+      break;
   }
 
   return NS_SUCCEEDED(rv) ? accessModifierMask : 0;
 }
 
 NS_IMETHODIMP
 nsAccessible::GetKeyboardShortcut(nsAString& aAccessKey)
 {
@@ -677,49 +671,44 @@ nsAccessible::IsVisible(PRBool* aIsOffsc
     if (isEmpty && !(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
       // Consider zero area objects hidden unless they are absolutely positioned
       // or floating and may have descendants that have a non-zero size
       return PR_FALSE;
     }
   }
 
   // The frame intersects the viewport, but we need to check the parent view chain :(
-  nsIDocument* doc = mContent->GetOwnerDoc();
-  if (!doc)  {
-    return PR_FALSE;
-  }
-
-  nsIFrame* frameWithView =
-    frame->HasView() ? frame : frame->GetAncestorWithViewExternal();
-  nsIView* view = frameWithView->GetViewExternal();
-  PRBool isVisible = CheckVisibilityInParentChain(doc, view);
+  bool isVisible = nsCoreUtils::CheckVisibilityInParentChain(frame);
   if (isVisible && rectVisibility == nsRectVisibility_kVisible) {
     *aIsOffscreen = PR_FALSE;
   }
   return isVisible;
 }
 
 PRUint64
 nsAccessible::NativeState()
 {
   PRUint64 state = 0;
-  nsEventStates intrinsicState = mContent->IntrinsicState();
-
-  if (intrinsicState.HasState(NS_EVENT_STATE_INVALID))
-    state |= states::INVALID;
-
-  if (intrinsicState.HasState(NS_EVENT_STATE_REQUIRED))
-    state |= states::REQUIRED;
-
-  PRBool disabled = mContent->IsHTML() ? 
-    (intrinsicState.HasState(NS_EVENT_STATE_DISABLED)) :
-    (mContent->AttrValueIs(kNameSpaceID_None,
-                           nsAccessibilityAtoms::disabled,
-                           nsAccessibilityAtoms::_true,
-                           eCaseMatters));
+  PRBool disabled = PR_FALSE;
+  if (mContent->IsElement()) {
+    nsEventStates elementState = mContent->AsElement()->State();
+
+    if (elementState.HasState(NS_EVENT_STATE_INVALID))
+      state |= states::INVALID;
+
+    if (elementState.HasState(NS_EVENT_STATE_REQUIRED))
+      state |= states::REQUIRED;
+
+    disabled = mContent->IsHTML() ? 
+      (elementState.HasState(NS_EVENT_STATE_DISABLED)) :
+      (mContent->AttrValueIs(kNameSpaceID_None,
+                             nsAccessibilityAtoms::disabled,
+                             nsAccessibilityAtoms::_true,
+                             eCaseMatters));
+  }
 
   // Set unavailable state based on disabled state, otherwise set focus states
   if (disabled) {
     state |= states::UNAVAILABLE;
   }
   else if (mContent->IsElement()) {
     nsIFrame *frame = GetFrame();
     if (frame && frame->IsFocusable()) {
@@ -1528,25 +1517,30 @@ nsAccessible::GetState(PRUint32* aState,
 
 PRUint64
 nsAccessible::State()
 {
   if (IsDefunct())
     return states::DEFUNCT;
 
   PRUint64 state = NativeState();
-  // Apply ARIA states to be sure accessible states will be overriden.
+  // Apply ARIA states to be sure accessible states will be overridden.
   ApplyARIAState(&state);
 
-  if (mRoleMapEntry && mRoleMapEntry->role == nsIAccessibleRole::ROLE_PAGETAB) {
+  if (mRoleMapEntry && mRoleMapEntry->role == nsIAccessibleRole::ROLE_PAGETAB &&
+      !(state & states::SELECTED) &&
+      !mContent->AttrValueIs(kNameSpaceID_None,
+                             nsAccessibilityAtoms::aria_selected,
+                             nsAccessibilityAtoms::_false, eCaseMatters)) {
+    // Special case: for tabs, focused implies selected, unless explicitly
+    // false, i.e. aria-selected="false".
     if (state & states::FOCUSED) {
       state |= states::SELECTED;
     } else {
-      // Expose 'selected' state on ARIA tab if the focus is on internal element
-      // of related tabpanel.
+      // If focus is in a child of the tab panel surely the tab is selected!
       nsCOMPtr<nsIAccessible> tabPanel = nsRelUtils::
         GetRelatedAccessible(this, nsIAccessibleRelation::RELATION_LABEL_FOR);
 
       if (nsAccUtils::Role(tabPanel) == nsIAccessibleRole::ROLE_PROPERTYPAGE) {
         nsRefPtr<nsAccessible> tabPanelAcc(do_QueryObject(tabPanel));
         nsINode *tabPanelNode = tabPanelAcc->GetNode();
         if (nsCoreUtils::IsAncestorOf(tabPanelNode, gLastFocusedNode))
           state |= states::SELECTED;
@@ -3241,54 +3235,16 @@ nsAccessible::GetFirstAvailableAccessibl
       GetAccService()->GetAccessibleInWeakShell(node, mWeakShell);
     if (accessible)
       return accessible;
   }
 
   return nsnull;
 }
 
-PRBool nsAccessible::CheckVisibilityInParentChain(nsIDocument* aDocument, nsIView* aView)
-{
-  nsIDocument* document = aDocument;
-  nsIView* view = aView;
-  // both view chain and widget chain are broken between chrome and content
-  while (document != nsnull) {
-    while (view != nsnull) {
-      if (view->GetVisibility() == nsViewVisibility_kHide) {
-        return PR_FALSE;
-      }
-      view = view->GetParent();
-    }
-
-    nsIDocument* parentDoc = document->GetParentDocument();
-    if (parentDoc != nsnull) {
-      nsIContent* content = parentDoc->FindContentForSubDocument(document);
-      if (content != nsnull) {
-        nsIPresShell* shell = parentDoc->GetShell();
-        if (!shell) {
-          return PR_FALSE;
-        }
-        nsIFrame* frame = content->GetPrimaryFrame();
-        while (frame != nsnull && !frame->HasView()) {
-          frame = frame->GetParent();
-        }
-
-        if (frame != nsnull) {
-          view = frame->GetViewExternal();
-        }
-      }
-    }
-
-    document = parentDoc;
-  }
-
-  return PR_TRUE;
-}
-
 nsresult
 nsAccessible::GetAttrValue(nsIAtom *aProperty, double *aValue)
 {
   NS_ENSURE_ARG_POINTER(aValue);
   *aValue = 0;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;  // Node already shut down
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -513,17 +513,17 @@ protected:
     eMixedChildren = 1 << 0, // text leaf children are presented
     eEmbeddedChildren = 1 << 1 // all children are embedded objects
   };
 
   /**
    * Return true if the children flag is set.
    */
   inline bool IsChildrenFlag(ChildrenFlags aFlag) const
-    { return (mFlags & kChildrenFlagsMask) == aFlag; }
+    { return static_cast<ChildrenFlags> (mFlags & kChildrenFlagsMask) == aFlag; }
 
   /**
    * Set children flag.
    */
   inline void SetChildrenFlag(ChildrenFlags aFlag)
     { mFlags = (mFlags & ~kChildrenFlagsMask) | aFlag; }
 
   /**
@@ -601,19 +601,16 @@ protected:
   virtual void DispatchClickEvent(nsIContent *aContent, PRUint32 aActionIndex);
 
   NS_DECL_RUNNABLEMETHOD_ARG2(nsAccessible, DispatchClickEvent,
                               nsCOMPtr<nsIContent>, PRUint32)
 
   //////////////////////////////////////////////////////////////////////////////
   // Helpers
 
-  // Check the visibility across both parent content and chrome
-  PRBool CheckVisibilityInParentChain(nsIDocument* aDocument, nsIView* aView);
-
   /**
    *  Get the container node for an atomic region, defined by aria-atomic="true"
    *  @return the container node
    */
   nsIDOMNode* GetAtomicRegion();
 
   /**
    * Get numeric value of the given ARIA attribute.
--- a/accessible/src/base/nsApplicationAccessible.cpp
+++ b/accessible/src/base/nsApplicationAccessible.cpp
@@ -327,18 +327,18 @@ nsApplicationAccessible::GetPlatformVers
 
   AppendUTF8toUTF16(cversion, aVersion);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode public methods
 
-PRBool
-nsApplicationAccessible::IsDefunct()
+bool
+nsApplicationAccessible::IsDefunct() const
 {
   return nsAccessibilityService::IsShutdown();
 }
 
 PRBool
 nsApplicationAccessible::Init()
 {
   mAppInfo = do_GetService("@mozilla.org/xre/app-info;1");
--- a/accessible/src/base/nsApplicationAccessible.h
+++ b/accessible/src/base/nsApplicationAccessible.h
@@ -110,17 +110,17 @@ public:
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString &aName);
   NS_IMETHOD GetActionDescription(PRUint8 aIndex, nsAString &aDescription);
   NS_IMETHOD DoAction(PRUint8 aIndex);
 
   // nsIAccessibleApplication
   NS_DECL_NSIACCESSIBLEAPPLICATION
 
   // nsAccessNode
-  virtual PRBool IsDefunct();
+  virtual bool IsDefunct() const;
   virtual PRBool Init();
   virtual void Shutdown();
   virtual bool IsPrimaryForNode() const;
 
   // nsAccessible
   virtual void ApplyARIAState(PRUint64* aState);
   virtual void Description(nsString& aDescription);
   virtual PRUint32 NativeRole();
--- a/accessible/src/base/nsBaseWidgetAccessible.cpp
+++ b/accessible/src/base/nsBaseWidgetAccessible.cpp
@@ -136,17 +136,17 @@ nsLinkableAccessible::GetValue(nsAString
 }
 
 
 NS_IMETHODIMP
 nsLinkableAccessible::GetNumActions(PRUint8 *aNumActions)
 {
   NS_ENSURE_ARG_POINTER(aNumActions);
 
-  *aNumActions = mActionAcc ? 1 : 0;
+  *aNumActions = (mIsOnclick || mIsLink) ? 1 : 0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsLinkableAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
 {
   aName.Truncate();
 
@@ -223,17 +223,16 @@ nsLinkableAccessible::BindToParent(nsAcc
   nsAccessibleWrap::BindToParent(aParent, aIndexInParent);
 
   // Cache action content.
   mActionAcc = nsnull;
   mIsLink = PR_FALSE;
   mIsOnclick = PR_FALSE;
 
   if (nsCoreUtils::HasClickListener(mContent)) {
-    mActionAcc = this;
     mIsOnclick = PR_TRUE;
     return;
   }
 
   // XXX: The logic looks broken since the click listener may be registered
   // on non accessible node in parent chain but this node is skipped when tree
   // is traversed.
   nsAccessible* walkUpAcc = this;
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -347,22 +347,25 @@ nsCaretAccessible::GetCaretRect(nsIWidge
 
   nsRect rect;
   nsIFrame* frame = caret->GetGeometry(caretSelection, &rect);
   if (!frame || rect.IsEmpty()) {
     return nsIntRect(); // Return empty rect
   }
 
   nsPoint offset;
+  // Offset from widget origin to the frame origin, which includes chrome
+  // on the widget.
   *aOutWidget = frame->GetNearestWidget(offset);
   NS_ENSURE_TRUE(*aOutWidget, nsIntRect());
   rect.MoveBy(offset);
 
   caretRect = rect.ToOutsidePixels(frame->PresContext()->AppUnitsPerDevPixel());
-  caretRect.MoveBy((*aOutWidget)->WidgetToScreenOffset());
+  // ((content screen origin) - (content offset in the widget)) = widget origin on the screen
+  caretRect.MoveBy((*aOutWidget)->WidgetToScreenOffset() - (*aOutWidget)->GetClientOffset());
 
   // Correct for character size, so that caret always matches the size of the character
   // This is important for font size transitions, and is necessary because the Gecko caret uses the
   // previous character's size as the user moves forward in the text by character.
   PRInt32 charX, charY, charWidth, charHeight;
   if (NS_SUCCEEDED(mLastTextAccessible->GetCharacterExtents(mLastCaretOffset, &charX, &charY,
                                                             &charWidth, &charHeight,
                                                             nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE))) {
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -58,16 +58,17 @@
 #include "nsPresContext.h"
 #include "nsIScrollableFrame.h"
 #include "nsEventStateManager.h"
 #include "nsISelection2.h"
 #include "nsISelectionController.h"
 #include "nsPIDOMWindow.h"
 #include "nsGUIEvent.h"
 #include "nsIView.h"
+#include "nsLayoutUtils.h"
 
 #include "nsContentCID.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 
 static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -748,16 +749,40 @@ nsCoreUtils::IsColumnHidden(nsITreeColum
 {
   nsCOMPtr<nsIDOMElement> element;
   aColumn->GetElement(getter_AddRefs(element));
   nsCOMPtr<nsIContent> content = do_QueryInterface(element);
   return content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::hidden,
                               nsAccessibilityAtoms::_true, eCaseMatters);
 }
 
+bool
+nsCoreUtils::CheckVisibilityInParentChain(nsIFrame* aFrame)
+{
+  nsIView* view = aFrame->GetClosestView();
+  if (view && !view->IsEffectivelyVisible())
+    return false;
+
+  nsIPresShell* presShell = aFrame->PresContext()->GetPresShell();
+  while (presShell) {
+    if (!presShell->IsActive()) {
+      return false;
+    }
+
+    nsIFrame* rootFrame = presShell->GetRootFrame();
+    presShell = nsnull;
+    if (rootFrame) {
+      nsIFrame* frame = nsLayoutUtils::GetCrossDocParentFrame(rootFrame);
+      if (frame) {
+        presShell = frame->PresContext()->GetPresShell();
+      }
+    }
+  }
+  return true;
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibleDOMStringList
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS1(nsAccessibleDOMStringList, nsIDOMDOMStringList)
 
 NS_IMETHODIMP
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -362,16 +362,22 @@ public:
   /**
    * Return true if the given node is table header element.
    */
   static PRBool IsHTMLTableHeader(nsIContent *aContent)
   {
     return aContent->NodeInfo()->Equals(nsAccessibilityAtoms::th) ||
       aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::scope);
   }
+
+  /**
+   * Check the visibility across both parent content and chrome.
+   */
+  static bool CheckVisibilityInParentChain(nsIFrame* aFrame);
+
 };
 
 
 /**
  * nsIDOMDOMStringList implementation.
  */
 class nsAccessibleDOMStringList : public nsIDOMDOMStringList
 {
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -49,18 +49,16 @@
 #include "nsICommandManager.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocument.h"
 #include "nsIDOMAttr.h"
 #include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentType.h"
-#include "nsIDOMNSDocument.h"
-#include "nsIDOMNSHTMLDocument.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMXULPopupElement.h"
 #include "nsIEditingSession.h"
 #include "nsEventStateManager.h"
 #include "nsIFrame.h"
 #include "nsHTMLSelectAccessible.h"
@@ -310,22 +308,17 @@ nsDocAccessible::NativeState()
   }
 
   // Expose state busy until the document is loaded or tree is constructed.
   if (!mIsLoaded || !mNotificationController->IsTreeConstructed()) {
     state |= states::BUSY | states::STALE;
   }
  
   nsIFrame* frame = GetFrame();
-  while (frame != nsnull && !frame->HasView()) {
-    frame = frame->GetParent();
-  }
- 
-  if (frame == nsnull ||
-      !CheckVisibilityInParentChain(mDocument, frame->GetViewExternal())) {
+  if (!frame || !nsCoreUtils::CheckVisibilityInParentChain(frame)) {
     state |= states::INVISIBLE | states::OFFSCREEN;
   }
 
   nsCOMPtr<nsIEditor> editor;
   GetAssociatedEditor(getter_AddRefs(editor));
   state |= editor ? states::EDITABLE : states::READONLY;
 
   return state;
@@ -406,32 +399,34 @@ NS_IMETHODIMP nsDocAccessible::GetURL(ns
     webNav->GetCurrentURI(getter_AddRefs(pURI));
     if (pURI)
       pURI->GetSpec(theURL);
   }
   CopyUTF8toUTF16(theURL, aURL);
   return NS_OK;
 }
 
-NS_IMETHODIMP nsDocAccessible::GetTitle(nsAString& aTitle)
+NS_IMETHODIMP
+nsDocAccessible::GetTitle(nsAString& aTitle)
 {
-  nsCOMPtr<nsIDOMNSDocument> domnsDocument(do_QueryInterface(mDocument));
-  if (domnsDocument) {
-    return domnsDocument->GetTitle(aTitle);
+  nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(mDocument);
+  if (!domDocument) {
+    return NS_ERROR_FAILURE;
   }
-  return NS_ERROR_FAILURE;
+  return domDocument->GetTitle(aTitle);
 }
 
-NS_IMETHODIMP nsDocAccessible::GetMimeType(nsAString& aMimeType)
+NS_IMETHODIMP
+nsDocAccessible::GetMimeType(nsAString& aMimeType)
 {
-  nsCOMPtr<nsIDOMNSDocument> domnsDocument(do_QueryInterface(mDocument));
-  if (domnsDocument) {
-    return domnsDocument->GetContentType(aMimeType);
+  nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(mDocument);
+  if (!domDocument) {
+    return NS_ERROR_FAILURE;
   }
-  return NS_ERROR_FAILURE;
+  return domDocument->GetContentType(aMimeType);
 }
 
 NS_IMETHODIMP nsDocAccessible::GetDocType(nsAString& aDocType)
 {
   nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(mDocument));
   nsCOMPtr<nsIDOMDocumentType> docType;
 
 #ifdef MOZ_XUL
@@ -602,16 +597,22 @@ nsDocAccessible::Init()
   NS_LOG_ACCDOCCREATE_FOR("document initialize", mDocument, this)
 
   // Initialize notification controller.
   nsCOMPtr<nsIPresShell> shell(GetPresShell());
   mNotificationController = new NotificationController(this, shell);
   if (!mNotificationController)
     return PR_FALSE;
 
+  // Mark the document accessible as loaded if its DOM document was loaded at
+  // this point (this can happen because a11y is started late or DOM document
+  // having no container was loaded.
+  if (mDocument->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE)
+    mIsLoaded = PR_TRUE;
+
   AddEventListeners();
   return PR_TRUE;
 }
 
 void
 nsDocAccessible::Shutdown()
 {
   if (!mWeakShell) // already shutdown
@@ -665,18 +666,18 @@ nsDocAccessible::GetFrame() const
 
   nsIFrame* root = nsnull;
   if (shell)
     root = shell->GetRootFrame();
 
   return root;
 }
 
-PRBool
-nsDocAccessible::IsDefunct()
+bool
+nsDocAccessible::IsDefunct() const
 {
   return nsHyperTextAccessibleWrap::IsDefunct() || !mDocument;
 }
 
 // nsDocAccessible protected member
 void nsDocAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aRelativeFrame)
 {
   *aRelativeFrame = GetFrame();
@@ -1032,16 +1033,24 @@ nsDocAccessible::AttributeChangedImpl(ns
       aAttribute == nsAccessibilityAtoms::title ||
       aAttribute == nsAccessibilityAtoms::aria_label ||
       aAttribute == nsAccessibilityAtoms::aria_labelledby) {
     FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE,
                                aContent);
     return;
   }
 
+  if (aAttribute == nsAccessibilityAtoms::aria_busy) {
+    PRBool isOn = !aContent->AttrValueIs(aNameSpaceID, aAttribute,
+                                         nsAccessibilityAtoms::_true, eCaseMatters);
+    nsRefPtr<AccEvent> event = new AccStateChangeEvent(aContent, states::BUSY, isOn);
+    FireDelayedAccessibleEvent(event);
+    return;
+  }
+
   if (aAttribute == nsAccessibilityAtoms::selected ||
       aAttribute == nsAccessibilityAtoms::aria_selected) {
     // ARIA or XUL selection
 
     nsAccessible *multiSelect =
       nsAccUtils::GetMultiSelectableContainer(aContent);
     // Multi selects use selection_add and selection_remove
     // Single select widgets just mirror event_selection for
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -103,17 +103,17 @@ public:
 
   // nsIDocumentObserver
   NS_DECL_NSIDOCUMENTOBSERVER
 
   // nsAccessNode
   virtual PRBool Init();
   virtual void Shutdown();
   virtual nsIFrame* GetFrame() const;
-  virtual PRBool IsDefunct();
+  virtual bool IsDefunct() const;
   virtual nsINode* GetNode() const { return mDocument; }
   virtual nsIDocument* GetDocumentNode() const { return mDocument; }
 
   // nsAccessible
   virtual void Description(nsString& aDescription);
   virtual PRUint32 NativeRole();
   virtual PRUint64 NativeState();
   virtual void ApplyARIAState(PRUint64* aState);
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -30,39 +30,40 @@
  * 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 ***** */
 
+#define CreateEvent CreateEventA
+#include "nsIDOMDocument.h"
+
 #include "States.h"
 #include "nsAccessibilityService.h"
 #include "nsApplicationAccessibleWrap.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsRelUtils.h"
 
 #include "mozilla/dom/Element.h"
 #include "nsHTMLSelectAccessible.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
 #include "nsIDocShellTreeOwner.h"
-#include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMHTMLAnchorElement.h"
 #include "nsIDOMHTMLImageElement.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLSelectElement.h"
 #include "nsIDOMDataContainerEvent.h"
-#include "nsIDOMNSDocument.h"
 #include "nsIDOMNSEvent.h"
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULPopupElement.h"
 #include "nsIDocument.h"
 #include "nsIEventListenerManager.h"
 #include "nsIFrame.h"
@@ -71,21 +72,18 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsISelectionPrivate.h"
 #include "nsIServiceManager.h"
 #include "nsPIDOMWindow.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsReadableUtils.h"
 #include "nsRootAccessible.h"
 #include "nsIDOMNSEventTarget.h"
-#include "nsIDOMDocumentEvent.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsFocusManager.h"
-#include "mozilla/dom/Element.h"
-
 
 #ifdef MOZ_XUL
 #include "nsXULTreeAccessible.h"
 #include "nsIXULDocument.h"
 #include "nsIXULWindow.h"
 #endif
 
 using namespace mozilla;
@@ -135,17 +133,17 @@ nsRootAccessible::GetName(nsAString& aNa
 
   if (mRoleMapEntry) {
     nsAccessible::GetName(aName);
     if (!aName.IsEmpty()) {
       return NS_OK;
     }
   }
 
-  nsCOMPtr<nsIDOMNSDocument> document(do_QueryInterface(mDocument));
+  nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mDocument);
   return document->GetTitle(aName);
 }
 
 PRUint32
 nsRootAccessible::NativeRole()
 {
   // If it's a <dialog> or <wizard>, use nsIAccessibleRole::ROLE_DIALOG instead
   dom::Element *root = mDocument->GetRootElement();
@@ -410,21 +408,21 @@ nsRootAccessible::FireCurrentFocusEvent(
 
   // Simulate a focus event so that we can reuse code that fires focus for
   // container children like treeitems.
   nsCOMPtr<nsINode> focusedNode = GetCurrentFocus();
   if (!focusedNode) {
     return; // No current focus
   }
 
-  nsCOMPtr<nsIDOMDocumentEvent> docEvent = do_QueryInterface(mDocument);
-  if (docEvent) {
+  nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
+  if (domDoc) {
     nsCOMPtr<nsIDOMEvent> event;
-    if (NS_SUCCEEDED(docEvent->CreateEvent(NS_LITERAL_STRING("Events"),
-                                           getter_AddRefs(event))) &&
+    if (NS_SUCCEEDED(domDoc->CreateEvent(NS_LITERAL_STRING("Events"),
+                                         getter_AddRefs(event))) &&
         NS_SUCCEEDED(event->InitEvent(NS_LITERAL_STRING("focus"), PR_TRUE, PR_TRUE))) {
 
       nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
       nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(focusedNode));
       privateEvent->SetTarget(target);
       HandleEvent(event);
     }
   }
--- a/accessible/src/html/nsHTMLLinkAccessible.cpp
+++ b/accessible/src/html/nsHTMLLinkAccessible.cpp
@@ -76,17 +76,17 @@ nsHTMLLinkAccessible::NativeState()
 
   if (mContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::name)) {
     // This is how we indicate it is a named anchor
     // In other words, this anchor can be selected as a location :)
     // There is no other better state to use to indicate this.
     states |= states::SELECTABLE;
   }
 
-  nsEventStates state = mContent->IntrinsicState();
+  nsEventStates state = mContent->AsElement()->State();
   if (state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED |
                                   NS_EVENT_STATE_UNVISITED)) {
     states |= states::LINKED;
 
     if (state.HasState(NS_EVENT_STATE_VISITED))
       states |= states::TRAVERSED;
 
     return states;
@@ -182,12 +182,12 @@ nsHTMLLinkAccessible::GetAnchorURI(PRUin
 // Protected members
 
 PRBool
 nsHTMLLinkAccessible::IsLinked()
 {
   if (IsDefunct())
     return PR_FALSE;
 
-  nsEventStates state = mContent->IntrinsicState();
+  nsEventStates state = mContent->AsElement()->State();
   return state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED |
                                      NS_EVENT_STATE_UNVISITED);
 }
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp
+++ b/accessible/src/msaa/nsAccessNodeWrap.cpp
@@ -49,21 +49,23 @@
 #include "nsWinUtils.h"
 
 #include "nsAttrName.h"
 #include "nsIDocument.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMNSHTMLElement.h"
 #include "nsIFrame.h"
 #include "nsINameSpaceManager.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
 #include "nsPIDOMWindow.h"
 #include "nsIServiceManager.h"
 
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+
 /// the accessible library and cached methods
 HINSTANCE nsAccessNodeWrap::gmAccLib = nsnull;
 HINSTANCE nsAccessNodeWrap::gmUserLib = nsnull;
 LPFNACCESSIBLEOBJECTFROMWINDOW nsAccessNodeWrap::gmAccessibleObjectFromWindow = nsnull;
 LPFNLRESULTFROMOBJECT nsAccessNodeWrap::gmLresultFromObject = NULL;
 LPFNNOTIFYWINEVENT nsAccessNodeWrap::gmNotifyWinEvent = nsnull;
 LPFNGETGUITHREADINFO nsAccessNodeWrap::gmGetGUIThreadInfo = nsnull;
 
@@ -706,32 +708,26 @@ void nsAccessNodeWrap::TurnOffNewTabSwit
       // no screen reader we're interested in. Bail out.
       return;
     }
   }
 
   // Check to see if the pref for disallowing CtrlTab is already set.
   // If so, bail out.
   // If not, set it.
-  nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
-  if (prefs) {
-    PRBool hasDisallowNewCtrlTabPref = PR_FALSE;
-    nsresult rv = prefs->PrefHasUserValue(CTRLTAB_DISALLOW_FOR_SCREEN_READERS_PREF,
-             &hasDisallowNewCtrlTabPref);
-    if (NS_SUCCEEDED(rv) && hasDisallowNewCtrlTabPref) {
-      // This pref has been set before. There is no default for it.
-      // Do nothing further, respect the setting that's there.
-      // That way, if noone touches it, it'll stay on after toggled once.
-      // If someone decided to turn it off, we respect that, too.
-      return;
-    }
-    
-    // Value has never been set, set it.
-    prefs->SetBoolPref(CTRLTAB_DISALLOW_FOR_SCREEN_READERS_PREF, PR_TRUE);
+  if (Preferences::HasUserValue(CTRLTAB_DISALLOW_FOR_SCREEN_READERS_PREF)) {
+    // This pref has been set before. There is no default for it.
+    // Do nothing further, respect the setting that's there.
+    // That way, if noone touches it, it'll stay on after toggled once.
+    // If someone decided to turn it off, we respect that, too.
+    return;
   }
+  
+  // Value has never been set, set it.
+  Preferences::SetBool(CTRLTAB_DISALLOW_FOR_SCREEN_READERS_PREF, PR_TRUE);
 }
 
 void nsAccessNodeWrap::DoATSpecificProcessing()
 {
   if (IsOnlyMsaaCompatibleJawsPresent())
     // All versions below 8.0.2173 are not compatible
     gIsIA2Disabled  = PR_TRUE;
 
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -53,17 +53,16 @@
 #include "AccessibleStates.h"
 
 #include "nsIMutableArray.h"
 #include "nsIDOMDocument.h"
 #include "nsIFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsINameSpaceManager.h"
 #include "nsINodeInfo.h"
-#include "nsIPrefService.h"
 #include "nsRootAccessible.h"
 #include "nsIServiceManager.h"
 #include "nsTextFormatter.h"
 #include "nsIView.h"
 #include "nsIViewManager.h"
 #include "nsRoleMap.h"
 #include "nsEventMap.h"
 #include "nsArrayUtils.h"
--- a/accessible/src/xul/nsXULMenuAccessible.cpp
+++ b/accessible/src/xul/nsXULMenuAccessible.cpp
@@ -45,25 +45,27 @@
 
 #include "nsIDOMElement.h"
 #include "nsIDOMXULElement.h"
 #include "nsIMutableArray.h"
 #include "nsIDOMXULContainerElement.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMKeyEvent.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
 #include "nsIServiceManager.h"
 #include "nsIPresShell.h"
 #include "nsIContent.h"
 #include "nsGUIEvent.h"
 #include "nsILookAndFeel.h"
 #include "nsWidgetsCID.h"
 
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+
 
 static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULSelectableAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULSelectableAccessible::
@@ -405,20 +407,17 @@ nsXULMenuitemAccessible::GetKeyboardShor
 
   nsAccessible* parentAcc = GetParent();
   if (parentAcc) {
     if (parentAcc->NativeRole() == nsIAccessibleRole::ROLE_MENUBAR) {
       // If top level menu item, add Alt+ or whatever modifier text to string
       // No need to cache pref service, this happens rarely
       if (gMenuAccesskeyModifier == -1) {
         // Need to initialize cached global accesskey pref
-        gMenuAccesskeyModifier = 0;
-        nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
-        if (prefBranch)
-          prefBranch->GetIntPref("ui.key.menuAccessKey", &gMenuAccesskeyModifier);
+        gMenuAccesskeyModifier = Preferences::GetInt("ui.key.menuAccessKey", 0);
       }
 
       nsAutoString propertyKey;
       switch (gMenuAccesskeyModifier) {
         case nsIDOMKeyEvent::DOM_VK_CONTROL:
           propertyKey.AssignLiteral("VK_CONTROL");
           break;
         case nsIDOMKeyEvent::DOM_VK_ALT:
--- a/accessible/src/xul/nsXULTreeAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeAccessible.cpp
@@ -151,18 +151,18 @@ nsXULTreeAccessible::GetValue(nsAString&
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeAccessible: nsAccessNode implementation
 
-PRBool
-nsXULTreeAccessible::IsDefunct()
+bool
+nsXULTreeAccessible::IsDefunct() const
 {
   return nsAccessibleWrap::IsDefunct() || !mTree || !mTreeView;
 }
 
 void
 nsXULTreeAccessible::Shutdown()
 {
   // XXX: we don't remove accessible from document cache if shutdown wasn't
@@ -829,18 +829,18 @@ nsXULTreeItemAccessibleBase::DoAction(PR
 
   DoCommand(nsnull, aIndex);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessibleBase: nsAccessNode implementation
 
-PRBool
-nsXULTreeItemAccessibleBase::IsDefunct()
+bool
+nsXULTreeItemAccessibleBase::IsDefunct() const
 {
   if (nsAccessibleWrap::IsDefunct() || !mTree || !mTreeView || mRow < 0)
     return PR_TRUE;
 
   PRInt32 rowCount = 0;
   nsresult rv = mTreeView->GetRowCount(&rowCount);
   return NS_FAILED(rv) || mRow >= rowCount;
 }
@@ -1086,18 +1086,18 @@ nsXULTreeItemAccessible::GetName(nsAStri
     mTreeView->GetCellValue(mRow, mColumn, aName);
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeItemAccessible: nsAccessNode implementation
 
-PRBool
-nsXULTreeItemAccessible::IsDefunct()
+bool
+nsXULTreeItemAccessible::IsDefunct() const
 {
   return nsXULTreeItemAccessibleBase::IsDefunct() || !mColumn;
 }
 
 PRBool
 nsXULTreeItemAccessible::Init()
 {
   if (!nsXULTreeItemAccessibleBase::Init())
--- a/accessible/src/xul/nsXULTreeAccessible.h
+++ b/accessible/src/xul/nsXULTreeAccessible.h
@@ -75,17 +75,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeAccessible,
                                            nsAccessible)
 
   // nsIAccessible
   NS_IMETHOD GetValue(nsAString& aValue);
   NS_IMETHOD GetFocusedChild(nsIAccessible **aFocusedChild);
 
   // nsAccessNode
-  virtual PRBool IsDefunct();
+  virtual bool IsDefunct() const;
   virtual void Shutdown();
 
   // nsAccessible
   virtual PRUint32 NativeRole();
   virtual PRUint64 NativeState();
   virtual nsAccessible* GetChildAtPoint(PRInt32 aX, PRInt32 aY,
                                         EWhichChildAtPoint aWhichChild);
 
@@ -196,17 +196,17 @@ public:
                            PRInt32 *aSimilarItemsInGroup,
                            PRInt32 *aPositionInGroup);
 
   NS_IMETHOD GetNumActions(PRUint8 *aCount);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 aIndex);
 
   // nsAccessNode
-  virtual PRBool IsDefunct();
+  virtual bool IsDefunct() const;
   virtual void Shutdown();
   virtual bool IsPrimaryForNode() const;
 
   // nsAccessible
   virtual PRUint64 NativeState();
   virtual PRInt32 GetIndexInParent() const;
 
   // nsXULTreeItemAccessibleBase
@@ -261,17 +261,17 @@ class nsXULTreeItemAccessible : public n
 public:
   nsXULTreeItemAccessible(nsIContent *aContent, nsIWeakReference *aShell,
                           nsAccessible *aParent, nsITreeBoxObject *aTree,
                           nsITreeView *aTreeView, PRInt32 aRow);
 
   NS_IMETHOD GetName(nsAString& aName);
 
   // nsAccessNode
-  virtual PRBool IsDefunct();
+  virtual bool IsDefunct() const;
   virtual PRBool Init();
   virtual void Shutdown();
 
   // nsAccessible
   virtual PRUint32 NativeRole();
 
   // nsXULTreeItemAccessibleBase
   virtual void RowInvalidated(PRInt32 aStartColIdx, PRInt32 aEndColIdx);
--- a/accessible/src/xul/nsXULTreeGridAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeGridAccessible.cpp
@@ -1082,18 +1082,18 @@ nsXULTreeGridCellAccessible::IsSelected(
   NS_ENSURE_SUCCESS(rv, rv);
 
   return selection->IsSelected(mRow, aIsSelected);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridCellAccessible: nsAccessNode implementation
 
-PRBool
-nsXULTreeGridCellAccessible::IsDefunct()
+bool
+nsXULTreeGridCellAccessible::IsDefunct() const
 {
   return nsLeafAccessible::IsDefunct() || !mParent || !mTree || !mTreeView ||
     !mColumn;
 }
 
 PRBool
 nsXULTreeGridCellAccessible::Init()
 {
--- a/accessible/src/xul/nsXULTreeGridAccessible.h
+++ b/accessible/src/xul/nsXULTreeGridAccessible.h
@@ -150,17 +150,17 @@ public:
   NS_IMETHOD GetNumActions(PRUint8 *aCount);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 aIndex);
 
   // nsIAccessibleTableCell
   NS_DECL_NSIACCESSIBLETABLECELL
 
   // nsAccessNode
-  virtual PRBool IsDefunct();
+  virtual bool IsDefunct() const;
   virtual PRBool Init();
   virtual bool IsPrimaryForNode() const;
 
   // nsAccessible
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
   virtual PRUint32 NativeRole();
   virtual PRUint64 NativeState();
   virtual PRInt32 GetIndexInParent() const;
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -85,26 +85,24 @@ include $(topsrcdir)/config/rules.mk
 		value.js \
 		test_aria_activedescendant.html \
 		test_aria_role_article.html \
 		test_aria_role_equation.html \
 		test_aria_roles.html \
 		test_aria_roles.xul \
 		test_aria_token_attrs.html \
 		test_bug420863.html \
-	$(warning   test_childAtPoint.html temporarily disabled) \
-	$(warning	test_childAtPoint.xul temporarily disabled) \
+		test_childAtPoint.html \
+		test_childAtPoint.xul \
 		test_descr.html \
 		test_elm_landmarks.html \
 		test_elm_listbox.xul \
-	$(warning   test_elm_media.html temporarily disabled) \
 		test_elm_nsApplicationAcc.html \
 		test_elm_plugin.html \
 		test_keys.html \
-	$(warning test_nsIAccessible_comboboxes.xul temporarily disabled) \
  		test_nsIAccessible_selects.html \
 		test_nsIAccessibleDocument.html \
 		test_nsIAccessibleImage.html \
 		test_nsIAccessNode_utils.html \
 		test_nsOuterDocAccessible.html \
 		test_role_nsHyperTextAcc.html \
 		test_takeFocus.html \
 		test_text_caret.html \
--- a/accessible/tests/mochitest/actions/Makefile.in
+++ b/accessible/tests/mochitest/actions/Makefile.in
@@ -47,14 +47,15 @@ include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
 		test_anchors.html \
 		test_aria.html \
 		test_general.html \
 		test_general.xul \
 		test_inputs.html \
 		test_link.html \
+		test_media.html \
 		test_tree.xul \
 		test_treegrid.xul \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
--- a/accessible/tests/mochitest/actions/test_general.html
+++ b/accessible/tests/mochitest/actions/test_general.html
@@ -31,19 +31,29 @@
           ID: "li_clickable2",
           actionName: "click",
           events: CLICK_EVENTS
         },
         {
           ID: "li_clickable3",
           actionName: "click",
           events: CLICK_EVENTS
+        },
+        {
+          ID: "onclick_img",
+          actionName: "click",
+          events: CLICK_EVENTS
         }
       ];
+
       testActions(actionsArray);
+
+      getAccessible("onclick_img").takeFocus();
+is(getAccessible("link1").numActions, 1, "links should have one action");
+is(getAccessible("link2").numActions, 1, "link with onclick handler should have 1 action");
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 
 <body>
@@ -53,20 +63,31 @@
      title="nsHTMLLiAccessible shouldn't be inherited from linkable accessible">
     Mozilla Bug 523789
   </a><br>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=423409"
      title="Expose click action if mouseup and mousedown are registered">
     Mozilla Bug 423409
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=659620"
+     title="hang when trying to edit a page on wikimo with NVDA running">
+    Mozilla Bug 659620
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <ul>
     <li id="li_clickable1" onclick="">Clickable list item</li>
     <li id="li_clickable2" onmousedown="">Clickable list item</li>
     <li id="li_clickable3" onmouseup="">Clickable list item</li>
   </ul>
+
+  <!-- linkable accessibles -->
+  <img id="onclick_img" onclick="" src="../moz.png">
+
+  <a id="link1" href="www">linkable textleaf accessible</a>
+  <div id="link2" onclick="">linkable textleaf accessible</div>
 </body>
 </html>
rename from accessible/tests/mochitest/test_elm_media.html
rename to accessible/tests/mochitest/actions/test_media.html
--- a/accessible/tests/mochitest/test_elm_media.html
+++ b/accessible/tests/mochitest/actions/test_media.html
@@ -8,25 +8,25 @@ https://bugzilla.mozilla.org/show_bug.cg
   <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>
+          src="../common.js"></script>
   <script type="application/javascript"
-          src="events.js"></script>
+          src="../events.js"></script>
   <script type="application/javascript"
-          src="actions.js"></script>
+          src="../actions.js"></script>
   <script type="application/javascript"
-          src="role.js"></script>
+          src="../role.js"></script>
   <script type="application/javascript"
-          src="states.js"></script>
+          src="../states.js"></script>
 
   <script type="application/javascript">
 
     // gA11yEventDumpID = "eventDump";
 
     function focusChecker(aAcc)
     {
       this.type = EVENT_FOCUS;
@@ -54,87 +54,49 @@ https://bugzilla.mozilla.org/show_bug.cg
         is(aEvent.accessible.name, aName,
            "Wrong name of " + prettyName(aEvent.accessible) + " on focus");
       }
     }
 
     function doTest()
     {
       //////////////////////////////////////////////////////////////////////////
-      // test the accessible tree
+      // test actions of audio controls
 
-      var accTree = {
-        role: ROLE_GROUPING,
-        children: [
-          { // start/stop button
-            role: ROLE_PUSHBUTTON,
-            name: "Play",
-            states: {
-              states: STATE_FOCUSABLE
-            }
-          },
-          { // buffer bar
-            role: ROLE_PROGRESSBAR
-          },
-          { // progress bar
-            role: ROLE_PROGRESSBAR
-          },
-          { // slider of progress bar
-            role: ROLE_SLIDER,
-            name: "0:00 of 0:01 elapsed",
-            states: {
-              states: STATE_FOCUSABLE
-            }
-          },
-          { // duration label, role="presentation"
-            role: ROLE_NOTHING
-          },
-          { // mute button
-            role: ROLE_PUSHBUTTON,
-            name: "Mute",
-            states: {
-              states: STATE_FOCUSABLE
-            }
-          }
-        ]
-      };
-      testAccessibleTree("audio", accTree);
-
-      //////////////////////////////////////////////////////////////////////////
-      // test actions of audio controls
+      todo(false, "Focus test are disabled until bug 494175 is fixed.");
 
       var audioElm = getAccessible("audio");
       var playBtn = audioElm.firstChild;
       var scrubber = playBtn.nextSibling.nextSibling.nextSibling;
       var muteBtn = audioElm.lastChild;
 
       var actions = [
         {
           ID: muteBtn,
           actionName: "press",
           events: CLICK_EVENTS,
           eventSeq: [
-            new focusChecker(muteBtn),
+     //       new focusChecker(muteBtn),
             new nameChecker(muteBtn, "Unmute"),
           ]
         },
-        {
-          ID: scrubber,
-          actionName: "activate",
-          events: null,
-          eventSeq: [
-            new focusChecker(scrubber)
-          ]
-        },
+     //   {
+     //     ID: scrubber,
+     //     actionName: "activate",
+     //     events: null,
+     //     eventSeq: [
+     //       new focusChecker(scrubber)
+     //     ]
+     //   },
         {
           ID: playBtn,
           actionName: "press",
           events: CLICK_EVENTS,
           eventSeq: [
-            new focusChecker(playBtn),
+     //       new focusChecker(playBtn),
             new nameChecker(playBtn, "Pause"),
           ]
         }
       ];
 
       testActions(actions); // Will call SimpleTest.finish();
     }
 
@@ -147,14 +109,14 @@ https://bugzilla.mozilla.org/show_bug.cg
   <a target="_blank"
      title="Expose HTML5 video and audio elements' embedded controls through accessibility APIs"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=483573">Mozilla Bug 483573</a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
-  <audio id="audio" src="bug461281.ogg"
+  <audio id="audio" src="../bug461281.ogg"
          controls="true"></audio>
 
   <div id="eventDump"></div>
 </body>
 </html>
--- a/accessible/tests/mochitest/attributes/test_obj_group.xul
+++ b/accessible/tests/mochitest/attributes/test_obj_group.xul
@@ -25,31 +25,34 @@
       testGroupAttrs("item1", 1, 2);
       testGroupAttrs("item2", 2, 2);
 
       //////////////////////////////////////////////////////////////////////////
       // xul:menu (bug 443881)
       var menu1 = document.getElementById("menu_item1");
       menu1.open = true;
 
-      window.setTimeout(function() {
+      menu1.addEventListener("popupshown", function() {
         var menu2 = document.getElementById("menu_item2");
         menu2.open = true;
 
-        window.setTimeout(function() {
+        menu2.addEventListener("popupshown", function() {
           testGroupAttrs("menu_item1.1", 1, 1);
           testGroupAttrs("menu_item1.2", 1, 3);
           testGroupAttrs("menu_item1.4", 2, 3);
           testGroupAttrs("menu_item2", 3, 3);
           testGroupAttrs("menu_item2.1", 1, 2, 1);
           testGroupAttrs("menu_item2.2", 2, 2, 1);
 
+          menu1.open = false;
+          menu2.open = false;
+
           SimpleTest.finish();
-        }, 200);
-      }, 200);
+        }, false);
+      }, false);
 
       //////////////////////////////////////////////////////////////////////////
       // xul:tab
       testGroupAttrs("tab1", 1, 2);
       testGroupAttrs("tab2", 2, 2);
 
       //////////////////////////////////////////////////////////////////////////
       // xul:radio
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -88,17 +88,17 @@ function addA11yLoadEvent(aFunc)
       function()
       {
         var accDoc = getAccessible(document);
         var state = {};
         accDoc.getState(state, {});
         if (state.value & STATE_BUSY)
           return waitForDocLoad();
 
-        window.setTimeout(aFunc, 150);
+        window.setTimeout(aFunc, 0);
       },
       0
     );
   }
 
   SimpleTest.waitForFocus(waitForDocLoad);
 }
 
--- a/accessible/tests/mochitest/events/test_aria_statechange.html
+++ b/accessible/tests/mochitest/events/test_aria_statechange.html
@@ -21,65 +21,97 @@
   <script type="application/javascript">
 
 
     /**
      * Do tests.
      */
     var gQueue = null;
 
+    // Debug stuff.
+    //gA11yEventDumpID = "eventdump";
+    // gA11yEventDumpToConsole = true;
+
     function expandNode(aNodeOrID, bExpand)
     {
       this.DOMNode = getNode(aNodeOrID);
 
-      this.invoke = function expand_invoke() {
+      this.invoke = function expandNode_invoke() {
         // Note: this should fire an EVENT_STATE_CHANGE
         this.DOMNode.setAttribute("aria-expanded", bExpand);
       };
 
-      this.check = function expand_check() {
+      this.check = function expandNode_check() {
         testStates(aNodeOrID,
                    bExpand ? STATE_EXPANDED : STATE_COLLAPSED,
                    EXT_STATE_EXPANDABLE);
       };
 
-      this.getID = function changeValue_getID() {
+      this.getID = function expandNode_getID() {
         return prettyName(aNodeOrID) + " aria-expanded changed";
       };
     }
 
+    function busyify(aNodeOrID, aBusy)
+    {
+      this.DOMNode = getNode(aNodeOrID);
+
+      this.invoke = function busyify_invoke() {
+        this.DOMNode.setAttribute("aria-busy", aBusy);
+      };
+
+      this.check = function busyify_check(event) {
+        testStates(aNodeOrID,
+                   (aBusy ? STATE_BUSY : 0), 0,
+                   (aBusy ? 0 : STATE_BUSY), 0);
+      };
+
+      this.getID = function busyify_getID() {
+        return prettyName(aNodeOrID) + " aria-busy changed to " + aBusy;
+      };
+    }
+
     function doTests()
     {
-      gQueue = new eventQueue(nsIAccessibleEvent.EVENT_STATE_CHANGE);
+      gQueue = new eventQueue(EVENT_STATE_CHANGE);
 
       gQueue.push(new expandNode("section", true));
       gQueue.push(new expandNode("section", false));
       gQueue.push(new expandNode("div", true));
       gQueue.push(new expandNode("div", false));
 
+      gQueue.push(new busyify("aria_doc", true));
+      gQueue.push(new busyify("aria_doc", false));
       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=551684"
      title="No statechange event for aria-expanded on native HTML elements, is fired on ARIA widgets">
     Mozilla Bug 551684
   </a>
 
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=648133"
+     title="fire state change event for aria-busy"
+    Mozilla Bug 648133
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
   <div id="eventdump"></div>
 
   <!-- aria-expanded -->
   <div id="section" role="section" aria-expanded="false">expandable section</div>
   <div id="div" aria-expanded="false">expandable native div</div>
 
+  <!-- aria-busy -->
+  <div id="aria_doc" role="document" tabindex="0">A document</div>
 </body>
 </html>
--- a/accessible/tests/mochitest/events/test_docload.html
+++ b/accessible/tests/mochitest/events/test_docload.html
@@ -113,16 +113,35 @@
         if (aAction == kRemove)
           return "remove iframe";
 
         return "change display style of iframe to " +
           ((aAction == kHide) ? "none" : "block");
       }
     }
 
+    function makeIFrameVisible(aID)
+    {
+      this.DOMNode = getNode(aID);
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, this.DOMNode.parentNode)
+      ];
+
+      this.invoke = function makeIFrameVisible_invoke()
+      {
+        this.DOMNode.style.visibility = "visible";
+      }
+
+      this.getID = function makeIFrameVisible_getID()
+      {
+        return "The accessible for DOM document loaded before it's shown shouldn't have busy state.";
+      }
+    }
+
     function openDialogWnd(aURL)
     {
       // Get application root accessible.
       var docAcc = getAccessible(document);
       while (docAcc) {
         this.mRootAcc = docAcc;
         try {
           docAcc = docAcc.parent;
@@ -219,33 +238,51 @@
 
     ////////////////////////////////////////////////////////////////////////////
     // Do tests
 
     var gQueue = null;
 
     // Debug stuff.
     // gA11yEventDumpID = "eventdump";
-    // gA11yEventDumpToConsole = true;
+    //gA11yEventDumpToConsole = true;
 
     function doTests()
     {
       gQueue = new eventQueue();
 
       gQueue.push(new changeIframeSrc("iframe", "about:"));
       gQueue.push(new changeIframeSrc("iframe", "about:buildconfig"));
       gQueue.push(new morphIFrame("iframe", kHide));
       gQueue.push(new morphIFrame("iframe", kShow));
       gQueue.push(new morphIFrame("iframe", kRemove));
+      gQueue.push(new makeIFrameVisible("iframe2"));
       gQueue.push(new openDialogWnd("about:"));
       gQueue.push(new openWndShutdownDoc());
 
+      gQueue.onFinish = doLastCallTests;
+
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
+    function doLastCallTests()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      // makeIFrameVisible() test, part2
+
+      // The document shouldn't have busy state (the DOM document was loaded
+      // before its accessible was created). Do this test lately to make sure
+      // the content of document accessible was created initially, prior to this
+      // the document accessible keeps busy state. The initial creation happens
+      // asynchronously after document creation, there are no events we could
+      // use to catch it.
+      var iframeDoc = getAccessible("iframe2").firstChild;
+      testStates(iframeDoc, 0, 0, STATE_BUSY);
+    }
+
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
 
 <body>
 
   <a target="_blank"
@@ -263,18 +300,24 @@
      title="Reorganize accessible document handling">
     Mozilla Bug 566103
   </a><br>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=571459"
      title="Shutdown document accessible when presshell goes away">
     Mozilla Bug 571459
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=658185"
+     title="The DOM document loaded before it's shown shouldn't have busy state">
+    Mozilla Bug 658185
+  </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <div id="testContainer"><iframe id="iframe"></iframe></div>
+  <div id="testContainer2"><iframe id="iframe2" src="about:" style="visibility: hidden;"></iframe></div>
   <div id="eventdump"></div>
 </body>
 </html>
--- a/accessible/tests/mochitest/states/Makefile.in
+++ b/accessible/tests/mochitest/states/Makefile.in
@@ -43,16 +43,18 @@ VPATH		= @srcdir@
 relativesrcdir  = accessible/states
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
 		test_aria.html \
 		test_aria_imgmap.html \
+		test_aria_tabs.html \
+		test_comboboxes.xul \
 		test_doc.html \
 		test_docarticle.html \
 		test_editablebody.html \
 		test_frames.html \
 		test_inputs.html \
 		test_inputs.xul \
 		test_link.html \
 		test_popup.xul \
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/states/test_aria_tabs.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <title>Test ARIA tab accessible selected state</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>
+
+  <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 focusARIATab(aID, aIsSelected)
+    {
+      this.DOMNode = getNode(aID);
+
+      this.invoke = function focusARIATab_invoke()
+      {
+        this.DOMNode.focus();
+      }
+
+      this.check = function focusARIATab_check(aEvent)
+      {
+        testStates(this.DOMNode, aIsSelected ? STATE_SELECTED : 0, 0,
+                   aIsSelected ? 0 : STATE_SELECTED);
+      }
+
+      this.getID = function focusARIATab_getID()
+      {
+        return "Focused ARIA Tab with aria-selected=" +
+                (aIsSelected ? "true, should" : "false, shouldn't") +
+                " have selected state on " + prettyName(aID);
+      }
+    }
+
+    function focusActiveDescendantTab(aTabID, aTabListID, aIsSelected)
+    {
+      this.DOMNode = getNode(aTabID);
+      this.tabListDOMNode = getNode(aTabListID);
+
+      this.invoke = function focusActiveDescendantTab_invoke()
+      {
+        this.tabListDOMNode.setAttribute("aria-activedescendant", aTabID);
+        this.tabListDOMNode.focus();
+      }
+
+      this.check = function focusActiveDescendantTab_check(aEvent)
+      {
+        testStates(this.DOMNode, aIsSelected ? STATE_SELECTED : 0, 0,
+                   aIsSelected ? 0 : STATE_SELECTED);
+      }
+
+      this.getID = function tabActiveDescendant_getID()
+      {
+        return "ARIA Tab with activedescendant " +
+                (aIsSelected ? "should" : "shouldn't") +
+                " have the selected state on " + prettyName(aTabID);
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Test
+
+    //gA11yEventDumpID = "eventdump"; // debug stuff
+    //gA11yEventDumpToConsole = true;
+
+    var gQueue = null;
+
+    function doTest()
+    {
+      // simple tabs
+      testStates("aria_tab1", 0, 0, STATE_SELECTED);
+      testStates("aria_tab2", STATE_SELECTED);
+
+      // To make sure our focus != selected is truly under test, we need to
+      // make sure our cache of what currently has focus is correct, which
+      // we update asyncronously.
+      gQueue = new eventQueue(EVENT_FOCUS);
+
+      gQueue.push(new focusARIATab("aria_tab1", true));
+      gQueue.push(new focusARIATab("aria_tab3", false));
+      gQueue.push(new focusARIATab("aria_tab2", true));
+
+      // selection through aria-activedescendant
+      // Make sure initially setting it selects the tab.
+      gQueue.push(new focusActiveDescendantTab("aria_tab5", "aria_tablist2", true));
+
+      // Now, make sure if one is selected selection gets transferred properly.
+      gQueue.push(new focusActiveDescendantTab("aria_tab6", "aria_tablist2", true));
+
+      // Now, make sure the focused but explicitly unselected one behaves.
+      gQueue.push(new focusActiveDescendantTab("aria_tab4", "aria_tablist2", false));
+
+      gQueue.invoke(); // SimpleTest.finish() will be called in the end
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=653601"
+     title="aria-selected ignored for ARIA tabs">
+    Mozilla Bug 653601
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <!-- tab -->
+  <div id="aria_tablist" role="tablist">
+    <div id="aria_tab1" role="tab" tabindex="0">unselected tab</div>
+    <div id="aria_tab2" role="tab" tabindex="0" aria-selected="true">selected tab</div>
+    <div id="aria_tab3" role="tab" tabindex="0" aria-selected="false">focused explicitly unselected tab</div>
+  </div>
+  
+  <!-- test activeDescendant -->
+  <div id="aria_tablist2" role="tablist" tabindex="0">
+    <div id="aria_tab4" role="tab" aria-selected="false">focused explicitly unselected tab</div>
+    <div id="aria_tab5" role="tab">initially selected tab</div>
+    <div id="aria_tab6" role="tab">later selected tab</div>
+  </div>
+</body>
+</html>
rename from accessible/tests/mochitest/test_nsIAccessible_comboboxes.xul
rename to accessible/tests/mochitest/states/test_comboboxes.xul
--- a/accessible/tests/mochitest/test_nsIAccessible_comboboxes.xul
+++ b/accessible/tests/mochitest/states/test_comboboxes.xul
@@ -11,19 +11,19 @@
   <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 type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
 
   <script type="application/javascript"
-          src="common.js" />
+          src="../common.js" />
   <script type="application/javascript"
-          src="events.js" />        
+          src="../events.js" />
 
   <script type="application/javascript">
   <![CDATA[
     function openHideCombobox(aComboboxNodeOrID, aIsOpen)
     {
       this.invoke = function invoke()
       {
         synthesizeMouse(this.DOMNode, 5, 5, {});
@@ -59,16 +59,17 @@
       gQueue.push(new openHideCombobox(ID, true));
       gQueue.push(new openHideCombobox(ID, false));
 
       // XXX: searchbar doesn't fire state change events because accessible
       // parent of combobox_list accessible is pushbutton accessible.
       //var searchbar = document.getElementById("searchbar");
       //gQueue.push(new openHideCombobox(searchbar, true));
       //gQueue.push(new openHideCombobox(searchbar, false));
+      todo(false, "Enable states test for XUL searchbar widget!");
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     // This is the hack needed for searchbar work outside of browser.
     function getBrowser()
     {
       return {
--- a/accessible/tests/mochitest/test_childAtPoint.html
+++ b/accessible/tests/mochitest/test_childAtPoint.html
@@ -20,29 +20,29 @@
       // Not specific case, child and deepchild testing.
       var list = getAccessible("list");
       var listitem = getAccessible("listitem");
       var image = getAccessible("image");
       testChildAtPoint(list, 1, 1, false, listitem);
       testChildAtPoint(list, 1, 1, true, image.firstChild);
 
       // ::MustPrune case (in this case childAtPoint doesn't look inside a
-      // button), point is inside of button.
-      var btn = getAccessible("btn");
-      testChildAtPoint(btn, 1, 1, false, btn);
-      testChildAtPoint(btn, 1, 1, true, btn);
+      // textbox), point is inside of textbox.
+      var txt = getAccessible("txt");
+      testChildAtPoint(txt, 1, 1, false, txt);
+      testChildAtPoint(txt, 1, 1, true, txt);
 
-      // ::MustPrune case, point is outside of button accessible but is in
+      // ::MustPrune case, point is outside of textbox accessible but is in
       // document.
-      testChildAtPoint(btn, -1, 1, false, null);
-      testChildAtPoint(btn, -1, 1, true, null);
+      testChildAtPoint(txt, -1, 1, false, null);
+      testChildAtPoint(txt, -1, 1, true, null);
 
       // ::MustPrune case, point is outside of root accessible.
-      testChildAtPoint(btn, -10000, 10000, false, null);
-      testChildAtPoint(btn, -10000, 10000, true, null);
+      testChildAtPoint(txt, -10000, 10000, false, null);
+      testChildAtPoint(txt, -10000, 10000, true, null);
 
       // Not specific case, point is inside of label accessible.
       var label = getAccessible("label");
       var labelText = label.firstChild;
       testChildAtPoint(label, 1, 1, false, labelText);
       testChildAtPoint(label, 1, 1, true, labelText);
   
       // Not specific case, point is outside of label accessible.
@@ -77,16 +77,16 @@
   </pre>
 
   <div role="list" id="list">
     <div role="listitem" id="listitem"><span role="image" id="image">img</span>item</div>
   </div>
 
   <span role="label">label1</span><span role="label" id="label">label2</span>
 
-  <span role="button">btn1</span><span role="button" id="btn">btn2</span>
+  <span role="textbox">textbox1</span><span role="textbox" id="txt">textbox2</span>
 
   <div id="outofflow" style="width: 10px; height: 10px; position: absolute; left: 0px; top: 0px; background-color: yellow;">
   </div>
   <div id="area" style="width: 100px; height: 100px; background-color: blue;"></div>
 
 </body>
 </html>
--- a/accessible/tests/mochitest/test_childAtPoint.xul
+++ b/accessible/tests/mochitest/test_childAtPoint.xul
@@ -19,18 +19,17 @@
   <script type="application/javascript"
           src="layout.js" />
 
   <script type="application/javascript">
   <![CDATA[
     function doTest()
     {
       // Initialize the tree
-      var view = new inTreeView();
-      view.mRowCount = 5;
+      var view = new nsTableTreeView(5);
 
       var tree = getNode("tree");
       var treeBox = tree.treeBoxObject;
       treeBox.view = view;
 
       // Tests
       var treecols = getNode("treecols");
       var x = treecols.boxObject.x;
--- a/accessible/tests/mochitest/tree/test_media.html
+++ b/accessible/tests/mochitest/tree/test_media.html
@@ -25,34 +25,43 @@ https://bugzilla.mozilla.org/show_bug.cg
     {
       //////////////////////////////////////////////////////////////////////////
       // test the accessible tree
 
       var accTree = {
         role: ROLE_GROUPING,
         children: [
           { // start/stop button
-            role: ROLE_PUSHBUTTON
+            role: ROLE_PUSHBUTTON,
+            name: "Play",
+            children: []
           },
           { // buffer bar
-            role: ROLE_PROGRESSBAR
+            role: ROLE_PROGRESSBAR,
+            children: []
           },
           { // progress bar
-            role: ROLE_PROGRESSBAR
+            role: ROLE_PROGRESSBAR,
+            children: []
           },
           { // slider of progress bar
-            role: ROLE_SLIDER
+            role: ROLE_SLIDER,
+            //name: "0:00 of 0:02 elapsed",
+            children: []
           },
           { // mute button
-            role: ROLE_PUSHBUTTON
+            role: ROLE_PUSHBUTTON,
+            name: "Mute",
+            children: []
           }
         ]
       };
       testAccessibleTree("audio", accTree);
 
+      todo(false, "Enable name test for slider. Fail on Linux.");
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
--- a/accessible/tests/mochitest/tree/test_txtctrl.xul
+++ b/accessible/tests/mochitest/tree/test_txtctrl.xul
@@ -10,16 +10,18 @@
           src="chrome://mochikit/content/MochiKit/packed.js" />
   <script type="application/javascript"
           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="../events.js" />
 
   <script type="application/javascript">
   <![CDATA[
     ////////////////////////////////////////////////////////////////////////////
     // Test
 
     function doTest()
     {
@@ -103,16 +105,21 @@
           {
             // xul:menupopup
             role: ROLE_COMBOBOX_LIST,
             children: []
           }
         ]
       };
 
+      function test_txc7() {
+        testAccessibleTree("txc7", accTree);
+        SimpleTest.finish();
+      }
+
       // XPFE and Toolkit autocomplete widgets differ.
       var txc7 = document.getElementById("txc7");
       if ("clearResults" in txc7) {
         SimpleTest.ok(true, "Testing (Old) XPFE autocomplete widget.");
 
         // Popup is always created. (See code below.)
 
         accTree.children.push(
@@ -134,21 +141,24 @@
                         children: []
                       }
                     ]
                   }
                 ]
               }
             ]
           }
-          );
+        );
+        test_txc7();
+
       } else {
         SimpleTest.ok(true, "Testing (New) Toolkit autocomplete widget.");
 
-        // Dumb access to trigger popup lazy creation. (See code below.)
+        // Dumb access to trigger popup lazy creation.
+        waitForEvent(EVENT_REORDER, txc7, test_txc7);
         txc7.popup;
 
         accTree.children.push(
           {
             role: ROLE_LIST,
             children: [
               {
                 role: ROLE_LIST,
@@ -156,27 +166,18 @@
                   {
                     role: ROLE_COLUMNHEADER,
                     children: []
                   }
                 ]
               }
             ]
           }
-          );
+        );
       }
-
-      // Delay txc7 test a bit, to let Toolkit popup lazy creation complete.
-      function test_txc7() {
-        testAccessibleTree("txc7", accTree);
-  
-        SimpleTest.finish();
-      }
-      // SimpleTest.executeSoon() doesn't help here: use setTimeout() with a little delay.
-      setTimeout(test_txc7, 25);
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   ]]>
   </script>
 
   <hbox flex="1" style="overflow: auto;">
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -97,61 +97,30 @@ else
 PROGRAM = $(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
 endif
 
 CPPSRCS = nsBrowserApp.cpp
 
 LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
 LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/base
 
-ifdef BUILD_STATIC_LIBS
-ifdef _MSC_VER
-STATIC_COMPONENTS_LINKER_PATH = -LIBPATH:$(DEPTH)/staticlib
-else
-STATIC_COMPONENTS_LINKER_PATH = -L$(DEPTH)/staticlib
-endif
-LIBS += $(DEPTH)/toolkit/xre/$(LIB_PREFIX)xulapp_s.$(LIB_SUFFIX)
-else
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 LIBS += $(DIST)/bin/XUL
+TK_LIBS := $(TK_LIBS)
 else
 EXTRA_DSO_LIBS += xul
 endif
-endif
-
-ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
-TK_LIBS := $(TK_LIBS)
-endif
-
-ifdef MOZ_ENABLE_LIBXUL
-APP_XPCOM_LIBS = $(XPCOM_GLUE_LDOPTS)
-else
-MOZILLA_INTERNAL_API = 1
-APP_XPCOM_LIBS = $(XPCOM_LIBS)
-endif
 
 LIBS += \
 	$(STATIC_COMPONENTS_LINKER_PATH) \
 	$(EXTRA_DSO_LIBS) \
-	$(APP_XPCOM_LIBS) \
+	$(XPCOM_GLUE_LDOPTS) \
 	$(NSPR_LIBS) \
 	$(NULL)
 
-ifdef BUILD_STATIC_LIBS
-LIBS += \
-	$(MOZ_JS_LIBS) \
-	$(TK_LIBS) \
-	$(NULL)
-
-# Add explicit X11 dependency when building against X11 toolkits
-ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
-LIBS += $(XLDFLAGS) $(XLIBS) $(ZLIB_LIBS)
-endif
-endif
-
 ifdef MOZ_JPROF
 LIBS += -ljprof
 endif
 
 ifndef MOZ_WINCONSOLE
 ifdef MOZ_DEBUG
 MOZ_WINCONSOLE = 1
 else
@@ -166,68 +135,44 @@ NSDISTMODE = copy
 include $(topsrcdir)/config/config.mk
 
 ifdef _MSC_VER
 # Always enter a Windows program through wmain, whether or not we're
 # a console application.
 WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
 endif
 
-ifdef BUILD_STATIC_LIBS
-include $(topsrcdir)/config/static-config.mk
-
-EXTRA_DEPS	+= \
-	$(STATIC_EXTRA_DEPS) \
-	$(NULL)
-DEFINES		+= $(STATIC_DEFINES)
-CPPSRCS		+= $(STATIC_CPPSRCS)
-EXTRA_DSO_LIBS	+= $(STATIC_EXTRA_DSO_LIBS)
-EXTRA_LIBS	+= $(STATIC_EXTRA_LIBS)
-endif
-
 ifeq ($(OS_ARCH),WINNT)
 OS_LIBS += $(call EXPAND_LIBNAME,comctl32 comdlg32 uuid shell32 ole32 oleaut32 version winspool)
 OS_LIBS += $(call EXPAND_LIBNAME,usp10 msimg32)
 endif
 
 ifeq ($(OS_ARCH),WINNT)
 RCINCLUDE = splash.rc
 ifndef GNU_CC
 RCFLAGS += -DMOZ_PHOENIX -I$(srcdir)
 else
 RCFLAGS += -DMOZ_PHOENIX --include-dir $(srcdir)
 endif
-ifdef BUILD_STATIC_LIBS
-RCFLAGS += -DMOZ_STATIC_BUILD
-endif
 ifdef DEBUG
 RCFLAGS += -DDEBUG
 endif
 endif
 
 ifeq ($(OS_ARCH),OS2)
 RESFILE=splashos2.res
 RCFLAGS += -DMOZ_PHOENIX
-ifdef BUILD_STATIC_LIBS
-RCFLAGS += -DMOZ_STATIC_BUILD -i $(DIST)/include
-endif
 ifdef DEBUG
 RCFLAGS += -DDEBUG
 endif
 RCFLAGS += -DFIREFOX_ICO=\"$(DIST)/branding/firefox-os2.ico\" -DDOCUMENT_ICO=\"$(DIST)/branding/document-os2.ico\"
 endif
 
 include $(topsrcdir)/config/rules.mk
 
-ifdef BUILD_STATIC_LIBS
-include $(topsrcdir)/config/static-rules.mk
-
-DEFINES += -DIMPL_XREAPI
-endif
-
 ifeq ($(MOZ_WIDGET_TOOLKIT),photon)
 LIBS += -lphexlib
 endif
 
 ifeq ($(OS_ARCH),WINNT)
 #
 # Control the default heap size.
 # This is the heap returned by GetProcessHeap().
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -92,16 +92,21 @@
       <versionRange severity="1"/>
     </emItem>
     <emItem id="{B7082FAA-CB62-4872-9106-E42DD88EDE45}">
       <versionRange minVersion="0.1" maxVersion="3.3.0.*">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
            <versionRange minVersion="3.7a1" maxVersion="*"/>
         </targetApplication>
       </versionRange>
+      <versionRange minVersion="3.3.1" maxVersion="*">
+        <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+           <versionRange minVersion="5.0a1" maxVersion="*"/>
+        </targetApplication>
+      </versionRange>
     </emItem>
     <emItem id="{E8E88AB0-7182-11DF-904E-6045E0D72085}"/>
   </emItems>
 <pluginItems>
   <pluginItem>
     <match name="name" exp="^Yahoo Application State Plugin$"/>
     <match name="description" exp="^Yahoo Application State Plugin$"/>
     <match name="filename" exp="npYState.dll"/>
--- a/browser/app/macbuild/Contents/Info.plist.in
+++ b/browser/app/macbuild/Contents/Info.plist.in
@@ -87,16 +87,65 @@
 			<array>
 				<string>GIFf</string>
 				<string>JPEG</string>
 				<string>PNGf</string>
 			</array>
 			<key>CFBundleTypeRole</key>
 			<string>Viewer</string>
 		</dict>
+		<dict>
+			<key>CFBundleTypeExtensions</key>
+			<array>
+				<string>oga</string>
+				<string>ogg</string>
+			</array>
+			<key>CFBundleTypeIconFile</key>
+			<string>document.icns</string>
+			<key>CFBundleTypeMIMETypes</key>
+			<array>
+				<string>audio/ogg</string>
+			</array>
+			<key>CFBundleTypeName</key>
+			<string>HTML5 Audio (Ogg)</string>
+			<key>CFBundleTypeRole</key>
+			<string>Viewer</string>
+		</dict>
+		<dict>
+			<key>CFBundleTypeExtensions</key>
+			<array>
+				<string>ogv</string>
+			</array>
+			<key>CFBundleTypeIconFile</key>
+			<string>document.icns</string>
+			<key>CFBundleTypeMIMETypes</key>
+			<array>
+				<string>video/ogg</string>
+			</array>
+			<key>CFBundleTypeName</key>
+			<string>HTML5 Video (Ogg)</string>
+			<key>CFBundleTypeRole</key>
+			<string>Viewer</string>
+		</dict>
+		<dict>
+			<key>CFBundleTypeExtensions</key>
+			<array>
+				<string>webm</string>
+			</array>
+			<key>CFBundleTypeIconFile</key>
+			<string>document.icns</string>
+			<key>CFBundleTypeMIMETypes</key>
+			<array>
+				<string>video/webm</string>
+			</array>
+			<key>CFBundleTypeName</key>
+			<string>HTML5 Video (WebM)</string>
+			<key>CFBundleTypeRole</key>
+			<string>Viewer</string>
+		</dict>
 	</array>
 	<key>CFBundleExecutable</key>
 	<string>firefox-bin</string>
 	<key>CFBundleGetInfoString</key>
 	<string>%APP_NAME% %APP_VERSION%</string>
 	<key>CFBundleIconFile</key>
 	<string>firefox</string>
 	<key>CFBundleIdentifier</key>
--- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/content/experiment-page.js
+++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/content/experiment-page.js
@@ -118,17 +118,17 @@ var stringBundle;
 	response == nsIFilePicker.returnReplace) {
       const nsIWebBrowserPersist = Components.interfaces.nsIWebBrowserPersist;
       let file = filePicker.file;
 
       // create a data url from the canvas and then create URIs of the source
       // and targets
       let io = Components.classes["@mozilla.org/network/io-service;1"].
 	getService(Components.interfaces.nsIIOService);
-      let source = io.newURI(canvas.toDataURL("image/png", ""), "UTF8", null);
+      let source = io.newURI(canvas.toDataURL("image/png"), "UTF8", null);
       let target = io.newFileURI(file);
 
       // prepare to save the canvas data
       let persist = Components.classes[
 	"@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].
 	  createInstance(nsIWebBrowserPersist);
       persist.persistFlags = nsIWebBrowserPersist.
 	PERSIST_FLAGS_REPLACE_EXISTING_FILES;
--- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/content/survey-generator.js
+++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/content/survey-generator.js
@@ -86,16 +86,19 @@ function onBuiltinSurveyLoad() {
   } else {
     contentDiv.innerHTML = "";
     if (task.surveyExplanation) {
       explanation.innerHTML = task.surveyExplanation;
     } else {
       explanation.innerHTML = "";
     }
     drawSurveyForm(task, contentDiv);
+    // Allow surveys to define arbitrary page load handlers - call them
+    // after creating the rest of the page:
+    task.onPageLoad(task, document);
   }
 }
 
 function drawSurveyForm(task, contentDiv) {
   let surveyQuestions = task.surveyQuestions;
 
   /* Fill form fields with old survey answers if available --
    * but not if the survey version has changed since you stored them!!
@@ -109,32 +112,32 @@ function drawSurveyForm(task, contentDiv
   submitButton.setAttribute("style", "");
   let changeButton = document.getElementById("change-answers");
   changeButton.setAttribute("style", "display:none");
   // Loop through questions and render html form input elements for each
   // one.
   for (let i = 0; i < surveyQuestions.length; i++) {
     let question = surveyQuestions[i].question;
     let explanation = surveyQuestions[i].explanation;
-    let elem;
+    let elem, j;
 
     elem = document.createElement("h3");
     elem.innerHTML = (i+1) + ". " + question;
     contentDiv.appendChild(elem);
     if (explanation) {
       elem = document.createElement("p");
       elem.setAttribute("class", "survey-question-explanation");
       elem.innerHTML = explanation;
       contentDiv.appendChild(elem);
     }
     // If you've done this survey before, preset all inputs using old answers
     let choices = surveyQuestions[i].choices;
     switch (surveyQuestions[i].type) {
     case MULTIPLE_CHOICE:
-      for (let j = 0; j < choices.length; j++) {
+      for (j = 0; j < choices.length; j++) {
         let newRadio = document.createElement("input");
         newRadio.setAttribute("type", "radio");
         newRadio.setAttribute("name", "answer_to_" + i);
         newRadio.setAttribute("value", j);
         if (oldAnswers && oldAnswers[i] == String(j)) {
           newRadio.setAttribute("checked", "true");
         }
         let label = document.createElement("span");
@@ -143,17 +146,17 @@ function drawSurveyForm(task, contentDiv
         contentDiv.appendChild(label);
         contentDiv.appendChild(document.createElement("br"));
       }
       break;
     case CHECK_BOXES:
     case CHECK_BOXES_WITH_FREE_ENTRY:
       let checkboxName = "answer_to_" + i;
       // Check boxes:
-      for (let j = 0; j < choices.length; j++) {
+      for (j = 0; j < choices.length; j++) {
         let newCheck = document.createElement("input");
         newCheck.setAttribute("type", "checkbox");
         newCheck.setAttribute("name", checkboxName);
         newCheck.setAttribute("value", j);
         if (oldAnswers && oldAnswers[i]) {
           for each (let an in oldAnswers[i]) {
             if (an == String(j)) {
               newCheck.setAttribute("checked", "true");
@@ -183,17 +186,17 @@ function drawSurveyForm(task, contentDiv
           }, false);
         let label = document.createElement("span");
         label.innerHTML = surveyQuestions[i].free_entry + "&nbsp:&nbsp";
         let inputBox = document.createElement("textarea");
         inputBox.setAttribute("id", freeformId);
         inputBox.addEventListener(
           "keypress", function() {
             let elements = document.getElementsByName(checkboxName);
-            for (let j = (elements.length - 1); j >= 0; j--) {
+            for (j = (elements.length - 1); j >= 0; j--) {
               if (elements[j].value == freeformId) {
                 elements[j].checked = true;
                 break;
               }
             }
           }, false);
         if (oldAnswers && oldAnswers[i]) {
           for each (let an in oldAnswers[i]) {
@@ -208,17 +211,17 @@ function drawSurveyForm(task, contentDiv
         contentDiv.appendChild(label);
         contentDiv.appendChild(inputBox);
       }
       break;
     case SCALE:
       let label = document.createElement("span");
       label.innerHTML = surveyQuestions[i].min_label;
       contentDiv.appendChild(label);
-      for (let j = surveyQuestions[i].scale_minimum;
+      for (j = surveyQuestions[i].scale_minimum;
            j <= surveyQuestions[i].scale_maximum;
            j++) {
         let newRadio = document.createElement("input");
         newRadio.setAttribute("type", "radio");
         newRadio.setAttribute("name", "answer_to_" + i);
         newRadio.setAttribute("value", j);
         if (oldAnswers && oldAnswers[i] == String(j)) {
           newRadio.setAttribute("checked", "true");
@@ -238,17 +241,17 @@ function drawSurveyForm(task, contentDiv
       }
       contentDiv.appendChild(inputBox);
       break;
     case MULTIPLE_CHOICE_WITH_FREE_ENTRY:
       let checked = false;
       let freeformId = "freeform_" + i;
       let radioName = "answer_to_" + i;
 
-      for (let j = 0; j < choices.length; j++) {
+      for (j = 0; j < choices.length; j++) {
         let newRadio = document.createElement("input");
         newRadio.setAttribute("type", "radio");
         newRadio.setAttribute("name", radioName);
         newRadio.setAttribute("value", j);
         newRadio.addEventListener(
           "click", function() {
             let inputBox = document.getElementById(freeformId);
             if (inputBox) {
--- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/install.rdf
+++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/install.rdf
@@ -1,24 +1,24 @@
 <?xml version="1.0"?>
 
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
   <Description about="urn:mozilla:install-manifest">
     <em:id>testpilot@labs.mozilla.com</em:id>
-    <em:version>1.1.1</em:version>
+    <em:version>1.1.2</em:version>
     <em:type>2</em:type>
 
     <!-- Target Application this extension can install into, 
          with minimum and maximum supported versions. --> 
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>3.5</em:minVersion>
-        <em:maxVersion>5.0</em:maxVersion>
+        <em:maxVersion>6.0</em:maxVersion>
       </Description>
     </em:targetApplication>
    
     <!-- Front End MetaData -->
     <em:name>Feedback</em:name>
     <em:description>Help make Firefox better by giving feedback.</em:description>
     <em:creator>Mozilla Corporation</em:creator>
     <em:homepageURL>http://testpilot.mozillalabs.com/</em:homepageURL>
--- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/remote-experiment-loader.js
+++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/remote-experiment-loader.js
@@ -507,25 +507,25 @@ exports.RemoteExperimentLoader.prototype
     let remoteExperiments = {};
     this._loadErrors = [];
     for each (filename in this._experimentFileNames) {
       this._logger.debug("GetExperiments is loading " + filename);
       try {
         remoteExperiments[filename] = this._loader.require(filename);
         this._logger.info("Loaded " + filename + " OK.");
       } catch(e) {
-      /* Turn the load-time errors into strings and store them, so we can display
-       * them on a debug page or include them with a data upload!  (Don't store
-       * exception objects directly as that causes garbage collector problems-
-       * aka bug 646122) */
-      let errStr = e.name + " on line " + e.lineNumber + " of file " +
-        e.fileName + ": " + e.message;
+        /* Turn the load-time errors into strings and store them, so we can display
+         * them on a debug page or include them with a data upload!  (Don't store
+         * exception objects directly as that causes garbage collector problems-
+         * aka bug 646122) */
+        let errStr = e.name + " on line " + e.lineNumber + " of file " +
+          e.fileName + ": " + e.message;
         this._loadErrors.push(errStr);
         this._logger.warn("Error loading " + filename);
-        this._logger.warn(e);
+        this._logger.warn(errStr);
       }
     }
     return remoteExperiments;
   },
 
   getStudyResults: function() {
     return this._studyResults;
   },
--- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/tasks.js
+++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/tasks.js
@@ -592,17 +592,17 @@ TestPilotExperiment.prototype = {
       if (this._handlers.getStudyMetadata) {
         let metadata = this._handlers.getStudyMetadata();
         if (metadata.length) {
           // getStudyMetadata must return an array, otherwise it is invalid.
           return metadata;
         }
       }
     } catch(e) {
-      this._logger.warn("Error in getStudyMetadata: " + e);
+      this._dataStore.logException("getStudyMetadata: " + e);
     }
     return null;
   },
 
   _reschedule: function TestPilotExperiment_reschedule() {
     // Schedule next run of test:
     // add recurrence interval to start date and store!
     let ms = this._recurrenceInterval * (24 * 60 * 60 * 1000);
@@ -655,16 +655,17 @@ TestPilotExperiment.prototype = {
     return Application.prefs.getValue(
       DATE_FOR_DATA_DELETION_PREFIX + this._id, "");
   },
 
   checkDate: function TestPilotExperiment_checkDate() {
     // This method handles all date-related status changes and should be
     // called periodically.
     let currentDate = this._now();
+    let self = this;
 
     // Reset automatically recurring tests:
     if (this._recursAutomatically &&
         this._status >= TaskConstants.STATUS_FINISHED &&
         currentDate >= this._startDate &&
 	currentDate <= this._endDate) {
       // if we've done a permanent opt-out, then don't start over-
       // just keep rescheduling.
@@ -698,28 +699,26 @@ TestPilotExperiment.prototype = {
 
     // If a study is STARTING, and we're in the right date range,
     // then start it, and move it to IN_PROGRESS.
     if ( this._status == TaskConstants.STATUS_STARTING &&
         currentDate >= this._startDate &&
         currentDate <= this._endDate) {
       this._logger.info("Study now starting.");
       // clear the data before starting.
-      let self = this;
       this._dataStore.wipeAllData(function() {
         // Experiment is now in progress.
         self.changeStatus(TaskConstants.STATUS_IN_PROGRESS, true);
         self.onExperimentStartup();
       });
     }
 
     // What happens when a test finishes:
     if (this._status < TaskConstants.STATUS_FINISHED &&
 	currentDate > this._endDate) {
-      let self = this;
       let setDataDeletionDate = true;
       this._logger.info("Passed End Date - Switched Task Status to Finished");
       this.changeStatus(TaskConstants.STATUS_FINISHED);
       this.onExperimentShutdown();
       this.doExperimentCleanup();
 
       if (this._recursAutomatically) {
         this._reschedule();
@@ -891,55 +890,61 @@ TestPilotExperiment.prototype = {
       };
       req.send(dataString);
     });
   },
 
   optOut: function TestPilotExperiment_optOut(reason, callback) {
     // Regardless of study ID, post the opt-out message to a special
     // database table of just opt-out messages; include study ID in metadata.
-    let url = Application.prefs.getValue(DATA_UPLOAD_PREF, "") + "opt-out";
     let logger = this._logger;
 
     this.onExperimentShutdown();
     this.changeStatus(TaskConstants.STATUS_CANCELLED);
     this._dataStore.wipeAllData();
     this.doExperimentCleanup();
     this._dateForDataDeletion = null;
     this._expirationDateForDataSubmission = null;
     logger.info("Opting out of test with reason " + reason);
     if (reason) {
       // Send us the reason...
       // (TODO: include metadata?)
+      let url = Application.prefs.getValue(DATA_UPLOAD_PREF, "") + "opt-out";
       let answer = {id: this._id,
                     reason: reason};
       let dataString = JSON.stringify(answer);
       var req =
         Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
 	  createInstance(Ci.nsIXMLHttpRequest);
       logger.trace("Posting " + dataString + " to " + url);
       req.open('POST', url, true);
       req.setRequestHeader("Content-type", "application/json");
       req.setRequestHeader("Content-length", dataString.length);
       req.setRequestHeader("Connection", "close");
       req.onreadystatechange = function(aEvt) {
         if (req.readyState == 4) {
           if (req.status == 200 || req.status == 201 || req.status == 202) {
 	    logger.info("Quit reason posted successfully " + req.responseText);
-    	    callback(true);
+            if (callback) {
+              callback(true);
+            }
 	  } else {
 	    logger.warn(req.status + " posting error " + req.responseText);
-	    callback(false);
+            if (callback) {
+              callback(false);
+            }
 	  }
 	}
       };
       logger.trace("Sending quit reason.");
       req.send(dataString);
     } else {
-      callback(false);
+      if (callback) {
+        callback(false);
+      }
     }
   },
 
   setRecurPref: function TPE_setRecurPrefs(value) {
     // value is NEVER_SUBMIT, ALWAYS_SUBMIT, or ASK_EACH_TIME
     let prefName = RECUR_PREF_PREFIX + this._id;
     this._logger.info("Setting recur pref to " + value);
     Application.prefs.setValue(prefName, value);
@@ -956,16 +961,17 @@ TestPilotBuiltinSurvey.prototype = {
                    surveyInfo.surveyName,
                    surveyInfo.surveyUrl,
                    surveyInfo.summary,
                    surveyInfo.thumbnail);
     this._studyId = surveyInfo.uploadWithExperiment; // what study do we belong to
     this._versionNumber = surveyInfo.versionNumber;
     this._questions = surveyInfo.surveyQuestions;
     this._explanation = surveyInfo.surveyExplanation;
+    this._onPageLoad = surveyInfo.onPageLoad;
   },
 
   get taskType() {
     return TaskConstants.TYPE_SURVEY;
   },
 
   get surveyExplanation() {
     return this._explanation;
@@ -983,16 +989,22 @@ TestPilotBuiltinSurvey.prototype = {
   get defaultUrl() {
     return this.currentStatusUrl;
   },
 
   get relatedStudyId() {
     return this._studyId;
   },
 
+  onPageLoad: function(task, document) {
+    if (this._onPageLoad) {
+      this._onPageLoad(task, document);
+    }
+  },
+
   onDetailPageOpened: function TPS_onDetailPageOpened() {
     if (this._status < TaskConstants.STATUS_IN_PROGRESS) {
       this.changeStatus( TaskConstants.STATUS_IN_PROGRESS, true );
     }
   },
 
   get oldAnswers() {
     let surveyResults =
@@ -1199,9 +1211,9 @@ TestPilotLegacyStudy.prototype = {
   },
 
   get taskType() {
     return TaskConstants.TYPE_LEGACY;
   }
   // TODO test that they don't say "thanks for contributing" if the
   // user didn't actually complete them...
 };
-TestPilotLegacyStudy.prototype.__proto__ = TestPilotTask;
\ No newline at end of file
+TestPilotLegacyStudy.prototype.__proto__ = TestPilotTask;
--- a/browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/Makefile.in
+++ b/browser/app/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/Makefile.in
@@ -38,18 +38,16 @@
 DEPTH		= ../../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
-DEFINES += -DFIREFOX_VERSION=$(FIREFOX_VERSION)
-
 FILES := \
 	install.rdf \
 	$(NULL)
 
 libs::
 	$(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(srcdir)/install.rdf.in > install.rdf
 	$(INSTALL) $(FILES) $(DIST)/bin/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
  
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -65,16 +65,17 @@ pref("extensions.webservice.discoverURL"
 // Blocklist preferences
 pref("extensions.blocklist.enabled", true);
 pref("extensions.blocklist.interval", 86400);
 // Controls what level the blocklist switches from warning about items to forcibly
 // blocking them.
 pref("extensions.blocklist.level", 2);
 pref("extensions.blocklist.url", "https://addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
 pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
+pref("extensions.blocklist.itemURL", "https://addons.mozilla.org/%LOCALE%/%APP%/blocked/%blockID%");
 
 pref("extensions.update.autoUpdateDefault", true);
 
 // Dictionary download preference
 pref("browser.dictionaries.download.url", "https://addons.mozilla.org/%LOCALE%/firefox/dictionaries/");
 
 // The minimum delay in seconds for the timer to fire.
 // default=2 minutes
@@ -896,16 +897,27 @@ pref("dom.ipc.plugins.enabled.i386.flash
 pref("dom.ipc.plugins.enabled.i386.javaplugin2_npapi.plugin", true);
 pref("dom.ipc.plugins.enabled.i386.javaappletplugin.plugin", true);
 // x86_64 ipc preferences
 pref("dom.ipc.plugins.enabled.x86_64", true);
 #else
 pref("dom.ipc.plugins.enabled", true);
 #endif
 
+// This pref governs whether we attempt to work around problems caused by
+// plugins using OS calls to manipulate the cursor while running out-of-
+// process.  These workarounds all involve intercepting (hooking) certain
+// OS calls in the plugin process, then arranging to make certain OS calls
+// in the browser process.  Eventually plugins will be required to use the
+// NPAPI to manipulate the cursor, and these workarounds will be removed.
+// See bug 621117.
+#ifdef XP_MACOSX
+pref("dom.ipc.plugins.nativeCursorSupport", true);
+#endif
+
 #ifdef XP_WIN
 pref("browser.taskbar.previews.enable", false);
 pref("browser.taskbar.previews.max", 20);
 pref("browser.taskbar.previews.cachetime", 5);
 pref("browser.taskbar.lists.enabled", true);
 pref("browser.taskbar.lists.frequent.enabled", true);
 pref("browser.taskbar.lists.recent.enabled", false);
 pref("browser.taskbar.lists.maxListItemCount", 7);
--- a/browser/base/content/aboutDialog.css
+++ b/browser/base/content/aboutDialog.css
@@ -67,38 +67,8 @@
   margin: 0 40px;
 }
 
 #currentChannel {
   margin: 0;
   padding: 0;
   font-weight: bold;
 }
-
-#channelSelector {
-  margin-top: 10px;
-}
-
-#channelSelectorStart {
-  -moz-margin-start: 0;
-}
-
-#channelMenulist {
-  margin: 0;
-}
-
-.channel-description {
-  margin: 10px 0;
-}
-
-#detailsBox,
-#channelSelector,
-.channel-description {
-  -moz-transition: opacity 250ms;
-}
-
-#contentDeck:not([selectedIndex="0"]) > #detailsBox,
-#contentDeck:not([selectedIndex="1"]) > #channelSelector,
-#channelDescriptionDeck:not([selectedIndex="0"]) > #releaseDescription,
-#channelDescriptionDeck:not([selectedIndex="1"]) > #betaDescription,
-#channelDescriptionDeck:not([selectedIndex="2"]) > #auroraDescription {
-  opacity: 0;
-}
--- a/browser/base/content/aboutDialog.js
+++ b/browser/base/content/aboutDialog.js
@@ -83,17 +83,19 @@ function init(aEvent)
     document.getElementById("extra-trademark").hidden = true;
   }
 #endif
 
 #ifdef MOZ_UPDATER
   gAppUpdater = new appUpdater();
 #endif
 
-  gChannelSelector.init();
+  let defaults = Services.prefs.getDefaultBranch("");
+  let channelLabel = document.getElementById("currentChannel");
+  channelLabel.value = defaults.getCharPref("app.update.channel");
 
 #ifdef XP_MACOSX
   // it may not be sized at this point, and we need its width to calculate its position
   window.sizeToContent();
   window.moveTo((screen.availWidth / 2) - (window.outerWidth / 2), screen.availHeight / 5);
 #endif
 }
 
@@ -568,77 +570,8 @@ appUpdater.prototype =
     if (!aIID.equals(Components.interfaces.nsIProgressEventSink) &&
         !aIID.equals(Components.interfaces.nsIRequestObserver) &&
         !aIID.equals(Components.interfaces.nsISupports))
       throw Components.results.NS_ERROR_NO_INTERFACE;
     return this;
   }
 };
 #endif
-
-var gChannelSelector = {
-  validChannels: { release: 1, beta: 1, aurora: 1 },
-  
-  init: function() {
-    try {
-      this.channelValue = Services.prefs.getCharPref("app.update.desiredChannel");
-    } catch (e) {
-      let defaults = Services.prefs.getDefaultBranch("");
-      this.channelValue = defaults.getCharPref("app.update.channel");
-    }
-
-    // Only show channel selector UI on valid update channels.
-    if (this.channelValue in this.validChannels) {
-      document.getElementById("currentChannelText").hidden = false;
-      this.setChannelLabel(this.channelValue);
-      this.setChannelMenuitem(this.channelValue);
-    }
-  },
-
-  selectChannel: function(aSelectedItem) {
-    document.getElementById("channelDescriptionDeck").selectedPanel =
-      document.getElementById(aSelectedItem.value + "Description");
-    document.getElementById("channelMenulist").setAttribute("aria-describedby",
-      aSelectedItem.value + "Description");
-  },
-
-  cancel: function() {
-    this.setChannelMenuitem(this.channelValue);
-    this.hide();
-  },
-
-  apply: function() {
-    this.channelValue = document.getElementById("channelMenulist").selectedItem.value;
-    this.setChannelLabel(this.channelValue);
-
-    // Change app update channel.
-    Services.prefs.setCharPref("app.update.desiredChannel", this.channelValue);
-
-    // Stop any downloads in progress
-    gAppUpdater.aus.pauseDownload();
-    // App updater will look at app.update.desiredChannel for new channel value
-    // and will clear it when the update is complete.
-    gAppUpdater.isChecking = true;
-    gAppUpdater.checker.checkForUpdates(gAppUpdater.updateCheckListener, true);
-
-    this.hide();
-  },
-
-  show: function() {
-    document.getElementById("contentDeck").selectedPanel =
-      document.getElementById("channelSelector");
-  },
-
-  hide: function() {
-    document.getElementById("contentDeck").selectedPanel =
-      document.getElementById("detailsBox");  
-  },
-
-  setChannelLabel: function(aValue) {
-    let channelLabel = document.getElementById("currentChannel");
-    channelLabel.value = document.getElementById(aValue + "Menuitem").label;
-  },
-
-  setChannelMenuitem: function(aValue) {
-    document.getElementById("channelMenulist").selectedItem =
-      document.getElementById(aValue + "Menuitem");
-  }
-}
--- a/browser/base/content/aboutDialog.xul
+++ b/browser/base/content/aboutDialog.xul
@@ -75,95 +75,60 @@
   <vbox id="aboutDialogContainer">
     <hbox id="clientBox">
       <vbox id="leftBox" flex="1"/>
       <vbox id="rightBox" flex="1">
 #expand <label id="version" value="__MOZ_APP_VERSION__"/>
         <label id="distribution" class="text-blurb"/>
         <label id="distributionId" class="text-blurb"/>
 
-        <!-- Make sure the selectedIndex attribute is always set so that the CSS
-             selectors for transitions work -->        
-        <deck id="contentDeck" selectedIndex="0">
-          <vbox id="detailsBox" aria-describedby="communityDesc contributeDesc">
-            <vbox id="updateBox">
+        <vbox id="detailsBox" aria-describedby="communityDesc contributeDesc">
+          <vbox id="updateBox">
 #ifdef MOZ_UPDATER
-              <deck id="updateDeck" orient="vertical">
-                <hbox id="updateButtonBox" align="center">
-                  <button id="updateButton" align="start"
-                          oncommand="gAppUpdater.buttonOnCommand();"/>
-                  <spacer flex="1"/>
-                </hbox>
-                <hbox id="checkingForUpdates" align="center">
-                  <image class="update-throbber"/><label>&update.checkingForUpdates;</label>
-                </hbox>
-                <hbox id="checkingAddonCompat" align="center">
-                  <image class="update-throbber"/><label>&update.checkingAddonCompat;</label>
-                </hbox>
-                <hbox id="downloading" align="center">
-                  <image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
-                </hbox>
-                <hbox id="downloadFailed" align="center">
-                  <label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
-                </hbox>
-                <hbox id="adminDisabled" align="center">
-                  <label>&update.adminDisabled;</label>
-                </hbox>
-                <hbox id="noUpdatesFound" align="center">
-                  <label>&update.noUpdatesFound;</label>
-                </hbox>
-                <hbox id="manualUpdate" align="center">
-                  <label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
-                </hbox>
-              </deck>
+            <deck id="updateDeck" orient="vertical">
+              <hbox id="updateButtonBox" align="center">
+                <button id="updateButton" align="start"
+                        oncommand="gAppUpdater.buttonOnCommand();"/>
+                <spacer flex="1"/>
+              </hbox>
+              <hbox id="checkingForUpdates" align="center">
+                <image class="update-throbber"/><label>&update.checkingForUpdates;</label>
+              </hbox>
+              <hbox id="checkingAddonCompat" align="center">
+                <image class="update-throbber"/><label>&update.checkingAddonCompat;</label>
+              </hbox>
+              <hbox id="downloading" align="center">
+                <image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
+              </hbox>
+              <hbox id="downloadFailed" align="center">
+                <label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
+              </hbox>
+              <hbox id="adminDisabled" align="center">
+                <label>&update.adminDisabled;</label>
+              </hbox>
+              <hbox id="noUpdatesFound" align="center">
+                <label>&update.noUpdatesFound;</label>
+              </hbox>
+              <hbox id="manualUpdate" align="center">
+                <label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
+              </hbox>
+            </deck>
 #endif
-            </vbox>
-
-            <description class="text-blurb" id="currentChannelText" hidden="true">
-              &channel.description.start;<label id="currentChannel"/>&channel.description.end;<label id="channelChangeLink" class="text-link" onclick="gChannelSelector.show();">&channel.change;</label>
-            </description>
-            <description class="text-blurb" id="communityDesc">
-              &community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end2;
-            </description>
-            <description class="text-blurb" id="contributeDesc">
-              &contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end;
-            </description>
           </vbox>
 
-          <vbox id="channelSelector">
-            <hbox pack="start" align="center">
-              <label id="channelSelectorStart">&channel.selector.start;</label>
-              <menulist id="channelMenulist" onselect="gChannelSelector.selectChannel(this.selectedItem);" aria-labelledby="channelSelectorStart channelMenulist channelSelectorEnd">
-                <menupopup>
-                  <menuitem id="releaseMenuitem" label="Release" value="release"/>
-                  <menuitem id="betaMenuitem" label="Beta" value="beta"/>
-                  <menuseparator/>
-                  <menuitem id="auroraMenuitem" label="Aurora" value="aurora"/>
-                </menupopup>
-              </menulist>
-              <label id="channelSelectorEnd">&channel.selector.end;</label>
-            </hbox>
-
-            <deck id="channelDescriptionDeck" selectedIndex="0">
-              <description id="releaseDescription" class="channel-description">&channel.release.description;</description>
-              <description id="betaDescription" class="channel-description">&channel.beta.description;</description>
-              <description id="auroraDescription" class="channel-description">&channel.aurora.description;</description>
-            </deck>
-
-            <hbox id="channelSelectorButtons" pack="end">
-#ifdef XP_UNIX
-              <button oncommand="gChannelSelector.cancel();" label="&channel.selector.cancelButton;"/>
-              <button oncommand="gChannelSelector.apply();" label="&channel.selector.applyButton;"/>
-#else
-              <button oncommand="gChannelSelector.apply();" label="&channel.selector.applyButton;"/>
-              <button oncommand="gChannelSelector.cancel();" label="&channel.selector.cancelButton;"/>
-#endif
-            </hbox>
-          </vbox>
-        </deck>
+          <description class="text-blurb" id="currentChannelText">
+            &channel.description.start;<label id="currentChannel"/>&channel.description.end;
+          </description>
+          <description class="text-blurb" id="communityDesc">
+            &community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end2;
+          </description>
+          <description class="text-blurb" id="contributeDesc">
+            &contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end;
+          </description>
+        </vbox>
       </vbox>
     </hbox>
     <vbox id="bottomBox">
       <hbox pack="center">
         <label class="text-link bottom-link" href="about:license">&bottomLinks.license;</label>
         <label class="text-link bottom-link" href="about:rights">&bottomLinks.rights;</label>
         <label class="text-link bottom-link" href="http://www.mozilla.com/legal/privacy/">&bottomLinks.privacy;</label>
       </hbox>
--- a/browser/base/content/browser-appmenu.inc
+++ b/browser/base/content/browser-appmenu.inc
@@ -196,16 +196,20 @@
                     label="&viewPageSourceCmd.label;"
                     command="View:PageSource"
                     key="key_viewSource"/>
           <menuitem id="appmenu_errorConsole"
                     hidden="true"
                     label="&errorConsoleCmd.label;"
                     key="key_errorConsole"
                     oncommand="toJavaScriptConsole();"/>
+          <menuseparator id="appmenu_devToolsEndSeparator"/>
+          <menuitem id="appmenu_getMoreDevtools"
+                    label="&getMoreDevtoolsCmd.label;"
+                    oncommand="openUILinkIn('https://addons.mozilla.org/firefox/collections/mozilla/webdeveloper/', 'tab');"/>
           <menuseparator/>
 #define ID_PREFIX appmenu_developer_
 #define OMIT_ACCESSKEYS
 #include browser-charsetmenu.inc
 #undef ID_PREFIX
 #undef OMIT_ACCESSKEYS
           <menuitem label="&goOfflineCmd.label;"
                     type="checkbox"
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -562,16 +562,21 @@
                             key="key_viewSource"
                             command="View:PageSource"/>
                   <menuitem id="javascriptConsole"
                             hidden="true"
                             label="&errorConsoleCmd.label;"
                             accesskey="&errorConsoleCmd.accesskey;"
                             key="key_errorConsole"
                             oncommand="toJavaScriptConsole();"/>
+                  <menuseparator id="devToolsEndSeparator"/>
+                  <menuitem id="getMoreDevtools"
+                            label="&getMoreDevtoolsCmd.label;"
+                            accesskey="&getMoreDevtoolsCmd.accesskey;"
+                            oncommand="openUILinkIn('https://addons.mozilla.org/firefox/collections/mozilla/webdeveloper/', 'tab');"/>
                 </menupopup>
               </menu>
               <menuitem id="menu_pageInfo"
                         accesskey="&pageInfoCmd.accesskey;"
                         label="&pageInfoCmd.label;"
 #ifndef XP_WIN
                         key="key_viewInfo"
 #endif
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -323,17 +323,17 @@ let gSyncUI = {
     if (!lastSync || this._needsSetup()) {
       syncButton.removeAttribute("tooltiptext");
       return;
     }
 
     // Show the day-of-week and time (HH:MM) of last sync
     let lastSyncDate = new Date(lastSync).toLocaleFormat("%a %H:%M");
     let lastSyncLabel =
-      this._stringBundle.formatStringFromName("lastSync.label", [lastSyncDate], 1);
+      this._stringBundle.formatStringFromName("lastSync2.label", [lastSyncDate], 1);
 
     syncButton.setAttribute("tooltiptext", lastSyncLabel);
   },
 
   _onSyncEnd: function SUI__onSyncEnd(success) {
     let title = this._stringBundle.GetStringFromName("error.sync.title");
     if (!success) {
       if (Weave.Status.login != Weave.LOGIN_SUCCEEDED) {
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -43,16 +43,17 @@ let TabView = {
   _browserKeyHandlerInitialized: false,
   _isFrameLoading: false,
   _initFrameCallbacks: [],
   PREF_BRANCH: "browser.panorama.",
   PREF_FIRST_RUN: "browser.panorama.experienced_first_run",
   PREF_STARTUP_PAGE: "browser.startup.page",
   PREF_RESTORE_ENABLED_ONCE: "browser.panorama.session_restore_enabled_once",
   VISIBILITY_IDENTIFIER: "tabview-visibility",
+  GROUPS_IDENTIFIER: "tabview-groups",
 
   // ----------
   get windowTitle() {
     delete this.windowTitle;
     let brandBundle = document.getElementById("bundle_brand");
     let brandShortName = brandBundle.getString("brandShortName");
     let title = gNavigatorBundle.getFormattedString("tabView2.title", [brandShortName]);
     return this.windowTitle = title;
@@ -90,24 +91,31 @@ let TabView = {
   init: function TabView_init() {
     if (this.firstUseExperienced) {
       if ((gBrowser.tabs.length - gBrowser.visibleTabs.length) > 0)
         this._setBrowserKeyHandlers();
 
       // ___ visibility
       let sessionstore =
         Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+
       let data = sessionstore.getWindowValue(window, this.VISIBILITY_IDENTIFIER);
-
       if (data && data == "true") {
         this.show();
       } else {
-        let self = this;
+        try {
+          data = sessionstore.getWindowValue(window, this.GROUPS_IDENTIFIER);
+          if (data) {
+            let parsedData = JSON.parse(data);
+            this.updateGroupNumberBroadcaster(parsedData.totalNumber || 0);
+          }
+        } catch (e) { }
 
-        // if a tab is changed from hidden to unhidden and the iframe is not 
+        let self = this;
+        // if a tab is changed from hidden to unhidden and the iframe is not
         // initialized, load the iframe and setup the tab.
         this._tabShowEventListener = function (event) {
           if (!self._window)
             self._initFrame(function() {
               self._window.UI.onTabSelect(gBrowser.selectedTab);
             });
         };
         gBrowser.tabContainer.addEventListener(
@@ -376,16 +384,24 @@ let TabView = {
     currentSet[alltabsPos] += "," + buttonId;
     currentSet = currentSet.join(",");
     toolbar.currentSet = currentSet;
     toolbar.setAttribute("currentset", currentSet);
     document.persist(toolbar.id, "currentset");
   },
 
   // ----------
+  // Function: updateGroupNumberBroadcaster
+  // Updates the group number broadcaster.
+  updateGroupNumberBroadcaster: function TabView_updateGroupNumberBroadcaster(number) {
+    let groupsNumber = document.getElementById("tabviewGroupsNumber");
+    groupsNumber.setAttribute("groups", number);
+  },
+
+  // ----------
   // Function: enableSessionRestore
   // Enables automatic session restore when the browser is started. Does
   // nothing if we already did that once in the past.
   enableSessionRestore: function UI_enableSessionRestore() {
     if (!this._window || !this.firstUseExperienced)
       return;
 
     // do nothing if we already enabled session restore once
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -491,8 +491,12 @@ statuspanel[label=""] {
   pointer-events: none;
 }
 
 .statuspanel-inner {
   height: 3em;
   width: 100%;
   -moz-box-align: end;
 }
+
+.panel-inner-arrowcontentfooter[footertype="promobox"] {
+  -moz-binding: url("chrome://browser/content/urlbarBindings.xml#promobox");
+}
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -256,58 +256,71 @@ function UpdateBackForwardCommands(aWebN
 
 /**
  * Click-and-Hold implementation for the Back and Forward buttons
  * XXXmano: should this live in toolbarbutton.xml?
  */
 function SetClickAndHoldHandlers() {
   var timer;
 
-  function timerCallback(aButton) {
+  function openMenu(aButton) {
+    cancelHold(aButton);
     aButton.firstChild.hidden = false;
     aButton.open = true;
-    timer = null;
   }
 
   function mousedownHandler(aEvent) {
     if (aEvent.button != 0 ||
         aEvent.currentTarget.open ||
         aEvent.currentTarget.disabled)
       return;
 
     // Prevent the menupopup from opening immediately
     aEvent.currentTarget.firstChild.hidden = true;
 
-    timer = setTimeout(timerCallback, 500, aEvent.currentTarget);
+    aEvent.currentTarget.addEventListener("mouseout", mouseoutHandler, false);
+    aEvent.currentTarget.addEventListener("mouseup", mouseupHandler, false);
+    timer = setTimeout(openMenu, 500, aEvent.currentTarget);
+  }
+
+  function mouseoutHandler(aEvent) {
+    let buttonRect = aEvent.currentTarget.getBoundingClientRect();
+    if (aEvent.clientX >= buttonRect.left &&
+        aEvent.clientX <= buttonRect.right &&
+        aEvent.clientY >= buttonRect.bottom)
+      openMenu(aEvent.currentTarget);
+    else
+      cancelHold(aEvent.currentTarget);
+  }
+
+  function mouseupHandler(aEvent) {
+    cancelHold(aEvent.currentTarget);
+  }
+
+  function cancelHold(aButton) {
+    clearTimeout(timer);
+    aButton.removeEventListener("mouseout", mouseoutHandler, false);
+    aButton.removeEventListener("mouseup", mouseupHandler, false);
   }
 
   function clickHandler(aEvent) {
     if (aEvent.button == 0 &&
         aEvent.target == aEvent.currentTarget &&
         !aEvent.currentTarget.open &&
         !aEvent.currentTarget.disabled) {
       let cmdEvent = document.createEvent("xulcommandevent");
       cmdEvent.initCommandEvent("command", true, true, window, 0,
                                 aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
                                 aEvent.metaKey, null);
       aEvent.currentTarget.dispatchEvent(cmdEvent);
     }
   }
 
-  function stopTimer(aEvent) {
-    if (timer) {
-      clearTimeout(timer);
-      timer = null;
-    }
-  }
-
   function _addClickAndHoldListenersOnElement(aElm) {
     aElm.addEventListener("mousedown", mousedownHandler, true);
-    aElm.addEventListener("mouseup", stopTimer, false);
-    aElm.addEventListener("mouseout", stopTimer, false);
     aElm.addEventListener("click", clickHandler, true);
   }
 
   // Bug 414797: Clone unified-back-forward-button's context menu into both the
   // back and the forward buttons.
   var unifiedButton = document.getElementById("unified-back-forward-button");
   if (unifiedButton && !unifiedButton._clickHandlersAttached) {
     unifiedButton._clickHandlersAttached = true;
@@ -2239,17 +2252,21 @@ function loadURI(uri, referrer, postData
     if (allowThirdPartyFixup) {
       flags = nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
     }
     gBrowser.loadURIWithFlags(uri, flags, referrer, null, postData);
   } catch (e) {
   }
 }
 
-function getShortcutOrURI(aURL, aPostDataRef) {
+function getShortcutOrURI(aURL, aPostDataRef, aMayInheritPrincipal) {
+  // Initialize outparam to false
+  if (aMayInheritPrincipal)
+    aMayInheritPrincipal.value = false;
+
   var shortcutURL = null;
   var keyword = aURL;
   var param = "";
 
   var offset = aURL.indexOf(" ");
   if (offset > 0) {
     keyword = aURL.substr(0, offset);
     param = aURL.substr(offset + 1);
@@ -2311,16 +2328,21 @@ function getShortcutOrURI(aURL, aPostDat
   else if (param) {
     // This keyword doesn't take a parameter, but one was provided. Just return
     // the original URL.
     aPostDataRef.value = null;
 
     return aURL;
   }
 
+  // This URL came from a bookmark, so it's safe to let it inherit the current
+  // document's principal.
+  if (aMayInheritPrincipal)
+    aMayInheritPrincipal.value = true;
+
   return shortcutURL;
 }
 
 function getPostDataStream(aStringData, aKeyword, aEncKeyword, aType) {
   var dataStream = Cc["@mozilla.org/io/string-input-stream;1"].
                    createInstance(Ci.nsIStringInputStream);
   aStringData = aStringData.replace(/%s/g, aEncKeyword).replace(/%S/g, aKeyword);
   dataStream.data = aStringData;
@@ -2855,17 +2877,17 @@ var PrintPreviewListener = {
     gBrowser.selectedTab = this._tabBeforePrintPreview;
     this._tabBeforePrintPreview = null;
     gInPrintPreviewMode = false;
     this._toggleAffectedChrome();
     gBrowser.removeTab(this._printPreviewTab);
     this._printPreviewTab = null;
   },
   _toggleAffectedChrome: function () {
-    gNavToolbox.hidden = gInPrintPreviewMode;
+    gNavToolbox.collapsed = gInPrintPreviewMode;
 
     if (gInPrintPreviewMode)
       this._hideChrome();
     else
       this._showChrome();
 
     if (this._chromeState.sidebarOpen)
       toggleSidebar(this._sidebarCommand);
@@ -2946,21 +2968,17 @@ function FillInHTMLTooltip(tipElement)
     return retVal;
 
   const XLinkNS = "http://www.w3.org/1999/xlink";
 
 
   var titleText = null;
   var XLinkTitleText = null;
   var SVGTitleText = null;
-#ifdef MOZ_SVG
   var lookingForSVGTitle = true;
-#else
-  var lookingForSVGTitle = false;
-#endif // MOZ_SVG
   var direction = tipElement.ownerDocument.dir;
 
   // If the element is invalid per HTML5 Forms specifications and has no title,
   // show the constraint validation error message.
   if ((tipElement instanceof HTMLInputElement ||
        tipElement instanceof HTMLTextAreaElement ||
        tipElement instanceof HTMLSelectElement ||
        tipElement instanceof HTMLButtonElement) &&
@@ -2971,21 +2989,18 @@ function FillInHTMLTooltip(tipElement)
     titleText = tipElement.validationMessage;
   }
 
   while (!titleText && !XLinkTitleText && !SVGTitleText && tipElement) {
     if (tipElement.nodeType == Node.ELEMENT_NODE) {
       titleText = tipElement.getAttribute("title");
       if ((tipElement instanceof HTMLAnchorElement && tipElement.href) ||
           (tipElement instanceof HTMLAreaElement && tipElement.href) ||
-          (tipElement instanceof HTMLLinkElement && tipElement.href)
-#ifdef MOZ_SVG
-          || (tipElement instanceof SVGAElement && tipElement.hasAttributeNS(XLinkNS, "href"))
-#endif // MOZ_SVG
-          ) {
+          (tipElement instanceof HTMLLinkElement && tipElement.href) ||
+          (tipElement instanceof SVGAElement && tipElement.hasAttributeNS(XLinkNS, "href"))) {
         XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title");
       }
       if (lookingForSVGTitle &&
           !(tipElement instanceof SVGElement &&
             tipElement.parentNode instanceof SVGElement &&
             !(tipElement.parentNode instanceof SVGForeignObjectElement))) {
         lookingForSVGTitle = false;
       }
@@ -3328,27 +3343,27 @@ const BrowserSearch = {
    * or focuses an existing window, if necessary.
    */
   webSearch: function BrowserSearch_webSearch() {
 #ifdef XP_MACOSX
     if (window.location.href != getBrowserURL()) {
       var win = getTopWin();
       if (win) {
         // If there's an open browser window, it should handle this command
-        win.focus()
+        win.focus();
         win.BrowserSearch.webSearch();
       } else {
         // If there are no open browser windows, open a new one
         function observer(subject, topic, data) {
           if (subject == win) {
             BrowserSearch.webSearch();
             Services.obs.removeObserver(observer, "browser-delayed-startup-finished");
           }
         }
-        win = window.openDialog("chrome://browser/content/", "_blank",
+        win = window.openDialog(getBrowserURL(), "_blank",
                                 "chrome,all,dialog=no", "about:blank");
         Services.obs.addObserver(observer, "browser-delayed-startup-finished", false); 
       }
       return;
     }
 #endif
     var searchBar = this.searchBar;
     if (searchBar && window.fullScreen)
@@ -7669,32 +7684,31 @@ var gIdentityHandler = {
       switch (gPrefService.getIntPref("browser.identity.ssl_domain_display")) {
         case 2 : // Show full domain
           icon_label = this._lastLocation.hostname;
           break;
         case 1 : // Show eTLD.
           icon_label = this.getEffectiveHost();
       }
 
-      // We need a port number for all lookups.  If one hasn't been specified, use
-      // the https default
-      var lookupHost = this._lastLocation.host;
-      if (lookupHost.indexOf(':') < 0)
-        lookupHost += ":443";
-
       // Verifier is either the CA Org, for a normal cert, or a special string
       // for certs that are trusted because of a security exception.
       var tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier",
                                                         [iData.caOrg]);
 
       // Check whether this site is a security exception. XPConnect does the right
       // thing here in terms of converting _lastLocation.port from string to int, but
       // the overrideService doesn't like undefined ports, so make sure we have
       // something in the default case (bug 432241).
-      if (this._overrideService.hasMatchingOverride(this._lastLocation.hostname,
+      // .hostname can return an empty string in some exceptional cases -
+      // hasMatchingOverride does not handle that, so avoid calling it.
+      // Updating the tooltip value in those cases isn't critical.
+      // FIXME: Fixing bug 646690 would probably makes this check unnecessary
+      if (this._lastLocation.hostname &&
+          this._overrideService.hasMatchingOverride(this._lastLocation.hostname,
                                                     (this._lastLocation.port || 443),
                                                     iData.cert, {}, {}))
         tooltip = gNavigatorBundle.getString("identity.identified.verified_by_you");
     }
     else if (newMode == this.IDENTITY_MODE_IDENTIFIED) {
       // If it's identified, then we can populate the dialog with credentials
       iData = this.getIdentityData();
       tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier",
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -172,16 +172,17 @@
 
     <!-- for invalid form error message -->
     <panel id="invalid-form-popup" type="arrow" orient="vertical" noautofocus="true" hidden="true" level="parent">
       <description/>
     </panel>
 
     <panel id="editBookmarkPanel"
            type="arrow"
+           footertype="promobox"
            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"/>
@@ -332,18 +333,23 @@
                                  updateEditUIVisibility();
                                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"
-           hidden="true" orient="vertical"/>
+    <panel id="notification-popup"
+           type="arrow"
+           footertype="promobox"
+           position="after_start"
+           hidden="true"
+           orient="vertical"
+           role="alert"/>
 
     <!-- Popup for site identity information -->
     <panel id="identity-popup"
            type="arrow"
            hidden="true"
            noautofocus="true"
            onpopupshown="document.getElementById('identity-popup-more-info-button').focus();"
            level="top">
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -621,26 +621,24 @@ function grabAll(elem)
         addImage(url.getStringValue(), gStrings.mediaBGImg, gStrings.notSet, elem, true);
     });
   }
 
   // one swi^H^H^Hif-else to rule them all
   if (elem instanceof HTMLImageElement)
     addImage(elem.src, gStrings.mediaImg,
              (elem.hasAttribute("alt")) ? elem.alt : gStrings.notSet, elem, false);
-#ifdef MOZ_SVG
   else if (elem instanceof SVGImageElement) {
     try {
       // Note: makeURLAbsolute will throw if either the baseURI is not a valid URI
       //       or the URI formed from the baseURI and the URL is not a valid URI
       var href = makeURLAbsolute(elem.baseURI, elem.href.baseVal);
       addImage(href, gStrings.mediaImg, "", elem, false);
     } catch (e) { }
   }
-#endif
 #ifdef MOZ_MEDIA
   else if (elem instanceof HTMLVideoElement) {
     addImage(elem.currentSrc, gStrings.mediaVideo, "", elem, false);
   }
   else if (elem instanceof HTMLAudioElement) {
     addImage(elem.currentSrc, gStrings.mediaAudio, "", elem, false);
   }
 #endif
@@ -836,19 +834,17 @@ function makePreview(row)
   var url = gImageView.data[row][COL_IMAGE_ADDRESS];
   var isBG = gImageView.data[row][COL_IMAGE_BG];
   var isAudio = false;
 
   setItemValue("imageurltext", url);
 
   var imageText;
   if (!isBG &&
-#ifdef MOZ_SVG
       !(item instanceof SVGImageElement) &&
-#endif
       !(gDocument instanceof ImageDocument)) {
     imageText = item.title || item.alt;
 
     if (!imageText && !(item instanceof HTMLImageElement))
       imageText = getValueText(item);
   }
   setItemValue("imagetext", imageText);
 
@@ -936,19 +932,17 @@ function makePreview(row)
 
   var newImage = new Image;
   newImage.id = "thepreviewimage";
   var physWidth = 0, physHeight = 0;
   var width = 0, height = 0;
 
   if ((item instanceof HTMLLinkElement || item instanceof HTMLInputElement ||
        item instanceof HTMLImageElement ||
-#ifdef MOZ_SVG
        item instanceof SVGImageElement ||
-#endif
       (item instanceof HTMLObjectElement && /^image\//.test(mimeType)) || isBG) && isProtocolAllowed) {
     newImage.setAttribute("src", url);
     physWidth = newImage.width || 0;
     physHeight = newImage.height || 0;
 
     // "width" and "height" attributes must be set to newImage,
     // even if there is no "width" or "height attribute in item;
     // otherwise, the preview image cannot be displayed correctly.
@@ -958,22 +952,20 @@ function makePreview(row)
     }
     else {
       // the Width and Height of an HTML tag should not be used for its background image
       // (for example, "table" can have "width" or "height" attributes)
       newImage.width = newImage.naturalWidth;
       newImage.height = newImage.naturalHeight;
     }
 
-#ifdef MOZ_SVG
     if (item instanceof SVGImageElement) {
       newImage.width = item.width.baseVal.value;
       newImage.height = item.height.baseVal.value;
     }
-#endif
 
     width = newImage.width;
     height = newImage.height;
 
     document.getElementById("theimagecontainer").collapsed = false
     document.getElementById("brokenimagecontainer").collapsed = true;
   }
 #ifdef MOZ_MEDIA
--- a/browser/base/content/syncAddDevice.xul
+++ b/browser/base/content/syncAddDevice.xul
@@ -49,16 +49,17 @@
 %syncBrandDTD;
 %syncSetupDTD;
 ]>
 <wizard xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         id="wizard"
         title="&addDevice.title.label;"
         windowtype="Sync:AddDevice"
+        persist="screenX screenY"
         onwizardnext="return gSyncAddDevice.onWizardAdvance();"
         onwizardback="return gSyncAddDevice.onWizardBack();"
         onwizardcancel="gSyncAddDevice.onWizardCancel();"
         onload="gSyncAddDevice.init();">
 
   <script type="application/javascript"
           src="chrome://browser/content/syncAddDevice.js"/>
   <script type="application/javascript"
--- a/browser/base/content/syncGenericChange.xul
+++ b/browser/base/content/syncGenericChange.xul
@@ -50,16 +50,17 @@
 %brandDTD;
 %syncBrandDTD;
 %syncSetupDTD;
 ]>
 <wizard xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         id="change-dialog"
         windowtype="Weave:ChangeSomething"
+        persist="screenX screenY"
         onwizardnext="Change.onLoad()"
         onwizardfinish="return Change.onDialogAccept();">
 
   <script type="application/javascript"
           src="chrome://browser/content/syncGenericChange.js"/>
   <script type="application/javascript"
           src="chrome://browser/content/syncUtils.js"/>
   <script type="application/javascript"
--- a/browser/base/content/syncKey.xhtml
+++ b/browser/base/content/syncKey.xhtml
@@ -46,16 +46,17 @@
   %syncKeyDTD;
   <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd" >
   %globalDTD;
 ]>
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
   <title>&syncKey.page.title;</title>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+  <meta name="robots" content="noindex"/>
   <style type="text/css">
     #synckey { font-size: 150% }
     footer { font-size: 70% }
 # Bug 575675: Need to have an a:visited rule in a chrome document.
     a:visited { color: purple; }
   </style>
 </head>
 
--- a/browser/base/content/syncQuota.xul
+++ b/browser/base/content/syncQuota.xul
@@ -45,16 +45,17 @@
 <!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
 <!ENTITY % syncQuotaDTD SYSTEM "chrome://browser/locale/syncQuota.dtd">
 %brandDTD;
 %syncBrandDTD;
 %syncQuotaDTD;
 ]>
 <dialog id="quotaDialog"
         windowtype="Sync:ViewQuota"
+        persist="screenX screenY width height"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         onload="gSyncQuota.init()"
         buttons="accept,cancel"
         title="&quota.dialogTitle.label;"
         ondialogcancel="return true;"
         ondialogaccept="return gSyncQuota.onAccept();">
 
--- a/browser/base/content/syncSetup.js
+++ b/browser/base/content/syncSetup.js
@@ -59,16 +59,17 @@ const SETUP_SUCCESS_PAGE            = 8;
 // Broader than we'd like, but after this changed from api-secure.recaptcha.net
 // we had no choice. At least we only do this for the duration of setup.
 // See discussion in Bugs 508112 and 653307.
 const RECAPTCHA_DOMAIN = "https://www.google.com";
 
 Cu.import("resource://services-sync/main.js");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/PlacesUtils.jsm");
 Cu.import("resource://gre/modules/PluralForm.jsm");
 
 var gSyncSetup = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIWebProgressListener,
                                          Ci.nsISupportsWeakReference]),
 
   captchaBrowser: null,
@@ -817,17 +818,19 @@ var gSyncSetup = {
   _handleChoice: function () {
     let desc = document.getElementById("mergeChoiceRadio").selectedIndex;
     document.getElementById("chosenActionDeck").selectedIndex = desc;
     switch (desc) {
       case 1:
         if (this._case1Setup)
           break;
 
-        let places_db = Weave.Svc.History.DBConnection;
+        let places_db = PlacesUtils.history
+                                   .QueryInterface(Ci.nsPIPlacesDatabase)
+                                   .DBConnection;
         if (Weave.Engines.get("history").enabled) {
           let daysOfHistory = 0;
           let stm = places_db.createStatement(
             "SELECT ROUND(( " +
               "strftime('%s','now','localtime','utc') - " +
               "( " +
                 "SELECT visit_date FROM moz_historyvisits " +
                 "ORDER BY visit_date ASC LIMIT 1 " +
@@ -848,31 +851,31 @@ var gSyncSetup = {
 
         if (Weave.Engines.get("bookmarks").enabled) {
           let bookmarks = 0;
           let stm = places_db.createStatement(
             "SELECT count(*) AS bookmarks " +
             "FROM moz_bookmarks b " +
             "LEFT JOIN moz_bookmarks t ON " +
             "b.parent = t.id WHERE b.type = 1 AND t.parent <> :tag");
-          stm.params.tag = Weave.Svc.Bookmark.tagsFolder;
+          stm.params.tag = PlacesUtils.tagsFolderId;
           if (stm.executeStep())
             bookmarks = stm.row.bookmarks;
           // Support %S for historical reasons (see bug 600141)
           document.getElementById("bookmarkCount").value =
             PluralForm.get(bookmarks,
                            this._stringBundle.GetStringFromName("bookmarksCount.label"))
                       .replace("%S", bookmarks)
                       .replace("#1", bookmarks);
         } else {
           document.getElementById("bookmarkCount").hidden = true;
         }
 
         if (Weave.Engines.get("passwords").enabled) {
-          let logins = Weave.Svc.Login.getAllLogins({});
+          let logins = Services.logins.getAllLogins({});
           // Support %S for historical reasons (see bug 600141)
           document.getElementById("passwordCount").value =
             PluralForm.get(logins.length,
                            this._stringBundle.GetStringFromName("passwordsCount.label"))
                       .replace("%S", logins.length)
                       .replace("#1", logins.length);
         } else {
           document.getElementById("passwordCount").hidden = true;
--- a/browser/base/content/syncSetup.xul
+++ b/browser/base/content/syncSetup.xul
@@ -49,16 +49,17 @@
 <!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
 <!ENTITY % syncSetupDTD SYSTEM "chrome://browser/locale/syncSetup.dtd">
 %brandDTD;
 %syncBrandDTD;
 %syncSetupDTD;
 ]>
 <wizard id="accountSetup" title="&accountSetupTitle.label;"
         windowtype="Weave:AccountSetup"
+        persist="screenX screenY"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         onwizardnext="return gSyncSetup.onWizardAdvance()"
         onwizardback="return gSyncSetup.onWizardBack()"
         onwizardfinish="gSyncSetup.onWizardFinish()"
         onwizardcancel="gSyncSetup.onWizardCancel()"
         onload="gSyncSetup.init()">
 
--- a/browser/base/content/syncUtils.js
+++ b/browser/base/content/syncUtils.js
@@ -50,41 +50,41 @@ let gSyncUtils = {
     let thisDocEl = document.documentElement,
         openerDocEl = window.opener && window.opener.document.documentElement;
     if (thisDocEl.id == "accountSetup" && window.opener &&
         openerDocEl.id == "BrowserPreferences" && !openerDocEl.instantApply)
       openUILinkIn(url, "window");
     else if (thisDocEl.id == "BrowserPreferences" && !thisDocEl.instantApply)
       openUILinkIn(url, "window");
     else if (document.documentElement.id == "change-dialog")
-      Weave.Svc.WinMediator.getMostRecentWindow("navigator:browser")
-        .openUILinkIn(url, "tab");
+      Services.wm.getMostRecentWindow("navigator:browser")
+              .openUILinkIn(url, "tab");
     else
       openUILinkIn(url, "tab");
   },
 
   changeName: function changeName(input) {
     // Make sure to update to a modified name, e.g., empty-string -> default
     Weave.Clients.localName = input.value;
     input.value = Weave.Clients.localName;
   },
 
   openChange: function openChange(type, duringSetup) {
     // Just re-show the dialog if it's already open
-    let openedDialog = Weave.Svc.WinMediator.getMostRecentWindow("Sync:" + type);
+    let openedDialog = Services.wm.getMostRecentWindow("Sync:" + type);
     if (openedDialog != null) {
       openedDialog.focus();
       return;
     }
 
     // Open up the change dialog
     let changeXUL = "chrome://browser/content/syncGenericChange.xul";
     let changeOpt = "centerscreen,chrome,resizable=no";
-    Weave.Svc.WinWatcher.activeWindow.openDialog(changeXUL, "", changeOpt,
-                                                 type, duringSetup);
+    Services.ww.activeWindow.openDialog(changeXUL, "", changeOpt,
+                                        type, duringSetup);
   },
 
   changePassword: function () {
     if (Weave.Utils.ensureMPUnlocked())
       this.openChange("ChangePassword");
   },
 
   resetPassphrase: function (duringSetup) {
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -90,17 +90,17 @@
         document.getElementById(this.getAttribute("tabcontainer"));
       </field>
       <field name="tabs" readonly="true">
         this.tabContainer.childNodes;
       </field>
       <property name="visibleTabs" readonly="true">
         <getter><![CDATA[
           return Array.filter(this.tabs, function(tab) {
-            return !tab.hidden && this._removingTabs.indexOf(tab) == -1;
+            return !tab.hidden && !tab.closing;
           }, this);
         ]]></getter>
       </property>
       <field name="mURIFixup" readonly="true">
         Components.classes["@mozilla.org/docshell/urifixup;1"]
                   .getService(Components.interfaces.nsIURIFixup);
       </field>
       <field name="mFaviconService" readonly="true">
@@ -203,17 +203,17 @@
             keyClose.setAttribute("disabled", "true");
 
           // We also want to remove the keyboard shortcut from the file menu
           // when the shortcut is disabled, and bring it back when it's
           // renabled.
           //
           // Fixing bug 630826 could make that happen automatically.
           // Fixing bug 630830 could avoid the ugly hack below.
-          
+
           let closeMenuItem = document.getElementById("menu_close");
           let parentPopup = closeMenuItem.parentNode;
           let nextItem = closeMenuItem.nextSibling;
           let clonedItem = closeMenuItem.cloneNode(true);
 
           parentPopup.removeChild(closeMenuItem);
 
           if (aEnabled)
@@ -958,16 +958,20 @@
                   break;
                 }
 
                 // Focus the location bar if it was previously focused for that tab.
                 // In full screen mode, only bother making the location bar visible
                 // if the tab is a blank one.
                 oldBrowser._urlbarFocused = (gURLBar && gURLBar.focused);
                 if (newBrowser._urlbarFocused && gURLBar) {
+
+                  // Explicitly close the popup if the URL bar retains focus
+                  gURLBar.closePopup();
+
                   if (!window.fullScreen) {
                     gURLBar.focus();
                     break;
                   } else if (isTabEmpty(this.mCurrentTab)) {
                     focusAndSelectUrlBar();
                     break;
                   }
                 }
@@ -994,17 +998,17 @@
             }
           ]]>
         </body>
       </method>
 
       <method name="_tabAttrModified">
         <parameter name="aTab"/>
         <body><![CDATA[
-          if (this._removingTabs.indexOf(aTab) > -1)
+          if (aTab.closing)
             return;
 
           // This event should be dispatched when any of these attributes change:
           // label, crop, busy, image, selected
           var event = document.createEvent("Events");
           event.initEvent("TabAttrModified", true, false);
           aTab.dispatchEvent(event);
         ]]></body>
@@ -1325,19 +1329,19 @@
 
               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);
-
+              } catch (ex) {
+                Cu.reportError(ex);
               }
-              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.
@@ -1450,17 +1454,17 @@
             if (aParams) {
               var animate = aParams.animate;
               var byMouse = aParams.byMouse;
             }
 
             // Handle requests for synchronously removing an already
             // asynchronously closing tab.
             if (!animate &&
-                this._removingTabs.indexOf(aTab) > -1) {
+                aTab.closing) {
               this._endRemoveTab(aTab);
               return;
             }
 
             var isLastTab = (this.tabs.length - this._removingTabs.length == 1);
 
             if (!this._beginRemoveTab(aTab, false, null, true))
               return;
@@ -1504,17 +1508,17 @@
 
       <method name="_beginRemoveTab">
         <parameter name="aTab"/>
         <parameter name="aTabWillBeMoved"/>
         <parameter name="aCloseWindowWithLastTab"/>
         <parameter name="aCloseWindowFastpath"/>
         <body>
           <![CDATA[
-            if (this._removingTabs.indexOf(aTab) > -1 || this._windowIsClosing)
+            if (aTab.closing || this._windowIsClosing)
               return false;
 
             var browser = this.getBrowserForTab(aTab);
 
             if (!aTabWillBeMoved) {
               let ds = browser.docShell;
               if (ds && ds.contentViewer && !ds.contentViewer.permitUnload())
                 return false;
@@ -1534,16 +1538,17 @@
                   aCloseWindowFastpath &&
                   this._removingTabs.length == 0 &&
                   (this._windowIsClosing = window.closeWindow(true)))
                 return null;
 
               newTab = true;
             }
 
+            aTab.closing = true;
             this._removingTabs.push(aTab);
             if (newTab)
               this.addTab("about:blank", {skipAnimation: true});
             else
               this.tabContainer.updateVisibility();
 
             // We're committed to closing the tab now.
             // Dispatch a notification.
@@ -1702,28 +1707,28 @@
         <parameter name="aTab"/>
         <body>
           <![CDATA[
             if (this.mCurrentTab != aTab)
               return;
 
             if (aTab.owner &&
                 !aTab.owner.hidden &&
-                this._removingTabs.indexOf(aTab.owner) == -1 &&
+                !aTab.owner.closing &&
                 Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")) {
               this.selectedTab = aTab.owner;
               return;
             }
 
             // Switch to a visible tab unless there aren't any others remaining
             let remainingTabs = this.visibleTabs;
             let numTabs = remainingTabs.length;
             if (numTabs == 0 || numTabs == 1 && remainingTabs[0] == aTab) {
               remainingTabs = Array.filter(this.tabs, function(tab) {
-                return this._removingTabs.indexOf(tab) == -1;
+                return !tab.closing;
               }, this);
             }
 
             // Try to find a remaining tab that comes after the given tab
             var tab = aTab;
             do {
               tab = tab.nextSibling;
             } while (tab && remainingTabs.indexOf(tab) == -1);
@@ -1928,17 +1933,17 @@
         </body>
       </method>
 
       <method name="hideTab">
         <parameter name="aTab"/>
         <body>
         <![CDATA[
           if (!aTab.hidden && !aTab.pinned && !aTab.selected &&
-              this._removingTabs.indexOf(aTab) == -1) {
+              !aTab.closing) {
             aTab.setAttribute("hidden", "true");
             this.tabContainer.adjustTabstrip();
             let event = document.createEvent("Events");
             event.initEvent("TabHide", true, false);
             aTab.dispatchEvent(event);
           }
         ]]>
         </body>
@@ -2943,18 +2948,17 @@
           }
         ]]></body>
       </method>
 
       <method name="_positionPinnedTabs">
         <body><![CDATA[
           var numPinned = this.tabbrowser._numPinnedTabs;
           var doPosition = this.getAttribute("overflow") == "true" &&
-                           numPinned > 0 &&
-                           numPinned < this.tabbrowser.visibleTabs.length;
+                           numPinned > 0;
 
           if (doPosition) {
             this.setAttribute("positionpinnedtabs", "true");
 
             let scrollButtonWidth = this.mTabstrip._scrollButtonDown.scrollWidth;
             let paddingStart = this.mTabstrip.scrollboxPaddingStart;
             let width = 0;
 
@@ -3072,17 +3076,17 @@
 
       <method name="_getDropIndex">
         <parameter name="event"/>
         <body><![CDATA[
           var tabs = this.childNodes;
           var tab = this._getDragTargetTab(event);
           if (window.getComputedStyle(this, null).direction == "ltr") {
             for (let i = tab ? tab._tPos : 0; i < tabs.length; i++)
-              if (event.screenX < tabs[i].boxObject.screenX + tabs[i].boxObject.width / 2) 
+              if (event.screenX < tabs[i].boxObject.screenX + tabs[i].boxObject.width / 2)
                 return i;
           } else {
             for (let i = tab ? tab._tPos : 0; i < tabs.length; i++)
               if (event.screenX > tabs[i].boxObject.screenX + tabs[i].boxObject.width / 2)
                 return i;
           }
           return tabs.length;
         ]]></body>
@@ -3166,17 +3170,17 @@
           this.mTabstrip._updateScrollButtonsDisabledState();
         ]]></body>
       </method>
 
       <method name="_canAdvanceToTab">
         <parameter name="aTab"/>
         <body>
         <![CDATA[
-          return this.tabbrowser._removingTabs.indexOf(aTab) == -1;
+          return !aTab.closing;
         ]]>
         </body>
       </method>
 
       <!-- Deprecated stuff, implemented for backwards compatibility. -->
       <property name="mTabstripClosebutton" readonly="true"
                 onget="return document.getElementById('tabs-closebutton');"/>
       <property name="mAllTabsPopup" readonly="true"
@@ -3189,17 +3193,17 @@
       <handler event="transitionend"><![CDATA[
         if (event.propertyName != "max-width")
           return;
 
         var tab = event.target;
 
         if (tab.getAttribute("fadein") == "true")
           this._handleNewTab(tab);
-        else if (this.tabbrowser._removingTabs.indexOf(tab) > -1)
+        else if (tab.closing)
           this.tabbrowser._endRemoveTab(tab);
       ]]></handler>
 
       <handler event="dblclick"><![CDATA[
 #ifdef MOZ_WIDGET_GTK2
         // Disable this on GTK2 when the menubar is draggable, since (a)
         // the menubar and tabbbar have unified appearance and should
         // thus not have different behavior (though this condition alone
@@ -3332,17 +3336,17 @@
             return;
           }
         }
 
         var newIndex = this._getDropIndex(event);
         var scrollRect = tabStrip.scrollClientRect;
         var rect = this.getBoundingClientRect();
         var minMargin = scrollRect.left - rect.left;
-        var maxMargin = Math.min(minMargin + scrollRect.width, 
+        var maxMargin = Math.min(minMargin + scrollRect.width,
                                  scrollRect.right);
         if (!ltr)
           [minMargin, maxMargin] = [this.clientWidth - maxMargin,
                                     this.clientWidth - minMargin];
         var newMargin;
         if (pixelsToScroll) {
           // if we are scrolling, put the drop indicator at the edge
           // so that it doesn't jump while scrolling
@@ -3630,16 +3634,17 @@
         <getter>
           return this.getAttribute("hidden") == "true";
         </getter>
       </property>
 
       <field name="mOverCloseButton">false</field>
       <field name="mCorrespondingMenuitem">null</field>
       <field name="_fullyOpen">false</field>
+      <field name="closing">false</field>
     </implementation>
 
     <handlers>
       <handler event="mouseover">
         var anonid = event.originalTarget.getAttribute("anonid");
         if (anonid == "close-button")
           this.mOverCloseButton = true;
       </handler>
@@ -3741,28 +3746,28 @@
             let curTab = this.childNodes[i].tab;
             if (!curTab) // "Tab Groups" menuitem and its menuseparator
               continue;
             let curTabBO = curTab.boxObject;
             if (!curTabBO) // "Tabs From Other Computers" menuitem
               continue;
             if (curTabBO.screenX >= tabstripBO.screenX &&
                 curTabBO.screenX + curTabBO.width <= tabstripBO.screenX + tabstripBO.width)
-              this.childNodes[i].setAttribute("tabIsVisible", "true"); 
+              this.childNodes[i].setAttribute("tabIsVisible", "true");
             else
               this.childNodes[i].removeAttribute("tabIsVisible");
           }
         ]]></body>
       </method>
 
       <method name="_createTabMenuItem">
         <parameter name="aTab"/>
         <body><![CDATA[
           var menuItem = document.createElementNS(
-            "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", 
+            "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
             "menuitem");
 
           menuItem.setAttribute("class", "menuitem-iconic alltabs-item menuitem-with-favicon");
 
           this._setMenuitemAttributes(menuItem, aTab);
 
           // Keep some attributes of the menuitem in sync with its
           // corresponding tab (e.g. the tab label)
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -2027,17 +2027,17 @@ let GroupItems = {
   // Function: getAppTabFavIconUrl
   // Gets the fav icon url for app tab.
   getAppTabFavIconUrl: function GroupItems__getAppTabFavIconUrl(xulTab) {
     let iconUrl;
 
     if (UI.shouldLoadFavIcon(xulTab.linkedBrowser))
       iconUrl = UI.getFavIconUrlForTab(xulTab);
     else
-      iconUrl = Utils.defaultFaviconURL;
+      iconUrl = gFavIconService.defaultFavicon.spec;
 
     return iconUrl;
   },
 
   // ----------
   // Function: addAppTab
   // Adds the given xul:tab to the app tab tray in all groups
   addAppTab: function GroupItems_addAppTab(xulTab) {
@@ -2102,17 +2102,19 @@ let GroupItems = {
   // Function: _save
   // Saves GroupItems state.
   _save: function GroupItems__save() {
     if (!this._inited) // too soon to save now
       return;
 
     let activeGroupId = this._activeGroupItem ? this._activeGroupItem.id : null;
     Storage.saveGroupItemsData(
-      gWindow, { nextID: this.nextID, activeGroupId: activeGroupId });
+      gWindow,
+      { nextID: this.nextID, activeGroupId: activeGroupId,
+        totalNumber: this.groupItems.length });
   },
 
   // ----------
   // Function: getBoundingBox
   // Given an array of DOM elements, returns a <Rect> with (roughly) the union of their locations.
   getBoundingBox: function GroupItems_getBoundingBox(els) {
     var bounds = [iQ(el).bounds() for each (el in els)];
     var left   = Math.min.apply({},[ b.left   for each (b in bounds) ]);
--- a/browser/base/content/tabview/iq.js
+++ b/browser/base/content/tabview/iq.js
@@ -603,17 +603,17 @@ iQClass.prototype = {
       let cStyle = window.getComputedStyle(elem, null);
       for (let prop in css) {
         prop = prop.replace(rupper, "-$1").toLowerCase();
         iQ(elem).css(prop, cStyle.getPropertyValue(prop));
       }
     });
 
     this.css({
-      '-moz-transition-property': 'all', // TODO: just animate the properties we're changing
+      '-moz-transition-property': Object.keys(css).join(", "),
       '-moz-transition-duration': (duration / 1000) + 's',
       '-moz-transition-timing-function': easing
     });
 
     this.css(css);
 
     let self = this;
     setTimeout(function() {
--- a/browser/base/content/tabview/modules/AllTabs.jsm
+++ b/browser/base/content/tabview/modules/AllTabs.jsm
@@ -52,20 +52,17 @@ let AllTabs = {
    * Get an array of all tabs from all tabbrowser windows.
    *
    * @usage let numAllTabs = AllTabs.tabs.length;
    *        AllTabs.tabs.forEach(handleAllTabs);
    */
   get tabs() {
     // Get tabs from each browser window and flatten them into one array
     return Array.concat.apply(null, browserWindows.map(function(browserWindow) {
-      let removingTabs = browserWindow.gBrowser._removingTabs;
-      return Array.filter(browserWindow.gBrowser.tabs, function (tab) {
-        return removingTabs.indexOf(tab) == -1;
-      });
+      return Array.filter(browserWindow.gBrowser.tabs, function (tab) !tab.closing);
     }));
   },
 
   /**
    * Attach a callback for a given tab event.
    *
    * @param eventName
    *        Name of the corresponding Tab* Event; one of "attrModified",
--- a/browser/base/content/tabview/modules/utils.jsm
+++ b/browser/base/content/tabview/modules/utils.jsm
@@ -485,18 +485,16 @@ Subscribable.prototype = {
     }, this);
   }
 };
 
 // ##########
 // Class: Utils
 // Singelton with common utility functions.
 let Utils = {
-  defaultFaviconURL: "chrome://mozapps/skin/places/defaultFavicon.png",
-
   // ----------
   // Function: toString
   // Prints [Utils] for debug use
   toString: function Utils_toString() {
     return "[Utils]";
   },
 
   // ___ Logging
--- a/browser/base/content/tabview/storage.js
+++ b/browser/base/content/tabview/storage.js
@@ -42,55 +42,37 @@
 // ##########
 // Class: Storage
 // Singleton for permanent storage of TabView data.
 let Storage = {
   GROUP_DATA_IDENTIFIER: "tabview-group",
   GROUPS_DATA_IDENTIFIER: "tabview-groups",
   TAB_DATA_IDENTIFIER: "tabview-tab",
   UI_DATA_IDENTIFIER: "tabview-ui",
-  CACHE_CLIENT_IDENTIFIER: "tabview-cache",
-  CACHE_PREFIX: "moz-panorama:",
 
   // ----------
   // Function: toString
   // Prints [Storage] for debug use
   toString: function Storage_toString() {
     return "[Storage]";
   },
 
   // ----------
   // Function: init
   // Sets up the object.
   init: function Storage_init() {
     this._sessionStore =
       Cc["@mozilla.org/browser/sessionstore;1"].
         getService(Ci.nsISessionStore);
-    
-    // Create stream-based cache session for tabview
-    let cacheService = 
-      Cc["@mozilla.org/network/cache-service;1"].
-        getService(Ci.nsICacheService);
-    this._cacheSession = cacheService.createSession(
-      this.CACHE_CLIENT_IDENTIFIER, Ci.nsICache.STORE_ON_DISK, true);
-    this.StringInputStream = Components.Constructor(
-      "@mozilla.org/io/string-input-stream;1", "nsIStringInputStream",
-      "setData");
-    this.StorageStream = Components.Constructor(
-      "@mozilla.org/storagestream;1", "nsIStorageStream", 
-      "init");
   },
 
   // ----------
   // Function: uninit
   uninit: function Storage_uninit () {
     this._sessionStore = null;
-    this._cacheSession = null;
-    this.StringInputStream = null;
-    this.StorageStream = null;
   },
 
   // ----------
   // Function: wipe
   // Cleans out all the stored data, leaving empty objects.
   wipe: function Storage_wipe() {
     try {
       var self = this;
@@ -110,166 +92,28 @@ let Storage = {
       this._sessionStore.setWindowValue(gWindow, this.GROUP_DATA_IDENTIFIER,
         JSON.stringify({}));
     } catch (e) {
       Utils.log("Error in wipe: "+e);
     }
   },
 
   // ----------
-  // Function: _openCacheEntry
-  // Opens a cache entry for the given <url> and requests access <access>.
-  // Calls <successCallback>(entry) when the entry was successfully opened with
-  // requested access rights. Otherwise calls <errorCallback>().
-  _openCacheEntry: function Storage__openCacheEntry(url, access, successCallback, errorCallback) {
-    let onCacheEntryAvailable = function (entry, accessGranted, status) {
-      if (entry && access == accessGranted && Components.isSuccessCode(status)) {
-        successCallback(entry);
-      } else {
-        entry && entry.close();
-        errorCallback();
-      }
-    }
-
-    let key = this.CACHE_PREFIX + url;
-
-    // switch to synchronous mode if parent window is about to close
-    if (UI.isDOMWindowClosing) {
-      let entry = this._cacheSession.openCacheEntry(key, access, true);
-      let status = Components.results.NS_OK;
-      onCacheEntryAvailable(entry, entry.accessGranted, status);
-    } else {
-      let listener = new CacheListener(onCacheEntryAvailable);
-      this._cacheSession.asyncOpenCacheEntry(key, access, listener);
-    }
-  },
-
-  // ----------
-  // Function: saveThumbnail
-  // Saves the <imageData> to the cache using the given <url> as key.
-  // Calls <callback>(status) when finished (passing true or false indicating
-  // whether the operation succeeded).
-  saveThumbnail: function Storage_saveThumbnail(url, imageData, callback) {
-    Utils.assert(url, "url");
-    Utils.assert(imageData, "imageData");
-    Utils.assert(typeof callback == "function", "callback arg must be a function");
-
-    let self = this;
-    let StringInputStream = this.StringInputStream;
-
-    let onCacheEntryAvailable = function (entry) {
-      let outputStream = entry.openOutputStream(0);
-
-      let cleanup = function () {
-        outputStream.close();
-        entry.close();
-      }
-
-      // switch to synchronous mode if parent window is about to close
-      if (UI.isDOMWindowClosing) {
-        outputStream.write(imageData, imageData.length);
-        cleanup();
-        callback(true);
-        return;
-      }
-
-      // asynchronous mode
-      let inputStream = new StringInputStream(imageData, imageData.length);
-      gNetUtil.asyncCopy(inputStream, outputStream, function (result) {
-        cleanup();
-        inputStream.close();
-        callback(Components.isSuccessCode(result));
-      });
-    }
-
-    let onCacheEntryUnavailable = function () {
-      callback(false);
-    }
-
-    this._openCacheEntry(url, Ci.nsICache.ACCESS_WRITE,
-        onCacheEntryAvailable, onCacheEntryUnavailable);
-  },
-
-  // ----------
-  // Function: loadThumbnail
-  // Asynchrously loads image data from the cache using the given <url> as key.
-  // Calls <callback>(status, data) when finished, passing true or false
-  // (indicating whether the operation succeeded) and the retrieved image data.
-  loadThumbnail: function Storage_loadThumbnail(url, callback) {
-    Utils.assert(url, "url");
-    Utils.assert(typeof callback == "function", "callback arg must be a function");
-
-    let self = this;
-
-    let onCacheEntryAvailable = function (entry) {
-      let imageChunks = [];
-      let nativeInputStream = entry.openInputStream(0);
-
-      const CHUNK_SIZE = 0x10000; // 65k
-      const PR_UINT32_MAX = 0xFFFFFFFF;
-      let storageStream = new self.StorageStream(CHUNK_SIZE, PR_UINT32_MAX, null);
-      let storageOutStream = storageStream.getOutputStream(0);
-
-      let cleanup = function () {
-        nativeInputStream.close();
-        storageStream.close();
-        storageOutStream.close();
-        entry.close();
-      }
-
-      gNetUtil.asyncCopy(nativeInputStream, storageOutStream, function (result) {
-        // cancel if parent window has already been closed
-        if (typeof UI == "undefined") {
-          cleanup();
-          return;
-        }
-
-        let imageData = null;
-        let isSuccess = Components.isSuccessCode(result);
-
-        if (isSuccess) {
-          let storageInStream = storageStream.newInputStream(0);
-          imageData = gNetUtil.readInputStreamToString(storageInStream,
-            storageInStream.available());
-          storageInStream.close();
-        }
-
-        cleanup();
-        callback(isSuccess, imageData);
-      });
-    }
-
-    let onCacheEntryUnavailable = function () {
-      callback(false);
-    }
-
-    this._openCacheEntry(url, Ci.nsICache.ACCESS_READ,
-        onCacheEntryAvailable, onCacheEntryUnavailable);
-  },
-
-  // ----------
   // Function: saveTab
   // Saves the data for a single tab.
   saveTab: function Storage_saveTab(tab, data) {
     Utils.assert(tab, "tab");
 
     if (data != null) {
       let imageData = data.imageData;
       // Remove imageData from payload
       delete data.imageData;
-      if (imageData != null) {
-        this.saveThumbnail(data.url, imageData, function (status) {
-          if (status) {
-            // Notify subscribers
-            tab._tabViewTabItem._sendToSubscribers("savedCachedImageData");
-          } else {
-            Utils.log("Error while saving thumbnail: " + e);
-          }
-        });
-      }
+
+      if (imageData != null)
+        ThumbnailStorage.saveThumbnail(tab, imageData);
     }
 
     this._sessionStore.setTabValue(tab, this.TAB_DATA_IDENTIFIER,
       JSON.stringify(data));
   },
 
   // ----------
   // Function: getTabData
@@ -287,28 +131,23 @@ let Storage = {
         existingData = JSON.parse(tabData);
       }
     } catch (e) {
       // getTabValue will fail if the property doesn't exist.
       Utils.log(e);
     }
 
     if (existingData) {
-      this.loadThumbnail(existingData.url, function (status, imageData) {
-        if (status) {
+      ThumbnailStorage.loadThumbnail(
+        tab, existingData.url,
+        function(status, imageData) { 
           callback(imageData);
-
-          // Notify subscribers
-          tab._tabViewTabItem._sendToSubscribers("loadedCachedImageData");
-        } else {
-          Utils.log("Error while loading thumbnail");
         }
-      });
+      );
     }
-
     return existingData;
   },
 
   // ----------
   // Function: saveGroupItem
   // Saves the data for a single groupItem, associated with a specific window.
   saveGroupItem: function Storage_saveGroupItem(win, data) {
     var id = data.id;
@@ -404,31 +243,8 @@ let Storage = {
     } catch (e) {
       Utils.log("Error in readData: "+e);
     }
 
     return existingData;
   }
 };
 
-// ##########
-// Class: CacheListener
-// Generic CacheListener for feeding to asynchronous cache calls.
-// Calls <callback>(entry, access, status) when the requested cache entry
-// is available.
-function CacheListener(callback) {
-  Utils.assert(typeof callback == "function", "callback arg must be a function");
-  this.callback = callback;
-};
-
-CacheListener.prototype = {
-  // ----------
-  // Function: toString
-  // Prints [CacheListener] for debug use
-  toString: function CacheListener_toString() {
-    return "[CacheListener]";
-  },
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsICacheListener]),
-  onCacheEntryAvailable: function (entry, access, status) {
-    this.callback(entry, access, status);
-  }
-};
--- a/browser/base/content/tabview/tabitems.js
+++ b/browser/base/content/tabview/tabitems.js
@@ -1553,11 +1553,11 @@ TabCanvas.prototype = {
     let top = win.scrollY;
 
     return new Rect(left, top, width, height);
   },
 
   // ----------
   // Function: toImageData
   toImageData: function TabCanvas_toImageData() {
-    return this.canvas.toDataURL("image/png", "");
+    return this.canvas.toDataURL("image/png");
   }
 };
--- a/browser/base/content/tabview/tabview.js
+++ b/browser/base/content/tabview/tabview.js
@@ -1,11 +1,12 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
+const Cr = Components.results;
 
 Cu.import("resource:///modules/tabview/AllTabs.jsm");
 Cu.import("resource:///modules/tabview/utils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "tabviewBundle", function() {
   return Services.strings.
@@ -45,10 +46,11 @@ var gTabViewFrame = gWindow.document.get
 
 #include iq.js
 #include storage.js
 #include items.js
 #include groupitems.js
 #include tabitems.js
 #include drag.js
 #include trench.js
+#include thumbnailStorage.js
 #include ui.js
 #include search.js
new file mode 100644
--- /dev/null
+++ b/browser/base/content/tabview/thumbnailStorage.js
@@ -0,0 +1,373 @@
+/* ***** 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 thumbnailStorage.js.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * 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 ***** */
+
+// **********
+// Title: thumbnailStorage.js
+
+// ##########
+// Class: ThumbnailStorage
+// Singleton for persistent storage of thumbnail data.
+let ThumbnailStorage = {
+  CACHE_CLIENT_IDENTIFIER: "tabview-cache",
+  CACHE_PREFIX: "moz-panorama:",
+  PREF_DISK_CACHE_SSL: "browser.cache.disk_cache_ssl",
+
+  // Holds the cache session reference
+  _cacheSession: null,
+
+  // Holds the string input stream reference
+  _stringInputStream: null,
+
+  // Holds the storage stream reference
+  _storageStream: null,
+
+  // Holds the progress listener reference
+  _progressListener: null,
+
+  // Used to keep track of disk_cache_ssl preference
+  enablePersistentHttpsCaching: null,
+
+  // Used to keep track of browsers whose thumbs we shouldn't save
+  excludedBrowsers: [],
+
+  // ----------
+  // Function: toString
+  // Prints [ThumbnailStorage] for debug use.
+  toString: function ThumbnailStorage_toString() {
+    return "[ThumbnailStorage]";
+  },
+
+  // ----------
+  // Function: init
+  // Should be called when UI is initialized.
+  init: function ThumbnailStorage_init() {
+    // Create stream-based cache session for tabview
+    let cacheService = 
+      Cc["@mozilla.org/network/cache-service;1"].
+        getService(Ci.nsICacheService);
+    this._cacheSession = cacheService.createSession(
+      this.CACHE_CLIENT_IDENTIFIER, Ci.nsICache.STORE_ON_DISK, true);
+    this._stringInputStream = Components.Constructor(
+      "@mozilla.org/io/string-input-stream;1", "nsIStringInputStream",
+      "setData");
+    this._storageStream = Components.Constructor(
+      "@mozilla.org/storagestream;1", "nsIStorageStream", 
+      "init");
+
+    // store the preference value
+    this.enablePersistentHttpsCaching =
+      Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
+
+    Services.prefs.addObserver(this.PREF_DISK_CACHE_SSL, this, false);
+
+    let self = this;
+    // tabs are already loaded before UI is initialized so cache-control
+    // values are unknown.  We add browsers with https to the list for now.
+    gBrowser.browsers.forEach(function(browser) {
+      let checkAndAddToList = function(browserObj) {
+        if (!self.enablePersistentHttpsCaching &&
+            browserObj.currentURI.schemeIs("https"))
+          self.excludedBrowsers.push(browserObj);
+      };
+      if (browser.contentDocument.readyState != "complete" ||
+          browser.webProgress.isLoadingDocument) {
+        browser.addEventListener("load", function() {
+          browser.removeEventListener("load", arguments.callee, true);
+          checkAndAddToList(browser);
+        }, true);
+      } else {
+        checkAndAddToList(browser);
+      }
+    });
+    gBrowser.addTabsProgressListener(this);
+  },
+
+  // Function: uninit
+  // Should be called when window is unloaded.
+  uninit: function ThumbnailStorage_uninit() {
+    gBrowser.removeTabsProgressListener(this);
+    Services.prefs.removeObserver(this.PREF_DISK_CACHE_SSL, this);
+  },
+
+  // ----------
+  // Function: _openCacheEntry
+  // Opens a cache entry for the given <url> and requests access <access>.
+  // Calls <successCallback>(entry) when the entry was successfully opened with
+  // requested access rights. Otherwise calls <errorCallback>().
+  _openCacheEntry: function ThumbnailStorage__openCacheEntry(url, access, successCallback, errorCallback) {
+    let onCacheEntryAvailable = function(entry, accessGranted, status) {
+      if (entry && access == accessGranted && Components.isSuccessCode(status)) {
+        successCallback(entry);
+      } else {
+        entry && entry.close();
+        errorCallback();
+      }
+    }
+
+    let key = this.CACHE_PREFIX + url;
+
+    // switch to synchronous mode if parent window is about to close
+    if (UI.isDOMWindowClosing) {
+      let entry = this._cacheSession.openCacheEntry(key, access, true);
+      let status = Cr.NS_OK;
+      onCacheEntryAvailable(entry, entry.accessGranted, status);
+    } else {
+      let listener = new CacheListener(onCacheEntryAvailable);
+      this._cacheSession.asyncOpenCacheEntry(key, access, listener);
+    }
+  },
+
+  // Function: _shouldSaveThumbnail
+  // Checks whether to save tab's thumbnail or not.
+  _shouldSaveThumbnail : function ThumbnailStorage__shouldSaveThumbnail(tab) {
+    return (this.excludedBrowsers.indexOf(tab.linkedBrowser) == -1);
+  },
+
+  // ----------
+  // Function: saveThumbnail
+  // Saves the <imageData> to the cache using the given <url> as key.
+  // Calls <callback>(status, data) when finished, passing true or false
+  // (indicating whether the operation succeeded).
+  saveThumbnail: function ThumbnailStorage_saveThumbnail(tab, imageData, callback) {
+    Utils.assert(tab, "tab");
+    Utils.assert(imageData, "imageData");
+    
+    if (!this._shouldSaveThumbnail(tab)) {
+      tab._tabViewTabItem._sendToSubscribers("deniedToCacheImageData");
+      if (callback)
+        callback(false);
+      return;
+    }
+
+    let self = this;
+
+    let completed = function(status) {
+      if (callback)
+        callback(status);
+
+      if (status) {
+        // Notify subscribers
+        tab._tabViewTabItem._sendToSubscribers("savedCachedImageData");
+      } else {
+        Utils.log("Error while saving thumbnail: " + e);
+      }
+    };
+
+    let onCacheEntryAvailable = function(entry) {
+      let outputStream = entry.openOutputStream(0);
+
+      let cleanup = function() {
+        outputStream.close();
+        entry.close();
+      }
+
+      // switch to synchronous mode if parent window is about to close
+      if (UI.isDOMWindowClosing) {
+        outputStream.write(imageData, imageData.length);
+        cleanup();
+        completed(true);
+        return;
+      }
+
+      // asynchronous mode
+      let inputStream = new self._stringInputStream(imageData, imageData.length);
+      gNetUtil.asyncCopy(inputStream, outputStream, function (result) {
+        cleanup();
+        inputStream.close();
+        completed(Components.isSuccessCode(result));
+      });
+    }
+
+    let onCacheEntryUnavailable = function() {
+      completed(false);
+    }
+
+    this._openCacheEntry(tab.linkedBrowser.currentURI.spec, 
+        Ci.nsICache.ACCESS_WRITE, onCacheEntryAvailable, 
+        onCacheEntryUnavailable);
+  },
+
+  // ----------
+  // Function: loadThumbnail
+  // Asynchrously loads image data from the cache using the given <url> as key.
+  // Calls <callback>(status, data) when finished, passing true or false
+  // (indicating whether the operation succeeded) and the retrieved image data.
+  loadThumbnail: function ThumbnailStorage_loadThumbnail(tab, url, callback) {
+    Utils.assert(tab, "tab");
+    Utils.assert(url, "url");
+    Utils.assert(typeof callback == "function", "callback arg must be a function");
+
+    let self = this;
+
+    let completed = function(status, imageData) {
+      callback(status, imageData);
+
+      if (status) {
+        // Notify subscribers
+        tab._tabViewTabItem._sendToSubscribers("loadedCachedImageData");
+      } else {
+        Utils.log("Error while loading thumbnail");
+      }
+    }
+
+    let onCacheEntryAvailable = function(entry) {
+      let imageChunks = [];
+      let nativeInputStream = entry.openInputStream(0);
+
+      const CHUNK_SIZE = 0x10000; // 65k
+      const PR_UINT32_MAX = 0xFFFFFFFF;
+      let storageStream = new self._storageStream(CHUNK_SIZE, PR_UINT32_MAX, null);
+      let storageOutStream = storageStream.getOutputStream(0);
+
+      let cleanup = function () {
+        nativeInputStream.close();
+        storageStream.close();
+        storageOutStream.close();
+        entry.close();
+      }
+
+      gNetUtil.asyncCopy(nativeInputStream, storageOutStream, function (result) {
+        // cancel if parent window has already been closed
+        if (typeof UI == "undefined") {
+          cleanup();
+          return;
+        }
+
+        let imageData = null;
+        let isSuccess = Components.isSuccessCode(result);
+
+        if (isSuccess) {
+          let storageInStream = storageStream.newInputStream(0);
+          imageData = gNetUtil.readInputStreamToString(storageInStream,
+            storageInStream.available());
+          storageInStream.close();
+        }
+
+        cleanup();
+        completed(isSuccess, imageData);
+      });
+    }
+
+    let onCacheEntryUnavailable = function() {
+      completed(false);
+    }
+
+    this._openCacheEntry(url, Ci.nsICache.ACCESS_READ,
+        onCacheEntryAvailable, onCacheEntryUnavailable);
+  },
+
+  // ----------
+  // Function: observe
+  // Implements the observer interface.
+  observe: function ThumbnailStorage_observe(subject, topic, data) {
+    this.enablePersistentHttpsCaching =
+      Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
+  },
+
+  // ----------
+  // Implements progress listener interface.
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+                                         Ci.nsISupportsWeakReference,
+                                         Ci.nsISupports]),
+
+  onStateChange: function ThumbnailStorage_onStateChange(
+    browser, webProgress, request, flag, status) {
+    if (flag & Ci.nsIWebProgressListener.STATE_START &&
+        flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
+      // ensure the dom window is the top one
+      if (webProgress.DOMWindow.parent == webProgress.DOMWindow) {
+        let index = this.excludedBrowsers.indexOf(browser);
+        if (index != -1)
+          this.excludedBrowsers.splice(index, 1);
+      }
+    }
+    if (flag & Ci.nsIWebProgressListener.STATE_STOP &&
+        flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
+      // ensure the dom window is the top one
+      if (webProgress.DOMWindow.parent == webProgress.DOMWindow &&
+          request && request instanceof Ci.nsIHttpChannel) {
+        request.QueryInterface(Ci.nsIHttpChannel);
+
+        let inhibitPersistentThumb = false;
+        if (request.isNoStoreResponse()) {
+           inhibitPersistentThumb = true;
+        } else if (!this.enablePersistentHttpsCaching &&
+                   request.URI.schemeIs("https")) {
+          let cacheControlHeader;
+          try {
+            cacheControlHeader = request.getResponseHeader("Cache-Control");
+          } catch(e) {
+            // this error would occur when "Cache-Control" doesn't exist in
+            // the eaders
+          }
+          if (cacheControlHeader && !(/public/i).test(cacheControlHeader))
+            inhibitPersistentThumb = true;
+        }
+
+        if (inhibitPersistentThumb &&
+            this.excludedBrowsers.indexOf(browser) == -1)
+          this.excludedBrowsers.push(browser);
+      }
+    }
+  }
+}
+
+// ##########
+// Class: CacheListener
+// Generic CacheListener for feeding to asynchronous cache calls.
+// Calls <callback>(entry, access, status) when the requested cache entry
+// is available.
+function CacheListener(callback) {
+  Utils.assert(typeof callback == "function", "callback arg must be a function");
+  this.callback = callback;
+};
+
+CacheListener.prototype = {
+  // ----------
+  // Function: toString
+  // Prints [CacheListener] for debug use
+  toString: function CacheListener_toString() {
+    return "[CacheListener]";
+  },
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsICacheListener]),
+  onCacheEntryAvailable: function CacheListener_onCacheEntryAvailable(
+    entry, access, status) {
+    this.callback(entry, access, status);
+  }
+};
+
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -152,16 +152,19 @@ let UI = {
   // Must be called after the object is created.
   init: function UI_init() {
     try {
       let self = this;
 
       // initialize the direction of the page
       this._initPageDirection();
 
+      // ___ thumbnail storage
+      ThumbnailStorage.init();
+
       // ___ storage
       Storage.init();
       let data = Storage.readUIData(gWindow);
       this._storageSanity(data);
       this._pageBounds = data.pageBounds;
 
       // ___ currentTab
       this._currentTab = gBrowser.selectedTab;
@@ -273,35 +276,38 @@ let UI = {
       // ___ Done
       this._frameInitialized = true;
       this._save();
 
       // fire an iframe initialized event so everyone knows tab view is 
       // initialized.
       let event = document.createEvent("Events");
       event.initEvent("tabviewframeinitialized", true, false);
-      dispatchEvent(event);      
+      dispatchEvent(event);
     } catch(e) {
       Utils.log(e);
     } finally {
       GroupItems.resumeArrange();
     }
   },
 
+  // Function: uninit
+  // Should be called when window is unloaded.
   uninit: function UI_uninit() {
     // call our cleanup functions
     this._cleanupFunctions.forEach(function(func) {
       func();
     });
     this._cleanupFunctions = [];
 
     // additional clean up
     TabItems.uninit();
     GroupItems.uninit();
     Storage.uninit();
+    ThumbnailStorage.uninit();
 
     this._removeTabActionHandlers();
     this._currentTab = null;
     this._pageBounds = null;
     this._reorderTabItemsOnShow = null;
     this._reorderTabsOnHide = null;
     this._frameInitialized = false;
   },
@@ -675,32 +681,32 @@ let UI = {
     });
 
     // Private Browsing:
     // When transitioning to PB, we exit Panorama if necessary (making note of the
     // fact that we were there so we can return after PB) and make sure we
     // 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") {
+    function pbObserver(subject, topic, data) {
+      if (topic == "private-browsing") {
         // We could probably do this in private-browsing-change-granted, but
         // this seems like a nicer spot, right in the middle of the process.
-        if (aData == "enter") {
+        if (data == "enter") {
           // If we are in Tab View, exit. 
           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.transitionMode = aData;
+      } else if (topic == "private-browsing-change-granted") {
+        if (data == "enter" || data == "exit") {
+          self._privateBrowsing.transitionMode = data;
           self.storageBusy();
         }
-      } else if (aTopic == "private-browsing-transition-complete") {
+      } else if (topic == "private-browsing-transition-complete") {
         // We use .transitionMode here, as aData is empty.
         if (self._privateBrowsing.transitionMode == "exit" &&
             self._privateBrowsing.wasInTabView)
           self.showTabView(false);
 
         self._privateBrowsing.transitionMode = "";
         self.storageReady();
       }
@@ -744,18 +750,17 @@ let UI = {
         // we don't want to go to the Tab View UI. 
         if (self._storageBusyCount)
           return;
 
         // if not closing the last tab
         if (gBrowser.tabs.length > 1) {
           // Don't return to TabView if there are any app tabs
           for (let a = 0; a < gBrowser._numPinnedTabs; a++) {
-            let theTab = gBrowser.tabs[a]; 
-            if (gBrowser._removingTabs.indexOf(theTab) == -1) 
+            if (!gBrowser.tabs[a].closing)
               return;
           }
 
           var groupItem = GroupItems.getActiveGroupItem();
 
           // 1) Only go back to the TabView tab when there you close the last
           // tab of a groupItem.
           let closingLastOfGroup = (groupItem && 
@@ -951,22 +956,21 @@ let UI = {
       var index = this._reorderTabItemsOnShow.indexOf(groupItem);
       if (index == -1)
         this._reorderTabItemsOnShow.push(groupItem);
     }
   },
   
   // ----------
   updateTabButton: function UI__updateTabButton() {
-    let groupsNumber = gWindow.document.getElementById("tabviewGroupsNumber");
     let exitButton = document.getElementById("exit-button");
     let numberOfGroups = GroupItems.groupItems.length;
 
-    groupsNumber.setAttribute("groups", numberOfGroups);
     exitButton.setAttribute("groups", numberOfGroups);
+    gTabView.updateGroupNumberBroadcaster(numberOfGroups);
   },
 
   // ----------
   // Function: getClosestTab
   // Convenience function to get the next tab closest to the entered position
   getClosestTab: function UI_getClosestTab(tabCenter) {
     let cl = null;
     let clDist;
@@ -986,30 +990,38 @@ let UI = {
   // Function: _setupBrowserKeys
   // Sets up the allowed browser keys using key elements.
   _setupBrowserKeys: function UI__setupKeyWhiteList() {
     let keys = {};
 
     [
 #ifdef XP_UNIX
       "quitApplication",
+#else
+      "redo",
 #endif
 #ifdef XP_MACOSX
-      "preferencesCmdMac", "minimizeWindow",
+      "preferencesCmdMac", "minimizeWindow", "hideThisAppCmdMac",
 #endif
-      "newNavigator", "newNavigatorTab", "find"
-     ].forEach(function(key) {
+      "newNavigator", "newNavigatorTab", "undo", "cut", "copy", "paste", 
+      "selectAll", "find"
+    ].forEach(function(key) {
       let element = gWindow.document.getElementById("key_" + key);
       keys[key] = element.getAttribute("key").toLocaleLowerCase().charCodeAt(0);
     });
 
     // for key combinations with shift key, the charCode of upper case letters 
     // are different to the lower case ones so need to handle them differently.
-    ["closeWindow", "tabview", "undoCloseTab", "undoCloseWindow",
-     "privatebrowsing"].forEach(function(key) {
+    [
+#ifdef XP_UNIX
+      "redo",
+#endif
+      "closeWindow", "tabview", "undoCloseTab", "undoCloseWindow",
+      "privatebrowsing"
+    ].forEach(function(key) {
       let element = gWindow.document.getElementById("key_" + key);
       keys[key] = element.getAttribute("key").toLocaleUpperCase().charCodeAt(0);
     });
 
     delete this._browserKeys;
     this._browserKeys = keys;
   },
 
@@ -1026,54 +1038,65 @@ let UI = {
         Keys.meta = false;
     });
 
     iQ(window).keypress(function(event) {
       if (event.metaKey)
         Keys.meta = true;
 
       function processBrowserKeys(evt) {
+        // let any keys with alt to pass through
+        if (evt.altKey)
+          return;
+
 #ifdef XP_MACOSX
         if (evt.metaKey) {
 #else
         if (evt.ctrlKey) {
 #endif
           let preventDefault = true;
           if (evt.shiftKey) {
             switch (evt.charCode) {
-              case self._browserKeys.privatebrowsing:
+              case self._browserKeys.tabview:
+                self.exit();
+                break;
+#ifdef XP_UNIX
+              case self._browserKeys.redo:
+#endif
+              case self._browserKeys.closeWindow:
               case self._browserKeys.undoCloseTab:
               case self._browserKeys.undoCloseWindow:
-              case self._browserKeys.closeWindow:
+              case self._browserKeys.privatebrowsing:
                 preventDefault = false;
                 break;
-              case self._browserKeys.tabview:
-                self.exit();
-                break;
             }
           } else {
             switch (evt.charCode) {
               case self._browserKeys.find:
                 self.enableSearch();
                 break;
-              case self._browserKeys.newNavigator:
-              case self._browserKeys.newNavigatorTab:
-                preventDefault = false;
-                break;
 #ifdef XP_UNIX
               case self._browserKeys.quitApplication:
-                preventDefault = false;
-                break;
+#else
+              case self._browserKeys.redo:
 #endif
 #ifdef XP_MACOSX
               case self._browserKeys.preferencesCmdMac:
               case self._browserKeys.minimizeWindow:
+              case self._browserKeys.hideThisAppCmdMac:
+#endif
+              case self._browserKeys.newNavigator:
+              case self._browserKeys.newNavigatorTab:
+              case self._browserKeys.undo:
+              case self._browserKeys.cut:
+              case self._browserKeys.copy:
+              case self._browserKeys.paste:
+              case self._browserKeys.selectAll:
                 preventDefault = false;
                 break;
-#endif
             }
           }
           if (preventDefault) {
             evt.stopPropagation();
             evt.preventDefault();
           }
         }
       }
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -107,17 +107,17 @@ endif
                  browser_bug386835.js \
                  browser_bug405137.js \
                  browser_bug406216.js \
                  browser_bug409481.js \
                  browser_bug413915.js \
                  browser_bug416661.js \
                  browser_bug417483.js \
                  browser_bug419612.js \
-                 browser_bug420160.js \
+                 browser_identity_UI.js \
                  browser_bug422590.js \
                  browser_bug424101.js \
                  browser_bug427559.js \
                  browser_bug432599.js \
                  browser_bug435035.js \
                  browser_bug441778.js \
                  browser_popupNotification.js \
                  browser_bug455852.js \
@@ -165,17 +165,20 @@ endif
                  browser_bug596687.js \
                  browser_bug597218.js \
                  browser_bug598923.js \
                  browser_bug599325.js \
                  browser_bug609700.js \
                  browser_bug616836.js \
                  browser_bug623893.js \
                  browser_bug624734.js \
+                 browser_bug647886.js \
+                 browser_bug655584.js \
                  browser_findbarClose.js \
+                 browser_keywordBookmarklets.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_customize_popupNotification.js \
                  browser_disablechrome.js \
                  browser_discovery.js \
                  browser_duplicateIDs.js \
                  browser_gestureSupport.js \
                  browser_getshortcutoruri.js \
@@ -226,17 +229,16 @@ endif
                  browser_tabs_owner.js \
                  browser_urlHighlight.js \
                  browser_visibleFindSelection.js \
                  browser_visibleTabs.js \
                  browser_visibleTabs_contextMenu.js \
                  browser_visibleTabs_bookmarkAllPages.js \
                  browser_visibleTabs_bookmarkAllTabs.js \
                  browser_visibleTabs_tabPreview.js \
-                 browser_webdev_menu.js \
                  bug592338.html \
                  disablechrome.html \
                  discovery.html \
                  domplate_test.js \
                  moz.png \
                  test_bug435035.html \
                  test_bug462673.html \
                  page_style_sample.html \
--- a/browser/base/content/test/browser_bug517902.js
+++ b/browser/base/content/test/browser_bug517902.js
@@ -26,15 +26,15 @@ function test() {
           finish();
         });
       });
     }, true);
   }, true);
 
   content.location =
     "data:text/html," +
-    "<style type='text/css'>#test-image,#not-test-image {background-image: url('about:logo?c');}</style>" +
+    "<style type='text/css'>%23test-image,%23not-test-image {background-image: url('about:logo?c');}</style>" +
     "<img src='about:logo?b' height=300 width=350 alt=2 id='not-test-image'>" +
     "<img src='about:logo?b' height=300 width=350 alt=2>" +
     "<img src='about:logo?a' height=200 width=250>" +
     "<img src='about:logo?b' height=200 width=250 alt=1>" +
     "<img src='about:logo?b' height=100 width=150 alt=2 id='test-image'>";
 }
--- a/browser/base/content/test/browser_bug581242.js
+++ b/browser/base/content/test/browser_bug581242.js
@@ -39,14 +39,15 @@ function test() {
   let blanktab = gBrowser.addTab();
   gBrowser.selectedTab = blanktab;
   BrowserOpenAddonsMgr();
 
   is(blanktab, gBrowser.selectedTab, "Current tab should be blank tab");
   // Verify that about:addons loads
   waitForExplicitFinish();
   gBrowser.selectedBrowser.addEventListener("load", function() {
+    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     let browser = blanktab.linkedBrowser;
     is(browser.currentURI.spec, "about:addons", "about:addons should load into blank tab.");
     gBrowser.removeTab(blanktab);
     finish();
   }, true);
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug647886.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  gBrowser.selectedBrowser.addEventListener("load", function () {
+    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
+    content.history.pushState({}, "2", "2.html");
+
+    testBackButton();
+  }, true);
+
+  loadURI("http://example.com");
+}
+
+function testBackButton() {
+  var backButton = document.getElementById("back-button");
+  var rect = backButton.getBoundingClientRect();
+
+  info("waiting for the history menu to open");
+
+  backButton.addEventListener("popupshown", function (event) {
+    backButton.removeEventListener("popupshown", arguments.callee, false);
+
+    ok(true, "history menu opened");
+    event.target.hidePopup();
+    finish();
+  }, false);
+
+  EventUtils.synthesizeMouseAtCenter(backButton, {type: "mousedown"});
+  EventUtils.synthesizeMouse(backButton, rect.width / 2, rect.height, {type: "mouseup"});
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug655584.js
@@ -0,0 +1,23 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 655584 - awesomebar suggestions don't update after tab is closed
+
+function test() {
+  var tab1 = gBrowser.addTab();
+  var tab2 = gBrowser.addTab();
+
+  // When urlbar in a new tab is focused, and a tab switch occurs,
+  // the urlbar popup should be closed
+  gBrowser.selectedTab = tab2;
+  gURLBar.focus(); // focus the urlbar in the tab we will switch to
+  gBrowser.selectedTab = tab1;
+  gURLBar.openPopup();
+  gBrowser.selectedTab = tab2;
+  ok(!gURLBar.popupOpen, "urlbar focused in tab to switch to, close popup");
+  
+  // cleanup
+  gBrowser.removeCurrentTab();
+  gBrowser.removeCurrentTab();
+}
--- a/browser/base/content/test/browser_getshortcutoruri.js
+++ b/browser/base/content/test/browser_getshortcutoruri.js
@@ -6,19 +6,20 @@ function getPostDataString(aIS) {
             createInstance(Ci.nsIScriptableInputStream);
   sis.init(aIS);
   var dataLines = sis.read(aIS.available()).split("\n");
 
   // only want the last line
   return dataLines[dataLines.length-1];
 }
 
-function keywordResult(aURL, aPostData) {
+function keywordResult(aURL, aPostData, aIsUnsafe) {
   this.url = aURL;
   this.postData = aPostData;
+  this.isUnsafe = aIsUnsafe;
 }
 
 function keyWordData() {}
 keyWordData.prototype = {
   init: function(aKeyWord, aURL, aPostData, aSearchWord) {
     this.keyword = aKeyWord;
     this.uri = makeURI(aURL);
     this.postData = aPostData;
@@ -47,64 +48,72 @@ var testData = [
 
   [new bmKeywordData("bmpostget", "http://bmpostget/search1=%s", "search2=%s", "foo3"),
    new keywordResult("http://bmpostget/search1=foo3", "search2=foo3")],
 
   [new bmKeywordData("bmget-nosearch", "http://bmget-nosearch/", null, ""),
    new keywordResult("http://bmget-nosearch/", null)],
 
   [new searchKeywordData("searchget", "http://searchget/?search={searchTerms}", null, "foo4"),
-   new keywordResult("http://searchget/?search=foo4", null)],
+   new keywordResult("http://searchget/?search=foo4", null, true)],
 
   [new searchKeywordData("searchpost", "http://searchpost/", "search={searchTerms}", "foo5"),
-   new keywordResult("http://searchpost/", "search=foo5")],
+   new keywordResult("http://searchpost/", "search=foo5", true)],
 
   [new searchKeywordData("searchpostget", "http://searchpostget/?search1={searchTerms}", "search2={searchTerms}", "foo6"),
-   new keywordResult("http://searchpostget/?search1=foo6", "search2=foo6")],
+   new keywordResult("http://searchpostget/?search1=foo6", "search2=foo6", true)],
 
   // Bookmark keywords that don't take parameters should not be activated if a
   // parameter is passed (bug 420328).
   [new bmKeywordData("bmget-noparam", "http://bmget-noparam/", null, "foo7"),
-   new keywordResult(null, null)],
+   new keywordResult(null, null, true)],
   [new bmKeywordData("bmpost-noparam", "http://bmpost-noparam/", "not_a=param", "foo8"),
-   new keywordResult(null, null)],
+   new keywordResult(null, null, true)],
 
   // Test escaping (%s = escaped, %S = raw)
   // UTF-8 default
   [new bmKeywordData("bmget-escaping", "http://bmget/?esc=%s&raw=%S", null, "foé"),
    new keywordResult("http://bmget/?esc=fo%C3%A9&raw=foé", null)],
   // Explicitly-defined ISO-8859-1
   [new bmKeywordData("bmget-escaping2", "http://bmget/?esc=%s&raw=%S&mozcharset=ISO-8859-1", null, "foé"),
    new keywordResult("http://bmget/?esc=fo%E9&raw=foé", null)],
 
   // Bug 359809: Test escaping +, /, and @
   // UTF-8 default
   [new bmKeywordData("bmget-escaping", "http://bmget/?esc=%s&raw=%S", null, "+/@"),
    new keywordResult("http://bmget/?esc=%2B%2F%40&raw=+/@", null)],
   // Explicitly-defined ISO-8859-1
   [new bmKeywordData("bmget-escaping2", "http://bmget/?esc=%s&raw=%S&mozcharset=ISO-8859-1", null, "+/@"),
    new keywordResult("http://bmget/?esc=%2B%2F%40&raw=+/@", null)],
+
+  // Test using a non-bmKeywordData object, to test the behavior of
+  // getShortcutOrURI for non-keywords (setupKeywords only adds keywords for
+  // bmKeywordData objects)
+  [{keyword: "http://gavinsharp.com"},
+   new keywordResult(null, null, true)]
 ];
 
 function test() {
   setupKeywords();
 
   for each (var item in testData) {
     var [data, result] = item;
 
     var postData = {};
     var query = data.keyword;
     if (data.searchWord)
       query += " " + data.searchWord;
-    var url = getShortcutOrURI(query, postData);
+    var mayInheritPrincipal = {};
+    var url = getShortcutOrURI(query, postData, mayInheritPrincipal);
 
     // null result.url means we should expect the same query we sent in
     var expected = result.url || query;
     is(url, expected, "got correct URL for " + data.keyword);
     is(getPostDataString(postData.value), result.postData, "got correct postData for " + data.keyword);
+    is(mayInheritPrincipal.value, !result.isUnsafe, "got correct mayInheritPrincipal for " + data.keyword);
   }
 
   cleanupKeywords();
 }
 
 var gBMFolder = null;
 var gAddedEngines = [];
 function setupKeywords() {
rename from browser/base/content/test/browser_bug420160.js
rename to browser/base/content/test/browser_identity_UI.js
--- a/browser/base/content/test/browser_bug420160.js
+++ b/browser/base/content/test/browser_identity_UI.js
@@ -1,53 +1,113 @@
-var listener = {
-  testFunction: null,
-
-  handleEvent: function (e) {
-    this.testFunction();
-  }
-}
-
 /* Tests for correct behaviour of getEffectiveHost on identity handler */
 function test() {
   waitForExplicitFinish();
 
   ok(gIdentityHandler, "gIdentityHandler should exist");
 
   gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", listener, true);
-  listener.testFunction = testNormalDomain;  
-  content.location = "http://test1.example.org/";
+  gBrowser.selectedBrowser.addEventListener("load", checkResult, true);
+
+  nextTest();
 }
 
 // Greek IDN for 'example.test'.
 var idnDomain = "\u03C0\u03B1\u03C1\u03AC\u03B4\u03B5\u03B9\u03B3\u03BC\u03B1.\u03B4\u03BF\u03BA\u03B9\u03BC\u03AE";
+var tests = [
+  {
+    name: "normal domain",
+    location: "http://test1.example.org/",
+    host: "test1.example.org",
+    effectiveHost: "example.org"
+  },
+  {
+    name: "view-source",
+    location: "view-source:http://example.com/",
+    // TODO: these should not be blank, bug 646690
+    host: "",
+    effectiveHost: ""
+  },
+  {
+    name: "normal HTTPS",
+    location: "https://example.com/",
+    host: "example.com",
+    effectiveHost: "example.com",
+    isHTTPS: true
+  },
+  {
+    name: "IDN subdomain",
+    location: "http://sub1." + idnDomain + "/",
+    host: "sub1." + idnDomain,
+    effectiveHost: idnDomain
+  },
+  {
+    name: "subdomain with port",
+    location: "http://sub1.test1.example.org:8000/",
+    host: "sub1.test1.example.org:8000",
+    effectiveHost: "example.org"
+  },
+  {
+    name: "subdomain HTTPS",
+    location: "https://test1.example.com",
+    host: "test1.example.com",
+    effectiveHost: "example.com",
+    isHTTPS: true
+  },
+  {
+    name: "view-source HTTPS",
+    location: "view-source:https://example.com/",
+    // TODO: these should not be blank, bug 646690
+    host: "",
+    effectiveHost: "",
+    isHTTPS: true
+  },
+  {
+    name: "IP address",
+    location: "http://127.0.0.1:8888/",
+    host: "127.0.0.1:8888",
+    effectiveHost: "127.0.0.1"
+  },
+]
 
-function testNormalDomain() {
-  is(gIdentityHandler._lastLocation.host, 'test1.example.org', "Identity handler is getting the full location");
-  is(gIdentityHandler.getEffectiveHost(), 'example.org', "getEffectiveHost should return example.org for test1.example.org");
+let gCurrentTest, gCurrentTestIndex = -1;
+// Go through the tests in both directions, to add additional coverage for
+// transitions between different states.
+let gForward = true;
+function nextTest() {
+  if (gForward)
+    gCurrentTestIndex++;
+  else
+    gCurrentTestIndex--;
 
-  listener.testFunction = testIDNDomain;
-  content.location = "http://sub1." + idnDomain + "/";
+  if (gCurrentTestIndex == tests.length) {
+    // Went too far, reverse
+    gCurrentTestIndex--;
+    gForward = false;
+  }
+
+  if (gCurrentTestIndex == -1) {
+    gBrowser.selectedBrowser.removeEventListener("load", checkResult, true);
+    gBrowser.removeCurrentTab();
+    finish();
+    return;
+  }
+
+  gCurrentTest = tests[gCurrentTestIndex];
+  gTestDesc = "#" + gCurrentTestIndex + " (" + gCurrentTest.name + ")";
+  if (!gForward)
+    gTestDesc += " (second time)";
+  content.location = gCurrentTest.location;
 }
 
-function testIDNDomain() {
-  is(gIdentityHandler._lastLocation.host, "sub1." + idnDomain, "Identity handler is getting the full location");
-  is(gIdentityHandler.getEffectiveHost(), idnDomain, "getEffectiveHost should return the IDN base domain in UTF-8");
-
-  listener.testFunction = testNormalDomainWithPort;
-  content.location = "http://sub1.test1.example.org:8000/";
-}
+function checkResult() {
+  if (gCurrentTest.isHTTPS) {
+    // Check that the effective host is displayed in the UI
+    let label = document.getElementById("identity-icon-label");
+    is(label.value, gCurrentTest.effectiveHost, "effective host is displayed in identity icon label for test " + gTestDesc);
+  }
 
-function testNormalDomainWithPort() {
-  is(gIdentityHandler._lastLocation.host, 'sub1.test1.example.org:8000', "Identity handler is getting port information");
-  is(gIdentityHandler.getEffectiveHost(), 'example.org', "getEffectiveHost should return example.org for sub1.test1.example.org:8000");
+  // Sanity check other values, and the value of gIdentityHandler.getEffectiveHost()
+  is(gIdentityHandler._lastLocation.host, gCurrentTest.host, "host matches for test " + gTestDesc);
+  is(gIdentityHandler.getEffectiveHost(), gCurrentTest.effectiveHost, "effectiveHost matches for test " + gTestDesc);
 
-  listener.testFunction = testIPWithPort;
-  content.location = "http://127.0.0.1:8888/";
+  executeSoon(nextTest);
 }
-
-function testIPWithPort() {
-  is(gIdentityHandler.getEffectiveHost(), '127.0.0.1', "getEffectiveHost should return 127.0.0.1 for 127.0.0.1:8888");
-  gBrowser.selectedBrowser.removeEventListener("load", listener, true);
-  gBrowser.removeCurrentTab();
-  finish();
-}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_keywordBookmarklets.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  let bmFolder = Application.bookmarks.menu.addFolder("keyword-test");
+  let tab = gBrowser.selectedTab = gBrowser.addTab();
+
+  registerCleanupFunction (function () {
+    bmFolder.remove();
+    gBrowser.removeTab(tab);
+  });
+
+  let bm = bmFolder.addBookmark("bookmarklet", makeURI("javascript:1;"));
+  bm.keyword = "bm";
+
+  addPageShowListener(function () {
+    let originalPrincipal = gBrowser.contentPrincipal;
+
+    // Enter bookmarklet keyword in the URL bar
+    gURLBar.value = "bm";
+    gURLBar.focus();
+    EventUtils.synthesizeKey("VK_RETURN", {});
+
+    addPageShowListener(function () {
+      ok(gBrowser.contentPrincipal.equals(originalPrincipal), "javascript bookmarklet should inherit principal");
+      finish();
+    });
+  });
+}
+
+function addPageShowListener(func) {
+  gBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() {
+    gBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false);
+    func();
+  });
+}
--- a/browser/base/content/test/browser_locationBarExternalLoad.js
+++ b/browser/base/content/test/browser_locationBarExternalLoad.js
@@ -4,40 +4,56 @@
 function test() {
   waitForExplicitFinish();
 
   nextTest();
 }
 
 let urls = [
   "javascript:'foopy';",
-  "data:text/html,<script>document.write(document.domain);</script>"
+  "data:text/html,<body>hi"
 ];
 
+function urlEnter(url) {
+  gURLBar.value = url;
+  gURLBar.focus();
+  EventUtils.synthesizeKey("VK_RETURN", {});
+}
+
+function urlClick(url) {
+  gURLBar.value = url;
+  gURLBar.focus();
+  let goButton = document.getElementById("urlbar-go-button");
+  EventUtils.synthesizeMouseAtCenter(goButton, {});
+}
+
 function nextTest() {
   let url = urls.shift();
-  if (url)
-    testURL(url, nextTest);
+  if (url) {
+    testURL(url, urlEnter, function () {
+      testURL(url, urlClick, nextTest);
+    });
+  }
   else
     finish();
 }
 
-function testURL(newURL, func) {
+function testURL(url, loadFunc, endFunc) {
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   registerCleanupFunction(function () {
     gBrowser.removeTab(tab);
   });
   addPageShowListener(function () {
     let pagePrincipal = gBrowser.contentPrincipal;
-    gURLBar.value = newURL;
-    gURLBar.handleCommand();
+    loadFunc(url);
 
     addPageShowListener(function () {
-      ok(!gBrowser.contentPrincipal.equals(pagePrincipal), "load of " + newURL + " produced a page with a different principal");
-      func();
+      ok(!gBrowser.contentPrincipal.equals(pagePrincipal),
+         "load of " + url + " by " + loadFunc.name + " should produce a page with a different principal");
+      endFunc();
     });
   });
 }
 
 function addPageShowListener(func) {
   gBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() {
     gBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false);
     func();
--- a/browser/base/content/test/browser_urlHighlight.js
+++ b/browser/base/content/test/browser_urlHighlight.js
@@ -49,16 +49,19 @@ function test() {
   testVal("<http://>mozilla.org</file.ext>");
   testVal("<http://>mozilla.org</sub/file.ext>");
   testVal("<http://>mozilla.org</sub/file.ext?foo>");
   testVal("<http://>mozilla.org</sub/file.ext?foo&bar>");
   testVal("<http://>mozilla.org</sub/file.ext?foo&bar#top>");
 
   testVal("<http://sub.>mozilla.org<:666/file.ext>");
 
+  testVal("<http://>[fe80::222:19ff:fe11:8c76]</file.ext>");
+  testVal("<http://user:pass@>[fe80::222:19ff:fe11:8c76]<:666/file.ext>");
+
   testVal("mailto:admin@mozilla.org");
   testVal("gopher://mozilla.org/");
   testVal("about:config");
 
   Services.prefs.setBoolPref(prefname, false);
 
   testVal("http://mozilla.org/");
 }
deleted file mode 100644
--- a/browser/base/content/test/browser_webdev_menu.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-function menuTest()
-{
-  gBrowser.selectedBrowser.removeEventListener("load", menuTest, true);
-
-  let menuContents = [
-    "menu_pageinspect",
-    "webConsole",
-    "menu_scratchpad",
-    "menu_pageSource",
-    "javascriptConsole"
-  ];
-
-  let menu = document.getElementById("webDeveloperMenu");
-  ok(menu, "we have the menu");
-
-  let popup = menu.firstChild;
-  is(popup.id, "menuWebDeveloperPopup", "menu first child is menuWebDeveloperPopup");
-
-  is(popup.childNodes.length, menuContents.length, "popup childNodes.length matches");
-
-  for(let a = 0; a < popup.children.length; a++) {
-    isnot(menuContents.indexOf(popup.children[a].id), -1, "menuitem " + popup.children[a].id + " in popup");
-  };
-
-  gBrowser.removeCurrentTab();
-  finish();  
-}
-
-function test()
-{
-  waitForExplicitFinish();
-
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", menuTest, true);
-
-  content.location = "data:text/html,<title>Web Developer Menu Test</title>" +
-    "<p>testing the Web Developer Menu";
-}
-
--- a/browser/base/content/test/browser_zbug569342.js
+++ b/browser/base/content/test/browser_zbug569342.js
@@ -13,51 +13,51 @@ function load(url, cb) {
     cb();
   }, true);
 }
 
 function test() {
   waitForExplicitFinish();
 
   ok(gFindBar.hidden, "Find bar should not be visible");
-
-  run_test_1();
+  nextTest();
 }
 
-function run_test_1() {
-  load("about:config", function() {
+let urls = [
+  "about:config",
+  "about:addons",
+  "about:permissions"
+];
+
+function nextTest() {
+  let url = urls.shift();
+  if (url) {
+    testFindDisabled(url, nextTest);
+  } else {
+    // Make sure the find bar is re-enabled after disabled page is closed.
+    testFindEnabled("about:blank", finish);
+  }
+}
+
+function testFindDisabled(url, cb) {
+  load(url, function() {
     ok(gFindBar.hidden, "Find bar should not be visible");
     EventUtils.synthesizeKey("/", {}, gTab.linkedBrowser.contentWindow);
     ok(gFindBar.hidden, "Find bar should not be visible");
     EventUtils.synthesizeKey("f", { accelKey: true });
     ok(gFindBar.hidden, "Find bar should not be visible");
     ok(document.getElementById("cmd_find").getAttribute("disabled"),
        "Find command should be disabled");
 
     gBrowser.removeTab(gTab);
-    run_test_2();
+    cb();
   });
 }
 
-function run_test_2() {
-  load("about:addons", function() {
-    ok(gFindBar.hidden, "Find bar should not be visible");
-    EventUtils.synthesizeKey("/", {}, gTab.linkedBrowser.contentWindow);
-    ok(gFindBar.hidden, "Find bar should not be visible");
-    EventUtils.synthesizeKey("f", { accelKey: true });
-    ok(gFindBar.hidden, "Find bar should not be visible");
-    ok(document.getElementById("cmd_find").getAttribute("disabled"),
-       "Find command should be disabled");
-
-    gBrowser.removeTab(gTab);
-    run_test_3();
-  });
-}
-
-function run_test_3() {
-  load("about:blank", function() {
+function testFindEnabled(url, cb) {
+  load(url, function() {
     ok(!document.getElementById("cmd_find").getAttribute("disabled"),
        "Find command should not be disabled");
 
     gBrowser.removeTab(gTab);
-    finish();
+    cb();
   });
-}
\ No newline at end of file
+}
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -108,18 +108,20 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug624953.js \
                  browser_tabview_bug625195.js \
                  browser_tabview_bug625269.js \
                  browser_tabview_bug625424.js \
                  browser_tabview_bug625666.js \
                  browser_tabview_bug626368.js \
                  browser_tabview_bug626525.js \
                  browser_tabview_bug626791.js \
+                 browser_tabview_bug627239.js \
                  browser_tabview_bug627288.js \
                  browser_tabview_bug627736.js \
+                 browser_tabview_bug628061.js \
                  browser_tabview_bug628165.js \
                  browser_tabview_bug628270.js \
                  browser_tabview_bug629189.js \
                  browser_tabview_bug629195.js \
                  browser_tabview_bug630102.js \
                  browser_tabview_bug630157.js \
                  browser_tabview_bug631662.js \
                  browser_tabview_bug631752.js \
--- a/browser/base/content/test/tabview/browser_tabview_bug594958.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug594958.js
@@ -10,22 +10,22 @@ function test() {
   }
 
   let finishTest = function () {
     win.close();
     finish();
   }
 
   // very long page that produces black bars at the right
-  let html1 = '<html><body style="background-color: #00f;">' +
-              '<div style="background: #fff; width: 95%; height: 10000px; ' +
+  let html1 = '<html><body style="background-color: %2300f;">' +
+              '<div style="background: %23fff; width: 95%; height: 10000px; ' +
               ' margin: 0 auto;"></div></body></html>';
 
   // very short page that produces black bars at the bottom
-  let html2 = '<html><body style="background-color: #00f;"></body></html>';
+  let html2 = '<html><body style="background-color: %2300f;"></body></html>';
 
   let tests = [{
     url: 'data:text/html,' + html1,
     colors: [
       {right: [255, 255, 255], bottom: [255, 255, 255]},
       {right: [255, 255, 255], bottom: [255, 255, 255]},
       {right: [255, 255, 255], bottom: [255, 255, 255]}
     ]
--- a/browser/base/content/test/tabview/browser_tabview_bug600645.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug600645.js
@@ -1,11 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+const fi = Cc["@mozilla.org/browser/favicon-service;1"].
+           getService(Ci.nsIFaviconService);
+
 let newTab;
 
 function test() {
   waitForExplicitFinish();
 
   newTab = gBrowser.addTab();
   gBrowser.pinTab(newTab);
 
@@ -22,27 +25,27 @@ function onTabViewWindowLoaded() {
 
   let groupItem = contentWindow.GroupItems.groupItems[0];
   let icon = contentWindow.iQ(".appTabIcon", groupItem.$appTabTray)[0];
   let $icon = contentWindow.iQ(icon);
 
   is($icon.data("xulTab"), newTab, 
      "The app tab icon has the right tab reference")
   // check to see whether it's showing the default one or not.
-  is($icon.attr("src"), contentWindow.Utils.defaultFaviconURL, 
+  is($icon.attr("src"), fi.defaultFavicon.spec,
      "The icon is showing the default fav icon for blank tab");
 
   let errorHandler = function(event) {
     newTab.removeEventListener("error", errorHandler, false);
 
     // since the browser code and test code are invoked when an error event is 
     // fired, a delay is used here to avoid the test code run before the browser 
     // code.
     executeSoon(function() {
-      is($icon.attr("src"), contentWindow.Utils.defaultFaviconURL, 
+      is($icon.attr("src"), fi.defaultFavicon.spec,
          "The icon is showing the default fav icon");
 
       // clean up
       gBrowser.removeTab(newTab);
       let endGame = function() {
         window.removeEventListener("tabviewhidden", endGame, false);
 
         ok(!TabView.isVisible(), "Tab View is hidden");
--- a/browser/base/content/test/tabview/browser_tabview_bug604699.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug604699.js
@@ -1,61 +1,62 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
-  let url = "http://non.existant/url";
+  let url = "http://www.example.com/";
   let cw;
+  let tab = gBrowser.tabs[0];
 
   let finishTest = function () {
     is(1, gBrowser.tabs.length, "there is one tab, only");
     ok(!TabView.isVisible(), "tabview is not visible");
     finish();
   }
 
   waitForExplicitFinish();
 
   let testErroneousLoading = function () {
-    cw.Storage.loadThumbnail(url, function (status, data) {
+    cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, data) {
       ok(!status, "thumbnail entry failed to load");
       is(null, data, "no thumbnail data received");
       next();
     });
   }
 
   let testAsynchronousSaving = function () {
     let saved = false;
     let data = "thumbnail-data-asynchronous";
 
-    cw.Storage.saveThumbnail(url, data, function (status) {
+    cw.ThumbnailStorage.saveThumbnail(tab, data, function (status) {
       ok(status, "thumbnail entry was saved");
       ok(saved, "thumbnail was saved asynchronously");
 
-      cw.Storage.loadThumbnail(url, function (status, imageData) {
+      cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, imageData) {
         ok(status, "thumbnail entry was loaded");
         is(imageData, data, "valid thumbnail data received");
         next();
       });
     });
 
     saved = true;
   }
 
   let testSynchronousSaving = function () {
     let saved = false;
     let data = "thumbnail-data-synchronous";
 
     cw.UI.isDOMWindowClosing = true;
     registerCleanupFunction(function () cw.UI.isDOMWindowClosing = false);
 
-    cw.Storage.saveThumbnail(url, data, function (status) {
+    cw.ThumbnailStorage.saveThumbnail(tab, data, function (status) {
       ok(status, "thumbnail entry was saved");
       ok(!saved, "thumbnail was saved synchronously");
 
-      cw.Storage.loadThumbnail(url, function (status, imageData) {
+      cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, imageData) {
         ok(status, "thumbnail entry was loaded");
         is(imageData, data, "valid thumbnail data received");
 
         cw.UI.isDOMWindowClosing = false;
         next();
       });
     });
 
@@ -67,15 +68,18 @@ function test() {
   let next = function () {
     let test = tests.shift();
     if (test)
       test();
     else
       hideTabView(finishTest);
   }
 
-  showTabView(function () {
-    registerCleanupFunction(function () TabView.hide());
-    cw = TabView.getContentWindow();
+  tab.linkedBrowser.loadURI(url);
+  afterAllTabsLoaded(function() {
+    showTabView(function () {
+      registerCleanupFunction(function () TabView.hide());
+      cw = TabView.getContentWindow();
 
-    next();
+      next();
+    });
   });
 }
--- a/browser/base/content/test/tabview/browser_tabview_bug624265.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug624265.js
@@ -14,25 +14,16 @@ function test() {
   let assertOneSingleGroupItem = function () {
     is(getContentWindow().GroupItems.groupItems.length, 1, 'There is one single groupItem');
   }
 
   let assertNumberOfVisibleTabs = function (numTabs) {
     is(gBrowser.visibleTabs.length, numTabs, 'There should be ' + numTabs + ' visible tabs');
   }
 
-  let restoreTab = function (callback) {
-    let tab = undoCloseTab(0);
-    
-    tab._tabViewTabItem.addSubscriber(tab, 'reconnected', function () {
-      tab._tabViewTabItem.removeSubscriber(tab, 'reconnected');
-      afterAllTabsLoaded(callback);
-    });
-  }
-
   let next = function () {
     while (gBrowser.tabs.length-1)
       gBrowser.removeTab(gBrowser.tabs[1]);
 
     hideTabView(function () {
       let callback = tests.shift();
 
       if (!callback)
@@ -81,17 +72,17 @@ function test() {
   }
 
   // ----------
   // [623792] duplicating tabs via middle click on forward/back buttons
   let testBackForwardDuplicateTab = function () {
     let tab = gBrowser.loadOneTab('http://mochi.test:8888/#1', {inBackground: true});
     gBrowser.selectedTab = tab;
 
-    let continueTest = function () {
+    afterAllTabsLoaded(function () {
       tab.linkedBrowser.loadURI('http://mochi.test:8888/#2');
 
       afterAllTabsLoaded(function () {
         ok(gBrowser.canGoBack, 'browser can go back in history');
         BrowserBack({button: 1});
 
         afterAllTabsLoaded(function () {
           assertNumberOfVisibleTabs(3);
@@ -101,23 +92,17 @@ function test() {
 
           afterAllTabsLoaded(function () {
             assertNumberOfVisibleTabs(4);
             assertOneSingleGroupItem();
             next();
           });
         });
       });
-    }
-
-    // The executeSoon() call is really needed here because there's probably
-    // some callback waiting to be fired after gBrowser.loadOneTab(). After
-    // that the browser is in a state where loadURI() will create a new entry
-    // in the session history (that is vital for back/forward functionality).
-    afterAllTabsLoaded(function () executeSoon(continueTest));
+    });
   }
 
   // ----------
   // [624102] check state after return from private browsing
   let testPrivateBrowsing = function () {
     gBrowser.loadOneTab('http://mochi.test:8888/#1', {inBackground: true});
     gBrowser.loadOneTab('http://mochi.test:8888/#2', {inBackground: true});
 
@@ -151,50 +136,35 @@ function test() {
   // tests for #624102
   tests.push(testPrivateBrowsing);
 
   loadTabView(next);
 }
 
 // ----------
 function loadTabView(callback) {
-  window.addEventListener('tabviewshown', function () {
-    window.removeEventListener('tabviewshown', arguments.callee, false);
-
-    hideTabView(function () {
-      window.removeEventListener('tabviewhidden', arguments.callee, false);
-      callback();
-    });
-  }, false);
-
-  TabView.show();
-}
-
-// ----------
-function hideTabView(callback) {
-  if (!TabView.isVisible())
-    return callback();
-
-  window.addEventListener('tabviewhidden', function () {
-    window.removeEventListener('tabviewhidden', arguments.callee, false);
-    callback();
-  }, false);
-
-  TabView.hide();
+  showTabView(function () {
+    hideTabView(callback);
+  });
 }
 
 // ----------
 function enterAndLeavePrivateBrowsing(callback) {
+  togglePrivateBrowsing(function () {
+    togglePrivateBrowsing(callback);
+  });
+}
+
+// ----------
+function togglePrivateBrowsing(callback) {
+  let topic = "private-browsing-transition-complete";
+
   function pbObserver(aSubject, aTopic, aData) {
-    if (aTopic != "private-browsing-transition-complete")
+    if (aTopic != topic)
       return;
 
-    if (pb.privateBrowsingEnabled)
-      pb.privateBrowsingEnabled = false;
-    else {
-      Services.obs.removeObserver(pbObserver, "private-browsing-transition-complete");
-      afterAllTabsLoaded(function () executeSoon(callback));
-    }
+    Services.obs.removeObserver(pbObserver, topic, false);
+    afterAllTabsLoaded(callback);
   }
 
-  Services.obs.addObserver(pbObserver, "private-browsing-transition-complete", false);
-  pb.privateBrowsingEnabled = true;
+  Services.obs.addObserver(pbObserver, topic, false);
+  pb.privateBrowsingEnabled = !pb.privateBrowsingEnabled;
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug627239.js
@@ -0,0 +1,156 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+let contentWindow;
+let enablePersistentHttpsCaching;
+let newTab;
+
+function test() {
+  waitForExplicitFinish();
+
+  newTab = gBrowser.addTab();
+
+  HttpRequestObserver.register();
+
+  registerCleanupFunction(function () {
+    HttpRequestObserver.unregister();
+    if (gBrowser.tabs[1])
+      gBrowser.removeTab(gBrowser.tabs[1]);
+    hideTabView(function () {});
+
+    contentWindow.ThumbnailStorage.enablePersistentHttpsCaching =
+        enablePersistentHttpsCaching;
+  });
+
+  showTabView(function() {
+    contentWindow = TabView.getContentWindow();
+    test1();
+  });
+}
+
+
+function test1() {
+  // page with cache-control: no-store, should not save thumbnail
+  HttpRequestObserver.cacheControlValue = "no-store";
+  newTab.linkedBrowser.loadURI("http://www.example.com/browser/browser/base/content/test/tabview/dummy_page.html");
+
+  afterAllTabsLoaded(function() {
+    let tabItem = newTab._tabViewTabItem;
+
+    ok(!contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab), 
+       "Should not save the thumbnail for tab");
+
+    tabItem.addSubscriber(tabItem, "deniedToCacheImageData", function() {
+      tabItem.removeSubscriber(tabItem, "deniedToCacheImageData");
+      test2();
+    });
+    tabItem.save(true);
+    HttpRequestObserver.cacheControlValue = null;
+  });
+}
+
+function test2() {
+  // page with cache-control: private, should save thumbnail
+  HttpRequestObserver.cacheControlValue = "private";
+
+  newTab.linkedBrowser.loadURI("http://www.example.com/");
+  afterAllTabsLoaded(function() {
+    let tabItem = newTab._tabViewTabItem;
+
+    ok(contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab), 
+       "Should save the thumbnail for tab");
+
+    tabItem.addSubscriber(tabItem, "savedCachedImageData", function() {
+      tabItem.removeSubscriber(tabItem, "savedCachedImageData");
+      test3();
+    });
+    tabItem.save(true);
+  });
+}
+
+function test3() {
+  // page with cache-control: private with https caching enabled, should save thumbnail
+  HttpRequestObserver.cacheControlValue = "private";
+
+  enablePersistentHttpsCaching =
+    contentWindow.ThumbnailStorage.enablePersistentHttpsCaching;
+  contentWindow.ThumbnailStorage.enablePersistentHttpsCaching = true;
+
+  newTab.linkedBrowser.loadURI("https://example.com/browser/browser/base/content/test/tabview/dummy_page.html");
+  afterAllTabsLoaded(function() {
+    let tabItem = newTab._tabViewTabItem;
+
+    ok(contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab),
+       "Should save the thumbnail for tab");
+
+    tabItem.addSubscriber(tabItem, "savedCachedImageData", function() {
+      tabItem.removeSubscriber(tabItem, "savedCachedImageData");
+
+      test4();
+    });
+    tabItem.save(true);
+  });
+}
+
+function test4() {
+  // page with cache-control: public with https caching disabled, should save thumbnail
+  HttpRequestObserver.cacheControlValue = "public";
+
+  contentWindow.ThumbnailStorage.enablePersistentHttpsCaching = false;
+
+  newTab.linkedBrowser.loadURI("https://example.com/browser/browser/base/content/test/tabview/");
+  afterAllTabsLoaded(function() {
+    let tabItem = newTab._tabViewTabItem;
+
+    ok(contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab),
+       "Should save the thumbnail for tab");
+
+    tabItem.addSubscriber(tabItem, "savedCachedImageData", function() {
+      tabItem.removeSubscriber(tabItem, "savedCachedImageData");
+
+      test5();
+    });
+    tabItem.save(true);
+  });
+}
+
+function test5() {
+  // page with cache-control: private with https caching disabled, should not save thumbnail
+  HttpRequestObserver.cacheControlValue = "private";
+ 
+  newTab.linkedBrowser.loadURI("https://example.com/");
+  afterAllTabsLoaded(function() {
+    let tabItem = newTab._tabViewTabItem;
+
+    ok(!contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab),
+       "Should not the thumbnail for tab");
+
+    tabItem.addSubscriber(tabItem, "deniedToCacheImageData", function() {
+      tabItem.removeSubscriber(tabItem, "deniedToCacheImageData");
+
+      hideTabView(function () {
+        gBrowser.removeTab(gBrowser.tabs[1]);
+        finish();
+      });
+    });
+    tabItem.save(true);
+  });
+}
+
+let HttpRequestObserver = {
+  cacheControlValue: null,
+
+  observe: function(subject, topic, data) {
+    if (topic == "http-on-examine-response" && this.cacheControlValue) {
+      let httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
+      httpChannel.setResponseHeader("Cache-Control", this.cacheControlValue, false);
+    }
+  },
+
+  register: function() {
+    Services.obs.addObserver(this, "http-on-examine-response", false);
+  },
+
+  unregister: function() {
+    Services.obs.removeObserver(this, "http-on-examine-response");
+  }
+};
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug628061.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+
+let state = {
+  windows: [{
+    tabs: [{
+      entries: [{ url: "about:blank" }],
+      hidden: true,
+      extData: {"tabview-tab": '{"url":"about:blank","groupID":1,"bounds":{"left":20,"top":20,"width":20,"height":20}}'}
+    },{
+      entries: [{ url: "about:blank" }],
+      hidden: false,
+      extData: {"tabview-tab": '{"url":"about:blank","groupID":2,"bounds":{"left":20,"top":20,"width":20,"height":20}}'},
+    }],
+    selected: 2,
+    extData: {
+      "tabview-groups": '{"nextID":3,"activeGroupId":2, "totalNumber":2}',
+      "tabview-group":
+        '{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},"id":1},' +
+        '"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},"id":2}}'
+    }
+  }]
+};
+
+function test() {
+  waitForExplicitFinish();
+
+  newWindowWithState(state, function(win) {
+    registerCleanupFunction(function() win.close());
+
+    is(win.document.getElementById("tabviewGroupsNumber").getAttribute("groups"), 
+       "2", "There are two groups");
+    waitForFocus(finish);
+  });
+}
--- a/browser/base/content/test/tabview/browser_tabview_startup_transitions.js
+++ b/browser/base/content/test/tabview/browser_tabview_startup_transitions.js
@@ -2,55 +2,53 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 var prefsBranch = Cc["@mozilla.org/preferences-service;1"].
                   getService(Ci.nsIPrefService).
                   getBranch("browser.panorama.");
 
 function animateZoom() prefsBranch.getBoolPref("animate_zoom");
 
-function registerCleanupFunction() {
-  prefsBranch.setUserPref("animate_zoom", true);
-}
-
 function test() {
   waitForExplicitFinish();
   
   let charsetArg = "charset=" + window.content.document.characterSet;
   let win = window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no",
                               "about:blank", charsetArg, null, null, true);
-  
+
+  registerCleanupFunction(function() {
+    prefsBranch.setBoolPref("animate_zoom", true);
+    win.close();
+  });
+
   ok(animateZoom(), "By default, we animate on zoom.");
   prefsBranch.setBoolPref("animate_zoom", false);
   ok(!animateZoom(), "animate_zoom = false");
   
   let onLoad = function() {
     win.removeEventListener("load", onLoad, false);
 
     // a few shared references
     let tabViewWindow = null;
     let transitioned = 0;
 
-    let onShown = function() {
-      win.removeEventListener("tabviewshown", onShown, false);
-
-      ok(!transitioned, "There should be no transitions");
-      win.close();
-
-      finish();
-    };
-
     let initCallback = function() {
       tabViewWindow = win.TabView._window;
       function onTransitionEnd(event) {
         transitioned++;
-        tabViewWindow.Utils.log(transitioned);
+        info(transitioned);
       }
       tabViewWindow.document.addEventListener("transitionend", onTransitionEnd, false);
 
-      win.TabView.show();
+      showTabView(function() {
+        ok(!transitioned, "There should be no transitions");
+
+        tabViewWindow.document.removeEventListener(
+          "transitionend", onTransitionEnd, false);
+
+        finish();
+      }, win);
     };
 
-    win.addEventListener("tabviewshown", onShown, false);
     win.TabView._initFrame(initCallback);
   }
   win.addEventListener("load", onLoad, false);
 }
--- a/browser/base/content/test/tabview/browser_tabview_undo_group.js
+++ b/browser/base/content/test/tabview/browser_tabview_undo_group.js
@@ -26,17 +26,19 @@ function onTabViewWindowLoaded() {
     // show tab view
     TabView.toggle();
   };
   let onTabViewShown = function() {
     window.removeEventListener("tabviewshown", onTabViewShown, false);
 
     is(groupItem.getChildren().length, 1, "The new group has a tab item");
     // start the tests
-    testUndoGroup(contentWindow, groupItem);
+    waitForFocus(function() {
+      testUndoGroup(contentWindow, groupItem);
+    }, contentWindow);
   };
   window.addEventListener("tabviewhidden", onTabViewHidden, false);
   window.addEventListener("tabviewshown", onTabViewShown, false);
 
   // click on the + button
   let newTabButton = groupItem.container.getElementsByClassName("newTabButton");
   ok(newTabButton[0], "New tab button exists");
 
@@ -75,17 +77,17 @@ function testUndoGroup(contentWindow, gr
     is(theGroupItem.container.style.display, "", "The group element is visible");
     ok(!theGroupItem.$undoContainer, "Undo container is not avaliable");
     
     // start the next test
     testCloseUndoGroup(contentWindow, groupItem);
   });
 
   let closeButton = groupItem.container.getElementsByClassName("close");
-  ok(closeButton, "Group item close button exists");
+  ok(closeButton[0], "Group item close button exists");
   EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
 }
 
 function testCloseUndoGroup(contentWindow, groupItem) {
   groupItem.addSubscriber(groupItem, "groupHidden", function() {
     groupItem.removeSubscriber(groupItem, "groupHidden");
 
     // check the data of the group
@@ -124,11 +126,11 @@ function testCloseUndoGroup(contentWindo
     let tabItems = contentWindow.TabItems.getItems();
     ok(tabItems[0], "A tab item exists");
     contentWindow.UI.setActive(tabItems[0]);
 
     TabView.toggle();
   });
 
   let closeButton = groupItem.container.getElementsByClassName("close");
-  ok(closeButton, "Group item close button exists");
+  ok(closeButton[0], "Group item close button exists");
   EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
 }
--- a/browser/base/content/test/tabview/head.js
+++ b/browser/base/content/test/tabview/head.js
@@ -100,17 +100,17 @@ function afterAllTabsLoaded(callback, wi
   let stillToLoad = 0;
   let restoreHiddenTabs = Services.prefs.getBoolPref(
                           "browser.sessionstore.restore_hidden_tabs");
 
   function onLoad() {
     this.removeEventListener("load", onLoad, true);
     stillToLoad--;
     if (!stillToLoad)
-      callback();
+      executeSoon(callback);
   }
 
   for (let a = 0; a < win.gBrowser.tabs.length; a++) {
     let tab = win.gBrowser.tabs[a];
     let browser = tab.linkedBrowser;
 
     let isRestorable = !(tab.hidden && !restoreHiddenTabs &&
                          browser.__SS_restoreState &&
@@ -296,8 +296,26 @@ function newWindowWithState(state, callb
   whenWindowLoaded(win, function () {
     ss.setWindowState(win, JSON.stringify(state), true);
   });
 
   whenWindowStateReady(win, function () {
     afterAllTabsLoaded(function () callback(win), win);
   });
 }
+
+// ----------
+function restoreTab(callback, index, win) {
+  win = win || window;
+
+  let tab = win.undoCloseTab(index || 0);
+  let tabItem = tab._tabViewTabItem;
+
+  if (tabItem._reconnected) {
+    afterAllTabsLoaded(callback, win);
+    return;
+  }
+
+  tab._tabViewTabItem.addSubscriber(tab, "reconnected", function onReconnected() {
+    tab._tabViewTabItem.removeSubscriber(tab, "reconnected");
+    afterAllTabsLoaded(callback, win);
+  });
+}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -187,17 +187,17 @@
             return;
 
           let controller = this.editor.selectionController;
           let selection = controller.getSelection(controller.SELECTION_URLSECONDARY);
           selection.removeAllRanges();
 
           let textNode = this.editor.rootElement.firstChild;
           let value = textNode.textContent;
-          let matchedURL = value.match(/^((?:http|https|ftp):\/\/(?:[^\/]+@)?)([^\/:]+)/);
+          let matchedURL = value.match(/^((?:http|https|ftp):\/\/(?:[^\/]+@)?)(.+?)(?::\d+)?(?:\/|$)/);
           if (!matchedURL)
             return;
 
           let [, preDomain, domain] = matchedURL;
           let baseDomain = domain;
           try {
             baseDomain = Services.eTLD.getBaseDomainFromHost(domain);
           } catch (e) {}
@@ -255,16 +255,17 @@
 
       <method name="handleCommand">
         <parameter name="aTriggeringEvent"/>
         <body><![CDATA[
           if (aTriggeringEvent instanceof MouseEvent && aTriggeringEvent.button == 2)
             return; // Do nothing for right clicks
 
           var url = this.value;
+          var mayInheritPrincipal = false;
           var postData = null;
 
           var action = this._parseActionUrl(url);
           if (action) {
             url = action.param;
             if (this.hasAttribute("actiontype")) {
               if (action.type == "switchtab") {
                 this.handleRevert();
@@ -272,73 +273,82 @@
                 if (switchToTabHavingURI(url) &&
                     isTabEmpty(prevTab))
                   gBrowser.removeTab(prevTab);
               }
               return;
             }
           }
           else {
-            [url, postData] = this._canonizeURL(aTriggeringEvent);
+            [url, postData, mayInheritPrincipal] = this._canonizeURL(aTriggeringEvent);
             if (!url)
               return;
           }
 
           this.value = url;
           gBrowser.userTypedValue = url;
           try {
             addToUrlbarHistory(url);
           } catch (ex) {
             // Things may go wrong when adding url to session history,
             // but don't let that interfere with the loading of the url.
             Cu.reportError(ex);
           }
 
+          function loadCurrent() {
+            let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
+            // Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from
+            // inheriting the currently loaded document's principal, unless this
+            // URL is marked as safe to inherit (e.g. came from a bookmark
+            // keyword).
+            if (!mayInheritPrincipal)
+              flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
+            gBrowser.loadURIWithFlags(url, flags, null, null, postData);
+          }
+
           if (aTriggeringEvent instanceof MouseEvent) {
             // We have a mouse event (from the go button), so use the standard
             // UI link behaviors
             let where = whereToOpenLink(aTriggeringEvent, false, false);
-            if (where != "current") {
+            if (where == "current") {
+              loadCurrent();
+            } else {
               this.handleRevert();
               content.focus();
+              openUILinkIn(url, where,
+                           { allowThirdPartyFixup: true, postData: postData });
             }
-            openUILinkIn(url, where,
-                        { allowThirdPartyFixup: true, postData: postData });
             return;
           }
 
           if (aTriggeringEvent &&
               aTriggeringEvent.altKey &&
               !isTabEmpty(gBrowser.selectedTab)) {
             this.handleRevert();
             content.focus();
             gBrowser.loadOneTab(url, {
                                 postData: postData,
                                 inBackground: false,
                                 allowThirdPartyFixup: true});
             aTriggeringEvent.preventDefault();
             aTriggeringEvent.stopPropagation();
           } else {
-            // Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from
-            // inheriting the currently loaded document's principal.
-            let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
-                        Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
-            gBrowser.loadURIWithFlags(url, flags, null, null, postData);
+            loadCurrent();
           }
 
           gBrowser.selectedBrowser.focus();
         ]]></body>
       </method>
 
       <method name="_canonizeURL">
         <parameter name="aTriggeringEvent"/>
         <body><![CDATA[
           var url = this.value;
           if (!url)
-            return ["", null];
+            return ["", null, false];
 
           // Only add the suffix when the URL bar value isn't already "URL-like",
           // and only if we get a keyboard event, to match user expectations.
           if (!/^\s*(www|https?)\b|\/\s*$/i.test(url) &&
               (aTriggeringEvent instanceof KeyEvent)) {
 #ifdef XP_MACOSX
             let accel = aTriggeringEvent.metaKey;
 #else
@@ -391,19 +401,20 @@
               } else
                 url = url + (existingSuffix == -1 ? suffix : "/");
 
               url = "http://www." + url;
             }
           }
 
           var postData = {};
-          url = getShortcutOrURI(url, postData);
+          var mayInheritPrincipal = { value: false };
+          url = getShortcutOrURI(url, postData, mayInheritPrincipal);
 
-          return [url, postData.value];
+          return [url, postData.value, mayInheritPrincipal.value];
         ]]></body>
       </method>
 
       <field name="_contentIsCropped">false</field>
 
       <method name="_initURLTooltip">
         <body><![CDATA[
           if (this.focused || !this._contentIsCropped)
@@ -896,17 +907,17 @@
                             label="&closeNotificationItem.label;"
                             xbl:inherits="oncommand=closeitemcommand"/>
             </xul:menupopup>
           </xul:button>
         </xul:hbox>
       </xul:vbox>
       <xul:vbox pack="start">
         <xul:toolbarbutton anonid="closebutton"
-                           class="messageCloseButton popup-notification-closebutton"
+                           class="messageCloseButton popup-notification-closebutton tabbable"
                            xbl:inherits="oncommand=closebuttoncommand"
                            tooltiptext="&closeNotification.tooltip;"/>
       </xul:vbox>
     </content>
     <implementation>  
       <constructor><![CDATA[
         let link = document.getAnonymousElementByAttribute(this, "anonid", "learnmore");
         link.value = gNavigatorBundle.getString("geolocation.learnMore");
@@ -943,17 +954,17 @@
                             label="&closeNotificationItem.label;"
                             xbl:inherits="oncommand=closeitemcommand"/>
             </xul:menupopup>
           </xul:button>
         </xul:hbox>
       </xul:vbox>
       <xul:vbox pack="start">
         <xul:toolbarbutton anonid="closebutton"
-                           class="messageCloseButton popup-notification-closebutton"
+                           class="messageCloseButton popup-notification-closebutton tabbable"
                            xbl:inherits="oncommand=closebuttoncommand"
                            tooltiptext="&closeNotification.tooltip;"/>
       </xul:vbox>
     </content>
     <implementation>
       <constructor><![CDATA[
         this.cancelbtn.setAttribute("tooltiptext", gNavigatorBundle.getString("addonDownloadCancelTooltip"));
 
@@ -1266,9 +1277,136 @@
         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>
     </implementation>
   </binding>
 
+ <binding id="promobox">
+    <content>
+      <xul:hbox class="panel-promo-box" align="start" flex="1">
+        <xul:hbox align="center" flex="1">
+          <xul:image class="panel-promo-icon"/>
+          <xul:description anonid="promo-message" class="panel-promo-message" flex="1">
+            placeholder <xul:description anonid="promo-link" class="plain text-link inline-link"/>
+          </xul:description>
+        </xul:hbox>
+        <xul:toolbarbutton class="panel-promo-closebutton"
+                           oncommand="document.getBindingParent(this).onCloseButtonCommand();"
+                           tooltiptext="&closeNotification.tooltip;"/>
+      </xul:hbox>
+    </content>
+
+    <implementation implements="nsIDOMEventListener">
+      <constructor><![CDATA[
+        this._panel.addEventListener("popupshowing", this, false);
+      ]]></constructor>
+
+      <destructor><![CDATA[
+        this._panel.removeEventListener("popupshowing", this, false);
+      ]]></destructor>
+
+      <field name="_panel" readonly="true"><![CDATA[
+        let node = this.parentNode;
+        while(node && node.localName != "panel") {
+          node = node.parentNode;
+        }
+        node;
+      ]]></field>
+      <field name="_promomessage" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "promo-message");
+      </field>
+      <field name="_promolink" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "promo-link");
+      </field>
+      <field name="_brandBundle" readonly="true">
+        Services.strings.createBundle("chrome://branding/locale/brand.properties");
+      </field>
+      <property name="_viewsLeft">
+        <getter><![CDATA[
+          try {
+            return Services.prefs.getIntPref("browser.syncPromoViewsLeft");
+          } catch(ex) {}
+          return 5;
+        ]]></getter>
+        <setter><![CDATA[
+          Services.prefs.setIntPref("browser.syncPromoViewsLeft", val);
+          return val;
+        ]]></setter>
+      </property>
+      <property name="_notificationType">
+        <getter><![CDATA[
+          // Use the popupid attribute to identify the notification type,
+          // otherwise just rely on the panel id for common arrowpanels.
+          let type = this._panel.firstChild.getAttribute("popupid") ||
+                     this._panel.id;
+          if (/^password-/.test(type))
+            return "passwords";
+          if (type == "editBookmarkPanel")
+            return "bookmarks";
+          return null;
+        ]]></getter>
+      </property>
+      <property name="_notificationMessage">
+        <getter><![CDATA[
+          return gNavigatorBundle.getFormattedString(
+            "syncPromoNotification." + this._notificationType + ".label",
+            [this._brandBundle.GetStringFromName("syncBrandShortName")]
+          );
+        ]]></getter>
+      </property>
+      <method name="onCloseButtonCommand">
+        <body><![CDATA[
+          this._viewsLeft = 0;
+          this.hidden = true;
+        ]]></body>
+      </method>
+      <method name="handleEvent">
+        <parameter name="event"/>
+        <body><![CDATA[
+          if (event.type != "popupshowing" || event.target != this._panel)
+            return;
+
+          // A previous notification may have unhidden this.
+          this.hidden = true;
+
+          // Only handle supported notification panels.
+          if (!this._notificationType) {
+            return;
+          }
+
+          let viewsLeft = this._viewsLeft;
+          if (viewsLeft) {
+            if (Services.prefs.prefHasUserValue("services.sync.username")) {
+              // If the user has already setup Sync, don't show the notification.
+              this._viewsLeft = 0;
+              // Be sure to hide the panel, in case it was visible and the user
+              // decided to setup Sync after noticing it.
+              viewsLeft = 0;
+              // The panel is still hidden, just bail out.
+              return;
+            }
+            else {
+              this._viewsLeft = viewsLeft - 1;
+            }
+
+            this._promolink.setAttribute("href", "https://services.mozilla.com/sync/");
+            this._promolink.value = gNavigatorBundle.getString("syncPromoNotification.learnMoreLinkText");
+
+            this.hidden = false;
+
+            // HACK: The description element doesn't wrap correctly in panels,
+            // thus set a width on it, based on the available space, before
+            // setting its textContent.
+            this._panel.addEventListener("popupshown", function (evt) {
+              this._panel.removeEventListener("popupshown", arguments.callee, true);
+              this._promomessage.width = this._promomessage.getBoundingClientRect().width;
+              this._promomessage.firstChild.textContent = this._notificationMessage;
+            }.bind(this), true);
+          }
+        ]]></body>
+      </method>
+    </implementation>
+  </binding>
+
 </bindings>
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -413,20 +413,22 @@ function openAboutDialog() {
   var enumerator = Services.wm.getEnumerator("Browser:About");
   while (enumerator.hasMoreElements()) {
     // Only open one about window (Bug 599573)
     let win = enumerator.getNext();
     win.focus();
     return;
   }
 
-#ifdef XP_MACOSX
+#ifdef XP_WIN
+  var features = "chrome,centerscreen,dependent";
+#elifdef XP_MACOSX
   var features = "chrome,resizable=no,minimizable=no";
 #else
-  var features = "chrome,centerscreen,dependent";
+  var features = "chrome,centerscreen,dependent,dialog=no";
 #endif
   window.openDialog("chrome://browser/content/aboutDialog.xul", "", features);
 }
 
 function openPreferences(paneID, extraArgs)
 {
   var instantApply = getBoolPref("browser.preferences.instantApply", false);
   var features = "chrome,titlebar,toolbar,centerscreen" + (instantApply ? ",dialog=no" : ",modal");
--- a/browser/branding/aurora/content/jar.mn
+++ b/browser/branding/aurora/content/jar.mn
@@ -1,11 +1,10 @@
 browser.jar:
 % content branding %content/branding/ contentaccessible=yes
   content/branding/about.png                     (about.png)
   content/branding/about-background.png          (about-background.png)
   content/branding/about-logo.png                (about-logo.png)
   content/branding/about-wordmark.png            (about-wordmark.png)
   content/branding/icon48.png                    (icon48.png)
   content/branding/icon64.png                    (icon64.png)
-  content/branding/icon128.png                   (../mozicon128.png)
   content/branding/icon16.png                    (../default16.png)
   content/branding/aboutDialog.css               (aboutDialog.css)
--- a/browser/branding/aurora/locales/en-US/brand.properties
+++ b/browser/branding/aurora/locales/en-US/brand.properties
@@ -1,3 +1,5 @@
 brandShortName=Aurora
 brandFullName=Aurora
 vendorShortName=Mozilla
+
+syncBrandShortName=Sync
--- a/browser/branding/nightly/content/jar.mn
+++ b/browser/branding/nightly/content/jar.mn
@@ -1,11 +1,10 @@
 browser.jar:
 % content branding %content/branding/ contentaccessible=yes
   content/branding/about.png                     (about.png)
   content/branding/about-background.png          (about-background.png)
   content/branding/about-logo.png                (about-logo.png)
   content/branding/about-wordmark.png            (about-wordmark.png)
   content/branding/icon48.png                    (icon48.png)
   content/branding/icon64.png                    (icon64.png)
-  content/branding/icon128.png                   (../mozicon128.png)
   content/branding/icon16.png                    (../default16.png)
   content/branding/aboutDialog.css               (aboutDialog.css)
--- a/browser/branding/nightly/locales/en-US/brand.properties
+++ b/browser/branding/nightly/locales/en-US/brand.properties
@@ -1,3 +1,5 @@
 brandShortName=Nightly
 brandFullName=Nightly
 vendorShortName=Mozilla
+
+syncBrandShortName=Sync
--- a/browser/branding/official/content/jar.mn
+++ b/browser/branding/official/content/jar.mn
@@ -1,10 +1,9 @@
 browser.jar:
 % content branding %content/branding/ contentaccessible=yes
   content/branding/about.png                     (about.png)
   content/branding/about-logo.png                (about-logo.png)
   content/branding/about-wordmark.png            (about-wordmark.png)
   content/branding/icon48.png                    (icon48.png)
   content/branding/icon64.png                    (icon64.png)
-  content/branding/icon128.png                   (../mozicon128.png)
   content/branding/icon16.png                    (../default16.png)
   content/branding/aboutDialog.css               (aboutDialog.css)
--- a/browser/branding/official/locales/en-US/brand.properties
+++ b/browser/branding/official/locales/en-US/brand.properties
@@ -2,8 +2,10 @@ brandShortName=Firefox
 brandFullName=Mozilla Firefox
 vendorShortName=Mozilla
 
 homePageSingleStartMain=Firefox Start, a fast home page with built-in search
 homePageImport=Import your home page from %S
 
 homePageMigrationPageTitle=Home Page Selection
 homePageMigrationDescription=Please select the home page you wish to use:
+
+syncBrandShortName=Sync
--- a/browser/branding/unofficial/content/jar.mn
+++ b/browser/branding/unofficial/content/jar.mn
@@ -1,11 +1,10 @@
 browser.jar:
 % content branding %content/branding/ contentaccessible=yes
   content/branding/about.png                     (about.png)
   content/branding/about-background.png          (about-background.png)
   content/branding/about-logo.png                (about-logo.png)
   content/branding/about-wordmark.png            (about-wordmark.png)
   content/branding/icon48.png                    (icon48.png)
   content/branding/icon64.png                    (icon64.png)
-  content/branding/icon128.png                   (../mozicon128.png)
   content/branding/icon16.png                    (../default16.png)
   content/branding/aboutDialog.css               (aboutDialog.css)
--- a/browser/branding/unofficial/locales/en-US/brand.properties
+++ b/browser/branding/unofficial/locales/en-US/brand.properties
@@ -1,3 +1,5 @@
 brandShortName=Mozilla Developer Preview
 brandFullName=Mozilla Developer Preview
 vendorShortName=mozilla.org
+
+syncBrandShortName=Sync
--- a/browser/components/BrowserComponents.manifest
+++ b/browser/components/BrowserComponents.manifest
@@ -1,18 +1,16 @@
 # nsBrowserContentHandler.js
 component {5d0ce354-df01-421a-83fb-7ead0990c24e} nsBrowserContentHandler.js application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 contract @mozilla.org/browser/clh;1 {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 component {47cd0651-b1be-4a0f-b5c4-10e5a573ef71} nsBrowserContentHandler.js application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 contract @mozilla.org/browser/final-clh;1 {47cd0651-b1be-4a0f-b5c4-10e5a573ef71} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 contract @mozilla.org/uriloader/content-handler;1?type=text/html {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 contract @mozilla.org/uriloader/content-handler;1?type=application/vnd.mozilla.xul+xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-#ifdef MOZ_SVG
 contract @mozilla.org/uriloader/content-handler;1?type=image/svg+xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-#endif
 contract @mozilla.org/uriloader/content-handler;1?type=text/rdf {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 contract @mozilla.org/uriloader/content-handler;1?type=text/xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 contract @mozilla.org/uriloader/content-handler;1?type=application/xhtml+xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 contract @mozilla.org/uriloader/content-handler;1?type=text/css {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 contract @mozilla.org/uriloader/content-handler;1?type=text/plain {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 contract @mozilla.org/uriloader/content-handler;1?type=image/gif {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 contract @mozilla.org/uriloader/content-handler;1?type=image/jpeg {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 contract @mozilla.org/uriloader/content-handler;1?type=image/jpg {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
--- a/browser/components/build/Makefile.in
+++ b/browser/components/build/Makefile.in
@@ -69,17 +69,9 @@ EXTRA_DSO_LDOPTS += \
 # Mac: Need to link with CoreFoundation for Mac Migrators (PList reading code)
 # GTK2: Need to link with glib for GNOME shell service
 ifneq (,$(filter cocoa gtk2,$(MOZ_WIDGET_TOOLKIT)))
 EXTRA_DSO_LDOPTS += \
   $(TK_LIBS) \
   $(NULL)
 endif
 
-ifndef MOZ_ENABLE_LIBXUL
-ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-# Doesn't work, couldn't figure out why
-#EXTRA_DSO_LIBS += thebes
-EXTRA_DSO_LDOPTS += $(LIBXUL_DIST)/lib/$(LIB_PREFIX)thebes.$(IMPORT_LIB_SUFFIX)
-endif
-endif
-
 include $(topsrcdir)/config/rules.mk
--- a/browser/components/places/content/places.xul
+++ b/browser/components/places/content/places.xul
@@ -216,16 +216,29 @@
                       label="&cmd.new_folder.label;"
                       accesskey="&cmd.new_folder.accesskey;"/>
             <menuitem id="newseparator"
                       command="placesCmd_new:separator"
                       label="&cmd.new_separator.label;"
                       accesskey="&cmd.new_separator.accesskey;"/>
 
 #ifndef XP_MACOSX
+            <menuseparator id="orgUndoSeparator"/>
+
+            <menuitem id="orgUndo"
+                      command="cmd_undo"
+                      label="&undoCmd.label;"
+                      key="key_undo"
+                      accesskey="&undoCmd.accesskey;"/>
+            <menuitem id="orgRedo"
+                      command="cmd_redo"
+                      label="&redoCmd.label;"
+                      key="key_redo"
+                      accesskey="&redoCmd.accesskey;"/>
+
             <menuseparator id="orgCutSeparator"/>
 
             <menuitem id="orgCut"
                       command="cmd_cut"
                       label="&cutCmd.label;"
                       key="key_cut"
                       accesskey="&cutCmd.accesskey;"
                       selection="separator|link|folder|mixed"/>
@@ -236,47 +249,44 @@
                       accesskey="&copyCmd.accesskey;"
                       selection="separator|link|folder|mixed"/>
             <menuitem id="orgPaste"
                       command="cmd_paste"
                       label="&pasteCmd.label;"
                       key="key_paste"
                       accesskey="&pasteCmd.accesskey;"
                       selection="mutable"/>
-            <menuitem id="orgUndo"
-                      command="cmd_undo"
-                      label="&undoCmd.label;"
-                      key="key_undo"
-                      accesskey="&undoCmd.accesskey;"/>
-            <menuitem id="orgRedo"
-                      command="cmd_redo"
-                      label="&redoCmd.label;"
-                      key="key_redo"
-                      accesskey="&redoCmd.accesskey;"/>
+            <menuitem id="orgDelete"
+                      command="cmd_delete"
+                      label="&deleteCmd.label;"
+                      key="key_delete"
+                      accesskey="&deleteCmd.accesskey;"/>
 
             <menuseparator id="selectAllSeparator"/>
-            
+
             <menuitem id="orgSelectAll"
                       command="cmd_selectAll"
                       label="&selectAllCmd.label;"
                       key="key_selectAll"
                       accesskey="&selectAllCmd.accesskey;"/>
 
 #endif
             <menuseparator id="orgMoveSeparator"/>
+
             <menuitem id="orgMoveBookmarks"
                       command="placesCmd_moveBookmarks"
                       label="&cmd.moveBookmarks.label;"
                       accesskey="&cmd.moveBookmarks.accesskey;"/>
+#ifdef XP_MACOSX
             <menuitem id="orgDelete"
                       command="cmd_delete"
                       label="&deleteCmd.label;"
                       key="key_delete"
                       accesskey="&deleteCmd.accesskey;"/>
-#ifndef XP_MACOSX
+#else
             <menuseparator id="orgCloseSeparator"/>
 
             <menuitem id="orgClose"
                       key="placesKey_close" 
                       label="&file.close.label;"
                       accesskey="&file.close.accesskey;" 
                       oncommand="close();"/>
 #endif
@@ -364,141 +374,137 @@
                oncommand="PlacesSearchBox.search(this.value);"
                collection="bookmarks">
       </textbox>
     </toolbar>
   </toolbox>
 
   <hbox flex="1" id="placesView">
     <tree id="placesList"
-          class="placesTree"
+          class="plain placesTree"
           type="places"
           hidecolumnpicker="true" context="placesContext"
           onselect="PlacesOrganizer.onPlaceSelected(true);"
           onclick="PlacesOrganizer.onTreeClick(event);"
-          onfocus="PlacesOrganizer.onTreeFocus(event);"          
+          onfocus="PlacesOrganizer.onTreeFocus(event);"
           seltype="single"
           persist="width"
           width="200"
           minwidth="100"
           maxwidth="400">
       <treecols>
         <treecol anonid="title" flex="1" primary="true" hideheader="true"/>
       </treecols>
       <treechildren flex="1"/>
     </tree>
     <splitter collapse="none" persist="state"></splitter>
     <vbox id="contentView" flex="4">
-      <deck id="contentDeck" flex="1">
-        <vbox id="defaultView" flex="1">
-          <vbox id="searchModifiers" hidden="true">
-            <toolbar id="organizerScopeBar" class="chromeclass-toolbar" align="center">
-              <label id="scopeBarTitle" value="&search.in.label;"/>
-              <toolbarbutton id="scopeBarAll" type="radio" group="scopeBar"
-                             oncommand="PlacesQueryBuilder.onScopeSelected(this);"
-                             label="&search.scopeBookmarks.label;"
-                             accesskey="&search.scopeBookmarks.accesskey;"/>
-              <!--
-              <toolbarbutton id="scopeBarDownloads" type="radio" group="scopeBar"
-                             oncommand="PlacesQueryBuilder.onScopeSelected(this);"
-                             label="&search.scopeDownloads.label;"
-                             accesskey="&search.scopeDownloads.accesskey;"/>
-              -->
-              <toolbarbutton id="scopeBarHistory" type="radio" group="scopeBar"
-                             oncommand="PlacesQueryBuilder.onScopeSelected(this);"
-                             label="&search.scopeHistory.label;"
-                             accesskey="&search.scopeHistory.accesskey;"/>
-              <toolbarbutton id="scopeBarFolder" type="radio" group="scopeBar"
-                             oncommand="PlacesQueryBuilder.onScopeSelected(this);"
-                             accesskey="&search.scopeFolder.accesskey;"
-                             emptytitle="&search.scopeFolder.label;" flex="1"/>
-              <!-- The folder scope button should flex but not take up more room
-                   than its label needs.  The only simple way to do that is to
-                   set a really big flex on the spacer, e.g., 2^31 - 1. -->
-              <spacer flex="2147483647"/>
-              <button id="saveSearch" class="small" 
-                       label="&saveSearch.label;" accesskey="&saveSearch.accesskey;"
-                       command="OrganizerCommand_search:save"/>
-            </toolbar>
+      <toolbox id="searchModifiers" hidden="true">
+        <toolbar id="organizerScopeBar" class="chromeclass-toolbar" align="center">
+          <label id="scopeBarTitle" value="&search.in.label;"/>
+          <toolbarbutton id="scopeBarAll" class="small-margin"
+                         type="radio" group="scopeBar"
+                         oncommand="PlacesQueryBuilder.onScopeSelected(this);"
+                         label="&search.scopeBookmarks.label;"
+                         accesskey="&search.scopeBookmarks.accesskey;"/>
+          <!--
+          <toolbarbutton id="scopeBarDownloads" class="small-margin"
+                         type="radio" group="scopeBar"
+                         oncommand="PlacesQueryBuilder.onScopeSelected(this);"
+                         label="&search.scopeDownloads.label;"
+                         accesskey="&search.scopeDownloads.accesskey;"/>
+          -->
+          <toolbarbutton id="scopeBarHistory" class="small-margin"
+                         type="radio" group="scopeBar"
+                         oncommand="PlacesQueryBuilder.onScopeSelected(this);"
+                         label="&search.scopeHistory.label;"
+                         accesskey="&search.scopeHistory.accesskey;"/>
+          <toolbarbutton id="scopeBarFolder" class="small-margin"
+                         type="radio" group="scopeBar"
+                         oncommand="PlacesQueryBuilder.onScopeSelected(this);"
+                         accesskey="&search.scopeFolder.accesskey;"
+                         emptytitle="&search.scopeFolder.label;" flex="1"/>
+          <!-- The folder scope button should flex but not take up more room
+                than its label needs.  The only simple way to do that is to
+                set a really big flex on the spacer, e.g., 2^31 - 1. -->
+          <spacer flex="2147483647"/>
+          <button id="saveSearch" class="small-margin"
+                  label="&saveSearch.label;" accesskey="&saveSearch.accesskey;"
+                  command="OrganizerCommand_search:save"/>
+        </toolbar>
+      </toolbox>
+      <tree id="placeContent"
+            class="plain placesTree"
+            context="placesContext"
+            hidecolumnpicker="true"
+            flex="1"
+            type="places"
+            flatList="true"
+            enableColumnDrag="true"
+            onkeypress="if (event.keyCode == KeyEvent.DOM_VK_RETURN) PlacesOrganizer.openSelectedNode(event);"
+            onopenflatcontainer="PlacesOrganizer.openFlatContainer(aContainer);"
+            onselect="PlacesOrganizer.onContentTreeSelect();"
+            onfocus="PlacesOrganizer.onTreeFocus(event);"
+            onclick="PlacesOrganizer.onTreeClick(event);">
+        <treecols id="placeContentColumns" context="placesColumnsContext">
+          <treecol label="&col.name.label;" id="placesContentTitle" anonid="title" flex="5" primary="true" ordinal="1" 
+                    persist="width hidden ordinal sortActive sortDirection"/>
+          <splitter class="tree-splitter"/>
+          <treecol label="&col.tags.label;" id="placesContentTags" anonid="tags" flex="2"
+                    persist="width hidden ordinal sortActive sortDirection"/>
+          <splitter class="tree-splitter"/>
+          <treecol label="&col.url.label;" id="placesContentUrl" anonid="url" flex="5"
+                    persist="width hidden ordinal sortActive sortDirection"/>
+          <splitter class="tree-splitter"/>
+          <treecol label="&col.lastvisit.label;" id="placesContentDate" anonid="date" flex="1" hidden="true"
+                    persist="width hidden ordinal sortActive sortDirection"/>
+          <splitter class="tree-splitter"/>
+          <treecol label="&col.visitcount.label;" id="placesContentVisitCount" anonid="visitCount" flex="1" hidden="true"
+                    persist="width hidden ordinal sortActive sortDirection"/>
+          <splitter class="tree-splitter"/>
+          <treecol label="&col.keyword.label;" id="placesContentKeyword" anonid="keyword" flex="1" hidden="true"
+                    persist="width hidden ordinal sortActive sortDirection"/>
+          <splitter class="tree-splitter"/>
+          <treecol label="&col.description.label;" id="placesContentDescription" anonid="description" flex="1" hidden="true"
+                    persist="width hidden ordinal sortActive sortDirection"/>
+          <splitter class="tree-splitter"/>
+          <treecol label="&col.dateadded.label;" id="placesContentDateAdded" anonid="dateAdded" flex="1" hidden="true"
+                    persist="width hidden ordinal sortActive sortDirection"/>
+          <splitter class="tree-splitter"/>
+          <treecol label="&col.lastmodified.label;" id="placesContentLastModified" anonid="lastModified" flex="1" hidden="true"
+                    persist="width hidden ordinal sortActive sortDirection"/>
+        </treecols>
+        <treechildren flex="1"/>
+      </tree>
+      <deck id="detailsDeck" style="height: 11em;">
+        <vbox id="itemsCountBox" align="center">
+          <spacer flex="3"/>
+          <label id="itemsCountText"/>
+          <spacer flex="1"/>
+          <description id="selectItemDescription">
+              &detailsPane.selectAnItemText.description;
+          </description>
+          <spacer flex="3"/>
+        </vbox>
+        <vbox id="infoBox" minimal="true">
+          <vbox id="editBookmarkPanelContent" flex="1"/>
+          <hbox id="infoBoxExpanderWrapper" align="center">
 
-          </vbox>
-          <vbox flex="1">
-            <tree id="placeContent" class="placesTree" context="placesContext"
-                  hidecolumnpicker="true"
-                  flex="1" type="places"
-                  flatList="true"
-                  enableColumnDrag="true"
-                  onkeypress="if (event.keyCode == KeyEvent.DOM_VK_RETURN) PlacesOrganizer.openSelectedNode(event);"
-                  onopenflatcontainer="PlacesOrganizer.openFlatContainer(aContainer);"
-                  onselect="PlacesOrganizer.onContentTreeSelect();"
-                  onfocus="PlacesOrganizer.onTreeFocus(event);"
-                  onclick="PlacesOrganizer.onTreeClick(event);">
-              <treecols id="placeContentColumns" context="placesColumnsContext">
-                <treecol label="&col.name.label;" id="placesContentTitle" anonid="title" flex="5" primary="true" ordinal="1" 
-                         persist="width hidden ordinal sortActive sortDirection"/>
-                <splitter class="tree-splitter"/>
-                <treecol label="&col.tags.label;" id="placesContentTags" anonid="tags" flex="2"
-                         persist="width hidden ordinal sortActive sortDirection"/>
-                <splitter class="tree-splitter"/>
-                <treecol label="&col.url.label;" id="placesContentUrl" anonid="url" flex="5"
-                         persist="width hidden ordinal sortActive sortDirection"/>
-                <splitter class="tree-splitter"/>
-                <treecol label="&col.lastvisit.label;" id="placesContentDate" anonid="date" flex="1" hidden="true"
-                         persist="width hidden ordinal sortActive sortDirection"/>
-                <splitter class="tree-splitter"/>
-                <treecol label="&col.visitcount.label;" id="placesContentVisitCount" anonid="visitCount" flex="1" hidden="true"
-                         persist="width hidden ordinal sortActive sortDirection"/>
-                <splitter class="tree-splitter"/>
-                <treecol label="&col.keyword.label;" id="placesContentKeyword" anonid="keyword" flex="1" hidden="true"
-                         persist="width hidden ordinal sortActive sortDirection"/>
-                <splitter class="tree-splitter"/>
-                <treecol label="&col.description.label;" id="placesContentDescription" anonid="description" flex="1" hidden="true"
-                         persist="width hidden ordinal sortActive sortDirection"/>
-                <splitter class="tree-splitter"/>
-                <treecol label="&col.dateadded.label;" id="placesContentDateAdded" anonid="dateAdded" flex="1" hidden="true"
-                         persist="width hidden ordinal sortActive sortDirection"/>
-                <splitter class="tree-splitter"/>
-                <treecol label="&col.lastmodified.label;" id="placesContentLastModified" anonid="lastModified" flex="1" hidden="true"
-                         persist="width hidden ordinal sortActive sortDirection"/>
-              </treecols>
-              <treechildren flex="1"/>
-            </tree>
-            <hbox id="infoPaneBox" style="height: 11em;">
-              <deck flex="1" id="detailsDeck">
-                <vbox id="itemsCountBox" align="center">
-                  <spacer flex="3"/>
-                  <label id="itemsCountText"/>
-                  <spacer flex="1"/>
-                  <description id="selectItemDescription">
-                     &detailsPane.selectAnItemText.description;
-                  </description>
-                  <spacer flex="3"/>
-                </vbox>
-                <vbox id="infoBox" minimal="true">
-                  <vbox id="editBookmarkPanelContent"/>
-                  <spacer flex="1"/>
-                  <hbox id="infoBoxExpanderWrapper" align="center">
+            <button type="image" id="infoBoxExpander"
+                    class="expander-down"
+                    oncommand="PlacesOrganizer.toggleAdditionalInfoFields();"
+                    observes="paneElementsBroadcaster"/>
 
-                    <button type="image" id="infoBoxExpander"
-                            class="expander-down"
-                            oncommand="PlacesOrganizer.toggleAdditionalInfoFields();"
-                            observes="paneElementsBroadcaster"/>
+            <label id="infoBoxExpanderLabel"
+                    lesslabel="&detailsPane.less.label;"
+                    lessaccesskey="&detailsPane.less.accesskey;"
+                    morelabel="&detailsPane.more.label;"
+                    moreaccesskey="&detailsPane.more.accesskey;"
+                    value="&detailsPane.more.label;"
+                    accesskey="&detailsPane.more.accesskey;"
+                    control="infoBoxExpander"/>
 
-                    <label id="infoBoxExpanderLabel"
-                           lesslabel="&detailsPane.less.label;"
-                           lessaccesskey="&detailsPane.less.accesskey;"
-                           morelabel="&detailsPane.more.label;"
-                           moreaccesskey="&detailsPane.more.accesskey;"
-                           value="&detailsPane.more.label;"
-                           accesskey="&detailsPane.more.accesskey;"
-                           control="infoBoxExpander"/>
-
-                    <spacer flex="1"/>
-                  </hbox>
-                </vbox>
-              </deck>
-            </hbox>
-          </vbox>
+          </hbox>
         </vbox>
       </deck>
     </vbox>
   </hbox>
 </window>
--- a/browser/components/places/src/PlacesUIUtils.jsm
+++ b/browser/components/places/src/PlacesUIUtils.jsm
@@ -91,179 +91,204 @@ var PlacesUIUtils = {
   getFormattedString: function PUIU_getFormattedString(key, params) {
     return bundle.formatStringFromName(key, params, params.length);
   },
 
   getString: function PUIU_getString(key) {
     return bundle.GetStringFromName(key);
   },
 
-  /**
-   * Get a transaction for copying a uri item from one container to another
-   * as a bookmark.
-   * @param   aData
-   *          JSON object of dropped or pasted item properties
-   * @param   aContainer
-   *          The container being copied into
-   * @param   aIndex
-   *          The index within the container the item is copied to
-   * @returns A nsITransaction object that performs the copy.
-   */
-  _getURIItemCopyTransaction: function (aData, aContainer, aIndex) {
-    return this.ptm.createItem(PlacesUtils._uri(aData.uri), aContainer, aIndex,
-                               aData.title, "");
-  },
+  get _copyableAnnotations() [
+    this.DESCRIPTION_ANNO,
+    this.LOAD_IN_SIDEBAR_ANNO,
+    PlacesUtils.POST_DATA_ANNO,
+    PlacesUtils.READ_ONLY_ANNO,
+  ],
 
   /**
-   * Get a transaction for copying a bookmark item from one container to
-   * another.
+   * Get a transaction for copying a uri item (either a bookmark or a history
+   * entry) from one container to another.
+   *
    * @param   aData
    *          JSON object of dropped or pasted item properties
    * @param   aContainer
    *          The container being copied into
    * @param   aIndex
    *          The index within the container the item is copied to
-   * @param   [optional] aExcludeAnnotations
-   *          Optional, array of annotations (listed by their names) to exclude
-   *          when copying the item.
-   * @returns A nsITransaction object that performs the copy.
+   * @return A nsITransaction object that performs the copy.
+   *
+   * @note Since a copy creates a completely new item, only some internal
+   *       annotations are synced from the old one.
+   * @see this._copyableAnnotations for the list of copyable annotations.
    */
-  _getBookmarkItemCopyTransaction:
-  function PUIU__getBookmarkItemCopyTransaction(aData, aContainer, aIndex,
-                                                aExcludeAnnotations) {
-    var itemURL = PlacesUtils._uri(aData.uri);
-    var itemTitle = aData.title;
-    var keyword = aData.keyword || null;
-    var annos = aData.annos || [];
-    // always exclude GUID when copying any item
-    var excludeAnnos = [PlacesUtils.GUID_ANNO];
-    if (aExcludeAnnotations)
-      excludeAnnos = excludeAnnos.concat(aExcludeAnnotations);
-    annos = annos.filter(function(aValue, aIndex, aArray) {
-      return excludeAnnos.indexOf(aValue.name) == -1;
-    });
-    var childTxns = [];
-    if (aData.dateAdded)
-      childTxns.push(this.ptm.editItemDateAdded(null, aData.dateAdded));
-    if (aData.lastModified)
-      childTxns.push(this.ptm.editItemLastModified(null, aData.lastModified));
-    if (aData.tags) {
-      var tags = aData.tags.split(", ");
-      // filter out tags already present, so that undo doesn't remove them
-      // from pre-existing bookmarks
-      var storedTags = PlacesUtils.tagging.getTagsForURI(itemURL);
-      tags = tags.filter(function (aTag) {
-        return (storedTags.indexOf(aTag) == -1);
-      }, this);
-      if (tags.length)
-        childTxns.push(this.ptm.tagURI(itemURL, tags));
+  _getURIItemCopyTransaction:
+  function PUIU__getURIItemCopyTransaction(aData, aContainer, aIndex)
+  {
+    let transactions = [];
+    if (aData.dateAdded) {
+      transactions.push(
+        new PlacesEditItemDateAddedTransaction(null, aData.dateAdded)
+      );
+    }
+    if (aData.lastModified) {
+      transactions.push(
+        new PlacesEditItemLastModifiedTransaction(null, aData.lastModified)
+      );
     }
 
-    return this.ptm.createItem(itemURL, aContainer, aIndex, itemTitle, keyword,
-                               annos, childTxns);
+    let keyword = aData.keyword || null;
+    let annos = [];
+    if (aData.annos) {
+      annos = aData.annos.filter(function (aAnno) {
+        return this._copyableAnnotations.indexOf(aAnno.name) != -1;
+      }, this);
+    }
+
+    return new PlacesCreateBookmarkTransaction(PlacesUtils._uri(aData.uri),
+                                               aContainer, aIndex, aData.title,
+                                               keyword, annos, transactions);
   },
 
   /**
    * Gets a transaction for copying (recursively nesting to include children)
    * a folder (or container) and its contents from one folder to another.
    *
    * @param   aData
    *          Unwrapped dropped folder data - Obj containing folder and children
    * @param   aContainer
    *          The container we are copying into
    * @param   aIndex
    *          The index in the destination container to insert the new items
-   * @returns A nsITransaction object that will perform the copy.
+   * @return A nsITransaction object that will perform the copy.
+   *
+   * @note Since a copy creates a completely new item, only some internal
+   *       annotations are synced from the old one.
+   * @see this._copyableAnnotations for the list of copyable annotations.
    */
   _getFolderCopyTransaction:
-  function PUIU__getFolderCopyTransaction(aData, aContainer, aIndex) {
-    function getChildItemsTransactions(aChildren) {
-      var childItemsTransactions = [];
-      var cc = aChildren.length;
-      var index = aIndex;
-      for (var i = 0; i < cc; ++i) {
-        var txn = null;
-        var node = aChildren[i];
-
+  function PUIU__getFolderCopyTransaction(aData, aContainer, aIndex)
+  {
+    function getChildItemsTransactions(aChildren)
+    {
+      let transactions = [];
+      let index = aIndex;
+      aChildren.forEach(function (node, i) {
         // Make sure that items are given the correct index, this will be
         // passed by the transaction manager to the backend for the insertion.
-        // Insertion behaves differently if index == DEFAULT_INDEX (append)
-        if (aIndex != PlacesUtils.bookmarks.DEFAULT_INDEX)
+        // Insertion behaves differently for DEFAULT_INDEX (append).
+        if (aIndex != PlacesUtils.bookmarks.DEFAULT_INDEX) {
           index = i;
+        }
 
         if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER) {
-          if (node.livemark && node.annos) // node is a livemark
-            txn = PlacesUIUtils._getLivemarkCopyTransaction(node, aContainer, index);
-          else
-            txn = PlacesUIUtils._getFolderCopyTransaction(node, aContainer, index);
+          if (node.livemark && node.annos) {
+            transactions.push(
+              PlacesUIUtils._getLivemarkCopyTransaction(node, aContainer, index)
+            );
+          }
+          else {
+            transactions.push(
+              PlacesUIUtils._getFolderCopyTransaction(node, aContainer, index)
+            );
+          }
         }
-        else if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR)
-          txn = PlacesUIUtils.ptm.createSeparator(-1, index);
-        else if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE)
-          txn = PlacesUIUtils._getBookmarkItemCopyTransaction(node, -1, index);
-
-        if (txn)
-          childItemsTransactions.push(txn);
-        else
-          throw("Unexpected item under a bookmarks folder");
-      }
-      return childItemsTransactions;
+        else if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR) {
+          transactions.push(new PlacesCreateSeparatorTransaction(-1, index));
+        }
+        else if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE) {
+          transactions.push(
+            PlacesUIUtils._getURIItemCopyTransaction(node, -1, index)
+          );
+        }
+        else {
+          throw new Error("Unexpected item under a bookmarks folder");
+        }
+      });
+      return transactions;
     }
 
-    // tag folders use tag transactions
-    if (aContainer == PlacesUtils.tagsFolderId) {
-      var txns = [];
+    if (aContainer == PlacesUtils.tagsFolderId) { // Copying a tag folder.
+      let transactions = [];
       if (aData.children) {
         aData.children.forEach(function(aChild) {
-          txns.push(this.ptm.tagURI(PlacesUtils._uri(aChild.uri), [aData.title]));
-        }, this);
+          transactions.push(
+            new PlacesTagURITransaction(PlacesUtils._uri(aChild.uri),
+                                        [aData.title])
+          );
+        });
       }
-      return this.ptm.aggregateTransactions("addTags", txns);
+      return new PlacesAggregatedTransaction("addTags", transactions);
     }
-    else if (aData.livemark && aData.annos) {
-      // Place is a Livemark Container
+
+    if (aData.livemark && aData.annos) { // Copying a livemark.
       return this._getLivemarkCopyTransaction(aData, aContainer, aIndex);
     }
-    else {
-      var childItems = getChildItemsTransactions(aData.children);
-      if (aData.dateAdded)
-        childItems.push(this.ptm.editItemDateAdded(null, aData.dateAdded));
-      if (aData.lastModified)
-        childItems.push(this.ptm.editItemLastModified(null, aData.lastModified));
 
-      var annos = aData.annos || [];
-      annos = annos.filter(function(aAnno) {
-        // always exclude GUID when copying any item
-        return aAnno.name != PlacesUtils.GUID_ANNO;
-      });
-      return this.ptm.createFolder(aData.title, aContainer, aIndex, annos, childItems);
+    let transactions = getChildItemsTransactions(aData.children);
+    if (aData.dateAdded) {
+      transactions.push(
+        new PlacesEditItemDateAddedTransaction(null, aData.dateAdded)
+      );
+    }
+    if (aData.lastModified) {
+      transactions.push(
+        new PlacesEditItemLastModifiedTransaction(null, aData.lastModified)
+      );
     }
+
+    let annos = [];
+    if (aData.annos) {
+      annos = aData.annos.filter(function (aAnno) {
+        return this._copyableAnnotations.indexOf(aAnno.name) != -1;
+      }, this);
+    }
+
+    return new PlacesCreateFolderTransaction(aData.title, aContainer, aIndex,
+                                             annos, transactions);
   },
 
+  /**
+   * Gets a transaction for copying a live bookmark item from one container to
+   * another.
+   *
+   * @param   aData
+   *          Unwrapped live bookmarkmark data
+   * @param   aContainer
+   *          The container we are copying into
+   * @param   aIndex
+   *          The index in the destination container to insert the new items
+   * @return A nsITransaction object that will perform the copy.
+   *
+   * @note Since a copy creates a completely new item, only some internal
+   *       annotations are synced from the old one.
+   * @see this._copyableAnnotations for the list of copyable annotations.
+   */
   _getLivemarkCopyTransaction:
-  function PUIU__getLivemarkCopyTransaction(aData, aContainer, aIndex) {
-    if (!aData.livemark || !aData.annos)
-      throw("node is not a livemark");
-    // Place is a Livemark Container
-    var feedURI = null;
-    var siteURI = null;
-    aData.annos = aData.annos.filter(function(aAnno) {
-      if (aAnno.name == PlacesUtils.LMANNO_FEEDURI) {
-        feedURI = PlacesUtils._uri(aAnno.value);
-        return false;
-      }
-      else if (aAnno.name == PlacesUtils.LMANNO_SITEURI) {
-        siteURI = PlacesUtils._uri(aAnno.value);
-        return false;
-      }
-      // always exclude GUID when copying any item
-      return aAnno.name != PlacesUtils.GUID_ANNO;
-    });
-    return this.ptm.createLivemark(feedURI, siteURI, aData.title, aContainer,
-                                   aIndex, aData.annos);
+  function PUIU__getLivemarkCopyTransaction(aData, aContainer, aIndex)
+  {
+    if (!aData.livemark || !aData.annos) {
+      throw new Error("node is not a livemark");
+    }
+
+    let feedURI, siteURI;
+    let annos = [];
+    if (aData.annos) {
+      annos = aData.annos.filter(function (aAnno) {
+        if (aAnno.name == PlacesUtils.LMANNO_FEEDURI) {
+          feedURI = PlacesUtils._uri(aAnno.value);
+        }
+        else if (aAnno.name == PlacesUtils.LMANNO_SITEURI) {
+          siteURI = PlacesUtils._uri(aAnno.value);
+        }
+        return this._copyableAnnotations.indexOf(aAnno.name) != -1
+      }, this);
+    }
+
+    return new PlacesCreateLivemarkTransaction(feedURI, siteURI, aData.title,
+                                               aContainer, aIndex, annos);
   },
 
   /**
    * Constructs a Transaction for the drop or paste of a blob of data into
    * a container.
    * @param   data
    *          The unwrapped data blob of dropped or pasted data.
    * @param   type
@@ -272,50 +297,54 @@ var PlacesUIUtils = {
    *          The container the data was dropped or pasted into
    * @param   index
    *          The index within the container the item was dropped or pasted at
    * @param   copy
    *          The drag action was copy, so don't move folders or links.
    * @returns An object implementing nsITransaction that can perform
    *          the move/insert.
    */
-  makeTransaction: function PUIU_makeTransaction(data, type, container,
-                                                 index, copy) {
+  makeTransaction:
+  function PUIU_makeTransaction(data, type, container, index, copy)
+  {
     switch (data.type) {
       case PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER:
-        if (copy)
+        if (copy) {
           return this._getFolderCopyTransaction(data, container, index);
+        }
+
         // Otherwise move the item.
-        return this.ptm.moveItem(data.id, container, index);
+        return new PlacesMoveItemTransaction(data.id, container, index);
         break;
       case PlacesUtils.TYPE_X_MOZ_PLACE:
-        if (data.id == -1) // Not bookmarked.
+        if (copy || data.id == -1) { // Id is -1 if the place is not bookmarked.
           return this._getURIItemCopyTransaction(data, container, index);
+        }
 
-        if (copy)
-          return this._getBookmarkItemCopyTransaction(data, container, index);
         // Otherwise move the item.
-        return this.ptm.moveItem(data.id, container, index);
+        return new PlacesMoveItemTransaction(data.id, container, index);
         break;
       case PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR:
-        // There is no data in a separator, so copying it just amounts to
-        // inserting a new separator.
-        if (copy)
-          return this.ptm.createSeparator(container, index);
+        if (copy) {
+          // There is no data in a separator, so copying it just amounts to
+          // inserting a new separator.
+          return new PlacesCreateSeparatorTransaction(container, index);
+        }
+
         // Otherwise move the item.
-        return this.ptm.moveItem(data.id, container, index);
+        return new PlacesMoveItemTransaction(data.id, container, index);
         break;
       default:
         if (type == PlacesUtils.TYPE_X_MOZ_URL ||
             type == PlacesUtils.TYPE_UNICODE ||
             type == this.TYPE_TAB_DROP) {
-          var title = (type != PlacesUtils.TYPE_UNICODE) ? data.title :
-                                                             data.uri;
-          return this.ptm.createItem(PlacesUtils._uri(data.uri),
-                                     container, index, title);
+          let title = type != PlacesUtils.TYPE_UNICODE ? data.title
+                                                       : data.uri;
+          return new PlacesCreateBookmarkTransaction(PlacesUtils._uri(data.uri),
+                                                     container, index, title);
         }
     }
     return null;
   },
 
   _reportDeprecatedAddBookmarkMethod:
   function PUIU__reportDeprecatedAddBookmarkMethod() {
     // Removes "PUIU_".
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/unit/test_PUIU_makeTransaction.js
@@ -0,0 +1,353 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function waitForBookmarkNotification(aNotification, aCallback, aProperty)
+{
+  PlacesUtils.bookmarks.addObserver({
+    validate: function (aMethodName, aData)
+    {
+      if (aMethodName == aNotification &&
+          (!aProperty || aProperty == aData.property)) {
+        PlacesUtils.bookmarks.removeObserver(this);
+        aCallback(aData);
+      }
+    },
+
+    // nsINavBookmarkObserver
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]),
+    onBeginUpdateBatch: function onBeginUpdateBatch()
+      this.validate(arguments.callee.name, arguments),
+    onEndUpdateBatch: function onEndUpdateBatch()
+      this.validate(arguments.callee.name, arguments),
+    onItemAdded: function onItemAdded(aItemId, aParentId, aIndex, aItemType,
+                                      aURI, aTitle)
+    {
+      return this.validate(arguments.callee.name, { id: aItemId,
+                                                    index: aIndex,
+                                                    type: aItemType,
+                                                    url: aURI ? aURI.spec : null,
+                                                    title: aTitle });
+    },
+    onBeforeItemRemoved: function onBeforeItemRemoved()
+      this.validate(arguments.callee.name, arguments),
+    onItemRemoved: function onItemRemoved()
+      this.validate(arguments.callee.name, arguments),
+    onItemChanged: function onItemChanged(aItemId, aProperty, aIsAnno,
+                                          aNewValue, aLastModified, aItemType)
+    {
+      return this.validate(arguments.callee.name,
+                           { id: aItemId,
+                             get index() PlacesUtils.bookmarks.getItemIndex(this.id),
+                             type: aItemType,
+                             property: aProperty,
+                             get url() aItemType == PlacesUtils.bookmarks.TYPE_BOOKMARK ?
+                                                PlacesUtils.bookmarks.getBookmarkURI(this.id).spec :
+                                                null,
+                             get title() PlacesUtils.bookmarks.getItemTitle(this.id),
+                           });
+    },
+    onItemVisited: function onItemVisited()
+      this.validate(arguments.callee.name, arguments),
+    onItemMoved: function onItemMoved(aItemId, aOldParentId, aOldIndex,
+                                      aNewParentId, aNewIndex, aItemType)
+    {
+      this.validate(arguments.callee.name, { id: aItemId,
+                                             index: aNewIndex,
+                                             type: aItemType });
+    }
+  }, false);
+}
+
+function wrapNodeByIdAndParent(aItemId, aParentId)
+{
+  let wrappedNode;
+  let root = PlacesUtils.getFolderContents(aParentId, false, false).root;
+  for (let i = 0; i < root.childCount; ++i) {
+    let node = root.getChild(i);
+    if (node.itemId == aItemId) {
+      let type;
+      if (PlacesUtils.nodeIsContainer(node)) {
+        type = PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER;
+      }
+      else if (PlacesUtils.nodeIsURI(node)) {
+        type = PlacesUtils.TYPE_X_MOZ_PLACE;
+      }
+      else if (PlacesUtils.nodeIsSeparator(node)) {
+        type = PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR;
+      }
+      else {
+        do_throw("Unknown node type");
+      }
+      wrappedNode = PlacesUtils.wrapNode(node, type);
+    }
+  }
+  root.containerOpen = false;
+  return JSON.parse(wrappedNode);
+}
+
+add_test(function test_text_paste()
+{
+  const TEST_URL = "http://places.moz.org/"
+  const TEST_TITLE = "Places bookmark"
+
+  waitForBookmarkNotification("onItemAdded", function(aData)
+  {
+    do_check_eq(aData.title, TEST_TITLE);
+    do_check_eq(aData.url, TEST_URL);
+    do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
+    do_check_eq(aData.index, 0);
+    run_next_test();
+  });
+
+  let txn = PlacesUIUtils.makeTransaction(
+    { title: TEST_TITLE, uri: TEST_URL },
+    PlacesUtils.TYPE_X_MOZ_URL,
+    PlacesUtils.unfiledBookmarksFolderId,
+    PlacesUtils.bookmarks.DEFAULT_INDEX,
+    true // Unused for text.
+  );
+  PlacesUtils.transactionManager.doTransaction(txn);
+});
+
+add_test(function test_container()
+{
+  const TEST_TITLE = "Places folder"
+
+  waitForBookmarkNotification("onItemChanged", function(aData)
+  {
+    do_check_eq(aData.title, TEST_TITLE);
+    do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
+    do_check_eq(aData.index, 1);
+
+    waitForBookmarkNotification("onItemAdded", function(aData)
+    {
+      do_check_eq(aData.title, TEST_TITLE);
+      do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
+      do_check_eq(aData.index, 2);
+      let id = aData.id;
+
+      waitForBookmarkNotification("onItemMoved", function(aData)
+      {
+        do_check_eq(aData.id, id);
+        do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
+        do_check_eq(aData.index, 1);
+
+        run_next_test();
+      });
+
+      let txn = PlacesUIUtils.makeTransaction(
+        wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+        0, // Unused for real nodes.
+        PlacesUtils.unfiledBookmarksFolderId,
+        1, // Move to position 1.
+        false
+      );
+      PlacesUtils.transactionManager.doTransaction(txn);
+    });
+
+    try {
+    let txn = PlacesUIUtils.makeTransaction(
+      wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+      0, // Unused for real nodes.
+      PlacesUtils.unfiledBookmarksFolderId,
+      PlacesUtils.bookmarks.DEFAULT_INDEX,
+      true
+    );
+    PlacesUtils.transactionManager.doTransaction(txn);
+    } catch(ex) {
+      do_throw(ex);
+    }
+  }, "random-anno");
+
+  let id = PlacesUtils.bookmarks.createFolder(PlacesUtils.unfiledBookmarksFolderId,
+                                              TEST_TITLE,
+                                              PlacesUtils.bookmarks.DEFAULT_INDEX);
+  PlacesUtils.annotations.setItemAnnotation(id, PlacesUIUtils.DESCRIPTION_ANNO,
+                                            "description", 0,
+                                            PlacesUtils.annotations.EXPIRE_NEVER);
+  PlacesUtils.annotations.setItemAnnotation(id, "random-anno",
+                                            "random-value", 0,
+                                            PlacesUtils.annotations.EXPIRE_NEVER);
+});
+
+
+add_test(function test_separator()
+{
+  waitForBookmarkNotification("onItemChanged", function(aData)
+  {
+    do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
+    do_check_eq(aData.index, 3);
+
+    waitForBookmarkNotification("onItemAdded", function(aData)
+    {
+      do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
+      do_check_eq(aData.index, 4);
+      let id = aData.id;
+
+      waitForBookmarkNotification("onItemMoved", function(aData)
+      {
+        do_check_eq(aData.id, id);
+        do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
+        do_check_eq(aData.index, 1);
+
+        run_next_test();
+      });
+
+      let txn = PlacesUIUtils.makeTransaction(
+        wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+        0, // Unused for real nodes.
+        PlacesUtils.unfiledBookmarksFolderId,
+        1, // Move to position 1.
+        false
+      );
+      PlacesUtils.transactionManager.doTransaction(txn);
+    });
+
+    try {
+    let txn = PlacesUIUtils.makeTransaction(
+      wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+      0, // Unused for real nodes.
+      PlacesUtils.unfiledBookmarksFolderId,
+      PlacesUtils.bookmarks.DEFAULT_INDEX,
+      true
+    );
+    PlacesUtils.transactionManager.doTransaction(txn);
+    } catch(ex) {
+      do_throw(ex);
+    }
+  }, "random-anno");
+
+  let id = PlacesUtils.bookmarks.insertSeparator(PlacesUtils.unfiledBookmarksFolderId,
+                                                 PlacesUtils.bookmarks.DEFAULT_INDEX);
+  PlacesUtils.annotations.setItemAnnotation(id, "random-anno",
+                                            "random-value", 0, 
+                                            PlacesUtils.annotations.EXPIRE_NEVER);
+});
+
+add_test(function test_bookmark()
+{
+  const TEST_URL = "http://places.moz.org/"
+  const TEST_TITLE = "Places bookmark"
+
+  waitForBookmarkNotification("onItemChanged", function(aData)
+  {
+    do_check_eq(aData.title, TEST_TITLE);
+    do_check_eq(aData.url, TEST_URL);
+    do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
+    do_check_eq(aData.index, 5);
+
+    waitForBookmarkNotification("onItemAdded", function(aData)
+    {
+      do_check_eq(aData.title, TEST_TITLE);
+      do_check_eq(aData.url, TEST_URL);
+      do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
+      do_check_eq(aData.index, 6);
+      let id = aData.id;
+
+      waitForBookmarkNotification("onItemMoved", function(aData)
+      {
+        do_check_eq(aData.id, id);
+        do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
+        do_check_eq(aData.index, 1);
+
+        run_next_test();
+      });
+
+      let txn = PlacesUIUtils.makeTransaction(
+        wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+        0, // Unused for real nodes.
+        PlacesUtils.unfiledBookmarksFolderId,
+        1, // Move to position 1.
+        false
+      );
+      PlacesUtils.transactionManager.doTransaction(txn);
+    });
+
+    try {
+    let txn = PlacesUIUtils.makeTransaction(
+      wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+      0, // Unused for real nodes.
+      PlacesUtils.unfiledBookmarksFolderId,
+      PlacesUtils.bookmarks.DEFAULT_INDEX,
+      true
+    );
+    PlacesUtils.transactionManager.doTransaction(txn);
+    } catch(ex) {
+      do_throw(ex);
+    }
+  }, "random-anno");
+
+  let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
+                                                NetUtil.newURI(TEST_URL),
+                                                PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                                TEST_TITLE);
+  PlacesUtils.annotations.setItemAnnotation(id, PlacesUIUtils.DESCRIPTION_ANNO,
+                                            "description", 0,
+                                            PlacesUtils.annotations.EXPIRE_NEVER);
+  PlacesUtils.annotations.setItemAnnotation(id, "random-anno",
+                                            "random-value", 0,
+                                            PlacesUtils.annotations.EXPIRE_NEVER);
+});
+
+add_test(function test_visit()
+{
+  const TEST_URL = "http://places.moz.org/"
+  const TEST_TITLE = "Places bookmark"
+
+  waitForBookmarkNotification("onItemAdded", function(aData)
+  {
+    do_check_eq(aData.title, TEST_TITLE);
+    do_check_eq(aData.url, TEST_URL);
+    do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
+    do_check_eq(aData.index, 7);
+
+    waitForBookmarkNotification("onItemAdded", function(aData)
+    {
+      do_check_eq(aData.title, TEST_TITLE);
+      do_check_eq(aData.url, TEST_URL);
+      do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
+      do_check_eq(aData.index, 8);
+      run_next_test();
+    });
+
+    try {
+    let node = wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId);
+    // Simulate a not-bookmarked node, will copy it to a new bookmark.
+    node.id = -1;
+    let txn = PlacesUIUtils.makeTransaction(
+      node,
+      0, // Unused for real nodes.
+      PlacesUtils.unfiledBookmarksFolderId,
+      PlacesUtils.bookmarks.DEFAULT_INDEX,
+      true
+    );
+    PlacesUtils.transactionManager.doTransaction(txn);
+    } catch(ex) {
+      do_throw(ex);
+    }
+  });
+
+  PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
+                                       NetUtil.newURI(TEST_URL),
+                                       PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                       TEST_TITLE);
+});
+
+add_test(function check_annotations() {
+  // As last step check how many items for each annotation exist.
+
+  // Copies should retain the description annotation.
+  let descriptions =
+    PlacesUtils.annotations.getItemsWithAnnotation(PlacesUIUtils.DESCRIPTION_ANNO, {});
+  do_check_eq(descriptions.length, 4);
+
+  // Only the original bookmarks should have this annotation.
+  let others = PlacesUtils.annotations.getItemsWithAnnotation("random-anno", {});
+  do_check_eq(others.length, 3);
+  run_next_test();
+});
+
+function run_test()
+{
+  run_next_test();
+}
--- a/browser/components/places/tests/unit/xpcshell.ini
+++ b/browser/components/places/tests/unit/xpcshell.ini
@@ -15,9 +15,10 @@ tail =
 [test_browserGlue_migrate.js]
 [test_browserGlue_prefs.js]
 [test_browserGlue_restore.js]
 [test_browserGlue_shutdown.js]
 [test_browserGlue_smartBookmarks.js]
 [test_clearHistory_shutdown.js]
 [test_leftpane_corruption_handling.js]
 [test_placesTxn.js]
+[test_PUIU_makeTransaction.js]
 [test_txnGUIDs.js]
--- a/browser/components/preferences/aboutPermissions.js
+++ b/browser/components/preferences/aboutPermissions.js
@@ -76,39 +76,39 @@ let TEST_EXACT_PERM_TYPES = ["geo"];
  * Site object represents a single site, uniquely identified by a host.
  */
 function Site(host) {
   this.host = host;
   this.listitem = null;
 
   this.httpURI = NetUtil.newURI("http://" + this.host);
   this.httpsURI = NetUtil.newURI("https://" + this.host);
-
-  this._favicon = "";
 }
 
 Site.prototype = {
   /**
-   * Gets the favicon to use for the site. This will return the default favicon
-   * if there is no favicon stored for the site.
+   * Gets the favicon to use for the site. The callback only gets called if
+   * a favicon is found for either the http URI or the https URI.
    *
-   * @return A favicon image URL.
+   * @param aCallback
+   *        A callback function that takes a favicon image URL as a parameter.
    */
-  get favicon() {
-    if (!this._favicon) {
-      // TODO: Bug 657961: Make this async when bug 655270 is fixed.
+  getFavicon: function Site_getFavicon(aCallback) {
+    function faviconDataCallback(aURI, aDataLen, aData, aMimeType) {
       try {
-        // First try to see if a favicon is stored for the http URI.
-        this._favicon = gFaviconService.getFaviconForPage(this.httpURI).spec;
+        aCallback(aURI.spec);
       } catch (e) {
-        // getFaviconImageForPage returns the default favicon if no stored favicon is found.
-        this._favicon = gFaviconService.getFaviconImageForPage(this.httpsURI).spec;
+        Cu.reportError("AboutPermissions: " + e);
       }
     }
-    return this._favicon;
+
+    // Try to find favicion for both URIs. Callback will only be called if a
+    // favicon URI is found, so this means we'll always prefer the https favicon.
+    gFaviconService.getFaviconURLForPage(this.httpURI, faviconDataCallback);
+    gFaviconService.getFaviconURLForPage(this.httpsURI, faviconDataCallback);
   },
 
   /**
    * Gets the number of history visits for the site.
    *
    * @param aCallback
    *        A function that takes the visit count (a number) as a parameter.
    */
@@ -140,16 +140,25 @@ Site.prototype = {
    *        The permission type string stored in permission manager.
    *        e.g. "cookie", "geo", "indexedDB", "popup", "image"
    * @param aResultObj
    *        An object that stores the permission value set for aType.
    *
    * @return A boolean indicating whether or not a permission is set.
    */
   getPermission: function Site_getPermission(aType, aResultObj) {
+    // Password saving isn't a nsIPermissionManager permission type, so handle
+    // it seperately.
+    if (aType == "password") {
+      aResultObj.value =  this.loginSavingEnabled ?
+                          Ci.nsIPermissionManager.ALLOW_ACTION :
+                          Ci.nsIPermissionManager.DENY_ACTION;
+      return true;
+    }
+
     let permissionValue;
     if (TEST_EXACT_PERM_TYPES.indexOf(aType) == -1) {
       permissionValue = Services.perms.testPermission(this.httpURI, aType);
     } else {
       permissionValue = Services.perms.testExactPermission(this.httpURI, aType);
     }
     aResultObj.value = permissionValue;
 
@@ -162,16 +171,23 @@ Site.prototype = {
    * @param aType
    *        The permission type string stored in permission manager.
    *        e.g. "cookie", "geo", "indexedDB", "popup", "image"
    * @param aPerm
    *        The permission value to set for the permission type. This should
    *        be one of the constants defined in nsIPermissionManager.
    */
   setPermission: function Site_setPermission(aType, aPerm) {
+    // Password saving isn't a nsIPermissionManager permission type, so handle
+    // it seperately.
+    if (aType == "password") {
+      this.loginSavingEnabled = aPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
+      return;
+    }
+
     // Using httpURI is kind of bogus, but the permission manager stores the
     // permission for the host, so the right thing happens in the end.
     Services.perms.add(this.httpURI, aType, aPerm);
   },
 
   /**
    * Clears a user-set permission value for the site given a permission type.
    *
@@ -260,32 +276,32 @@ let PermissionDefaults = {
 
   get password() {
     if (Services.prefs.getBoolPref("signon.rememberSignons")) {
       return this.ALLOW;
     }
     return this.DENY;
   },
   set password(aValue) {
-    let value = (aValue == this.ALLOW);
+    let value = (aValue != this.DENY);
     Services.prefs.setBoolPref("signon.rememberSignons", value);
   },
 
   // For use with network.cookie.* prefs.
   COOKIE_ACCEPT: 0,
   COOKIE_DENY: 2,
   COOKIE_NORMAL: 0,
   COOKIE_SESSION: 2,
 
   get cookie() {
     if (Services.prefs.getIntPref("network.cookie.cookieBehavior") == this.COOKIE_DENY) {
       return this.DENY;
     }
 
-    if (Services.prefs.getIntPref("network.cookie.lifetimePolicy") == this.COOKIE_DENY) {
+    if (Services.prefs.getIntPref("network.cookie.lifetimePolicy") == this.COOKIE_SESSION) {
       return this.SESSION;
     }
     return this.ALLOW;
   },
   set cookie(aValue) {
     let value = (aValue == this.DENY) ? this.COOKIE_DENY : this.COOKIE_ACCEPT;
     Services.prefs.setIntPref("network.cookie.cookieBehavior", value);
 
@@ -298,30 +314,30 @@ let PermissionDefaults = {
     if (!Services.prefs.getBoolPref("geo.enabled")) {
       return this.DENY;
     }
     // We always ask for permission to share location with a specific site, so
     // there is no global ALLOW.
     return this.UNKNOWN;
   },
   set geo(aValue) {
-    let value = (aValue == this.ALLOW);
+    let value = (aValue != this.DENY);
     Services.prefs.setBoolPref("geo.enabled", value);
   },
 
   get indexedDB() {
     if (!Services.prefs.getBoolPref("dom.indexedDB.enabled")) {
       return this.DENY;
     }
     // We always ask for permission to enable indexedDB storage for a specific
     // site, so there is no global ALLOW.
     return this.UNKNOWN;
   },
   set indexedDB(aValue) {
-    let value = (aValue == this.ALLOW);
+    let value = (aValue != this.DENY);
     Services.prefs.setBoolPref("dom.indexedDB.enabled", value);
   },
 
   get popup() {
     if (Services.prefs.getBoolPref("dom.disable_open_during_load")) {
       return this.DENY;
     }
     return this.ALLOW;
@@ -458,37 +474,41 @@ let AboutPermissions = {
   /**
    * Creates Site objects for the top-frecency sites in the places database and stores
    * them in _sites. The number of sites created is controlled by PLACES_SITES_LIMIT.
    */
   getSitesFromPlaces: function() {
     gSitesStmt.params.limit = this.PLACES_SITES_LIMIT;
     gSitesStmt.executeAsync({
       handleResult: function(aResults) {
+        AboutPermissions.startSitesListBatch();
         let row;
         while (row = aResults.getNextRow()) {
           let host = row.getResultByName("host");
           AboutPermissions.addHost(host);
         }
+        AboutPermissions.endSitesListBatch();
       },
       handleError: function(aError) {
         Cu.reportError("AboutPermissions: " + aError);
       },
       handleCompletion: function(aReason) {
         // Notify oberservers for testing purposes.
         Services.obs.notifyObservers(null, "browser-permissions-initialized", null);
       }
     });
   },
 
   /**
    * Finds sites that have non-default permissions and creates Site objects for
    * them if they are not already stored in _sites.
    */
   enumerateServices: function() {
+    this.startSitesListBatch();
+
     let logins = Services.logins.getAllLogins();
     logins.forEach(function(aLogin) {
       try {
         // aLogin.hostname is a string in origin URL format (e.g. "http://foo.com")
         let uri = NetUtil.newURI(aLogin.hostname);
         this.addHost(uri.host);
       } catch (e) {
         // newURI will throw for add-ons logins stored in chrome:// URIs 
@@ -510,16 +530,18 @@ let AboutPermissions = {
       while (enumerator.hasMoreElements()) {
         let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission);
         // Only include sites with exceptions set for supported permission types.
         if (this._supportedPermissions.indexOf(permission.type) != -1) {
           this.addHost(permission.host);
         }
       }
     }
+
+    this.endSitesListBatch();
   },
 
   /**
    * Creates a new Site and adds it to _sites if it's not already there.
    *
    * @param aHost
    *        A host string.
    */
@@ -537,20 +559,35 @@ let AboutPermissions = {
    *
    * @param aSite
    *        A Site object.
    */
   addToSitesList: function(aSite) {
     let item = document.createElement("richlistitem");
     item.setAttribute("class", "site");
     item.setAttribute("value", aSite.host);
-    item.setAttribute("favicon", aSite.favicon);
+
+    aSite.getFavicon(function(aURL) {
+      item.setAttribute("favicon", aURL);
+    });
     aSite.listitem = item;
 
-    this.sitesList.appendChild(item);    
+    (this._listFragment || this.sitesList).appendChild(item);
+  },
+
+  startSitesListBatch: function () {
+    if (!this._listFragment)
+      this._listFragment = document.createDocumentFragment();
+  },
+
+  endSitesListBatch: function () {
+    if (this._listFragment) {
+      this.sitesList.appendChild(this._listFragment);
+      this._listFragment = null;
+    }
   },
 
   /**
    * Hides sites in richlistbox based on search text in sites-filter textbox.
    */
   filterSitesList: function() {
     let siteItems = this.sitesList.children;
     let filterValue = document.getElementById("sites-filter").value.toLowerCase();
@@ -648,54 +685,40 @@ let AboutPermissions = {
    * stored permission.
    *
    * @param aType
    *        The permission type string stored in permission manager.
    *        e.g. "cookie", "geo", "indexedDB", "popup", "image"
    */
   updatePermission: function(aType) {
     let allowItem = document.getElementById(aType + "-" + PermissionDefaults.ALLOW);
-    if (!this._selectedSite &&
-        this._noGlobalAllow.indexOf(aType) != -1) {
-      allowItem.hidden = true;
-      return;
-    }
-
-    allowItem.hidden = false;
+    allowItem.hidden = !this._selectedSite &&
+                       this._noGlobalAllow.indexOf(aType) != -1;
 
     let permissionMenulist = document.getElementById(aType + "-menulist");
     let permissionValue;    
     if (!this._selectedSite) {
-
       // If there is no selected site, we are updating the default permissions interface.
       permissionValue = PermissionDefaults[aType];
-    } else if (aType == "password") {
-      // Services.logins.getLoginSavingEnabled already looks at the default
-      // permission, so we don't need to.
-      permissionValue = this._selectedSite.loginSavingEnabled ?
-                        PermissionDefaults.ALLOW : PermissionDefaults.DENY;
     } else {
       let result = {};
       permissionValue = this._selectedSite.getPermission(aType, result) ?
                         result.value : PermissionDefaults[aType];
     }
 
     permissionMenulist.selectedItem = document.getElementById(aType + "-" + permissionValue);
   },
 
   onPermissionCommand: function(event) {
     let permissionType = event.currentTarget.getAttribute("type");
     let permissionValue = event.target.value;
 
     if (!this._selectedSite) {
       // If there is no selected site, we are setting the default permission.
       PermissionDefaults[permissionType] = permissionValue;
-    } else if (permissionType == "password") {
-      let isEnabled = permissionValue == PermissionDefaults.ALLOW;
-      this._selectedSite.loginSavingEnabled = isEnabled;
     } else {
       this._selectedSite.setPermission(permissionType, permissionValue);
     }
   },
 
   updateVisitCount: function() {
     this._selectedSite.getVisitCount(function(aCount) {
       let visitForm = AboutPermissions._stringBundle.GetStringFromName("visitCount");
--- a/browser/components/preferences/aboutPermissions.xml
+++ b/browser/components/preferences/aboutPermissions.xml
@@ -37,15 +37,15 @@
    - ***** END LICENSE BLOCK ***** -->
 
 <!DOCTYPE bindings>
 <bindings xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
   <binding id="site" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
     <content>
-      <xul:hbox class="site-container" align="center">
+      <xul:hbox class="site-container" align="center" flex="1">
         <xul:image xbl:inherits="src=favicon" class="site-favicon"/>
-        <xul:label xbl:inherits="value,selected" class="site-domain" crop="end"/>
+        <xul:label xbl:inherits="value,selected" class="site-domain" crop="end" flex="1"/>
       </xul:hbox>
     </content>
   </binding>
 </bindings>
--- a/browser/components/preferences/aboutPermissions.xul
+++ b/browser/components/preferences/aboutPermissions.xul
@@ -47,16 +47,17 @@
 %aboutPermissionsDTD;
 ]>
 
 <page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
       xmlns:xhtml="http://www.w3.org/1999/xhtml"
       id="permissions-page" title="&permissionsManager.title;"
       onload="AboutPermissions.init();"
       onunload="AboutPermissions.cleanUp();"
+      disablefastfind="true"
       role="application">
 
   <script type="application/javascript"
           src="chrome://browser/content/preferences/aboutPermissions.js"/>
 
   <hbox flex="1" id="permissions-content">
 
     <vbox id="sites-box">
@@ -158,26 +159,26 @@
                       oncommand="AboutPermissions.onPermissionCommand(event);">
               <menupopup>
                 <menuitem id="cookie-1" value="1" label="&permission.allow;"/>
                 <menuitem id="cookie-8" value="8" label="&permission.allowForSession;"/>
                 <menuitem id="cookie-2" value="2" label="&permission.block;"/>
               </menupopup>
             </menulist>
             <button id="cookies-clear-all-button"
-                    label="&cookie.clearAll;"
+                    label="&cookie.removeAll;"
                     oncommand="Services.cookies.removeAll();"/>
             <button id="cookies-manage-all-button"
                     label="&cookie.manage;"
                     oncommand="AboutPermissions.manageCookies();"/>
           </hbox>
           <hbox id="cookies-count" align="center">
             <label id="cookies-label"/>
             <button id="cookies-clear-button"
-                    label="&cookie.clear;"
+                    label="&cookie.remove;"
                     oncommand="AboutPermissions.clearCookies();"/>
             <button id="cookies-manage-button"
                     label="&cookie.manage;"
                     oncommand="AboutPermissions.manageCookies();"/>
           </hbox>
         </vbox>
       </hbox>
 
--- a/browser/components/preferences/privacy.xul
+++ b/browser/components/preferences/privacy.xul
@@ -182,18 +182,18 @@
               >&dontrememberActions.clearHistory.label;</html:a>&dontrememberActions.post.label;</description>
             </vbox>
             <spacer flex="1" class="indent"/>
           </hbox>
         </vbox>
         <vbox id="historyCustomPane">
           <separator class="thin"/>
           <checkbox id="privateBrowsingAutoStart" class="indent"
-                    label="&privateBrowsingPermanent.label;"
-                    accesskey="&privateBrowsingPermanent.accesskey;"
+                    label="&privateBrowsingPermanent2.label;"
+                    accesskey="&privateBrowsingPermanent2.accesskey;"
                     preference="browser.privatebrowsing.autostart"/>
 
           <vbox class="indent">
             <vbox class="indent">
               <checkbox id="rememberHistory"
                         label="&rememberHistory.label;"
                         accesskey="&rememberHistory.accesskey;"
                         preference="places.history.enabled"/>
--- a/browser/components/preferences/tests/browser_permissions.js
+++ b/browser/components/preferences/tests/browser_permissions.js
@@ -20,16 +20,21 @@ const PERM_SESION = 8;
 const TEST_PERMS = {
   "password": PERM_ALLOW,
   "cookie": PERM_ALLOW,
   "geo": PERM_UNKNOWN,
   "indexedDB": PERM_UNKNOWN,
   "popup": PERM_DENY
 };
 
+const NO_GLOBAL_ALLOW = [
+  "geo",
+  "indexedDB"
+];
+
 // number of managed permissions in the interface
 const TEST_PERMS_COUNT = 5;
 
 function test() {
   waitForExplicitFinish();
   registerCleanupFunction(cleanUp);
 
   // add test history visit
@@ -138,16 +143,22 @@ var tests = [
     is(defaultsHeader, gHeaderDeck.selectedPanel,
        "correct header shown for all sites");
 
     ok(gBrowser.contentDocument.getElementById("passwords-count").hidden,
        "passwords count is hidden");
     ok(gBrowser.contentDocument.getElementById("cookies-count").hidden,
        "cookies count is hidden");
 
+    // Test to make sure "Allow" items hidden for certain permission types
+    NO_GLOBAL_ALLOW.forEach(function(aType) {
+      let menuitem = gBrowser.contentDocument.getElementById(aType + "-" + PERM_ALLOW);
+      ok(menuitem.hidden, aType + " allow menuitem hidden for all sites");
+    });
+
     runNextTest();
   },
 
   function test_all_sites_permission() {
     // there should be no user-set pref for cookie behavior
     is(Services.prefs.getIntPref("network.cookie.cookieBehavior"), PERM_UNKNOWN,
        "network.cookie.cookieBehavior is expected default");
 
@@ -190,16 +201,22 @@ var tests = [
        "correct header shown for a specific site");
     is(gSiteLabel.value, TEST_URI_2.host, "header updated for selected site");
 
     ok(!gBrowser.contentDocument.getElementById("passwords-count").hidden,
        "passwords count is not hidden");
     ok(!gBrowser.contentDocument.getElementById("cookies-count").hidden,
        "cookies count is not hidden");
 
+    // Test to make sure "Allow" items are *not* hidden for certain permission types
+    NO_GLOBAL_ALLOW.forEach(function(aType) {
+      let menuitem = gBrowser.contentDocument.getElementById(aType + "-" + PERM_ALLOW);
+      ok(!menuitem.hidden, aType  + " allow menuitem not hidden for single site");
+    });
+
     runNextTest();
   },
 
   function test_permissions() {
     let menulists = gBrowser.contentDocument.getElementsByClassName("pref-menulist");
     is(menulists.length, TEST_PERMS_COUNT, "got expected number of managed permissions");
 
     for (let i = 0; i < menulists.length; i++) {
--- a/browser/components/sidebar/src/nsSidebar.js
+++ b/browser/components/sidebar/src/nsSidebar.js
@@ -36,40 +36,32 @@
 # 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 *****
 
+Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const DEBUG = false; /* set to false to suppress debug messages */
 
 const SIDEBAR_CID               = Components.ID("{22117140-9c6e-11d3-aaf1-00805f8a4905}");
 const nsISupports               = Components.interfaces.nsISupports;
 const nsISidebar                = Components.interfaces.nsISidebar;
 const nsISidebarExternal        = Components.interfaces.nsISidebarExternal;
 const nsIClassInfo              = Components.interfaces.nsIClassInfo;
 
 // File extension for Sherlock search plugin description files
 const SHERLOCK_FILE_EXT_REGEXP = /\.src$/i;
 
 function nsSidebar()
 {
-    const PROMPTSERVICE_CONTRACTID = "@mozilla.org/embedcomp/prompt-service;1";
-    const nsIPromptService = Components.interfaces.nsIPromptService;
-    this.promptService =
-        Components.classes[PROMPTSERVICE_CONTRACTID].getService(nsIPromptService);
-
-    const SEARCHSERVICE_CONTRACTID = "@mozilla.org/browser/search-service;1";
-    const nsIBrowserSearchService = Components.interfaces.nsIBrowserSearchService;
-    this.searchService =
-      Components.classes[SEARCHSERVICE_CONTRACTID].getService(nsIBrowserSearchService);
 }
 
 nsSidebar.prototype.classID = SIDEBAR_CID;
 
 nsSidebar.prototype.nc = "http://home.netscape.com/NC-rdf#";
 
 function sidebarURLSecurityCheck(url)
 {
@@ -97,30 +89,25 @@ function(aTitle, aContentURL, aCustomize
            aCustomizeURL + ")\n");
 
     return this.addPanelInternal(aTitle, aContentURL, aCustomizeURL, true);
 }
 
 nsSidebar.prototype.addPanelInternal =
 function (aTitle, aContentURL, aCustomizeURL, aPersist)
 {
-    var WINMEDSVC = Components.classes['@mozilla.org/appshell/window-mediator;1']
-                              .getService(Components.interfaces.nsIWindowMediator);
-
     // XXX Bug 620418: We shouldn't do this anymore. Instead, we should find the
     // global object for our caller and use it.
-    var win = WINMEDSVC.getMostRecentWindow( "navigator:browser" );
+    var win = Services.wm.getMostRecentWindow("navigator:browser");
     if (!sidebarURLSecurityCheck(aContentURL))
       return;
 
     var uri = null;
-    var ioService = Components.classes["@mozilla.org/network/io-service;1"]
-                              .getService(Components.interfaces.nsIIOService);
     try {
-      uri = ioService.newURI(aContentURL, null, null);
+      uri = Services.io.newURI(aContentURL, null, null);
     }
     catch(ex) { return; }
 
     win.PlacesUIUtils.showBookmarkDialog({ action: "add"
                                          , type: "bookmark"
                                          , hiddenRows: [ "description"
                                                        , "keyword"
                                                        , "location"
@@ -136,37 +123,35 @@ function (engineURL, iconURL)
 {
   try
   {
     // Make sure the URLs are HTTP, HTTPS, or FTP.
     var isWeb = /^(https?|ftp):\/\//i;
 
     if (!isWeb.test(engineURL))
       throw "Unsupported search engine URL";
-  
+
     if (iconURL && !isWeb.test(iconURL))
       throw "Unsupported search icon URL.";
   }
   catch(ex)
   {
     debug(ex);
     Components.utils.reportError("Invalid argument passed to window.sidebar.addSearchEngine: " + ex);
-    
-    var searchBundle = srGetStrBundle("chrome://global/locale/search/search.properties");
-    var brandBundle = srGetStrBundle("chrome://branding/locale/brand.properties");
+
+    var searchBundle = Services.strings.createBundle("chrome://global/locale/search/search.properties");
+    var brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
     var brandName = brandBundle.GetStringFromName("brandShortName");
     var title = searchBundle.GetStringFromName("error_invalid_engine_title");
     var msg = searchBundle.formatStringFromName("error_invalid_engine_msg",
                                                 [brandName], 1);
-    var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"].
-             getService(Components.interfaces.nsIWindowWatcher);
-    ww.getNewPrompter(null).alert(title, msg);
+    Services.ww.getNewPrompter(null).alert(title, msg);
     return false;
   }
-  
+
   return true;
 }
 
 // The suggestedTitle and suggestedCategory parameters are ignored, but remain
 // for backward compatibility.
 nsSidebar.prototype.addSearchEngine =
 function (engineURL, iconURL, suggestedTitle, suggestedCategory)
 {
@@ -180,46 +165,44 @@ function (engineURL, iconURL, suggestedT
   // have less consistent suffixes, so we assume that ".src" is a Sherlock
   // (text) file, and anything else is OpenSearch (XML).
   var dataType;
   if (SHERLOCK_FILE_EXT_REGEXP.test(engineURL))
     dataType = Components.interfaces.nsISearchEngine.DATA_TEXT;
   else
     dataType = Components.interfaces.nsISearchEngine.DATA_XML;
 
-  this.searchService.addEngine(engineURL, dataType, iconURL, true);
+  Services.search.addEngine(engineURL, dataType, iconURL, true);
 }
 
 // This function exists largely to implement window.external.AddSearchProvider(),
 // to match other browsers' APIs.  The capitalization, although nonstandard here,
 // is therefore important.
 nsSidebar.prototype.AddSearchProvider =
 function (aDescriptionURL)
 {
   // Get the favicon URL for the current page, or our best guess at the current
   // page since we don't have easy access to the active document.  Most search
   // engines will override this with an icon specified in the OpenSearch
   // description anyway.
-  var WINMEDSVC = Components.classes['@mozilla.org/appshell/window-mediator;1']
-                            .getService(Components.interfaces.nsIWindowMediator);
-  var win = WINMEDSVC.getMostRecentWindow("navigator:browser");
-  var browser = win.document.getElementById("content");
+  var win = Services.wm.getMostRecentWindow("navigator:browser");
+  var browser = win.gBrowser;
   var iconURL = "";
   // Use documentURIObject in the check for shouldLoadFavIcon so that we
   // do the right thing with about:-style error pages.  Bug 453442
   if (browser.shouldLoadFavIcon(browser.selectedBrowser
                                        .contentDocument
                                        .documentURIObject))
-    iconURL = win.gBrowser.getIcon();
-  
+    iconURL = browser.getIcon();
+
   if (!this.validateSearchEngine(aDescriptionURL, iconURL))
     return;
 
   const typeXML = Components.interfaces.nsISearchEngine.DATA_XML;
-  this.searchService.addEngine(aDescriptionURL, typeXML, iconURL, true);
+  Services.search.addEngine(aDescriptionURL, typeXML, iconURL, true);
 }
 
 // This function exists to implement window.external.IsSearchProviderInstalled(),
 // for compatibility with other browsers.  It will return an integer value
 // indicating whether the given engine is installed for the current user.
 // However, it is currently stubbed out due to security/privacy concerns
 // stemming from difficulties in determining what domain issued the request.
 // See bug 340604 and
@@ -260,21 +243,8 @@ function (iid) {
 
 var NSGetFactory = XPCOMUtils.generateNSGetFactory([nsSidebar]);
 
 /* static functions */
 if (DEBUG)
     debug = function (s) { dump("-*- sidebar component: " + s + "\n"); }
 else
     debug = function (s) {}
-
-// String bundle service
-var gStrBundleService = null;
-
-function srGetStrBundle(path)
-{
-  if (!gStrBundleService)
-    gStrBundleService =
-      Components.classes["@mozilla.org/intl/stringbundle;1"]
-                .getService(Components.interfaces.nsIStringBundleService);
-
-  return gStrBundleService.createBundle(path);
-}
--- a/browser/config/version.txt
+++ b/browser/config/version.txt
@@ -1,1 +1,1 @@
-6.0a1
+7.0a1
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -36,19 +36,17 @@
 #
 # ***** END LICENSE BLOCK *****
 
 MOZ_APP_BASENAME=Firefox
 MOZ_APP_VENDOR=Mozilla
 MOZ_UPDATER=1
 MOZ_PHOENIX=1
 
-MOZ_ENABLE_LIBXUL=1
 MOZ_CHROME_FILE_FORMAT=omni
-MOZ_STATIC_BUILD_UNSUPPORTED=1
 # always enabled for form history
 MOZ_MORKREADER=1
 MOZ_SAFE_BROWSING=1
 MOZ_SERVICES_SYNC=1
 MOZ_APP_VERSION=$FIREFOX_VERSION
 MOZ_EXTENSIONS_DEFAULT=" gnomevfs"
 # MOZ_APP_DISPLAYNAME will be set by branding/configure.sh
 # Changing either of these values requires a clobber to ensure correct results,
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -42,26 +42,17 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 include $(topsrcdir)/config/rules.mk
 
 MOZ_PKG_REMOVALS = $(srcdir)/removed-files.in
 
-ifdef MOZ_ENABLE_LIBXUL
 MOZ_PKG_MANIFEST_P = $(srcdir)/package-manifest.in
-else
-define message
-You need to build with --enable-libxul (the default, unless you specify
---disable-libxul or --enable-shared or --enable-debug) to package a build.
-endef
-default libs installer::
-	$(error $(message))
-endif
 
 MOZ_NONLOCALIZED_PKG_LIST = \
 	xpcom \
 	browser \
 	$(NULL)
 
 MOZ_LOCALIZED_PKG_LIST = $(AB_CD)
 
@@ -122,18 +113,17 @@ ifdef RUN_TEST_PROGRAM
 _ABS_RUN_TEST_PROGRAM = $(call core_abspath,$(RUN_TEST_PROGRAM))
 endif
 
 GENERATE_CACHE = \
   $(_ABS_RUN_TEST_PROGRAM) $(LIBXUL_DIST)/bin/xpcshell$(BIN_SUFFIX) -g "$$PWD" -a "$$PWD" -f $(topsrcdir)/browser/installer/precompile_cache.js -e 'populate_startupcache("omni.jar", "startupCache.zip");' && \
   rm -rf jsloader && \
   $(UNZIP) startupCache.zip && \
   rm startupCache.zip && \
-  find jsloader | xargs touch -t 201001010000 && \
-  $(ZIP) -r9mX omni.jar jsloader
+  $(ZIP) -r9m omni.jar jsloader
 endif
 
 include $(topsrcdir)/toolkit/mozapps/installer/packager.mk
 
 ifeq (bundle, $(MOZ_FS_LAYOUT))
 BINPATH = $(_BINPATH)
 DEFINES += -DAPPNAME=$(_APPNAME)
 else
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -53,16 +53,17 @@
 @BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@
 #ifdef XP_MACOSX
 @BINPATH@/XUL
 #else
 @BINPATH@/@DLL_PREFIX@xul@DLL_SUFFIX@
 #endif
 #ifdef XP_MACOSX
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@.app/
+@BINPATH@/@DLL_PREFIX@plugin_child_interpose@DLL_SUFFIX@
 #else
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@
 #endif
 #ifdef XP_WIN32
 #ifndef MOZ_MEMORY
 #if _MSC_VER == 1400
 @BINPATH@/Microsoft.VC80.CRT.manifest
 @BINPATH@/msvcm80.dll
@@ -132,17 +133,16 @@
 @BINPATH@/components/commandhandler.xpt
 @BINPATH@/components/commandlines.xpt
 @BINPATH@/components/composer.xpt
 @BINPATH@/components/content_base.xpt
 @BINPATH@/components/content_events.xpt
 @BINPATH@/components/content_canvas.xpt
 @BINPATH@/components/content_htmldoc.xpt
 @BINPATH@/components/content_html.xpt
-@BINPATH@/components/content_xmldoc.xpt
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/content_xtf.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_base.xpt
 @BINPATH@/components/dom_canvas.xpt
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -1272,31 +1272,23 @@ xpicleanup@BIN_SUFFIX@
     Microsoft.VC80.CRT.manifest
     msvcm80.dll
     msvcp80.dll
     msvcr80.dll
   #else
     mozcrt19.dll
   #endif
 #endif
-#ifdef MOZ_ENABLE_LIBXUL
-  @DLL_PREFIX@xpcom_core@DLL_SUFFIX@
-  components/@DLL_PREFIX@jar50@DLL_SUFFIX@
-  #ifdef XP_WIN
-    components/xpinstal.dll
-  #else
-    components/@DLL_PREFIX@jsd@DLL_SUFFIX@
-    components/@DLL_PREFIX@xpinstall@DLL_SUFFIX@
-  #endif
+@DLL_PREFIX@xpcom_core@DLL_SUFFIX@
+components/@DLL_PREFIX@jar50@DLL_SUFFIX@
+#ifdef XP_WIN
+  components/xpinstal.dll
 #else
-  #ifdef XP_MACOSX
-    XUL
-  #else
-    @DLL_PREFIX@xul@DLL_SUFFIX@
-  #endif
+  components/@DLL_PREFIX@jsd@DLL_SUFFIX@
+  components/@DLL_PREFIX@xpinstall@DLL_SUFFIX@
 #endif
 #ifndef MOZ_UPDATER
   components/nsUpdateService.js
   components/nsUpdateServiceStub.js
 #endif
 #Talkback
 #ifdef XP_WIN
   extensions/talkback@mozilla.org/components/BrandRes.dll
--- a/browser/locales/en-US/chrome/browser/aboutDialog.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutDialog.dtd
@@ -55,26 +55,8 @@
 <!ENTITY update.downloading.start   "Downloading update — ">
 <!ENTITY update.downloading.end     "">
 
 <!-- LOCALIZATION NOTE (channel.description.start,channel.description.end): channel.description.start and
      channel.description.end create one sentence, with the current channel label inserted in between.
      example: You are currently on the _Stable_ update channel. -->
 <!ENTITY channel.description.start  "You are currently on the ">
 <!ENTITY channel.description.end    " update channel. ">
-
-<!ENTITY channel.change             "Change">
-
-<!ENTITY channel.release.description       "Enjoy the tried and tested final release being used by hundreds of millions around the world. Stay in control of your online experience with super speed, easy customization and the latest Web technologies.">
-<!ENTITY channel.beta.description          "Experience cutting edge features with more stability. Provide feedback to help refine and polish what will be in the final release.">
-<!ENTITY channel.aurora.description        "Experience the newest innovations in an unstable environment that's not for the faint of heart. Provide feedback on features and performance to help determine what makes the final release.">
-
-<!-- LOCALIZATION NOTE (channel.selector.start,channel.selector.end): channel.selector.start and
-     channel.selector.end create one sentence, with a channel selection menulist instered in between.
-     This is all in one line, so try to make the localized text short.
-     example: Switch to the [Stable] update channel. -->
-<!ENTITY channel.selector.start          "Switch to the">
-<!ENTITY channel.selector.end            "update channel.">
-
-<!-- LOCALIZATION NOTE (channel.selector.applyButton): This button applies the user's choice to switch
-     to a new update channel and starts the application update process. -->
-<!ENTITY channel.selector.applyButton    "Apply and Update">
-<!ENTITY channel.selector.cancelButton   "Cancel">
--- a/browser/locales/en-US/chrome/browser/aboutRobots.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutRobots.dtd
@@ -10,18 +10,18 @@
 <!-- Movie: Logan's Run... Box (cybog): "Welcome Humans! I am ready for you." -->
 <!ENTITY robots.errorTitleText "Welcome Humans!">
 <!-- Movie: The Day The Earth Stood Still. Spoken by Klaatu. -->
 <!ENTITY robots.errorShortDescText "We have come to visit you in peace and with goodwill!">
 <!-- Various books by Isaac Asimov. http://en.wikipedia.org/wiki/Three_Laws_of_Robotics -->
 <!ENTITY robots.errorLongDesc1 "Robots may not injure a human being or, through inaction, allow a human being to come to harm.">
 <!-- Movie: Blade Runner. Batty: "I've seen things you people wouldn't believe..." -->
 <!ENTITY robots.errorLongDesc2 "Robots have seen things you people wouldn't believe.">
-<!-- Book: Hitchiker's Guide To The Galaxy. What the Sirius Cybernetics Corporation calls robots. -->
+<!-- Book: Hitchhiker's Guide To The Galaxy. What the Sirius Cybernetics Corporation calls robots. -->
 <!ENTITY robots.errorLongDesc3 "Robots are Your Plastic Pal Who's Fun To Be With.">
 <!-- TV: Futurama. Bender's first line is "Bite my shiny metal ass." -->
 <!ENTITY robots.errorLongDesc4 "Robots have shiny metal posteriors which should not be bitten.">
 <!-- TV: Battlestar Galactica (2004 series). From the opening text. -->
 <!ENTITY robots.errorTrailerDescText "And they have a plan.">
 <!-- TV: Battlestar Galactica (2004 series). Common expletive referring to Cylons. -->
 <!ENTITY robots.imgtitle "Frakkin' Toasters">
-<!-- Book: Hitchiker's Guide To The Galaxy. Arthur presses a button and it warns him. -->
+<!-- Book: Hitchhiker's Guide To The Galaxy. Arthur presses a button and it warns him. -->
 <!ENTITY robots.dontpress "Please do not press this button again.">
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -221,16 +221,19 @@ can reach it easily. -->
 <!ENTITY inspectStylePanelTitle.label  "Style">
 <!-- LOCALIZATION NOTE (inspectObjectButton.label): This button label
   -  appears on the Inspector's toolbar. It is used to open and close the Object
   -  panel. There is also a label in inspector.properties for the panel
   -  titlebar: object.objectPanelTitle. -->
 <!ENTITY inspectObjectButton.label       "Object">
 <!ENTITY inspectObjectButton.accesskey   "O">
 
+<!ENTITY getMoreDevtoolsCmd.label        "Get More Tools">
+<!ENTITY getMoreDevtoolsCmd.accesskey    "M">
+
 <!ENTITY fileMenu.label         "File"> 
 <!ENTITY fileMenu.accesskey       "F">
 <!ENTITY newNavigatorCmd.label        "New Window">
 <!ENTITY newNavigatorCmd.key        "N">
 <!ENTITY newNavigatorCmd.accesskey      "N">
 
 <!ENTITY editMenu.label         "Edit"> 
 <!ENTITY editMenu.accesskey       "E"> 
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -311,8 +311,15 @@ safeModeRestartButton=Restart
 # Encoding" menu in the main Firefox button on Windows. Any other value will
 # hide it. Regardless of the value of this setting, the "Character Encoding"
 # menu will always be accessible via the "Web Developer" menu.
 # This is not a string to translate; it just controls whether the menu shows
 # up in the Firefox button. If users frequently use the "Character Encoding"
 # menu, set this to "true". Otherwise, you can leave it as "false".
 browser.menu.showCharacterEncoding=false
 
+# LOCALIZATION NOTE (syncPromoNotification.bookmarks.label): This appears in
+# the add bookmark star panel.  %S will be replaced by syncBrandShortName.
+syncPromoNotification.bookmarks.label=You can access your bookmarks on all your devices with %S.
+# LOCALIZATION NOTE (syncPromoNotification.passwords.label): This appears in
+# the remember password panel.  %S will be replaced by syncBrandShortName.
+syncPromoNotification.passwords.label=You can access your passwords on all your devices with %S.
+syncPromoNotification.learnMoreLinkText=Learn More
--- a/browser/locales/en-US/chrome/browser/preferences/aboutPermissions.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/aboutPermissions.dtd
@@ -17,19 +17,19 @@
 <!ENTITY permission.allow                "Allow">
 <!ENTITY permission.allowForSession      "Allow for Session">
 <!ENTITY permission.block                "Block">
 
 <!ENTITY password.label                  "Store Passwords">
 <!ENTITY password.manage                 "Manage Passwords…">
 
 <!ENTITY cookie.label                    "Set Cookies">
-<!ENTITY cookie.clear                    "Clear Cookies">
+<!ENTITY cookie.remove                   "Remove Cookies">
 <!ENTITY cookie.manage                   "Manage Cookies…">
-<!ENTITY cookie.clearAll                 "Clear All Cookies">
+<!ENTITY cookie.removeAll                "Remove All Cookies">
 
 <!ENTITY geo.label                       "Share Location">
 
 <!-- LOCALIZATION NOTE (indexedDB.label): This is describing indexedDB storage
      using the same language used for the permIndexedDB string in browser/pageInfo.dtd -->
 <!ENTITY indexedDB.label                 "Maintain Offline Storage">
 
 <!ENTITY popup.label                     "Open Pop-up Windows">
--- a/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
@@ -56,18 +56,18 @@
 <!ENTITY  dontrememberDescription.label  "&brandShortName; will use the same settings as private browsing, and will not remember any history as you browse the Web.">
 
 <!-- LOCALIZATION NOTE (dontrememberActions.pre.label): include a trailing space as needed -->
 <!-- LOCALIZATION NOTE (dontrememberActions.post.label): include a starting space as needed -->
 <!ENTITY  dontrememberActions.pre.label          "You may also want to ">
 <!ENTITY  dontrememberActions.clearHistory.label "clear all current history">
 <!ENTITY  dontrememberActions.post.label         ".">
 
-<!ENTITY  privateBrowsingPermanent.label "Permanent Private Browsing mode">
-<!ENTITY  privateBrowsingPermanent.accesskey "P">
+<!ENTITY  privateBrowsingPermanent2.label "Always use private browsing mode">
+<!ENTITY  privateBrowsingPermanent2.accesskey "p">
 
 <!ENTITY  rememberHistory.label      "Remember my browsing history">
 <!ENTITY  rememberHistory.accesskey  "b">
 
 <!ENTITY  rememberDownload.label         "Remember download history">
 <!ENTITY  rememberDownload.accesskey     "d">
 
 <!ENTITY  rememberSearchForm.label       "Remember search and form history">
--- a/browser/locales/en-US/chrome/browser/scratchpad.dtd
+++ b/browser/locales/en-US/chrome/browser/scratchpad.dtd
@@ -77,38 +77,29 @@
   -  renamed from "Context" to avoid confusion with the right-click context
   -  menu in the text area. It refers to the JavaScript Environment (or context)
   -  the user is evaluating against. I.e., Content (current tab) or Chrome
   -  (browser).
   -->
 <!ENTITY environmentMenu.label        "Environment">
 <!ENTITY environmentMenu.accesskey    "N">
 
-<!-- LOCALIZATION NOTE (contextMenu.label, accesskey): No longer used.
-<!ENTITY contextMenu.label            "Context">
-<!ENTITY contextMenu.accesskey        "C">
-  -->
 
 <!ENTITY contentContext.label         "Content">
 <!ENTITY contentContext.accesskey     "C">
 
 <!-- LOCALIZATION NOTE (browserContext.label, accesskey): This menu item is used
   -  to select an execution environment for the browser window itself as opposed
   -  to content. This is a feature for browser and addon developers and only
   -  enabled via the devtools.chrome.enabled preference. Formerly, this label
   -  was called "Chrome".
   -->
 <!ENTITY browserContext.label         "Browser">
 <!ENTITY browserContext.accesskey     "B">
 
-<!-- LOCALIZATION NOTE (chromeContext.label, accesskey): No longer used.
-<!ENTITY chromeContext.label          "Chrome">
-<!ENTITY chromeContext.accesskey      "H">
-  -->
-
 <!-- LOCALIZATION NOTE (resetContext.label): This command allows the developer
   -  to reset/clear the global object of the environment where the code executes.
   -->
 <!ENTITY resetContext.label           "Reset">
 <!ENTITY resetContext.accesskey       "R">
 
 <!ENTITY executeMenu.label            "Execute">
 <!ENTITY executeMenu.accesskey        "X">
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -1399,16 +1399,41 @@ richlistitem[type~="action"][actiontype=
   margin-bottom: .5em;
 }
 
 /* Implements editBookmarkPanel resizing on folderTree un-collapse. */
 #editBMPanel_folderTree {
   min-width: 27em;
 }
 
+.panel-promo-box {
+  margin: 8px -10px -10px -10px;
+  padding: 8px 16px;
+  border-top: 1px solid ThreeDShadow;
+  background-image: -moz-linear-gradient(hsla(0,0%,0%,.15), hsla(0,0%,0%,.08) 6px);
+}
+
+.panel-promo-icon {
+  list-style-image: url("chrome://browser/skin/sync-24.png");
+  -moz-margin-end: 10px;
+  vertical-align: middle;
+}
+
+.panel-promo-closebutton {
+  list-style-image: url("moz-icon://stock/gtk-close?size=menu");
+  margin-top: 0;
+  margin-bottom: 0;
+  -moz-margin-end: -6px;
+}
+
+.panel-promo-closebutton > .toolbarbutton-text {
+  padding: 0;
+  margin: 0;
+}
+
 /* Content area */
 #sidebar {
   background-color: Window;
 }
 
 /* Throbber */
 #navigator-throbber {
   width: 16px;
@@ -1667,16 +1692,21 @@ richlistitem[type~="action"][actiontype=
 .alltabs-item[selected="true"] {
   font-weight: bold;
 }
 
 .alltabs-item[busy] > .menu-iconic-left > .menu-iconic-icon {
   list-style-image: url("chrome://global/skin/icons/loading_16.png");
 }
 
+.alltabs-item[tabIsVisible] {
+  /* box-shadow instead of background-color to work around native styling */
+  box-shadow: inset 0 0 0 2em hsla(0,0%,50%,.15);
+}
+
 /* Sidebar */
 #sidebar-header > .tabs-closebutton {
   margin-bottom: 0px !important;
   padding: 0px 2px 0px 2px !important;
 }
 
 #sidebar-throbber[loading="true"] {
   list-style-image: url("chrome://global/skin/icons/loading_16.png");
--- a/browser/themes/gnomestripe/browser/jar.mn
+++ b/browser/themes/gnomestripe/browser/jar.mn
@@ -82,16 +82,17 @@ browser.jar:
   skin/classic/browser/tabview/new-tab.png            (tabview/new-tab.png)
   skin/classic/browser/tabview/search.png             (tabview/search.png)  
   skin/classic/browser/tabview/stack-expander.png     (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png            (tabview/tabview.png)
   skin/classic/browser/tabview/tabview.css            (tabview/tabview.css)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-16-throbber.png
   skin/classic/browser/sync-16.png
+  skin/classic/browser/sync-24.png
   skin/classic/browser/sync-24-throbber.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-desktopIcon.png
   skin/classic/browser/sync-mobileIcon.png
   skin/classic/browser/syncSetup.css
   skin/classic/browser/syncCommon.css
   skin/classic/browser/syncQuota.css
--- a/browser/themes/gnomestripe/browser/places/organizer.css
+++ b/browser/themes/gnomestripe/browser/places/organizer.css
@@ -59,48 +59,21 @@
   height: 12px;
 }
 
 /* Root View */
 #placesView {
   background-color: Window;
 }
 
-/* Place List, Place Content */
-.placesTree {
-  margin: 0px;
-}
-
-#placesList {
-  margin: 0px;
-  border: none;
-  padding: 0;
-}
-
-#placeContent {
-  border: 0px;
-}
-
-#infoPaneBox {
+/* Info box */
+#detailsDeck {
   padding: 5px;
 }
 
-.small, .small[disabled="true"] {
-  min-width: 0px;
-  padding: 0px 4px 0px 4px;
-  margin: 0px;  
-  border: 0px;
-}
-
-.small .button-text,
-.small .button-box {
-  padding: 0px;
-  border: 0px;
-}
-
 #infoBoxExpanderLabel {
   -moz-padding-start: 2px;
 }
 
 #searchModifiers {
   padding-right: 3px;
 }
 
--- a/browser/themes/gnomestripe/browser/preferences/aboutPermissions.css
+++ b/browser/themes/gnomestripe/browser/preferences/aboutPermissions.css
@@ -14,33 +14,33 @@
   border: 1px solid ThreeDShadow;
   border-radius: 5px;
 }
 
 /* sites box */
 
 #sites-box {
   padding: 10px;
+  width: 25em;
 }
 
 .site {
-  width: 250px;
-  overflow-x: hidden;
   padding: 4px;
   border-bottom: 1px solid ThreeDLightShadow;
 }
 
 .site-favicon {
   height: 16px;
   width: 16px;
   -moz-margin-end: 4px;
+  list-style-image: url("moz-icon://stock/gtk-file?size=menu");
 }
 
-.site-domain {
-  max-width: 200px; /* crop set in XBL will ellipsize the domain if it's too long */
+#all-sites-item > .site-container > .site-favicon {
+  list-style-image: none;
 }
 
 /* permissions box */
 
 #permissions-box {
   padding-top: 10px;
   overflow-y: auto;
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d67eb47ac4a3563e87ef78f88d0dfdd63b007340
GIT binary patch
literal 1565
zc$@(p2IBdNP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv000H#Nkl<Zc-n<l
z2~1R16os||6|vEjCLr2UAi>tAaVb#iQmj-vtQCe<8xs_87?@#nqza;fii(Je3?nLw
zD64=_zy)OnkaciDKtZ$$11dYnG9%)W+k1cJn~9qGl9LDjy}9Sz`_Db^>ohdo)&YPw
z!0{1cGGaQy1ThQowFX}zW+1*mOhxD+bano3)F`gK2_6v<ktdVMhaWwD0=<2GF!b~(
zjE;`NvuDp>VqyYbzI@4mFAyaOMB=aoKiI6m5at@PkKapBT3+#nVEy{_&bGF;uxoGR
zn6jf2x_f$HU~mwg4iCfV*chnQYIy$qIqclCAJVgOptkP%L{*JKwj*p8Uz4H1I|LUm
zmuQ#9*u}+VFeNp8r1jo?c-YnsM0C5k1r*nAKy_^$GY5z^!-=F6=Kr>KC3JOn!;Sj-
zB2!aSTa01E#9~KY!Figfj-UB%;CWq<m#OQn--KI@O+Ygq0M7kW1Q&|0fUN8)U`fH3
zFNCAg6L9H@jM>-G`3U;@`-!a4&CTsMhJ+niIe9ecTUlBCRCwW1dr4_IlwGX^nlsMk
zLT2_kA|N8>c}wd(Six}u&oygbuk-cm*tBKa9sFG%kqizEQN}H1W@ZZ*0pMUyZz_?-
zXJ9r^bg`I0N?InI$v6w)dk;WjN-9H8QB?yE9=3s_v+E9jL7*&9yhY6yZUS#!00f2X
zxQA=wlu3z9eu`qU3e%f8bLQf-%<OK=26FNWAT=`^l1`_=zJo`=%Vz_EM+9mr54{^r
z3Cx|GocX)=AMDu{wucA^y?0vfj$k$_8ylPDR2d?ezEK<$emXsi37n=0elqzqh{S(G
zaB%RrXyc|XJn2w*MO7>I4QPqt^HuI1{MchBUq{Ep(SZnE_%2>$=j2LAG_>)n$mqja
zr&2SRvd~NfM`EQQkw^wKwfuBj=yng3XH<1fZQNT;X?{E*F`r~hza@3$7hY(rsZ~_r
zngwn8MiQS;!Uj)1lg`v!dMy5xP$-<E38YKGXvXITECIOyjwxG%L&T^sQW^z^v$^@|
z`i91ST>FkTd>@~XTuF+dG7$kmDwUS%>+4U_`SAF}+uM5$mG0V&dZst9c}dQ#xHeD6
zz`$VM5lMVAG1E(?_duE8>4TV4e|YGHhldA}OsO&Nq6nJqG!t1JuFa(l--hhm-6t=v
z7(ajMGUVnLGWz%9`-kZ2>Q2^<q*N+BwaZ1%R<B;|RZv)zLw3?XFhE_+bT?*HgUfSh
zkGXK;<~nSqn^!BVp}0iO)G;PDj<h^WJBzlqwu#Wt&`3*5ODpmnE|(kO<>mDReX5&$
zN~KbfL6T7-K~pjNlBaucJ*A?c;1@S<HFS~IF&k<&m7SfP2d+<JN!r`np|i8|g~N)K
z4;>sFl<w~Ckdc|Cpx`XV&=e_~(z5adR;GFu78V>IKf#Nw+rzuj*m~$?Q8rjI1)kPX
zlZjzNLj&CZ_W{*;98Iw!Au+j0JNO7%JJ|(6EEaoGmaGJ4IJvkLtX<~=8~g)R3S=Nv
zP&O#P{<veuV>ukhwQ{+fEE=#|nL79M_QLSU2zzp-{&<(5`!-i&Of!njHjKWpv9Z1D
zDsCT|7;yjm3(&+m&@Hc5R@dGqlOqcu2PL1vjs`3zV;h~19@Cw{*n0EbR#MQYkB^Td
zYZKa6<y0({FUQ$cg+$=;y9YSAt^$s;8#t`wfZf7Hus=G6x||`qEGs3=Q$VtHa$my4
z(O5|cSwAa`x9{R<CMG7{OYE2RA`uW)Iy%GRrS`CJ(Gnn2BNFL}B<dHkaq1n0^uVE*
z5gv~hMxxPH-uo{6DMm&{KhB*$KX2)><!bxozrxSII51@XfnwMa8V0-eMM31Dqp&yX
zFzktp26R-wJ6gr{{3Dq0F71J?`3`VQBBwMoG@Ng3Jv$07_j6dHS`q;-K*U^`*gF&y
z0)!&Ky8(E9d=Ll(N>a{;2v`#BPZ(p(CyOP*nhX*#Tl2S-X3gY%Ul;!YA6#GD&N3^{
P00000NkvXXu0mjfLDl2u
deleted file mode 100644
index 2f4ed89d0cd7c03c8348342a5bb4a72ca9ac8cda..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -1389,16 +1389,57 @@ richlistitem[type~="action"][actiontype=
   background-color: #eee !important;
   color: #000 !important;
 }
 
 .editBMPanel_rowLabel {
   text-align: end;
 }
 
+.panel-promo-box {
+  margin: 8px -16px -16px -16px;
+  padding: 8px 16px;
+  background-color: hsla(0,0%,7%,.3);
+  border-top: 1px solid hsla(0,0%,100%,.1);
+  border-bottom-left-radius: 6px;
+  border-bottom-right-radius: 6px;
+  box-shadow: 0 1px 1px hsla(0,0%,0%,.25) inset;
+}
+
+.panel-promo-message > .text-link {
+  color: hsl(210,100%,75%);
+}
+
+.panel-promo-icon {
+  list-style-image: url("chrome://browser/skin/sync-24.png");
+  -moz-margin-end: 10px;
+  vertical-align: middle;
+}
+
+.panel-promo-closebutton {
+  list-style-image: url("chrome://global/skin/notification/close.png");
+  -moz-image-region: rect(0, 16px, 16px, 0);
+  border: none;
+  -moz-margin-end: -14px;
+  margin-top: -8px;
+}
+
+.panel-promo-closebutton:hover {
+  -moz-image-region: rect(0, 32px, 16px, 16px);
+}
+
+.panel-promo-closebutton:hover:active {
+  -moz-image-region: rect(0, 48px, 16px, 32px);
+}
+
+.panel-promo-closebutton > .toolbarbutton-text {
+  padding: 0;
+  margin: 0;
+}
+
 /* ----- SIDEBAR ELEMENTS ----- */
 
 #sidebar,
 sidebarheader {
   background-color: #d4dde5;
 }
 
 #sidebar:-moz-window-inactive,
@@ -1960,16 +2001,21 @@ toolbarbutton.chevron > .toolbarbutton-m
 .alltabs-item > .menu-iconic-left > .menu-iconic-icon {
   list-style-image: url("chrome://global/skin/tree/item.png");
 }
 
 .alltabs-item[busy] > .menu-iconic-left > .menu-iconic-icon {
   list-style-image: url("chrome://global/skin/icons/loading_16.png") !important;
 }
 
+.alltabs-item[tabIsVisible] {
+  /* box-shadow instead of background-color to work around native styling */
+  box-shadow: inset 0 0 0 2em hsla(0,0%,50%,.15);
+}
+
 /* Tabstrip close button */
 .tabs-closebutton {
   -moz-padding-end: 4px;
   list-style-image: url("chrome://global/skin/icons/close.png");
   -moz-image-region: rect(0, 16px, 16px, 0);
   border: none;
 }
 
--- a/browser/themes/pinstripe/browser/jar.mn
+++ b/browser/themes/pinstripe/browser/jar.mn
@@ -37,17 +37,16 @@ browser.jar:
   skin/classic/browser/reload-stop-go.png
   skin/classic/browser/searchbar-dropmarker.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/Search.png
   skin/classic/browser/section_collapsed.png
   skin/classic/browser/section_collapsed-rtl.png
   skin/classic/browser/section_expanded.png
   skin/classic/browser/Secure-Glyph-White.png
-  skin/classic/browser/Secure-background.gif
   skin/classic/browser/Toolbar.png
   skin/classic/browser/toolbarbutton-dropmarker.png
   skin/classic/browser/urlbar-arrow.png
   skin/classic/browser/urlbar-popup-blocked.png
   skin/classic/browser/feeds/subscribe.css                  (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css               (feeds/subscribe-ui.css)
   skin/classic/browser/feeds/feedIcon.png                   (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png                 (feeds/feedIcon16.png)
@@ -121,16 +120,17 @@ browser.jar:
   skin/classic/browser/tabview/new-tab.png                  (tabview/new-tab.png)
   skin/classic/browser/tabview/search.png                   (tabview/search.png)
   skin/classic/browser/tabview/stack-expander.png           (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png                  (tabview/tabview.png)
   skin/classic/browser/tabview/tabview.css                  (tabview/tabview.css)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-throbber.png
   skin/classic/browser/sync-16.png
+  skin/classic/browser/sync-24.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-desktopIcon.png
   skin/classic/browser/sync-mobileIcon.png
   skin/classic/browser/syncSetup.css
   skin/classic/browser/syncCommon.css
   skin/classic/browser/syncQuota.css
 #endif
--- a/browser/themes/pinstripe/browser/places/organizer.css
+++ b/browser/themes/pinstripe/browser/places/organizer.css
@@ -1,18 +1,12 @@
 %include ../shared.inc
 
 /* Places Organizer Sidebars */
 
-#placesList {
-  -moz-appearance: none;
-  border: none;
-  margin: 0;
-}
-
 #placesList > treechildren::-moz-tree-row {
   background-color: transparent;
   border-color: transparent;
 }
 
 #placesList > treechildren::-moz-tree-row(selected) {  
   background: @sidebarItemBackground@;
   border-top: @sidebarItemBorderTop@;
@@ -174,33 +168,27 @@
 
 /* Root View */
 #placesView {
   border-top: 1px solid ThreeDDarkShadow;
   -moz-user-focus: ignore;
 }
 
 /* Place List, Place Content */
-.placesTree {
-  margin: 0px;
-}
-
 #placesList {
-  -moz-appearance: none;
   background-color: #d2d8e2;
   width: 160px;
-  margin: 0px;
-  border: 0px;
 }
 
 #placesList:-moz-window-inactive {
   background-color: #e8e8e8;
 }
 
-#infoPaneBox {
+/* Info box */
+#detailsDeck {
   border-top: 1px solid #919191;
   background-color: #f0f0f0;
   padding: 10px;
 }
 
 #placeContent {
   -moz-appearance: none;
   border: 0px;
@@ -230,29 +218,16 @@
 #placeContent > treechildren::-moz-tree-column {
   border-right: 1px solid #d7dad7;
 }
 
 #placeContent > treechildren::-moz-tree-cell(separator) {
   border-color: transparent;
 }
 
-.small {
-  min-width: 0px;
-  padding: 0px 4px 0px 4px;
-  margin: 0px;  
-  border: 0px;
-}
-
-.small .button-text,
-.small .button-box {
-  padding: 0px;
-  border: 0px;
-}
-
 /* Scope Bar */
 
 #advancedSearch > hbox, 
 #advancedSearchRows > row {
   background-color: #E8E8E8;
   border-top: 1px solid #F8F8F8;
   border-bottom: 1px solid #BABABA;
 }
--- a/browser/themes/pinstripe/browser/preferences/aboutPermissions.css
+++ b/browser/themes/pinstripe/browser/preferences/aboutPermissions.css
@@ -16,33 +16,33 @@
   border: 1px solid rgba(50, 65, 92, 0.4);
   border-radius: 5px;
 }
 
 /* sites box */
 
 #sites-box {
   padding: 10px;
+  width: 25em;
 }
 
 .site {
-  width: 250px;
-  overflow-x: hidden;
   padding: 4px;
   border-bottom: 1px solid ThreeDLightShadow;
 }
 
 .site-favicon {
   height: 16px;
   width: 16px;
   -moz-margin-end: 4px;
+  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
 }
 
-.site-domain {
-  max-width: 200px; /* crop set in XBL will ellipsize the domain if it's too long */
+#all-sites-item > .site-container > .site-favicon {
+  list-style-image: none;
 }
 
 /* permissions box */
 
 #permissions-box {
   padding: 10px;
   overflow-y: auto;
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d67eb47ac4a3563e87ef78f88d0dfdd63b007340
GIT binary patch
literal 1565
zc$@(p2IBdNP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv000H#Nkl<Zc-n<l
z2~1R16os||6|vEjCLr2UAi>tAaVb#iQmj-vtQCe<8xs_87?@#nqza;fii(Je3?nLw
zD64=_zy)OnkaciDKtZ$$11dYnG9%)W+k1cJn~9qGl9LDjy}9Sz`_Db^>ohdo)&YPw
z!0{1cGGaQy1ThQowFX}zW+1*mOhxD+bano3)F`gK2_6v<ktdVMhaWwD0=<2GF!b~(
zjE;`NvuDp>VqyYbzI@4mFAyaOMB=aoKiI6m5at@PkKapBT3+#nVEy{_&bGF;uxoGR
zn6jf2x_f$HU~mwg4iCfV*chnQYIy$qIqclCAJVgOptkP%L{*JKwj*p8Uz4H1I|LUm
zmuQ#9*u}+VFeNp8r1jo?c-YnsM0C5k1r*nAKy_^$GY5z^!-=F6=Kr>KC3JOn!;Sj-
zB2!aSTa01E#9~KY!Figfj-UB%;CWq<m#OQn--KI@O+Ygq0M7kW1Q&|0fUN8)U`fH3
zFNCAg6L9H@jM>-G`3U;@`-!a4&CTsMhJ+niIe9ecTUlBCRCwW1dr4_IlwGX^nlsMk
zLT2_kA|N8>c}wd(Six}u&oygbuk-cm*tBKa9sFG%kqizEQN}H1W@ZZ*0pMUyZz_?-
zXJ9r^bg`I0N?InI$v6w)dk;WjN-9H8QB?yE9=3s_v+E9jL7*&9yhY6yZUS#!00f2X
zxQA=wlu3z9eu`qU3e%f8bLQf-%<OK=26FNWAT=`^l1`_=zJo`=%Vz_EM+9mr54{^r
z3Cx|GocX)=AMDu{wucA^y?0vfj$k$_8ylPDR2d?ezEK<$emXsi37n=0elqzqh{S(G
zaB%RrXyc|XJn2w*MO7>I4QPqt^HuI1{MchBUq{Ep(SZnE_%2>$=j2LAG_>)n$mqja
zr&2SRvd~NfM`EQQkw^wKwfuBj=yng3XH<1fZQNT;X?{E*F`r~hza@3$7hY(rsZ~_r
zngwn8MiQS;!Uj)1lg`v!dMy5xP$-<E38YKGXvXITECIOyjwxG%L&T^sQW^z^v$^@|
z`i91ST>FkTd>@~XTuF+dG7$kmDwUS%>+4U_`SAF}+uM5$mG0V&dZst9c}dQ#xHeD6
zz`$VM5lMVAG1E(?_duE8>4TV4e|YGHhldA}OsO&Nq6nJqG!t1JuFa(l--hhm-6t=v
z7(ajMGUVnLGWz%9`-kZ2>Q2^<q*N+BwaZ1%R<B;|RZv)zLw3?XFhE_+bT?*HgUfSh
zkGXK;<~nSqn^!BVp}0iO)G;PDj<h^WJBzlqwu#Wt&`3*5ODpmnE|(kO<>mDReX5&$
zN~KbfL6T7-K~pjNlBaucJ*A?c;1@S<HFS~IF&k<&m7SfP2d+<JN!r`np|i8|g~N)K
z4;>sFl<w~Ckdc|Cpx`XV&=e_~(z5adR;GFu78V>IKf#Nw+rzuj*m~$?Q8rjI1)kPX
zlZjzNLj&CZ_W{*;98Iw!Au+j0JNO7%JJ|(6EEaoGmaGJ4IJvkLtX<~=8~g)R3S=Nv
zP&O#P{<veuV>ukhwQ{+fEE=#|nL79M_QLSU2zzp-{&<(5`!-i&Of!njHjKWpv9Z1D
zDsCT|7;yjm3(&+m&@Hc5R@dGqlOqcu2PL1vjs`3zV;h~19@Cw{*n0EbR#MQYkB^Td
zYZKa6<y0({FUQ$cg+$=;y9YSAt^$s;8#t`wfZf7Hus=G6x||`qEGs3=Q$VtHa$my4
z(O5|cSwAa`x9{R<CMG7{OYE2RA`uW)Iy%GRrS`CJ(Gnn2BNFL}B<dHkaq1n0^uVE*
z5gv~hMxxPH-uo{6DMm&{KhB*$KX2)><!bxozrxSII51@XfnwMa8V0-eMM31Dqp&yX
zFzktp26R-wJ6gr{{3Dq0F71J?`3`VQBBwMoG@Ng3Jv$07_j6dHS`q;-K*U^`*gF&y
z0)!&Ky8(E9d=Ll(N>a{;2v`#BPZ(p(CyOP*nhX*#Tl2S-X3gY%Ul;!YA6#GD&N3^{
P00000NkvXXu0mjfLDl2u
--- a/browser/themes/winstripe/browser/browser-aero.css
+++ b/browser/themes/winstripe/browser/browser-aero.css
@@ -26,16 +26,20 @@
     -moz-border-bottom-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
     -moz-border-right-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
   }
 
   #appmenu-popup {
     margin-top: -1px;
     -moz-margin-start: 1px;
   }
+
+  .panel-promo-message {
+    font-style: italic;
+  }
 }
 
 @media all and (-moz-windows-default-theme) {
   #navigator-toolbox > toolbar:not(:-moz-lwtheme),
   #addon-bar:not(:-moz-lwtheme) {
     background-color