Merge the last PGO-green inbound changeset to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Sat, 21 Jul 2012 09:18:11 -0400
changeset 100036 6f87c97307916c1c7d4d479da524113969450361
parent 100035 446b788ab99d048922bbd432bca73a9198b4e8b6 (current diff)
parent 100020 e9e2767a427556247a18d841e73ba58d24bc5d95 (diff)
child 100037 a3e1c960433bb66e12ca8d3be0dbe42c8b24a54d
push id12307
push userryanvm@gmail.com
push dateSat, 21 Jul 2012 18:32:33 +0000
treeherdermozilla-inbound@defbe00ca091 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.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 the last PGO-green inbound changeset to m-c.
toolkit/content/tests/unit/test_privatebrowsing_downloadLastDir_c.js
toolkit/mozapps/downloads/tests/unit/test_DownloadLastDir.js
toolkit/mozapps/downloads/tests/unit/test_DownloadLastDirWithCPS.js
toolkit/mozapps/downloads/tests/unit/test_privatebrowsing_downloadLastDir.js
--- a/accessible/src/base/ARIAStateMap.cpp
+++ b/accessible/src/base/ARIAStateMap.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "ARIAStateMap.h"
 
+#include "nsARIAMap.h"
 #include "States.h"
 
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using namespace mozilla::a11y::aria;
 
@@ -216,21 +217,33 @@ aria::MapToState(EStateRule aRule, dom::
         0, states::MULTISELECTABLE | states::EXTSELECTABLE);
 
       MapTokenType(aElement, aState, data);
       return true;
     }
 
     case eARIAOrientation:
     {
-      static const EnumTypeData data(
-        nsGkAtoms::aria_orientation, states::HORIZONTAL,
-        &nsGkAtoms::vertical, states::VERTICAL);
+      if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_orientation,
+                                NS_LITERAL_STRING("horizontal"), eCaseMatters)) {
+        *aState &= ~states::VERTICAL;
+        *aState |= states::HORIZONTAL;
+      } else if (aElement->AttrValueIs(kNameSpaceID_None,
+                                       nsGkAtoms::aria_orientation,
+                                       NS_LITERAL_STRING("vertical"),
+                                       eCaseMatters)) {
+        *aState &= ~states::HORIZONTAL;
+        *aState |= states::VERTICAL;
+      } else {
+        NS_ASSERTION(!(*aState & (states::HORIZONTAL | states::VERTICAL)),
+                     "orientation state on role with default aria-orientation!");
+        *aState |= GetRoleMap(aElement)->Is(nsGkAtoms::scrollbar) ?
+          states::VERTICAL : states::HORIZONTAL;
+      }
 
-      MapEnumType(aElement, aState, data);
       return true;
     }
 
     case eARIAPressed:
     {
       static const TokenTypeData data(
         nsGkAtoms::aria_pressed, eMixedType,
         states::CHECKABLE, states::PRESSED);
--- a/accessible/src/base/NotificationController.cpp
+++ b/accessible/src/base/NotificationController.cpp
@@ -16,17 +16,19 @@
 #include "TextLeafAccessible.h"
 #include "TextUpdater.h"
 
 #ifdef DEBUG
 #include "Logging.h"
 #endif
 
 #include "mozilla/dom/Element.h"
+#include "mozilla/Telemetry.h"
 
+using namespace mozilla;
 using namespace mozilla::a11y;
 
 // Defines the number of selection add/remove events in the queue when they
 // aren't packed into single selection within event.
 const unsigned int kSelChangeCountToPack = 5;
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector
@@ -169,16 +171,18 @@ NotificationController::IsUpdatePending(
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: private
 
 void
 NotificationController::WillRefresh(mozilla::TimeStamp aTime)
 {
+  Telemetry::AutoTimer<Telemetry::A11Y_UPDATE_TIME> updateTimer();
+
   // If the document accessible that notification collector was created for is
   // now shut down, don't process notifications anymore.
   NS_ASSERTION(mDocument,
                "The document was shut down while refresh observer is attached!");
   if (!mDocument)
     return;
 
   // Any generic notifications should be queued if we're processing content
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -675,20 +675,30 @@ Accessible::NativeState()
   // Gather states::INVISIBLE and states::OFFSCREEN flags for this object.
   state |= VisibilityState();
 
   nsIFrame *frame = GetFrame();
   if (frame && (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW))
     state |= states::FLOATING;
 
   // Check if a XUL element has the popup attribute (an attached popup menu).
-  if (mContent->IsXUL())
+  if (mContent->IsXUL()) {
     if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popup))
       state |= states::HASPOPUP;
 
+    const nsStyleXUL *xulStyle = frame->GetStyleXUL();
+    if (xulStyle && frame->IsBoxFrame()) {
+      // In XUL all boxes are either vertical or horizontal
+      if (xulStyle->mBoxOrient == NS_STYLE_BOX_ORIENT_VERTICAL)
+        state |= states::VERTICAL;
+      else
+        state |= states::HORIZONTAL;
+    }
+  }
+
   // Bypass the link states specialization for non links.
   if (!mRoleMapEntry || mRoleMapEntry->roleRule == kUseNativeRole ||
       mRoleMapEntry->role == roles::LINK)
     state |= NativeLinkState();
 
   return state;
 }
 
@@ -1505,27 +1515,16 @@ Accessible::State()
     return state;
 
   const nsStyleDisplay* display = frame->GetStyleDisplay();
   if (display && display->mOpacity == 1.0f &&
       !(state & states::INVISIBLE)) {
     state |= states::OPAQUE1;
   }
 
-  const nsStyleXUL *xulStyle = frame->GetStyleXUL();
-  if (xulStyle) {
-    // In XUL all boxes are either vertical or horizontal
-    if (xulStyle->mBoxOrient == NS_STYLE_BOX_ORIENT_VERTICAL) {
-      state |= states::VERTICAL;
-    }
-    else {
-      state |= states::HORIZONTAL;
-    }
-  }
-
   return state;
 }
 
 void
 Accessible::ApplyARIAState(PRUint64* aState) const
 {
   if (!mContent->IsElement())
     return;
--- a/accessible/tests/mochitest/hyperlink/test_general.html
+++ b/accessible/tests/mochitest/hyperlink/test_general.html
@@ -70,48 +70,46 @@ https://bugzilla.mozilla.org/show_bug.cg
       //////////////////////////////////////////////////////////////////////////
       // normal hyperlink
       var normalHyperlinkAcc = getAccessible("NormalHyperlink",
                                              [nsIAccessibleHyperLink]);
       testThis("NormalHyperlink", normalHyperlinkAcc, ROLE_LINK, 1,
                "Mozilla Foundation", true, 17, 18);
       is(normalHyperlinkAcc.getURI(0).spec, "http://www.mozilla.org/", 
          "URI wrong for normalHyperlinkElement!");
-      testStates(normalHyperlinkAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
+      testStates(normalHyperlinkAcc, STATE_LINKED, 0);
 
       //////////////////////////////////////////////////////////////////////////
       // ARIA hyperlink
       var ariaHyperlinkAcc = getAccessible("AriaHyperlink",
                                            [nsIAccessibleHyperLink]);
       testThis("AriaHyperlink", ariaHyperlinkAcc, ROLE_LINK, 1,
                "Mozilla Foundation Home", true, 30, 31);
-      testStates(ariaHyperlinkAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
+      testStates(ariaHyperlinkAcc, STATE_LINKED, 0);
       testAction("AriaHyperlink", ariaHyperlinkAcc, "click");
 
       //////////////////////////////////////////////////////////////////////////
       // ARIA hyperlink with status invalid
       var invalidAriaHyperlinkAcc = getAccessible("InvalidAriaHyperlink",
                                                   [nsIAccessibleHyperLink]);
       is(invalidAriaHyperlinkAcc.valid, false, "Should not be valid!");
-      testStates(invalidAriaHyperlinkAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
+      testStates(invalidAriaHyperlinkAcc, STATE_LINKED, 0);
 
       //////////////////////////////////////////////////////////////////////////
       // image map and its link children
 
       var imageMapHyperlinkAcc = getAccessible("imgmap",
                                                [nsIAccessibleHyperLink]);
       testThis("imgmap", imageMapHyperlinkAcc, ROLE_IMAGE_MAP, 2, "b", true,
                79, 80);
       is(imageMapHyperlinkAcc.getURI(0).spec,
          "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!");
-      testStates(imageMapHyperlinkAcc,
-                 (0),
-                 (EXT_STATE_HORIZONTAL));
+      testStates(imageMapHyperlinkAcc, 0, 0);
 
       var area1 = getAccessible(imageMapHyperlinkAcc.firstChild,
                                 [nsIAccessibleHyperLink]);
       testThis("Area1", area1, ROLE_LINK, 1, "b", true, 0, 1);
       is(area1.getURI(0).spec,
          "http://www.bbc.co.uk/radio4/atoz/index.shtml#b", "URI wrong!");
       testStates(area1, (STATE_LINKED));
 
@@ -122,111 +120,96 @@ https://bugzilla.mozilla.org/show_bug.cg
          "http://www.bbc.co.uk/radio4/atoz/index.shtml#a", "URI wrong!");
       testStates(area2, (STATE_LINKED));
 
       //////////////////////////////////////////////////////////////////////////
       // empty hyperlink
       var EmptyHLAcc = getAccessible("emptyLink",
                                      [nsIAccessibleHyperLink]);
       testThis("emptyLink", EmptyHLAcc, ROLE_LINK, 1, null, true, 93, 94);
-      testStates(EmptyHLAcc,
-                 (STATE_FOCUSABLE | STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
+      testStates(EmptyHLAcc, (STATE_FOCUSABLE | STATE_LINKED), 0);
       testAction("emptyLink", EmptyHLAcc, "jump");
 
       //////////////////////////////////////////////////////////////////////////
       // normal hyperlink with embedded span
       var hyperlinkWithSpanAcc = getAccessible("LinkWithSpan",
                                                [nsIAccessibleHyperLink]);
       testThis("LinkWithSpan", hyperlinkWithSpanAcc, ROLE_LINK, 1,
                "Heise Online", true, 119, 120);
       is(hyperlinkWithSpanAcc.getURI(0).spec, "http://www.heise.de/", 
          "URI wrong for hyperlinkElementWithSpan!");
-      testStates(hyperlinkWithSpanAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
+      testStates(hyperlinkWithSpanAcc, STATE_LINKED, 0);
       testAction("LinkWithSpan", hyperlinkWithSpanAcc, "jump");
 
       //////////////////////////////////////////////////////////////////////////
       // Named anchor, should never have state_linked
       var namedAnchorAcc = getAccessible("namedAnchor",
                                          [nsIAccessibleHyperLink]);
       testThis("namedAnchor", namedAnchorAcc, ROLE_LINK, 1,
                "This should never be of state_linked", true, 196, 197);
-      testStates(namedAnchorAcc,
-                 (STATE_SELECTABLE),
-                 (EXT_STATE_HORIZONTAL), (STATE_FOCUSABLE | STATE_LINKED));
+      testStates(namedAnchorAcc, STATE_SELECTABLE,
+                 0, (STATE_FOCUSABLE | STATE_LINKED));
       testAction("namedAnchor", namedAnchorAcc, "");
 
       //////////////////////////////////////////////////////////////////////////
       // No link (hasn't any attribute), should never have state_linked
       var noLinkAcc = getAccessible("noLink",
                                     [nsIAccessibleHyperLink]);
       testThis("noLink", noLinkAcc, ROLE_LINK, 1,
                "This should never be of state_linked", true, 254, 255);
-      testStates(noLinkAcc,
-                 0,
-                 (EXT_STATE_HORIZONTAL), (STATE_FOCUSABLE | STATE_LINKED));
+      testStates(noLinkAcc, 0, 0, (STATE_FOCUSABLE | STATE_LINKED));
       testAction("noLink", noLinkAcc, "");
 
       //////////////////////////////////////////////////////////////////////////
       // Link with registered 'click' event, should have state_linked
       var linkWithClickAcc = getAccessible("linkWithClick",
                                            [nsIAccessibleHyperLink]);
       testThis("linkWithClick", linkWithClickAcc, ROLE_LINK, 1,
                "This should have state_linked", true, 292, 293);
-      testStates(linkWithClickAcc,
-                 (STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
+      testStates(linkWithClickAcc, STATE_LINKED, 0);
       testAction("linkWithClick", linkWithClickAcc, "click");
 
       //////////////////////////////////////////////////////////////////////////
       // Maps to group links (bug 431615).
       var linksMapAcc = getAccessible("linksmap");
 
       //////////////////////////////////////////////////////////////////////////
       // Link with title attribute, no name from the subtree (bug 438325).
       var id = "linkWithTitleNoNameFromSubtree";
       var linkAcc = getAccessible(id, [nsIAccessibleHyperLink]);
       testThis(id, linkAcc, ROLE_LINK, 1, "Link with title", true, 344, 345);
-      testStates(linkAcc,
-                 (STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
+      testStates(linkAcc, STATE_LINKED, 0);
       testAction(id, linkAcc, "jump");
 
       //////////////////////////////////////////////////////////////////////////
       // Link with title attribute, name from the subtree - onscreen name
       // (bug 438325).
       id = "linkWithTitleNameFromSubtree";
       linkAcc = getAccessible(id, [nsIAccessibleHyperLink]);
       testThis(id, linkAcc, ROLE_LINK, 1, "the name from subtree", true, 393,
                394);
-      testStates(linkAcc,
-                 (STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
+      testStates(linkAcc, STATE_LINKED, 0);
       testAction(id, linkAcc, "jump");
 
       //////////////////////////////////////////////////////////////////////////
       // Link with title attribute, name from the nested html:img (bug 438325).
       id = "linkWithTitleNameFromImg";
       linkAcc = getAccessible(id, [nsIAccessibleHyperLink]);
       testThis(id, linkAcc, ROLE_LINK, 1, "The title for link", true, 447,
                448);
-      testStates(linkAcc,
-                 (STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
+      testStates(linkAcc, STATE_LINKED, 0);
       testAction(id, linkAcc, "jump");
 
       //////////////////////////////////////////////////////////////////////////
       // Link with label, no name from the subtree (bug 438325).
       id = "linkWithLabelNoNameFromSubtree";
       linkAcc = getAccessible(id, [nsIAccessibleHyperLink]);
       testThis(id, linkAcc, ROLE_LINK, 1, "Link with label and nested image:",
                true, 450, 451);
-      testStates(linkAcc,
-                 (STATE_LINKED),
-                 (EXT_STATE_HORIZONTAL));
+      testStates(linkAcc, STATE_LINKED, 0);
       testAction(id, linkAcc, "jump");
 
       //////////////////////////////////////////////////////////////////////////
       // Text accessible shouldn't implement nsIAccessibleHyperLink
       var res = isAccessible(getNode("namedAnchor").firstChild,
                              [nsIAccessibleHyperLink]);
       ok(!res, "Text accessible shouldn't implement nsIAccessibleHyperLink");
 
--- a/accessible/tests/mochitest/hyperlink/test_general.xul
+++ b/accessible/tests/mochitest/hyperlink/test_general.xul
@@ -40,17 +40,17 @@
     var gQueue = null;
     function doTest()
     {
       var linkedLabelAcc = getAccessible("linkedLabel",
                                          [nsIAccessibleHyperLink]);
       testThis("linkedLabel", linkedLabelAcc, ROLE_LINK, 1,
                "Mozilla Foundation home", "http://www.mozilla.org/", 1, 2,
                true);
-      testStates(linkedLabelAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
+      testStates(linkedLabelAcc, STATE_LINKED, 0);
 
       var labelWithValueAcc = getAccessible("linkLabelWithValue",
                                             [nsIAccessibleHyperLink]);
       testThis("linkLabelWithValue", labelWithValueAcc, ROLE_LINK, 1,
                "Mozilla Foundation", "http://www.mozilla.org/", 2, 3, true,
                false, true);
       testStates(labelWithValueAcc, STATE_LINKED, EXT_STATE_HORIZONTAL);
 
--- a/accessible/tests/mochitest/states/test_aria.html
+++ b/accessible/tests/mochitest/states/test_aria.html
@@ -148,25 +148,25 @@
 
       // some weak landmarks
       testStates("aria_main_link", STATE_LINKED);
       testStates("aria_navigation_link", STATE_LINKED);
       testStates("aria_main_anchor", STATE_SELECTABLE);
       testStates("aria_navigation_anchor", STATE_SELECTABLE);
 
       // aria-orientation (applied to scrollbar, separator, slider)
-      testStates("aria_scrollbar", 0, EXT_STATE_HORIZONTAL);
-      testStates("aria_hscrollbar", 0, EXT_STATE_HORIZONTAL);
-      testStates("aria_vscrollbar", 0, EXT_STATE_VERTICAL);
-      testStates("aria_separator", 0, EXT_STATE_HORIZONTAL);
-      testStates("aria_hseparator", 0, EXT_STATE_HORIZONTAL);
-      testStates("aria_vseparator", 0, EXT_STATE_VERTICAL);
-      testStates("aria_slider", 0, EXT_STATE_HORIZONTAL);
-      testStates("aria_hslider", 0, EXT_STATE_HORIZONTAL);
-      testStates("aria_vslider", 0, EXT_STATE_VERTICAL);
+      testStates("aria_scrollbar", 0, EXT_STATE_VERTICAL, 0, EXT_STATE_HORIZONTAL);
+      testStates("aria_hscrollbar", 0, EXT_STATE_HORIZONTAL, 0, EXT_STATE_VERTICAL);
+      testStates("aria_vscrollbar", 0, EXT_STATE_VERTICAL, 0, EXT_STATE_HORIZONTAL);
+      testStates("aria_separator", 0, EXT_STATE_HORIZONTAL, 0, EXT_STATE_VERTICAL);
+      testStates("aria_hseparator", 0, EXT_STATE_HORIZONTAL, 0, EXT_STATE_VERTICAL);
+      testStates("aria_vseparator", 0, EXT_STATE_VERTICAL, 0, EXT_STATE_HORIZONTAL);
+      testStates("aria_slider", 0, EXT_STATE_HORIZONTAL, 0, EXT_STATE_VERTICAL);
+      testStates("aria_hslider", 0, EXT_STATE_HORIZONTAL, 0, EXT_STATE_VERTICAL);
+      testStates("aria_vslider", 0, EXT_STATE_VERTICAL, 0, EXT_STATE_HORIZONTAL);
 
       // indeterminate ARIA progressbars (no aria-valuenow or aria-valuetext attribute)
       // should expose mixed state
       testStates("aria_progressbar", STATE_MIXED);
       testStates("aria_progressbar_valuenow", 0, 0, STATE_MIXED);
       testStates("aria_progressbar_valuetext", 0, 0, STATE_MIXED);
 
       SimpleTest.finish();
@@ -220,16 +220,21 @@
      title="Mochitests for ARIA states">
     Mozilla Bug 457226
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=740851"
      title="ARIA undetermined progressmeters should expose mixed state">
     Mozilla Bug 740851
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=762876
+     title="fix default horizontal / vertical state of role=scrollbar and ensure only one of horizontal / vertical states is exposed">
+    Mozilla Bug 762876
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <div id="textbox_autocomplete_inline" role="textbox" aria-autocomplete="inline"></div>
   <div id="textbox_autocomplete_list" role="textbox" aria-autocomplete="list"></div>
   <div id="textbox_autocomplete_both" role="textbox" aria-autocomplete="both"></div>
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -241,27 +241,27 @@ var shell = {
           let documentElement = contentWindow.document.documentElement;
           if (!documentElement)
             return;
 
           let manifest = documentElement.getAttribute('manifest');
           if (!manifest)
             return;
 
-          let documentURI = contentWindow.document.documentURIObject;
-          if (!Services.perms.testPermission(documentURI, 'offline-app')) {
+          let principal = contentWindow.document.nodePrincipal;
+          if (Services.perms.testPermissionFromPrincipal(principal, 'offline-app') == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
             if (Services.prefs.getBoolPref('browser.offline-apps.notify')) {
               // FIXME Bug 710729 - Add a UI for offline cache notifications
               return;
             }
             return;
           }
 
-          Services.perms.add(documentURI, 'offline-app',
-                             Ci.nsIPermissionManager.ALLOW_ACTION);
+          Services.perms.addFromPrincipal(principal, 'offline-app',
+                                          Ci.nsIPermissionManager.ALLOW_ACTION);
 
           let manifestURI = Services.io.newURI(manifest, null, documentURI);
           let updateService = Cc['@mozilla.org/offlinecacheupdate-service;1']
                               .getService(Ci.nsIOfflineCacheUpdateService);
           updateService.scheduleUpdate(manifestURI, documentURI, window);
         } catch (e) {
           dump('Error while creating offline cache: ' + e + '\n');
         }
--- a/b2g/components/CameraContent.js
+++ b/b2g/components/CameraContent.js
@@ -54,17 +54,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");
+    let perm = Services.perms.testExactPermissionFromPrincipal(principal, "content-camera");
 
     //only pages with perm set and chrome pages can use the camera in content
     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;
   },
--- a/browser/components/privatebrowsing/test/browser/Makefile.in
+++ b/browser/components/privatebrowsing/test/browser/Makefile.in
@@ -15,16 +15,20 @@ MOCHITEST_BROWSER_FILES =  \
 		browser_console_clear.js \
 		browser_privatebrowsing_certexceptionsui.js \
 		browser_privatebrowsing_clearplugindata.js \
 		browser_privatebrowsing_clearplugindata.html \
 		browser_privatebrowsing_commandline_toggle.js \
 		browser_privatebrowsing_concurrent.js \
 		browser_privatebrowsing_concurrent_page.html \
 		browser_privatebrowsing_crh.js \
+		browser_privatebrowsing_downloadLastDir.js \
+		browser_privatebrowsing_downloadLastDir_c.js \
+		browser_privatebrowsing_downloadLastDir_toggle.js \
+		browser_privatebrowsing_DownloadLastDirWithCPS.js \
 		browser_privatebrowsing_fastswitch.js \
 		browser_privatebrowsing_findbar.js \
 		browser_privatebrowsing_forgetthissite.js \
 		browser_privatebrowsing_geoprompt.js \
 		browser_privatebrowsing_geoprompt_page.html \
 		browser_privatebrowsing_import.js \
 		browser_privatebrowsing_lastpbcontextexited.js \
 		browser_privatebrowsing_localStorage.js \
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js
@@ -0,0 +1,222 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+let downloadModule = {};
+Cu.import("resource://gre/modules/DownloadLastDir.jsm", downloadModule);
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/FileUtils.jsm");
+
+let gDownloadLastDir = new downloadModule.DownloadLastDir(window);
+let pb = Cc["@mozilla.org/privatebrowsing;1"].
+         getService(Ci.nsIPrivateBrowsingService);
+
+function test() {
+  function clearHistory() {
+    // simulate clearing the private data
+    Services.obs.notifyObservers(null, "browser:purge-session-history", "");
+  }
+
+  is(typeof gDownloadLastDir, "object", "gDownloadLastDir should be a valid object");
+  is(gDownloadLastDir.file, null, "LastDir pref should be null to start with");
+
+  let tmpDir = FileUtils.getDir("TmpD", [], true);
+
+  let uri1 = Services.io.newURI("http://test1.com/", null, null);
+  let uri2 = Services.io.newURI("http://test2.com/", null, null);
+  let uri3 = Services.io.newURI("http://test3.com/", null, null);
+  let uri4 = Services.io.newURI("http://test4.com/", null, null);
+
+  function newDir() {
+    let dir = tmpDir.clone();
+    dir.append("testdir");
+    dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0700);
+    return dir;
+  }
+
+  let dir1 = newDir();
+  let dir2 = newDir();
+  let dir3 = newDir();
+  try {
+    { // set up last dir
+      gDownloadLastDir.setFile(null, tmpDir);
+      is(gDownloadLastDir.file.path, tmpDir.path, "LastDir should point to the tmpDir");
+      isnot(gDownloadLastDir.file, tmpDir, "gDownloadLastDir.file should not be pointing to tmpDir");
+    }
+
+    { // set uri1 to dir1, all should now return dir1
+      // also check that a new object is returned
+      gDownloadLastDir.setFile(uri1, dir1);
+      is(gDownloadLastDir.file.path, dir1.path, "gDownloadLastDir should return dir1");
+      isnot(gDownloadLastDir.file, dir1, "gDownloadLastDir.file should not return dir1");
+      is(gDownloadLastDir.getFile(uri1).path, dir1.path, "uri1 should return dir1"); // set in CPS
+      isnot(gDownloadLastDir.getFile(uri1), dir1, "getFile on uri1 should not return dir1");
+      is(gDownloadLastDir.getFile(uri2).path, dir1.path, "uri2 should return dir1"); // fallback
+      isnot(gDownloadLastDir.getFile(uri2), dir1, "getFile on uri2 should not return dir1");
+      is(gDownloadLastDir.getFile(uri3).path, dir1.path, "uri3 should return dir1"); // fallback
+      isnot(gDownloadLastDir.getFile(uri3), dir1, "getFile on uri3 should not return dir1");
+      is(gDownloadLastDir.getFile(uri4).path, dir1.path, "uri4 should return dir1"); // fallback
+      isnot(gDownloadLastDir.getFile(uri4), dir1, "getFile on uri4 should not return dir1");
+    }
+
+    { // set uri2 to dir2, all except uri1 should now return dir2
+      gDownloadLastDir.setFile(uri2, dir2);
+      is(gDownloadLastDir.file.path, dir2.path, "gDownloadLastDir should point to dir2");
+      is(gDownloadLastDir.getFile(uri1).path, dir1.path, "uri1 should return dir1"); // set in CPS
+      is(gDownloadLastDir.getFile(uri2).path, dir2.path, "uri2 should return dir2"); // set in CPS
+      is(gDownloadLastDir.getFile(uri3).path, dir2.path, "uri3 should return dir2"); // fallback
+      is(gDownloadLastDir.getFile(uri4).path, dir2.path, "uri4 should return dir2"); // fallback
+    }
+
+    { // set uri3 to dir3, all except uri1 and uri2 should now return dir3
+      gDownloadLastDir.setFile(uri3, dir3);
+      is(gDownloadLastDir.file.path, dir3.path, "gDownloadLastDir should point to dir3");
+      is(gDownloadLastDir.getFile(uri1).path, dir1.path, "uri1 should return dir1"); // set in CPS
+      is(gDownloadLastDir.getFile(uri2).path, dir2.path, "uri2 should return dir2"); // set in CPS
+      is(gDownloadLastDir.getFile(uri3).path, dir3.path, "uri3 should return dir3"); // set in CPS
+      is(gDownloadLastDir.getFile(uri4).path, dir3.path, "uri4 should return dir4"); // fallback
+    }
+
+    { // set uri1 to dir2, all except uri3 should now return dir2
+      gDownloadLastDir.setFile(uri1, dir2);
+      is(gDownloadLastDir.file.path, dir2.path, "gDownloadLastDir should point to dir2");
+      is(gDownloadLastDir.getFile(uri1).path, dir2.path, "uri1 should return dir2"); // set in CPS
+      is(gDownloadLastDir.getFile(uri2).path, dir2.path, "uri2 should return dir2"); // set in CPS
+      is(gDownloadLastDir.getFile(uri3).path, dir3.path, "uri3 should return dir3"); // set in CPS
+      is(gDownloadLastDir.getFile(uri4).path, dir2.path, "uri4 should return dir2"); // fallback
+    }
+
+    { // check clearHistory removes all data
+      clearHistory();
+      is(gDownloadLastDir.file, null, "clearHistory removes all data");
+      is(Services.contentPrefs.hasPref(uri1, "browser.download.lastDir"), false, "LastDir preference should be absent");
+      is(gDownloadLastDir.getFile(uri1), null, "uri1 should point to null");
+      is(gDownloadLastDir.getFile(uri2), null, "uri2 should point to null");
+      is(gDownloadLastDir.getFile(uri3), null, "uri3 should point to null");
+      is(gDownloadLastDir.getFile(uri4), null, "uri4 should point to null");
+    }
+
+    Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+
+    { // check data set outside PB mode is remembered
+      gDownloadLastDir.setFile(null, tmpDir);
+      pb.privateBrowsingEnabled = true;
+      is(gDownloadLastDir.file.path, tmpDir.path, "LastDir should point to tmpDir inside PB mode");
+      is(gDownloadLastDir.getFile(uri1).path, tmpDir.path, "uri1 should return tmpDir inside PB mode");
+
+      pb.privateBrowsingEnabled = false;
+      is(gDownloadLastDir.file.path, tmpDir.path, "LastDir should point to tmpDir outside PB mode");
+      is(gDownloadLastDir.getFile(uri1).path, tmpDir.path, "uri1 should return tmpDir outside PB mode");
+
+      clearHistory();
+    }
+
+    { // check data set using CPS outside PB mode is remembered
+      gDownloadLastDir.setFile(uri1, dir1);
+      pb.privateBrowsingEnabled = true;
+      is(gDownloadLastDir.file.path, dir1.path, "LastDir should point to dir1 inside PB mode");
+      is(gDownloadLastDir.getFile(uri1).path, dir1.path, "uri1 should return dir1 inside PB mode");
+
+      pb.privateBrowsingEnabled = false;
+      is(gDownloadLastDir.file.path, dir1.path, "LastDir should point to dir1 outside PB mode");
+      is(gDownloadLastDir.getFile(uri1).path, dir1.path, "uri1 should return dir1 outside PB mode");
+
+      clearHistory();
+    }
+
+    { // check data set inside PB mode is forgotten
+      pb.privateBrowsingEnabled = true;
+      gDownloadLastDir.setFile(null, tmpDir);
+      is(gDownloadLastDir.file.path, tmpDir.path, "LastDir should return tmpDir inside PB mode");
+      is(gDownloadLastDir.getFile(uri1).path, tmpDir.path, "uri1 should return tmpDir inside PB mode");
+
+      pb.privateBrowsingEnabled = false;
+      is(gDownloadLastDir.file, null, "LastDir should be null outside PB mode");
+      is(gDownloadLastDir.getFile(uri1), null, "uri1 should return null outside PB mode");
+
+      clearHistory();
+    }
+
+    { // check data set using CPS inside PB mode is forgotten
+      pb.privateBrowsingEnabled = true;
+      gDownloadLastDir.setFile(uri1, dir1);
+      is(gDownloadLastDir.file.path, dir1.path, "LastDir should point to dir1 inside PB mode");
+      is(gDownloadLastDir.getFile(uri1).path, dir1.path, "uri1 should return dir1 inside PB mode");
+
+      pb.privateBrowsingEnabled = false;
+      is(gDownloadLastDir.file, null, "LastDir should point to null outside PB mode");
+      is(gDownloadLastDir.getFile(uri1), null, "uri1 should return null outside PB mode");
+
+      clearHistory();
+    }
+
+    { // check data set outside PB mode but changed inside is remembered correctly
+      gDownloadLastDir.setFile(uri1, dir1);
+      pb.privateBrowsingEnabled = true;
+      gDownloadLastDir.setFile(uri1, dir2);
+      is(gDownloadLastDir.file.path, dir2.path, "LastDir should point to dir2 inside PB mode");
+      is(gDownloadLastDir.getFile(uri1).path, dir2.path, "uri1 should return dir2 inside PB mode");
+
+      pb.privateBrowsingEnabled = false;
+      is(gDownloadLastDir.file.path, dir1.path, "LastDir should point to dir1 outside PB mode");
+      is(gDownloadLastDir.getFile(uri1).path, dir1.path, "uri1 should return dir1 outside PB mode");
+
+      // check that the last dir store got cleared
+      pb.privateBrowsingEnabled = true;
+      is(gDownloadLastDir.file.path, dir1.path, "LastDir should be cleared");
+      is(gDownloadLastDir.getFile(uri1).path, dir1.path, "uri1 should return dir1");
+
+      pb.privateBrowsingEnabled = false;
+      clearHistory();
+    }
+
+    { // check clearHistory inside PB mode clears data outside PB mode
+      pb.privateBrowsingEnabled = true;
+      gDownloadLastDir.setFile(uri1, dir2);
+
+      clearHistory();
+      is(gDownloadLastDir.file, null, "LastDir should be null afer clearing history");
+      is(gDownloadLastDir.getFile(uri1), null, "uri1 should return null");
+
+      pb.privateBrowsingEnabled = false;
+      is(gDownloadLastDir.file, null, "LastDir should be null");
+      is(gDownloadLastDir.getFile(uri1), null, "uri1 should return null");
+    }
+
+    { // check that disabling CPS works
+      Services.prefs.setBoolPref("browser.download.lastDir.savePerSite", false);
+
+      gDownloadLastDir.setFile(uri1, dir1);
+      is(gDownloadLastDir.file.path, dir1.path, "LastDir should be set to dir1");
+      is(gDownloadLastDir.getFile(uri1).path, dir1.path, "uri1 should return dir1");
+      is(gDownloadLastDir.getFile(uri2).path, dir1.path, "uri2 should return dir1");
+      is(gDownloadLastDir.getFile(uri3).path, dir1.path, "uri3 should return dir1");
+      is(gDownloadLastDir.getFile(uri4).path, dir1.path, "uri4 should return dir1");
+
+      gDownloadLastDir.setFile(uri2, dir2);
+      is(gDownloadLastDir.file.path, dir2.path, "LastDir should be set to dir2");
+      is(gDownloadLastDir.getFile(uri1).path, dir2.path, "uri1 should return dir2");
+      is(gDownloadLastDir.getFile(uri2).path, dir2.path, "uri2 should return dir2");
+      is(gDownloadLastDir.getFile(uri3).path, dir2.path, "uri3 should return dir2");
+      is(gDownloadLastDir.getFile(uri4).path, dir2.path, "uri4 should return dir2");
+
+      Services.prefs.clearUserPref("browser.download.lastDir.savePerSite");
+    }
+
+    { // check that passing null to setFile clears the stored value
+      gDownloadLastDir.setFile(uri3, dir3);
+      is(gDownloadLastDir.getFile(uri3).path, dir3.path, "LastDir should be set to dir3");
+      gDownloadLastDir.setFile(uri3, null);
+      is(gDownloadLastDir.getFile(uri3), null, "uri3 should return null");
+    }
+  } finally {
+      dir1.remove(true);
+      dir2.remove(true);
+      dir3.remove(true);
+      Services.prefs.clearUserPref("browser.download.lastDir.savePerSite");
+      Services.prefs.clearUserPref("browser.download.lastDir");
+      gDownloadLastDir.cleanupPrivateFile();
+      delete FileUtils;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir.js
@@ -0,0 +1,98 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+let downloadModule = {};
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/DownloadLastDir.jsm", downloadModule);
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://mochikit/MockFilePicker.jsm");
+
+let launcher = {
+  source: Services.io.newURI("http://test1.com/file", null, null)
+};
+let pb = Cc["@mozilla.org/privatebrowsing;1"].
+         getService(Ci.nsIPrivateBrowsingService);
+let gDownloadLastDir = new downloadModule.DownloadLastDir(window);
+
+MockFilePicker.init();
+MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
+
+function test() {
+  Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+  let prefs = Services.prefs.getBranch("browser.download.");
+  let launcherDialog = Cc["@mozilla.org/helperapplauncherdialog;1"].
+                       getService(Ci.nsIHelperAppLauncherDialog);
+  let tmpDir = FileUtils.getDir("TmpD", [], true);
+  function newDirectory() {
+    let dir = tmpDir.clone();
+    dir.append("testdir");
+    dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0700);
+    return dir;
+  }
+  function newFileInDirectory(dir) {
+    let file = dir.clone();
+    file.append("testfile");
+    file.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0600);
+    return file;
+  }
+
+  let dir1 = newDirectory();
+  let dir2 = newDirectory();
+  let dir3 = newDirectory();
+  let file1 = newFileInDirectory(dir1);
+  let file2 = newFileInDirectory(dir2);
+  let file3 = newFileInDirectory(dir3);
+
+  // cleanup functions registration
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("browser.privatebrowsing.keep_current_session");
+    Services.prefs.clearUserPref("browser.download.lastDir");
+    [dir1, dir2, dir3].forEach(function(dir) dir.remove(true));
+    MockFilePicker.cleanup();
+    gDownloadLastDir.cleanupPrivateFile();
+    delete FileUtils;
+  });
+
+  let context = gBrowser.selectedBrowser.contentWindow;
+
+  prefs.setComplexValue("lastDir", Ci.nsIFile, tmpDir);
+  MockFilePicker.returnFiles = [file1];
+  let file = launcherDialog.promptForSaveToFile(launcher, context, null, null, null);
+  ok(!!file, "promptForSaveToFile correctly returned a file");
+  // file picker should start with browser.download.lastDir
+  is(MockFilePicker.displayDirectory.path, tmpDir.path, "File picker should start with browser.download.lastDir");
+  // browser.download.lastDir should be modified before entering the private browsing mode
+  is(prefs.getComplexValue("lastDir", Ci.nsIFile).path, dir1.path, "LastDir should be modified before entering the PB mode");
+  // gDownloadLastDir should be usable outside of the private browsing mode
+  is(gDownloadLastDir.file.path, dir1.path, "gDownloadLastDir should be usable outside of the PB mode");
+
+  pb.privateBrowsingEnabled = true;
+  is(prefs.getComplexValue("lastDir", Ci.nsIFile).path, dir1.path, "LastDir should be that set before entering PB mode");
+  MockFilePicker.returnFiles = [file2];
+  MockFilePicker.displayDirectory = null;
+  file = launcherDialog.promptForSaveToFile(launcher, context, null, null, null);
+  ok(!!file, "promptForSaveToFile correctly returned a file");
+  // file picker should start with browser.download.lastDir as set before entering the private browsing mode
+  is(MockFilePicker.displayDirectory.path, dir1.path, "Start with LastDir as set before entering the PB mode");
+  // browser.download.lastDir should not be modified inside the private browsing mode
+  is(prefs.getComplexValue("lastDir", Ci.nsIFile).path, dir1.path, "LastDir should not be modified inside the PB mode");
+  // but gDownloadLastDir should be modified
+  is(gDownloadLastDir.file.path, dir2.path, "gDownloadLastDir should be modified inside PB mode");
+
+  pb.privateBrowsingEnabled = false;
+  // gDownloadLastDir should be cleared after leaving the private browsing mode
+  is(gDownloadLastDir.file.path, dir1.path, "gDownloadLastDir should be cleared after leaving the PB mode");
+  MockFilePicker.returnFiles = [file3];
+  MockFilePicker.displayDirectory = null;
+  file = launcherDialog.promptForSaveToFile(launcher, context, null, null, null);
+  ok(!!file, "promptForSaveToFile correctly returned a file");
+  // file picker should start with browser.download.lastDir as set before entering the private browsing mode
+  is(MockFilePicker.displayDirectory.path, dir1.path, "Start with LastDir as set before entering the PB mode");
+  // browser.download.lastDir should be modified after leaving the private browsing mode
+  is(prefs.getComplexValue("lastDir", Ci.nsIFile).path, dir3.path, "LastDir should be modified after leaving the PB mode");
+  // gDownloadLastDir should be usable after leaving the private browsing mode
+  is(gDownloadLastDir.file.path, dir3.path, "gDownloadLastDir should be usable after leaving the PB mode");
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_c.js
@@ -0,0 +1,112 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+let downloadModule = {};
+Cu.import("resource://gre/modules/DownloadLastDir.jsm", downloadModule);
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://mochikit/MockFilePicker.jsm");
+
+let pb = Cc["@mozilla.org/privatebrowsing;1"].
+         getService(Ci.nsIPrivateBrowsingService);
+let gDownloadLastDir = new downloadModule.DownloadLastDir(window);
+
+MockFilePicker.init();
+MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
+
+function test() {
+  let stringBundleToRestore = ContentAreaUtils.stringBundle;
+  let validateFileNameToRestore = validateFileName;
+
+  Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+  let prefs = Services.prefs.getBranch("browser.download.");
+  let tmpDir = FileUtils.getDir("TmpD", [], true);
+  function newDirectory() {
+    let dir = tmpDir.clone();
+    dir.append("testdir");
+    dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0700);
+    return dir;
+  }
+
+  function newFileInDirectory(dir) {
+    let file = dir.clone();
+    file.append("testfile");
+    file.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0600);
+    return file;
+  }
+
+  let dir1 = newDirectory();
+  let dir2 = newDirectory();
+  let dir3 = newDirectory();
+  let file1 = newFileInDirectory(dir1);
+  let file2 = newFileInDirectory(dir2);
+  let file3 = newFileInDirectory(dir3);
+
+  // cleanup function registration
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("browser.privatebrowsing.keep_current_session");
+    Services.prefs.clearUserPref("browser.download.lastDir");
+    [dir1, dir2, dir3].forEach(function(dir) dir.remove(true));
+    MockFilePicker.cleanup();
+    ContentAreaUtils.stringBundle = stringBundleToRestore;
+    validateFileName = validateFileNameToRestore;
+    gDownloadLastDir.cleanupPrivateFile();
+    delete FileUtils;
+  });
+
+  // Overwrite stringBundle to return an object masquerading as a string bundle
+  delete ContentAreaUtils.stringBundle;
+  ContentAreaUtils.stringBundle = {
+    GetStringFromName: function() ""
+  };
+
+  // Overwrite validateFileName to validate everything
+  validateFileName = function(foo) foo;
+
+  let params = {
+    fpTitleKey: "test",
+    fileInfo: new FileInfo("test.txt", "test.txt", "test", "txt", "http://mozilla.org/test.txt"),
+    contentType: "text/plain",
+    saveMode: SAVEMODE_FILEONLY,
+    saveAsType: kSaveAsType_Complete,
+    file: null
+  };
+
+  prefs.setComplexValue("lastDir", Ci.nsIFile, tmpDir);
+  MockFilePicker.returnFiles = [file1];
+  MockFilePicker.displayDirectory = null;
+  ok(getTargetFile(params), "Show the file picker dialog with given params");
+  // file picker should start with browser.download.lastDir
+  is(MockFilePicker.displayDirectory.path, tmpDir.path, "file picker should start with browser.download.lastDir");
+  // browser.download.lastDir should be modified before entering the private browsing mode
+  is(prefs.getComplexValue("lastDir", Ci.nsIFile).path, dir1.path, "LastDir should be modified before entering PB mode");
+  // gDownloadLastDir should be usable outside of the private browsing mode
+  is(gDownloadLastDir.file.path, dir1.path, "gDownloadLastDir should be usable outside of the PB mode");
+
+  pb.privateBrowsingEnabled = true;
+  is(prefs.getComplexValue("lastDir", Ci.nsIFile).path, dir1.path, "LastDir should be that set before PB mode");
+  MockFilePicker.returnFiles = [file2];
+  MockFilePicker.displayDirectory = null;
+  ok(getTargetFile(params), "Show the file picker dialog with the given params");
+  // file picker should start with browser.download.lastDir as set before entering the private browsing mode
+  is(MockFilePicker.displayDirectory.path, dir1.path, "File picker should start with LastDir set before entering PB mode");
+  // browser.download.lastDir should not be modified inside the private browsing mode
+  is(prefs.getComplexValue("lastDir", Ci.nsIFile).path, dir1.path, "LastDir should not be modified inside PB mode");
+  // but gDownloadLastDir should be modified
+  is(gDownloadLastDir.file.path, dir2.path, "gDownloadLastDir should be modified");
+
+  pb.privateBrowsingEnabled = false;
+  // gDownloadLastDir should be cleared after leaving the private browsing mode
+  is(gDownloadLastDir.file.path, dir1.path, "gDownloadLastDir should be cleared after leaving PB mode");
+  MockFilePicker.returnFiles = [file3];
+  MockFilePicker.displayDirectory = null;
+  ok(getTargetFile(params), "Show the file picker dialog with the given params");
+  // file picker should start with browser.download.lastDir as set before entering the private browsing mode
+  is(MockFilePicker.displayDirectory.path, dir1.path, "File picker should start with LastDir set before PB mode");
+  // browser.download.lastDir should be modified after leaving the private browsing mode
+  is(prefs.getComplexValue("lastDir", Ci.nsIFile).path, dir3.path, "LastDir should be modified after leaving PB mode");
+  // gDownloadLastDir should be usable after leaving the private browsing mode
+  is(gDownloadLastDir.file.path, dir3.path, "gDownloadLastDir should be usable after leaving PB mode");
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js
@@ -0,0 +1,74 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+let downloadModule = {};
+Cu.import("resource://gre/modules/DownloadLastDir.jsm", downloadModule);
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+let gDownloadLastDir = new downloadModule.DownloadLastDir(window);
+let pb = Cc["@mozilla.org/privatebrowsing;1"].
+         getService(Ci.nsIPrivateBrowsingService);
+
+function test() {
+  function clearHistory() {
+    // simulate clearing the private data
+    Services.obs.notifyObservers(null, "browser:purge-session-history", "");
+  }
+
+  is(typeof gDownloadLastDir, "object", "gDownloadLastDir should be a valid object");
+  is(gDownloadLastDir.file, null, "gDownloadLastDir.file should be null to start with");
+  let tmpDir = FileUtils.getDir("TmpD", [], true);
+  let newDir = tmpDir.clone();
+
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("browser.privatebrowsing.keep_current_session");
+    Services.prefs.clearUserPref("browser.download.lastDir");
+    newDir.remove(true);
+    gDownloadLastDir.cleanupPrivateFile();
+    delete FileUtils;
+  });
+
+  newDir.append("testdir");
+  newDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0700);
+
+  gDownloadLastDir.file = tmpDir;
+  is(gDownloadLastDir.file.path, tmpDir.path, "LastDir should point to the temporary directory");
+  isnot(gDownloadLastDir.file, tmpDir, "gDownloadLastDir.file should not be pointing to the tmpDir");
+
+  gDownloadLastDir.file = 1; // not an nsIFile
+  is(gDownloadLastDir.file, null, "gDownloadLastDir.file should be null");
+  gDownloadLastDir.file = tmpDir;
+
+  clearHistory();
+  is(gDownloadLastDir.file, null, "gDownloadLastDir.file should be null");
+  gDownloadLastDir.file = tmpDir;
+
+  Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+
+  pb.privateBrowsingEnabled = true;
+  is(gDownloadLastDir.file.path, tmpDir.path, "LastDir should point to the temporary directory");
+  isnot(gDownloadLastDir.file, tmpDir, "gDownloadLastDir.file should not be pointing to the tmpDir");
+
+  pb.privateBrowsingEnabled = false;
+  is(gDownloadLastDir.file.path, tmpDir.path, "LastDir should point to the tmpDir");
+  pb.privateBrowsingEnabled = true;
+
+  gDownloadLastDir.file = newDir;
+  is(gDownloadLastDir.file.path, newDir.path, "gDownloadLastDir should be modified in PB mode");
+  isnot(gDownloadLastDir.file, newDir, "gDownloadLastDir should not point to the newDir");
+
+  pb.privateBrowsingEnabled = false;
+  is(gDownloadLastDir.file.path, tmpDir.path, "gDownloadLastDir should point to the earlier directory outside PB mode");
+  isnot(gDownloadLastDir.file, tmpDir, "gDownloadLastDir should not be modifief outside PB mode");
+
+  pb.privateBrowsingEnabled = true;
+  isnot(gDownloadLastDir.file, null, "gDownloadLastDir should not be null inside PB mode");
+  clearHistory();
+  is(gDownloadLastDir.file, null, "gDownloadLastDir should be null after clearing history");
+
+  pb.privateBrowsingEnabled = false;
+  is(gDownloadLastDir.file, null, "gDownloadLastDir should be null outside PB mode");
+}
--- a/dom/alarm/AlarmsManager.js
+++ b/dom/alarm/AlarmsManager.js
@@ -129,18 +129,17 @@ AlarmsManager.prototype = {
 
     // Set navigator.mozAlarms to null.
     if (!Services.prefs.getBoolPref("dom.mozAlarms.enabled"))
       return null;
 
     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, "alarms");
+    let perm = Services.perms.testExactPermissionFromPrincipal(principal, "alarms");
 
     // Only pages with perm set can use the alarms.
     this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
 
     if (!this.hasPrivileges)
       return null;
 
     this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
--- a/dom/system/gonk/VolumeServiceTest.cpp
+++ b/dom/system/gonk/VolumeServiceTest.cpp
@@ -20,17 +20,17 @@
 #define VOLUME_MANAGER_LOG_TAG  "VolumeServiceTest"
 #include "VolumeManagerLog.h"
 
 using namespace mozilla::services;
 
 namespace mozilla {
 namespace system {
 
-#define TEST_NSVOLUME_OBSERVER  1
+#define TEST_NSVOLUME_OBSERVER  0
 
 #if TEST_NSVOLUME_OBSERVER
 
 /***************************************************************************
 * A test class to verify that the Observer stuff is working properly.
 */
 class VolumeTestObserver : public nsIObserver
 {
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -5123,17 +5123,16 @@ CompExprTransplanter::transplant(ParseNo
             return false;
         if (pn->isArity(PN_FUNC))
             --funcLevel;
 
         if (pn->isDefn()) {
             if (genexp && !BumpStaticLevel(pn, tc))
                 return false;
         } else if (pn->isUsed()) {
-            JS_ASSERT(!pn->isOp(JSOP_NOP));
             JS_ASSERT(pn->pn_cookie.isFree());
 
             Definition *dn = pn->pn_lexdef;
             JS_ASSERT(dn->isDefn());
 
             /*
              * Adjust the definition's block id only if it is a placeholder not
              * to the left of the root node, and if pn is the last use visited
--- a/js/src/jit-test/tests/basic/bug632778-1.js
+++ b/js/src/jit-test/tests/basic/bug632778-1.js
@@ -1,7 +1,6 @@
-load(libdir + "asserts.js");
+// |jit-test| error: TypeError
 function f() {
     "use strict";
 }
 g = wrap(f);
-assertThrowsInstanceOf(function () { Object.defineProperty(g, "arguments", {set: function(){}}); }, TypeError);
-
+Object.defineProperty(g, "arguments", {set: function(){}});
--- a/js/src/jit-test/tests/basic/bug632778-2.js
+++ b/js/src/jit-test/tests/basic/bug632778-2.js
@@ -1,4 +1,3 @@
-load(libdir + "asserts.js");
+// |jit-test| error: TypeError
 obj = wrap(Number.bind());
-assertThrowsInstanceOf(function () { Object.defineProperty(obj, "caller", {set: function(){}}); }, TypeError);
-
+Object.defineProperty(obj, "caller", {set: function () {}});
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug633828.js
@@ -0,0 +1,6 @@
+// |jit-test| error: SyntaxError
+(function() {
+  function a() {}
+  function a() {}
+}
+for
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug770952.js
@@ -0,0 +1,5 @@
+// |jit-test| error: TypeError
+eval("var x; typeof x")
+Array.prototype.iterator = function () { for(y in x); };
+for (var v of ['a', 'b', 'c', 'd'])
+    s = v;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testBug775807.js
@@ -0,0 +1,19 @@
+// |jit-test| dump-bytecode;error:SyntaxError
+
+(function() {
+    const x = ((function() {
+        return {
+            e: function() {
+                (function() {
+                    for (e in x) {}
+                })()
+            }
+        }
+    }(function() {
+        return {
+            t: {
+                c
+            }
+        }
+    })))
+})()
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -1775,26 +1775,28 @@ DumpBytecodeScriptCallback(JSRuntime *rt
 } /* anonymous namespace */
 
 JS_PUBLIC_API(void)
 JS_DumpCompartmentBytecode(JSContext *cx)
 {
     ScriptsToDump scripts;
     IterateCells(cx->runtime, cx->compartment, gc::FINALIZE_SCRIPT, &scripts, DumpBytecodeScriptCallback);
 
-    for (size_t i = 0; i < scripts.length(); i++)
-        JS_DumpBytecode(cx, scripts[i]);
+    for (size_t i = 0; i < scripts.length(); i++) {
+        if (scripts[i]->enclosingScriptsCompiledSuccessfully())
+            JS_DumpBytecode(cx, scripts[i]);
+    }
 }
 
 JS_PUBLIC_API(void)
 JS_DumpCompartmentPCCounts(JSContext *cx)
 {
     for (CellIter i(cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
         JSScript *script = i.get<JSScript>();
-        if (script->hasScriptCounts)
+        if (script->hasScriptCounts && script->enclosingScriptsCompiledSuccessfully())
             JS_DumpPCCounts(cx, script);
     }
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_UnwrapObject(JSObject *obj)
 {
     return UnwrapObject(obj);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1855,16 +1855,40 @@ JSScript::numNotes()
 {
     jssrcnote *sn;
     jssrcnote *notes_ = notes();
     for (sn = notes_; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
         continue;
     return sn - notes_ + 1;    /* +1 for the terminator */
 }
 
+bool
+JSScript::enclosingScriptsCompiledSuccessfully() const
+{
+    /*
+     * When a nested script is succesfully compiled, it is eagerly given the
+     * static JSFunction of its enclosing script. The enclosing function's
+     * 'script' field will be NULL until the enclosing script successfully
+     * compiles. Thus, we can detect failed compilation by looking for
+     * JSFunctions in the enclosingScope chain without scripts.
+     */
+    JSObject *enclosing = enclosingScope_;
+    while (enclosing) {
+        if (enclosing->isFunction()) {
+            JSFunction *fun = enclosing->toFunction();
+            if (!fun->script())
+                return false;
+            enclosing = fun->script()->enclosingScope_;
+        } else {
+            enclosing = enclosing->asStaticBlock().enclosingStaticScope();
+        }
+    }
+    return true;
+}
+
 JS_FRIEND_API(void)
 js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
 {
     JS_ASSERT(!script->callDestroyHook);
     JS_ASSERT(!script->isActiveEval);
     if (JSNewScriptHook hook = cx->runtime->debugHooks.newScriptHook) {
         AutoKeepAtoms keep(cx->runtime);
         hook(cx, script->filename, script->lineno, script, fun,
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -648,17 +648,32 @@ struct JSScript : public js::gc::Cell
     inline js::analyze::ScriptAnalysis *analysis();
 
     inline bool hasGlobal() const;
     inline bool hasClearedGlobal() const;
 
     inline js::GlobalObject &global() const;
 
     /* See StaticScopeIter comment. */
-    JSObject *enclosingStaticScope() const { return enclosingScope_; }
+    JSObject *enclosingStaticScope() const {
+        JS_ASSERT(enclosingScriptsCompiledSuccessfully());
+        return enclosingScope_;
+    }
+
+    /*
+     * If a compile error occurs in an enclosing function after parsing a
+     * nested function, the enclosing function's JSFunction, which appears on
+     * the nested function's enclosingScope chain, will be invalid. Normal VM
+     * operation only sees scripts where all enclosing scripts have been
+     * successfully compiled. Any path that may look at scripts left over from
+     * unsuccessful compilation (e.g., by iterating over all scripts in the
+     * compartment) should check this predicate before doing any operation that
+     * uses enclosingScope (e.g., ScopeCoordinateName).
+     */
+    bool enclosingScriptsCompiledSuccessfully() const;
 
   private:
     bool makeTypes(JSContext *cx);
     bool makeAnalysis(JSContext *cx);
 
 #ifdef JS_METHODJIT
   private:
     // CallCompiler must be a friend because it generates code that directly
--- a/services/aitc/modules/browserid.js
+++ b/services/aitc/modules/browserid.js
@@ -207,37 +207,36 @@ BrowserIDService.prototype = {
   /**
    * Open a login window and ask the user to login, returning the assertion
    * generated as a result to the caller.
    */
   _getAssertionWithLogin: function _getAssertionWithLogin(cb, win) {
     // We're executing navigator.id.get as a content script in win.
     // This results in a popup that we will temporarily unblock.
     let pm = Services.perms;
-    let origin = Services.io.newURI(
-      win.wrappedJSObject.location.toString(), null, null
-    );
-    let oldPerm = pm.testExactPermission(origin, "popup");
+    let principal = win.document.nodePrincipal;
+
+    let oldPerm = pm.testExactPermissionFromPrincipal(principal, "popup");
     try {
-      pm.add(origin, "popup", pm.ALLOW_ACTION);
+      pm.addFromPrincipal(principal, "popup", pm.ALLOW_ACTION);
     } catch(e) {
       this._log.warn("Setting popup blocking to false failed " + e);
     }
 
     // Open sandbox and execute script. This sandbox will be GC'ed.
     let sandbox = new Cu.Sandbox(win, {
       wantXrays:        false,
       sandboxPrototype: win
     });
 
     let self = this;
     function callback(val) {
       // Set popup blocker permission to original value.
       try {
-        pm.add(origin, "popup", oldPerm);
+        pm.addFromPrincipal(principal, "popup", oldPerm);
       } catch(e) {
         this._log.warn("Setting popup blocking to original value failed " + e);
       }
 
       if (val) {
         self._log.info("_getAssertionWithLogin succeeded");
         try {
           cb(null, val);
--- a/toolkit/components/telemetry/TelemetryHistograms.h
+++ b/toolkit/components/telemetry/TelemetryHistograms.h
@@ -27,16 +27,17 @@
 /**
  * a11y telemetry
  */
 HISTOGRAM_FLAG(A11Y_INSTANTIATED_FLAG, "has accessibility support been instantiated")
 HISTOGRAM_ENUMERATED_VALUES(A11Y_CONSUMERS, 11, "Accessibility client by enum id")
 HISTOGRAM_FLAG(A11Y_ISIMPLEDOM_USAGE_FLAG, "have the ISimpleDOM* accessibility interfaces been used")
 HISTOGRAM_FLAG(A11Y_IATABLE_USAGE_FLAG, "has the IAccessibleTable accessibility interface been used")
 HISTOGRAM_FLAG(A11Y_XFORMS_USAGE_FLAG, "has XForms accessibility been instantiated")
+HISTOGRAM(A11Y_UPDATE_TIME, 1, 10000, 50, EXPONENTIAL, "time spent updating accessibility (ms)")
 
 /**
  * Cycle collector telemetry
  */
 HISTOGRAM(CYCLE_COLLECTOR, 1, 10000, 50, EXPONENTIAL, "Time spent on one cycle collection (ms)")
 HISTOGRAM(CYCLE_COLLECTOR_VISITED_REF_COUNTED, 1, 300000, 50, EXPONENTIAL, "Number of ref counted objects visited by the cycle collector")
 HISTOGRAM(CYCLE_COLLECTOR_VISITED_GCED, 1, 300000, 50, EXPONENTIAL, "Number of JS objects visited by the cycle collector")
 HISTOGRAM(CYCLE_COLLECTOR_COLLECTED, 1, 100000, 50, EXPONENTIAL, "Number of objects collected by the cycle collector")
--- a/toolkit/content/contentAreaUtils.js
+++ b/toolkit/content/contentAreaUtils.js
@@ -1,9 +1,9 @@
-# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 
+# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 
 # 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/.
 
 var ContentAreaUtils = {
   get ioService() {
     delete this.ioService;
     return this.ioService =
@@ -426,17 +426,17 @@ function internalPersist(persistArgs)
                     targetFileURL);
   }
 }
 
 /**
  * Structure for holding info about automatically supplied parameters for
  * internalSave(...). This allows parameters to be supplied so the user does not
  * need to be prompted for file info.
- * @param aFileAutoChosen This is an nsILocalFile object that has been
+ * @param aFileAutoChosen This is an nsIFile object that has been
  *        pre-determined as the filename for the target to save to
  * @param aUriAutoChosen  This is the nsIURI object for the target
  */
 function AutoChosen(aFileAutoChosen, aUriAutoChosen) {
   this.file = aFileAutoChosen;
   this.uri  = aUriAutoChosen;
 }
 
@@ -520,23 +520,23 @@ function initFileInfo(aFI, aURL, aURLCha
  *        An nsIURI associated with the download. The last used
  *        directory of the picker is retrieved from/stored in the 
  *        Content Pref Service using this URI.
  * @return true if the user confirmed a filename in the picker or the picker
  *         was not displayed; false if they dismissed the picker.
  */
 function getTargetFile(aFpP, /* optional */ aSkipPrompt, /* optional */ aRelatedURI)
 {
-  if (!getTargetFile.gDownloadLastDir)
-    Components.utils.import("resource://gre/modules/DownloadLastDir.jsm", getTargetFile);
-  var gDownloadLastDir = getTargetFile.gDownloadLastDir;
+  let downloadModule = {};
+  Components.utils.import("resource://gre/modules/DownloadLastDir.jsm", downloadModule);
+  var gDownloadLastDir = new downloadModule.DownloadLastDir(window);
 
   var prefs = getPrefsBrowserDownload("browser.download.");
   var useDownloadDir = prefs.getBoolPref("useDownloadDir");
-  const nsILocalFile = Components.interfaces.nsILocalFile;
+  const nsIFile = Components.interfaces.nsIFile;
 
   if (!aSkipPrompt)
     useDownloadDir = false;
 
   // Default to the user's default downloads directory configured
   // through download prefs.
   var dlMgr = Components.classes["@mozilla.org/download-manager;1"]
                         .getService(Components.interfaces.nsIDownloadManager);
@@ -563,17 +563,17 @@ function getTargetFile(aFpP, /* optional
       dirExists = true;
     }
   } catch(e) {}
 
   if (!dirExists) {
     // Default to desktop.
     var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
                                 .getService(Components.interfaces.nsIProperties);
-    dir = fileLocator.get("Desk", nsILocalFile);
+    dir = fileLocator.get("Desk", nsIFile);
   }
 
   var fp = makeFilePicker();
   var titleKey = aFpP.fpTitleKey || "SaveLinkTitle";
   fp.init(window, ContentAreaUtils.stringBundle.GetStringFromName(titleKey),
           Components.interfaces.nsIFilePicker.modeSave);
 
   fp.displayDirectory = dir;
@@ -595,21 +595,21 @@ function getTargetFile(aFpP, /* optional
 
   if (fp.show() == Components.interfaces.nsIFilePicker.returnCancel || !fp.file)
     return false;
 
   if (aFpP.saveMode != SAVEMODE_FILEONLY)
     prefs.setIntPref("save_converter_index", fp.filterIndex);
 
   // Do not store the last save directory as a pref inside the private browsing mode
-  var directory = fp.file.parent.QueryInterface(nsILocalFile);
+  var directory = fp.file.parent.QueryInterface(nsIFile);
   gDownloadLastDir.setFile(aRelatedURI, directory);
 
   fp.file.leafName = validateFileName(fp.file.leafName);
-  
+
   aFpP.saveAsType = fp.filterIndex;
   aFpP.file = fp.file;
   aFpP.fileURL = fp.fileURL;
   return true;
 }
 
 // Since we're automatically downloading, we don't get the file picker's
 // logic to check for existing files, so we need to do that here.
deleted file mode 100644
--- a/toolkit/content/tests/unit/test_privatebrowsing_downloadLastDir_c.js
+++ /dev/null
@@ -1,130 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 Cc = Components.classes;
-
-function loadUtilsScript() {
-  let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
-               getService(Ci.mozIJSSubScriptLoader);
-  loader.loadSubScript("chrome://global/content/contentAreaUtils.js");
-  Components.utils.import("resource://gre/modules/DownloadLastDir.jsm");
-}
-
-do_get_profile();
-
-let window = {};
-function run_test()
-{
-  let pb;
-  try {
-    pb = Cc["@mozilla.org/privatebrowsing;1"].
-         getService(Ci.nsIPrivateBrowsingService);
-  } catch (e) {
-    print("PB service is not available, bail out");
-    return;
-  }
-
-  loadUtilsScript();
-
-  let prefsService = Cc["@mozilla.org/preferences-service;1"].
-                     getService(Ci.nsIPrefService).
-                     QueryInterface(Ci.nsIPrefBranch);
-  prefsService.setBoolPref("browser.privatebrowsing.keep_current_session", true);
-  let prefs = prefsService.getBranch("browser.download.");
-  let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
-               getService(Ci.nsIProperties);
-  let tmpDir = dirSvc.get("TmpD", Ci.nsILocalFile);
-  function newDirectory() {
-    let dir = tmpDir.clone();
-    dir.append("testdir" + Math.floor(Math.random() * 10000));
-    dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0700);
-    return dir;
-  }
-  function newFileInDirectory(dir) {
-    let file = dir.clone();
-    file.append("testfile" + Math.floor(Math.random() * 10000));
-    file.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0600);
-    return file;
-  }
-  let dir1 = newDirectory();
-  let dir2 = newDirectory();
-  let dir3 = newDirectory();
-  let file1 = newFileInDirectory(dir1);
-  let file2 = newFileInDirectory(dir2);
-  let file3 = newFileInDirectory(dir3);
-
-  // overwrite makeFilePicker, as we don't want to create a real filepicker object
-  let fp = {
-    appendFilter: function() {},
-    appendFilters: function() {},
-    init: function() {},
-    show: function() Ci.nsIFilePicker.returnOK,
-    displayDirectory: null,
-    file: file1
-  };
-  makeFilePicker = function() fp;
-
-  // Overwrite stringBundle to return an object masquerading as a string bundle
-  delete ContentAreaUtils.stringBundle;
-  ContentAreaUtils.stringBundle = {
-    GetStringFromName: function() ""
-  };
-
-  // Overwrite validateFileName to validate everything
-  validateFileName = function(foo) foo;
-
-  let params = {
-    fpTitleKey: "test",
-    fileInfo: new FileInfo("test.txt", "test.txt", "test", "txt", "http://mozilla.org/test.txt"),
-    contentType: "text/plain",
-    saveMode: SAVEMODE_FILEONLY,
-    saveAsType: kSaveAsType_Complete,
-    file: null
-  };
-
-  prefs.setComplexValue("lastDir", Ci.nsILocalFile, tmpDir);
-
-  do_check_true(getTargetFile(params));
-  // file picker should start with browser.download.lastDir
-  do_check_eq(fp.displayDirectory.path, tmpDir.path);
-  // browser.download.lastDir should be modified before entering the private browsing mode
-  do_check_eq(prefs.getComplexValue("lastDir", Ci.nsILocalFile).path, dir1.path);
-  // gDownloadLastDir should be usable outside of the private browsing mode
-  do_check_eq(gDownloadLastDir.file.path, dir1.path);
-
-  pb.privateBrowsingEnabled = true;
-  do_check_eq(prefs.getComplexValue("lastDir", Ci.nsILocalFile).path, dir1.path);
-  fp.file = file2;
-  fp.displayDirectory = null;
-  do_check_true(getTargetFile(params));
-  // file picker should start with browser.download.lastDir as set before entering the private browsing mode
-  do_check_eq(fp.displayDirectory.path, dir1.path);
-  // browser.download.lastDir should not be modified inside the private browsing mode
-  do_check_eq(prefs.getComplexValue("lastDir", Ci.nsILocalFile).path, dir1.path);
-  // but gDownloadLastDir should be modified
-  do_check_eq(gDownloadLastDir.file.path, dir2.path);
-
-  pb.privateBrowsingEnabled = false;
-  // gDownloadLastDir should be cleared after leaving the private browsing mode
-  do_check_eq(gDownloadLastDir.file.path, dir1.path);
-  fp.file = file3;
-  fp.displayDirectory = null;
-  do_check_true(getTargetFile(params));
-  // file picker should start with browser.download.lastDir as set before entering the private browsing mode
-  do_check_eq(fp.displayDirectory.path, dir1.path);
-  // browser.download.lastDir should be modified after leaving the private browsing mode
-  do_check_eq(prefs.getComplexValue("lastDir", Ci.nsILocalFile).path, dir3.path);
-  // gDownloadLastDir should be usable after leaving the private browsing mode
-  do_check_eq(gDownloadLastDir.file.path, dir3.path);
-
-  // cleanup
-  Cc["@mozilla.org/observer-service;1"]
-    .getService(Ci.nsIObserverService)
-    .notifyObservers(null, "quit-application", null);
-
-  prefsService.clearUserPref("browser.privatebrowsing.keep_current_session");
-  [dir1, dir2, dir3].forEach(function(dir) dir.remove(true));
-}
--- a/toolkit/content/tests/unit/xpcshell.ini
+++ b/toolkit/content/tests/unit/xpcshell.ini
@@ -1,8 +1,7 @@
 [DEFAULT]
 head = 
 tail = 
 
 [test_contentAreaUtils.js]
 [test_dict.js]
-[test_privatebrowsing_downloadLastDir_c.js]
 [test_propertyListsUtils.js]
--- a/toolkit/mozapps/downloads/DownloadLastDir.jsm
+++ b/toolkit/mozapps/downloads/DownloadLastDir.jsm
@@ -1,8 +1,9 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 /*
  * The behavior implemented by gDownloadLastDir is documented here.
  *
  * In normal browsing sessions, gDownloadLastDir uses the browser.download.lastDir
@@ -20,114 +21,118 @@
  *
  * If passed a URI, the last used directory is also stored with that URI in the
  * content preferences database. This can be disabled by setting the pref
  * browser.download.lastDir.savePerSite to false.
  */
 
 const LAST_DIR_PREF = "browser.download.lastDir";
 const SAVE_PER_SITE_PREF = LAST_DIR_PREF + ".savePerSite";
-const PBSVC_CID = "@mozilla.org/privatebrowsing;1";
-const nsILocalFile = Components.interfaces.nsILocalFile;
+const nsIFile = Components.interfaces.nsIFile;
 
-var EXPORTED_SYMBOLS = [ "gDownloadLastDir" ];
+var EXPORTED_SYMBOLS = [ "DownloadLastDir" ];
 
 Components.utils.import("resource://gre/modules/Services.jsm");
-
-let pbSvc = null;
-if (PBSVC_CID in Components.classes) {
-  pbSvc = Components.classes[PBSVC_CID]
-                    .getService(Components.interfaces.nsIPrivateBrowsingService);
-}
+Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 let observer = {
   QueryInterface: function (aIID) {
     if (aIID.equals(Components.interfaces.nsIObserver) ||
         aIID.equals(Components.interfaces.nsISupports) ||
         aIID.equals(Components.interfaces.nsISupportsWeakReference))
       return this;
     throw Components.results.NS_NOINTERFACE;
   },
   observe: function (aSubject, aTopic, aData) {
     switch (aTopic) {
-      case "private-browsing":
-        if (aData == "enter")
-          gDownloadLastDirFile = readLastDirPref();
-        else if (aData == "exit") {
-          gDownloadLastDirFile = null;
-        }
+      case "last-pb-context-exited":
+        gDownloadLastDirFile = null;
         break;
       case "browser:purge-session-history":
         gDownloadLastDirFile = null;
         if (Services.prefs.prefHasUserValue(LAST_DIR_PREF))
           Services.prefs.clearUserPref(LAST_DIR_PREF);
         Services.contentPrefs.removePrefsByName(LAST_DIR_PREF);
         break;
     }
   }
 };
 
 let os = Components.classes["@mozilla.org/observer-service;1"]
                    .getService(Components.interfaces.nsIObserverService);
-os.addObserver(observer, "private-browsing", true);
+os.addObserver(observer, "last-pb-context-exited", true);
 os.addObserver(observer, "browser:purge-session-history", true);
 
 function readLastDirPref() {
   try {
-    return Services.prefs.getComplexValue(LAST_DIR_PREF, nsILocalFile);
+    return Services.prefs.getComplexValue(LAST_DIR_PREF, nsIFile);
   }
   catch (e) {
     return null;
   }
 }
 
 function isContentPrefEnabled() {
   try {
     return Services.prefs.getBoolPref(SAVE_PER_SITE_PREF);
-  } 
+  }
   catch (e) {
     return true;
   }
 }
 
 let gDownloadLastDirFile = readLastDirPref();
-let gDownloadLastDir = {
+
+function DownloadLastDir(aWindow) {
+  this.window = aWindow;
+}
+
+DownloadLastDir.prototype = {
+  isPrivate: function DownloadLastDir_isPrivate() {
+    return PrivateBrowsingUtils.isWindowPrivate(this.window);
+  },
   // compat shims
   get file() { return this.getFile(); },
   set file(val) { this.setFile(null, val); },
+  cleanupPrivateFile: function () {
+    gDownloadLastDirFile = null;
+  },
   getFile: function (aURI) {
     if (aURI && isContentPrefEnabled()) {
       let lastDir = Services.contentPrefs.getPref(aURI, LAST_DIR_PREF);
       if (lastDir) {
         var lastDirFile = Components.classes["@mozilla.org/file/local;1"]
-                                    .createInstance(Components.interfaces.nsILocalFile);
+                                    .createInstance(Components.interfaces.nsIFile);
         lastDirFile.initWithPath(lastDir);
         return lastDirFile;
       }
     }
     if (gDownloadLastDirFile && !gDownloadLastDirFile.exists())
       gDownloadLastDirFile = null;
 
-    if (pbSvc && pbSvc.privateBrowsingEnabled)
+    if (this.isPrivate()) {
+      if (!gDownloadLastDirFile)
+        gDownloadLastDirFile = readLastDirPref();
       return gDownloadLastDirFile;
+    }
     else
       return readLastDirPref();
   },
   setFile: function (aURI, aFile) {
     if (aURI && isContentPrefEnabled()) {
       if (aFile instanceof Components.interfaces.nsIFile)
         Services.contentPrefs.setPref(aURI, LAST_DIR_PREF, aFile.path);
       else
         Services.contentPrefs.removePref(aURI, LAST_DIR_PREF);
     }
-    if (pbSvc && pbSvc.privateBrowsingEnabled) {
+    if (this.isPrivate()) {
       if (aFile instanceof Components.interfaces.nsIFile)
         gDownloadLastDirFile = aFile.clone();
       else
         gDownloadLastDirFile = null;
     } else {
       if (aFile instanceof Components.interfaces.nsIFile)
-        Services.prefs.setComplexValue(LAST_DIR_PREF, nsILocalFile, aFile);
+        Services.prefs.setComplexValue(LAST_DIR_PREF, nsIFile, aFile);
       else if (Services.prefs.prefHasUserValue(LAST_DIR_PREF))
         Services.prefs.clearUserPref(LAST_DIR_PREF);
     }
   }
 };
--- a/toolkit/mozapps/downloads/nsHelperAppDlg.js
+++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /*
 # 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/.
 */
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -92,18 +92,19 @@ nsUnknownContentTypeDialogProgressListen
  *
  * In addition, this file implements an nsIModule object that registers the
  * nsUnknownContentTypeDialog component.
  */
 
 const PREF_BD_USEDOWNLOADDIR = "browser.download.useDownloadDir";
 const nsITimer = Components.interfaces.nsITimer;
 
+let downloadModule = {};
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-Components.utils.import("resource://gre/modules/DownloadLastDir.jsm");
+Components.utils.import("resource://gre/modules/DownloadLastDir.jsm", downloadModule);
 Components.utils.import("resource://gre/modules/DownloadPaths.jsm");
 Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
 
 /* ctor
  */
 function nsUnknownContentTypeDialog() {
   // Initialize data properties.
   this.mLauncher = null;
@@ -240,16 +241,18 @@ nsUnknownContentTypeDialog.prototype = {
     // Use file picker to show dialog.
     var nsIFilePicker = Components.interfaces.nsIFilePicker;
     var picker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
     var windowTitle = bundle.GetStringFromName("saveDialogTitle");
     var parent = aContext.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow);
     picker.init(parent, windowTitle, nsIFilePicker.modeSave);
     picker.defaultString = aDefaultFile;
 
+    let gDownloadLastDir = new downloadModule.DownloadLastDir(parent);
+
     if (aSuggestedFileExtension) {
       // aSuggestedFileExtension includes the period, so strip it
       picker.defaultExtension = aSuggestedFileExtension.substring(1);
     }
     else {
       try {
         picker.defaultExtension = this.mLauncher.MIMEInfo.primaryExtension;
       }
deleted file mode 100644
--- a/toolkit/mozapps/downloads/tests/unit/test_DownloadLastDir.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/* 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/. */
-
-function run_test()
-{
-  let Cc = Components.classes;
-  let Ci = Components.interfaces;
-  let Cu = Components.utils;
-  do_get_profile();
-  Cu.import("resource://gre/modules/DownloadLastDir.jsm");
-
-  function clearHistory() {
-    // simulate clearing the private data
-    Cc["@mozilla.org/observer-service;1"].
-    getService(Ci.nsIObserverService).
-    notifyObservers(null, "browser:purge-session-history", "");
-  }
-
-  do_check_eq(typeof gDownloadLastDir, "object");
-  do_check_eq(gDownloadLastDir.file, null);
-
-  let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
-               getService(Ci.nsIProperties);
-  let tmpDir = dirSvc.get("TmpD", Ci.nsILocalFile);
-  let newDir = tmpDir.clone();
-  newDir.append("testdir" + Math.floor(Math.random() * 10000));
-  newDir.QueryInterface(Ci.nsILocalFile);
-  newDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0700);
-
-  gDownloadLastDir.file = tmpDir;
-  do_check_eq(gDownloadLastDir.file.path, tmpDir.path);
-  do_check_neq(gDownloadLastDir.file, tmpDir);
-
-  gDownloadLastDir.file = 1; // not an nsIFile
-  do_check_eq(gDownloadLastDir.file, null);
-  gDownloadLastDir.file = tmpDir;
-
-  clearHistory();
-  do_check_eq(gDownloadLastDir.file, null);
-  gDownloadLastDir.file = tmpDir;
-
-  let pb;
-  try {
-    pb = Cc["@mozilla.org/privatebrowsing;1"].
-         getService(Ci.nsIPrivateBrowsingService);
-  } catch (e) {
-    print("PB service is not available, bail out");
-    return;
-  }
-
-  let prefs = Cc["@mozilla.org/preferences-service;1"].
-              getService(Ci.nsIPrefBranch);
-  prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
-
-  pb.privateBrowsingEnabled = true;
-  do_check_eq(gDownloadLastDir.file.path, tmpDir.path);
-  do_check_neq(gDownloadLastDir.file, tmpDir);
-
-  pb.privateBrowsingEnabled = false;
-  do_check_eq(gDownloadLastDir.file.path, tmpDir.path);
-  pb.privateBrowsingEnabled = true;
-
-  gDownloadLastDir.file = newDir;
-  do_check_eq(gDownloadLastDir.file.path, newDir.path);
-  do_check_neq(gDownloadLastDir.file, newDir);
-
-  pb.privateBrowsingEnabled = false;
-  do_check_eq(gDownloadLastDir.file.path, tmpDir.path);
-  do_check_neq(gDownloadLastDir.file, tmpDir);
-
-  pb.privateBrowsingEnabled = true;
-  do_check_neq(gDownloadLastDir.file, null);
-  clearHistory();
-  do_check_eq(gDownloadLastDir.file, null);
-
-  pb.privateBrowsingEnabled = false;
-  do_check_eq(gDownloadLastDir.file, null);
-
-  prefs.clearUserPref("browser.privatebrowsing.keep_current_session");
-  newDir.remove(true);
-}
deleted file mode 100644
--- a/toolkit/mozapps/downloads/tests/unit/test_DownloadLastDirWithCPS.js
+++ /dev/null
@@ -1,228 +0,0 @@
-/* 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 Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/DownloadLastDir.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-do_get_profile();
-
-function run_test() {
-  function clearHistory() {
-    // simulate clearing the private data
-    Services.obs.notifyObservers(null, "browser:purge-session-history", "");
-  }
-
-  do_check_eq(typeof gDownloadLastDir, "object");
-  do_check_eq(gDownloadLastDir.file, null);
-  
-  let tmpDir = Services.dirsvc.get("TmpD", Ci.nsILocalFile);
-  
-  let uri1 = Services.io.newURI("http://test1.com/", null, null);
-  let uri2 = Services.io.newURI("http://test2.com/", null, null);
-  let uri3 = Services.io.newURI("http://test3.com/", null, null);
-  let uri4 = Services.io.newURI("http://test4.com/", null, null);
-
-  function newDir() {
-    let dir = tmpDir.clone();
-    dir.append("testdir" + Math.floor(Math.random() * 10000));
-    dir.QueryInterface(Ci.nsILocalFile);
-    dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0700);
-    return dir;
-  }
-  
-  let dir1 = newDir();
-  let dir2 = newDir();
-  let dir3 = newDir();
-
-  try {
-    { // set up last dir
-      gDownloadLastDir.setFile(null, tmpDir);
-      do_check_eq(gDownloadLastDir.file.path, tmpDir.path);
-      do_check_neq(gDownloadLastDir.file, tmpDir);
-    }
-
-    { // set uri1 to dir1, all should now return dir1
-      // also check that a new object is returned
-      gDownloadLastDir.setFile(uri1, dir1);
-      do_check_eq(gDownloadLastDir.file.path, dir1.path);
-      do_check_neq(gDownloadLastDir.file, dir1);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir1.path); // set in CPS
-      do_check_neq(gDownloadLastDir.getFile(uri1), dir1);
-      do_check_eq(gDownloadLastDir.getFile(uri2).path, dir1.path); // fallback
-      do_check_neq(gDownloadLastDir.getFile(uri2), dir1);
-      do_check_eq(gDownloadLastDir.getFile(uri3).path, dir1.path); // fallback
-      do_check_neq(gDownloadLastDir.getFile(uri3), dir1);
-      do_check_eq(gDownloadLastDir.getFile(uri4).path, dir1.path); // fallback
-      do_check_neq(gDownloadLastDir.getFile(uri4), dir1);
-    }
-
-    { // set uri2 to dir2, all except uri1 should now return dir2
-      gDownloadLastDir.setFile(uri2, dir2);
-      do_check_eq(gDownloadLastDir.file.path, dir2.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir1.path); // set in CPS
-      do_check_eq(gDownloadLastDir.getFile(uri2).path, dir2.path); // set in CPS
-      do_check_eq(gDownloadLastDir.getFile(uri3).path, dir2.path); // fallback
-      do_check_eq(gDownloadLastDir.getFile(uri4).path, dir2.path); // fallback
-    }
-
-    { // set uri3 to dir3, all except uri1 and uri2 should now return dir3
-      gDownloadLastDir.setFile(uri3, dir3);
-      do_check_eq(gDownloadLastDir.file.path, dir3.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir1.path); // set in CPS
-      do_check_eq(gDownloadLastDir.getFile(uri2).path, dir2.path); // set in CPS
-      do_check_eq(gDownloadLastDir.getFile(uri3).path, dir3.path); // set in CPS
-      do_check_eq(gDownloadLastDir.getFile(uri4).path, dir3.path); // fallback
-    }
-
-    { // set uri1 to dir2, all except uri3 should now return dir2
-      gDownloadLastDir.setFile(uri1, dir2);
-      do_check_eq(gDownloadLastDir.file.path, dir2.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir2.path); // set in CPS
-      do_check_eq(gDownloadLastDir.getFile(uri2).path, dir2.path); // set in CPS
-      do_check_eq(gDownloadLastDir.getFile(uri3).path, dir3.path); // set in CPS
-      do_check_eq(gDownloadLastDir.getFile(uri4).path, dir2.path); // fallback
-    }
-
-    { // check clearHistory removes all data
-      clearHistory();
-      do_check_eq(gDownloadLastDir.file, null);
-      do_check_eq(Services.contentPrefs.hasPref(uri1, "browser.download.lastDir"), false);
-      do_check_eq(gDownloadLastDir.getFile(uri1), null);
-      do_check_eq(gDownloadLastDir.getFile(uri2), null);
-      do_check_eq(gDownloadLastDir.getFile(uri3), null);
-      do_check_eq(gDownloadLastDir.getFile(uri4), null);
-    }
-
-    let pb;
-    try {
-      pb = Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIPrivateBrowsingService);
-    } catch (e) {
-      print("PB service is not available, bail out");
-      return;
-    }
-
-    Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
-    
-    { // check data set outside PB mode is remembered
-      gDownloadLastDir.setFile(null, tmpDir);
-      pb.privateBrowsingEnabled = true;
-      do_check_eq(gDownloadLastDir.file.path, tmpDir.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, tmpDir.path);
-
-      pb.privateBrowsingEnabled = false;
-      do_check_eq(gDownloadLastDir.file.path, tmpDir.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, tmpDir.path);
-      
-      clearHistory();
-    }
-
-    { // check data set using CPS outside PB mode is remembered
-      gDownloadLastDir.setFile(uri1, dir1);
-      pb.privateBrowsingEnabled = true;
-      do_check_eq(gDownloadLastDir.file.path, dir1.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir1.path);
-
-      pb.privateBrowsingEnabled = false;
-      do_check_eq(gDownloadLastDir.file.path, dir1.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir1.path);
-
-      clearHistory();
-    }
-    
-    { // check data set inside PB mode is forgotten
-      pb.privateBrowsingEnabled = true;
-      gDownloadLastDir.setFile(null, tmpDir);
-      do_check_eq(gDownloadLastDir.file.path, tmpDir.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, tmpDir.path);
-
-      pb.privateBrowsingEnabled = false;
-      do_check_eq(gDownloadLastDir.file, null);
-      do_check_eq(gDownloadLastDir.getFile(uri1), null);
-      
-      clearHistory();
-    }
-    
-    { // check data set using CPS inside PB mode is forgotten
-      pb.privateBrowsingEnabled = true;
-      gDownloadLastDir.setFile(uri1, dir1);
-      do_check_eq(gDownloadLastDir.file.path, dir1.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir1.path);
-
-      pb.privateBrowsingEnabled = false;
-      do_check_eq(gDownloadLastDir.file, null);
-      do_check_eq(gDownloadLastDir.getFile(uri1), null);
-
-      clearHistory();
-    }
-
-    { // check data set outside PB mode but changed inside is remembered correctly
-      gDownloadLastDir.setFile(uri1, dir1);
-      pb.privateBrowsingEnabled = true;
-      gDownloadLastDir.setFile(uri1, dir2);
-      do_check_eq(gDownloadLastDir.file.path, dir2.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir2.path);
-
-      pb.privateBrowsingEnabled = false;
-      do_check_eq(gDownloadLastDir.file.path, dir1.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir1.path);
-
-      // check that the last dir store got cleared
-      pb.privateBrowsingEnabled = true;
-      do_check_eq(gDownloadLastDir.file.path, dir1.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir1.path);
-      
-      pb.privateBrowsingEnabled = false;
-      clearHistory();
-    }
-    
-    { // check clearHistory inside PB mode clears data outside PB mode
-      pb.privateBrowsingEnabled = true;
-      gDownloadLastDir.setFile(uri1, dir2);
-
-      clearHistory();
-      do_check_eq(gDownloadLastDir.file, null);
-      do_check_eq(gDownloadLastDir.getFile(uri1), null);
-
-      pb.privateBrowsingEnabled = false;
-      do_check_eq(gDownloadLastDir.file, null);
-      do_check_eq(gDownloadLastDir.getFile(uri1), null);
-    }
-
-    { // check that disabling CPS works
-      Services.prefs.setBoolPref("browser.download.lastDir.savePerSite", false);
-
-      gDownloadLastDir.setFile(uri1, dir1);
-      do_check_eq(gDownloadLastDir.file.path, dir1.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir1.path);
-      do_check_eq(gDownloadLastDir.getFile(uri2).path, dir1.path);
-      do_check_eq(gDownloadLastDir.getFile(uri3).path, dir1.path);
-      do_check_eq(gDownloadLastDir.getFile(uri4).path, dir1.path);
-
-      gDownloadLastDir.setFile(uri2, dir2);
-      do_check_eq(gDownloadLastDir.file.path, dir2.path);
-      do_check_eq(gDownloadLastDir.getFile(uri1).path, dir2.path);
-      do_check_eq(gDownloadLastDir.getFile(uri2).path, dir2.path);
-      do_check_eq(gDownloadLastDir.getFile(uri3).path, dir2.path);
-      do_check_eq(gDownloadLastDir.getFile(uri4).path, dir2.path);
-
-      Services.prefs.clearUserPref("browser.download.lastDir.savePerSite");
-    }
-
-    { // check that passing null to setFile clears the stored value
-      gDownloadLastDir.setFile(uri3, dir3);
-      do_check_eq(gDownloadLastDir.getFile(uri3).path, dir3.path);
-      gDownloadLastDir.setFile(uri3, null);
-      do_check_eq(gDownloadLastDir.getFile(uri3), null);
-    }
-  } finally {
-    dir1.remove(true);
-    dir2.remove(true);
-    dir3.remove(true);
-    Services.prefs.clearUserPref("browser.download.lastDir.savePerSite");
-  }
-}
deleted file mode 100644
--- a/toolkit/mozapps/downloads/tests/unit/test_privatebrowsing_downloadLastDir.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 Cc = Components.classes;
-const Cu = Components.utils;
-const Cr = Components.results;
-
-do_get_profile();
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/DownloadLastDir.jsm");
-
-let context = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor]),
-  getInterface: XPCOMUtils.generateQI([Ci.nsIDOMWindow])
-};
-
-let launcher = {
-  source: Services.io.newURI("http://test1.com/file", null, null)
-};
-
-Cu.import("resource://test/MockFilePicker.jsm");
-MockFilePicker.init();
-MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
-
-function run_test()
-{
-  let pb;
-  try {
-    pb = Cc["@mozilla.org/privatebrowsing;1"].
-         getService(Ci.nsIPrivateBrowsingService);
-  } catch (e) {
-    print("PB service is not available, bail out");
-    return;
-  }
-
-  let prefsService = Cc["@mozilla.org/preferences-service;1"].
-                     getService(Ci.nsIPrefService).
-                     QueryInterface(Ci.nsIPrefBranch);
-  prefsService.setBoolPref("browser.privatebrowsing.keep_current_session", true);
-  let prefs = prefsService.getBranch("browser.download.");
-  let launcherDialog = Cc["@mozilla.org/helperapplauncherdialog;1"].
-                       getService(Ci.nsIHelperAppLauncherDialog);
-  let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
-               getService(Ci.nsIProperties);
-  let tmpDir = dirSvc.get("TmpD", Ci.nsILocalFile);
-  function newDirectory() {
-    let dir = tmpDir.clone();
-    dir.append("testdir" + Math.floor(Math.random() * 10000));
-    dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0700);
-    return dir;
-  }
-  function newFileInDirectory(dir) {
-    let file = dir.clone();
-    file.append("testfile" + Math.floor(Math.random() * 10000));
-    file.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0600);
-    return file;
-  }
-  let dir1 = newDirectory();
-  let dir2 = newDirectory();
-  let dir3 = newDirectory();
-  let file1 = newFileInDirectory(dir1);
-  let file2 = newFileInDirectory(dir2);
-  let file3 = newFileInDirectory(dir3);
-
-  prefs.setComplexValue("lastDir", Ci.nsILocalFile, tmpDir);
-
-  MockFilePicker.returnFiles = [file1];
-  let file = launcherDialog.promptForSaveToFile(launcher, context, null, null, null);
-  do_check_true(!!file);
-  // file picker should start with browser.download.lastDir
-  do_check_eq(MockFilePicker.displayDirectory.path, tmpDir.path);
-  // browser.download.lastDir should be modified before entering the private browsing mode
-  do_check_eq(prefs.getComplexValue("lastDir", Ci.nsILocalFile).path, dir1.path);
-  // gDownloadLastDir should be usable outside of the private browsing mode
-  do_check_eq(gDownloadLastDir.file.path, dir1.path);
-
-  pb.privateBrowsingEnabled = true;
-  do_check_eq(prefs.getComplexValue("lastDir", Ci.nsILocalFile).path, dir1.path);
-  MockFilePicker.returnFiles = [file2];
-  MockFilePicker.displayDirectory = null;
-  file = launcherDialog.promptForSaveToFile(launcher, context, null, null, null);
-  do_check_true(!!file);
-  // file picker should start with browser.download.lastDir as set before entering the private browsing mode
-  do_check_eq(MockFilePicker.displayDirectory.path, dir1.path);
-  // browser.download.lastDir should not be modified inside the private browsing mode
-  do_check_eq(prefs.getComplexValue("lastDir", Ci.nsILocalFile).path, dir1.path);
-  // but gDownloadLastDir should be modified
-  do_check_eq(gDownloadLastDir.file.path, dir2.path);
-
-  pb.privateBrowsingEnabled = false;
-  // gDownloadLastDir should be cleared after leaving the private browsing mode
-  do_check_eq(gDownloadLastDir.file.path, dir1.path);
-  MockFilePicker.returnFiles = [file3];
-  MockFilePicker.displayDirectory = null;
-  file = launcherDialog.promptForSaveToFile(launcher, context, null, null, null);
-  do_check_true(!!file);
-  // file picker should start with browser.download.lastDir as set before entering the private browsing mode
-  do_check_eq(MockFilePicker.displayDirectory.path, dir1.path);
-  // browser.download.lastDir should be modified after leaving the private browsing mode
-  do_check_eq(prefs.getComplexValue("lastDir", Ci.nsILocalFile).path, dir3.path);
-  // gDownloadLastDir should be usable after leaving the private browsing mode
-  do_check_eq(gDownloadLastDir.file.path, dir3.path);
-
-  // cleanup
-  prefsService.clearUserPref("browser.privatebrowsing.keep_current_session");
-  [dir1, dir2, dir3].forEach(function(dir) dir.remove(true));
-
-  MockFilePicker.cleanup();
-}
--- a/toolkit/mozapps/downloads/tests/unit/xpcshell.ini
+++ b/toolkit/mozapps/downloads/tests/unit/xpcshell.ini
@@ -1,12 +1,9 @@
 [DEFAULT]
 head = head_downloads.js
 tail = 
 
-[test_DownloadLastDir.js]
-[test_DownloadLastDirWithCPS.js]
 [test_DownloadPaths.js]
 [test_DownloadUtils.js]
 [test_lowMinutes.js]
-[test_privatebrowsing_downloadLastDir.js]
 [test_syncedDownloadUtils.js]
 [test_unspecified_arguments.js]