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 id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherdermozilla-central@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge 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
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
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
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
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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
new file mode 100644
--- /dev/null
+++ b/build/autoconf/arch.m4
@@ -0,0 +1,222 @@
+AC_DEFUN([MOZ_ARCH_OPTS],
+[
+
+dnl ========================================================
+dnl = ARM toolchain tweaks
+dnl ========================================================
+
+MOZ_THUMB=toolchain-default
+MOZ_THUMB_INTERWORK=toolchain-default
+MOZ_FPU=toolchain-default
+MOZ_FLOAT_ABI=toolchain-default
+MOZ_SOFT_FLOAT=toolchain-default
+
+MOZ_ARG_WITH_STRING(arch,
+[  --with-arch=[[type|toolchain-default]]
+                           Use specific CPU features (-march=type). Resets
+                           thumb, fpu, float-abi, etc. defaults when set],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-arch is not supported on non-GNU toolchains])
+    fi
+    MOZ_ARCH=$withval)
+
+if test -z "$MOZ_ARCH"; then
+    dnl Defaults
+    case "${CPU_ARCH}-${OS_TARGET}" in
+    arm-Android)
+        MOZ_THUMB=yes
+        MOZ_ARCH=armv7-a
+        MOZ_FPU=vfp
+        MOZ_FLOAT_ABI=softfp
+        ;;
+    arm-Darwin)
+        MOZ_ARCH=toolchain-default
+        MOZ_THUMB=yes
+        ;;
+    arm-*)
+        if test -n "$MOZ_PLATFORM_MAEMO"; then
+            MOZ_THUMB=no
+            MOZ_ARCH=armv7-a
+            MOZ_FLOAT_ABI=softfp
+        fi
+        if test "$MOZ_PLATFORM_MAEMO" = 6; then
+            MOZ_THUMB=yes
+        fi
+        ;;
+    esac
+fi
+
+MOZ_ARG_WITH_STRING(thumb,
+[  --with-thumb[[=yes|no|toolchain-default]]]
+[                          Use Thumb instruction set (-mthumb)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-thumb is not supported on non-GNU toolchains])
+    fi
+    MOZ_THUMB=$withval)
+
+MOZ_ARG_WITH_STRING(thumb-interwork,
+[  --with-thumb-interwork[[=yes|no|toolchain-default]]
+                           Use Thumb/ARM instuctions interwork (-mthumb-interwork)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-thumb-interwork is not supported on non-GNU toolchains])
+    fi
+    MOZ_THUMB_INTERWORK=$withval)
+
+MOZ_ARG_WITH_STRING(fpu,
+[  --with-fpu=[[type|toolchain-default]]
+                           Use specific FPU type (-mfpu=type)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-fpu is not supported on non-GNU toolchains])
+    fi
+    MOZ_FPU=$withval)
+
+MOZ_ARG_WITH_STRING(float-abi,
+[  --with-float-abi=[[type|toolchain-default]]
+                           Use specific arm float ABI (-mfloat-abi=type)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-float-abi is not supported on non-GNU toolchains])
+    fi
+    MOZ_FLOAT_ABI=$withval)
+
+MOZ_ARG_WITH_STRING(soft-float,
+[  --with-soft-float[[=yes|no|toolchain-default]]
+                           Use soft float library (-msoft-float)],
+    if test -z "$GNU_CC"; then
+        AC_MSG_ERROR([--with-soft-float is not supported on non-GNU toolchains])
+    fi
+    MOZ_SOFT_FLOAT=$withval)
+
+case "$MOZ_ARCH" in
+toolchain-default|"")
+    arch_flag=""
+    ;;
+*)
+    arch_flag="-march=$MOZ_ARCH"
+    ;;
+esac
+
+case "$MOZ_THUMB" in
+yes)
+    MOZ_THUMB2=1
+    thumb_flag="-mthumb"
+    ;;
+no)
+    MOZ_THUMB2=
+    thumb_flag="-marm"
+    ;;
+*)
+    _SAVE_CFLAGS="$CFLAGS"
+    CFLAGS="$arch_flag"
+    AC_TRY_COMPILE([],[return sizeof(__thumb2__);],
+        MOZ_THUMB2=1,
+        MOZ_THUMB2=)
+    CFLAGS="$_SAVE_CFLAGS"
+    thumb_flag=""
+    ;;
+esac
+
+if test "$MOZ_THUMB2" = 1; then
+    AC_DEFINE(MOZ_THUMB2)
+fi
+
+case "$MOZ_THUMB_INTERWORK" in
+yes)
+    thumb_interwork_flag="-mthumb-interwork"
+    ;;
+no)
+    thumb_interwork_flag="-mno-thumb-interwork"
+    ;;
+*) # toolchain-default
+    thumb_interwork_flag=""
+    ;;
+esac
+
+case "$MOZ_FPU" in
+toolchain-default|"")
+    fpu_flag=""
+    ;;
+*)
+    fpu_flag="-mfpu=$MOZ_FPU"
+    ;;
+esac
+
+case "$MOZ_FLOAT_ABI" in
+toolchain-default|"")
+    float_abi_flag=""
+    ;;
+*)
+    float_abi_flag="-mfloat-abi=$MOZ_FLOAT_ABI"
+    ;;
+esac
+
+case "$MOZ_SOFT_FLOAT" in
+yes)
+    soft_float_flag="-msoft-float"
+    ;;
+no)
+    soft_float_flag="-mno-soft-float"
+    ;;
+*) # toolchain-default
+    soft_float_flag=""
+    ;;
+esac
+
+dnl Use echo to avoid accumulating space characters
+all_flags=`echo $arch_flag $thumb_flag $thumb_interwork_flag $fpu_flag $float_abi_flag $soft_float_flag`
+if test -n "$all_flags"; then
+    _SAVE_CFLAGS="$CFLAGS"
+    CFLAGS="$all_flags"
+    AC_MSG_CHECKING(whether the chosen combination of compiler flags ($all_flags) works)
+    AC_TRY_COMPILE([],[return 0;],
+        AC_MSG_RESULT([yes]),
+        AC_MSG_ERROR([no]))
+
+    CFLAGS="$_SAVE_CFLAGS $all_flags"
+    CXXFLAGS="$CXXFLAGS $all_flags"
+    ASFLAGS="$ASFLAGS $all_flags"
+    if test -n "$thumb_flag"; then
+        LDFLAGS="$LDFLAGS $thumb_flag"
+    fi
+fi
+
+AC_SUBST(MOZ_THUMB2)
+
+if test "$CPU_ARCH" = "arm"; then
+  AC_MSG_CHECKING(for ARM SIMD support in compiler)
+  # We try to link so that this also fails when
+  # building with LTO.
+  AC_TRY_LINK([],
+                 [asm("uqadd8 r1, r1, r2");],
+                 result="yes", result="no")
+  AC_MSG_RESULT("$result")
+  if test "$result" = "yes"; then
+      AC_DEFINE(HAVE_ARM_SIMD)
+      HAVE_ARM_SIMD=1
+  fi
+
+  AC_MSG_CHECKING(for ARM NEON support in compiler)
+  # We try to link so that this also fails when
+  # building with LTO.
+  AC_TRY_LINK([],
+                 [asm(".fpu neon\n vadd.i8 d0, d0, d0");],
+                 result="yes", result="no")
+  AC_MSG_RESULT("$result")
+  if test "$result" = "yes"; then
+      AC_DEFINE(HAVE_ARM_NEON)
+      HAVE_ARM_NEON=1
+  fi
+fi # CPU_ARCH = arm
+
+AC_SUBST(HAVE_ARM_SIMD)
+AC_SUBST(HAVE_ARM_NEON)
+
+if test -n "$MOZ_ARCH"; then
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-arch=$MOZ_ARCH"
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-thumb=$MOZ_THUMB"
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-thumb-interwork=$MOZ_THUMB_INTERWORK"
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-fpu=$MOZ_FPU"
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-float-abi=$MOZ_FLOAT_ABI"
+  NSPR_CONFIGURE_ARGS="$NSPR_CONFIGURE_ARGS --with-soft-float=$MOZ_SOFT_FLOAT"
+fi
+
+])
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -695,18 +695,18 @@ user_pref("camino.use_system_proxy_setti
     # Need to figure out what tool and whether it write to a file or stdout
     if self.UNIXISH:
       utility = [os.path.join(utilityPath, "screentopng")]
       imgoutput = 'stdout'
     elif self.IS_MAC: