Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Mon, 19 Mar 2012 14:13:34 -0700
changeset 105996 a4916f9d8d2f217b2d452a5802f8ace5d44f396b
parent 105995 b5b6e6aebb36140047dd6563c8a4507d942999c4 (current diff)
parent 89722 c22568c8cf0e147e78989f31f678377327141057 (diff)
child 105997 e96d5b1f47b8bd29a8d7f7f1149482b8b8660a91
push idunknown
push userunknown
push dateunknown
milestone14.0a1
Merge from mozilla-central.
accessible/src/base/nsAccUtils.cpp
accessible/src/base/nsAccUtils.h
accessible/src/base/nsAccessNode.cpp
accessible/src/base/nsAccessibilityService.cpp
accessible/src/base/nsAccessibilityService.h
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsAccessible.h
accessible/src/base/nsCoreUtils.cpp
accessible/src/base/nsCoreUtils.h
accessible/src/html/nsHTMLImageMapAccessible.cpp
accessible/tests/mochitest/common.js
aclocal.m4
b2g/installer/package-manifest.in
browser/base/content/aboutHome-restore-icon-small.png
browser/base/content/aboutHome-restore-icon.png
browser/base/content/aboutHome-snippet1.png
browser/base/content/aboutHome-snippet2.png
browser/base/content/aboutHome.css
browser/base/content/aboutHome.js
browser/base/content/aboutHome.xhtml
browser/base/content/browser.js
browser/base/content/nsContextMenu.js
browser/base/content/test/subtst_contextmenu.html
browser/base/content/test/test_contextmenu.html
browser/base/jar.mn
browser/components/nsBrowserContentHandler.js
browser/components/nsBrowserGlue.js
browser/components/sessionstore/src/nsSessionStore.js
browser/components/tabview/groupitems.js
browser/components/tabview/tabitems.js
browser/components/tabview/test/Makefile.in
browser/components/tabview/test/head.js
browser/components/tabview/ui.js
build/mobile/devicemanagerADB.py
config/autoconf.mk.in
configure.in
content/base/public/nsDeprecatedOperationList.h
content/base/public/nsINode.h
content/base/public/nsTreeSanitizer.h
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/base/src/nsEventSource.cpp
content/base/src/nsFrameLoader.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsImageLoadingContent.cpp
content/base/src/nsTreeSanitizer.cpp
content/base/src/nsWebSocket.cpp
content/base/src/nsXMLHttpRequest.cpp
content/canvas/src/CustomQS_Canvas2D.h
content/canvas/src/CustomQS_WebGL.h
content/canvas/src/DocumentRendererChild.cpp
content/canvas/src/Makefile.in
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
content/canvas/test/test_canvas.html
content/events/src/nsContentEventHandler.cpp
content/events/src/nsEventDispatcher.cpp
content/events/src/nsEventListenerManager.cpp
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsHTMLAudioElement.cpp
content/html/content/src/nsHTMLBodyElement.cpp
content/html/content/src/nsHTMLMediaElement.cpp
content/html/content/src/nsHTMLOptionElement.cpp
content/html/content/src/nsHTMLSelectElement.cpp
content/html/content/src/nsHTMLTableElement.cpp
content/html/content/src/nsHTMLTextAreaElement.cpp
content/html/content/src/nsHTMLVideoElement.cpp
content/html/content/src/nsIConstraintValidation.cpp
content/html/document/src/nsHTMLContentSink.cpp
content/html/document/src/nsHTMLDocument.cpp
content/svg/content/src/nsSVGSVGElement.cpp
content/xbl/src/nsXBLBinding.cpp
content/xbl/src/nsXBLDocumentInfo.cpp
content/xbl/src/nsXBLProtoImplField.cpp
content/xbl/src/nsXBLProtoImplProperty.cpp
content/xbl/src/nsXBLPrototypeHandler.cpp
content/xbl/src/nsXBLService.cpp
content/xbl/src/nsXBLWindowKeyHandler.cpp
content/xml/document/src/nsXMLContentSink.cpp
content/xml/document/src/nsXMLDocument.cpp
content/xslt/src/xml/txXMLUtils.h
content/xul/document/src/nsXULControllers.cpp
content/xul/document/src/nsXULDocument.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/base/nsFocusManager.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsJSEnvironment.cpp
dom/base/nsWrapperCache.h
dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
dom/locales/en-US/chrome/dom/dom.properties
dom/wifi/nsDOMWifiManager.js
dom/wifi/nsDOMWifiManager.manifest
dom/wifi/nsWifiWorker.h
dom/wifi/nsWifiWorker.js
dom/wifi/nsWifiWorker.manifest
editor/libeditor/html/nsHTMLDataTransfer.cpp
embedding/android/GeckoApp.java
embedding/android/GeckoAppShell.java
embedding/android/Makefile.in
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLContextProviderGLX.cpp
gfx/gl/GLContextProviderOSMesa.cpp
gfx/gl/GLContextProviderWGL.cpp
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/ThebesLayerBuffer.cpp
gfx/layers/ThebesLayerBuffer.h
gfx/layers/basic/BasicLayers.cpp
gfx/layers/ipc/PLayers.ipdl
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/ipc/ShadowLayersParent.cpp
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/layers/opengl/ThebesLayerOGL.h
gfx/thebes/gfxDWriteFonts.cpp
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFT2Fonts.cpp
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxFontconfigUtils.cpp
gfx/thebes/gfxGDIFont.cpp
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxHarfBuzzShaper.cpp
gfx/thebes/gfxMacFont.cpp
gfx/thebes/gfxMacPlatformFontList.mm
gfx/thebes/gfxOS2Fonts.cpp
gfx/thebes/gfxPangoFonts.cpp
gfx/thebes/gfxUserFontSet.cpp
gfx/thebes/gfxUserFontSet.h
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsSurface.cpp
image/src/DiscardTracker.cpp
image/src/RasterImage.cpp
image/src/RasterImage.h
image/src/imgFrame.cpp
image/src/imgFrame.h
intl/uconv/ucvcn/nsGBKToUnicode.cpp
js/src/Makefile.in
js/src/configure.in
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/ParseNode.h
js/src/frontend/SemanticAnalysis.cpp
js/src/gc/Barrier.h
js/src/gc/Statistics.h
js/src/ion/CodeGenerator.cpp
js/src/ion/CodeGenerator.h
js/src/ion/Ion.cpp
js/src/ion/IonBuilder.cpp
js/src/ion/IonBuilder.h
js/src/ion/LIR-Common.h
js/src/ion/LOpcodes.h
js/src/ion/Lowering.cpp
js/src/ion/Lowering.h
js/src/ion/MIR.h
js/src/ion/MOpcodes.h
js/src/jit-test/jit_test.py
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi-tests/Makefile.in
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsatom.h
js/src/jsbool.cpp
js/src/jscompartment.cpp
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsfuninlines.h
js/src/jsgc.cpp
js/src/jsgcmark.cpp
js/src/jsgcmark.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsinterpinlines.h
js/src/jsnum.cpp
js/src/jsnum.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsopcode.tbl
js/src/jsproxy.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jsutil.h
js/src/jsval.h
js/src/jswrapper.cpp
js/src/jsxdrapi.h
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/shell/js.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.h
js/src/vm/StringBuffer-inl.h
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCWrappedNativeInfo.cpp
js/xpconnect/src/dom_quickstubs.qsconf
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/WrapperFactory.cpp
layout/base/FrameLayerBuilder.cpp
layout/base/crashtests/crashtests.list
layout/base/nsDocumentViewer.cpp
layout/base/nsFrameManager.cpp
layout/base/nsIPresShell.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/forms/nsFieldSetFrame.cpp
layout/generic/nsFirstLetterFrame.cpp
layout/generic/nsFirstLetterFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsFrame.h
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsHTMLCanvasFrame.h
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsIFrame.h
layout/generic/nsImageFrame.cpp
layout/generic/nsImageFrame.h
layout/generic/nsImageMap.cpp
layout/generic/nsImageMap.h
layout/generic/nsInlineFrame.cpp
layout/generic/nsInlineFrame.h
layout/generic/nsPageContentFrame.cpp
layout/generic/nsPageContentFrame.h
layout/generic/nsSelection.cpp
layout/generic/nsSubDocumentFrame.cpp
layout/generic/nsSubDocumentFrame.h
layout/generic/nsTextFrame.h
layout/generic/nsTextFrameThebes.cpp
layout/generic/nsTextRunTransformations.h
layout/generic/nsVideoFrame.cpp
layout/generic/nsVideoFrame.h
layout/inspector/src/inFlasher.cpp
layout/reftests/bugs/reftest.list
layout/reftests/scrolling/reftest.list
layout/reftests/svg/as-image/img-blobBuilder-1.html
layout/reftests/svg/as-image/img-blobBuilder-2.html
layout/reftests/svg/as-image/reftest.list
layout/style/nsCSSDataBlock.cpp
layout/style/nsCSSDataBlock.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsFontFaceLoader.cpp
layout/style/nsFontFaceLoader.h
layout/style/nsStyleStruct.h
layout/svg/base/src/nsSVGClipPathFrame.h
layout/svg/base/src/nsSVGContainerFrame.cpp
layout/svg/base/src/nsSVGContainerFrame.h
layout/svg/base/src/nsSVGMarkerFrame.cpp
layout/svg/base/src/nsSVGMarkerFrame.h
layout/svg/base/src/nsSVGMaskFrame.h
layout/svg/base/src/nsSVGOuterSVGFrame.cpp
layout/svg/base/src/nsSVGOuterSVGFrame.h
layout/svg/base/src/nsSVGPaintServerFrame.h
layout/svg/base/src/nsSVGPatternFrame.h
layout/svg/base/src/nsSVGSwitchFrame.cpp
layout/tables/FixedTableLayoutStrategy.cpp
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/tools/reftest/remotereftest.py
layout/xul/base/src/nsMenuPopupFrame.cpp
layout/xul/base/src/nsScrollBoxObject.cpp
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mobile/android/components/CapturePicker.js
mobile/xul/app/mobile.js
mobile/xul/installer/package-manifest.in
modules/libpref/src/init/all.js
mozglue/android/APKOpen.cpp
netwerk/mime/nsMIMEHeaderParamImpl.cpp
netwerk/protocol/data/nsDataHandler.cpp
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelChild.h
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/nsHttpConnectionMgr.cpp
parser/html/nsParserUtils.cpp
parser/htmlparser/public/nsIParserService.h
parser/htmlparser/src/nsParserService.h
testing/jetpack/jetpack-location.txt
testing/mochitest/runtestsremote.py
toolkit/components/aboutmemory/content/aboutMemory.js
toolkit/components/downloads/nsDownloadScanner.h
toolkit/components/places/nsNavHistory.cpp
toolkit/components/places/nsPlacesImportExportService.cpp
toolkit/components/satchel/nsFormFillController.cpp
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/components/telemetry/TelemetryPing.js
toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/profile/nsToolkitProfileService.cpp
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/nsAppShell.cpp
widget/gtk2/nsLookAndFeel.cpp
xpcom/base/nsCycleCollector.cpp
xpcom/base/nsError.h
xpcom/glue/pldhash.cpp
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -317,30 +317,16 @@ nsAccUtils::GetSelectableContainer(nsAcc
   nsAccessible* parent = aAccessible;
   while ((parent = parent->Parent()) && !parent->IsSelect()) {
     if (Role(parent) == nsIAccessibleRole::ROLE_PANE)
       return nsnull;
   }
   return parent;
 }
 
-nsAccessible*
-nsAccUtils::GetMultiSelectableContainer(nsINode* aNode)
-{
-  nsAccessible* accessible = GetAccService()->GetAccessible(aNode, nsnull);
-  if (accessible) {
-    nsAccessible* container = GetSelectableContainer(accessible,
-                                                     accessible->State());
-    if (container && container->State() & states::MULTISELECTABLE)
-      return container;
-  }
-
-  return nsnull;
-}
-
 bool
 nsAccUtils::IsARIASelected(nsAccessible *aAccessible)
 {
   return aAccessible->GetContent()->
     AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_selected,
                 nsGkAtoms::_true, eCaseMatters);
 }
 
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -192,21 +192,16 @@ public:
    *
    * @param  aAccessible  [in] the item accessible
    * @param  aState       [in] the state of the item accessible
    */
   static nsAccessible* GetSelectableContainer(nsAccessible* aAccessible,
                                               PRUint64 aState);
 
   /**
-   * Return multi selectable container for the given item.
-   */
-  static nsAccessible *GetMultiSelectableContainer(nsINode *aNode);
-
-  /**
    * Return true if the DOM node of given accessible has aria-selected="true"
    * attribute.
    */
   static bool IsARIASelected(nsAccessible *aAccessible);
 
   /**
    * Return text accessible containing focus point of the given selection.
    * Used for normal and misspelling selection changes processing.
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -293,29 +293,30 @@ nsAccessibilityService::CreateHTMLFileIn
   NS_ADDREF(accessible);
   return accessible;
 }
 
 already_AddRefed<nsAccessible>
 nsAccessibilityService::CreateHTMLImageAccessible(nsIContent* aContent,
                                                   nsIPresShell* aPresShell)
 {
-  nsAutoString mapElmName;
-  aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usemap, mapElmName);
-  nsCOMPtr<nsIDOMHTMLMapElement> mapElm;
-  if (nsIDocument* document = aContent->GetCurrentDoc()) {
-    mapElm = do_QueryInterface(document->FindImageMap(mapElmName));
-  }
+  nsAccessible* accessible =
+    new nsHTMLImageAccessibleWrap(aContent,
+                                  nsAccUtils::GetDocAccessibleFor(aPresShell));
+  NS_ADDREF(accessible);
+  return accessible;
+}
 
-  nsAccessible* accessible = mapElm ?
-    new nsHTMLImageMapAccessible(aContent, 
-                                 nsAccUtils::GetDocAccessibleFor(aPresShell), 
-                                 mapElm) :
-    new nsHTMLImageAccessibleWrap(aContent, 
-                                  nsAccUtils::GetDocAccessibleFor(aPresShell));
+already_AddRefed<nsAccessible>
+nsAccessibilityService::CreateHTMLImageMapAccessible(nsIContent* aContent,
+                                                     nsIPresShell* aPresShell)
+{
+  nsAccessible* accessible =
+    new nsHTMLImageMapAccessible(aContent,
+                                 nsAccUtils::GetDocAccessibleFor(aPresShell));
   NS_ADDREF(accessible);
   return accessible;
 }
 
 already_AddRefed<nsAccessible>
 nsAccessibilityService::CreateHTMLGroupboxAccessible(nsIContent* aContent,
                                                      nsIPresShell* aPresShell)
 {
@@ -607,16 +608,38 @@ nsAccessibilityService::UpdateListBullet
       nsHTMLLIAccessible* listItem = accessible->AsHTMLListItem();
       if (listItem)
         listItem->UpdateBullet(aHasBullet);
     }
   }
 }
 
 void
+nsAccessibilityService::UpdateImageMap(nsImageFrame* aImageFrame)
+{
+  nsIPresShell* presShell = aImageFrame->PresContext()->PresShell();
+  nsDocAccessible* document = GetDocAccessible(presShell->GetDocument());
+  if (document) {
+    nsAccessible* accessible =
+      document->GetAccessible(aImageFrame->GetContent());
+    if (accessible) {
+      nsHTMLImageMapAccessible* imageMap = accessible->AsImageMap();
+      if (imageMap) {
+        imageMap->UpdateChildAreas();
+        return;
+      }
+
+      // If image map was initialized after we created an accessible (that'll
+      // be an image accessible) then recreate it.
+      RecreateAccessible(presShell, aImageFrame->GetContent());
+    }
+  }
+}
+
+void
 nsAccessibilityService::PresShellDestroyed(nsIPresShell *aPresShell)
 {
   // Presshell destruction will automatically destroy shells for descendant
   // documents, so no need to worry about those. Just shut down the accessible
   // for this one document. That keeps us from having bad behavior in case of
   // deep bushy subtrees.
   // When document subtree containing iframe is hidden then we don't get
   // pagehide event for the iframe's underlying document and its presshell is
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -43,16 +43,18 @@
 
 #include "a11yGeneric.h"
 #include "nsAccDocManager.h"
 
 #include "mozilla/a11y/FocusManager.h"
 
 #include "nsIObserver.h"
 
+class nsImageFrame;
+
 namespace mozilla {
 namespace a11y {
 
 /**
  * Return focus manager.
  */
 FocusManager* FocusMgr();
 
@@ -104,16 +106,18 @@ public:
   already_AddRefed<nsAccessible>
     CreateHTMLFileInputAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
   virtual already_AddRefed<nsAccessible>
     CreateHTMLGroupboxAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
   virtual already_AddRefed<nsAccessible>
     CreateHTMLHRAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
   virtual already_AddRefed<nsAccessible>
     CreateHTMLImageAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
+  already_AddRefed<nsAccessible>
+    CreateHTMLImageMapAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
   virtual already_AddRefed<nsAccessible>
     CreateHTMLLabelAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
   virtual already_AddRefed<nsAccessible>
     CreateHTMLLIAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
   virtual already_AddRefed<nsAccessible>
     CreateHTMLListboxAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
   virtual already_AddRefed<nsAccessible>
     CreateHTMLMediaAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
@@ -150,16 +154,21 @@ public:
 
   /**
    * Update list bullet accessible.
    */
   virtual void UpdateListBullet(nsIPresShell* aPresShell,
                                 nsIContent* aHTMLListItemContent,
                                 bool aHasBullet);
 
+  /**
+   * Update the image map.
+   */
+  void UpdateImageMap(nsImageFrame* aImageFrame);
+
   virtual void NotifyOfAnchorJumpTo(nsIContent *aTarget);
 
   virtual void PresShellDestroyed(nsIPresShell* aPresShell);
 
   /**
    * Notify that presshell is activated.
    */
   virtual void PresShellActivated(nsIPresShell* aPresShell);
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -1037,57 +1037,52 @@ nsAccessible::GetBounds(PRInt32* aX, PRI
 
 // helpers
 
 nsIFrame* nsAccessible::GetBoundsFrame()
 {
   return GetFrame();
 }
 
-/* void removeSelection (); */
 NS_IMETHODIMP nsAccessible::SetSelected(bool aSelect)
 {
-  // Add or remove selection
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  if (State() & states::SELECTABLE) {
-    nsAccessible* multiSelect =
-      nsAccUtils::GetMultiSelectableContainer(mContent);
-    if (!multiSelect) {
-      return aSelect ? TakeFocus() : NS_ERROR_FAILURE;
+  nsAccessible* select = nsAccUtils::GetSelectableContainer(this, State());
+  if (select) {
+    if (select->State() & states::MULTISELECTABLE) {
+      if (mRoleMapEntry) {
+        if (aSelect) {
+          return mContent->SetAttr(kNameSpaceID_None,
+                                   nsGkAtoms::aria_selected,
+                                   NS_LITERAL_STRING("true"), true);
+        }
+        return mContent->UnsetAttr(kNameSpaceID_None,
+                                   nsGkAtoms::aria_selected, true);
+      }
+
+      return NS_OK;
     }
 
-    if (mRoleMapEntry) {
-      if (aSelect) {
-        return mContent->SetAttr(kNameSpaceID_None,
-                                 nsGkAtoms::aria_selected,
-                                 NS_LITERAL_STRING("true"), true);
-      }
-      return mContent->UnsetAttr(kNameSpaceID_None,
-                                 nsGkAtoms::aria_selected, true);
-    }
+    return aSelect ? TakeFocus() : NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
-/* void takeSelection (); */
 NS_IMETHODIMP nsAccessible::TakeSelection()
 {
-  // Select only this item
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  if (State() & states::SELECTABLE) {
-    nsAccessible* multiSelect =
-      nsAccUtils::GetMultiSelectableContainer(mContent);
-    if (multiSelect)
-      multiSelect->ClearSelection();
-
+  nsAccessible* select = nsAccUtils::GetSelectableContainer(this, State());
+  if (select) {
+    if (select->State() & states::MULTISELECTABLE)
+      select->ClearSelection();
     return SetSelected(true);
   }
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsAccessible::TakeFocus()
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -57,16 +57,17 @@
 
 class AccEvent;
 class AccGroupInfo;
 class EmbeddedObjCollector;
 class KeyBinding;
 class nsAccessible;
 class nsHyperTextAccessible;
 class nsHTMLImageAccessible;
+class nsHTMLImageMapAccessible;
 class nsHTMLLIAccessible;
 struct nsRoleMapEntry;
 class Relation;
 class nsTextAccessible;
 
 struct nsRect;
 class nsIContent;
 class nsIFrame;
@@ -449,20 +450,23 @@ public:
 
   inline bool IsHyperText() const { return mFlags & eHyperTextAccessible; }
   nsHyperTextAccessible* AsHyperText();
 
   inline bool IsHTMLFileInput() const { return mFlags & eHTMLFileInputAccessible; }
 
   inline bool IsHTMLListItem() const { return mFlags & eHTMLListItemAccessible; }
   nsHTMLLIAccessible* AsHTMLListItem();
-  
+
   inline bool IsImageAccessible() const { return mFlags & eImageAccessible; }
   nsHTMLImageAccessible* AsImage();
 
+  bool IsImageMapAccessible() const { return mFlags & eImageMapAccessible; }
+  nsHTMLImageMapAccessible* AsImageMap();
+
   inline bool IsListControl() const { return mFlags & eListControlAccessible; }
 
   inline bool IsMenuButton() const { return mFlags & eMenuButtonAccessible; }
 
   inline bool IsMenuPopup() const { return mFlags & eMenuPopupAccessible; }
 
   inline bool IsRoot() const { return mFlags & eRootAccessible; }
   nsRootAccessible* AsRoot();
@@ -684,21 +688,22 @@ protected:
     eAutoCompleteAccessible = 1 << 3,
     eAutoCompletePopupAccessible = 1 << 4,
     eComboboxAccessible = 1 << 5,
     eDocAccessible = 1 << 6,
     eHyperTextAccessible = 1 << 7,
     eHTMLFileInputAccessible = 1 << 8,
     eHTMLListItemAccessible = 1 << 9,
     eImageAccessible = 1 << 10,
-    eListControlAccessible = 1 << 11,
-    eMenuButtonAccessible = 1 << 12,
-    eMenuPopupAccessible = 1 << 13,
-    eRootAccessible = 1 << 14,
-    eTextLeafAccessible = 1 << 15
+    eImageMapAccessible = 1 << 11,
+    eListControlAccessible = 1 << 12,
+    eMenuButtonAccessible = 1 << 13,
+    eMenuPopupAccessible = 1 << 14,
+    eRootAccessible = 1 << 15,
+    eTextLeafAccessible = 1 << 16
   };
 
   //////////////////////////////////////////////////////////////////////////////
   // Miscellaneous helpers
 
   /**
    * Return ARIA role (helper method).
    */
--- a/accessible/src/html/nsHTMLImageMapAccessible.cpp
+++ b/accessible/src/html/nsHTMLImageMapAccessible.cpp
@@ -47,25 +47,26 @@
 #include "nsIServiceManager.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMHTMLAreaElement.h"
 #include "nsIFrame.h"
 #include "nsImageFrame.h"
 #include "nsImageMap.h"
 
 using namespace mozilla::a11y;
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLImageMapAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLImageMapAccessible::
-  nsHTMLImageMapAccessible(nsIContent* aContent, nsDocAccessible* aDoc,
-                           nsIDOMHTMLMapElement* aMapElm) :
-  nsHTMLImageAccessibleWrap(aContent, aDoc), mMapElement(aMapElm)
+  nsHTMLImageMapAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
+  nsHTMLImageAccessibleWrap(aContent, aDoc)
 {
+  mFlags |= eImageMapAccessible;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLImageMapAccessible: nsISupports
 
 NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLImageMapAccessible, nsHTMLImageAccessible)
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -99,49 +100,85 @@ nsHTMLImageMapAccessible::AnchorURIAt(PR
   if (!area)
     return nsnull;
 
   nsIContent* linkContent = area->GetContent();
   return linkContent ? linkContent->GetHrefURI() : nsnull;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsHTMLImageMapAccessible: nsAccessible protected
+// nsHTMLImageMapAccessible: public
 
-void 
-nsHTMLImageMapAccessible::CacheChildren()
+void
+nsHTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents)
 {
-  if (!mMapElement)
-    return;
+  nsImageFrame* imageFrame = do_QueryFrame(mContent->GetPrimaryFrame());
 
-  nsCOMPtr<nsIDOMHTMLCollection> mapAreas;
-  mMapElement->GetAreas(getter_AddRefs(mapAreas));
-  if (!mapAreas)
+  // If image map is not initialized yet then we trigger one time more later.
+  nsImageMap* imageMapObj = imageFrame->GetExistingImageMap();
+  if (!imageMapObj)
     return;
 
-  nsDocAccessible* document = Document();
+  bool doReorderEvent = false;
+
+  // Remove areas that are not a valid part of the image map anymore.
+  for (PRInt32 childIdx = mChildren.Length() - 1; childIdx >= 0; childIdx--) {
+    nsAccessible* area = mChildren.ElementAt(childIdx);
+    if (area->GetContent()->GetPrimaryFrame())
+      continue;
 
-  PRUint32 areaCount = 0;
-  mapAreas->GetLength(&areaCount);
+    if (aDoFireEvents) {
+      nsRefPtr<AccEvent> event = new AccHideEvent(area, area->GetContent());
+      mDoc->FireDelayedAccessibleEvent(event);
+      doReorderEvent = true;
+    }
+
+    RemoveChild(area);
+  }
 
-  for (PRUint32 areaIdx = 0; areaIdx < areaCount; areaIdx++) {
-    nsCOMPtr<nsIDOMNode> areaNode;
-    mapAreas->Item(areaIdx, getter_AddRefs(areaNode));
-    if (!areaNode)
-      return;
+  // Insert new areas into the tree.
+  PRUint32 areaElmCount = imageMapObj->AreaCount();
+  for (PRUint32 idx = 0; idx < areaElmCount; idx++) {
+    nsIContent* areaContent = imageMapObj->GetAreaAt(idx);
+
+    nsAccessible* area = mChildren.SafeElementAt(idx);
+    if (!area || area->GetContent() != areaContent) {
+      nsRefPtr<nsAccessible> area = new nsHTMLAreaAccessible(areaContent, mDoc);
+      if (!mDoc->BindToDocument(area, nsAccUtils::GetRoleMapEntry(areaContent)))
+        break;
 
-    nsCOMPtr<nsIContent> areaContent(do_QueryInterface(areaNode));
-    nsRefPtr<nsAccessible> area =
-      new nsHTMLAreaAccessible(areaContent, mDoc);
+      if (!InsertChildAt(idx, area)) {
+        mDoc->UnbindFromDocument(area);
+        break;
+      }
 
-    if (!document->BindToDocument(area, nsAccUtils::GetRoleMapEntry(areaContent)) ||
-        !AppendChild(area)) {
-      return;
+      if (aDoFireEvents) {
+        nsRefPtr<AccEvent> event = new AccShowEvent(area, areaContent);
+        mDoc->FireDelayedAccessibleEvent(event);
+        doReorderEvent = true;
+      }
     }
   }
+
+  // Fire reorder event if needed.
+  if (doReorderEvent) {
+    nsRefPtr<AccEvent> reorderEvent =
+      new AccEvent(nsIAccessibleEvent::EVENT_REORDER, mContent,
+                   eAutoDetect, AccEvent::eCoalesceFromSameSubtree);
+    mDoc->FireDelayedAccessibleEvent(reorderEvent);
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLImageMapAccessible: nsAccessible protected
+
+void
+nsHTMLImageMapAccessible::CacheChildren()
+{
+  UpdateChildAreas(false);
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLAreaAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLAreaAccessible::
@@ -222,16 +259,27 @@ nsHTMLAreaAccessible::GetBounds(PRInt32 
   nsIntRect orgRectPixels = frame->GetScreenRectExternal();
   *aX += orgRectPixels.x;
   *aY += orgRectPixels.y;
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// nsHTMLAreaAccessible: nsAccessNode public
+
+bool
+nsHTMLAreaAccessible::IsPrimaryForNode() const
+{
+  // Make HTML area DOM element not accessible. HTML image map accessible
+  // manages its tree itself.
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // nsHTMLAreaAccessible: nsAccessible public
 
 PRUint64
 nsHTMLAreaAccessible::NativeState()
 {
   // Bypass the link states specialization for non links.
   if (mRoleMapEntry &&
       mRoleMapEntry->role != roles::NOTHING &&
--- a/accessible/src/html/nsHTMLImageMapAccessible.h
+++ b/accessible/src/html/nsHTMLImageMapAccessible.h
@@ -46,54 +46,68 @@
 #include "nsIDOMHTMLMapElement.h"
 
 /**
  * Used for HTML image maps.
  */
 class nsHTMLImageMapAccessible : public nsHTMLImageAccessibleWrap
 {
 public:
-  nsHTMLImageMapAccessible(nsIContent* aContent, nsDocAccessible* aDoc,
-                           nsIDOMHTMLMapElement* aMapElm);
+  nsHTMLImageMapAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
+  virtual ~nsHTMLImageMapAccessible() { }
 
   // nsISupports and cycle collector
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsAccessible
   virtual mozilla::a11y::role NativeRole();
 
   // HyperLinkAccessible
   virtual PRUint32 AnchorCount();
   virtual nsAccessible* AnchorAt(PRUint32 aAnchorIndex);
   virtual already_AddRefed<nsIURI> AnchorURIAt(PRUint32 aAnchorIndex);
 
+  /**
+   * Update area children of the image map.
+   */
+  void UpdateChildAreas(bool aDoFireEvents = true);
+
 protected:
 
   // nsAccessible
   virtual void CacheChildren();
+};
 
-private:
-  // Reference on linked map element if any.
-  nsCOMPtr<nsIDOMHTMLMapElement> mMapElement;
-};
+////////////////////////////////////////////////////////////////////////////////
+// nsAccessible downcasting method
+
+inline nsHTMLImageMapAccessible*
+nsAccessible::AsImageMap()
+{
+  return IsImageMapAccessible() ?
+    static_cast<nsHTMLImageMapAccessible*>(this) : nsnull;
+}
 
 
 /**
  * Accessible for image map areas - must be child of image.
  */
 class nsHTMLAreaAccessible : public nsHTMLLinkAccessible
 {
 public:
 
   nsHTMLAreaAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
 
   // nsIAccessible
 
   NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height);
 
+  // nsAccessNode
+  virtual bool IsPrimaryForNode() const;
+
   // nsAccessible
   virtual void Description(nsString& aDescription);
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual PRUint64 NativeState();
   virtual nsAccessible* ChildAtPoint(PRInt32 aX, PRInt32 aY,
                                      EWhichChildAtPoint aWhichChild);
 
   // HyperLinkAccessible
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -481,16 +481,31 @@ function testDefunctAccessible(aAcc, aNo
   try {
     aAcc.parent;
   } catch (e) {
     success = (e.result == Components.results.NS_ERROR_FAILURE);
   }
   ok(success, "parent" + msg);
 }
 
+/**
+ * Ensure that image map accessible tree is created.
+ */
+function ensureImageMapTree(aID)
+{
+  // XXX: We send a useless mouse move to the image to force it to setup its
+  // image map, because flushing layout won't do it. Hopefully bug 135040
+  // will make this not suck.
+  synthesizeMouse(getNode(aID), 10, 10, { type: "mousemove" });
+
+  // XXX This may affect a11y more than other code because imagemaps may not
+  // get drawn or have an mouse event over them. Bug 570322 tracks a11y
+  // dealing with this.
+  todo(false, "Need to remove this image map workaround.");
+}
 
 /**
  * Convert role to human readable string.
  */
 function roleToString(aRole)
 {
   return gAccRetrieval.getStringRole(aRole);
 }
--- a/accessible/tests/mochitest/hyperlink/test_general.html
+++ b/accessible/tests/mochitest/hyperlink/test_general.html
@@ -4,16 +4,18 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=418368
 -->
 <head>
   <title>nsIHyperLinkAccessible chrome tests</title>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
   <script type="application/javascript"
@@ -83,16 +85,18 @@ https://bugzilla.mozilla.org/show_bug.cg
       // ARIA hyperlink with status invalid
       var invalidAriaHyperlinkAcc = getAccessible("InvalidAriaHyperlink",
                                                   [nsIAccessibleHyperLink]);
       is(invalidAriaHyperlinkAcc.valid, false, "Should not be valid!");
       testStates(invalidAriaHyperlinkAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
 
       //////////////////////////////////////////////////////////////////////////
       // image map and its link children
+      ensureImageMapTree("imgmap");
+
       var imageMapHyperlinkAcc = getAccessible("imgmap",
                                                [nsIAccessibleHyperLink]);
       testThis("imgmap", imageMapHyperlinkAcc, ROLE_IMAGE_MAP, 2, "b", true,
                79, 80);
       is(imageMapHyperlinkAcc.getURI(0).spec,
          "http://www.bbc.co.uk/radio4/atoz/index.shtml#b", "URI wrong!");
       is(imageMapHyperlinkAcc.getURI(1).spec,
          "http://www.bbc.co.uk/radio4/atoz/index.shtml#a", "URI wrong!");
@@ -263,17 +267,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     ><area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#a"
            coords="0,0,13,14"
            alt="a"
            shape="rect"></area
     ></map
   ><img width="447" id="imgmap"
         height="15"
         usemap="#atoz_map"
-        src="letters.gif"><br>Empty link:<br
+        src="../letters.gif"><br>Empty link:<br
   ><a id="emptyLink" href=""><img src=""></a
   ><br>Link with embedded span<br
   ><a id="LinkWithSpan" href="http://www.heise.de/"><span lang="de">Heise Online</span></a
   ><br>Named anchor, must not have "linked" state for it to be exposed correctly:<br
   ><a id="namedAnchor" name="named_anchor">This should never be of state_linked</a
   ><br>Link having no attributes, must not have "linked" state:<a id="noLink"
   >This should never be of state_linked</a
   ><br>Link with registered 'click' event: <a id="linkWithClick" onclick="var clicked = true;"
--- a/accessible/tests/mochitest/hypertext/test_general.html
+++ b/accessible/tests/mochitest/hypertext/test_general.html
@@ -4,16 +4,18 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=428248
 -->
 <head>
   <title>nsIHyper>TextAccessible chrome tests</title>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 
   <script type="application/javascript"
           src="../common.js"></script>
 
   <script type="application/javascript">
     var gParagraphAcc;
 
     function testLinkIndexAtOffset(aID, aOffset, aIndex)
@@ -48,16 +50,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
       // ARIA hyperlink
       testThis("AriaHyperlink", 27, 1, "Mozilla Foundation Home");
 
       // ARIA hyperlink with status invalid
       testThis("InvalidAriaHyperlink", 63, 2, "Invalid link");
 
       // image map, but not its link children. They are not part of hypertext.
+      ensureImageMapTree("imgmap");
       testThis("imgmap", 76, 3, "b");
 
       // empty hyperlink
       testThis("emptyLink", 90, 4, null);
 
       // normal hyperlink with embedded span
       testThis("LinkWithSpan", 116, 5, "Heise Online");
 
@@ -126,17 +129,17 @@ https://bugzilla.mozilla.org/show_bug.cg
                               shape="rect"></area
    ><area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#a"
           coords="0,0,13,14"
           alt="a"
           shape="rect"></area></map
    ><img width="447" id="imgmap"
          height="15"
          usemap="#atoz_map"
-         src="letters.gif"></img><br
+         src="../letters.gif"></img><br
   >Empty link:<br
   ><a id="emptyLink" href=""><img src=""></img></a><br
   >Link with embedded span<br
   ><a id="LinkWithSpan" href="http://www.heise.de/"><span lang="de">Heise Online</span></a><br
   >Named anchor, must not have "linked" state for it to be exposed correctly:<br
   ><a id="namedAnchor" name="named_anchor">This should never be of state_linked</a>
   </p>
   <p id="p2"><a href="http://mozilla.org">mozilla.org</a></p>
--- a/accessible/tests/mochitest/states/test_aria_imgmap.html
+++ b/accessible/tests/mochitest/states/test_aria_imgmap.html
@@ -14,31 +14,32 @@
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
 
   <script type="application/javascript">
   function doTest()
   {
-    //XXX We send a useless mouse move to the image to force it to setup its
-    // image map, because flushing layout won't do it. Hopefully bug 135040
-    // will make this not suck.
-    synthesizeMouse($("imagemap"), 10, 10, { type: "mousemove" });
-    //XXX This may affect a11y more than other code because imagemaps may not
-    // get drawn or have an mouse event over them. Bug 570322 tracks a11y
-    // dealing with this.
-    todo(false, "Need to remove this image map workaround.");
+    ensureImageMapTree("imagemap");
+
+    var imageMap = getAccessible("imagemap");
 
-    testStates("t1", 0, EXT_STATE_EDITABLE, STATE_LINKED);
-    testStates("t2", 0, EXT_STATE_EDITABLE, STATE_LINKED);
-    testStates("rb1", (STATE_CHECKABLE | STATE_CHECKED), 0, STATE_LINKED);
-    testStates("rb2", STATE_CHECKABLE, 0, STATE_CHECKED, STATE_LINKED);
-    testStates("cb1", (STATE_CHECKABLE | STATE_CHECKED), 0, STATE_LINKED);
-    testStates("cbox", (STATE_HASPOPUP | STATE_COLLAPSED),
+    var t1 = imageMap.getChildAt(0);
+    testStates(t1, 0, EXT_STATE_EDITABLE, STATE_LINKED);
+    var t2 = imageMap.getChildAt(1);
+    testStates(t2, 0, EXT_STATE_EDITABLE, STATE_LINKED);
+    var rb1 = imageMap.getChildAt(2);
+    testStates(rb1, (STATE_CHECKABLE | STATE_CHECKED), 0, STATE_LINKED);
+    var rb2 = imageMap.getChildAt(3);
+    testStates(rb2, STATE_CHECKABLE, 0, STATE_CHECKED, STATE_LINKED);
+    var cb1 = imageMap.getChildAt(4);
+    testStates(cb1, (STATE_CHECKABLE | STATE_CHECKED), 0, STATE_LINKED);
+    var cbox = imageMap.getChildAt(5);
+    testStates(cbox, (STATE_HASPOPUP | STATE_COLLAPSED),
                EXT_STATE_EXPANDABLE, STATE_LINKED);
 
     SimpleTest.finish();
   }
 
   SimpleTest.waitForExplicitFinish();
   addA11yLoadEvent(doTest);
   </script>
--- a/accessible/tests/mochitest/tree/test_aria_imgmap.html
+++ b/accessible/tests/mochitest/tree/test_aria_imgmap.html
@@ -14,24 +14,17 @@
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
 
   <script type="application/javascript">
   function doTest()
   {
-    //XXX We send a useless mouse move to the image to force it to setup its
-    // image map, because flushing layout won't do it. Hopefully bug 135040
-    // will make this not suck.
-    synthesizeMouse($("imagemap"), 10, 10, { type: "mousemove" });
-    //XXX This may affect a11y more than other code because imagemaps may not
-    // get drawn or have an mouse event over them. Bug 570322 tracks a11y
-    // dealing with this.
-    todo(false, "Need to remove this image map workaround.");
+    ensureImageMapTree("imagemap");
 
     var accTree = {
       role: ROLE_IMAGE_MAP,
       children: [
         {
           role: ROLE_ENTRY,
           name: "first name"
         },
--- a/accessible/tests/mochitest/treeupdate/Makefile.in
+++ b/accessible/tests/mochitest/treeupdate/Makefile.in
@@ -49,16 +49,17 @@ include $(topsrcdir)/config/rules.mk
 		test_ariadialog.html \
 		test_canvas.html \
 		test_colorpicker.xul \
 		test_cssoverflow.html \
 		test_contextmenu.xul \
 		test_doc.html \
 		test_gencontent.html \
 		test_hidden.html \
+		test_imagemap.html \
 		test_list_editabledoc.html \
 		test_list.html \
 		test_menu.xul \
 		test_menubutton.xul \
 		test_recreation.html \
 		test_select.html \
 		test_textleaf.html \
 		test_visibility.html \
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_imagemap.html
@@ -0,0 +1,394 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>HTML img map accessible tree update tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+    function insertArea(aImageMapID, aMapID)
+    {
+      this.imageMap = getAccessible(aImageMapID);
+      this.mapNode = getNode(aMapID);
+
+      function getInsertedArea(aThisObj)
+      {
+        return aThisObj.imageMap.firstChild;
+      }
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_SHOW, getInsertedArea, this),
+        new invokerChecker(EVENT_REORDER, this.imageMap)
+      ];
+
+      this.invoke = function insertArea_invoke()
+      {
+        var areaElm = document.createElement("area");
+        areaElm.setAttribute("href",
+                             "http://www.bbc.co.uk/radio4/atoz/index.shtml#a");
+        areaElm.setAttribute("coords", "0,0,13,14");
+        areaElm.setAttribute("alt", "a");
+        areaElm.setAttribute("shape", "rect");
+
+        this.mapNode.insertBefore(areaElm, this.mapNode.firstChild);
+      }
+
+      this.finalCheck = function insertArea_finalCheck()
+      {
+        var accTree =
+          { IMAGE_MAP: [
+            {
+              role: ROLE_LINK,
+              name: "a",
+              children: [ ]
+            },
+            {
+              role: ROLE_LINK,
+              name: "b",
+              children: [ ]
+            },
+          ] };
+        testAccessibleTree(this.imageMap, accTree);
+      }
+
+      this.getID = function insertArea_getID()
+      {
+        return "insert area element";
+      }
+    }
+
+    function appendArea(aImageMapID, aMapID)
+    {
+      this.imageMap = getAccessible(aImageMapID);
+      this.mapNode = getNode(aMapID);
+
+      function getAppendedArea(aThisObj)
+      {
+        return aThisObj.imageMap.lastChild;
+      }
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_SHOW, getAppendedArea, this),
+        new invokerChecker(EVENT_REORDER, this.imageMap)
+      ];
+
+      this.invoke = function appendArea_invoke()
+      {
+        var areaElm = document.createElement("area");
+        areaElm.setAttribute("href",
+                             "http://www.bbc.co.uk/radio4/atoz/index.shtml#c");
+        areaElm.setAttribute("coords", "34,0,47,14");
+        areaElm.setAttribute("alt", "c");
+        areaElm.setAttribute("shape", "rect");
+
+        this.mapNode.appendChild(areaElm);
+      }
+
+      this.finalCheck = function appendArea_finalCheck()
+      {
+        var accTree =
+          { IMAGE_MAP: [
+            {
+              role: ROLE_LINK,
+              name: "a",
+              children: [ ]
+            },
+            {
+              role: ROLE_LINK,
+              name: "b",
+              children: [ ]
+            },
+            {
+              role: ROLE_LINK,
+              name: "c",
+              children: [ ]
+            }
+          ] };
+        testAccessibleTree(this.imageMap, accTree);
+      }
+
+      this.getID = function appendArea_getID()
+      {
+        return "append area element";
+      }
+    }
+
+    function removeArea(aImageMapID, aMapID)
+    {
+      this.imageMap = getAccessible(aImageMapID);
+      this.area = null;
+      this.mapNode = getNode(aMapID);
+
+      function getRemovedArea(aThisObj)
+      {
+        return aThisObj.area;
+      }
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getRemovedArea, this),
+        new invokerChecker(EVENT_REORDER, this.imageMap)
+      ];
+
+      this.invoke = function removeArea_invoke()
+      {
+        this.area = this.imageMap.firstChild;
+        this.mapNode.removeChild(this.mapNode.firstElementChild);
+      }
+
+      this.finalCheck = function removeArea_finalCheck()
+      {
+        var accTree =
+          { IMAGE_MAP: [
+            {
+              role: ROLE_LINK,
+              name: "b",
+              children: [ ]
+            },
+            {
+              role: ROLE_LINK,
+              name: "c",
+              children: [ ]
+            }
+          ] };
+        testAccessibleTree(this.imageMap, accTree);
+      }
+
+      this.getID = function removeArea_getID()
+      {
+        return "remove area element";
+      }
+    }
+
+    function removeNameOnMap(aImageMapContainerID, aImageMapID, aMapID)
+    {
+      this.container = getAccessible(aImageMapContainerID);
+      this.containerNode = this.container.DOMNode;
+      this.imageMap = getAccessible(aImageMapID);
+      this.imgNode = this.imageMap.DOMNode;
+      this.mapNode = getNode(aMapID);
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, this.imageMap),
+        new invokerChecker(EVENT_SHOW, this.imgNode),
+        new invokerChecker(EVENT_REORDER, this.container)
+      ];
+
+      this.invoke = function removeNameOnMap_invoke()
+      {
+        this.mapNode.removeAttribute("name");
+      }
+
+      this.finalCheck = function removeNameOnMap_finalCheck()
+      {
+        var accTree =
+          { SECTION: [
+            { GRAPHIC: [ ] }
+          ] };
+        testAccessibleTree(this.container, accTree);
+      }
+
+      this.getID = function removeNameOnMap_getID()
+      {
+        return "remove @name on map element";
+      }
+    }
+
+    function restoreNameOnMap(aImageMapContainerID, aImageMapID, aMapID)
+    {
+      this.container = getAccessible(aImageMapContainerID);
+      this.containerNode = this.container.DOMNode;
+      this.imageMap = null;
+      this.imgNode = getNode(aImageMapID);
+      this.mapNode = getNode(aMapID);
+
+      function getImageMap(aThisObj)
+      {
+        return aThisObj.imageMap;
+      }
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getImageMap, this),
+        new invokerChecker(EVENT_SHOW, this.imgNode),
+        new invokerChecker(EVENT_REORDER, this.container)
+      ];
+
+      this.invoke = function restoreNameOnMap_invoke()
+      {
+        this.imageMap = getAccessible(aImageMapID);
+        this.mapNode.setAttribute("name", "atoz_map");
+      }
+
+      this.finalCheck = function removeNameOnMap_finalCheck()
+      {
+        var accTree =
+          { SECTION: [
+            { IMAGE_MAP: [
+              { LINK: [ ] },
+              { LINK: [ ] }
+            ] }
+          ] };
+        testAccessibleTree(this.container, accTree);
+      }
+
+      this.getID = function removeNameOnMap_getID()
+      {
+        return "restore @name on map element";
+      }
+    }
+
+    function removeMap(aImageMapContainerID, aImageMapID, aMapID)
+    {
+      this.container = getAccessible(aImageMapContainerID);
+      this.containerNode = this.container.DOMNode;
+      this.imageMap = null;
+      this.imgNode = getNode(aImageMapID);
+      this.mapNode = getNode(aMapID);
+
+      function getImageMap(aThisObj)
+      {
+        return aThisObj.imageMap;
+      }
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getImageMap, this),
+        new invokerChecker(EVENT_SHOW, this.imgNode),
+        new invokerChecker(EVENT_REORDER, this.container)
+      ];
+
+      this.invoke = function removeMap_invoke()
+      {
+        this.imageMap = getAccessible(aImageMapID);
+        this.mapNode.parentNode.removeChild(this.mapNode);
+      }
+
+      this.finalCheck = function removeMap_finalCheck()
+      {
+        var accTree =
+          { SECTION: [
+            { GRAPHIC: [ ] }
+          ] };
+        testAccessibleTree(this.container, accTree);
+      }
+
+      this.getID = function removeMap_getID()
+      {
+        return "remove map element";
+      }
+    }
+
+    function insertMap(aImageMapContainerID, aImageID)
+    {
+      this.container = getAccessible(aImageMapContainerID);
+      this.containerNode = this.container.DOMNode;
+      this.image = null;
+      this.imgMapNode = getNode(aImageID);
+
+      function getImage(aThisObj)
+      {
+        return aThisObj.image;
+      }
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getImage, this),
+        new invokerChecker(EVENT_SHOW, this.imgMapNode),
+        new invokerChecker(EVENT_REORDER, this.container)
+      ];
+
+      this.invoke = function insertMap_invoke()
+      {
+        this.image = getAccessible(aImageID);
+
+        var map = document.createElement("map");
+        map.setAttribute("name", "atoz_map");
+        map.setAttribute("id", "map");
+
+        var area = document.createElement("area")
+        area.setAttribute("href",
+                          "http://www.bbc.co.uk/radio4/atoz/index.shtml#b");
+        area.setAttribute("coords", "17,0,30,14");
+        area.setAttribute("alt", "b");
+        area.setAttribute("shape", "rect");
+
+        map.appendChild(area);
+
+        this.containerNode.appendChild(map);
+
+        ensureImageMapTree(aImageID);
+      }
+
+      this.finalCheck = function insertMap_finalCheck()
+      {
+        var accTree =
+          { SECTION: [
+            { IMAGE_MAP: [
+              { LINK: [ ] }
+            ] }
+          ] };
+        testAccessibleTree(this.container, accTree);
+      }
+
+      this.getID = function insertMap_getID()
+      {
+        return "insert map element";
+      }
+    }
+
+    //gA11yEventDumpToConsole = true;
+
+    var gQueue = null;
+    function doTest()
+    {
+      gQueue = new eventQueue();
+
+      gQueue.push(new insertArea("imgmap", "map"));
+      gQueue.push(new appendArea("imgmap", "map"));
+      gQueue.push(new removeArea("imgmap", "map"));
+      gQueue.push(new removeNameOnMap("container", "imgmap", "map"));
+      gQueue.push(new restoreNameOnMap("container", "imgmap", "map"));
+      gQueue.push(new removeMap("container", "imgmap", "map"));
+      gQueue.push(new insertMap("container", "imgmap"));
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     title="Image map accessible tree is not updated when image map is changed"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=732389">
+    Mozilla Bug 732389
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <map name="atoz_map" id="map">
+    <area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#b"
+          coords="17,0,30,14" alt="b" shape="rect">
+  </map>
+
+  <div id="container">
+    <img id="imgmap" width="447" height="15"
+         usemap="#atoz_map"
+         src="../letters.gif">
+  </div>
+
+</body>
+</html>
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -14,16 +14,17 @@ builtin(include, build/autoconf/mozprog.
 builtin(include, build/autoconf/mozheader.m4)dnl
 builtin(include, build/autoconf/mozcommonheader.m4)dnl
 builtin(include, build/autoconf/acwinpaths.m4)dnl
 builtin(include, build/autoconf/lto.m4)dnl
 builtin(include, build/autoconf/gcc-pr49911.m4)dnl
 builtin(include, build/autoconf/frameptr.m4)dnl
 builtin(include, build/autoconf/compiler-opts.m4)dnl
 builtin(include, build/autoconf/expandlibs.m4)dnl
+builtin(include, build/autoconf/arch.m4)dnl
 
 MOZ_PROG_CHECKMSYS()
 
 # Read the user's .mozconfig script.  We can't do this in
 # configure.in: autoconf puts the argument parsing code above anything
 # expanded from configure.in, and we need to get the configure options
 # from .mozconfig in place before that argument parsing code.
 MOZ_READ_MOZCONFIG(.)
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -142,17 +142,17 @@ pref("browser.formfill.enable", true);
 /* spellcheck */
 pref("layout.spellcheckDefault", 0);
 
 /* block popups by default, and notify the user about blocked popups */
 pref("dom.disable_open_during_load", true);
 pref("privacy.popups.showBrowserMessage", true);
 
 pref("keyword.enabled", true);
-pref("keyword.URL", "http://www.google.com/m?ie=UTF-8&oe=UTF-8&sourceid=navclient&gfns=1&q=");
+pref("keyword.URL", "https://www.google.com/m?ie=UTF-8&oe=UTF-8&sourceid=navclient&gfns=1&q=");
 
 pref("accessibility.typeaheadfind", false);
 pref("accessibility.typeaheadfind.timeout", 5000);
 pref("accessibility.typeaheadfind.flashBar", 1);
 pref("accessibility.typeaheadfind.linksonly", false);
 pref("accessibility.typeaheadfind.casesensitive", 0);
 
 // pointer to the default engine name
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -12,16 +12,17 @@ const Cr = Components.results;
 
 const LocalFile = CC('@mozilla.org/file/local;1',
                      'nsILocalFile',
                      'initWithPath');
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/ContactService.jsm');
+Cu.import('resource://gre/modules/Webapps.jsm');
 
 XPCOMUtils.defineLazyGetter(Services, 'env', function() {
   return Cc['@mozilla.org/process/environment;1']
            .getService(Ci.nsIEnvironment);
 });
 
 XPCOMUtils.defineLazyGetter(Services, 'ss', function() {
   return Cc['@mozilla.org/content/style-sheet-service;1']
@@ -61,17 +62,17 @@ function startupHttpd(baseDir, port) {
 
 // FIXME Bug 707625
 // until we have a proper security model, add some rights to
 // the pre-installed web applications
 // XXX never grant 'content-camera' to non-gaia apps
 function addPermissions(urls) {
   let permissions = [
     'indexedDB', 'indexedDB-unlimited', 'webapps-manage', 'offline-app',
-    'content-camera', 'webcontacts-manage', 'wifi-manage'
+    'content-camera', 'webcontacts-manage', 'wifi-manage', 'desktop-notification'
   ];
   urls.forEach(function(url) {
     let uri = Services.io.newURI(url, null, null);
     let allow = Ci.nsIPermissionManager.ALLOW_ACTION;
 
     permissions.forEach(function(permission) {
       Services.perms.add(uri, permission, allow);
     });
@@ -160,16 +161,20 @@ var shell = {
     // Load webapi.js as a frame script
     let frameScriptUrl = 'chrome://browser/content/webapi.js';
     try {
       messageManager.loadFrameScript(frameScriptUrl, true);
     } catch (e) {
       dump('Error loading ' + frameScriptUrl + ' as a frame script: ' + e + '\n');
     }
 
+    CustomEventManager.init();
+
+    WebappsHelper.init();
+
     let browser = this.contentBrowser;
     browser.homePage = homeURL;
     browser.goHome();
   },
 
   stop: function shell_stop() {
     window.removeEventListener('MozApplicationManifest', this);
     window.removeEventListener('mozfullscreenchange', this);
@@ -416,8 +421,75 @@ Services.obs.addObserver(function onCons
   let serverPort = Services.prefs.getIntPref('b2g.remote-js.port');
   let serverSocket = Cc['@mozilla.org/network/server-socket;1']
                        .createInstance(Ci.nsIServerSocket);
   serverSocket.init(serverPort, true, -1);
   dump('Opened socket on ' + serverSocket.port + '\n');
   serverSocket.asyncListen(listener);
 })();
 
+CustomEventManager = {
+  init: function custevt_init() {
+    window.addEventListener("ContentStart", (function(evt) {
+      content.addEventListener("mozContentEvent", this, false, true);
+    }).bind(this), false);
+  },
+
+  handleEvent: function custevt_handleEvent(evt) {
+    let detail = evt.detail;
+    dump("XXX FIXME : Got a mozContentEvent: " + detail.type);
+
+    switch(detail.type) {
+      case "desktop-notification-click":
+      case "desktop-notification-close":
+        AlertsHelper.handleEvent(detail);
+        break;
+    }
+  }
+}
+
+AlertsHelper = {
+  _listeners: {},
+  _count: 0,
+
+  handleEvent: function alert_handleEvent(detail) {
+    if (!detail || !detail.id)
+      return;
+
+    let listener = this._listeners[detail.id];
+    let topic = detail.type == "desktop-notification-click" ? "alertclickcallback" : "alertfinished";
+    listener.observer.observe(null, topic, listener.cookie);
+
+    // we're done with this notification
+    if (topic === "alertfinished")
+      delete this._listeners[detail.id];
+  },
+
+  registerListener: function alert_registerListener(cookie, alertListener) {
+    let id = "alert" + this._count++;
+    this._listeners[id] = { observer: alertListener, cookie: cookie };
+    return id;
+  },
+
+  showAlertNotification: function alert_showAlertNotification(imageUrl, title, text, textClickable, 
+                                                              cookie, alertListener, name) {
+    let id = this.registerListener(cookie, alertListener);
+    shell.sendEvent(content, "mozChromeEvent", { type: "desktop-notification", id: id, icon: imageUrl, 
+                                                 title: title, text: text } );
+  }
+}
+
+WebappsHelper = {
+  init: function webapps_init() {
+    Services.obs.addObserver(this, "webapps-launch", false);
+  },
+
+  observe: function webapps_observe(subject, topic, data) {
+    let json = JSON.parse(data);
+    DOMApplicationRegistry.getManifestFor(json.origin, function(aManifest) {
+      if (!aManifest)
+        return;
+
+      let manifest = new DOMApplicationManifest(aManifest, json.origin);
+      shell.sendEvent(content, "mozChromeEvent", { type: "webapps-launch", url: manifest.fullLaunchPath(), origin: json.origin });
+    });
+  }
+}
new file mode 100644
--- /dev/null
+++ b/b2g/components/AlertsService.js
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+// -----------------------------------------------------------------------
+// Alerts Service
+// -----------------------------------------------------------------------
+
+function AlertsService() { }
+
+AlertsService.prototype = {
+  classID: Components.ID("{5dce03b2-8faa-4b6e-9242-6ddb0411750c}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService]),
+
+  showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener, aName) {
+    let browser = Services.wm.getMostRecentWindow("navigator:browser");
+    browser.AlertsHelper.showAlertNotification(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener, aName);
+  }
+};
+
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([AlertsService]);
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -1,7 +1,15 @@
 # Scrollbars
 category agent-style-sheets browser-content-stylesheet chrome://browser/content/content.css
 
 # CameraContent.js
 component {eff4231b-abce-4f7f-a40a-d646e8fde3ce} CameraContent.js
 contract @mozilla.org/b2g-camera-content;1 {eff4231b-abce-4f7f-a40a-d646e8fde3ce}
 category JavaScript-navigator-property mozCamera @mozilla.org/b2g-camera-content;1
+
+# AlertsService.js
+component {5dce03b2-8faa-4b6e-9242-6ddb0411750c} AlertsService.js
+contract @mozilla.org/alerts-service;1 {5dce03b2-8faa-4b6e-9242-6ddb0411750c}
+
+# ContentPermissionPrompt.js
+component {8c719f03-afe0-4aac-91ff-6c215895d467} ContentPermissionPrompt.js
+contract @mozilla.org/content-permission/prompt;1 {8c719f03-afe0-4aac-91ff-6c215895d467}
--- a/b2g/components/CameraContent.js
+++ b/b2g/components/CameraContent.js
@@ -57,17 +57,17 @@ CameraContent.prototype = {
 
   init: function(aWindow) {
     let principal = aWindow.document.nodePrincipal;
     let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
 
     let perm = principal == secMan.getSystemPrincipal() ? Ci.nsIPermissionManager.ALLOW_ACTION : Services.perms.testExactPermission(principal.URI, "content-camera");
 
     //only pages with perm set and chrome pages can use the camera in content
-    this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION || from.schemeIs("chrome");
+    this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
 
     Services.obs.addObserver(this, "inner-window-destroyed", false);
     let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
     this.innerWindowID = util.currentInnerWindowID;
   },
  
   classID: Components.ID("{eff4231b-abce-4f7f-a40a-d646e8fde3ce}"),
 
new file mode 100644
--- /dev/null
+++ b/b2g/components/ContentPermissionPrompt.js
@@ -0,0 +1,45 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const Ci = Components.interfaces;
+const Cr = Components.results;
+const Cu = Components.utils;
+const Cc = Components.classes;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+function ContentPermissionPrompt() {}
+
+ContentPermissionPrompt.prototype = {
+
+  handleExistingPermission: function handleExistingPermission(request) {
+    let result = Services.perms.testExactPermission(request.uri, request.type);
+    if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
+      request.allow();
+      return true;
+    }
+    if (result == Ci.nsIPermissionManager.DENY_ACTION) {
+      request.cancel();
+      return true;
+    }
+    return false;
+  },
+
+  prompt: function(request) {
+    // returns true if the request was handled
+    if (this.handleExistingPermission(request))
+       return;
+
+    // TODO : show UI to grant or deny permission
+  },
+
+  classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
+};
+
+
+//module initialization
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]);
--- a/b2g/components/Makefile.in
+++ b/b2g/components/Makefile.in
@@ -46,11 +46,13 @@ XPIDL_MODULE = B2GComponents
 
 XPIDLSRCS = \
         b2g.idl \
         $(NULL)
 
 EXTRA_PP_COMPONENTS = \
         B2GComponents.manifest \
         CameraContent.js \
+        AlertsService.js \
+        ContentPermissionPrompt.js \
         $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/b2g/config/mozconfigs/linux32/debug
+++ b/b2g/config/mozconfigs/linux32/debug
@@ -1,15 +1,15 @@
 #GONK_TOOLCHAIN_VERSION=0
 #export GONK_PRODUCT=generic
 #gonk="/home/cjones/mozilla/gonk-toolchain-$GONK_TOOLCHAIN_VERSION"
 
-mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-prof-gonk
+mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-b2g
 
-mk_add_options MOZ_MAKE_FLAGS="-s -j16"
+mk_add_options MOZ_MAKE_FLAGS="-j8"
 
 ac_add_options --enable-application=b2g
 
 ac_add_options --target=arm-android-eabi
 ac_add_options --with-gonk="$gonk"
 ac_add_options --with-endian=little
 ac_add_options --disable-elf-hack
 ac_add_options --enable-debug-symbols
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -139,16 +139,17 @@
 @BINPATH@/components/content_htmldoc.xpt
 @BINPATH@/components/content_html.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_apps.xpt
 @BINPATH@/components/dom_base.xpt
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/dom_telephony.xpt
 @BINPATH@/components/dom_wifi.xpt
 @BINPATH@/components/dom_system_gonk.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
 #ifdef MOZ_B2G_BT
@@ -285,17 +286,16 @@
 @BINPATH@/components/xpcom_threads.xpt
 @BINPATH@/components/xpcom_xpti.xpt
 @BINPATH@/components/xpconnect.xpt
 @BINPATH@/components/xulapp.xpt
 @BINPATH@/components/xul.xpt
 @BINPATH@/components/xuldoc.xpt
 @BINPATH@/components/xultmpl.xpt
 @BINPATH@/components/zipwriter.xpt
-@BINPATH@/components/webapps.xpt
 
 ; JavaScript components
 @BINPATH@/components/ConsoleAPI.manifest
 @BINPATH@/components/ConsoleAPI.js
 @BINPATH@/components/ContactManager.js
 @BINPATH@/components/ContactManager.manifest
 @BINPATH@/components/FeedProcessor.manifest
 @BINPATH@/components/FeedProcessor.js
@@ -402,20 +402,20 @@
 @BINPATH@/components/messageWakeupService.manifest
 @BINPATH@/components/nsFilePicker.js
 @BINPATH@/components/nsFilePicker.manifest
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/RadioInterfaceLayer.manifest
 @BINPATH@/components/RadioInterfaceLayer.js
 @BINPATH@/components/SmsDatabaseService.manifest
 @BINPATH@/components/SmsDatabaseService.js
-@BINPATH@/components/nsWifiWorker.js
-@BINPATH@/components/nsWifiWorker.manifest
-@BINPATH@/components/nsDOMWifiManager.js
-@BINPATH@/components/nsDOMWifiManager.manifest
+@BINPATH@/components/WifiWorker.js
+@BINPATH@/components/WifiWorker.manifest
+@BINPATH@/components/DOMWifiManager.js
+@BINPATH@/components/DOMWifiManager.manifest
 #endif
 #ifdef XP_MACOSX
 @BINPATH@/components/libalerts.dylib
 #endif
 #ifdef MOZ_ENABLE_DBUS
 @BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
 #endif
 @BINPATH@/components/nsINIProcessor.manifest
@@ -425,16 +425,18 @@
 #ifdef MOZ_SERVICES_SYNC
 @BINPATH@/components/SyncComponents.manifest
 @BINPATH@/components/Weave.js
 @BINPATH@/components/WeaveCrypto.manifest
 @BINPATH@/components/WeaveCrypto.js
 #endif
 @BINPATH@/components/TelemetryPing.js
 @BINPATH@/components/TelemetryPing.manifest
+@BINPATH@/components/Webapps.js
+@BINPATH@/components/Webapps.manifest
 
 ; Modules
 @BINPATH@/modules/*
 
 ; Safe Browsing
 @BINPATH@/components/nsURLClassifier.manifest
 @BINPATH@/components/nsUrlClassifierHashCompleter.js
 @BINPATH@/components/nsUrlClassifierListManager.js
@@ -610,8 +612,10 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 
 [b2g]
 @BINPATH@/chrome/icons/
 @BINPATH@/chrome/chrome@JAREXT@
 @BINPATH@/chrome/chrome.manifest
 @BINPATH@/components/B2GComponents.manifest
 @BINPATH@/components/B2GComponents.xpt
 @BINPATH@/components/CameraContent.js
+@BINPATH@/components/AlertsService.js
+@BINPATH@/components/ContentPermissionPrompt.js
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1331241604000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1331848989000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
@@ -60,18 +60,18 @@
                     </versionRange>
                   </emItem>
       <emItem  blockID="i13" id="{E8E88AB0-7182-11DF-904E-6045E0D72085}">
                         </emItem>
       <emItem  blockID="i64" id="royal@facebook.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i72" id="{4ED1F68A-5463-4931-9384-8FFF5ED91D92}">
-                        <versionRange  minVersion="0" maxVersion="3.4.1.194" severity="1">
+      <emItem  blockID="i72" os="WINNT" id="{4ED1F68A-5463-4931-9384-8FFF5ED91D92}">
+                        <versionRange  minVersion="3.4.1" maxVersion="3.4.1.194" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i53" id="{a3a5c777-f583-4fef-9380-ab4add1bc2a8}">
                         <versionRange  minVersion="2.0.3" maxVersion="2.0.3">
@@ -148,16 +148,20 @@
       <emItem  blockID="i19" id="{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}">
                         <versionRange  minVersion="1.1b1" maxVersion="1.1b1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i3" id="langpack-vi-VN@firefox.mozilla.org">
                         <versionRange  minVersion="2.0" maxVersion="2.0">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i73" id="a1g0a9g219d@a1.com">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i51" id="admin@youtubeplayer.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i52" id="ff-ext@youtube">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
deleted file mode 100644
index e6b80682e5f4a46023977fb26b65e36095832cce..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 82b2bb7f51fe39a9f2fce05d7e310c2378f46785..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
rename from browser/base/content/aboutHome.css
rename to browser/base/content/abouthome/aboutHome.css
--- a/browser/base/content/aboutHome.css
+++ b/browser/base/content/abouthome/aboutHome.css
@@ -19,16 +19,17 @@
  * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2010
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Marco Bonardo <mak77@bonardo.net> (original author)
  *   Mihai Sucan <mihai.sucan@gmail.com>
  *   Stephen Horlander <shorlander@mozilla.com>
+ *   Frank Yan <fyan@mozilla.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
@@ -36,349 +37,326 @@
  * 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 ***** */
 %endif
 
 html {
-  font-family: sans-serif;
-  background: -moz-Field;
-  color: -moz-FieldText;
+  font: message-box;
+  font-size: 100%;
+  background-color: hsl(0,0%,90%);
+  background-image: url(chrome://browser/content/abouthome/noise.png),
+                    -moz-linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.4));
+  background-attachment: fixed;
+  color: #000;
   height: 100%;
 }
 
 body {
-  display: inline-block;
-  position: relative;
   margin: 0;
+  height: 100%;
+}
+
+#container {
+  display: -moz-box;
+  -moz-box-orient: vertical;
   width: 100%;
   height: 100%;
 }
 
+input,
+button {
+  font-size: inherit;
+  font-family: inherit;
+}
+
 a {
+  color: -moz-nativehyperlinktext;
   text-decoration: none;
 }
 
-a:hover {
-  text-decoration: underline;
+.spacer {
+  -moz-box-flex: 1;
 }
 
-#brandStart {
+#topSection {
   text-align: center;
-  height: 19%;
-  max-height: 256px;
-  min-height: 92px;
 }
 
-#brandStartSpacer {
-  height: 6.5%;
-}
-
-#brandStartLogo {
-  height: 100%;
+#brandLogo {
+  height: 154px;
+  margin: 22px 0 31px;
 }
 
-#searchContainer {
-  height: 15%;
-  min-height: 90px;
-}
-
-#searchContainer::before {
-  content: " ";
-  display: block;
-  height: 23%;
+#searchForm,
+#snippets {
+  width: 470px;
 }
 
 #searchForm {
-  display: table;
-  width: 100%;
-  max-width: 1830px;
-  margin: 0 auto;
-}
-
-@media all and (max-height: 700px) {
-  #searchContainer { height: 20% }
-}
-
-@media all and (max-height: 500px) {
-  #searchContainer { height: 25% }
-}
-
-@media all and (max-height: 370px) {
-  #searchContainer { height: 30% }
+  display: -moz-box;
 }
 
 #searchLogoContainer {
-  display: table-cell;
-  width: 30%;
-  text-align: end;
-  line-height: 32px;
+  display: -moz-box;
+  -moz-box-align: center;
+  padding-top: 2px;
+  -moz-padding-end: 8px;
 }
 
 #searchEngineLogo {
-  -moz-margin-end: 2.5%;
-  vertical-align: middle;
-}
-
-#searchInputContainer {
-  display: table-cell;
-  width: 38%;
-  max-width: 700px;
-  min-width: 150px;
+  display: inline-block;
 }
 
 #searchText {
-  width: 100%;
-  height: 24px;
-  padding: 3px 6px;
-  border-radius: 2px;
-  border: 1px solid rgb(150,150,150);
-  border-top-color: rgb(100,100,100);
-  box-shadow: 0 1px 0 rgba(255,255,255,0.5);
-  font-size: 1.2em;
-}
-
-#searchButtons {
-  display: table-cell;
-  width: 31%;
-  -moz-padding-start: 13px;
-  vertical-align: top;
+  -moz-box-flex: 1;
+  padding: 6px 8px;
+  background: hsla(0,0%,100%,.9) padding-box;
+  border: 1px solid;
+  border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
+  box-shadow: 0 1px 0 hsla(210,65%,9%,.02) inset,
+              0 0 2px hsla(210,65%,9%,.1) inset,
+              0 1px 0 hsla(0,0%,100%,.2);
+  border-radius: 2.5px 0 0 2.5px;
 }
 
-@media all and (max-width: 470px) {
-  #searchLogoContainer { width: 10% }
-  #searchButtons { width: 11% }
-  #searchInputContainer { width: 40% }
+body[dir=rtl] #searchText {
+  border-radius: 0 2.5px 2.5px 0;
 }
 
-@media all and (min-width: 470px) and (max-width: 600px) {
-  #searchLogoContainer { width: 15% }
-  #searchButtons { width: 16%; white-space: nowrap }
-  #searchInputContainer { width: 45% }
-}
-
-@media all and (min-width: 600px) and (max-width: 850px) {
-  #searchLogoContainer { width: 20% }
-  #searchButtons { width: 21%; white-space: nowrap }
-  #searchInputContainer { width: 49% }
+#searchText:focus {
+  border-color: hsla(206,100%,60%,.6) hsla(206,76%,52%,.6) hsla(204,100%,40%,.6);
 }
 
 #searchSubmit {
-  background: -moz-linear-gradient(#f1f1f1, #dfdfdf);
-  padding: 4px 8px;
-  height: 32px;
-  border: 1px solid #ccc;
-  border-top-color: #ccc;
-  border-bottom-color: #999;
-  -moz-border-start-color: #afafaf;
-  -moz-border-end-color: #999;
-  box-shadow: 1px 1px 0 #e7e7e7,
-              0 1px 0 #fcfcfc inset,
-              0 -1px 0 #d7d7d7 inset;
-  font-size: 1em;
-  color: #000;
+  -moz-margin-start: -1px;
+  background: -moz-linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.1)) padding-box;
+  padding: 0 9px;
+  border: 1px solid;
+  border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
+  -moz-border-start: 1px solid transparent;
+  border-radius: 0 2.5px 2.5px 0;
+  box-shadow: 0 0 2px hsla(0,0%,100%,.5) inset,
+              0 1px 0 hsla(0,0%,100%,.2);
   cursor: pointer;
+  -moz-transition-property: background-color, border-color, box-shadow;
+  -moz-transition-duration: 150ms;
 }
 
 body[dir=rtl] #searchSubmit {
-  box-shadow: -1px 1px 0 #e7e7e7,
-              0 1px 0 #fcfcfc inset,
-              0 -1px 0 #d7d7d7 inset;
+  border-radius: 2.5px 0 0 2.5px;
+}
+
+#searchText:focus + #searchSubmit,
+#searchText + #searchSubmit:hover {
+  border-color: #59b5fc #45a3e7 #3294d5;
+  color: white;
 }
 
-#searchSubmit:active {
-  background: -moz-linear-gradient(#c5c5c5, #c5c5c5);
-  box-shadow: 1px 1px 0 #e7e7e7;
+#searchText:focus + #searchSubmit {
+  background-image: -moz-linear-gradient(#4cb1ff, #1793e5);
+  box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
+              0 0 0 1px hsla(0,0%,100%,.1) inset,
+              0 1px 0 hsla(210,54%,20%,.03);
 }
 
-body[dir=rtl] #searchSubmit:active {
-  box-shadow: -1px 1px 0 #e7e7e7;
+#searchText + #searchSubmit:hover {
+  background-image: -moz-linear-gradient(#66bdff, #0d9eff);
+  box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
+              0 0 0 1px hsla(0,0%,100%,.1) inset,
+              0 1px 0 hsla(210,54%,20%,.03),
+              0 0 4px hsla(206,100%,20%,.2);
 }
 
-#contentContainer {
-  height: 30%;
-  background-image: -moz-radial-gradient(center top, ellipse farthest-side, rgba(16,83,130,.5), rgba(16,83,130,0) 75%),
-                    -moz-radial-gradient(center top, ellipse farthest-side, rgba(180,218,244,.5), rgba(180,218,244,0)),
-                    -moz-radial-gradient(center top, ellipse farthest-side, rgba(180,218,244,.3), rgba(180,218,244,0));
-  background-size: 100% 5px,
-                   100% 50px,
-                   100% 100%;
-  background-repeat: no-repeat;
+#searchText + #searchSubmit:hover:active {
+  box-shadow: 0 1px 1px hsla(211,79%,6%,.1) inset,
+              0 0 1px hsla(211,79%,6%,.2) inset;
+  -moz-transition-duration: 0ms;
 }
 
-@media all and (max-height: 400px) {
-  #contentContainer { height: 20% }
+#defaultSnippet1,
+#defaultSnippet2 {
+  display: block;
+  min-height: 38px;
+  background: 30px center no-repeat;
+  padding: 6px 0;
+  -moz-padding-start: 79px;
 }
 
-#snippetContainer {
-  position: relative;
-  top: -24px;
-  text-align: center;
+body[dir=rtl] #defaultSnippet1,
+body[dir=rtl] #defaultSnippet2 {
+  background-position: right 30px center;
+}
+
+#defaultSnippet1 {
+  background-image: url("chrome://browser/content/abouthome/snippet1.png");
+}
+
+#defaultSnippet2 {
+  background-image: url("chrome://browser/content/abouthome/snippet2.png");
 }
 
 #snippets {
   display: inline-block;
-  padding: 14px;
-  width: 30%;
-  max-width: 600px;
-  background-image: -moz-linear-gradient(rgba(255,255,255,.8), rgba(255,255,255,.1));
-  background-color: rgb(250,250,250);
-  border-radius: 4px;
-  box-shadow: 0 1px 0 rgba(255,255,255,.8) inset,
-              0 -2px 0 rgba(0,0,0,.1) inset,
-              0 0 10px rgba(255,255,255,.5) inset,
-              0 0 0 1px rgba(0,0,0,.1),
-              0 2px 4px rgba(0,0,0,.2);
-  color: rgb(60,60,60);
-  font-size: .85em;
-  cursor: pointer;
+  text-align: start;
+  margin: 12px 0;
+  color: #3c3c3c;
+  font-size: 75%;
 }
 
-#snippets:empty {
-  visibility: hidden;
-}
-
-@media all and (max-width: 470px) {
-  #snippets { width: 65% }
+#launcher {
+  display: -moz-box;
+  -moz-box-align: center;
+  -moz-box-pack: center;
+  width: 100%;
+  background-color: hsla(0,0%,0%,.03);
+  border-top: 1px solid hsla(0,0%,0%,.03);
+  box-shadow: 0 1px 2px hsla(0,0%,0%,.02) inset,
+              0 -1px 0 hsla(0,0%,100%,.25);
 }
 
-@media all and (min-width: 470px) and (max-width: 850px) {
-  #snippets { width: 45% }
-}
-
-#snippets:hover {
-  background-color: rgb(255,255,255);
-  box-shadow: 0 1px 0 rgba(255,255,255,.8) inset,
-              0 -2px 0 rgba(0,0,0,.1) inset,
-              0 0 10px rgba(255,255,255,.5) inset,
-              0 0 5px rgba(0,0,0,.1),
-              0 0 0 1px rgba(0,0,0,.1),
-              0 2px 4px rgba(0,0,0,.2);
+#launcher:not([session]),
+body[narrow] #launcher[session] {
+  display: block; /* display separator and restore button on separate lines */
+  text-align: center;
+  white-space: nowrap; /* prevent navigational buttons from wrapping */
 }
 
-#snippets:hover:active {
-  background-color: rgb(210,210,210);
-  box-shadow: 0 2px 3px rgba(0,0,0,.3) inset,
-              0 1px 0 rgba(255,255,255,.5);
+.launchButton {
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  margin: 16px 1px;
+  padding: 14px 6px;
+  min-width: 88px;
+  max-width: 176px;
+  max-height: 85px;
+  vertical-align: top;
+  white-space: normal;
+  background: transparent padding-box;
+  border: 1px solid transparent;
+  border-radius: 2.5px;
+  color: #525c66;
+  font-size: 75%;
+  cursor: pointer;
+  -moz-transition-property: background-color, border-color, box-shadow;
+  -moz-transition-duration: 150ms;
 }
 
-#defaultSnippet1,
-#defaultSnippet2 {
-  display: table-row;
-  text-align: start;
+body[narrow] #launcher[session] > .launchButton {
+  margin: 4px 1px;
 }
 
-#defaultSnippet1::before,
-#defaultSnippet2::before {
-  display: table-cell;
-  vertical-align: middle;
-  -moz-padding-end: 1em;
+.launchButton:hover {
+  background-color: hsla(211,79%,6%,.03);
+  border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
 }
 
-#defaultSnippet1::before {
-  content: url("chrome://browser/content/aboutHome-snippet1.png");
+.launchButton:hover:active {
+  background-image: -moz-linear-gradient(hsla(211,79%,6%,.02), hsla(211,79%,6%,.05));
+  border-color: hsla(210,54%,20%,.2) hsla(210,54%,20%,.23) hsla(210,54%,20%,.25);
+  box-shadow: 0 1px 1px hsla(211,79%,6%,.05) inset,
+              0 0 1px hsla(211,79%,6%,.1) inset;
+  -moz-transition-duration: 0ms;
 }
-#defaultSnippet2::before {
-  content: url("chrome://browser/content/aboutHome-snippet2.png");
+
+#launcher:not([session]) > #restorePreviousSessionSeparator,
+#launcher:not([session]) > #restorePreviousSession {
+  display: none;
 }
 
-#sessionRestoreContainer {
-  padding-top: 1.5%;
-  text-align: center;
+#restorePreviousSessionSeparator {
+  width: 3px;
+  height: 116px;
+  margin: 0 10px;
+  background-image: -moz-linear-gradient(hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0)),
+                    -moz-linear-gradient(hsla(211,79%,6%,0), hsla(211,79%,6%,.2), hsla(211,79%,6%,0)),
+                    -moz-linear-gradient(hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0));
+  background-position: left top, center, right bottom;
+  background-size: 1px auto;
+  background-repeat: no-repeat;
 }
 
-@media all and (max-height: 500px) {
-  #sessionRestoreContainer {
-    position: relative;
-    top: -15px;
-    padding-top: 0;
-  }
+body[narrow] #restorePreviousSessionSeparator {
+  margin: 0 auto;
+  width: 512px;
+  height: 3px;
+  background-image: -moz-linear-gradient(0, hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0)),
+                    -moz-linear-gradient(0, hsla(211,79%,6%,0), hsla(211,79%,6%,.2), hsla(211,79%,6%,0)),
+                    -moz-linear-gradient(0, hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0));
+  background-size: auto 1px;
 }
 
 #restorePreviousSession {
-  padding: 10px;
-  border: 0;
-  border-radius: 4px;
-  box-shadow: 0 0 0 1px rgba(9,37,59,0),
-              0 1px 2px rgba(9,37,59,0),
-              0 0 10px rgba(255,255,255,0),
-              0 -3px 0 rgba(180,194,212,0) inset;
-  -moz-transition-property: background-color, box-shadow;
-  -moz-transition-duration: 0.25s;
-  -moz-transition-timing-function: ease-out;
-  background: transparent;
-  color: rgb(50,50,50);
-  font-weight: bold;
-  font-size: 1em;
-  cursor: pointer;
+  max-width: none;
+  font-size: 90%;
+}
+
+body[narrow] #restorePreviousSession {
+  font-size: 80%;
+}
+
+.launchButton::before {
+  display: block;
+  margin-bottom: 6px;
+  line-height: 0; /* remove extra vertical space due to non-zero font-size */
+}
+
+#bookmarks::before {
+  content: url("chrome://browser/content/abouthome/bookmarks.png");
+}
+
+#history::before {
+  content: url("chrome://browser/content/abouthome/history.png");
+}
+
+#settings::before {
+  content: url("chrome://browser/content/abouthome/settings.png");
+}
+
+#addons::before {
+  content: url("chrome://browser/content/abouthome/addons.png");
+}
+
+#downloads::before {
+  content: url("chrome://browser/content/abouthome/downloads.png");
+}
+
+#sync::before {
+  content: url("chrome://browser/content/abouthome/sync.png");
 }
 
 #restorePreviousSession::before {
-  display: inline-block;
-  content: url("chrome://browser/content/aboutHome-restore-icon.png");
-  -moz-margin-end: 10px;
+  content: url("chrome://browser/content/abouthome/restore-large.png");
+  display: inline-block; /* display on same line as text label */
   vertical-align: middle;
-  height: 66px; /* Needed to avoid a blank space under the image */
+  margin-bottom: 0;
+  -moz-margin-end: 8px;
 }
 
 body[dir=rtl] #restorePreviousSession::before {
   -moz-transform: scaleX(-1);
 }
 
-@media all and (max-height: 500px) {
-  #restorePreviousSession::before {
-    content: url("chrome://browser/content/aboutHome-restore-icon-small.png");
-    height: 41px;
-  }
+body[narrow] #restorePreviousSession::before {
+  content: url("chrome://browser/content/abouthome/restore.png");
 }
 
-@media all and (max-width: 500px) {
-  #restorePreviousSession::before { 
-    content: url("chrome://browser/content/aboutHome-restore-icon-small.png");
-    height: 41px;
-  }
-}
-
-#restorePreviousSession:disabled {
-  display: none;
-}
-
-#restorePreviousSession:hover {
-  background-image: -moz-linear-gradient(rgba(255,255,255,.7), rgba(255,255,255,.2));
-  border-radius: 4px;
-  box-shadow: 0 0 0 1px rgba(9,37,59,.2),
-              0 1px 2px rgba(9,37,59,.2),
-              0 0 10px rgba(255,255,255,.4),
-              0 -3px 0 rgba(180,194,212,.3) inset;
+#aboutMozilla {
+  display: block;
+  position: relative; /* pin wordmark to edge of document, not of viewport */
+  -moz-box-ordinal-group: 0;
+  opacity: .5;
+  -moz-transition: opacity 150ms;
 }
 
-#restorePreviousSession:hover:active {
-  background-image: -moz-linear-gradient(rgba(255,255,255,.0), rgba(255,255,255,.2));
-  background-color: rgba(23,75,115,.1);
-  box-shadow: 0 0 0 1px rgba(9,37,59,.2),
-              0 1px 2px rgba(9,37,59,.4) inset,
-              0 1px 5px rgba(9,37,59,.15) inset;
+#aboutMozilla:hover {
+  opacity: 1;
 }
 
-#bottomSection {
+#aboutMozilla::before {
+  content: url("chrome://browser/content/abouthome/mozilla.png");
+  display: block;
   position: absolute;
-  color: rgb(150,150,150);
-  font-size: .8em;
-  width: 100%;
-  text-align: center;
-  bottom: 2%;
+  top: 12px;
+  right: 12px;
 }
-
-#syncLinksContainer {
-  padding-top: 1em;
-}
-
-.sync-link {
-  padding: 1em;
-}
-
-@media all and (max-height: 370px) {
-  #bottomSection {
-    visibility: hidden;
-  }
-}
rename from browser/base/content/aboutHome.js
rename to browser/base/content/abouthome/aboutHome.js
--- a/browser/base/content/aboutHome.js
+++ b/browser/base/content/abouthome/aboutHome.js
@@ -17,16 +17,17 @@
  *
  * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2010
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Marco Bonardo <mak77@bonardo.net> (original author)
  *   Mihai Sucan <mihai.sucan@gmail.com>
+ *   Frank Yan <fyan@mozilla.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
@@ -150,16 +151,19 @@ const SNIPPETS_UPDATE_INTERVAL_MS = 8640
 let gSearchEngine;
 
 function onLoad(event)
 {
   setupSearchEngine();
   document.getElementById("searchText").focus();
 
   loadSnippets();
+
+  fitToWidth();
+  window.addEventListener("resize", fitToWidth);
 }
 
 
 function onSearchSubmit(aEvent)
 {
   let searchTerms = document.getElementById("searchText").value;
   if (gSearchEngine && searchTerms.length > 0) {
     const SEARCH_TOKENS = {
@@ -205,23 +209,27 @@ function setupSearchEngine()
 
 function loadSnippets()
 {
   // Check last snippets update.
   let lastUpdate = localStorage["snippets-last-update"];
   let updateURL = localStorage["snippets-update-url"];
   if (updateURL && (!lastUpdate ||
                     Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS)) {
+    // Try to update from network.
+    let xhr = new XMLHttpRequest();
+    try {
+      xhr.open("GET", updateURL, true);
+    } catch (ex) {
+      showSnippets();
+      return;
+    }
     // Even if fetching should fail we don't want to spam the server, thus
     // set the last update time regardless its results.  Will retry tomorrow.
     localStorage["snippets-last-update"] = Date.now();
-
-    // Try to update from network.
-    let xhr = new XMLHttpRequest();
-    xhr.open('GET', updateURL, true);
     xhr.onerror = function (event) {
       showSnippets();
     };
     xhr.onload = function (event)
     {
       if (xhr.status == 200) {
         localStorage["snippets"] = xhr.responseText;
       }
@@ -255,41 +263,31 @@ function showSnippets()
       // Bad content, continue to show default snippets.
     }
   }
 
   // Show default snippets otherwise.
   let defaultSnippetsElt = document.getElementById("defaultSnippets");
   let entries = defaultSnippetsElt.querySelectorAll("span");
   // Choose a random snippet.  Assume there is always at least one.
-  let randIndex = Math.round(Math.random() * (entries.length - 1));
+  let randIndex = Math.floor(Math.random() * entries.length);
   let entry = entries[randIndex];
   // Inject url in the eventual link.
   if (DEFAULT_SNIPPETS_URLS[randIndex]) {
     let links = entry.getElementsByTagName("a");
     // Default snippets can have only one link, otherwise something is messed
     // up in the translation.
     if (links.length == 1) {
       links[0].href = DEFAULT_SNIPPETS_URLS[randIndex];
-      activateSnippetsButtonClick(entry);
     }
   }
   // Move the default snippet to the snippets element.
   snippetsElt.appendChild(entry);
 }
 
-/**
- * Searches a single link element in aElt and binds its href to the click
- * action of the snippets button.
- *
- * @param aElt
- *        Element to search the link into.
- */
-function activateSnippetsButtonClick(aElt) {
-  let links = aElt.getElementsByTagName("a");
-  if (links.length == 1) {
-    document.getElementById("snippets")
-            .addEventListener("click", function(aEvent) {
-      if (aEvent.target.nodeName != "a")
-        window.location = links[0].href;
-    }, false);
+function fitToWidth() {
+  if (window.scrollMaxX) {
+    document.body.setAttribute("narrow", "true");
+  } else if (document.body.hasAttribute("narrow")) {
+    document.body.removeAttribute("narrow");
+    fitToWidth();
   }
 }
rename from browser/base/content/aboutHome.xhtml
rename to browser/base/content/abouthome/aboutHome.xhtml
--- a/browser/base/content/aboutHome.xhtml
+++ b/browser/base/content/abouthome/aboutHome.xhtml
@@ -20,16 +20,17 @@
 # The Initial Developer of the Original Code is the Mozilla Foundation.
 # Portions created by the Initial Developer are Copyright (C) 2010
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #   Marco Bonardo <mak77@bonardo.net> (original author)
 #   Mihai Sucan <mihai.sucan@gmail.com>
 #   Stephen Horlander <shorlander@mozilla.com>
+#   Frank Yan <fyan@mozilla.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
@@ -55,57 +56,53 @@
 
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <title>&abouthome.pageTitle;</title>
 
     <link rel="icon" type="image/png" id="favicon"
           href="chrome://branding/content/icon16.png"/>
     <link rel="stylesheet" type="text/css" media="all"
-          href="chrome://browser/content/aboutHome.css"/>
+          href="chrome://browser/content/abouthome/aboutHome.css"/>
 
     <script type="text/javascript;version=1.8"
-            src="chrome://browser/content/aboutHome.js"/>
+            src="chrome://browser/content/abouthome/aboutHome.js"/>
   </head>
 
   <body dir="&locale.dir;" onload="onLoad(event)">
-    <div id="brandStartSpacer" />
-    <div id="brandStart">
-      <img id="brandStartLogo" src="chrome://branding/content/about-logo.png" alt="" />
-    </div>
+    <div id="container">
+      <div class="spacer"/>
+      <div id="topSection">
+        <img id="brandLogo" src="chrome://branding/content/about-logo.png" alt=""/>
 
-    <div id="searchContainer">
-      <form name="searchForm" id="searchForm" onsubmit="onSearchSubmit(event)">
-        <div id="searchLogoContainer"><img id="searchEngineLogo" /></div>
-        <div id="searchInputContainer">
-          <input type="text" name="q" value="" id="searchText" maxlength="256" />
+        <div id="searchContainer">
+          <form name="searchForm" id="searchForm" onsubmit="onSearchSubmit(event)">
+            <div id="searchLogoContainer"><img id="searchEngineLogo"/></div>
+            <input type="text" name="q" value="" id="searchText" maxlength="256"/>
+            <input id="searchSubmit" type="submit" value="&abouthome.searchEngineButton.label;"/>
+          </form>
         </div>
-        <div id="searchButtons">
-          <input id="searchSubmit" type="submit" value="&abouthome.searchEngineButton.label;" />
-        </div>
-      </form>
-    </div>
 
-    <div id="contentContainer">
-      <div id="snippetContainer">
-        <div id="defaultSnippets" hidden="true">
-          <span id="defaultSnippet1">&abouthome.defaultSnippet1.v1;</span>
-          <span id="defaultSnippet2">&abouthome.defaultSnippet2.v1;</span>
+        <div id="snippetContainer">
+          <div id="defaultSnippets" hidden="true">
+            <span id="defaultSnippet1">&abouthome.defaultSnippet1.v1;</span>
+            <span id="defaultSnippet2">&abouthome.defaultSnippet2.v1;</span>
+          </div>
+          <div id="snippets"/>
         </div>
-        <div id="snippets"/>
+      </div>
+      <div class="spacer"/>
+
+      <div id="launcher" session="true">
+        <button class="launchButton" id="bookmarks">&abouthome.bookmarksButton.label;</button>
+        <button class="launchButton" id="history">&abouthome.historyButton.label;</button>
+        <button class="launchButton" id="settings">&abouthome.settingsButton.label;</button>
+        <button class="launchButton" id="addons">&abouthome.addonsButton.label;</button>
+        <button class="launchButton" id="downloads">&abouthome.downloadsButton.label;</button>
+        <button class="launchButton" id="sync">&syncBrand.shortName.label;</button>
+        <div id="restorePreviousSessionSeparator"/>
+        <button class="launchButton" id="restorePreviousSession">&historyRestoreLastSession.label;</button>
       </div>
 
-      <div id="sessionRestoreContainer">
-        <button id="restorePreviousSession">&historyRestoreLastSession.label;</button>
-      </div>
-    </div>
-
-    <div id="bottomSection">
-      <div id="aboutMozilla">
-        <a href="http://www.mozilla.com/about/">&abouthome.aboutMozilla;</a>
-      </div>
-      <div id="syncLinksContainer">
-        <a href="javascript:void(0);" class="sync-link" id="setupSyncLink">&abouthome.syncSetup.label;</a>
-        <a href="javascript:void(0);" class="sync-link" id="pairDeviceLink">&abouthome.pairDevice.label;</a>
-      </div>
+      <a id="aboutMozilla" href="http://www.mozilla.com/about/"/>
     </div>
   </body>
 </html>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..41519ce4982a0385b7668eaad8c20e1d06070b7b
GIT binary patch
literal 1444
zc$@*G1zY-wP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU%MoC0LR9M5+msw0yR~W}_oBG%{pPQyW
z7}KOSJT$T3N>M}<6&Us)%Z$jtFayIZch);|@66oUR~Q&TmX<|g!$VD46GHI8Hce|y
zO=;g~OoM1`o7Ae2G+)2(hM5i{57%TcDakMQaF%=i=R5!JoIAUA{U830me-vut!i1S
zXt?wUS;O+pqvf^7UdiOe=Niw{EBZif5rA>UM5tWTu7Trc8xHKafCfeHmqwh_KQs;D
z(W@d<?q`EgCszwQE}+NcTIM2S5E+}#Kq4&OLC~|l;EoGOUYRjlak9|JTt+}(cm_=F
z*ux)w{Q2OH3jlz({fY4<VPGn=1r(8)YoGhDZTBlNVmLWrb%sZ9@;MQkZxCF;!OFZ%
zP*hsA|4?al!J$*t1x2OR2eRt-l$>vBRP@;%(5h)02uCOdtt!)R*ruT|g(oZD*zCVI
z{T`%DvVe*@`B3%6Zm5^{LQPu_R5o|Pg{DriELU4-zrl-J5K7I8P?_p3_1S?^v<myv
z7+Gr%)M0wowyB|_UU6Hp0ENc<m7WWOJuoDO*Ww)zp)wa41@GV#8gCkcsTmO}`;wmk
z9~~3NShM=m|3*Fn8WVq0vVhAv_MR(tMSO8SAQ1*<U{<n#E<N{`keGx39x(a9A`F0;
z5BsDGFmV5n0Dtn+ykK(2L2vV#B@5^_@*Bdyq`0s7z~qTTx1J4U&w*J{dE|7B^Kh9=
zi&^u|76EFD=b<}3E}D(-Bqo47K?bBJiA%Rhfjl7BSk{Uw8p?1&S(&W$cCB0kE!{?F
z>eRv6dc{K&v_B)j!iR2Hgao+I)f^r;W>0)Wh>hMFo|v1*=QnnAw}%9h5DCzG^v)2p
zsTgSKGJuM4iD_&1C&i4xh{L(Yj;k2~zuf!vV^?Ts$?T4<dSfGtckcdV#AEg-@;-9h
zpBP(o1cyPu$Vh?2@)$izOEHykQB;?1qq>$Z{iE#j{!OG1IgfmVyp_F0k>rGqaYb?P
zL|)*+qjZRENH(c~^)>ag0a3kFXd5VMEc$_>;YKf|+njimtBl;*mPravT#%tLl7~vG
zn1dzfx45)LsSD~ILGdM05Pjs1J)fLg7@z&@`Vhm1|Ddqb#3YLR;fs%4$xLvhOeU{t
zR>DQ49vVBebdEnp_jaJDg5ziEn$f+_(k7JxO~!|kOSqN$kaySaKWO*GM!v8K@fC|Z
zx-vR7KaTb9Wdzi;cCYl}cb*j|LFJ$^dqgp{co~t4`|W<9OkmN)1cxi(ag{Dg(`_)|
z3i-eQpXIUL$cM=3P4;aGf2)ewpcJ9KqVQ3eXvK7?kooAz`Uh5oXlhxAjVzm7(e<>u
zX-qDCHXkq!U#Ilju-7W?54|uK%3C3lTHaJ%L_GfcNrT;+xSJM{3q?@Fa0=<Sq1OJ~
zfo`SH=3>Na+RO(NIiG2-b9gvlB(@zx0+d>-TDpLK+n;tnxpepijC>gV(0?bp|KYOg
zJ<UqpI^&9LJEqqvz~w%(Q~GVFV^_(5PTc!ksJ^|&1jov2W$FH>sxDqv>KtIh?b&XO
z7Cj*EF{WPPdw~7k<c^~GhF*XTBtdO<gRDil@ZXOW&F=;-B(`lgM&}6NryR2&{l|yF
zd4u+ve2|9HjaF#Et5t=Uhk^Ab)BW{!VUbozZRzyP9!G~(yUO^rWC1#>C)KHA#e65U
zb{{>TFkEQW=81kgK7B1k7gM_b)2Gi4rzYpdvF$s(Bd|_lGGno<wR!I=)Xc4y`SI}q
yBF~|D^KvRi_U80|ZS#~XL29-cTaBEMGWWm2aTm|u=>tjt0000<MNUMnLSTZ;x6I7|
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5c7e194a61c1e669b24c382603269a093989f517
GIT binary patch
literal 1276
zc$@+J1OxktP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F8000ETNkl<Zc-qC5
zYfPJE6vz8b6E9P;O`>KW{op4P6J!B81jcoY%55<2TFRwR3!|l_w9vQhTUvT=DYQVj
z?7|$&V$3o#B%4E+gn({16tkEZql+I*jBKfd#T?IhMS@y{7SIpB0MB{O|NPH$d*K1V
z|4P^i@#zJ;gp2}S;)$ZD)VzvCWFCJ%fMXcjmc21>EUSnoD6Ji8P#8ems)wAC8ZVCh
zHwLKF<8PH8sX5cRX7r2z>mCMCvt|{?qA|Ab2C(~6yuvC;pOSThWAGA(l666TrP#^G
zSbTc^zp-lr*nL^FsJUact7jBkLzlrB7zbJj91Erh$_`<d`)eStLhMu+Twot~kBW2H
z`Y%GO-U)dX_1*kTT!pm!E!d@j6hY~s>LzuNbr0dvlYvVF_dAUVF_w~362*0!mKTcM
z8OX&BTXhbw`p0PRH^Ys|F(xRj(<fvU^5U>q2qHI-oKu3`Yk~%60PMKr4%~vx&=|#p
z()NeRCr=-U--Q9XYOmwtQiekMwEW5|*~QgM<@It<b$P(zJCFN+F(eeD8&Os#1IoeN
zaneAo)1<lOA>?Nk#^C;rpC}S8=a$z)adi_^HYh-JrUN7@BghyVbXfYp+<O+6`T`!h
zv5-*A<Q=8Clta0sL0X(9X=fD)m#7xjd~L%3zG^?!$rzAnZJ;uGpwr?5ovoi+Qd7?e
zboZVEs}BqN$94qGrJOF$2x*WOX_7Wqqqap0f|8mC8wMI%nQv%<3GcS0?>q_Y3#3go
zH0EAtkTc6025!%NUZ*m;e=&N7p}X%K?d85e+Ek;Bb^d(!-d9zd58<<)%+4#@jP4b@
z&opsgKy5mtEAw~0Xa<0%{(cLhZcfi?RIDp#Bon=7_Y~F@0MvdoJ-g6G4R3V~4^DhM
zqi<tfYm{L2j_wJhg_^<1Ter2;=yvbG3s<k->~3S-Yk%B=(Op3rN`q_d!^tTFY9HR|
zOZejD53W1#U_Qp}psN@WluH`#Uz@a`X7sVl!mys=BbJ`P1Y`5#eIAYot<?wi-r=jL
z^)ereA59U2_bq5tFxS+k9_l0_)cABul)5WP*~MJ(*yNn>42Y!d_cdg|6^IDR6-ib1
z60=TG@$e1cxBpjMMmoh2LAlt(Lt241usE`F1Ne`{OSLVXptI9AVK5>nmo)HG9>p0*
zI=OQLr6Orsqe2gQGT;~p1;w_FlSV;BJwG;F165*~tV!JkdPo01U~E26n>_TU2iuLV
zRgJla#zM}Owj1H?26@BL;{skxQufXb2pbiHvQ7(iu>oWCaR*DTwXT`n10Q|=;79Sd
z-~AvlIs0$m*kg+6Z2rIGv~+X>YI);Qb9pguhGF0xiDF8jx8pwgx$ZP(Ds1`9VDFn=
zTE5=`0I|pu$dgFi;+J15bXM<-oUy|Cig3B~xA0x%L_&Igcm}Gaszrs){%6OaHG3BD
zE2hR6A9<PtX<zAn^D_!4=NTk%ZsBf6r^)?UD`Vqw>8DVloX0ug8DMQ*Z=*uDqUmzp
zxivFK?|2IG90^fT659-otv|KTBdIs0K4sgDjzzJYd1Q9^ZQ&XqUPa20H00p=7>R5J
mo$}2_4kPJE1@g*PXW)02(gT@f=I})T0000<MNUMnLSTZFLTTOr
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3d4d10e7abb472690b37dbd8cea26c79ec8205ea
GIT binary patch
literal 898
zc$@)(1AY97P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80009?Nkl<Zc-qyM
z%TE(g6vm116(5QEzqoKEaVH^>D2N6W!B8WlQh~mN&UE^qkLk2SdDHUr0irJ5xR4bD
zO$kUVg|wy>(^6WRX<4`clIuN9N-$1f3Ns6D@=KcD@1FCWd(XX1i;Di2alQ2ZwVM@n
zD|c!dQTZb|FE9rh(28!LyzW`JnRFn6?nji<!wbxT2DG9ZXiyuGW8e*PkGw}+qaS#I
zInaPsbOTUX=kU8+l7j#ZXhk>BN->8f&jVV~4YcT)Ty;VKtpo<(2&M!9T1k3<9hwq^
zBt6hf(1`WE6$EHSH}IUWBbRql5TF&^fI??OPS1oOKr6n1c5Gm9LJ*)8-9S^D6*2gg
z69Q-@Fkr#Y>}x@QR+1*9`(Fv7;3h0CsbotkYBRU0o}e-w9z0c|HcJ<x`(6qHw6KOR
z7UU?sTlc%T^xov2fvS3iU#>MHjfq8CbLT(kY(1#MJ&f$V<AMM!tl^6VITY<yR4r?c
z?irYwo0lmmCT(<ik+pja*?Pt$0b-ljA*9kXTc1A9wCov3rBWAt-~3G)GmA}luy7PF
z7!wtUX=1&22VB|NIiEJ0&0hJd55UCYQc$ijI#UMcAhL9g<Q9nm#Dc<9MkYJ^bwQcQ
zWG?eIV=|e%5LjMq)S6rg12d32OIUmyAO;kqHaIy*&T-tO18+nkkvJb*4a?M&BThN`
zQAg(xvVf5z0BfNTHN|lA3x36+$@3!?i=7LFqK~obHInW_W*i7ADFj$U;p8d<lZNDQ
z#09+#kx1lhFdVK`QOp`)@69z31Qh~k^?3J`lq0>k^j%(X^8F?vk)Jhc0~00iy*A-S
zGJ}x=0F55+no93TL2~G;V?Dv4Q0PqbSG-zlWPa#u-ME_vafKdUV2-4Fk&2=>pqY=I
zJU;?~!0FifdZpIj4C$=c1nz36bU*MNiH}ODrxX6=l?G^LQGbklKHsTiI$f?YFu^v9
z8(*z~T*Ux<hTTz;ws;^ImWiG`Kc=UrPi|~(-Ubsd@VgFY4Og|T!;M-AYaDNTJ=`Ek
z|D=Kmj@v4;yS*P<2|L$9*tc{R_DeXjRx5e({2)p4#P;^~)!p6QD$K*3ot+!dtVfCU
Y2Tou=l3c_Nga7~l07*qoM6N<$f;t<JX#fBK
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ae742b1aa8acd6115533186c86f7ac37828681f7
GIT binary patch
literal 1654
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
AM*si-
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f2c348d13566a943593afc93934e5503661deaa9
GIT binary patch
literal 2684
zc$@)z3WN2DP)<h;3K|Lk000e1NJLTq002b*000vR1^@s6##+F`0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU+9!W$&RCwCVSP5`d<rV(#{`U9sUiJlu
z#D+j{fLNRWbwLG&FkveLvWRS<K)?c4K_)>2My+fG*~PXNX6Ot9v{(maaeygOOj8yG
zY1xF*keHCS=H<P+^_;ten}Bv;MyL19pL_55mvjE_Kj%B=hEi3PJj^v?el__qE{dWE
z!!R2-jx7^K=`XS@&sB*^Xo`M{rs*<@rb`t?KB&mbN|eL+LWX9>vJ6uyL5D0$!&K$o
zJ#Jt7=6C93$^Y|3fq@)1(&zJ4IvfrXi^VEKq0m0q>QRr!Go2TNi2xX3DRS#p-EE?%
z3Q12*?GG3%v)OD!lEfR|HZ~DS5g$nHLxb|L9`+y?cmpZO&r6TBN(4bcoq-fj)|G2F
zNJg5Ul2lsrBvlf5cmSg)l98TDhhwe8Znu+`Sk$5QKcKDj!<(%BC~d;%VMnvm{fCpu
zMBMLnpL}K3<m0eSA}gu{;iG{99)&x{lL8>AD9VgJ?EQ|le-Kak;iE@^ILJr~T$wh0
zWEH%2gLZw^E6Z-;$+I*S7ZpVZh3J5wTv3!()p)+!9!xJgeSQ@Z)>H7@S5=g8prnFf
zx#!{CD@)=*SyA5Iv2I0t#)9ffmSG3N*iOJ+7bu!~8^&KyJCGvuPl7lf0%TXHsOl|P
z;|v)38+g8B&;*Xlp&6zcPxHQj!)9UpX_&WT#{4P=$8p0sUMK{PD3lbrAIuNQsw%dH
z1!7|SWMEtqAnWgLNK$E_cl@kZmzOg%?Zt602keyI+rD=BAq^CV-M-f8boRy#NuqcL
zjP1(vJX%gfQ7nzO#D>jV@>WBN&sT=zg&UD%xg;71kBP-v3IVhmXar;dFVAtiTyA%n
zAPCwxP*?(Ml()3Rro>y~V`1#)s5CDpD<>RnslfFth@!#Tqa;ai;&S$#=HQN0zb`#0
zDT`b#7io>hNnSxdf9}F11P+pls_B6jecNrGp%_hnH|*o#u+{-LO#{6=?vXJL1@{9a
zUS6?q>6mS+m+fJ5vNM}yRgXacr7J9vu-k-2QId0ztYCqk!ik~5ip%A^l@z5sJB)>Q
z8z>po91N|)4cTnM7N0Mr3<;5@sc=q4+VSR4xN9U9FM>7lLQLr6NH|=K-qWR1ZY&gy
zo#0u{Ofp0v#2JdV^g%n4$s~jaNy6GBGb3GS3PuQmqQwDC-DL)I)7EEIZQp0yKUlXy
zTD)>ye?hQ;S`JN)+ikY`L{iMP(KL%7!P3iM>K+zmL;w<v={+vj`3a+jYzg>%4Zq#}
zry2E)!9g~`Mi`2GGpcOh=0`f`UVeYqzBzY7(Puc0CqAz?KNt)npam|cYaBF;Y4Sv`
z9vcP@=(`^jq_5ia;U<Y;J1Z{52QK=0EE=0LdF=4((6_`IGVgBs{aeVFxFh%*{CU~)
z+uvTlT>}hl!)B5h)*X7&!v+!6-gOKt{dYNK`Y)@L7srnH;P|Q9#eIqk_YZw`z$sWQ
zSbOeb?@x~Xt(u4Z2)wO}7Cw?BtC)kpU5Vf8I0k^c5AtL<66ptp&mcTGx657&fNTVL
zG#ZUO2O;qcjVC4(H{6KF?Hr9>#W3h?i3k9)v0{Ez9mBGuxTvru9E*1bPa;l-V{l6>
zMyAYN9D{XFV94U8Ii8;u2n710H=vjF=~=j~;E_(Bp-mmbL3ac5-5`7o9YaQ}<CV7g
zxYm=UB|D+j!HgPcR}p|<D125Flhqi?V80f>tZHFyh~Z`g1UnLmWDE#ZlZV2QFam<|
zcxxgF&R~!#&@F%ly!1F0QHCprW-eS>m%tE!fr&)o8{`O1b6F|}$19>ppa9c&1m+cZ
z?DqBOzNpXVcK&tfvp;(efJ-3Zl6x|VH9X9ENp0g4>v&?h<Jz!h6U(x#pmRMON_S}a
zc$iQKwymp!0*X~I4&7d{Bm*#7MVax|E;GooL2yJjnqe8AYAD8(s1v24y#up{@Q$Fs
z#cOHP-~r$z9=vBa5WNG}1J7(6J?y#VQ|G;Y6GBY`P0`b=)-+p<ccR_(btqNuR}7gs
zUeQ8LzoWIF<3rFl$p%0GI644u#{*Tg^iEpzI>k&~YR96+f_R5wr=uJ;9F-Mao)ks<
z-Qb4zM3OT%0!GD6IeHp+$5N-uRf1juB(Ib{{@CWMjI^T&2+pC}WfV(d?Le-S#Y?Pq
zn<R|=u<=r_*E<Ql0(A#`o|9>Tl&dK|Pxw^rm$MNZb3AKhYPDm%YRakha$=F=DR^AY
zubY~~I^wdDf{>eQ#amk+WjH|tMG&}~s*!$yZw9#Cu0`m+7)oh=?~y@I_uD*q&TFEq
zDEB=CtBqDWpmq^Vo$7ru5%vZADP@Aqu6ZnYWUzAD3rO_!2R`}C2OK$D3x7i|ZLHD`
z*?SC8I~Zt*Y20kz-aQY95HqS?4>+K^oYIZ)CMEev3=L3BQd7JqbT_5E5HY(Q4kwL$
zU{L*-;e%IBsa#Ztp=R|owSz6~WJbXV&1UvP?V+e`)vd~?hF3y4;inDWOSC5ViUrjt
zVfw|>e?QBc<0V;fYM`{$d?vfM14U=>cAR2ic9bKlKT+~nZFWZB5U@DJC<Dah`lH=p
zKjLyZ&VXBH;rRhO)Rzw#xE04kCRzbJk|PMbcD6||!M(X^;~JJ@YoM=&7x)?g>emK|
zwa+F*=N7vlG~rq}AIQHikp3)u&dtvFH+X`XiF}YzR)gFRS@pUp2V<a0X8$q$<t1C8
zj@qwfQdQ#=8^|hYJUJvr$%tbsC@8}d{ysU*e{uG&TIWn1|3+?B`T+<9#b&eH;B$YV
z%jNEZr^GV!<w;}8t8=n4&gx&fzMtsCDjT|GzuoTW12JC$^Ge)qcS+A4g(77XYNkHj
zMxy<TVA$ZN{|w*+Q9l6agerOiq(cAL5kvo#k?KE&sU1TCQtbkl(=oVm+Jrp<&;1kE
zKso5>p5jlb5Nv|aCh&DA$IIvQ3}Jf|794^yH;Tr>q%X|PcPq&M0;;{8xG9chkD2nK
zN4uT`GWDDC%U7;zz`Qi)wbQ@b_|6+=&R?wg^6Se*jdz-Jfa!zTnQ1ql?%(%_(_ue2
zappqp%eGf>(Wk&04dyp&#}7<guUB!m{b$c#B>8!{cQVpacj876MA%@wruG~uEXe=r
zrEw#w4j=ox4D4~{W~MdQ-EQzsp8e{z4ewMh+xyYsS)oWIGu`h?z@}qU=Pteq@<n?;
zIyCM-_1_k84C4V0N#x~Zo_S$p+1}mzJ|1=BR$bA&muIY}0E|qqBgL@iHne8r8D*Kq
za}%@%<2itpswtl^b3uc_6WR&<Ve=}SmkrGiEoRKU3F8#)RB49n+`1b3z5nB5^~!{b
z1<768)?h9#u*ffsub8i3g$wH-2lRj@7`iTjp4hIfYcK;B8#?emOqVDAVqxRXEvr%9
q9a=6lhtYQp+E>OpDF5`o0t^75%aU;_iQJ<A0000<MNUMnLSTYZX9>gr
copy from browser/themes/winstripe/newtab/noise.png
copy to browser/base/content/abouthome/noise.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ef593e6e14c87b6774b39361f9ce31b1c908dbed
GIT binary patch
literal 2841
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5c3d6f4376c24bfe320ccac1e2b09f896c83a2a9
GIT binary patch
literal 1796
zc$@(Q2mAPmP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU&rb$FWR9M5+S7}UCR~WU6CPtgKCbd6X
zn>6Y6!$#YrE~R4KSQHQ$bOc7E4nh$ShJjfehFRY18w0bzfWs=#s#O~k(^d^lqtVtz
zjK+{O){rzJXt9PEExG;9>%5n#MTF{~lALgJzwey$-S6Fd-<w&p{!f3Oq+}<oNz37q
zB?V_UO6BJ>a*O{2Fvc8W$a$)!A16uXuHLj=k+yyJaBi`Z6)6p@vewCJOg^TuHZrX(
zz*OdXehx9@AQv2PpU6CMqg0ZfTlA~EqL!&RKQnq;m_5+J?7>cc>~HP;$sX*u?{4m4
zuBHQg4D-kZhq^NajsIl6HY1mleO|+=O<rcM-_Ky;iS#l@sEgIPn(lQUI^Mz<TdTD;
zjAITlZ%ZE!<bne(G@v#8mM2S|OUlaclULR<y{m~|8AM@VX=r0+PxIAFR|XYi{wDG{
zZ_^1^u>G9L+dOLWwX*nPz=a01pb72A7O;NH4z8%mz_$`Bi8Fr??)dUB8K)9n5b|lf
zjIf%p?c9X{y|=036m@9A87l-D(1Iqkr*3<CPWor%T4wMx6A>%#<$<x$8@Xq1h$yDw
zQxOXYD}ElhqBXd~L)OMNDx!zyLlfHMkvS=ORqD0{(!$Ey`|Lr!b*Nr|unKIfb(u2T
z$_-g!D-)6=GD70Y4O`~K74p*X$gS<1ulXY9k1}DCLK`0N`d0y)q;g}0&cPhC!#&t=
zac~nEE!B}gAr+A#Dfl)aDeD#R(sPRLNOx7RG-=@<iK$!n#uYL9w;RLhdPiUgrvp0B
zh6lVJI&RzM<nK|9QJbmKZoXxc!5Qx2Te(NgvCVnK*XaWKuvE>B>l{I*G<w+1G7UD{
zsf1+7BB6->Gv~|p*%~Lng*H6k1y8X6BBhjREOfp*_@t=-A(O9#RqCCrL}j|Kvj-*|
zp-!G#=L)lu8WUYag_o#^`LQBi=Dgw4TzxCgM;^T3DHf1dq-ayq<$*T4!rhMr@~k+L
zbnI-6?II8VO|(}~M6x8`D(D|OaWY2}(+A)MPq6^`UfqDf-6SSV7kH+?!*hCP7#Gm^
zs?@D>g)UUpxkiOz;RR2zfZbJfW9E8XB7e8i(h%j_3}B2o#HI@zKkSn<seHZQp*FeC
zK@V|w!BZ@tSZR157$M0SZ2Pgj??^P#b+E_ciwuH**mPkFv@=>Ulb5S21rMd(epF9;
zL|7m^#R5vIjSs9SfQWi$h-o?R5o+68g!lZB&U&4#k&n#;)dn}K(3;hPN4ds)h&C)A
zgBLu-0!nL4cd$!s)Vf+aQYF=fej#S_g=JU`Vl#n)P6_7@$iyxyYWq<DV(@~eSU`o=
zGHCQf_?=DnI9)cn8$#^D#mjG$Yb|%N;}M?@kP8mDf(|sHjX1pEDHfnIx{jebw8lgi
z1w9|OCOzk)*baW);t3r=+~VKQ=S&6U@VUeR7aF9s7@E*V4&v|>3-E=a3MD-=v<5)S
zCHW=2Lj0F&*AuD@t|9CX#9=ZS5JL`f!4ddbJ4$+>Dd@uso?-#Fe;->^rsnS8d?Eq+
zfUe7lRVmqvg)4R7^3`2h&UckQK&XYyqL=`z4l(2)7aaa2M;g$=s*wjSyx<xC8hyqc
zXzkK)^~_8{CQ7Q**;!^@@!*Pen_rCO%)_@pQ(JGhvd(!Ixi}pF#+VC5dwOEu3-iDM
z7aGulCbW_3Y=|6y=RaOZ!y}_hDs{F|+~;Px3(y5Tw`9rA)63Uwo*!52yM(-x-=8%{
zI=^TKFvc8?t&j&!N_N3XXg~{^(1yp&ky}eA`<Qq(+I`T4XN5<BR-vWx3LPV%%gfhh
zyz@~0Lc-fIER2sKH$}2@09@gbK@-~WfY+nGXkK^tBS%&AF=<2*1g*u-imU4II2gU}
zo0qLgU-GCgBE*n`TyW5CK?j=9hR3YOd{!;hS$$_!W-qlYM3sl>*fi32znvA7sadA1
zm?dr5G4$ys>2ca%Apm2{A%+~}f&(rzpao56PwUH=5)+*bEk~8qGCe&%13kMsT+!5x
zD!SoHRc2gPte{lQ17pk~h8*OA11>b61<e`#E<m+?Umb5y=<Q<~OFeC*0KXbQ?+mhi
zHac=vKM#yCC&ZBp4!F>m_R1$I;<cM2qXphj^l(+J<2GI}!ttx6bB&b(7z@V{ImiVE
zTxdMe&of*og!c*3@A}V}shwYI%$_T1ljoX3?-&O##vEeboch6n+!$x}Q~jYDJ9-}w
mQV1CYSqvGmImBL_iRNE?brB92^z8Nk0000<MNUMnLSTY?a9BqG
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4b0c30990933f748f41f8424ff81bd0622c05b18
GIT binary patch
literal 1557
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
Hu0mjf%%}sx
rename from browser/base/content/aboutHome-snippet1.png
rename to browser/base/content/abouthome/snippet1.png
rename from browser/base/content/aboutHome-snippet2.png
rename to browser/base/content/abouthome/snippet2.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..11e40cc93755ab65b0dcd4a51a58c87f6c096278
GIT binary patch
literal 1879
zc$@)O2dMaoP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU&`AI}UR9M5!S7}UCR}{8VZEa0kZQ9uW
zXn&Y!+Qg)38>3aQD6$I_fq`L%Vc(Y-*4c;I_kn?7hD8yy2x$a=XlkuNEhbFV)YfWg
z4JBHOU@NquLdfkoPv7{^8K|^BO7bOd-n;jl?`+?_EL-+}{@W1}yLnf5d}&}*N@r+n
zhBGWa%Nd!N`v5SF&!H@iGhlCW+s-g{;*Jp3y8q0v@1D4gfl;Z$aT%o~t5ise`6|Mb
z8c4O=Lip-N3i!;G7)W7_f}|JKlBkpd;vboGgtp-w6tfPndPxKbA+I?vepe_^TgMgk
z`-s-oMfCPV#MshJOs$70;4{9%ZxVxpl#4WDgF_b*asRG}g#3tv?CCIe*67Z#_`qi-
z00vej=ke@9Z4>3l+}7g}2FK?_q-&n}X6QmW5MK>h$Vn@xCY5z2!h;MY=T%^4jL%Sa
z)+%6rx}aJ?FnWyElXLtgx3rU%&fX4iz6OYIN-e0G5$l_Q*dd~C?jmBHjbxRJNN{wj
z!zVb#YhmZXEU)nRtdoT`O3E-sN2lB!F#STcb@Z>hcQ@gFR(kQ#D!G{|4ZQ|!$V{yy
zhbtk_SLy``1VyLv@+)N!c{`*Yop*Z#ewP~Tq_wM8579pt5Sg?&vxH9+K-`4A!hit?
zNuf_N;QQ`~ME5<hD=dCpN<r0qT!^f(_DtYAO;aaPSv!cX`5+a2jlwcMHTCBP+%Hy{
zwoA3vGa{XBPHXF=N`NG3=<NrIK+{OrnWYmjWlv8B^o|OfMhAwCNPq!7IIJ_Z5KTk-
z`4a=@^kQA}TpgrUWp;dl(Lb7;H2|N%p^FkAF^)vB6iA$gy72%h5okzwd?t6Ea}W}*
z)WYfs88|_v$esrNmKq(z+IFZ99QXs?)?3?-m5H>ZxBqyIn-P9}_}VWyLUrSq8c1OJ
zX<#4{y`7}wRg6OxR=PHYu+sdCYn8yTgK|hi2VGoeZY2t{<185dkY0at?3PcNKy?|T
z_Mjs#4Ga!(K}Tk>988<&qX@(+I3_LBwIL~o>p*40^dn0e7y%#Zd}ngX?+FLbU%oON
zw}_anRhjHx%PnnGAT*E=^bSeR<+ivMXO{|`P*;io6Zp<z?`Q*K%iTD5aWPHl>gms@
zRn~*8&Uui4PQb)mdQ6~PbO%$7>}Y734v-4a|C6T&cP#Zx85^H?t6ZeLkD1iM1ksS2
z+emh~c+#~nuTuIz*|3jtN<(GckNQ4|^;{|eoRBhsdQ1t5s(}fhfxq*3(plHSf=bz}
z3JE}i&`^RHmGYIp{o9kZs78JR`v9Ad1_oPDRX6i^QB~cP0vAElH1Ky`g=B8`XNfD9
z>Kyj2LL2UEqfghuGQM(HW^5s<hW##Jnu_5}*b~d~T`GaFSPr`c?h=?y%rFfZ=t{Xj
z^@D3+wM>6h2r|iBgs7AmNgSuBe=$c}{32d`@||~3v==+GWCTYJ2`~ZrK&m9#qprnf
z+deLKJf?=Z5RXz$Q4Im5+_~^68q>YaKXP8F;BczV<w>ZKL%U4yBzj`DwLg~Qk<shx
zOZdu3Jl&WJQU8$`E4^sKCn$QOJLjK<u-1mfWz718$5*+obfK|{Nx57Q95aku3)pIP
zL1wgr63VB)zcRdmIWEif*4EBiNS7R(Dk%AV2nl4N7^E{gCI5FI5%N@><2W2naV<&6
zD!UK*{t;Yab?{6@iM5u44JI)CBDLits_8sKSAV*;rL<N#g(+ihz${=Xu$kgAO7MF1
z71Woz)h~j&-LNx?om{bwz`T=`{7Qmk&^g+{y-Z++%Y^E=-o9f=?nGlnXHTC2Q;rLn
z8!-|jflY~*j+m7EK@=I^J+U8Pj|eqZ_})Znl@^Gw0rsPF$2?%_@w-T6K8@#uC*^uq
zWokZN4Hrrok^sj{h~bh7<(NKo<{Sst?@h`XC=+TZ!bs8+@H?iSC)Qpcz5Z*!f+ID3
z@7`9Z(O|XQ1ZlKU%n=wNSEQLc*xPRcqOU-svC|8y2_Fs{B<l%MD1|`PfO9`K{PRc}
zW_nTm2KXurwi6XlON?3s8o?E5XL^ntGh>#v1w_8VN-Mn06>BMym~wZ(Z<uzmrvChm
zn`3GJ<OF3B`2=n}mU5x`k5Ykh^2<|arSR?@Xuj2;jzjqsQoIpU5qbhnP)(h2+<D;=
z8}>fCq@%-I6Svc$ZrSksCOBWYJ0hVM#|*mpVbei+kq9;-HXvVBPjH-T;CfyO4V?r3
z6NIxffAkKFdVi@$>I%RMv|a%Gt`1-0bsp|(mK&N*DNMEjzS4BLN~RwXsx05ijkW=}
zGxj?=x;vm`4d<K}g|H{a)Aensq+SNB2W$s;1A+mOfWSw;KL)&q{j!+jzX31oW@7ok
RBdh=b002ovPDHLkV1m-`bcp}}
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -170,31 +170,17 @@ let gSyncUI = {
   },
 
   onLoginFinish: function SUI_onLoginFinish() {
     // Clear out any login failure notifications
     let title = this._stringBundle.GetStringFromName("error.login.title");
     this.clearError(title);
   },
 
-  // Set visibility of "Setup Sync" link
-  showSetupSyncAboutHome: function SUI_showSetupSyncAboutHome(toShow) {
-    let browsers = gBrowser.browsers;
-    for (let i = 0; i < browsers.length; i++) {
-      let b = browsers[i];
-      if ("about:home" == b.currentURI.spec) {
-        b.contentDocument.getElementById("setupSyncLink").hidden = !toShow;
-      }
-    }
-  },
-
   onSetupComplete: function SUI_onSetupComplete() {
-    // Remove "setup sync" link in about:home if it is open. 
-    this.showSetupSyncAboutHome(false);
-
     onLoginFinish();
   },
 
   onLoginError: function SUI_onLoginError() {
     // if login fails, any other notifications are essentially moot
     Weave.Notifications.removeAll();
 
     // if we haven't set up the client, don't show errors
@@ -232,18 +218,16 @@ let gSyncUI = {
   },
 
   onLogout: function SUI_onLogout() {
     this.updateUI();
   },
 
   onStartOver: function SUI_onStartOver() {
     this.clearError();
-    // Make "setup sync" link visible in about:home if it is open. 
-    this.showSetupSyncAboutHome(true);
   },
 
   onQuotaNotice: function onQuotaNotice(subject, data) {
     let title = this._stringBundle.GetStringFromName("warning.sync.quota.label");
     let description = this._stringBundle.GetStringFromName("warning.sync.quota.description");
     let buttons = [];
     buttons.push(new Weave.NotificationButton(
       this._stringBundle.GetStringFromName("error.sync.viewQuotaButton.label"),
--- a/browser/base/content/browser-thumbnails.js
+++ b/browser/base/content/browser-thumbnails.js
@@ -105,16 +105,25 @@ let gBrowserThumbnails = {
       return false;
 
     // Don't take screenshots of about: pages.
     if (aBrowser.currentURI.schemeIs("about"))
       return false;
 
     let channel = aBrowser.docShell.currentDocumentChannel;
 
+    // No valid document channel. We shouldn't take a screenshot.
+    if (!channel)
+      return false;
+
+    // Don't take screenshots of internally redirecting about: pages.
+    // This includes error pages.
+    if (channel.originalURI.schemeIs("about"))
+      return false;
+
     try {
       // If the channel is a nsIHttpChannel get its http status code.
       let httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
 
       // Continue only if we have a 2xx status code.
       return Math.floor(httpChannel.responseStatus / 100) == 2;
     } catch (e) {
       // Not a http channel, we just assume a success status code.
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -51,16 +51,17 @@
 #   Dietrich Ayala <dietrich@mozilla.com>
 #   Gavin Sharp <gavin@gavinsharp.com>
 #   Justin Dolske <dolske@mozilla.com>
 #   Rob Campbell <rcampbell@mozilla.com>
 #   David Dahl <ddahl@mozilla.com>
 #   Patrick Walton <pcwalton@mozilla.com>
 #   Mihai Sucan <mihai.sucan@gmail.com>
 #   Victor Porof <vporof@mozilla.com>
+#   Frank Yan <fyan@mozilla.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
@@ -2701,99 +2702,93 @@ function PageProxyClickHandler(aEvent)
  *  Handle load of some pages (about:*) so that we can make modifications
  *  to the DOM for unprivileged pages.
  */
 function BrowserOnAboutPageLoad(document) {
   if (/^about:home$/i.test(document.documentURI)) {
     let ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
              getService(Components.interfaces.nsISessionStore);
     if (!ss.canRestoreLastSession)
-      document.getElementById("sessionRestoreContainer").hidden = true;
-    // Sync-related links
-    if (Services.prefs.prefHasUserValue("services.sync.username")) {
-      document.getElementById("setupSyncLink").hidden = true;
-    }
+      document.getElementById("launcher").removeAttribute("session");
   }
 }
 
 /**
  * Handle command events bubbling up from error page content
  */
 function BrowserOnClick(event) {
-    // Don't trust synthetic events
-    if (!event.isTrusted ||
-        (event.target.localName != "button" &&
-         event.target.className != "sync-link"))
+    if (!event.isTrusted || // Don't trust synthetic events
+        event.button == 2 || event.target.localName != "button")
       return;
 
     var ot = event.originalTarget;
-    var errorDoc = ot.ownerDocument;
+    var ownerDoc = ot.ownerDocument;
 
     // If the event came from an ssl error page, it is probably either the "Add
     // Exception…" or "Get me out of here!" button
-    if (/^about:certerror/.test(errorDoc.documentURI)) {
-      if (ot == errorDoc.getElementById('exceptionDialogButton')) {
+    if (/^about:certerror/.test(ownerDoc.documentURI)) {
+      if (ot == ownerDoc.getElementById('exceptionDialogButton')) {
         var params = { exceptionAdded : false, handlePrivateBrowsing : true };
 
         try {
           switch (gPrefService.getIntPref("browser.ssl_override_behavior")) {
             case 2 : // Pre-fetch & pre-populate
               params.prefetchCert = true;
             case 1 : // Pre-populate
-              params.location = errorDoc.location.href;
+              params.location = ownerDoc.location.href;
           }
         } catch (e) {
           Components.utils.reportError("Couldn't get ssl_override pref: " + e);
         }
 
         window.openDialog('chrome://pippki/content/exceptionDialog.xul',
                           '','chrome,centerscreen,modal', params);
 
         // If the user added the exception cert, attempt to reload the page
         if (params.exceptionAdded)
-          errorDoc.location.reload();
+          ownerDoc.location.reload();
       }
-      else if (ot == errorDoc.getElementById('getMeOutOfHereButton')) {
+      else if (ot == ownerDoc.getElementById('getMeOutOfHereButton')) {
         getMeOutOfHere();
       }
     }
-    else if (/^about:blocked/.test(errorDoc.documentURI)) {
+    else if (/^about:blocked/.test(ownerDoc.documentURI)) {
       // The event came from a button on a malware/phishing block page
       // First check whether it's malware or phishing, so that we can
       // use the right strings/links
-      var isMalware = /e=malwareBlocked/.test(errorDoc.documentURI);
-
-      if (ot == errorDoc.getElementById('getMeOutButton')) {
+      var isMalware = /e=malwareBlocked/.test(ownerDoc.documentURI);
+
+      if (ot == ownerDoc.getElementById('getMeOutButton')) {
         getMeOutOfHere();
       }
-      else if (ot == errorDoc.getElementById('reportButton')) {
+      else if (ot == ownerDoc.getElementById('reportButton')) {
         // This is the "Why is this site blocked" button.  For malware,
         // we can fetch a site-specific report, for phishing, we redirect
         // to the generic page describing phishing protection.
 
         if (isMalware) {
           // Get the stop badware "why is this blocked" report url,
           // append the current url, and go there.
           try {
             let reportURL = formatURL("browser.safebrowsing.malware.reportURL", true);
-            reportURL += errorDoc.location.href;
+            reportURL += ownerDoc.location.href;
             content.location = reportURL;
           } catch (e) {
             Components.utils.reportError("Couldn't get malware report URL: " + e);
           }
         }
         else { // It's a phishing site, not malware
           try {
             content.location = formatURL("browser.safebrowsing.warning.infoURL", true);
           } catch (e) {
             Components.utils.reportError("Couldn't get phishing info URL: " + e);
           }
         }
       }
-      else if (ot == errorDoc.getElementById('ignoreWarningButton')) {
+      else if (ot == ownerDoc.getElementById('ignoreWarningButton')) {
         // Allow users to override and continue through to the site,
         // but add a notify bar as a reminder, so that they don't lose
         // track after, e.g., tab switching.
         gBrowser.loadURIWithFlags(content.location.href,
                                   nsIWebNavigation.LOAD_FLAGS_BYPASS_CLASSIFIER,
                                   null, null, null);
 
         Services.perms.add(makeURI(content.location.href), "safe-browsing",
@@ -2838,33 +2833,41 @@ function BrowserOnClick(event) {
           title,
           value,
           "chrome://global/skin/icons/blacklist_favicon.png",
           notificationBox.PRIORITY_CRITICAL_HIGH,
           buttons
         );
       }
     }
-    else if (/^about:home$/i.test(errorDoc.documentURI)) {
-      if (ot == errorDoc.getElementById("restorePreviousSession")) {
+    else if (/^about:home$/i.test(ownerDoc.documentURI)) {
+      if (ot == ownerDoc.getElementById("restorePreviousSession")) {
         let ss = Cc["@mozilla.org/browser/sessionstore;1"].
                  getService(Ci.nsISessionStore);
         if (ss.canRestoreLastSession)
           ss.restoreLastSession();
-        errorDoc.getElementById("sessionRestoreContainer").hidden = true;
+        ownerDoc.getElementById("launcher").removeAttribute("session");
+      }
+      else if (ot == ownerDoc.getElementById("bookmarks")) {
+        PlacesCommandHook.showPlacesOrganizer("AllBookmarks");
+      }
+      else if (ot == ownerDoc.getElementById("history")) {
+        PlacesCommandHook.showPlacesOrganizer("History");
       }
-      else if (ot == errorDoc.getElementById("pairDeviceLink")) {
-        if (Services.prefs.prefHasUserValue("services.sync.username")) {
-          gSyncUI.openAddDevice();
-        } else {
-          gSyncUI.openSetup("pair");
-        }
+      else if (ot == ownerDoc.getElementById("settings")) {
+        openPreferences();
+      }
+      else if (ot == ownerDoc.getElementById("addons")) {
+        BrowserOpenAddonsMgr();
       }
-      else if (ot == errorDoc.getElementById("setupSyncLink")) {
-        gSyncUI.openSetup(null);
+      else if (ot == ownerDoc.getElementById("downloads")) {
+        BrowserDownloadsUI();
+      }
+      else if (ot == ownerDoc.getElementById("sync")) {
+        openPreferences("paneSync");
       }
     }
 }
 
 /**
  * Re-direct the browser to a known-safe page.  This function is
  * used when, for example, the user browses to a known malware page
  * and is presented with about:blocked.  The "Get me out of here!"
@@ -5115,16 +5118,17 @@ var TabsProgressListener = {
     // Attach a listener to watch for "click" events bubbling up from error
     // pages and other similar page. This lets us fix bugs like 401575 which
     // require error page UI to do privileged things, without letting error
     // pages have any privilege themselves.
     // We can't look for this during onLocationChange since at that point the
     // document URI is not yet the about:-uri of the error page.
 
     if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
+        Components.isSuccessCode(aStatus) &&
         /^about:/.test(aWebProgress.DOMWindow.document.documentURI)) {
       aBrowser.addEventListener("click", BrowserOnClick, false);
       aBrowser.addEventListener("pagehide", function () {
         aBrowser.removeEventListener("click", BrowserOnClick, false);
         aBrowser.removeEventListener("pagehide", arguments.callee, true);
       }, true);
 
       // We also want to make changes to page UI for unprivileged about pages.
--- a/browser/base/content/newtab/drop.js
+++ b/browser/base/content/newtab/drop.js
@@ -89,17 +89,21 @@ let gDrop = {
     if (draggedSite) {
       // Pin the dragged site at its new place.
       if (aCell != draggedSite.cell)
         draggedSite.pin(index);
     } else {
       // A new link was dragged onto the grid. Create it by pinning its URL.
       let dt = aEvent.dataTransfer;
       let [url, title] = dt.getData("text/x-moz-url").split(/[\r\n]+/);
-      gPinnedLinks.pin({url: url, title: title}, index);
+      let link = {url: url, title: title};
+      gPinnedLinks.pin(link, index);
+
+      // Make sure the newly added link is not blocked.
+      gBlockedLinks.unblock(link);
     }
   },
 
   /**
    * Time a rearrange with a little delay.
    * @param aCell The drop target cell.
    */
   _delayedRearrange: function Drop_delayedRearrange(aCell) {
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -87,16 +87,17 @@ nsContextMenu.prototype = {
     this.isFrameImage = document.getElementById("isFrameImage");
     this.ellipsis = "\u2026";
     try {
       this.ellipsis = gPrefService.getComplexValue("intl.ellipsis",
                                                    Ci.nsIPrefLocalizedString).data;
     } catch (e) { }
     this.isTextSelected = this.isTextSelection();
     this.isContentSelected = this.isContentSelection();
+    this.onPlainTextLink = false;
 
     // Initialize (disable/remove) menu items.
     this.initItems();
   },
 
   hiding: function CM_hiding() {
     InlineSpellCheckerUI.clearSuggestionsFromMenu();
     InlineSpellCheckerUI.clearDictionaryListFromMenu();
@@ -127,17 +128,16 @@ nsContextMenu.prototype = {
                           getProtocolHandlerInfo("mailto");
       isMailtoInternal = (!mailtoHandler.alwaysAskBeforeHandling &&
                           mailtoHandler.preferredAction == Ci.nsIHandlerInfo.useHelperApp &&
                           (mailtoHandler.preferredApplicationHandler instanceof Ci.nsIWebHandlerApp));
     }
 
     // Time to do some bad things and see if we've highlighted a URL that
     // isn't actually linked.
-    var onPlainTextLink = false;
     if (this.isTextSelected && !this.onLink) {
       // Ok, we have some text, let's figure out if it looks like a URL.
       let selection =  document.commandDispatcher.focusedWindow
                                .getSelection();
       let linkText = selection.toString().trim();
       let uri;
       if (/^(?:https?|ftp):/i.test(linkText)) {
         try {
@@ -185,24 +185,24 @@ nsContextMenu.prototype = {
             uri = uriFixup.createFixupURI(linkText, uriFixup.FIXUP_FLAG_NONE);
           } catch (ex) {}
         }
       }
 
       if (uri && uri.host) {
         this.linkURI = uri;
         this.linkURL = this.linkURI.spec;
-        onPlainTextLink = true;
+        this.onPlainTextLink = true;
       }
     }
 
-    var shouldShow = this.onSaveableLink || isMailtoInternal || onPlainTextLink;
+    var shouldShow = this.onSaveableLink || isMailtoInternal || this.onPlainTextLink;
     this.showItem("context-openlink", shouldShow);
     this.showItem("context-openlinkintab", shouldShow);
-    this.showItem("context-openlinkincurrent", onPlainTextLink);
+    this.showItem("context-openlinkincurrent", this.onPlainTextLink);
     this.showItem("context-sep-open", shouldShow);
   },
 
   initNavigationItems: function CM_initNavigationItems() {
     var shouldShow = !(this.isContentSelected || this.onLink || this.onImage ||
                        this.onCanvas || this.onVideo || this.onAudio ||
                        this.onTextInput);
     this.showItem("context-back", shouldShow);
@@ -217,19 +217,19 @@ nsContextMenu.prototype = {
 
   initSaveItems: function CM_initSaveItems() {
     var shouldShow = !(this.onTextInput || this.onLink ||
                        this.isContentSelected || this.onImage ||
                        this.onCanvas || this.onVideo || this.onAudio);
     this.showItem("context-savepage", shouldShow);
     this.showItem("context-sendpage", shouldShow);
 
-    // Save+Send link depends on whether we're in a link.
-    this.showItem("context-savelink", this.onSaveableLink);
-    this.showItem("context-sendlink", this.onSaveableLink);
+    // Save+Send link depends on whether we're in a link, or selected text matches valid URL pattern.
+    this.showItem("context-savelink", this.onSaveableLink || this.onPlainTextLink);
+    this.showItem("context-sendlink", this.onSaveableLink || this.onPlainTextLink);
 
     // Save image depends on having loaded its content, video and audio don't.
     this.showItem("context-saveimage", this.onLoadedImage || this.onCanvas);
     this.showItem("context-savevideo", this.onVideo);
     this.showItem("context-saveaudio", this.onAudio);
     this.showItem("context-video-saveimage", this.onVideo);
     this.setItemAttr("context-savevideo", "disabled", !this.mediaURL);
     this.setItemAttr("context-saveaudio", "disabled", !this.mediaURL);
@@ -305,17 +305,17 @@ nsContextMenu.prototype = {
 
   initMiscItems: function CM_initMiscItems() {
     var isTextSelected = this.isTextSelected;
 
     // Use "Bookmark This Link" if on a link.
     this.showItem("context-bookmarkpage",
                   !(this.isContentSelected || this.onTextInput || this.onLink ||
                     this.onImage || this.onVideo || this.onAudio));
-    this.showItem("context-bookmarklink", this.onLink && !this.onMailtoLink);
+    this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink) || this.onPlainTextLink);
     this.showItem("context-searchselect", isTextSelected);
     this.showItem("context-keywordfield",
                   this.onTextInput && this.onKeywordField);
     this.showItem("frame", this.inFrame);
     this.showItem("frame-sep", this.inFrame && isTextSelected);
 
     // Hide menu entries for images, show otherwise
     if (this.inFrame) {
@@ -1068,19 +1068,25 @@ nsContextMenu.prototype = {
 
     // kick off the channel with our proxy object as the listener
     channel.asyncOpen(new saveAsListener(), null);
   },
 
   // Save URL of clicked-on link.
   saveLink: function() {
     var doc =  this.target.ownerDocument;
+    var linkText;
+    // If selected text is found to match valid URL pattern.
+    if (this.onPlainTextLink)
+      linkText = document.commandDispatcher.focusedWindow.getSelection().toString().trim();
+    else
+      linkText = this.linkText();
     urlSecurityCheck(this.linkURL, doc.nodePrincipal);
 
-    this.saveHelper(this.linkURL, this.linkText(), null, true, doc);
+    this.saveHelper(this.linkURL, linkText, null, true, doc);
   },
 
   sendLink: function() {
     // we don't know the title of the link so pass in an empty string
     MailIntegration.sendMessage( this.linkURL, "" );
   },
 
   // Backwards-compatibility wrapper
@@ -1385,18 +1391,24 @@ nsContextMenu.prototype = {
     openUILinkIn(uri, where);
   },
 
   bookmarkThisPage: function CM_bookmarkThisPage() {
     window.top.PlacesCommandHook.bookmarkPage(this.browser, PlacesUtils.bookmarksMenuFolderId, true);
   },
 
   bookmarkLink: function CM_bookmarkLink() {
+    var linkText;
+    // If selected text is found to match valid URL pattern.
+    if (this.onPlainTextLink)
+      linkText = document.commandDispatcher.focusedWindow.getSelection().toString().trim();
+    else
+      linkText = this.linkText();
     window.top.PlacesCommandHook.bookmarkLink(PlacesUtils.bookmarksMenuFolderId, this.linkURL,
-                                              this.linkText());
+                                              linkText);
   },
 
   addBookmarkForFrame: function CM_addBookmarkForFrame() {
     var doc = this.target.ownerDocument;
     var uri = doc.documentURIObject;
 
     var itemId = PlacesUtils.getMostRecentBookmarkForURI(uri);
     if (itemId == -1) {
--- a/browser/base/content/test/browser_aboutHome.js
+++ b/browser/base/content/test/browser_aboutHome.js
@@ -5,19 +5,16 @@
 registerCleanupFunction(function() {
   // Ensure we don't pollute prefs for next tests.
   try {
     Services.prefs.clearUserPref("network.cookies.cookieBehavior");
   } catch (ex) {}
   try {
     Services.prefs.clearUserPref("network.cookie.lifetimePolicy");
   } catch (ex) {}
-  try {
-    Services.prefs.clearUserPref("services.sync.username");
-  } catch (ex) {}
 });
 
 let gTests = [
 
 {
   desc: "Check that rejecting cookies does not prevent page from working",
   setup: function ()
   {
@@ -107,131 +104,21 @@ let gTests = [
   run: function ()
   {
     let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
 
     let snippetsElt = doc.getElementById("snippets");
     ok(snippetsElt, "Found snippets element");
     is(snippetsElt.getElementsByTagName("span").length, 1,
        "A default snippet is visible.");
-
+    let storage = getStorage();
+    storage.removeItem("snippets");
     executeSoon(runNextTest);
   }
 },
-
-{
-  desc: "Check sync links visibility before and after Sync setup",
-  setup: function ()
-  {
-    try {
-      Services.prefs.clearUserPref("services.sync.username");
-    } catch (ex) {}
-    Services.obs.notifyObservers(null, "weave:service:ready", null);
-  },
-  run: function ()
-  {
-    let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
-    let pairLink = doc.getElementById("pairDeviceLink");
-    let setupLink = doc.getElementById("setupSyncLink");
-
-    ok(pairLink, "Found 'Pair Device' link");
-    ok(setupLink, "Found 'Set Up Sync' link");
-    ok(!pairLink.hidden, "'Pair' link is visible before setup");
-    ok(!setupLink.hidden, "'Set Up' link is visible before setup");
-
-    Services.obs.notifyObservers(null, "weave:service:setup-complete", null);
-
-    executeSoon(function () {
-      setupLink = doc.getElementById("setupSyncLink");
-      ok(setupLink.hidden, "'Set Up' link is hidden after setup");
-      ok(!pairLink.hidden, "'Pair' link is visible after setup");
-
-      executeSoon(runNextTest);
-    });
-  }
-},
-
-{
-  desc: "Check sync links visibility before and after Sync unlink",
-  setup: function ()
-  {
-    Services.prefs.setCharPref("services.sync.username", "someuser@domain.com");
-    Services.obs.notifyObservers(null, "weave:service:ready", null);
-  },
-  run: function ()
-  {
-    let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
-    let pairLink = doc.getElementById("pairDeviceLink");
-    let setupLink = doc.getElementById("setupSyncLink");
-
-    ok(!pairLink.hidden, "'Pair' link is visible before unlink");
-    ok(setupLink.hidden, "'Set Up' link is hidden before unlink");
-
-    Services.obs.notifyObservers(null, "weave:service:start-over", null);
-
-    executeSoon(function () {
-      setupLink = doc.getElementById("setupSyncLink");
-      ok(!setupLink.hidden, "'Set Up' link is visible after unlink");
-      ok(!pairLink.hidden, "'Pair' link is visible after unlink");
-      executeSoon(runNextTest);
-    });
-  }
-},
-
-{
-  desc: "Check Pair Device link opens correct dialog with Sync account ",
-  setup: function ()
-  {
-    Services.prefs.setCharPref("services.sync.username", "someuser@domain.com");
-    Services.obs.notifyObservers(null, "weave:service:ready", null);
-  },
-  run: function ()
-  {
-    expectDialogWindow("Sync:AddDevice");
-    let browser = gBrowser.selectedTab.linkedBrowser;
-    let button = browser.contentDocument.getElementById("pairDeviceLink");
-    EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow);
-  }
-},
-
-{
-  desc: "Check Pair Device link opens correct dialog without Sync account",
-  setup: function ()
-  {
-    try {
-      Services.prefs.clearUserPref("services.sync.username");
-    } catch (ex) {}
-    Services.obs.notifyObservers(null, "weave:service:ready", null);
-  },
-  run: function ()
-  {
-    expectDialogWindow("Weave:AccountSetup");
-    let browser = gBrowser.selectedTab.linkedBrowser;
-    let button = browser.contentDocument.getElementById("pairDeviceLink");
-    EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow);
-  }
-},
-
-{
-  desc: "Check Sync Setup link opens correct dialog (without Sync account)",
-  setup: function ()
-  {
-    try {
-      Services.prefs.clearUserPref("services.sync.username");
-    } catch (ex) {}
-    Services.obs.notifyObservers(null, "weave:service:ready", null);
-  },
-  run: function ()
-  {
-    expectDialogWindow("Weave:AccountSetup");
-    let browser = gBrowser.selectedTab.linkedBrowser;
-    let button = browser.contentDocument.getElementById("setupSyncLink");
-    EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow);
-  }
-},
 ];
 
 function test()
 {
   waitForExplicitFinish();
 
   // browser-chrome test harness inits browser specifying an hardcoded page
   // and this causes nsIBrowserHandler.defaultArgs to not be evaluated since
@@ -267,32 +154,16 @@ function runNextTest()
       executeSoon(test.run);
     }, true);
   }
   else {
     finish();
   }
 }
 
-function expectDialogWindow(expectedDialog) {
-  Services.ww.registerNotification(function onWindow(subject, topic) {
-    let win = subject.QueryInterface(Components.interfaces.nsIDOMWindow);
-    win.addEventListener("load", function onLoad() {
-      win.removeEventListener("load", onLoad, false);
-      let wintype = win.document.documentElement.getAttribute("windowtype");
-      if (topic == "domwindowopened" && wintype == expectedDialog) {
-        Services.ww.unregisterNotification(onWindow);
-        // Clean up dialog.
-        win.close();
-        executeSoon(runNextTest);
-      }
-    }, false);
-  });
-}
-
 function getStorage()
 {
   let aboutHomeURI = Services.io.newURI("moz-safe-about:home", null, null);
   let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
                   getService(Components.interfaces.nsIScriptSecurityManager).
                   getCodebasePrincipal(Services.io.newURI("about:home", null, null));
   let dsm = Components.classes["@mozilla.org/dom/storagemanager;1"].
             getService(Components.interfaces.nsIDOMStorageManager);
--- a/browser/base/content/test/newtab/Makefile.in
+++ b/browser/base/content/test/newtab/Makefile.in
@@ -20,13 +20,14 @@ include $(topsrcdir)/config/rules.mk
 	browser_newtab_reset.js \
 	browser_newtab_tabsync.js \
 	browser_newtab_unpin.js \
 	browser_newtab_bug722273.js \
 	browser_newtab_bug723102.js \
 	browser_newtab_bug723121.js \
 	browser_newtab_bug725996.js \
 	browser_newtab_bug734043.js \
+	browser_newtab_bug735987.js \
 	head.js \
 	$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
--- a/browser/base/content/test/newtab/browser_newtab_block.js
+++ b/browser/base/content/test/newtab/browser_newtab_block.js
@@ -20,41 +20,41 @@ function runTests() {
 
   yield blockCell(cells[4]);
   checkGrid("0,1,2,3,6,7,8,9,");
 
   yield blockCell(cells[4]);
   checkGrid("0,1,2,3,7,8,9,,");
 
   // we removed a pinned site
-  reset();
+  yield restore();
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks(",1");
 
   yield addNewTabPageTab();
   checkGrid("0,1p,2,3,4,5,6,7,8");
 
   yield blockCell(cells[1]);
   checkGrid("0,2,3,4,5,6,7,8,");
 
   // we remove the last site on the grid (which is pinned) and expect the gap
   // to be re-filled and the new site to be unpinned
-  reset();
+  yield restore();
   setLinks("0,1,2,3,4,5,6,7,8,9");
   setPinnedLinks(",,,,,,,,8");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8p");
 
   yield blockCell(cells[8]);
   checkGrid("0,1,2,3,4,5,6,7,9");
 
   // we remove the first site on the grid with the last one pinned. all cells
   // but the last one should shift to the left and a new site fades in
-  reset();
+  yield restore();
   setLinks("0,1,2,3,4,5,6,7,8,9");
   setPinnedLinks(",,,,,,,,8");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8p");
 
   yield blockCell(cells[0]);
   checkGrid("1,2,3,4,5,6,7,9,8p");
--- a/browser/base/content/test/newtab/browser_newtab_bug734043.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug734043.js
@@ -1,30 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function runTests() {
-  // TODO Bug 735166 - Intermittent timeout in browser_newtab_bug734043.js
-  return;
-
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7,8");
 
   let receivedError = false;
   let block = cw.document.querySelector(".newtab-control-block");
 
   function onError() {
     receivedError = true;
   }
 
   cw.addEventListener("error", onError);
 
-  for (let i = 0; i < 3; i++) {
+  for (let i = 0; i < 3; i++)
     EventUtils.synthesizeMouseAtCenter(block, {}, cw);
-    yield executeSoon(TestRunner.next);
-  }
 
   yield whenPagesUpdated();
   ok(!receivedError, "we got here without any errors");
   cw.removeEventListener("error", onError);
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_bug735987.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function runTests() {
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7,8");
+
+  yield simulateDrop(cells[1]);
+  checkGrid("0,99p,1,2,3,4,5,6,7");
+
+  yield blockCell(cells[1]);
+  checkGrid("0,1,2,3,4,5,6,7,8");
+
+  yield simulateDrop(cells[1]);
+  checkGrid("0,99p,1,2,3,4,5,6,7");
+
+  yield blockCell(cells[1]);
+  checkGrid("0,1,2,3,4,5,6,7,8");
+}
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -5,18 +5,16 @@ const PREF_NEWTAB_ENABLED = "browser.new
 
 Services.prefs.setBoolPref(PREF_NEWTAB_ENABLED, true);
 
 let tmp = {};
 Cu.import("resource:///modules/NewTabUtils.jsm", tmp);
 let NewTabUtils = tmp.NewTabUtils;
 
 registerCleanupFunction(function () {
-  reset();
-
   while (gBrowser.tabs.length > 1)
     gBrowser.removeTab(gBrowser.tabs[1]);
 
   Services.prefs.clearUserPref(PREF_NEWTAB_ENABLED);
 });
 
 /**
  * Global variables that are accessed by tests.
@@ -52,18 +50,39 @@ let TestRunner = {
 
   /**
    * Runs the next available test or finishes if there's no test left.
    */
   next: function () {
     try {
       TestRunner._iter.next();
     } catch (e if e instanceof StopIteration) {
-      finish();
+      TestRunner.finish();
     }
+  },
+
+  /**
+   * Finishes all tests and cleans up.
+   */
+  finish: function () {
+    function cleanupAndFinish() {
+      // Restore the old provider.
+      NewTabUtils.links._provider = originalProvider;
+
+      whenPagesUpdated(finish);
+      NewTabUtils.restore();
+    }
+
+    let callbacks = NewTabUtils.links._populateCallbacks;
+    let numCallbacks = callbacks.length;
+
+    if (numCallbacks)
+      callbacks.splice(0, numCallbacks, cleanupAndFinish);
+    else
+      cleanupAndFinish();
   }
 };
 
 /**
  * Allows to provide a list of links that is used to construct the grid.
  * @param aLinksPattern the pattern (see below)
  *
  * Example: setLinks("1,2,3")
@@ -101,23 +120,21 @@ function setPinnedLinks(aLinksPattern) {
     pinnedLinks[index] = link;
   });
 
   // Inject the list of pinned links to work with.
   NewTabUtils.pinnedLinks._links = pinnedLinks;
 }
 
 /**
- * Resets the lists of blocked and pinned links and clears the storage.
+ * Restore the grid state.
  */
-function reset() {
-  NewTabUtils.reset();
-
-  // Restore the old provider to prevent memory leaks.
-  NewTabUtils.links._provider = originalProvider;
+function restore() {
+  whenPagesUpdated();
+  NewTabUtils.restore();
 }
 
 /**
  * Creates a new tab containing 'about:newtab'.
  */
 function addNewTabPageTab() {
   let tab = gBrowser.selectedTab = gBrowser.addTab("about:newtab");
   let browser = tab.linkedBrowser;
@@ -264,21 +281,21 @@ function simulateDrop(aDropTarget, aDrag
 
   if (aDragSource)
     cw.gDrag.end(aDragSource.site);
 }
 
 /**
  * Resumes testing when all pages have been updated.
  */
-function whenPagesUpdated() {
+function whenPagesUpdated(aCallback) {
   let page = {
     update: function () {
       NewTabUtils.allPages.unregister(this);
-      executeSoon(TestRunner.next);
+      executeSoon(aCallback || TestRunner.next);
     }
   };
 
   NewTabUtils.allPages.register(page);
   registerCleanupFunction(function () {
     NewTabUtils.allPages.unregister(page);
   });
 }
--- a/browser/base/content/test/subtst_contextmenu.html
+++ b/browser/base/content/test/subtst_contextmenu.html
@@ -53,11 +53,13 @@ Browser context menu subtest.
       <menuitem label="Bogus item"></menuitem>
     </menu>
     <menu>
     </menu>
     <menuitem label="Hidden item" hidden></menuitem>
     <menuitem></menuitem>
   </menu>
 </div>
+<div id="test-select-text">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</div>
+<div id="test-select-text-link">http://mozilla.com</div>
 
 </body>
 </html>
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -15,16 +15,17 @@ Browser context menu tests.
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Login Manager: multiple login autocomplete. **/
 
 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 function openContextMenuFor(element, shiftkey, shouldWaitForFocus) {
     // Context menu should be closed before we open it again.
     is(contextMenu.state, "closed", "checking if popup is closed");
 
@@ -67,16 +68,26 @@ function invokeItemAction(generatedItemI
 {
   var item = contextMenu.getElementsByAttribute("generateditemid",
                                                 generatedItemId)[0];
   ok(item, "Got generated XUL menu item");
   item.doCommand();
   ok(!pagemenu.hasAttribute("hopeless"), "attribute got removed");
 }
 
+function selectText(element) {
+  // Clear any previous selections before selecting new element.
+  subwindow.getSelection().removeAllRanges();
+
+  var div = subwindow.document.createRange();
+  div.setStartBefore(element);
+  div.setEndAfter(element);
+  subwindow.getSelection().addRange(div);
+}
+
 function getVisibleMenuItems(aMenu, aData) {
     var items = [];
     var accessKeys = {};
     for (var i = 0; i < aMenu.childNodes.length; i++) {
         var item = aMenu.childNodes[i];
         if (item.hidden)
             continue;
 
@@ -662,24 +673,62 @@ function runTest(testNum) {
                           "---",                  null,
                           "context-viewbgimage",  false,
                           "context-selectall",    true,
                           "---",                  null,
                           "context-viewsource",   true,
                           "context-viewinfo",     true
                          ].concat(inspectItems));
         closeContextMenu();
+        selectText(selecttext); // Select text prior to opening context menu.
+        openContextMenuFor(selecttext); // Invoke context menu for next test.
+        return;
+
+    case 22:
+        // Context menu for selected text
+        if (Services.appinfo.OS == "Darwin") {
+          // This test is only enabled on Mac due to bug 736399.
+          checkContextMenu(["context-copy",                        true,
+                            "context-selectall",                   true,
+                            "---",                                 null,
+                            "context-searchselect",                true,
+                            "context-viewpartialsource-selection", true
+                           ].concat(inspectItems));
+        }
+        closeContextMenu();
+        selectText(selecttextlink); // Select text prior to opening context menu.
+        openContextMenuFor(selecttextlink); // Invoke context menu for next test.
+        return;
+
+    case 23:
+        // Context menu for selected text which matches valid URL pattern
+        if (Services.appinfo.OS == "Darwin") {
+          // This test is only enabled on Mac due to bug 736399.
+          checkContextMenu(["context-openlinkincurrent",           true,
+                            "context-openlinkintab",               true,
+                            "context-openlink",                    true,
+                            "---",                                 null,
+                            "context-bookmarklink",                true,
+                            "context-savelink",                    true,
+                            "context-sendlink",                    true,
+                            "context-copy",                        true,
+                            "context-selectall",                   true,
+                            "---",                                 null,
+                            "context-searchselect",                true,
+                            "context-viewpartialsource-selection", true
+                           ].concat(inspectItems));
+        }
+        closeContextMenu();
 
         subwindow.close();
         SimpleTest.finish();
         return;
 
     /*
      * Other things that would be nice to test:
-     *  - selected text
      *  - spelling / misspelled word (in text input?)
      *  - check state of disabled items
      *  - test execution of menu items (maybe as a separate test?)
      */
 
     default:
         ok(false, "Unexpected invocation of test #" + testNum);
         subwindow.close();
@@ -729,16 +778,18 @@ function startTest() {
     video_in_iframe = subwindow.document.getElementById("test-video-in-iframe").contentDocument.getElementsByTagName("video")[0];
     video_in_iframe.pause();
     image_in_iframe = subwindow.document.getElementById("test-image-in-iframe").contentDocument.getElementsByTagName("img")[0];
     textarea = subwindow.document.getElementById("test-textarea");
     contenteditable = subwindow.document.getElementById("test-contenteditable");
     contenteditable.focus(); // content editable needs to be focused to enable spellcheck
     inputspell = subwindow.document.getElementById("test-input-spellcheck");
     pagemenu = subwindow.document.getElementById("test-pagemenu");
+    selecttext = subwindow.document.getElementById("test-select-text");
+    selecttextlink = subwindow.document.getElementById("test-select-text-link");
 
     contextMenu.addEventListener("popupshown", function() { runTest(++testNum); }, false);
     runTest(1);
 }
 
 // We open this in a separate window, because the Mochitests run inside a frame.
 // The frame causes an extra menu item, and prevents running the test
 // standalone (ie, clicking the test name in the Mochitest window) to see
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -105,21 +105,43 @@ function getBoolPref(prefname, def)
   try {
     return Services.prefs.getBoolPref(prefname);
   }
   catch(er) {
     return def;
   }
 }
 
-// openUILink handles clicks on UI elements that cause URLs to load.
-function openUILink( url, e, ignoreButton, ignoreAlt, allowKeywordFixup, postData, referrerUrl )
-{
-  var where = whereToOpenLink(e, ignoreButton, ignoreAlt);
-  openUILinkIn(url, where, allowKeywordFixup, postData, referrerUrl);
+/* openUILink handles clicks on UI elements that cause URLs to load.
+ *
+ * As the third argument, you may pass an object with the same properties as
+ * accepted by openUILinkIn, plus "ignoreButton" and "ignoreAlt".
+ */
+function openUILink(url, event, aIgnoreButton, aIgnoreAlt, aAllowThirdPartyFixup,
+                    aPostData, aReferrerURI) {
+  let params;
+
+  if (aIgnoreButton && typeof aIgnoreButton == "object") {
+    params = aIgnoreButton;
+
+    // don't forward "ignoreButton" and "ignoreAlt" to openUILinkIn
+    aIgnoreButton = params.ignoreButton;
+    aIgnoreAlt = params.ignoreAlt;
+    delete params.ignoreButton;
+    delete params.ignoreAlt;
+  } else {
+    params = {
+      allowThirdPartyFixup: aAllowThirdPartyFixup,
+      postData: aPostData,
+      referrerURI: aReferrerURI
+    };
+  }
+
+  let where = whereToOpenLink(event, aIgnoreButton, aIgnoreAlt);
+  openUILinkIn(url, where, params);
 }
 
 
 /* whereToOpenLink() looks at an event to decide where to open a link.
  *
  * The event may be a mouse event (click, double-click, middle-click) or keypress event (enter).
  *
  * On Windows, the modifiers are:
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -11,23 +11,31 @@ browser.jar:
 %  overlay chrome://global/content/viewSource.xul chrome://browser/content/viewSourceOverlay.xul
 %  overlay chrome://global/content/viewPartialSource.xul chrome://browser/content/viewSourceOverlay.xul
 %  style chrome://global/content/customizeToolbar.xul chrome://browser/content/browser.css
 %  style chrome://global/content/customizeToolbar.xul chrome://browser/skin/
 *       content/browser/aboutDialog.xul               (content/aboutDialog.xul)
 *       content/browser/aboutDialog.js                (content/aboutDialog.js)
 *       content/browser/aboutDialog.css               (content/aboutDialog.css)
 *       content/browser/aboutRobots.xhtml             (content/aboutRobots.xhtml)
-*       content/browser/aboutHome.xhtml               (content/aboutHome.xhtml)
-*       content/browser/aboutHome.js                  (content/aboutHome.js)
-*       content/browser/aboutHome.css                 (content/aboutHome.css)
-        content/browser/aboutHome-restore-icon.png    (content/aboutHome-restore-icon.png)
-        content/browser/aboutHome-restore-icon-small.png    (content/aboutHome-restore-icon-small.png)
-        content/browser/aboutHome-snippet1.png        (content/aboutHome-snippet1.png)
-        content/browser/aboutHome-snippet2.png        (content/aboutHome-snippet2.png)
+*       content/browser/abouthome/aboutHome.xhtml     (content/abouthome/aboutHome.xhtml)
+*       content/browser/abouthome/aboutHome.js        (content/abouthome/aboutHome.js)
+*       content/browser/abouthome/aboutHome.css       (content/abouthome/aboutHome.css)
+        content/browser/abouthome/snippet1.png        (content/abouthome/snippet1.png)
+        content/browser/abouthome/snippet2.png        (content/abouthome/snippet2.png)
+        content/browser/abouthome/bookmarks.png       (content/abouthome/bookmarks.png)
+        content/browser/abouthome/history.png         (content/abouthome/history.png)
+        content/browser/abouthome/settings.png        (content/abouthome/settings.png)
+        content/browser/abouthome/addons.png          (content/abouthome/addons.png)
+        content/browser/abouthome/downloads.png       (content/abouthome/downloads.png)
+        content/browser/abouthome/sync.png            (content/abouthome/sync.png)
+        content/browser/abouthome/restore.png         (content/abouthome/restore.png)
+        content/browser/abouthome/restore-large.png   (content/abouthome/restore-large.png)
+        content/browser/abouthome/mozilla.png         (content/abouthome/mozilla.png)
+        content/browser/abouthome/noise.png           (content/abouthome/noise.png)
         content/browser/aboutRobots-icon.png          (content/aboutRobots-icon.png)
         content/browser/aboutRobots-widget-left.png   (content/aboutRobots-widget-left.png)
 *       content/browser/browser.css                   (content/browser.css)
 *       content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xul                   (content/browser.xul)
 *       content/browser/browser-tabPreviews.xml       (content/browser-tabPreviews.xml)
 *       content/browser/content.js                    (content/content.js)
 *       content/browser/newtab/newTab.xul             (content/newtab/newTab.xul)
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -97,17 +97,17 @@ static RedirEntry kRedirMap[] = {
   { "sessionrestore", "chrome://browser/content/aboutSessionRestore.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
 #ifdef MOZ_SERVICES_SYNC
   { "sync-progress", "chrome://browser/content/sync/progress.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
   { "sync-tabs", "chrome://browser/content/sync/aboutSyncTabs.xul",
     nsIAboutModule::ALLOW_SCRIPT },
 #endif
-  { "home", "chrome://browser/content/aboutHome.xhtml",
+  { "home", "chrome://browser/content/abouthome/aboutHome.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT },
   { "newtab", "chrome://browser/content/newtab/newTab.xul",
     nsIAboutModule::ALLOW_SCRIPT },
   { "permissions", "chrome://browser/content/preferences/aboutPermissions.xul",
     nsIAboutModule::ALLOW_SCRIPT },
 };
 static const int kRedirTotal = NS_ARRAY_LENGTH(kRedirMap);
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -882,17 +882,17 @@ let AboutHomeUtils = {
       name: defaultEngine.name
     , searchUrl: submission.uri.spec
     }
     this._storage.setItem("search-engine", JSON.stringify(engine));
   },
 
   loadSnippetsURL: function AHU_loadSnippetsURL()
   {
-    const STARTPAGE_VERSION = 1;
+    const STARTPAGE_VERSION = 2;
     let updateURL = Services.prefs
                             .getCharPref(this.SNIPPETS_URL_PREF)
                             .replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION);
     updateURL = Services.urlFormatter.formatURL(updateURL);
     this._storage.setItem("snippets-update-url", updateURL);
   },
 };
 
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -63,17 +63,17 @@ XPCOMUtils.defineLazyGetter(this, "Place
   Cu.import("resource://gre/modules/PlacesUtils.jsm");
   return PlacesUtils;
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "KeywordURLResetPrompter",
                                   "resource:///modules/KeywordURLResetPrompter.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "webappsUI", 
-                                  "resource://gre/modules/webappsUI.jsm");
+                                  "resource:///modules/webappsUI.jsm");
 
 const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
 const PREF_PLUGINS_UPDATEURL  = "plugins.update.url";
 
 // We try to backup bookmarks at idle times, to avoid doing that at shutdown.
 // Number of idle seconds before trying to backup bookmarks.  15 minutes.
 const BOOKMARKS_BACKUP_IDLE_TIME = 15 * 60;
 // Minimum interval in milliseconds between backups.
--- a/browser/components/places/tests/unit/test_bookmarksRestoreNotification.js
+++ b/browser/components/places/tests/unit/test_bookmarksRestoreNotification.js
@@ -226,83 +226,18 @@ var tests = [
       this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
       this.file.append("this file doesn't exist because nobody created it");
       try {
         importer.importHTMLFromFile(this.file, true);
         do_throw("  Restore should have failed");
       }
       catch (e) {}
     }
-  },
-
-  {
-    desc:       "HTML restore into folder: normal restore should succeed",
-    currTopic:  NSIOBSERVER_TOPIC_BEGIN,
-    finalTopic: NSIOBSERVER_TOPIC_SUCCESS,
-    data:       NSIOBSERVER_DATA_HTML,
-    run:        function () {
-      this.file = createFile("bookmarks-test_restoreNotification.html");
-      addBookmarks();
-      importer.exportHTMLToFile(this.file);
-      remove_all_bookmarks();
-      this.folderId = bmsvc.createFolder(bmsvc.unfiledBookmarksFolder,
-                                         "test folder",
-                                         bmsvc.DEFAULT_INDEX);
-      print("  Sanity check: createFolder() should have succeeded");
-      do_check_true(this.folderId > 0);
-      try {
-        importer.importHTMLFromFileToFolder(this.file, this.folderId, false);
-      }
-      catch (e) {
-        do_throw("  Restore should not have failed");
-      }
-    }
-  },
+  }
 
-  {
-    desc:       "HTML restore into folder: empty file should succeed",
-    currTopic:  NSIOBSERVER_TOPIC_BEGIN,
-    finalTopic: NSIOBSERVER_TOPIC_SUCCESS,
-    data:       NSIOBSERVER_DATA_HTML,
-    run:        function () {
-      this.file = createFile("bookmarks-test_restoreNotification.init.html");
-      this.folderId = bmsvc.createFolder(bmsvc.unfiledBookmarksFolder,
-                                         "test folder",
-                                         bmsvc.DEFAULT_INDEX);
-      print("  Sanity check: createFolder() should have succeeded");
-      do_check_true(this.folderId > 0);
-      try {
-        importer.importHTMLFromFileToFolder(this.file, this.folderId, false);
-      }
-      catch (e) {
-        do_throw("  Restore should not have failed");
-      }
-    }
-  },
-
-  {
-    desc:       "HTML restore into folder: nonexistent file should fail",
-    currTopic:  NSIOBSERVER_TOPIC_BEGIN,
-    finalTopic: NSIOBSERVER_TOPIC_FAILED,
-    data:       NSIOBSERVER_DATA_HTML,
-    run:        function () {
-      this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
-      this.file.append("this file doesn't exist because nobody created it");
-      this.folderId = bmsvc.createFolder(bmsvc.unfiledBookmarksFolder,
-                                         "test folder",
-                                         bmsvc.DEFAULT_INDEX);
-      print("  Sanity check: createFolder() should have succeeded");
-      do_check_true(this.folderId > 0);
-      try {
-        importer.importHTMLFromFileToFolder(this.file, this.folderId, false);
-        do_throw("  Restore should have failed");
-      }
-      catch (e) {}
-    }
-  }
 ];
 
 // nsIObserver that observes bookmarks-restore-begin.
 var beginObserver = {
   observe: function _beginObserver(aSubject, aTopic, aData) {
     var test = tests[currTestIndex];
 
     print("  Observed " + aTopic);
--- a/browser/components/places/tests/unit/test_bookmarks_html.js
+++ b/browser/components/places/tests/unit/test_bookmarks_html.js
@@ -213,68 +213,16 @@ add_test(function test_emptytitle_export
 
     waitForAsyncUpdates(function () {
       remove_all_bookmarks();
       run_next_test();
     });
   });
 });
 
-add_test(function test_import_preplaces_to_folder()
-{
-  // Test importing a pre-Places canonical bookmarks file to a specific folder.
-  // 1. create a new folder
-  // 2. import bookmarks.preplaces.html to that folder
-  // 3. run the test-suite
-
-  let testFolder = PlacesUtils.bookmarks.createFolder(
-    PlacesUtils.bookmarksMenuFolderId, "test-import",
-    PlacesUtils.bookmarks.DEFAULT_INDEX
-  );
-  try {
-    importer.importHTMLFromFileToFolder(gBookmarksFileOld, testFolder, false);
-  } catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
-
-  waitForAsyncUpdates(function () {
-    // Import-to-folder creates subfolders for toolbar and unfiled.
-    testImportedBookmarksToFolder(testFolder);
-
-    waitForAsyncUpdates(function () {
-      remove_all_bookmarks();
-      run_next_test();
-    });
-  });
-});
-
-add_test(function test_import_to_folder()
-{
-  // Test importing a Places canonical bookmarks file to a specific folder.
-  // 1. create a new folder
-  // 2. import bookmarks.exported.html to that folder
-  // 3. run the test-suite
-
-  let testFolder = PlacesUtils.bookmarks.createFolder(
-    PlacesUtils.bookmarksMenuFolderId, "test-import",
-    PlacesUtils.bookmarks.DEFAULT_INDEX
-  );
-  try {
-    importer.importHTMLFromFileToFolder(gBookmarksFileNew, testFolder, false);
-  } catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
-
-  waitForAsyncUpdates(function () {
-    // Import-to-folder creates subfolders for toolbar and unfiled.
-    testImportedBookmarksToFolder(testFolder);
-
-    waitForAsyncUpdates(function () {
-      remove_all_bookmarks();
-      run_next_test();
-    });
-  });
-});
-
 add_test(function test_import_ontop()
 {
   // Test importing the exported bookmarks.html file *on top of* the existing
   // bookmarks.
   // 1. empty bookmarks db
   // 2. import the exported bookmarks file
   // 3. export to file
   // 3. import the exported bookmarks file
--- a/browser/components/sessionstore/src/nsSessionStartup.js
+++ b/browser/components/sessionstore/src/nsSessionStartup.js
@@ -67,17 +67,17 @@
 /* :::::::: Constants and Helpers ::::::::::::::: */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource:///modules/TelemetryStopwatch.jsm");
+Cu.import("resource://gre/modules/TelemetryStopwatch.jsm");
 
 const STATE_RUNNING_STR = "running";
 const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 megabytes
 
 function debug(aMsg) {
   aMsg = ("SessionStartup: " + aMsg).replace(/\S{80}/g, "$&\n");
   Services.console.logStringMessage(aMsg);
 }
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -126,17 +126,17 @@ const TAB_EVENTS = ["TabOpen", "TabClose
 #endif
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 // debug.js adds NS_ASSERT. cf. bug 669196
 Cu.import("resource://gre/modules/debug.js");
 
 Cu.import("resource:///modules/TelemetryTimestamps.jsm");
-Cu.import("resource:///modules/TelemetryStopwatch.jsm");
+Cu.import("resource://gre/modules/TelemetryStopwatch.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
   Cu.import("resource://gre/modules/NetUtil.jsm");
   return NetUtil;
 });
 
 XPCOMUtils.defineLazyGetter(this, "ScratchpadManager", function() {
   Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
--- a/browser/components/sessionstore/test/browser_480148.js
+++ b/browser/components/sessionstore/test/browser_480148.js
@@ -31,132 +31,127 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 function test() {
   /** Test for Bug 484108 **/
-  requestLongerTimeout(2);
-
   waitForExplicitFinish();
+  requestLongerTimeout(3);
 
   // builds the tests state based on a few parameters
   function buildTestState(num, selected, hidden) {
     let state = { windows: [ { "tabs": [], "selected": selected } ] };
     while (num--) {
       state.windows[0].tabs.push({entries: [{url: "http://example.com/"}]});
       let i = state.windows[0].tabs.length - 1;
       if (hidden.length > 0 && i == hidden[0]) {
         state.windows[0].tabs[i].hidden = true;
         hidden.splice(0, 1);
       }
     }
     return state;
   }
 
-  // builds an array of the indexs we expect to see in the order they get loaded
-  function buildExpectedOrder(num, selected, shown) {
-    // assume selected is 1-based index
-    selected--;
-    let expected = [selected];
-    // fill left to selected if space
-    for (let i = selected - (shown - expected.length); i >= 0 && i < selected; i++)
-      expected.push(i);
-    // fill from left to right until right length or end
-    for (let i = selected + 1; expected.length < shown && i < num; i++)
-      expected.push(i);
-    // fill in the remaining
-    for (let i = 0; i < num; i++) {
-      if (expected.indexOf(i) == -1) {
-        expected.push(i);
-      }
+  let tests = [
+    { testNum: 1,
+      totalTabs: 13,
+      selectedTab: 1,
+      shownTabs: 6,
+      hiddenTabs: [],
+      order: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+    },
+    { testNum: 2,
+      totalTabs: 13,
+      selectedTab: 13,
+      shownTabs: 6,
+      hiddenTabs: [],
+      order: [12, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6]
+    },
+    { testNum: 3,
+      totalTabs: 13,
+      selectedTab: 4,
+      shownTabs: 6,
+      hiddenTabs: [],
+      order: [3, 4, 5, 6, 7, 8, 0, 1, 2, 9, 10, 11, 12]
+    },
+    { testNum: 4,
+      totalTabs: 13,
+      selectedTab: 11,
+      shownTabs: 6,
+      hiddenTabs: [],
+      order: [10, 7, 8, 9, 11, 12, 0, 1, 2, 3, 4, 5, 6]
+    },
+    { testNum: 5,
+      totalTabs: 13,
+      selectedTab: 13,
+      shownTabs: 6,
+      hiddenTabs: [0, 4, 9],
+      order: [12, 6, 7, 8, 10, 11, 1, 2, 3, 5, 0, 4, 9]
+    },
+    { testNum: 6,
+      totalTabs: 13,
+      selectedTab: 4,
+      shownTabs: 6,
+      hiddenTabs: [1, 7, 12],
+      order: [3, 4, 5, 6, 8, 9, 0, 2, 10, 11, 1, 7, 12]
+    },
+    { testNum: 7,
+      totalTabs: 13,
+      selectedTab: 4,
+      shownTabs: 6,
+      hiddenTabs: [0, 1, 2],
+      order: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2]
     }
-    return expected;
-  }
-
-  // the number of tests we're running
-  let numTests = 7;
-  let completedTests = 0;
+  ];
 
   let tabMinWidth = parseInt(getComputedStyle(gBrowser.selectedTab, null).minWidth);
+  let testIndex = 0;
 
-  function runTest(testNum, totalTabs, selectedTab, shownTabs, hiddenTabs, order) {
-    let test = {
-      state: buildTestState(totalTabs, selectedTab, hiddenTabs),
-      numTabsToShow: shownTabs,
-      expectedOrder: order,
-      actualOrder: [],
-      windowWidth: null,
-      callback: null,
-      window: null,
-
-      handleSSTabRestoring: function (aEvent) {
-        let tab = aEvent.originalTarget;
-        let tabbrowser = this.window.gBrowser;
-        let currentIndex = Array.indexOf(tabbrowser.tabs, tab);
-        this.actualOrder.push(currentIndex);
+  function runNextTest() {
+    if (tests.length == 0) {
+      finish();
+      return;
+    }
 
-        if (this.actualOrder.length < this.state.windows[0].tabs.length)
-          return;
-
-        // all of the tabs should be restoring or restored by now
-        is(this.actualOrder.length, this.state.windows[0].tabs.length,
-           "Test #" + testNum + ": Number of restored tabs is as expected");
-
-        is(this.actualOrder.join(" "), this.expectedOrder.join(" "),
-           "Test #" + testNum + ": 'visible' tabs restored first");
+    info ("Starting test " + (++testIndex));
+    let test = tests.shift();
+    let state = buildTestState(test.totalTabs, test.selectedTab, test.hiddenTabs);
+    let tabbarWidth = Math.floor((test.shownTabs - 0.5) * tabMinWidth);
+    let win = openDialog(location, "_blank", "chrome,all,dialog=no");
+    let actualOrder = [];
 
-        // cleanup
-        this.window.close();
-        // if we're all done, explicitly finish
-        if (++completedTests == numTests) {
-          this.window.removeEventListener("load", this, false);
-          this.window.removeEventListener("SSTabRestoring", this, false);
-          finish();
-        }
-      },
+    win.addEventListener("SSTabRestoring", function onSSTabRestoring(aEvent) {
+      let tab = aEvent.originalTarget;
+      let currentIndex = Array.indexOf(win.gBrowser.tabs, tab);
+      actualOrder.push(currentIndex);
+
+      if (actualOrder.length < state.windows[0].tabs.length)
+        return;
 
-      handleLoad: function (aEvent) {
-        let _this = this;
-        executeSoon(function () {
-          let extent = _this.window.outerWidth - _this.window.gBrowser.tabContainer.mTabstrip.scrollClientSize;
-          let windowWidth = _this.tabbarWidth + extent;
-          _this.window.resizeTo(windowWidth, _this.window.outerHeight);
-          ss.setWindowState(_this.window, JSON.stringify(_this.state), true);
-        });
-      },
+      // all of the tabs should be restoring or restored by now
+      is(actualOrder.length, state.windows[0].tabs.length,
+         "Test #" + testIndex + ": Number of restored tabs is as expected");
 
-      // Implement nsIDOMEventListener for handling various window and tab events
-      handleEvent: function (aEvent) {
-        switch (aEvent.type) {
-          case "load":
-            this.handleLoad(aEvent);
-            break;
-          case "SSTabRestoring":
-            this.handleSSTabRestoring(aEvent);
-            break;
-        }
-      },
+      is(actualOrder.join(" "), test.order.join(" "),
+         "Test #" + testIndex + ": 'visible' tabs restored first");
+
+      // Cleanup.
+      win.removeEventListener("SSTabRestoring", onSSTabRestoring, false);
+      win.close();
+      executeSoon(runNextTest);
+    }, false);
 
-      // setup and actually run the test
-      run: function () {
-        this.tabbarWidth = Math.floor((this.numTabsToShow - 0.5) * tabMinWidth);
-        this.window = openDialog(location, "_blank", "chrome,all,dialog=no");
-        this.window.addEventListener("SSTabRestoring", this, false);
-        this.window.addEventListener("load", this, false);
-      }
-    };
-    test.run();
-  }
+    win.addEventListener("load", function onLoad(aEvent) {
+      win.removeEventListener("load", onLoad, false);
+      executeSoon(function () {
+        let extent = win.outerWidth - win.gBrowser.tabContainer.mTabstrip.scrollClientSize;
+        let windowWidth = tabbarWidth + extent;
+        win.resizeTo(windowWidth, win.outerHeight);
+        ss.setWindowState(win, JSON.stringify(state), true);
+      });
+    }, false);
+  };
 
-  // actually create & run the tests
-  runTest(1, 13, 1,  6, [],         [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
-  runTest(2, 13, 13, 6, [],         [12, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6]);
-  runTest(3, 13, 4,  6, [],         [3, 4, 5, 6, 7, 8, 0, 1, 2, 9, 10, 11, 12]);
-  runTest(4, 13, 11, 6, [],         [10, 7, 8, 9, 11, 12, 0, 1, 2, 3, 4, 5, 6]);
-  runTest(5, 13, 13, 6, [0, 4, 9],  [12, 6, 7, 8, 10, 11, 1, 2, 3, 5, 0, 4, 9]);
-  runTest(6, 13, 4,  6, [1, 7, 12], [3, 4, 5, 6, 8, 9, 0, 2, 10, 11, 1, 7, 12]);
-  runTest(7, 13, 4,  6, [0, 1, 2],  [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2]);
-
-  // finish() is run by the last test to finish, so no cleanup down here
+  runNextTest();
 }
--- a/browser/components/sessionstore/test/browser_624727.js
+++ b/browser/components/sessionstore/test/browser_624727.js
@@ -1,12 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
+  waitForExplicitFinish();
+
   let assertNumberOfTabs = function (num, msg) {
     is(gBrowser.tabs.length, num, msg);
   }
 
   let assertNumberOfPinnedTabs = function (num, msg) {
     is(gBrowser._numPinnedTabs, num, msg);
   }
 
@@ -20,16 +22,18 @@ function test() {
 
   let [tab1, tab2] = gBrowser.tabs;
   let linkedBrowser = tab1.linkedBrowser;
   gBrowser.pinTab(tab1);
   gBrowser.pinTab(tab2);
   assertNumberOfPinnedTabs(2, "both tabs are now pinned");
 
   // run the test
-  ss.setBrowserState(JSON.stringify({ windows: [{ tabs: [{ url: "about:blank" }] }] }));
-  assertNumberOfTabs(1, "one tab left after setBrowserState()");
-  assertNumberOfPinnedTabs(0, "there are no pinned tabs");
-  is(gBrowser.tabs[0].linkedBrowser, linkedBrowser, "first tab's browser got re-used");
-
-  waitForExplicitFinish();
-  waitForSaveState(finish);
+  waitForBrowserState(
+    { windows: [{ tabs: [{ url: "about:blank" }] }] },
+    function () {
+      assertNumberOfTabs(1, "one tab left after setBrowserState()");
+      assertNumberOfPinnedTabs(0, "there are no pinned tabs");
+      is(gBrowser.tabs[0].linkedBrowser, linkedBrowser, "first tab's browser got re-used");
+      finish();
+    }
+  );
 }
--- a/browser/components/sessionstore/test/browser_625016.js
+++ b/browser/components/sessionstore/test/browser_625016.js
@@ -9,20 +9,24 @@ function test() {
 
   // We'll test this by opening a new window, waiting for the save event, then
   // closing that window. We'll observe the "sessionstore-state-write" notification
   // and check that the state contains no _closedWindows. We'll then add a new
   // tab and make sure that the state following that was reset and the closed
   // window is now in _closedWindows.
 
   waitForExplicitFinish();
+  requestLongerTimeout(2);
 
   // We speed up the interval between session saves to ensure that the test
   // runs quickly.
-  Services.prefs.setIntPref("browser.sessionstore.interval", 2000);
+  Services.prefs.setIntPref("browser.sessionstore.interval", 4000);
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("browser.sessionstore.interval");
+  });
 
   // We'll clear all closed windows to make sure our state is clean
   // forgetClosedWindow doesn't trigger a delayed save
   while (ss.getClosedWindowCount()) {
     ss.forgetClosedWindow(0);
   }
   is(ss.getClosedWindowCount(), 0, "starting with no closed windows");
 
@@ -92,17 +96,16 @@ function observe2(aSubject, aTopic, aDat
 // We'll open a tab, which should trigger another state save which would wipe
 // the _shouldRestore attribute from the closed window
 function openTab() {
   Services.obs.addObserver(observe2, "sessionstore-state-write", false);
   newTab = gBrowser.addTab("about:mozilla");
 }
 
 function done() {
-  Services.prefs.clearUserPref("browser.sessionstore.interval");
   gBrowser.removeTab(newTab);
   // The API still represents the closed window as closed, so we can clear it
   // with the API, but just to make sure...
   is(ss.getClosedWindowCount(), 1, "1 closed window according to API");
   ss.forgetClosedWindow(0);
   executeSoon(finish);
 }
 
--- a/browser/components/sessionstore/test/browser_705597.js
+++ b/browser/components/sessionstore/test/browser_705597.js
@@ -2,56 +2,63 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let tabState = {
   entries: [{url: "about:home", children: [{url: "about:mozilla"}]}]
 };
 
 function test() {
   waitForExplicitFinish();
+  requestLongerTimeout(2);
+
+  Services.prefs.setIntPref("browser.sessionstore.interval", 4000);
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("browser.sessionstore.interval");
+  });
 
   let tab = gBrowser.addTab("about:blank");
-  registerCleanupFunction(function () gBrowser.removeTab(tab));
 
   let browser = tab.linkedBrowser;
 
   whenBrowserLoaded(browser, function () {
     ss.setTabState(tab, JSON.stringify(tabState));
 
     let sessionHistory = browser.sessionHistory;
     let entry = sessionHistory.getEntryAtIndex(0, false);
 
     whenChildCount(entry, 1, function () {
       whenChildCount(entry, 2, function () {
         whenBrowserLoaded(browser, function () {
           let {entries} = JSON.parse(ss.getTabState(tab));
           is(entries.length, 1, "tab has one history entry");
           ok(!entries[0].children, "history entry has no subframes");
 
-          finish();
+          // Make sure that we reset the state.
+          let blankState = { windows: [{ tabs: [{ entries: [{ url: "about:blank" }] }]}]};
+          waitForBrowserState(blankState, finish);
         });
 
         // reload the browser to deprecate the subframes
         browser.reload();
       });
 
       // create a dynamic subframe
       let doc = browser.contentDocument;
       let iframe = doc.createElement("iframe");
+      doc.body.appendChild(iframe);
       iframe.setAttribute("src", "about:mozilla");
-      doc.body.appendChild(iframe);
     });
   });
 }
 
 function whenBrowserLoaded(aBrowser, aCallback) {
   aBrowser.addEventListener("load", function onLoad() {
     aBrowser.removeEventListener("load", onLoad, true);
     executeSoon(aCallback);
   }, true);
 }
 
 function whenChildCount(aEntry, aChildCount, aCallback) {
   if (aEntry.childCount == aChildCount)
     aCallback();
   else
-    executeSoon(function () whenChildCount(aEntry, aChildCount, aCallback));
+    setTimeout(function () whenChildCount(aEntry, aChildCount, aCallback), 100);
 }
--- a/browser/components/sessionstore/test/browser_707862.js
+++ b/browser/components/sessionstore/test/browser_707862.js
@@ -2,55 +2,64 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let tabState = {
   entries: [{url: "about:home", children: [{url: "about:mozilla"}]}]
 };
 
 function test() {
   waitForExplicitFinish();
+  requestLongerTimeout(2);
+
+  Services.prefs.setIntPref("browser.sessionstore.interval", 4000);
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("browser.sessionstore.interval");
+  });
 
   let tab = gBrowser.addTab("about:blank");
-  registerCleanupFunction(function () gBrowser.removeTab(tab));
 
   let browser = tab.linkedBrowser;
 
   whenBrowserLoaded(browser, function () {
     ss.setTabState(tab, JSON.stringify(tabState));
 
     let sessionHistory = browser.sessionHistory;
     let entry = sessionHistory.getEntryAtIndex(0, false);
 
     whenChildCount(entry, 1, function () {
       whenChildCount(entry, 2, function () {
         whenBrowserLoaded(browser, function () {
           let sessionHistory = browser.sessionHistory;
           let entry = sessionHistory.getEntryAtIndex(0, false);
 
-          whenChildCount(entry, 0, finish);
+          whenChildCount(entry, 0, function () {
+            // Make sure that we reset the state.
+            let blankState = { windows: [{ tabs: [{ entries: [{ url: "about:blank" }] }]}]};
+            waitForBrowserState(blankState, finish);
+          });
         });
 
         // reload the browser to deprecate the subframes
         browser.reload();
       });
 
       // create a dynamic subframe
       let doc = browser.contentDocument;
       let iframe = doc.createElement("iframe");
+      doc.body.appendChild(iframe);
       iframe.setAttribute("src", "about:mozilla");
-      doc.body.appendChild(iframe);
     });
   });
 }
 
 function whenBrowserLoaded(aBrowser, aCallback) {
   aBrowser.addEventListener("load", function onLoad() {
     aBrowser.removeEventListener("load", onLoad, true);
     executeSoon(aCallback);
   }, true);
 }
 
 function whenChildCount(aEntry, aChildCount, aCallback) {
   if (aEntry.childCount == aChildCount)
     aCallback();
   else
-    executeSoon(function () whenChildCount(aEntry, aChildCount, aCallback));
+    setTimeout(function () whenChildCount(aEntry, aChildCount, aCallback), 100);
 }
--- a/browser/components/tabview/content.js
+++ b/browser/components/tabview/content.js
@@ -89,21 +89,31 @@ let WindowMessageHandler = {
   // ----------
   // Function: isDocumentLoaded
   // Checks if the currently active document is loaded.
   isDocumentLoaded: function WMH_isDocumentLoaded(cx) {
     let isLoaded = (content.document.readyState == "complete" &&
                     !webProgress.isLoadingDocument);
 
     sendAsyncMessage(cx.name, {isLoaded: isLoaded});
+  },
+
+  // ----------
+  // Function: isImageDocument
+  // Checks if the currently active document is an image document or not.
+  isImageDocument: function WMH_isImageDocument(cx) {
+    let isImageDocument = (content.document instanceof Ci.nsIImageDocument);
+
+    sendAsyncMessage(cx.name, {isImageDocument: isImageDocument});
   }
 };
 
 // add message listeners
 addMessageListener("Panorama:isDocumentLoaded", WindowMessageHandler.isDocumentLoaded);
+addMessageListener("Panorama:isImageDocument", WindowMessageHandler.isImageDocument);
 
 // ----------
 // WebProgressListener
 //
 // Observe the web progress of content pages loaded into this browser. When the
 // state of a page changes we check if we're still allowed to store page
 // information permanently.
 let WebProgressListener = {
--- a/browser/components/tabview/groupitems.js
+++ b/browser/components/tabview/groupitems.js
@@ -229,20 +229,22 @@ function GroupItem(listOfEls, options) {
   // ___ app tabs: create app tab tray and populate it
   let appTabTrayContainer = iQ("<div/>")
     .addClass("appTabTrayContainer")
     .appendTo($container);
   this.$appTabTray = iQ("<div/>")
     .addClass("appTabTray")
     .appendTo(appTabTrayContainer);
 
-  AllTabs.tabs.forEach(function(xulTab) {
+  let pinnedTabCount = gBrowser._numPinnedTabs;
+  AllTabs.tabs.forEach(function (xulTab, index) {
+    // only adjust tray when it's the last app tab.
     if (xulTab.pinned)
-      self.addAppTab(xulTab, {dontAdjustTray: true});
-  });
+      this.addAppTab(xulTab, {dontAdjustTray: index + 1 < pinnedTabCount});
+  }, this);
 
   // ___ Undo Close
   this.$undoContainer = null;
   this._undoButtonTimeoutId = null;
 
   // ___ Superclass initialization
   this._init($container[0]);
 
@@ -753,17 +755,17 @@ GroupItem.prototype = Utils.extend(new I
     let self = this;
 
     let finalize = function () {
       self._children.forEach(function(child) {
         iQ(child.container).show();
       });
 
       UI.setActive(self);
-      self._sendToSubscribers("groupShown", { groupItemId: self.id });
+      self._sendToSubscribers("groupShown");
     };
 
     let $container = iQ(this.container).show();
 
     if (!options || !options.immediately) {
       $container.animate({
         "-moz-transform": "scale(1)",
         "opacity": 1
@@ -922,17 +924,17 @@ GroupItem.prototype = Utils.extend(new I
     setTimeout(function() {
       self.$undoContainer.animate({
         "-moz-transform": "scale(1)",
         "opacity": 1
       }, {
         easing: "tabviewBounce",
         duration: 170,
         complete: function() {
-          self._sendToSubscribers("groupHidden", { groupItemId: self.id });
+          self._sendToSubscribers("groupHidden");
         }
       });
     }, 50);
 
     // add click handlers
     this.$undoContainer.click(function(e) {
       // don't do anything if the close button is clicked.
       if (e.target == undoClose[0])
@@ -1047,17 +1049,17 @@ GroupItem.prototype = Utils.extend(new I
             (!GroupItems.getActiveGroupItem() && !item.tab.hidden))
           UI.setActive(this);
       }
 
       if (!options.dontArrange)
         this.arrange({animate: !options.immediately});
 
       this._unfreezeItemSize({dontArrange: true});
-      this._sendToSubscribers("childAdded",{ groupItemId: this.id, item: item });
+      this._sendToSubscribers("childAdded", { item: item });
 
       UI.setReorderTabsOnHide(this);
     } catch(e) {
       Utils.log('GroupItem.add error', e);
     }
   },
 
   // ----------
@@ -1150,17 +1152,17 @@ GroupItem.prototype = Utils.extend(new I
           (this._children.length == 0 && !gBrowser._numPinnedTabs &&
            !item.isDragging)) {
         this._makeLastActiveGroupItemActive();
       } else if (!options.dontArrange) {
         this.arrange({animate: !options.immediately});
         this._unfreezeItemSize({dontArrange: true});
       }
 
-      this._sendToSubscribers("childRemoved",{ groupItemId: this.id, item: item });
+      this._sendToSubscribers("childRemoved", { item: item });
     } catch(e) {
       Utils.log(e);
     }
   },
 
   // ----------
   // Function: removeAll
   // Removes all of the groupItem's children.
@@ -1176,46 +1178,56 @@ GroupItem.prototype = Utils.extend(new I
       self.remove(child, newOptions);
     });
   },
 
   // ----------
   // Adds the given xul:tab as an app tab in this group's apptab tray
   //
   // Parameters:
+  //   xulTab - the xul:tab.
   //   options - change how the app tab is added.
   //
   // Options:
-  //   dontAdjustTray - (boolean) if true, the $appTabTray size is not adjusted,
-  //                    which means that the adjustAppTabTray() method is not
-  //                    called.
+  //   position - the position of the app tab should be added to.
+  //   dontAdjustTray - (boolean) if true, do not adjust the tray.
   addAppTab: function GroupItem_addAppTab(xulTab, options) {
-    let self = this;
+    GroupItems.getAppTabFavIconUrl(xulTab, function(iconUrl) {
+      let self = this;
+      let $appTab = iQ("<img>")
+        .addClass("appTabIcon")
+        .attr("src", iconUrl)
+        .data("xulTab", xulTab)
+        .mousedown(function GroupItem_addAppTab_onAppTabMousedown(event) {
+          // stop mousedown propagation to disable group dragging on app tabs
+          event.stopPropagation();
+        })
+        .click(function GroupItem_addAppTab_onAppTabClick(event) {
+          if (!Utils.isLeftClick(event))
+            return;
 
-    let iconUrl = GroupItems.getAppTabFavIconUrl(xulTab);
-    let $appTab = iQ("<img>")
-      .addClass("appTabIcon")
-      .attr("src", iconUrl)
-      .data("xulTab", xulTab)
-      .appendTo(this.$appTabTray)
-      .mousedown(function onAppTabMousedown(event) {
-        // stop mousedown propagation to disable group dragging on app tabs
-        event.stopPropagation();
-      })
-      .click(function(event) {
-        if (!Utils.isLeftClick(event))
-          return;
+          UI.setActive(self, { dontSetActiveTabInGroup: true });
+          UI.goToTab(iQ(this).data("xulTab"));
+        });
+
+      if (options && "position" in options) {
+        let children = this.$appTabTray[0].childNodes;
 
-        UI.setActive(self, { dontSetActiveTabInGroup: true });
-        UI.goToTab(iQ(this).data("xulTab"));
-      });
+        if (options.position >= children.length)
+          $appTab.appendTo(this.$appTabTray);
+        else
+          this.$appTabTray[0].insertBefore($appTab[0], children[options.position]);
+      } else {
+        $appTab.appendTo(this.$appTabTray);
+      }
+      if (!options || !options.dontAdjustTray)
+        this.adjustAppTabTray(true);
 
-    // adjust the tray, if needed.
-    if (!options || !options.dontAdjustTray)
-      this.adjustAppTabTray(true);
+      this._sendToSubscribers("appTabIconAdded", { item: $appTab });
+    }.bind(this));
   },
 
   // ----------
   // Removes the given xul:tab as an app tab in this group's apptab tray
   removeAppTab: function GroupItem_removeAppTab(xulTab) {
     // remove the icon
     iQ(".appTabIcon", this.$appTabTray).each(function(icon) {
       let $icon = iQ(icon);
@@ -2073,42 +2085,32 @@ let GroupItems = {
 
   // ----------
   // Function: _updateAppTabIcons
   // Update images of any apptab icons that point to passed in xultab 
   _updateAppTabIcons: function GroupItems__updateAppTabIcons(xulTab) {
     if (!xulTab.pinned)
       return;
 
-    let iconUrl = this.getAppTabFavIconUrl(xulTab);
-    this.groupItems.forEach(function(groupItem) {
-      iQ(".appTabIcon", groupItem.$appTabTray).each(function(icon) {
-        let $icon = iQ(icon);
-        if ($icon.data("xulTab") != xulTab)
-          return true;
-
-        if (iconUrl != $icon.attr("src"))
-          $icon.attr("src", iconUrl);
-        return false;
+    this.getAppTabFavIconUrl(xulTab, function(iconUrl) {
+      iQ(".appTabIcon").each(function GroupItems__updateAppTabIcons_forEach(icon) {
+         let $icon = iQ(icon);
+         if ($icon.data("xulTab") == xulTab && iconUrl != $icon.attr("src"))
+           $icon.attr("src", iconUrl);
       });
     });
   },
 
   // ----------
   // 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 = gFavIconService.defaultFavicon.spec;
-
-    return iconUrl;
+  getAppTabFavIconUrl: function GroupItems_getAppTabFavIconUrl(xulTab, callback) {
+    UI.getFavIconUrlForTab(xulTab, function GroupItems_getAppTabFavIconUrl_getFavIconUrlForTab(iconUrl) {
+      callback(iconUrl || gFavIconService.defaultFavicon.spec);
+    });
   },
 
   // ----------
   // Function: addAppTab
   // Adds the given xul:tab to the app tab tray in all groups
   addAppTab: function GroupItems_addAppTab(xulTab) {
     this.groupItems.forEach(function(groupItem) {
       groupItem.addAppTab(xulTab);
--- a/browser/components/tabview/tabitems.js
+++ b/browser/components/tabview/tabitems.js
@@ -980,30 +980,31 @@ let TabItems = {
 
       Utils.assertThrow(tab, "tab");
 
       // ___ get the TabItem
       Utils.assertThrow(tab._tabViewTabItem, "must already be linked");
       let tabItem = tab._tabViewTabItem;
 
       // Even if the page hasn't loaded, display the favicon and title
-
       // ___ icon
-      if (UI.shouldLoadFavIcon(tab.linkedBrowser)) {
-        let iconUrl = UI.getFavIconUrlForTab(tab);
-
-        if (tabItem.$favImage[0].src != iconUrl)
-          tabItem.$favImage[0].src = iconUrl;
-
-        iQ(tabItem.$fav[0]).show();
-      } else {
-        if (tabItem.$favImage[0].hasAttribute("src"))
-          tabItem.$favImage[0].removeAttribute("src");
-        iQ(tabItem.$fav[0]).hide();
-      }
+      UI.getFavIconUrlForTab(tab, function TabItems__update_getFavIconUrlCallback(iconUrl) {
+        let favImage = tabItem.$favImage[0];
+        let fav = tabItem.$fav;
+        if (iconUrl) {
+          if (favImage.src != iconUrl)
+            favImage.src = iconUrl;
+          fav.show();
+        } else {
+          if (favImage.hasAttribute("src"))
+            favImage.removeAttribute("src");
+          fav.hide();
+        }
+        tabItem._sendToSubscribers("iconUpdated");
+      });
 
       // ___ label
       let label = tab.label;
       let $name = tabItem.$tabTitle;
       if ($name.text() != label)
         $name.text(label);
 
       // ___ remove from waiting list now that we have no other
--- a/browser/components/tabview/test/Makefile.in
+++ b/browser/components/tabview/test/Makefile.in
@@ -153,16 +153,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug656913.js \
                  browser_tabview_bug662266.js \
                  browser_tabview_bug663421.js \
                  browser_tabview_bug665502.js \
                  browser_tabview_bug669694.js \
                  browser_tabview_bug673196.js \
                  browser_tabview_bug673729.js \
                  browser_tabview_bug677310.js \
+                 browser_tabview_bug678374.js \
                  browser_tabview_bug679853.js \
                  browser_tabview_bug681599.js \
                  browser_tabview_bug685476.js \
                  browser_tabview_bug685692.js \
                  browser_tabview_bug686654.js \
                  browser_tabview_bug696602.js \
                  browser_tabview_bug697390.js \
                  browser_tabview_bug705621.js \
@@ -187,14 +188,16 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_thumbnail_storage.js \
                  browser_tabview_undo_group.js \
                  dummy_page.html \
                  head.js \
                  search1.html \
                  search2.html \
                  test_bug600645.html \
                  test_bug644097.html \
+                 test_bug678374.html \
+                 test_bug678374_icon16.png \
                  $(NULL)
 
 # browser_tabview_bug597980.js is disabled for leaking, see bug 711907
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
--- a/browser/components/tabview/test/browser_tabview_apptabs.js
+++ b/browser/components/tabview/test/browser_tabview_apptabs.js
@@ -1,23 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   waitForExplicitFinish();
 
-  window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
-  TabView.toggle();
+  showTabView(onTabViewWindowLoaded);
 }
 
 function onTabViewWindowLoaded() {
-  window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
   ok(TabView.isVisible(), "Tab View is visible");
 
-  let contentWindow = document.getElementById("tab-view").contentWindow;
+  let contentWindow = TabView.getContentWindow();
 
   // establish initial state
   is(contentWindow.GroupItems.groupItems.length, 1,
       "we start with one group (the default)");
   is(gBrowser.tabs.length, 1, "we start with one tab");
   let originalTab = gBrowser.tabs[0];
 
   // create a group
@@ -31,67 +29,68 @@ function onTabViewWindowLoaded() {
   let xulTab = gBrowser.loadOneTab("about:blank");
   is(gBrowser.tabs.length, 2, "we now have two tabs");
   is(groupItemOne._children.length, 1, "the new tab was added to the group");
 
   // make sure the group has no app tabs
   is(appTabCount(groupItemOne), 0, "there are no app tab icons");
 
   // pin the tab, make sure the TabItem goes away and the icon comes on
-  gBrowser.pinTab(xulTab);
-  is(groupItemOne._children.length, 0,
-      "the app tab's TabItem was removed from the group");
-  is(appTabCount(groupItemOne), 1, "there's now one app tab icon");
+  whenAppTabIconAdded(function() {
+    is(groupItemOne._children.length, 0,
+       "the app tab's TabItem was removed from the group");
+    is(appTabCount(groupItemOne), 1, "there's now one app tab icon");
 
-  // create a second group and make sure it gets the icon too
-  box.offset(box.width + 20, 0);
-  let groupItemTwo = new contentWindow.GroupItem([],
-      { bounds: box, title: "test2" });
-  is(contentWindow.GroupItems.groupItems.length, 3, "we now have three groups");
-  is(appTabCount(groupItemTwo), 1,
-      "there's an app tab icon in the second group");
+    // create a second group and make sure it gets the icon too
+    box.offset(box.width + 20, 0);
+    let groupItemTwo = new contentWindow.GroupItem([],
+        { bounds: box, title: "test2" });
+    whenAppTabIconAdded(function() {
+      is(contentWindow.GroupItems.groupItems.length, 3, "we now have three groups");
+      is(appTabCount(groupItemTwo), 1,
+         "there's an app tab icon in the second group");
 
-  // When the tab was pinned, the last active group with an item got the focus.
-  // Therefore, switching the focus back to group item one.
-  contentWindow.UI.setActive(groupItemOne);
+      // When the tab was pinned, the last active group with an item got the focus.
+      // Therefore, switching the focus back to group item one.
+      contentWindow.UI.setActive(groupItemOne);
 
-  // unpin the tab, make sure the icon goes away and the TabItem comes on
-  gBrowser.unpinTab(xulTab);
-  is(groupItemOne._children.length, 1, "the app tab's TabItem is back");
-  is(appTabCount(groupItemOne), 0, "the icon is gone from group one");
-  is(appTabCount(groupItemTwo), 0, "the icon is gone from group 2");
+      // unpin the tab, make sure the icon goes away and the TabItem comes on
+      gBrowser.unpinTab(xulTab);
+      is(groupItemOne._children.length, 1, "the app tab's TabItem is back");
+      is(appTabCount(groupItemOne), 0, "the icon is gone from group one");
+      is(appTabCount(groupItemTwo), 0, "the icon is gone from group two");
 
-  // pin the tab again
-  gBrowser.pinTab(xulTab);
+      whenAppTabIconAdded(function() {
+        // close the second group
+        groupItemTwo.close();
 
-  // close the second group
-  groupItemTwo.close();
+        // find app tab in group and hit it
+        whenTabViewIsHidden(function() {
+          ok(!TabView.isVisible(),
+             "Tab View is hidden because we clicked on the app tab");
 
-  // find app tab in group and hit it
-  let onTabViewHidden = function() {
-    window.removeEventListener("tabviewhidden", onTabViewHidden, false);
-    ok(!TabView.isVisible(),
-        "Tab View is hidden because we clicked on the app tab");
+          // delete the app tab and make sure its icon goes away
+          gBrowser.removeTab(xulTab);
+          is(appTabCount(groupItemOne), 0, "closing app tab removes its icon");
 
-    // delete the app tab and make sure its icon goes away
-    gBrowser.removeTab(xulTab);
-    is(appTabCount(groupItemOne), 0, "closing app tab removes its icon");
+          // clean up
+          groupItemOne.close();
 
-    // clean up
-    groupItemOne.close();
+          is(contentWindow.GroupItems.groupItems.length, 1,
+             "we finish with one group");
+          is(gBrowser.tabs.length, 1, "we finish with one tab");
+          ok(!TabView.isVisible(), "we finish with Tab View not visible");
 
-    is(contentWindow.GroupItems.groupItems.length, 1,
-        "we finish with one group");
-    is(gBrowser.tabs.length, 1, "we finish with one tab");
-    ok(!TabView.isVisible(), "we finish with Tab View not visible");
+          finish();
+        });
 
-    finish();
-  };
-
-  window.addEventListener("tabviewhidden", onTabViewHidden, false);
-
-  let appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
-  EventUtils.sendMouseEvent({ type: "click" }, appTabIcons[0], contentWindow);
+        let appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
+        EventUtils.sendMouseEvent({ type: "click" }, appTabIcons[0], contentWindow);
+      });
+      gBrowser.pinTab(xulTab);
+    });
+  });
+  gBrowser.pinTab(xulTab);
 }
 
 function appTabCount(groupItem) {
   return groupItem.container.getElementsByClassName("appTabIcon").length;
 }
--- a/browser/components/tabview/test/browser_tabview_bug587503.js
+++ b/browser/components/tabview/test/browser_tabview_bug587503.js
@@ -1,13 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   waitForExplicitFinish();
+  requestLongerTimeout(2);
 
   newWindowWithTabView(onTabViewWindowLoaded);
 }
 
 function onTabViewWindowLoaded(win) {
   ok(win.TabView.isVisible(), "Tab View is visible");
 
   let contentWindow = win.document.getElementById("tab-view").contentWindow;
@@ -100,18 +101,18 @@ function onTabViewWindowLoaded(win) {
             is(index, 4, "Tab 5 is back and again the fifth tab.");
             contentWindow.Utils.log('dropSpaceActiveValues',dropSpaceActiveValues);
             is(dropSpaceActiveValues[0], false, "The group began by not showing a dropSpace");
             is(dropSpaceActiveValues[dropSpaceActiveValues.length - 1], true, "In the end, the group was showing a dropSpace");
             
             // Close the window and we're done!
             win.close();
             finish();
-          }, 6000, false);
-        },1000);
+          }, 10000, false);
+        }, 2000);
         
       });
     
     });
 
   });
 }
 
--- a/browser/components/tabview/test/browser_tabview_bug595965.js
+++ b/browser/components/tabview/test/browser_tabview_bug595965.js
@@ -48,95 +48,106 @@ function onTabViewShown(win) {
 
   let tray = groupItem.$appTabTray;
   let trayContainer = iQ(tray[0].parentNode);
 
   is(parseInt(trayContainer.css("width")), 0,
      "$appTabTray container is not visible");
 
   // pin the tab, make sure the TabItem goes away and the icon comes on
-  gBrowser.pinTab(xulTabs[0]);
-  is(groupItem._children.length, 0,
-     "the app tab's TabItem was removed from the group");
-  is(appTabCount(groupItem), 1, "there's now one app tab icon");
+  whenAppTabIconAdded(function() {
+    is(groupItem._children.length, 0,
+       "the app tab's TabItem was removed from the group");
+    is(appTabCount(groupItem), 1, "there's now one app tab icon");
+
+    is(tray.css("-moz-column-count"), 1,
+       "$appTabTray column count is 1");
+    isnot(parseInt(trayContainer.css("width")), 0,
+       "$appTabTray container is visible");
+
 
-  is(tray.css("-moz-column-count"), 1,
-     "$appTabTray column count is 1");
-  isnot(parseInt(trayContainer.css("width")), 0,
-     "$appTabTray container is visible");
+    let iconHeight = iQ(iQ(".appTabIcon", tray)[0]).height();
+    let trayHeight = parseInt(trayContainer.css("height"));
+    let rows = Math.floor(trayHeight / iconHeight);
+    let icons = rows * 2;
 
-  let iconHeight = iQ(iQ(".appTabIcon", tray)[0]).height();
-  let trayHeight = parseInt(trayContainer.css("height"));
-  let rows = Math.floor(trayHeight / iconHeight);
-  let icons = rows * 2;
+    function pinnedSomeTabs() {
+      is(appTabCount(groupItem), icons, "number of app tab icons is correct");
+
+      is(tray.css("-moz-column-count"), 2,
+         "$appTabTray column count is 2");
 
-  // add enough tabs to have two columns
-  for (let i = 1; i < icons; i++) {
-    xulTabs.push(gBrowser.loadOneTab("about:blank"));
-    gBrowser.pinTab(xulTabs[i]);
-  }
+      ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
+         "$appTabTray container does not have .appTabTrayContainerTruncated");
 
-  is(appTabCount(groupItem), icons, "number of app tab icons is correct");
+      // add one more tab
+      xulTabs.push(gBrowser.loadOneTab("about:blank"));
+      whenAppTabIconAdded(function() {
+        is(tray.css("-moz-column-count"), 3,
+           "$appTabTray column count is 3");
 
-  is(tray.css("-moz-column-count"), 2,
-     "$appTabTray column count is 2");
+        ok(trayContainer.hasClass("appTabTrayContainerTruncated"),
+           "$appTabTray container hasClass .appTabTrayContainerTruncated");
 
-  ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
-     "$appTabTray container does not have .appTabTrayContainerTruncated");
+        // remove all but one app tabs
+        for (let i = 1; i < xulTabs.length; i++)
+          gBrowser.removeTab(xulTabs[i]);
 
-  // add one more tab
-  xulTabs.push(gBrowser.loadOneTab("about:blank"));
-  gBrowser.pinTab(xulTabs[xulTabs.length-1]);
+        is(tray.css("-moz-column-count"), 1,
+           "$appTabTray column count is 1");
 
-  is(tray.css("-moz-column-count"), 3,
-     "$appTabTray column count is 3");
+        is(appTabCount(groupItem), 1, "there's now one app tab icon");
 
-  ok(trayContainer.hasClass("appTabTrayContainerTruncated"),
-     "$appTabTray container hasClass .appTabTrayContainerTruncated");
+        ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
+           "$appTabTray container does not have .appTabTrayContainerTruncated");
 
-  // remove all but one app tabs
-  for (let i = 1; i < xulTabs.length; i++)
-    gBrowser.removeTab(xulTabs[i]);
+        // unpin the last remaining tab
+        gBrowser.unpinTab(xulTabs[0]);
 
-  is(tray.css("-moz-column-count"), 1,
-     "$appTabTray column count is 1");
+        is(parseInt(trayContainer.css("width")), 0,
+           "$appTabTray container is not visible");
 
-  is(appTabCount(groupItem), 1, "there's now one app tab icon");
+        // When the tab was pinned, the last active group with an item got the focus.
+        // Therefore, switching the focus back to group item one.
+        contentWindow.UI.setActive(groupItem);
 
-  ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
-     "$appTabTray container does not have .appTabTrayContainerTruncated");
+        is(appTabCount(groupItem), 0, "there are no app tab icons");
+
+        is(groupItem._children.length, 1, "the normal tab shows in the group");
+
+        gBrowser.removeTab(xulTabs[0]);
 
-  // When the tab was pinned, the last active group with an item got the focus.
-  // Therefore, switching the focus back to group item one.
-  contentWindow.UI.setActive(groupItem);
+        // close the group
+        groupItem.close();
 
-  // unpin the last remaining tab
-  gBrowser.unpinTab(xulTabs[0]);
+        hideTabView(function() {
+          ok(!TabView.isVisible(), "Tab View is hidden");
 
-  is(parseInt(trayContainer.css("width")), 0,
-     "$appTabTray container is not visible");
+          is(contentWindow.GroupItems.groupItems.length, 1,
+             "we finish with one group");
+          is(gBrowser.tabs.length, 1, "we finish with one tab");
 
-  is(appTabCount(groupItem), 0, "there are no app tab icons");
+          win.close();
 
-  is(groupItem._children.length, 1, "the normal tab shows in the group");
-
-  gBrowser.removeTab(xulTabs[0]);
-
-  // close the group
-  groupItem.close();
+          executeSoon(finish);
+        }, win);
+      }, win);
+      win.gBrowser.pinTab(xulTabs[xulTabs.length-1]);
+    };
 
-  hideTabView(function() {
-    ok(!TabView.isVisible(), "Tab View is hidden");
-
-    is(contentWindow.GroupItems.groupItems.length, 1,
-       "we finish with one group");
-    is(gBrowser.tabs.length, 1, "we finish with one tab");
-
-    win.close();
-
-    executeSoon(finish);
+    // add enough tabs to have two columns
+    let returnCount = 0;
+    for (let i = 1; i < icons; i++) {
+      xulTabs.push(gBrowser.loadOneTab("about:blank"));
+      whenAppTabIconAdded(function() {
+        if (++returnCount == (icons - 1))
+          executeSoon(pinnedSomeTabs);
+      }, win);
+      win.gBrowser.pinTab(xulTabs[i]);
+    }
   }, win);
+  win.gBrowser.pinTab(xulTabs[0]);
 }
 
 function appTabCount(groupItem) {
   return groupItem.container.getElementsByClassName("appTabIcon").length;
 }
 
--- a/browser/components/tabview/test/browser_tabview_bug600645.js
+++ b/browser/components/tabview/test/browser_tabview_bug600645.js
@@ -5,25 +5,24 @@ const fi = Cc["@mozilla.org/browser/favi
            getService(Ci.nsIFaviconService);
 
 let newTab;
 
 function test() {
   waitForExplicitFinish();
 
   newTab = gBrowser.addTab();
-  gBrowser.pinTab(newTab);
 
-  window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
-  TabView.toggle();
+  showTabView(function() {
+    whenAppTabIconAdded(onTabPinned);
+    gBrowser.pinTab(newTab);
+  })
 }
 
-function onTabViewWindowLoaded() {
-  window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
-
+function onTabPinned() {
   let contentWindow = document.getElementById("tab-view").contentWindow;
   is(contentWindow.GroupItems.groupItems.length, 1, 
      "There is one group item on startup");
 
   let groupItem = contentWindow.GroupItems.groupItems[0];
   let icon = contentWindow.iQ(".appTabIcon", groupItem.$appTabTray)[0];
   let $icon = contentWindow.iQ(icon);
 
--- a/browser/components/tabview/test/browser_tabview_bug610242.js
+++ b/browser/components/tabview/test/browser_tabview_bug610242.js
@@ -24,16 +24,17 @@ function onTabViewWindowLoaded(win) {
   contentWindow.UI.setActive(group);
   is(contentWindow.GroupItems.getActiveGroupItem(), group, "new group is active");
   
   // Create a bunch of tabs in the group
   let bg = {inBackground: true};
   let datatext = win.gBrowser.loadOneTab("data:text/plain,bug610242", bg);
   let datahtml = win.gBrowser.loadOneTab("data:text/html,<blink>don't blink!</blink>", bg);
   let mozilla  = win.gBrowser.loadOneTab("about:mozilla", bg);
+  let robots   = win.gBrowser.loadOneTab("about:robots", bg);
   let html     = win.gBrowser.loadOneTab("http://example.com", bg);
   let png      = win.gBrowser.loadOneTab("http://mochi.test:8888/browser/browser/base/content/test/moz.png", bg);
   let svg      = win.gBrowser.loadOneTab("http://mochi.test:8888/browser/browser/base/content/test/title_test.svg", bg);
   
   ok(!group.shouldStack(group._children.length), "Group should not stack.");
   
   // PREPARE FINISH:
   group.addSubscriber("close", function onClose() {
@@ -41,44 +42,59 @@ function onTabViewWindowLoaded(win) {
 
     ok(group.isEmpty(), "The group is empty again");
 
     contentWindow.UI.setActive(currentGroup);
     isnot(contentWindow.GroupItems.getActiveGroupItem(), null, "There is an active group");
     is(win.gBrowser.tabs.length, 1, "There is only one tab left");
     is(win.gBrowser.visibleTabs.length, 1, "There is also only one visible tab");
 
-    let onTabViewHidden = function() {
-      win.removeEventListener("tabviewhidden", onTabViewHidden, false);
+    whenTabViewIsHidden(function() {
       win.close();
       ok(win.closed, "new window is closed");
       finish();
-    };
-    win.addEventListener("tabviewhidden", onTabViewHidden, false);
+    }, win);
     win.gBrowser.selectedTab = originalTab;
 
     win.TabView.hide();
   });
 
   function check(tab, label, visible) {
     let display = contentWindow.getComputedStyle(tab._tabViewTabItem.$fav[0], null).getPropertyValue("display");
     if (visible) {
       is(display, "block", label + " has favicon");
     } else {
       is(display, "none", label + " has no favicon");
     }
   }
 
   afterAllTabsLoaded(function() {
     afterAllTabItemsUpdated(function() {
-      check(datatext, "datatext", false);
-      check(datahtml, "datahtml", false);
-      check(mozilla, "about:mozilla", true);
-      check(html, "html", true);
-      check(png, "png", false);
-      check(svg, "svg", true);
-  
-      // Get rid of the group and its children
-      // The group close will trigger a finish().
-      closeGroupItem(group);
-    }, win);  
+      let children = group.getChildren();
+      let len = children.length;
+      let iconUpdateCounter = 0;
+
+      children.forEach(function(tabItem) {
+        tabItem.addSubscriber("iconUpdated", function onIconUpdated() {
+          // the tab is not loaded completely so ignore it.
+          if (tabItem.tab.linkedBrowser.currentURI.spec == "about:blank")
+            return;
+
+          tabItem.removeSubscriber("iconUpdated", onIconUpdated);
+
+          if (++iconUpdateCounter == len) {
+            check(datatext, "datatext", false);
+            check(datahtml, "datahtml", false);
+            check(mozilla, "about:mozilla", false);
+            check(robots, "about:robots", true);
+            check(html, "html", true);
+            check(png, "png", false);
+            check(svg, "svg", true);
+
+            // Get rid of the group and its children
+            // The group close will trigger a finish().
+            closeGroupItem(group);
+          }
+        });
+      });
+    }, win);
   }, win);
 }
--- a/browser/components/tabview/test/browser_tabview_bug626791.js
+++ b/browser/components/tabview/test/browser_tabview_bug626791.js
@@ -167,11 +167,12 @@ function test() {
         test();
       }, cw);
     };
 
     newWindowWithTabView(onShow, onLoad);
   }
 
   waitForExplicitFinish();
+  requestLongerTimeout(2);
 
   next();
 }
--- a/browser/components/tabview/test/browser_tabview_bug640765.js
+++ b/browser/components/tabview/test/browser_tabview_bug640765.js
@@ -6,63 +6,69 @@ let groupItem;
 
 function test() {
   waitForExplicitFinish();
 
   let newTabOne = gBrowser.addTab();
   let newTabTwo = gBrowser.addTab();
   let newTabThree = gBrowser.addTab();
 
-  gBrowser.pinTab(newTabOne);
-  gBrowser.pinTab(newTabTwo);
-  gBrowser.pinTab(newTabThree);
-
   registerCleanupFunction(function() {
     TabView.hide();
     while (gBrowser.tabs.length > 1)
       gBrowser.removeTab(gBrowser.tabs[0]);
   });
 
   showTabView(function() {
     contentWindow = document.getElementById("tab-view").contentWindow;
     is(contentWindow.GroupItems.groupItems.length, 1, "Has only one group");
 
     groupItem = contentWindow.GroupItems.groupItems[0];
 
-    is(xulTabForAppTabIcon(0), newTabOne,
-       "New tab one matches the first app tab icon in tabview");
-    is(xulTabForAppTabIcon(1), newTabTwo,
-       "New tab two matches the second app tab icon in tabview");
-    is(xulTabForAppTabIcon(2), newTabThree,
-       "New tab three matches the third app tab icon in tabview");
+    whenAppTabIconAdded(function() {
+      whenAppTabIconAdded(function() {
+        whenAppTabIconAdded(function() {
 
-    // move the last tab to the first position
-    gBrowser.moveTabTo(newTabThree, 0);
-    is(xulTabForAppTabIcon(0), newTabThree,
-       "New tab three matches the first app tab icon in tabview");
-    is(xulTabForAppTabIcon(1), newTabOne,
-       "New tab one matches the second app tab icon in tabview");
-    is(xulTabForAppTabIcon(2), newTabTwo,
-       "New tab two matches the third app tab icon in tabview");
+          is(xulTabForAppTabIcon(0), newTabOne,
+            "New tab one matches the first app tab icon in tabview");
+          is(xulTabForAppTabIcon(1), newTabTwo,
+            "New tab two matches the second app tab icon in tabview");
+          is(xulTabForAppTabIcon(2), newTabThree,
+            "New tab three matches the third app tab icon in tabview");
+
+          // move the last tab to the first position
+          gBrowser.moveTabTo(newTabThree, 0);
+          is(xulTabForAppTabIcon(0), newTabThree,
+            "New tab three matches the first app tab icon in tabview");
+          is(xulTabForAppTabIcon(1), newTabOne,
+            "New tab one matches the second app tab icon in tabview");
+          is(xulTabForAppTabIcon(2), newTabTwo,
+            "New tab two matches the third app tab icon in tabview");
 
-    // move the first tab to the second position
-    gBrowser.moveTabTo(newTabThree, 1);
-    is(xulTabForAppTabIcon(0), newTabOne,
-       "New tab one matches the first app tab icon in tabview");
-    is(xulTabForAppTabIcon(1), newTabThree,
-       "New tab three matches the second app tab icon in tabview");
-    is(xulTabForAppTabIcon(2), newTabTwo,
-       "New tab two matches the third app tab icon in tabview");
+          // move the first tab to the second position
+          gBrowser.moveTabTo(newTabThree, 1);
+          is(xulTabForAppTabIcon(0), newTabOne,
+            "New tab one matches the first app tab icon in tabview");
+          is(xulTabForAppTabIcon(1), newTabThree,
+            "New tab three matches the second app tab icon in tabview");
+          is(xulTabForAppTabIcon(2), newTabTwo,
+            "New tab two matches the third app tab icon in tabview");
 
-    hideTabView(function() {
-      gBrowser.removeTab(newTabOne);
-      gBrowser.removeTab(newTabTwo);
-      gBrowser.removeTab(newTabThree);
-      finish();
+          hideTabView(function() {
+            gBrowser.removeTab(newTabOne);
+            gBrowser.removeTab(newTabTwo);
+            gBrowser.removeTab(newTabThree);
+            finish();
+          });
+        });
+        gBrowser.pinTab(newTabThree);
+      });
+      gBrowser.pinTab(newTabTwo);
     });
+    gBrowser.pinTab(newTabOne);
   });
 }
 
 function xulTabForAppTabIcon(index) {
     return contentWindow.iQ(
              contentWindow.iQ(".appTabIcon", 
                               groupItem.$appTabTray)[index]).data("xulTab");
 }
new file mode 100644
--- /dev/null
+++ b/browser/components/tabview/test/browser_tabview_bug678374.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const ICON_URL = "moz-anno:favicon:http://example.com/browser/browser/components/tabview/test/test_bug678374_icon16.png";
+const TEST_URL = "http://example.com/browser/browser/components/tabview/test/test_bug678374.html";
+
+function test() {
+  Services.prefs.setBoolPref("browser.chrome.favicons", false);
+
+  waitForExplicitFinish();
+
+  newWindowWithTabView(function(win) {
+    is(win.gBrowser.tabs.length, 3, "There are 3 tabs")
+
+    let newTabOne = win.gBrowser.tabs[1];
+    let newTabTwo = win.gBrowser.tabs[2];
+    let cw = win.TabView.getContentWindow();
+    let groupItem = cw.GroupItems.groupItems[0];
+
+    // test tab item
+    let newTabItemOne = newTabOne._tabViewTabItem;
+
+    newTabItemOne.addSubscriber("iconUpdated", function onIconUpdated() {
+      newTabItemOne.removeSubscriber("iconUpdated", onIconUpdated);
+      is(newTabItemOne.$favImage[0].src, ICON_URL, "The tab item is showing the right icon.");
+
+      // test pin tab
+      whenAppTabIconAdded(function() {
+        let icon = cw.iQ(".appTabIcon", groupItem.$appTabTray)[0];
+        is(icon.src, ICON_URL, "The app tab is showing the right icon");
+
+        finish();
+      }, win);
+      win.gBrowser.pinTab(newTabTwo);
+    });
+  }, function(win) {
+    registerCleanupFunction(function() { 
+      Services.prefs.clearUserPref("browser.chrome.favicons");
+      win.close(); 
+   });
+
+    win.gBrowser.loadOneTab(TEST_URL);
+    win.gBrowser.loadOneTab(TEST_URL);
+  });
+}
--- a/browser/components/tabview/test/browser_tabview_bug685476.js
+++ b/browser/components/tabview/test/browser_tabview_bug685476.js
@@ -1,24 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   waitForExplicitFinish();
 
   showTabView(function () {
     let tab = gBrowser.addTab();
-    gBrowser.pinTab(tab);
     registerCleanupFunction(function () gBrowser.removeTab(tab));
 
-    let cw = TabView.getContentWindow();
-    let body = cw.document.body;
-    let [appTabIcon] = cw.iQ(".appTabTray .appTabIcon");
+    whenAppTabIconAdded(function() {
+      let cw = TabView.getContentWindow();
+      let body = cw.document.body;
+      let [appTabIcon] = cw.iQ(".appTabTray .appTabIcon");
 
-    EventUtils.synthesizeMouseAtCenter(appTabIcon, {type: "mousedown"}, cw);
-    EventUtils.synthesizeMouse(body, 500, 100, {type: "mousemove"}, cw);
-    EventUtils.synthesizeMouse(body, 500, 100, {type: "mouseup"}, cw);
+      EventUtils.synthesizeMouseAtCenter(appTabIcon, {type: "mousedown"}, cw);
+      EventUtils.synthesizeMouse(body, 500, 100, {type: "mousemove"}, cw);
+      EventUtils.synthesizeMouse(body, 500, 100, {type: "mouseup"}, cw);
 
-    ok(TabView.isVisible(), "tabview is still visible");
+      ok(TabView.isVisible(), "tabview is still visible");
 
-    hideTabView(finish);
+      hideTabView(finish);
+    });
+    gBrowser.pinTab(tab);
   });
 }
--- a/browser/components/tabview/test/head.js
+++ b/browser/components/tabview/test/head.js
@@ -380,8 +380,22 @@ function togglePrivateBrowsing(callback)
     executeSoon(function () afterAllTabsLoaded(callback));
   }, topic, false);
 
   let pb = Cc["@mozilla.org/privatebrowsing;1"].
            getService(Ci.nsIPrivateBrowsingService);
 
   pb.privateBrowsingEnabled = !pb.privateBrowsingEnabled;
 }
+
+// ----------
+function whenAppTabIconAdded(callback, win) {
+  win = win || window;
+
+  let contentWindow = win.TabView.getContentWindow();
+  let groupItems = contentWindow.GroupItems.groupItems;
+  let groupItem = groupItems[(groupItems.length - 1)];
+
+  groupItem.addSubscriber("appTabIconAdded", function onAppTabIconAdded() {
+    groupItem.removeSubscriber("appTabIconAdded", onAppTabIconAdded);
+    callback();
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/tabview/test/test_bug678374.html
@@ -0,0 +1,7 @@
+<html>
+  <head>
+    <title>Bug 678374</title>
+    <link rel="icon" type="image/png" id="favicon" href="test_bug678374_icon16.png" />
+  <body>
+  </body>
+</html>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bc317a8d5fc3121c939e2bc9a17f5d024b709a12
GIT binary patch
literal 924
zc$@*817rM&P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV000AHNkl<Zc-mc(
zeMsB|7{{NxvwQL8{qFtMd-Hd{J3a3_@AQ0|Zb~^TaRz2987(%p1>1t&a4q(ah$gW%
z8~dwZ5J60-O=1aaVdNh|ZlkDy8`LrwLK_O@pcwJ#7ZFl_e0lzPKHu;6fk%M<E4y&}
z-uS66ZY`c!TK)OMmGwLG_a9#Q{O;!H9}xO?Z{qrWF}`<O{sXUU{QlO!<W&-H&a?C4
zb@qPwJx_nOOwXmS2~J!kw*SI|^H*-Y1jx+VpCadOZW%26@XMTK*CdAWG=&2n(J^(I
z>SO0|Jo7eH{o{oC$B^hSV(sDJiF4<UEN@6+k$((+THl;76ptc~L89F!P_`dKY21gW
zw4Xrfc|wgt#2X(aQE11n77>XdyT@MBCNGKri5)X*Nb_mDp)UMQeK?A{aAjKY*0$iy
zwiC#;<Ew4LSJ#X)QAa%Af<4uRsdczoZv4uW41J8$jNp#uN#sk!3p%I+POS+?s)Q|;
z$5Nfcmu<lsOyLSA@fUiq^&UPgCl?<qi{~gNF;S@mX=v*}Eq7t9&gx)}%6J~Xo~*>P
z_%bE5awie39=BRT5}h|?czkY6#6l>lQE2Z#iKGyZhB=tQ9Livg)Df<4rn&bCwB`<y
zdOLThhN^&yWcoH_;Pu(NA~q5!mF|Hj$+qo4suCF8Nh|>kqo;;Pd@0I(1El{pXei@~
z)*%&M47vW_<j|RKz7pv}O(zK_Yp5+X5l-tjdsR%%gg$F9DlxW&G_+z1s@}lvj$pD!
zFcbz?<-)@1aglz4@j8;VDuHMmHJ8;>Y7tA23TIrOAwAJYEL*~0^&(<Ilr+*hG9wSs
zPimV)#6f+dMoi1-%Zi>5MvPvp&L~yBYCMqy4!?>R6h!P8)4fRltDOSK{EhX4V(TT~
zbK(xf5vkJULJVGPb`QnvWikzU6h*;ev}5*Wsd((jB^f%o^~%pqUps4bw&KzOt2L<0
zhuPxCY<3cfso3@ECNZ-uki|MM`kjnkHp?rYY#F?`v?($&JL<~q!5=Q+^QZ87V|d(A
z?3Dprfm)o!-B<_Tn3coto8_Gqk$3NG8H~*RC~|yBtS^6>wmmgA<=A=Xnyc-(d#<)U
y>yGXND?0drY454WW#6>O3ui^fmPDq$mA?Qdy0Sx%{P*|(0000<MNUMnLSTZyBg9Go
--- a/browser/components/tabview/ui.js
+++ b/browser/components/tabview/ui.js
@@ -46,16 +46,22 @@
 // Title: ui.js
 
 let Keys = { meta: false };
 
 // ##########
 // Class: UI
 // Singleton top-level UI manager.
 let UI = {
+  // Pref that controls whether to display site icons
+  PREF_CHROME_SITE_ICONS: "browser.chrome.site_icons",
+
+  // Pref that controls whether to display fav icons
+  PREF_CHROME_FAVICONS: "browser.chrome.favicons",
+
   // Variable: _frameInitialized
   // True if the Tab View UI frame has been initialized.
   _frameInitialized: false,
 
   // Variable: _pageBounds
   // Stores the page bounds.
   _pageBounds: null,
 
@@ -136,16 +142,22 @@ let UI = {
   // Variable: _lastOpenedTab
   // Used to keep track of the last opened tab.
   _lastOpenedTab: null,
 
   // Variable: _originalSmoothScroll
   // Used to keep track of the tab strip smooth scroll value.
   _originalSmoothScroll: null,
 
+  // Used to keep track of the browser.chrome.site_icons pref value.
+  _prefSiteIcons: null,
+
+  // Used to keep track of the browser.chrome.favicons pref value.
+  _prefFavicons: null,
+
   // ----------
   // Function: toString
   // Prints [UI] for debug use
   toString: function UI_toString() {
     return "[UI]";
   },
 
   // ----------
@@ -236,16 +248,20 @@ let UI = {
       });
 
       // ___ setup key handlers
       this._setTabViewFrameKeyHandlers();
 
       // ___ add tab action handlers
       this._addTabActionHandlers();
 
+      // ___ add preference observers
+      Services.prefs.addObserver(this.PREF_CHROME_SITE_ICONS, this, false);
+      Services.prefs.addObserver(this.PREF_CHROME_FAVICONS, this, false);
+
       // ___ groups
       GroupItems.init();
       GroupItems.pauseArrange();
       let hasGroupItemsData = GroupItems.load();
 
       // ___ tabs
       TabItems.init();
       TabItems.pausePainting();
@@ -287,16 +303,19 @@ let UI = {
       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);
+
+      // XXX this can be removed when bug 731868 is fixed
+      event = null;
     } catch(e) {
       Utils.log(e);
     } finally {
       GroupItems.resumeArrange();
     }
   },
 
   // Function: uninit
@@ -309,16 +328,19 @@ let UI = {
     this._cleanupFunctions = [];
 
     // additional clean up
     TabItems.uninit();
     GroupItems.uninit();
     Storage.uninit();
     StoragePolicy.uninit();
 
+    Services.prefs.removeObserver(this.PREF_CHROME_SITE_ICONS, this);
+    Services.prefs.removeObserver(this.PREF_CHROME_FAVICONS, this);
+
     this._removeTabActionHandlers();
     this._currentTab = null;
     this._pageBounds = null;
     this._reorderTabItemsOnShow = null;
     this._reorderTabsOnHide = null;
     this._frameInitialized = false;
   },
 
@@ -847,16 +869,29 @@ let UI = {
   // Function: _removeTabActionHandlers
   // Removes handlers to handle tab actions.
   _removeTabActionHandlers: function UI__removeTabActionHandlers() {
     for (let name in this._eventListeners)
       AllTabs.unregister(name, this._eventListeners[name]);
   },
 
   // ----------
+  // Function: observe
+  // Observes different preference value changes.
+  observe: function UI_observe(subject, topic, data) {
+    if (data == this.PREF_CHROME_SITE_ICONS) {
+      this._prefSiteIcons =
+        Services.prefs.getBoolPref(this.PREF_CHROME_SITE_ICONS);
+    } else if (data == this.PREF_CHROME_FAVICONS) {
+      this._prefFavicons =
+        Services.prefs.getBoolPref(this.PREF_CHROME_FAVICONS);
+    }
+  },
+
+  // ----------
   // Function: goToTab
   // Selects the given xul:tab in the browser.
   goToTab: function UI_goToTab(xulTab) {
     // If it's not focused, the onFocus listener would handle it.
     if (gBrowser.selectedTab == xulTab)
       this.onTabSelect(xulTab);
     else
       gBrowser.selectedTab = xulTab;
@@ -1599,49 +1634,85 @@ let UI = {
 
     if (this._storageSanity(data))
       Storage.saveUIData(gWindow, data);
   },
 
   // ----------
   // Function: _saveAll
   // Saves all data associated with TabView.
-  // TODO: Save info items
   _saveAll: function UI__saveAll() {
     this._save();
     GroupItems.saveAll();
     TabItems.saveAll();
   },
 
   // ----------
-  // Function: shouldLoadFavIcon
-  // Takes a xul:browser and checks whether we should display a favicon for it.
-  shouldLoadFavIcon: function UI_shouldLoadFavIcon(browser) {
-    return !(browser.contentDocument instanceof window.ImageDocument) &&
-            (browser.currentURI.schemeIs("about") ||
-             gBrowser.shouldLoadFavIcon(browser.contentDocument.documentURIObject));
+  // Function: _isImageDocument
+  // Checks whether an image is loaded into the given tab.
+  _isImageDocument: function UI__isImageDocument(tab, callback) {
+    let mm = tab.linkedBrowser.messageManager;
+    let message = "Panorama:isImageDocument";
+
+    mm.addMessageListener(message, function onMessage(cx) {
+      mm.removeMessageListener(cx.name, onMessage);
+      callback(cx.json.isImageDocument);
+    });
+    mm.sendAsyncMessage(message);
+  },
+
+  // ----------
+  // Function: _shouldLoadFavIcon
+  // Checks whether fav icon should be loaded for a given tab.
+  _shouldLoadFavIcon: function UI__shouldLoadFavIcon(tab) {
+    let uri = tab.linkedBrowser.currentURI;
+
+    if (!uri)
+      return false;
+
+    if (this._prefSiteIcons == null)
+      this._prefSiteIcons =
+        Services.prefs.getBoolPref(this.PREF_CHROME_SITE_ICONS);
+
+    if (!this._prefSiteIcons)
+      return false;
+
+    if (this._prefFavicons == null)
+      this._prefFavicons =
+        Services.prefs.getBoolPref(this.PREF_CHROME_FAVICONS);
+
+    return (this._prefFavicons && ("schemeIs" in uri) &&
+            (uri.schemeIs("http") || uri.schemeIs("https")));
   },
 
   // ----------
   // Function: getFavIconUrlForTab
   // Gets fav icon url for the given xul:tab.
-  getFavIconUrlForTab: function UI_getFavIconUrlForTab(tab) {
-    let url;
+  getFavIconUrlForTab: function UI_getFavIconUrlForTab(tab, callback) {
+    this._isImageDocument(tab, function(isImageDoc) {
+      if (isImageDoc) {
+        callback(tab.pinned ? tab.image : null);
+      } else {
+        let tabImage = tab.image;
+        if (tabImage) {
+          // if starts with http/https, fetch icon from favicon service via the moz-anno protocal
+          if (/^https?:/.test(tabImage))
+            tabImage = gFavIconService.getFaviconLinkForIcon(gWindow.makeURI(tab.image)).spec;
 
-    if (tab.image) {
-      // if starts with http/https, fetch icon from favicon service via the moz-anno protocal
-      if (/^https?:/.test(tab.image))
-        url = gFavIconService.getFaviconLinkForIcon(gWindow.makeURI(tab.image)).spec;
-      else
-        url = tab.image;
-    } else {
-      url = gFavIconService.getFaviconImageForPage(tab.linkedBrowser.currentURI).spec;
-    }
-
-    return url;
+          callback(tabImage);
+        } else {
+          // determine to load the default/cached icon or not and also ensure we don't show the default icon
+          // for about:-style error pages
+          let url = null;
+          if (this._shouldLoadFavIcon(tab))
+            url = gFavIconService.getFaviconImageForPage(tab.linkedBrowser.currentURI).spec;
+          callback(url);
+        }
+      }
+    }.bind(this));
   },
 
   // ----------
   // Function: notifySessionRestoreEnabled
   // Notify the user that session restore has been automatically enabled
   // by showing a banner that expects no user interaction. It fades out after
   // some seconds.
   notifySessionRestoreEnabled: function UI_notifySessionRestoreEnabled() {
--- a/browser/components/thumbnails/PageThumbs.jsm
+++ b/browser/components/thumbnails/PageThumbs.jsm
@@ -104,31 +104,32 @@ let PageThumbs = {
   },
 
   /**
    * Captures a thumbnail for the given browser and stores it to the cache.
    * @param aBrowser The browser to capture a thumbnail for.
    * @param aCallback The function to be called when finished (optional).
    */
   captureAndStore: function PageThumbs_captureAndStore(aBrowser, aCallback) {
+    let url = aBrowser.currentURI.spec;
     this.capture(aBrowser.contentWindow, function (aInputStream) {
       let telemetryStoreTime = new Date();
 
       function finish(aSuccessful) {
         if (aSuccessful) {
           Services.telemetry.getHistogramById("FX_THUMBNAILS_STORE_TIME_MS")
             .add(new Date() - telemetryStoreTime);
         }
 
         if (aCallback)
           aCallback(aSuccessful);
       }
 
       // Get a writeable cache entry.
-      PageThumbsCache.getWriteEntry(aBrowser.currentURI.spec, function (aEntry) {
+      PageThumbsCache.getWriteEntry(url, function (aEntry) {
         if (!aEntry) {
           finish(false);
           return;
         }
 
         let outputStream = aEntry.openOutputStream(0);
 
         // Write the image data to the cache entry.
--- a/browser/components/thumbnails/test/Makefile.in
+++ b/browser/components/thumbnails/test/Makefile.in
@@ -8,13 +8,14 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = browser/components/thumbnails/test
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_FILES = \
 	browser_thumbnails_capture.js \
+	browser_thumbnails_bug726727.js \
 	head.js \
 	$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/components/thumbnails/test/browser_thumbnails_bug726727.js
@@ -0,0 +1,19 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * These tests ensure that capturing a sites's thumbnail, saving it and
+ * retrieving it from the cache works.
+ */
+function runTests() {
+  // Create a tab that shows an error page.
+  let tab = gBrowser.addTab("http://non-existant.url/");
+  let browser = tab.linkedBrowser;
+
+  yield browser.addEventListener("DOMContentLoaded", function onLoad() {
+    browser.removeEventListener("DOMContentLoaded", onLoad, false);
+    executeSoon(next);
+  }, false);
+
+  ok(!gBrowserThumbnails._shouldCapture(browser), "we're not going to capture an error page");
+}
--- a/browser/devtools/debugger/DebuggerUI.jsm
+++ b/browser/devtools/debugger/DebuggerUI.jsm
@@ -44,17 +44,17 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
-Cu.import("resource:///modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/source-editor.jsm");
 
 let EXPORTED_SYMBOLS = ["DebuggerUI"];
 
 /**
  * Creates a pane that will host the debugger UI.
  */
 function DebuggerPane(aTab) {
--- a/browser/devtools/shared/test/browser_promise_basic.js
+++ b/browser/devtools/shared/test/browser_promise_basic.js
@@ -192,23 +192,114 @@ function testFailGroup(data) {
   preResolution = undefined;
   laterResolution = undefined;
   member1 = undefined;
   member2 = undefined;
   member3 = undefined;
   laterGroup = undefined;
   laterRejection = undefined;
 
-  finished();
+  testTrap();
+}
+
+function testTrap() {
+  var p = new Promise();
+  var message = "Expected exception";
+  p.chainPromise(
+    function() {
+      throw new Error(message);
+    }).trap(
+      function(aError) {
+        is(aError instanceof Error, true, "trap received exception");
+        is(aError.message, message, "trap received correct exception");
+        return 1;
+      }).chainPromise(
+        function(aResult) {
+          is(aResult, 1, "trap restored correct result");
+          testAlways();
+        });
+  p.resolve();
+}
+
+function testAlways() {
+  var shouldbeTrue1 = false;
+  var shouldbeTrue2 = false;
+  var p = new Promise();
+  p.chainPromise(
+    function() {
+      throw new Error();
+    }
+  ).chainPromise(// Promise rejected, should not be executed
+    function() {
+      ok(false, "This should not be executed");
+    }
+  ).always(
+    function(x) {
+      shouldbeTrue1 = true;
+      return "random value";
+    }
+  ).trap(
+    function(arg) {
+      ok((arg instanceof Error), "The random value should be ignored");
+      return 1;// We should still have this result later
+    }
+  ).trap(
+    function() {
+      ok(false, "This should not be executed 2");
+    }
+  ).always(
+    function() {
+      shouldbeTrue2 = true;
+    }
+  ).then(
+    function(aResult){
+      ok(shouldbeTrue1, "First always must be executed");
+      ok(shouldbeTrue2, "Second always must be executed");
+      is(aResult, 1, "Result should be unaffected by always");
+
+      testComplete();
+    }
+  );
+  p.resolve();
 }
 
 function fail() {
   gBrowser.removeCurrentTab();
   info("Failed Promise Tests");
   ok(false, "fail called");
   finish();
 }
 
+/**
+ * We wish to launch all tests with several configurations (at the moment,
+ * non-debug and debug mode).
+ *
+ * If 0, we have not completed any test yet.
+ * If 1, we have completed the tests in non-debug mode.
+ * If 2, we have also completed the tests in debug mode.
+ */
+var configurationTestComplete = 0;
+function testComplete() {
+  switch (configurationTestComplete) {
+  case 0:
+    info("Finished run in non-debug mode");
+    configurationTestComplete = 1;
+    Promise.Debug.setDebug(true);
+    window.setTimeout(testBasic, 0);
+    return;
+  case 1:
+    info("Finished run in debug mode");
+    configurationTestComplete = 2;
+    Promise.Debug.setDebug(false);
+    window.setTimeout(finished, 0);
+    return;
+  default:
+    ok(false, "Internal error in testComplete "+configurationTestComplete);
+    return;
+  }
+}
+
+
 function finished() {
   gBrowser.removeCurrentTab();
   info("Finishing Promise Tests");
   finish();
 }
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -43,16 +43,17 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 include $(topsrcdir)/config/rules.mk
 
 MOZ_PKG_REMOVALS = $(srcdir)/removed-files.in
 
 MOZ_PKG_MANIFEST_P = $(srcdir)/package-manifest.in
+MOZ_PKG_FATAL_WARNINGS = 1
 
 MOZ_NONLOCALIZED_PKG_LIST = \
 	xpcom \
 	browser \
 	$(NULL)
 
 MOZ_LOCALIZED_PKG_LIST = $(AB_CD)
 
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -20,28 +20,30 @@
 @APPNAME@/Contents/Info.plist
 @APPNAME@/Contents/PkgInfo
 @APPNAME@/Contents/Resources/
 #endif
 
 [@AB_CD@]
 @BINPATH@/chrome/@AB_CD@@JAREXT@
 @BINPATH@/chrome/@AB_CD@.manifest
-@BINPATH@/@PREF_DIR@/firefox-l10n.js
-@BINPATH@/searchplugins/*
 @BINPATH@/defaults/profile/bookmarks.html
+@BINPATH@/defaults/profile/chrome/*
 @BINPATH@/defaults/profile/localstore.rdf
 @BINPATH@/defaults/profile/mimeTypes.rdf
-@BINPATH@/defaults/profile/chrome/*
+@BINPATH@/dictionaries/*
+@BINPATH@/hyphenation/*
+@BINPATH@/@PREF_DIR@/firefox-l10n.js
+@BINPATH@/searchplugins/*
+#ifdef XP_WIN32
+@BINPATH@/uninstall/helper.exe
+#endif
+#ifdef MOZ_UPDATER
 @BINPATH@/update.locale
 @BINPATH@/updater.ini
-@BINPATH@/dictionaries/*
-@BINPATH@/hyphenation/*
-#ifdef XP_WIN32
-@BINPATH@/uninstall/helper.exe
 #endif
 
 [xpcom]
 @BINPATH@/dependentlibs.list
 #ifdef XP_WIN32
 @BINPATH@/@DLL_PREFIX@gkmedias@DLL_SUFFIX@
 #endif
 @BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@
@@ -381,20 +383,20 @@
 @BINPATH@/components/contentSecurityPolicy.js
 @BINPATH@/components/contentAreaDropListener.manifest
 @BINPATH@/components/contentAreaDropListener.js
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/RadioInterfaceLayer.manifest
 @BINPATH@/components/RadioInterfaceLayer.js
 @BINPATH@/components/SmsDatabaseService.manifest
 @BINPATH@/components/SmsDatabaseService.js
-@BINPATH@/components/nsWifiWorker.js
-@BINPATH@/components/nsWifiWorker.manifest
-@BINPATH@/components/nsDOMWifiManager.js
-@BINPATH@/components/nsDOMWifiManager.manifest
+@BINPATH@/components/WifiWorker.js
+@BINPATH@/components/WifiWorker.manifest
+@BINPATH@/components/DOMWifiManager.js
+@BINPATH@/components/DOMWifiManager.manifest
 #endif
 @BINPATH@/components/BrowserProfileMigrators.manifest
 @BINPATH@/components/ProfileMigrator.js
 @BINPATH@/components/ChromeProfileMigrator.js
 @BINPATH@/components/FirefoxProfileMigrator.js
 #ifdef XP_MACOSX
 @BINPATH@/components/libalerts.dylib
 #endif
@@ -551,21 +553,23 @@
 #ifdef SOLARIS
 bin/libfreebl_32fpu_3.so
 bin/libfreebl_32int_3.so
 bin/libfreebl_32int64_3.so
 #endif
 
 ; [Updater]
 ;
+#ifdef MOZ_UPDATER
 #ifdef XP_MACOSX
 @BINPATH@/updater.app/
 #else
 @BINPATH@/updater@BIN_SUFFIX@
 #endif
+#endif
 
 ; [MaintenanceService]
 ;
 #ifdef MOZ_MAINTENANCE_SERVICE
 @BINPATH@/maintenanceservice.exe
 @BINPATH@/maintenanceservice_installer.exe
 #endif
 
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -10,17 +10,16 @@
 @DLL_PREFIX@xpistub@DLL_SUFFIX@
 @DLL_PREFIX@zlib@DLL_SUFFIX@
 @DLL_PREFIX@jemalloc@DLL_SUFFIX@
 @DLL_PREFIX@mozutils@DLL_SUFFIX@
 #ifdef MOZ_STATIC_JS
 @DLL_PREFIX@mozjs@DLL_SUFFIX@
 #endif
 LICENSE
-update.locale
 browserconfig.properties
 chrome/US.jar
 chrome/app-chrome.manifest
 chrome/browser.manifest
 chrome/chrome.rdf
 chrome/chromelist.txt
 chrome/classic.jar
 chrome/classic.manifest
@@ -690,16 +689,25 @@ searchplugins/yandex.png
 searchplugins/yandex.src
 searchplugins/zoznam-sk.gif
 searchplugins/zoznam-sk.png
 searchplugins/zoznam-sk.src
 uninstall/UninstallDeerPark.exe
 uninstall/UninstallFirefox.exe
 uninstall/uninst.exe
 uninstall/uninstall.exe
+update.locale
+#ifndef MOZ_UPDATER
+  #ifdef XP_MACOSX
+    updater.app/
+  #else
+    updater@BIN_SUFFIX@
+  #endif
+  updater.ini
+#endif
 xpicleanup@BIN_SUFFIX@
 #ifdef MOZ_OMNIJAR
   omni.jar
   chrome/af.jar
   chrome/af.manifest
   chrome/ar.jar
   chrome/ar.manifest
   chrome/as.jar
@@ -922,20 +930,20 @@ xpicleanup@BIN_SUFFIX@
   components/PlacesProtocolHandler.js
   components/storage-Legacy.js
   components/storage-mozStorage.js
 #ifdef MOZ_B2G_RIL
   components/nsTelephonyWorker.manifest
   components/nsTelephonyWorker.js
   components/Telephony.manifest
   components/Telephony.js
-  components/nsWifiWorker.js
-  components/nsWifiWorker.manifest
-  components/nsDOMWifiManager.js
-  components/nsDOMWifiManager.manifest
+  components/WifiWorker.js
+  components/WifiWorker.manifest
+  components/DOMWifiManager.js
+  components/DOMWifiManager.manifest
 #endif
   components/txEXSLTRegExFunctions.js
   components/Weave.js
   components/Webapps.js
   components/Webapps.manifest
   components/WebContentConverter.js
   defaults/autoconfig/platform.js
   defaults/autoconfig/prefcalls.js
--- a/browser/locales/en-US/chrome/browser-region/region.properties
+++ b/browser/locales/en-US/chrome/browser-region/region.properties
@@ -12,17 +12,17 @@ browser.contentHandlers.types.0.title=Go
 browser.contentHandlers.types.0.uri=http://fusion.google.com/add?feedurl=%s
 browser.contentHandlers.types.1.title=My Yahoo!
 browser.contentHandlers.types.1.uri=http://add.my.yahoo.com/rss?url=%s
 
 # URL for site-specific search engines
 # TRANSLATION NOTE: {moz:domain} and {searchTerms} are placeholders for the site
 # to be searched and the user's search query. Place them in the appropriate location
 # for your locale's URL but do not translate them.
-browser.search.siteSearchURL=http://www.google.com/search?ie=UTF-8&oe=UTF-8&sourceid=navclient&q=site%3A{moz:domain}+{searchTerms}
+browser.search.siteSearchURL=https://www.google.com/search?ie=UTF-8&oe=UTF-8&sourceid=navclient&q=site%3A{moz:domain}+{searchTerms}
 
 # increment this number when anything gets changed in the list below.  This will
 # cause Firefox to re-read these prefs and inject any new handlers into the 
 # profile database.  Note that "new" is defined as "has a different URL"; this
 # means that it's not possible to update the name of existing handler, so 
 # don't make any spelling errors here.
 gecko.handlerService.defaultHandlersVersion=3
 
--- a/browser/locales/en-US/chrome/browser/aboutHome.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutHome.dtd
@@ -1,23 +1,26 @@
-<!ENTITY % brandDTD
-    SYSTEM "chrome://branding/locale/brand.dtd">
-  %brandDTD;
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
+%brandDTD;
+<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
+%syncBrandDTD;
 
 <!-- These strings are used in the about:home page -->
 
 <!ENTITY abouthome.pageTitle "&brandFullName; Start Page">
 
 <!ENTITY abouthome.searchEngineButton.label "Search">
 
-<!ENTITY abouthome.aboutMozilla "About Mozilla">
-
 <!-- LOCALIZATION NOTE (abouthome.defaultSnippet1.v1):
      text in <a/> will be linked to the Firefox features page on mozilla.com
 -->
 <!ENTITY abouthome.defaultSnippet1.v1 "Thanks for choosing Firefox! To get the most out of your browser, learn more about the <a>latest features</a>.">
 <!-- LOCALIZATION NOTE (abouthome.defaultSnippet2.v1):
      text in <a/> will be linked to the featured add-ons on addons.mozilla.org
 -->
 <!ENTITY abouthome.defaultSnippet2.v1 "It's easy to customize your Firefox exactly the way you want it. <a>Choose from thousands of add-ons</a>.">
 
-<!ENTITY abouthome.syncSetup.label   "Set Up Sync">
-<!ENTITY abouthome.pairDevice.label  "Pair a Device">
+<!ENTITY abouthome.bookmarksButton.label "Bookmarks">
+<!ENTITY abouthome.historyButton.label   "History">
+<!ENTITY abouthome.settingsButton.label  "Settings">
+<!ENTITY abouthome.addonsButton.label    "Add-ons">
+<!ENTITY abouthome.appsButton.label      "Marketplace">
+<!ENTITY abouthome.downloadsButton.label "Downloads">
--- a/browser/locales/en-US/searchplugins/google.xml
+++ b/browser/locales/en-US/searchplugins/google.xml
@@ -8,27 +8,27 @@
 #else
 #define GOOGLE_CLIENT_PARAM <MozParam name="client" condition="defaultEngine" trueValue="firefox-a" falseValue="firefox"/>
 #endif
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Google</ShortName>
 <Description>Google Search</Description>
 <InputEncoding>UTF-8</InputEncoding>
 <Image width="16" height="16">data:image/png;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA</Image>
-<Url type="application/x-suggestions+json" method="GET" template="http://suggestqueries.google.com/complete/search?output=firefox&amp;client=firefox&amp;hl={moz:locale}&amp;q={searchTerms}"/>
-<Url type="text/html" method="GET" template="http://www.google.com/search">
+<Url type="application/x-suggestions+json" method="GET" template="https://www.google.com/complete/search?output=firefox&amp;client=firefox&amp;hl={moz:locale}&amp;q={searchTerms}"/>
+<Url type="text/html" method="GET" template="https://www.google.com/search">
 #expand   __GOOGLE_PARAMS__
 #expand   __GOOGLE_CLIENT_PARAM__
 </Url>
 <!-- Keyword search URL is the same as the default, but with an additional parameter -->
-<Url type="application/x-moz-keywordsearch" method="GET" template="http://www.google.com/search">
+<Url type="application/x-moz-keywordsearch" method="GET" template="https://www.google.com/search">
 #expand   __GOOGLE_PARAMS__
 #expand   __GOOGLE_CLIENT_PARAM__
   <Param name="channel" value="fflb"/>
 </Url>
 <!-- Context/Right-click search URL is the same as the default, but with an additional parameter -->
-<Url type="application/x-moz-contextsearch" method="GET" template="http://www.google.com/search">
+<Url type="application/x-moz-contextsearch" method="GET" template="https://www.google.com/search">
 #expand   __GOOGLE_PARAMS__
 #expand   __GOOGLE_CLIENT_PARAM__
   <Param name="channel" value="rcs"/>
 </Url>
-<SearchForm>http://www.google.com/</SearchForm>
+<SearchForm>https://www.google.com/</SearchForm>
 </SearchPlugin>
--- a/browser/modules/NewTabUtils.jsm
+++ b/browser/modules/NewTabUtils.jsm
@@ -379,16 +379,25 @@ let BlockedLinks = {
 
     // Make sure we unpin blocked links.
     PinnedLinks.unpin(aLink);
 
     Storage.set("blockedLinks", this.links);
   },
 
   /**
+   * Unblocks a given link.
+   * @param aLink The link to unblock.
+   */
+  unblock: function BlockedLinks_unblock(aLink) {
+    if (this.isBlocked(aLink))
+      delete this.links[aLink.url];
+  },
+
+  /**
    * Returns whether a given link is blocked.
    * @param aLink The link to check.
    */
   isBlocked: function BlockedLinks_isBlocked(aLink) {
     return (aLink.url in this.links);
   },
 
   /**
@@ -545,17 +554,17 @@ let Links = {
 
     return pinnedLinks;
   },
 
   /**
    * Resets the links cache.
    */
   resetCache: function Links_resetCache() {
-    this._links = [];
+    this._links = null;
   },
 
   /**
    * Implements the nsIObserver interface to get notified about browser history
    * sanitization.
    */
   observe: function Links_observe(aSubject, aTopic, aData) {
     // Make sure to update open about:newtab instances. If there are no opened
@@ -579,22 +588,26 @@ let Links = {
                                          Ci.nsISupportsWeakReference])
 };
 
 /**
  * Singleton that provides the public API of this JSM.
  */
 let NewTabUtils = {
   /**
-   * Resets the NewTabUtils module, its links and its storage.
+   * Restores all sites that have been removed from the grid.
    */
-  reset: function NewTabUtils_reset() {
+  restore: function NewTabUtils_restore() {
     Storage.clear();
     Links.resetCache();
     PinnedLinks.resetCache();
     BlockedLinks.resetCache();
+
+    Links.populateCache(function () {
+      AllPages.update();
+    }, true);
   },
 
   allPages: AllPages,
   links: Links,
   pinnedLinks: PinnedLinks,
   blockedLinks: BlockedLinks
 };
index c0396f7abae8a9f498fe87c91e8bf66835d0c172..893a27d76ed0ba02cb06d0bc12b0e8ecd77a7abb
GIT binary patch
literal 21309
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
index c0396f7abae8a9f498fe87c91e8bf66835d0c172..893a27d76ed0ba02cb06d0bc12b0e8ecd77a7abb
GIT binary patch
literal 21309
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
--- a/browser/themes/winstripe/browser-aero.css
+++ b/browser/themes/winstripe/browser-aero.css
@@ -1,13 +1,13 @@
 %define WINSTRIPE_AERO
 %include browser.css
 %undef WINSTRIPE_AERO
 
-%define customToolbarColor hsl(214,44%,87%)
+%define customToolbarColor hsl(210,75%,92%)
 %define glassActiveBorderColor rgb(37, 44, 51)
 %define glassInactiveBorderColor rgb(102, 102, 102)
 
 @media not all and (-moz-windows-classic) {
   #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #appmenu-button-container {
     margin-top: 1px;
   }
 
--- a/browser/themes/winstripe/places/organizer-aero.css
+++ b/browser/themes/winstripe/places/organizer-aero.css
@@ -1,13 +1,13 @@
 %include organizer.css
 
 %filter substitution
 %define toolbarHighlight rgba(255,255,255,.5)
-%define customToolbarColor hsl(214,44%,87%)
+%define customToolbarColor hsl(210,75%,92%)
 
 #placesView {
   border-top: none;
 }
 
 @media not all and (-moz-windows-classic) {
   #placesToolbox {
     -moz-appearance: none;
index c0396f7abae8a9f498fe87c91e8bf66835d0c172..893a27d76ed0ba02cb06d0bc12b0e8ecd77a7abb
GIT binary patch
literal 21309
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