merge m-c into fig
authorMargaret Leibovic <margaret.leibovic@gmail.com>
Wed, 17 Jul 2013 13:50:36 -0700
changeset 156317 4e944265f5b8d39d08424b3f3a17bf23800439eb
parent 156316 101158e5e30274d58997270037b3c7c5a6dbe4c7 (current diff)
parent 151125 604c8518cc50031fb0600aeb0e26e9e21438ffb0 (diff)
child 156318 c2cab1e6f266918e391c886f9a95de033779bb79
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone25.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 m-c into fig
addon-sdk/source/doc/module-source/sdk/page-mod/match-pattern.md
addon-sdk/source/doc/static-files/media/xul-migration-cs.png
browser/metro/base/content/aboutPanel.js
browser/metro/base/content/bindings/autocomplete.xml
browser/metro/base/content/preferences.js
browser/metro/base/content/sync.js
browser/metro/theme/forms.css
build/stlport/stl/config/_android.h.in
build/xpccheck.py
config/makefiles/test/check-export-targets.mk
config/purge_directories.py
dom/future/Future.cpp
dom/future/Future.h
dom/future/FutureCallback.cpp
dom/future/FutureCallback.h
dom/future/FutureResolver.cpp
dom/future/FutureResolver.h
dom/future/Makefile.in
dom/future/moz.build
dom/future/tests/Makefile.in
dom/future/tests/moz.build
dom/future/tests/test_bug883683.html
dom/future/tests/test_future.html
dom/future/tests/test_resolve.html
dom/indexedDB/nsIIDBVersionChangeEvent.idl
dom/interfaces/settings/nsIDOMSettingsManager.idl
dom/network/tests/marionette/test_mobile_iccinfo.js
dom/telephony/TelephonyFactory.h
dom/webidl/Future.webidl
js/src/frontend/SharedContext-inl.h
js/src/ion/FixedArityList.h
layout/style/nsStyleStructList.h
mobile/android/base/AnimatedHeightLayout.java
mobile/android/base/BrowserApp.java
mobile/android/base/BrowserToolbar.java
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mobile/android/base/PageActionLayout.java
mobile/android/base/SearchEngineRow.java
mobile/android/base/Tab.java
mobile/android/base/Tabs.java
mobile/android/base/db/BrowserDB.java
mobile/android/base/db/LocalBrowserDB.java
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/resources/layout-large-v11/browser_toolbar.xml
mobile/android/base/resources/layout/browser_toolbar.xml
mobile/android/base/resources/layout/gecko_app.xml
mobile/android/base/resources/layout/home_search_item_row.xml
mobile/android/base/resources/layout/search_engine_row.xml
mobile/android/base/resources/layout/suggestion_item.xml
mobile/android/base/resources/values/dimens.xml
mobile/android/base/resources/values/styles.xml
mobile/android/base/resources/xml/preferences_customize.xml
mobile/android/base/strings.xml.in
mobile/android/base/tests/testAllPagesTab.java.in
mobile/android/base/tests/testBookmark.java.in
toolkit/mozapps/update/test/unit/xpcshell_updater_windows.ini
toolkit/mozapps/update/test/unit/xpcshell_updater_xp_unix.ini
--- a/.hgignore
+++ b/.hgignore
@@ -42,16 +42,19 @@
 # SVN directories
 \.svn/
 
 # Ignore the files and directory that Eclipse IDE creates
 \.project$
 \.cproject$
 \.settings/
 
+# Ignore the directory that JetBrains IDEs create
+\.idea/
+
 # Python stuff installed at build time.
 ^python/psutil/.*\.so
 ^python/psutil/.*\.pyd
 ^python/psutil/build/
 
 # Git repositories
 .git/
 
--- a/CLOBBER
+++ b/CLOBBER
@@ -12,9 +12,10 @@
 #          O               O
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
-Bug 887463 - Remove webvtt parser.
+Bug 889503 - Move Settings API to WebIDL.
+Requires a clobber due to Bug 890744.
--- a/Makefile.in
+++ b/Makefile.in
@@ -55,17 +55,17 @@ ifndef MOZ_PROFILE_USE
 # a specific subdirectory of the object directory. The invoked Python
 # script simply iterates over all the manifests, purging files as
 # necessary. To manage new directories or add files to the manifests,
 # modify the backend generator.
 #
 # We need to explicitly put backend.RecursiveMakeBackend.built here
 # otherwise the rule in rules.mk doesn't run early enough.
 default alldep all:: CLOBBER $(topsrcdir)/configure config.status backend.RecursiveMakeBackend.built
-	$(PYTHON) $(topsrcdir)/config/purge_directories.py -d _build_manifests/purge .
+	$(call py_action,purge_manifests,-d _build_manifests/purge .)
 endif
 
 CLOBBER: $(topsrcdir)/CLOBBER
 	@echo "STOP!  The CLOBBER file has changed."
 	@echo "Please run the build through a sanctioned build wrapper, such as"
 	@echo "'mach build' or client.mk."
 	@exit 1
 
--- a/accessible/src/atk/Makefile.in
+++ b/accessible/src/atk/Makefile.in
@@ -7,19 +7,16 @@ topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 EXPORT_LIBRARY = ..
 LIBXUL_LIBRARY = 1
 
-# we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
 include $(topsrcdir)/config/rules.mk
 
 ifdef MOZ_ENABLE_GTK
 CFLAGS      += $(TK_CFLAGS)
 CXXFLAGS    += $(TK_CFLAGS)
 endif
 
 ifdef MOZ_ENABLE_DBUS
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -6,19 +6,16 @@ DEPTH = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBXUL_LIBRARY = 1
 
-# we don't want the shared lib, but we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../generic \
   -I$(srcdir)/../html \
   -I$(srcdir)/../xpcom \
   -I$(srcdir)/../xul \
--- a/accessible/src/base/nsAccessiblePivot.cpp
+++ b/accessible/src/base/nsAccessiblePivot.cpp
@@ -411,37 +411,60 @@ nsAccessiblePivot::MovePivotInternal(Acc
   mPosition = aPosition;
   int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
   mStartOffset = mEndOffset = -1;
 
   return NotifyOfPivotChange(oldPosition, oldStart, oldEnd, aReason);
 }
 
 Accessible*
+nsAccessiblePivot::AdjustStartPosition(Accessible* aAccessible,
+                                       RuleCache& aCache,
+                                       uint16_t* aFilterResult,
+                                       nsresult* aResult)
+{
+  Accessible* matched = aAccessible;
+  *aResult = aCache.ApplyFilter(aAccessible, aFilterResult);
+
+  if (aAccessible != mRoot && aAccessible != mModalRoot) {
+    for (Accessible* temp = aAccessible->Parent();
+         temp && temp != mRoot && temp != mModalRoot; temp = temp->Parent()) {
+      uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE;
+      *aResult = aCache.ApplyFilter(temp, &filtered);
+      NS_ENSURE_SUCCESS(*aResult, nullptr);
+      if (filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) {
+        *aFilterResult = filtered;
+        matched = temp;
+      }
+    }
+  }
+
+  return matched;
+}
+
+Accessible*
 nsAccessiblePivot::SearchBackward(Accessible* aAccessible,
                                   nsIAccessibleTraversalRule* aRule,
                                   bool aSearchCurrent,
                                   nsresult* aResult)
 {
   *aResult = NS_OK;
 
   // Initial position could be unset, in that case return null.
   if (!aAccessible)
     return nullptr;
 
   RuleCache cache(aRule);
-  Accessible* accessible = aAccessible;
-
   uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE;
+  Accessible* accessible = AdjustStartPosition(aAccessible, cache,
+                                               &filtered, aResult);
+  NS_ENSURE_SUCCESS(*aResult, nullptr);
 
-  if (aSearchCurrent) {
-    *aResult = cache.ApplyFilter(accessible, &filtered);
-    NS_ENSURE_SUCCESS(*aResult, nullptr);
-    if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH)
-      return accessible;
+  if (aSearchCurrent && (filtered & nsIAccessibleTraversalRule::FILTER_MATCH)) {
+    return accessible;
   }
 
   Accessible* root = GetActiveRoot();
   while (accessible != root) {
     Accessible* parent = accessible->Parent();
     int32_t idxInParent = accessible->IndexInParent();
     while (idxInParent > 0) {
       if (!(accessible = parent->GetChildAt(--idxInParent)))
@@ -487,17 +510,17 @@ nsAccessiblePivot::SearchForward(Accessi
 
   // Initial position could be not set, in that case begin search from root.
   Accessible* root = GetActiveRoot();
   Accessible* accessible = (!aAccessible) ? root : aAccessible;
 
   RuleCache cache(aRule);
 
   uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE;
-  *aResult = cache.ApplyFilter(accessible, &filtered);
+  accessible = AdjustStartPosition(accessible, cache, &filtered, aResult);
   NS_ENSURE_SUCCESS(*aResult, nullptr);
   if (aSearchCurrent && (filtered & nsIAccessibleTraversalRule::FILTER_MATCH))
     return accessible;
 
   while (true) {
     Accessible* firstChild = nullptr;
     while (!(filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) &&
            (firstChild = accessible->FirstChild())) {
--- a/accessible/src/base/nsAccessiblePivot.h
+++ b/accessible/src/base/nsAccessiblePivot.h
@@ -11,16 +11,17 @@
 
 #include "Accessible-inl.h"
 #include "nsAutoPtr.h"
 #include "nsTObserverArray.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 
 class nsIAccessibleTraversalRule;
+class RuleCache;
 
 /**
  * Class represents an accessible pivot.
  */
 class nsAccessiblePivot MOZ_FINAL : public nsIAccessiblePivot
 {
 public:
   typedef mozilla::a11y::Accessible Accessible;
@@ -86,16 +87,28 @@ private:
   }
 
   /*
    * Update the pivot, and notify observers. Return true if it moved.
    */
   bool MovePivotInternal(Accessible* aPosition, PivotMoveReason aReason);
 
   /*
+   * Get initial node we should start a search from with a given rule.
+   *
+   * When we do a move operation from one position to another,
+   * the initial position can be inside of a subtree that is ignored by
+   * the given rule. We need to step out of the ignored subtree and start
+   * the search from there.
+   *
+   */
+  Accessible* AdjustStartPosition(Accessible* aAccessible, RuleCache& aCache,
+                                  uint16_t* aFilterResult, nsresult* aResult);
+
+  /*
    * The root accessible.
    */
   nsRefPtr<Accessible> mRoot;
 
   /*
    * The temporary modal root accessible.
    */
   nsRefPtr<Accessible> mModalRoot;
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -767,19 +767,19 @@ HyperTextAccessible::GetRelativeOffset(n
       -- hyperTextOffset;
     }
   }
 
   return hyperTextOffset;
 }
 
 int32_t
-HyperTextAccessible::FindBoundary(int32_t aOffset, nsDirection aDirection,
-                                  nsSelectionAmount aAmount,
-                                  EWordMovementType aWordMovementType)
+HyperTextAccessible::FindOffset(int32_t aOffset, nsDirection aDirection,
+                                nsSelectionAmount aAmount,
+                                EWordMovementType aWordMovementType)
 {
   // Convert hypertext offset to frame-relative offset.
   int32_t offsetInFrame = aOffset, notUsedOffset = aOffset;
   nsRefPtr<Accessible> accAtOffset;
   nsIFrame* frameAtOffset =
     GetPosAndText(offsetInFrame, notUsedOffset, nullptr, nullptr,
                   nullptr, getter_AddRefs(accAtOffset));
   if (!frameAtOffset) {
@@ -798,16 +798,91 @@ HyperTextAccessible::FindBoundary(int32_
 
   // Return hypertext offset of the boundary of the found word.
   return GetRelativeOffset(mDoc->PresShell(), frameAtOffset, offsetInFrame,
                            accAtOffset, aAmount, aDirection,
                            (aWordMovementType == eStartWord || aAmount == eSelectBeginLine),
                            aWordMovementType);
 }
 
+int32_t
+HyperTextAccessible::FindLineBoundary(int32_t aOffset,
+                                      EWhichLineBoundary aWhichLineBoundary)
+{
+  // Note: empty last line doesn't have own frame (a previous line contains '\n'
+  // character instead) thus when it makes a difference we need to process this
+  // case separately (otherwise operations are performed on previous line).
+  switch (aWhichLineBoundary) {
+    case ePrevLineBegin: {
+      // Fetch a previous line and move to its start (as arrow up and home keys
+      // were pressed).
+      if (IsEmptyLastLineOffset(aOffset))
+        return FindOffset(aOffset, eDirPrevious, eSelectBeginLine);
+
+      int32_t tmpOffset = FindOffset(aOffset, eDirPrevious, eSelectLine);
+      return FindOffset(tmpOffset, eDirPrevious, eSelectBeginLine);
+    }
+
+    case ePrevLineEnd: {
+      if (IsEmptyLastLineOffset(aOffset))
+        return aOffset - 1;
+
+      // If offset is at first line then return 0 (first line start).
+      int32_t tmpOffset = FindOffset(aOffset, eDirPrevious, eSelectBeginLine);
+      if (tmpOffset == 0)
+        return 0;
+
+      // Otherwise move to end of previous line (as arrow up and end keys were
+      // pressed).
+      tmpOffset = FindOffset(aOffset, eDirPrevious, eSelectLine);
+      return FindOffset(tmpOffset, eDirNext, eSelectEndLine);
+    }
+
+    case eThisLineBegin:
+      if (IsEmptyLastLineOffset(aOffset))
+        return aOffset;
+
+      // Move to begin of the current line (as home key was pressed).
+      return FindOffset(aOffset, eDirPrevious, eSelectBeginLine);
+
+    case eThisLineEnd:
+      if (IsEmptyLastLineOffset(aOffset))
+        return aOffset;
+
+      // Move to end of the current line (as end key was pressed).
+      return FindOffset(aOffset, eDirNext, eSelectEndLine);
+
+    case eNextLineBegin: {
+      if (IsEmptyLastLineOffset(aOffset))
+        return aOffset;
+
+      // Move to begin of the next line if any (arrow down and home keys),
+      // otherwise end of the current line (arrow down only).
+      int32_t tmpOffset = FindOffset(aOffset, eDirNext, eSelectLine);
+      if (tmpOffset == CharacterCount())
+        return tmpOffset;
+
+      return FindOffset(tmpOffset, eDirPrevious, eSelectBeginLine);
+    }
+
+    case eNextLineEnd: {
+      if (IsEmptyLastLineOffset(aOffset))
+        return aOffset;
+
+      // Move to next line end (as down arrow and end key were pressed).
+      int32_t tmpOffset = FindOffset(aOffset, eDirNext, eSelectLine);
+      if (tmpOffset != CharacterCount())
+        return FindOffset(tmpOffset, eDirNext, eSelectEndLine);
+      return tmpOffset;
+    }
+  }
+
+  return -1;
+}
+
 /*
 Gets the specified text relative to aBoundaryType, which means:
 BOUNDARY_CHAR             The character before/at/after the offset is returned.
 BOUNDARY_WORD_START       From the word start before/at/after the offset to the next word start.
 BOUNDARY_WORD_END         From the word end before/at/after the offset to the next work end.
 BOUNDARY_LINE_START       From the line start before/at/after the offset to the next line start.
 BOUNDARY_LINE_END         From the line end before/at/after the offset to the next line start.
 */
@@ -1025,17 +1100,31 @@ HyperTextAccessible::GetTextBeforeOffset
     case BOUNDARY_WORD_END: {
       // Move word backward twice to find start and end offsets.
       *aEndOffset = FindWordBoundary(offset, eDirPrevious, eEndWord);
       *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eEndWord);
       return GetText(*aStartOffset, *aEndOffset, aText);
     }
 
     case BOUNDARY_LINE_START:
+      if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET)
+        offset = AdjustCaretOffset(offset);
+
+      *aStartOffset = FindLineBoundary(offset, ePrevLineBegin);
+      *aEndOffset = FindLineBoundary(offset, eThisLineBegin);
+      return GetText(*aStartOffset, *aEndOffset, aText);
+
     case BOUNDARY_LINE_END:
+      if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET)
+        offset = AdjustCaretOffset(offset);
+
+      *aEndOffset = FindLineBoundary(offset, ePrevLineEnd);
+      *aStartOffset = FindLineBoundary(*aEndOffset, ePrevLineEnd);
+      return GetText(*aStartOffset, *aEndOffset, aText);
+
     case BOUNDARY_ATTRIBUTE_RANGE:
       return GetTextHelper(eGetBefore, aBoundaryType, aOffset,
                            aStartOffset, aEndOffset, aText);
 
     default:
       return NS_ERROR_INVALID_ARG;
   }
 }
@@ -1066,70 +1155,32 @@ HyperTextAccessible::GetTextAtOffset(int
     case BOUNDARY_WORD_END:
       // Ignore the spec and follow what WebKitGtk does because Orca expects it,
       // i.e. return a next word at word end offset of the current word
       // (WebKitGtk behavior) instead the current word (AKT spec).
       *aEndOffset = FindWordBoundary(offset, eDirNext, eEndWord);
       *aStartOffset = FindWordBoundary(*aEndOffset, eDirPrevious, eEndWord);
       return GetText(*aStartOffset, *aEndOffset, aText);
 
-    case BOUNDARY_LINE_START: {
-      // Empty last line doesn't have own frame (a previous line contains '\n'
-      // character instead) thus we can't operate on last line separately
-      // from previous line.
-      if (offset == CharacterCount()) {
-        nsAutoString lastChar;
-        GetText(offset -1, -1, lastChar);
-        if (lastChar.EqualsLiteral("\n")) {
-          *aStartOffset = *aEndOffset = offset;
-          return NS_OK;
-        }
-      }
-
+    case BOUNDARY_LINE_START:
       if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET)
         offset = AdjustCaretOffset(offset);
 
-      // Home key, arrow down and if not on last line then home key.
-      *aStartOffset = FindLineBoundary(offset, eDirPrevious, eSelectBeginLine);
-      *aEndOffset = FindLineBoundary(offset, eDirNext, eSelectLine);
-      int32_t tmpOffset = FindLineBoundary(*aEndOffset, eDirPrevious, eSelectBeginLine);
-      if (tmpOffset != *aStartOffset)
-        *aEndOffset = tmpOffset;
-
+      *aStartOffset = FindLineBoundary(offset, eThisLineBegin);
+      *aEndOffset = FindLineBoundary(offset, eNextLineBegin);
       return GetText(*aStartOffset, *aEndOffset, aText);
-    }
-
-    case BOUNDARY_LINE_END: {
-      // Empty last line doesn't have own frame (a previous line contains '\n'
-      // character instead) thus we can't operate on last line separately
-      // from the previous line.
-      if (offset == CharacterCount()) {
-        nsAutoString lastChar;
-        GetText(offset -1, -1, lastChar);
-        if (lastChar.EqualsLiteral("\n")) {
-          *aStartOffset = offset - 1;
-          *aEndOffset = offset;
-          aText = lastChar;
-          return NS_OK;
-        }
-      }
-
+
+    case BOUNDARY_LINE_END:
       if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET)
         offset = AdjustCaretOffset(offset);
 
-      // In contrast to word end boundary we follow the spec here. End key,
-      // then up arrow and if not on first line then end key.
-      *aEndOffset = FindLineBoundary(offset, eDirNext, eSelectEndLine);
-      int32_t tmpOffset = FindLineBoundary(offset, eDirPrevious, eSelectLine);
-      *aStartOffset = FindLineBoundary(tmpOffset, eDirNext, eSelectEndLine);
-      if (*aStartOffset == *aEndOffset)
-        *aStartOffset = 0;
-
+      // In contrast to word end boundary we follow the spec here.
+      *aStartOffset = FindLineBoundary(offset, ePrevLineEnd);
+      *aEndOffset = FindLineBoundary(offset, eThisLineEnd);
       return GetText(*aStartOffset, *aEndOffset, aText);
-    }
 
     case BOUNDARY_ATTRIBUTE_RANGE:
       return GetTextHelper(eGetAt, aBoundaryType, aOffset,
                            aStartOffset, aEndOffset, aText);
 
     default:
       return NS_ERROR_INVALID_ARG;
   }
@@ -1172,17 +1223,31 @@ HyperTextAccessible::GetTextAfterOffset(
         if (*aStartOffset != offset) {
           *aStartOffset = *aEndOffset;
           *aEndOffset = FindWordBoundary(*aStartOffset, eDirNext, eEndWord);
         }
       }
       return GetText(*aStartOffset, *aEndOffset, aText);
 
     case BOUNDARY_LINE_START:
+      if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET)
+        offset = AdjustCaretOffset(offset);
+
+      *aStartOffset = FindLineBoundary(offset, eNextLineBegin);
+      *aEndOffset = FindLineBoundary(*aStartOffset, eNextLineBegin);
+      return GetText(*aStartOffset, *aEndOffset, aText);
+
     case BOUNDARY_LINE_END:
+      if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET)
+        offset = AdjustCaretOffset(offset);
+
+      *aStartOffset = FindLineBoundary(offset, eThisLineEnd);
+      *aEndOffset = FindLineBoundary(offset, eNextLineEnd);
+      return GetText(*aStartOffset, *aEndOffset, aText);
+
     case BOUNDARY_ATTRIBUTE_RANGE:
       return GetTextHelper(eGetAfter, aBoundaryType, aOffset,
                            aStartOffset, aEndOffset, aText);
 
     default:
       return NS_ERROR_INVALID_ARG;
   }
 }
--- a/accessible/src/generic/HyperTextAccessible.h
+++ b/accessible/src/generic/HyperTextAccessible.h
@@ -279,39 +279,65 @@ protected:
           frameSelection->GetHint() == nsFrameSelection::HINTLEFT) {
         return aOffset - 1;
       }
     }
     return aOffset;
   }
 
   /**
+   * Return true if the given offset points to terminal empty line if any.
+   */
+  bool IsEmptyLastLineOffset(int32_t aOffset)
+  {
+    if (aOffset != static_cast<int32_t>(CharacterCount()))
+      return false;
+
+    nsAutoString lastChar;
+    GetText(aOffset -1, -1, lastChar);
+    return lastChar.EqualsLiteral("\n");
+  }
+
+  /**
    * Return an offset of the found word boundary.
    */
   int32_t FindWordBoundary(int32_t aOffset, nsDirection aDirection,
                            EWordMovementType aWordMovementType)
   {
-    return FindBoundary(aOffset, aDirection, eSelectWord, aWordMovementType);
+    return FindOffset(aOffset, aDirection, eSelectWord, aWordMovementType);
   }
 
   /**
-   * Return an offset of the found line boundary.
+   * Used to get begin/end of previous/this/next line. Note: end of line
+   * is an offset right before '\n' character if any, the offset is right after
+   * '\n' character is begin of line. In case of wrap word breaks these offsets
+   * are equal.
    */
-  int32_t FindLineBoundary(int32_t aOffset, nsDirection aDirection,
-                           nsSelectionAmount aAmount)
-  {
-    return FindBoundary(aOffset, aDirection, aAmount, eDefaultBehavior);
-  }
+  enum EWhichLineBoundary {
+    ePrevLineBegin,
+    ePrevLineEnd,
+    eThisLineBegin,
+    eThisLineEnd,
+    eNextLineBegin,
+    eNextLineEnd
+  };
 
   /**
-   * Return an offset of the found word or line boundary. Helper.
+   * Return an offset for requested line boundary. See constants above.
    */
-  int32_t FindBoundary(int32_t aOffset, nsDirection aDirection,
-                       nsSelectionAmount aAmount,
-                       EWordMovementType aWordMovementType = eDefaultBehavior);
+  int32_t FindLineBoundary(int32_t aOffset,
+                           EWhichLineBoundary aWhichLineBoundary);
+
+  /**
+   * Return an offset corresponding to the given direction and selection amount
+   * relative the given offset. A helper used to find word or line boundaries.
+   */
+  int32_t FindOffset(int32_t aOffset, nsDirection aDirection,
+                     nsSelectionAmount aAmount,
+                     EWordMovementType aWordMovementType = eDefaultBehavior);
 
   /*
    * This does the work for nsIAccessibleText::GetText[At|Before|After]Offset
    * @param aType, eGetBefore, eGetAt, eGetAfter
    * @param aBoundaryType, char/word-start/word-end/line-start/line-end/paragraph/attribute
    * @param aOffset, offset into the hypertext to start from
    * @param *aStartOffset, the resulting start offset for the returned substring
    * @param *aEndOffset, the resulting end offset for the returned substring
--- a/accessible/src/generic/Makefile.in
+++ b/accessible/src/generic/Makefile.in
@@ -6,19 +6,16 @@ DEPTH = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBXUL_LIBRARY = 1
 
-# we don't want the shared lib, but we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir)/../xpcom \
   -I$(srcdir)/../base \
   -I$(srcdir)/../html \
   -I$(srcdir)/../xul \
   -I$(srcdir)/../../../content/base/src \
--- a/accessible/src/html/Makefile.in
+++ b/accessible/src/html/Makefile.in
@@ -7,19 +7,16 @@ DEPTH = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBXUL_LIBRARY = 1
 
-# we don't want the shared lib, but we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir)/../base \
   -I$(srcdir)/../generic \
   -I$(srcdir)/../xpcom \
   -I$(srcdir)/../../../content/base/src \
   -I$(srcdir)/../../../content/html/content/src \
--- a/accessible/src/jsat/AccessFu.jsm
+++ b/accessible/src/jsat/AccessFu.jsm
@@ -269,19 +269,17 @@ this.AccessFu = {
         this.Input.moveCursor('movePrevious', 'Simple', 'gesture');
         break;
       case 'Accessibility:ActivateObject':
         this.Input.activateCurrent(JSON.parse(aData));
         break;
       case 'Accessibility:Focus':
         this._focused = JSON.parse(aData);
         if (this._focused) {
-          let mm = Utils.getMessageManager(Utils.CurrentBrowser);
-          mm.sendAsyncMessage('AccessFu:VirtualCursor',
-                              {action: 'whereIsIt', move: true});
+          this.showCurrent(true);
         }
         break;
       case 'Accessibility:MoveCaret':
         this.Input.moveCaret(JSON.parse(aData));
         break;
       case 'remote-browser-frame-shown':
       case 'in-process-browser-or-app-frame-shown':
       {
@@ -322,30 +320,34 @@ this.AccessFu = {
           this._removeMessageListeners(mm);
           this._processedMessageManagers.splice(mmIndex, 1);
         }
         break;
       }
       case 'TabSelect':
       {
         if (this._focused) {
-          let mm = Utils.getMessageManager(Utils.CurrentBrowser);
           // We delay this for half a second so the awesomebar could close,
           // and we could use the current coordinates for the content item.
           // XXX TODO figure out how to avoid magic wait here.
           Utils.win.setTimeout(
             function () {
-              mm.sendAsyncMessage('AccessFu:VirtualCursor', {action: 'whereIsIt'});
-            }, 500);
+              this.showCurrent(false);
+            }.bind(this), 500);
         }
         break;
       }
     }
   },
 
+  showCurrent: function showCurrent(aMove) {
+    let mm = Utils.getMessageManager(Utils.CurrentBrowser);
+    mm.sendAsyncMessage('AccessFu:ShowCurrent', { move: aMove });
+  },
+
   announce: function announce(aAnnouncement) {
     this._output(Presentation.announce(aAnnouncement),
                  Utils.CurrentBrowser);
   },
 
   // So we don't enable/disable twice
   _enabled: false,
 
@@ -357,50 +359,74 @@ this.AccessFu = {
   _processedMessageManagers: []
 };
 
 var Output = {
   brailleState: {
     startOffset: 0,
     endOffset: 0,
     text: '',
+    selectionStart: 0,
+    selectionEnd: 0,
 
     init: function init(aOutput) {
       if (aOutput && 'output' in aOutput) {
         this.startOffset = aOutput.startOffset;
         this.endOffset = aOutput.endOffset;
         // We need to append a space at the end so that the routing key corresponding
         // to the end of the output (i.e. the space) can be hit to move the caret there.
         this.text = aOutput.output + ' ';
-        return this.text;
+        this.selectionStart = typeof aOutput.selectionStart === 'number' ?
+                              aOutput.selectionStart : this.selectionStart;
+        this.selectionEnd = typeof aOutput.selectionEnd === 'number' ?
+                            aOutput.selectionEnd : this.selectionEnd;
+
+        return { text: this.text,
+                 selectionStart: this.selectionStart,
+                 selectionEnd: this.selectionEnd };
       }
+
+      return null;
     },
 
-    update: function update(aText) {
+    adjustText: function adjustText(aText) {
       let newBraille = [];
       let braille = {};
 
       let prefix = this.text.substring(0, this.startOffset).trim();
       if (prefix) {
         prefix += ' ';
         newBraille.push(prefix);
       }
 
-      let newText = aText;
-      newBraille.push(newText);
+      newBraille.push(aText);
 
       let suffix = this.text.substring(this.endOffset).trim();
       if (suffix) {
         suffix = ' ' + suffix;
         newBraille.push(suffix);
       }
 
-      braille.startOffset = prefix.length;
-      braille.output = newBraille.join('');
-      braille.endOffset = braille.output.length - suffix.length;
+      this.startOffset = braille.startOffset = prefix.length;
+      this.text = braille.text = newBraille.join('') + ' ';
+      this.endOffset = braille.endOffset = braille.text.length - suffix.length;
+      braille.selectionStart = this.selectionStart;
+      braille.selectionEnd = this.selectionEnd;
+
+      return braille;
+    },
+
+    adjustSelection: function adjustSelection(aSelection) {
+      let braille = {};
+
+      braille.startOffset = this.startOffset;
+      braille.endOffset = this.endOffset;
+      braille.text = this.text;
+      this.selectionStart = braille.selectionStart = aSelection.selectionStart + this.startOffset;
+      this.selectionEnd = braille.selectionEnd = aSelection.selectionEnd + this.startOffset;
 
       return braille;
     }
   },
 
   start: function start() {
     Cu.import('resource://gre/modules/Geometry.jsm');
   },
@@ -497,32 +523,37 @@ var Output = {
           announceBox.classList.remove('showing');
         break;
       }
     }
   },
 
   Android: function Android(aDetails, aBrowser) {
     const ANDROID_VIEW_TEXT_CHANGED = 0x10;
+    const ANDROID_VIEW_TEXT_SELECTION_CHANGED = 0x2000;
 
     if (!this._bridge)
       this._bridge = Cc['@mozilla.org/android/bridge;1'].getService(Ci.nsIAndroidBridge);
 
     for each (let androidEvent in aDetails) {
       androidEvent.type = 'Accessibility:Event';
       if (androidEvent.bounds)
         androidEvent.bounds = this._adjustBounds(androidEvent.bounds, aBrowser, true);
-      if (androidEvent.eventType === ANDROID_VIEW_TEXT_CHANGED) {
-        androidEvent.brailleText = this.brailleState.update(androidEvent.text);
+
+      switch(androidEvent.eventType) {
+        case ANDROID_VIEW_TEXT_CHANGED:
+          androidEvent.brailleOutput = this.brailleState.adjustText(androidEvent.text);
+          break;
+        case ANDROID_VIEW_TEXT_SELECTION_CHANGED:
+          androidEvent.brailleOutput = this.brailleState.adjustSelection(androidEvent.brailleOutput);
+          break;
+        default:
+          androidEvent.brailleOutput = this.brailleState.init(androidEvent.brailleOutput);
+          break;
       }
-      let (output = this.brailleState.init(androidEvent.brailleText)) {
-        if (typeof output === 'string') {
-          androidEvent.brailleText = output;
-        }
-      };
       this._bridge.handleGeckoMessage(JSON.stringify(androidEvent));
     }
   },
 
   Haptic: function Haptic(aDetails, aBrowser) {
     Utils.win.navigator.vibrate(aDetails.pattern);
   },
 
@@ -598,18 +629,17 @@ var Input = {
   _handleGesture: function _handleGesture(aGesture) {
     let gestureName = aGesture.type + aGesture.touches.length;
     Logger.info('Gesture', aGesture.type,
                 '(fingers: ' + aGesture.touches.length + ')');
 
     switch (gestureName) {
       case 'dwell1':
       case 'explore1':
-        this.moveCursor('moveToPoint', 'SimpleTouch', 'gesture',
-                        aGesture.x, aGesture.y);
+        this.moveToPoint('SimpleTouch', aGesture.x, aGesture.y);
         break;
       case 'doubletap1':
         this.activateCurrent();
         break;
       case 'doubletaphold1':
         this.sendContextMenuMessage();
         break;
       case 'swiperight1':
@@ -720,22 +750,28 @@ var Input = {
     default:
       return;
     }
 
     aEvent.preventDefault();
     aEvent.stopPropagation();
   },
 
-  moveCursor: function moveCursor(aAction, aRule, aInputType, aX, aY) {
+  moveToPoint: function moveToPoint(aRule, aX, aY) {
     let mm = Utils.getMessageManager(Utils.CurrentBrowser);
-    mm.sendAsyncMessage('AccessFu:VirtualCursor',
+    mm.sendAsyncMessage('AccessFu:MoveToPoint', {rule: aRule,
+                                                 x: aX, y: aY,
+                                                 origin: 'top'});
+  },
+
+  moveCursor: function moveCursor(aAction, aRule, aInputType) {
+    let mm = Utils.getMessageManager(Utils.CurrentBrowser);
+    mm.sendAsyncMessage('AccessFu:MoveCursor',
                         {action: aAction, rule: aRule,
-                         x: aX, y: aY, origin: 'top',
-                         inputType: aInputType});
+                         origin: 'top', inputType: aInputType});
   },
 
   moveCaret: function moveCaret(aDetails) {
     if (!this.editState.editing) {
       return;
     }
 
     aDetails.atStart = this.editState.atStart;
@@ -754,19 +790,22 @@ var Input = {
   },
 
   sendContextMenuMessage: function sendContextMenuMessage() {
     let mm = Utils.getMessageManager(Utils.CurrentBrowser);
     mm.sendAsyncMessage('AccessFu:ContextMenu', {});
   },
 
   activateContextMenu: function activateContextMenu(aMessage) {
-    if (Utils.MozBuildApp === 'mobile/android')
+    if (Utils.MozBuildApp === 'mobile/android') {
+      let vp = Utils.getViewport(Utils.win) || { zoom: 1.0 };
       Services.obs.notifyObservers(null, 'Gesture:LongPress',
-                                   JSON.stringify({x: aMessage.x, y: aMessage.y}));
+                                   JSON.stringify({x: aMessage.x / vp.zoom,
+                                                   y: aMessage.y / vp.zoom}));
+    }
   },
 
   setEditState: function setEditState(aEditState) {
     this.editState = aEditState;
   },
 
   scroll: function scroll(aPage, aHorizontal) {
     let mm = Utils.getMessageManager(Utils.CurrentBrowser);
@@ -777,16 +816,18 @@ var Input = {
     delete this.keyMap;
     this.keyMap = {
       a: ['moveNext', 'Anchor'],
       A: ['movePrevious', 'Anchor'],
       b: ['moveNext', 'Button'],
       B: ['movePrevious', 'Button'],
       c: ['moveNext', 'Combobox'],
       C: ['movePrevious', 'Combobox'],
+      d: ['moveNext', 'Landmark'],
+      D: ['movePrevious', 'Landmark'],
       e: ['moveNext', 'Entry'],
       E: ['movePrevious', 'Entry'],
       f: ['moveNext', 'FormElement'],
       F: ['movePrevious', 'FormElement'],
       g: ['moveNext', 'Graphic'],
       G: ['movePrevious', 'Graphic'],
       h: ['moveNext', 'Heading'],
       H: ['movePrevious', 'Heading'],
--- a/accessible/src/jsat/EventManager.jsm
+++ b/accessible/src/jsat/EventManager.jsm
@@ -207,16 +207,19 @@ this.EventManager.prototype = {
           this.present(Presentation.editingModeChanged(editState.editing));
 
         if (editState.editing != this.editState.editing ||
             editState.multiline != this.editState.multiline ||
             editState.atEnd != this.editState.atEnd ||
             editState.atStart != this.editState.atStart)
           this.sendMsgFunc("AccessFu:Input", editState);
 
+        this.present(Presentation.textSelectionChanged(acc.getText(0,-1),
+                     caretOffset, caretOffset, 0, 0, aEvent.isFromUserInput));
+
         this.editState = editState;
         break;
       }
       case EVENT_TEXT_INSERTED:
       case EVENT_TEXT_REMOVED:
       {
         if (aEvent.isFromUserInput) {
           // XXX support live regions as well.
--- a/accessible/src/jsat/OutputGenerator.jsm
+++ b/accessible/src/jsat/OutputGenerator.jsm
@@ -34,16 +34,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 var gStringBundle = Cc['@mozilla.org/intl/stringbundle;1'].
   getService(Ci.nsIStringBundleService).
   createBundle('chrome://global/locale/AccessFu.properties');
 
 this.EXPORTED_SYMBOLS = ['UtteranceGenerator', 'BrailleGenerator'];
 
 this.OutputGenerator = {
 
+  defaultOutputOrder: OUTPUT_DESC_LAST,
+
   /**
    * Generates output for a PivotContext.
    * @param {PivotContext} aContext object that generates and caches
    *    context information for a given accessible and its relationship with
    *    another accessible.
    * @return {Object} An object that neccessarily has an output property which
    *    is an array of strings. Depending on the utterance order,
    *    the strings describe the context for an accessible object either
@@ -169,32 +171,22 @@ this.OutputGenerator = {
   },
 
   /**
    * Adds a landmark role to the output if available.
    * @param {Array} aOutput Output array.
    * @param {nsIAccessible} aAccessible current accessible object.
    */
   _addLandmark: function _addLandmark(aOutput, aAccessible) {
-    let getLandmarkName = function getLandmarkName(aAccessible) {
-      let roles = Utils.getAttributes(aAccessible)['xml-roles'];
-      if (!roles) {
-        return;
-      }
+    let landmarkName = Utils.getLandmarkName(aAccessible);
+    if (!landmarkName) {
+      return;
+    }
 
-      // Looking up a role that would match a landmark.
-      for (let landmark of this.gLandmarks) {
-        if (roles.indexOf(landmark) > -1) {
-          return gStringBundle.GetStringFromName(landmark);
-        }
-      }
-    };
-
-    let landmark = getLandmarkName.apply(this, [aAccessible]);
-
+    let landmark = gStringBundle.GetStringFromName(landmarkName);
     if (!landmark) {
       return;
     }
 
     aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? 'unshift' : 'push'](
       landmark);
   },
 
@@ -215,25 +207,16 @@ this.OutputGenerator = {
   _getLocalizedStates: function _getLocalizedStates(aStates) {},
 
   _getPluralFormString: function _getPluralFormString(aString, aCount) {
     let str = gStringBundle.GetStringFromName(this._getOutputName(aString));
     str = PluralForm.get(aCount, str);
     return str.replace('#1', aCount);
   },
 
-  gLandmarks: [
-    'banner',
-    'complementary',
-    'contentinfo',
-    'main',
-    'navigation',
-    'search'
-  ],
-
   roleRuleMap: {
     'menubar': INCLUDE_DESC,
     'scrollbar': INCLUDE_DESC,
     'grip': INCLUDE_DESC,
     'alert': INCLUDE_DESC | INCLUDE_NAME,
     'menupopup': INCLUDE_DESC,
     'menuitem': INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
     'tooltip': INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
@@ -378,18 +361,16 @@ this.OutputGenerator = {
  * last string usually makes sense, but speaking the first often won't.
  * For example {@link genForAction} might return ['button', 'clicked'] for a
  * clicked event. Speaking only 'clicked' makes sense. Speaking 'button' does
  * not.
  */
 this.UtteranceGenerator = {
   __proto__: OutputGenerator,
 
-  defaultOutputOrder: OUTPUT_DESC_FIRST,
-
   gActionMap: {
     jump: 'jumpAction',
     press: 'pressAction',
     check: 'checkAction',
     uncheck: 'uncheckAction',
     select: 'selectAction',
     open: 'openAction',
     close: 'closeAction',
@@ -590,35 +571,33 @@ this.UtteranceGenerator = {
     }
 
     return stateUtterances;
   },
 
   _getListUtterance: function _getListUtterance(aAccessible, aRoleStr, aFlags, aItemCount) {
     let desc = [];
     let roleStr = this._getLocalizedRole(aRoleStr);
-    if (roleStr)
+    if (roleStr) {
       desc.push(roleStr);
-    desc.push
-      (gStringBundle.formatStringFromName('listItemCount', [aItemCount], 1));
+    }
+    desc.push(this._getPluralFormString('listItemsCount', aItemCount));
     let utterance = [desc.join(' ')];
 
     this._addName(utterance, aAccessible, aFlags);
     this._addLandmark(utterance, aAccessible);
 
     return utterance;
   }
 };
 
 
 this.BrailleGenerator = {
   __proto__: OutputGenerator,
 
-  defaultOutputOrder: OUTPUT_DESC_LAST,
-
   genForContext: function genForContext(aContext) {
     let output = OutputGenerator.genForContext.apply(this, arguments);
 
     let acc = aContext.accessible;
     if (acc instanceof Ci.nsIAccessibleText) {
       output.endOffset = this.outputOrder === OUTPUT_DESC_FIRST ?
                          output.output.join(' ').length : acc.characterCount;
       output.startOffset = output.endOffset - acc.characterCount;
--- a/accessible/src/jsat/Presentation.jsm
+++ b/accessible/src/jsat/Presentation.jsm
@@ -56,17 +56,17 @@ Presenter.prototype = {
    */
   textChanged: function textChanged(aIsInserted, aStartOffset,
                                     aLength, aText,
                                     aModifiedText) {},
 
   /**
    * Text selection has changed. TODO.
    */
-  textSelectionChanged: function textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd) {},
+  textSelectionChanged: function textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd, aIsFromUser) {},
 
   /**
    * Selection has changed. TODO.
    * @param {nsIAccessible} aObject the object that has been selected.
    */
   selectionChanged: function selectionChanged(aObject) {},
 
   /**
@@ -229,35 +229,35 @@ AndroidPresenter.prototype = {
     if (isExploreByTouch) {
       // This isn't really used by TalkBack so this is a half-hearted attempt
       // for now.
       androidEvents.push({eventType: this.ANDROID_VIEW_HOVER_EXIT, text: []});
     }
 
     let state = Utils.getStates(aContext.accessible)[0];
 
-    let brailleText = '';
+    let brailleOutput = {};
     if (Utils.AndroidSdkVersion >= 16) {
       if (!this._braillePresenter) {
         this._braillePresenter = new BraillePresenter();
       }
-      brailleText = this._braillePresenter.pivotChanged(aContext, aReason).
+      brailleOutput = this._braillePresenter.pivotChanged(aContext, aReason).
                          details;
     }
 
     androidEvents.push({eventType: (isExploreByTouch) ?
                           this.ANDROID_VIEW_HOVER_ENTER : focusEventType,
                         text: UtteranceGenerator.genForContext(aContext).output,
                         bounds: aContext.bounds,
                         clickable: aContext.accessible.actionCount > 0,
                         checkable: !!(state &
                                       Ci.nsIAccessibleStates.STATE_CHECKABLE),
                         checked: !!(state &
                                     Ci.nsIAccessibleStates.STATE_CHECKED),
-                        brailleText: brailleText});
+                        brailleOutput: brailleOutput});
 
 
     return {
       type: this.type,
       details: androidEvents
     };
   },
 
@@ -305,30 +305,38 @@ AndroidPresenter.prototype = {
         aText.substring(0, aStart) + aModifiedText + aText.substring(aStart);
     }
 
     return {type: this.type, details: [eventDetails]};
   },
 
   textSelectionChanged: function AndroidPresenter_textSelectionChanged(aText, aStart,
                                                                        aEnd, aOldStart,
-                                                                       aOldEnd) {
+                                                                       aOldEnd, aIsFromUser) {
     let androidEvents = [];
 
-    if (Utils.AndroidSdkVersion >= 14) {
+    if (Utils.AndroidSdkVersion >= 14 && !aIsFromUser) {
+      if (!this._braillePresenter) {
+        this._braillePresenter = new BraillePresenter();
+      }
+      let brailleOutput = this._braillePresenter.textSelectionChanged(aText, aStart, aEnd,
+                                                                      aOldStart, aOldEnd,
+                                                                      aIsFromUser).details;
+
       androidEvents.push({
         eventType: this.ANDROID_VIEW_TEXT_SELECTION_CHANGED,
         text: [aText],
         fromIndex: aStart,
         toIndex: aEnd,
-        itemCount: aText.length
+        itemCount: aText.length,
+        brailleOutput: brailleOutput
       });
     }
 
-    if (Utils.AndroidSdkVersion >= 16) {
+    if (Utils.AndroidSdkVersion >= 16 && aIsFromUser) {
       let [from, to] = aOldStart < aStart ? [aOldStart, aStart] : [aStart, aOldStart];
       androidEvents.push({
         eventType: this.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
         text: [aText],
         fromIndex: from,
         toIndex: to
       });
     }
@@ -449,19 +457,30 @@ BraillePresenter.prototype = {
 
   pivotChanged: function BraillePresenter_pivotChanged(aContext, aReason) {
     if (!aContext.accessible) {
       return null;
     }
 
     let brailleOutput = BrailleGenerator.genForContext(aContext);
     brailleOutput.output = brailleOutput.output.join(' ');
+    brailleOutput.selectionStart = 0;
+    brailleOutput.selectionEnd = 0;
 
     return { type: this.type, details: brailleOutput };
-  }
+  },
+
+  textSelectionChanged: function BraillePresenter_textSelectionChanged(aText, aStart,
+                                                                       aEnd, aOldStart,
+                                                                       aOldEnd, aIsFromUser) {
+    return { type: this.type,
+             details: { selectionStart: aStart,
+                        selectionEnd: aEnd } };
+  },
+
 
 };
 
 this.Presentation = {
   get presenters() {
     delete this.presenters;
     this.presenters = [new VisualPresenter()];
 
@@ -491,18 +510,21 @@ this.Presentation = {
   textChanged: function Presentation_textChanged(aIsInserted, aStartOffset,
                                     aLength, aText,
                                     aModifiedText) {
     return [p.textChanged(aIsInserted, aStartOffset, aLength,
                           aText, aModifiedText)
               for each (p in this.presenters)];
   },
 
-  textSelectionChanged: function textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd) {
-    return [p.textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd)
+  textSelectionChanged: function textSelectionChanged(aText, aStart, aEnd,
+                                                      aOldStart, aOldEnd,
+                                                      aIsFromUser) {
+    return [p.textSelectionChanged(aText, aStart, aEnd,
+                                   aOldStart, aOldEnd, aIsFromUser)
               for each (p in this.presenters)];
   },
 
   tabStateChanged: function Presentation_tabStateChanged(aDocObj, aPageState) {
     return [p.tabStateChanged(aDocObj, aPageState)
               for each (p in this.presenters)];
   },
 
--- a/accessible/src/jsat/TraversalRules.jsm
+++ b/accessible/src/jsat/TraversalRules.jsm
@@ -179,16 +179,24 @@ this.TraversalRules = {
      ROLE_TOGGLE_BUTTON,
      ROLE_BUTTONDROPDOWN,
      ROLE_BUTTONDROPDOWNGRID]),
 
   Combobox: new BaseTraversalRule(
     [ROLE_COMBOBOX,
      ROLE_LISTBOX]),
 
+  Landmark: new BaseTraversalRule(
+    [],
+    function Landmark_match(aAccessible) {
+      return Utils.getLandmarkName(aAccessible) ? FILTER_MATCH :
+        FILTER_IGNORE;
+    }
+  ),
+
   Entry: new BaseTraversalRule(
     [ROLE_ENTRY,
      ROLE_PASSWORD_TEXT]),
 
   FormElement: new BaseTraversalRule(
     [ROLE_PUSHBUTTON,
      ROLE_SPINBUTTON,
      ROLE_TOGGLE_BUTTON,
--- a/accessible/src/jsat/Utils.jsm
+++ b/accessible/src/jsat/Utils.jsm
@@ -229,17 +229,18 @@ this.Utils = {
   getBounds: function getBounds(aAccessible) {
       let objX = {}, objY = {}, objW = {}, objH = {};
       aAccessible.getBounds(objX, objY, objW, objH);
       return new Rect(objX.value, objY.value, objW.value, objH.value);
   },
 
   inHiddenSubtree: function inHiddenSubtree(aAccessible) {
     for (let acc=aAccessible; acc; acc=acc.parent) {
-      if (JSON.parse(Utils.getAttributes(acc).hidden)) {
+      let hidden = Utils.getAttributes(acc).hidden;
+      if (hidden && JSON.parse(hidden)) {
         return true;
       }
     }
     return false;
   },
 
   isAliveAndVisible: function isAliveAndVisible(aAccessible) {
     if (!aAccessible) {
@@ -255,16 +256,38 @@ this.Utils = {
           Utils.inHiddenSubtree(aAccessible)) {
         return false;
       }
     } catch (x) {
       return false;
     }
 
     return true;
+  },
+
+  getLandmarkName: function getLandmarkName(aAccessible) {
+    const landmarks = [
+      'banner',
+      'complementary',
+      'contentinfo',
+      'main',
+      'navigation',
+      'search'
+    ];
+    let roles = this.getAttributes(aAccessible)['xml-roles'];
+    if (!roles) {
+      return;
+    }
+
+    // Looking up a role that would match a landmark.
+    for (let landmark of landmarks) {
+      if (roles.indexOf(landmark) > -1) {
+        return landmark;
+      }
+    }
   }
 };
 
 this.Logger = {
   DEBUG: 0,
   INFO: 1,
   WARNING: 2,
   ERROR: 3,
--- a/accessible/src/jsat/content-script.js
+++ b/accessible/src/jsat/content-script.js
@@ -21,110 +21,146 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   'resource://gre/modules/accessibility/EventManager.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'ObjectWrapper',
   'resource://gre/modules/ObjectWrapper.jsm');
 
 Logger.debug('content-script.js');
 
 let eventManager = null;
 
-function virtualCursorControl(aMessage) {
-  if (Logger.logLevel >= Logger.DEBUG)
-    Logger.debug(aMessage.name, JSON.stringify(aMessage.json));
+function moveCursor(aMessage) {
+  if (Logger.logLevel >= Logger.DEBUG) {
+    Logger.debug(aMessage.name, JSON.stringify(aMessage.json, null, ' '));
+  }
 
-  try {
-    let vc = Utils.getVirtualCursor(content.document);
-    let origin = aMessage.json.origin;
-    if (origin != 'child') {
-      if (forwardMessage(vc, aMessage))
-        return;
-    }
+  let vc = Utils.getVirtualCursor(content.document);
+  let origin = aMessage.json.origin;
+  let action = aMessage.json.action;
+  let rule = TraversalRules[aMessage.json.rule];
 
-    let details = aMessage.json;
-    let rule = TraversalRules[details.rule];
-    let moved = 0;
-    switch (details.action) {
-    case 'moveFirst':
-    case 'moveLast':
-      moved = vc[details.action](rule);
-      break;
-    case 'moveNext':
-    case 'movePrevious':
-      try {
-        if (origin == 'parent' && vc.position == null) {
-          if (details.action == 'moveNext')
-            moved = vc.moveFirst(rule);
-          else
-            moved = vc.moveLast(rule);
-        } else {
-          moved = vc[details.action](rule);
-        }
-      } catch (x) {
-        let acc = Utils.AccRetrieval.
-          getAccessibleFor(content.document.activeElement);
-        moved = vc.moveNext(rule, acc, true);
-      }
-      break;
-    case 'moveToPoint':
-      if (!this._ppcp) {
-        this._ppcp = Utils.getPixelsPerCSSPixel(content);
-      }
-      moved = vc.moveToPoint(rule,
-                             details.x * this._ppcp, details.y * this._ppcp,
-                             true);
-      break;
-    case 'whereIsIt':
-      if (!forwardMessage(vc, aMessage)) {
-        if (!vc.position && aMessage.json.move)
-          vc.moveFirst(TraversalRules.Simple);
-        else {
-          sendAsyncMessage('AccessFu:Present', Presentation.pivotChanged(
-            vc.position, null, Ci.nsIAccessiblePivot.REASON_NONE));
+  function moveCursorInner() {
+    try {
+      if (origin == 'parent' &&
+          !Utils.isAliveAndVisible(vc.position)) {
+        // We have a bad position in this frame, move vc to last or first item.
+        if (action == 'moveNext') {
+          return vc.moveFirst(rule);
+        } else if (action == 'movePrevious') {
+          return vc.moveLast(rule);
         }
       }
 
-      break;
-    default:
-      break;
+      return vc[action](rule);
+    } catch (x) {
+      if (action == 'moveNext' || action == 'movePrevious') {
+        // If we are trying to move next/prev put the vc on the focused item.
+        let acc = Utils.AccRetrieval.
+          getAccessibleFor(content.document.activeElement);
+        return vc.moveNext(rule, acc, true);
+      } else {
+        throw x;
+      }
     }
 
-    if (moved == true) {
-      forwardMessage(vc, aMessage);
-    } else if (moved == false && details.action != 'moveToPoint') {
+    return false;
+  }
+
+  try {
+    if (origin != 'child' &&
+        forwardToChild(aMessage, moveCursor, vc.position)) {
+      // We successfully forwarded the move to the child document.
+      return;
+    }
+
+    if (moveCursorInner()) {
+      // If we moved, try forwarding the message to the new position,
+      // it may be a frame with a vc of its own.
+      forwardToChild(aMessage, moveCursor, vc.position);
+    } else {
+      // If we did not move, we probably reached the end or start of the
+      // document, go back to parent content and move us out of the iframe.
       if (origin == 'parent') {
         vc.position = null;
       }
-      aMessage.json.origin = 'child';
-      sendAsyncMessage('AccessFu:VirtualCursor', aMessage.json);
+      forwardToParent(aMessage);
     }
   } catch (x) {
-    Logger.logException(x, 'Failed to move virtual cursor');
+    Logger.logException(x, 'Cursor move failed');
   }
 }
 
-function forwardMessage(aVirtualCursor, aMessage) {
+function moveToPoint(aMessage) {
+  if (Logger.logLevel >= Logger.DEBUG) {
+    Logger.debug(aMessage.name, JSON.stringify(aMessage.json, null, ' '));
+  }
+
+  let vc = Utils.getVirtualCursor(content.document);
+  let details = aMessage.json;
+  let rule = TraversalRules[details.rule];
+
   try {
-    let acc = aVirtualCursor.position;
-    if (acc && acc.role == ROLE_INTERNAL_FRAME) {
-      let mm = Utils.getMessageManager(acc.DOMNode);
-      mm.addMessageListener(aMessage.name, virtualCursorControl);
-      aMessage.json.origin = 'parent';
-      if (Utils.isContentProcess) {
-        // XXX: OOP content's screen offset is 0,
-        // so we remove the real screen offset here.
-        aMessage.json.x -= content.mozInnerScreenX;
-        aMessage.json.y -= content.mozInnerScreenY;
-      }
-      mm.sendAsyncMessage(aMessage.name, aMessage.json);
-      return true;
+    if (!this._ppcp) {
+      this._ppcp = Utils.getPixelsPerCSSPixel(content);
+    }
+    vc.moveToPoint(rule, details.x * this._ppcp, details.y * this._ppcp, true);
+    forwardToChild(aMessage, moveToPoint, vc.position);
+  } catch (x) {
+    Logger.logException(x, 'Failed move to point');
+  }
+}
+
+function showCurrent(aMessage) {
+  if (Logger.logLevel >= Logger.DEBUG) {
+    Logger.debug(aMessage.name, JSON.stringify(aMessage.json, null, ' '));
+  }
+
+  let vc = Utils.getVirtualCursor(content.document);
+
+  if (!forwardToChild(vc, showCurrent, aMessage)) {
+    if (!vc.position && aMessage.json.move) {
+      vc.moveFirst(TraversalRules.Simple);
+    } else {
+      sendAsyncMessage('AccessFu:Present', Presentation.pivotChanged(
+                         vc.position, null, Ci.nsIAccessiblePivot.REASON_NONE));
     }
-  } catch (x) {
-    // Frame may be hidden, we regard this case as false.
+  }
+}
+
+function forwardToParent(aMessage) {
+  // XXX: This is a silly way to make a deep copy
+  let newJSON = JSON.parse(JSON.stringify(aMessage.json));
+  newJSON.origin = 'child';
+  sendAsyncMessage(aMessage.name, newJSON);
+}
+
+function forwardToChild(aMessage, aListener, aVCPosition) {
+  let acc = aVCPosition || Utils.getVirtualCursor(content.document).position;
+
+  if (!Utils.isAliveAndVisible(acc) || acc.role != ROLE_INTERNAL_FRAME) {
+    return false;
   }
-  return false;
+
+  if (Logger.logLevel >= Logger.DEBUG) {
+    Logger.debug('forwardToChild', Logger.accessibleToString(acc),
+                 aMessage.name, JSON.stringify(aMessage.json, null, '  '));
+  }
+
+  let mm = Utils.getMessageManager(acc.DOMNode);
+  mm.addMessageListener(aMessage.name, aListener);
+  // XXX: This is a silly way to make a deep copy
+  let newJSON = JSON.parse(JSON.stringify(aMessage.json));
+  newJSON.origin = 'parent';
+  if (Utils.isContentProcess) {
+    // XXX: OOP content's screen offset is 0,
+    // so we remove the real screen offset here.
+    newJSON.x -= content.mozInnerScreenX;
+    newJSON.y -= content.mozInnerScreenY;
+  }
+  mm.sendAsyncMessage(aMessage.name, newJSON);
+  return true;
 }
 
 function activateCurrent(aMessage) {
   Logger.debug('activateCurrent');
   function activateAccessible(aAccessible) {
     if (aAccessible.actionCount > 0) {
       aAccessible.doAction(0);
     } else {
@@ -169,33 +205,34 @@ function activateCurrent(aMessage) {
   }
 
   let focusedAcc = Utils.AccRetrieval.getAccessibleFor(content.document.activeElement);
   if (focusedAcc && focusedAcc.role === ROLE_ENTRY) {
     moveCaretTo(focusedAcc, aMessage.json.offset);
     return;
   }
 
-  let vc = Utils.getVirtualCursor(content.document);
-  if (!forwardMessage(vc, aMessage))
-    activateAccessible(vc.position);
+  let position = Utils.getVirtualCursor(content.document).position;
+  if (!forwardToChild(aMessage, activateCurrent, position)) {
+    activateAccessible(position);
+  }
 }
 
 function activateContextMenu(aMessage) {
   function sendContextMenuCoordinates(aAccessible) {
-    let objX = {}, objY = {}, objW = {}, objH = {};
-    aAccessible.getBounds(objX, objY, objW, objH);
-    let x = objX.value + objW.value / 2;
-    let y = objY.value + objH.value / 2;
-    sendAsyncMessage('AccessFu:ActivateContextMenu', {x: x, y: y});
+    let bounds = Utils.getBounds(aAccessible);
+    sendAsyncMessage('AccessFu:ActivateContextMenu',
+                     { x: bounds.left + bounds.width / 2,
+                       y: bounds.top + bounds.height / 2 });
   }
 
-  let vc = Utils.getVirtualCursor(content.document);
-  if (!forwardMessage(vc, aMessage))
-    sendContextMenuCoordinates(vc.position);
+  let position = Utils.getVirtualCursor(content.document).position;
+  if (!forwardToChild(aMessage, activateContextMenu, position)) {
+    sendContextMenuCoordinates(position);
+  }
 }
 
 function moveCaret(aMessage) {
   const MOVEMENT_GRANULARITY_CHARACTER = 1;
   const MOVEMENT_GRANULARITY_WORD = 2;
   const MOVEMENT_GRANULARITY_PARAGRAPH = 8;
 
   let direction = aMessage.json.direction;
@@ -238,17 +275,17 @@ function moveCaret(aMessage) {
   }
 
   presentCaretChange(text, oldOffset, accText.caretOffset);
 }
 
 function presentCaretChange(aText, aOldOffset, aNewOffset) {
   if (aOldOffset !== aNewOffset) {
     let msg = Presentation.textSelectionChanged(aText, aNewOffset, aNewOffset,
-                                                aOldOffset, aOldOffset);
+                                                aOldOffset, aOldOffset, true);
     sendAsyncMessage('AccessFu:Present', msg);
   }
 }
 
 function scroll(aMessage) {
   let vc = Utils.getVirtualCursor(content.document);
 
   function tryToScroll() {
@@ -310,53 +347,56 @@ function scroll(aMessage) {
                 (page < 0 && content.scrollX > 0))) {
       content.scroll(content.innerWidth * page + content.scrollX);
       return true;
     }
 
     return false;
   }
 
-  if (aMessage.json.origin != 'child') {
-    if (forwardMessage(vc, aMessage))
-      return;
+  if (aMessage.json.origin != 'child' &&
+      forwardToChild(aMessage, scroll, vc.position)) {
+    return;
   }
 
   if (!tryToScroll()) {
     // Failed to scroll anything in this document. Try in parent document.
-    aMessage.json.origin = 'child';
-    sendAsyncMessage('AccessFu:Scroll', aMessage.json);
+    forwardToParent(aMessage);
   }
 }
 
 addMessageListener(
   'AccessFu:Start',
   function(m) {
     Logger.debug('AccessFu:Start');
     if (m.json.buildApp)
       Utils.MozBuildApp = m.json.buildApp;
 
-    addMessageListener('AccessFu:VirtualCursor', virtualCursorControl);
+    addMessageListener('AccessFu:MoveToPoint', moveToPoint);
+    addMessageListener('AccessFu:MoveCursor', moveCursor);
+    addMessageListener('AccessFu:ShowCurrent', showCurrent);
     addMessageListener('AccessFu:Activate', activateCurrent);
     addMessageListener('AccessFu:ContextMenu', activateContextMenu);
     addMessageListener('AccessFu:Scroll', scroll);
     addMessageListener('AccessFu:MoveCaret', moveCaret);
 
     if (!eventManager) {
       eventManager = new EventManager(this);
     }
     eventManager.start();
   });
 
 addMessageListener(
   'AccessFu:Stop',
   function(m) {
     Logger.debug('AccessFu:Stop');
 
-    removeMessageListener('AccessFu:VirtualCursor', virtualCursorControl);
+    removeMessageListener('AccessFu:MoveToPoint', moveToPoint);
+    removeMessageListener('AccessFu:MoveCursor', moveCursor);
+    removeMessageListener('AccessFu:ShowCurrent', showCurrent);
     removeMessageListener('AccessFu:Activate', activateCurrent);
     removeMessageListener('AccessFu:ContextMenu', activateContextMenu);
     removeMessageListener('AccessFu:Scroll', scroll);
     removeMessageListener('AccessFu:MoveCaret', moveCaret);
 
     eventManager.stop();
   });
 
--- a/accessible/src/mac/Makefile.in
+++ b/accessible/src/mac/Makefile.in
@@ -8,19 +8,16 @@ srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 EXPORT_LIBRARY = ..
 LIBXUL_LIBRARY = 1
 
 
-# we don't want the shared lib, but we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../base \
   -I$(srcdir)/../generic \
   -I$(srcdir)/../html \
   -I$(srcdir)/../xul \
--- a/accessible/src/other/Makefile.in
+++ b/accessible/src/other/Makefile.in
@@ -7,19 +7,16 @@ topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 EXPORT_LIBRARY = ..
 LIBXUL_LIBRARY = 1
 
-# we don't want the shared lib, but we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../base \
   -I$(srcdir)/../generic \
   -I$(srcdir)/../html \
   -I$(srcdir)/../xul \
--- a/accessible/src/windows/ia2/Makefile.in
+++ b/accessible/src/windows/ia2/Makefile.in
@@ -12,20 +12,16 @@ include $(DEPTH)/config/autoconf.mk
 LIBRARY_NAME = accessibility_toolkit_ia2_s
 EXPORT_LIBRARY = 1
 LIBXUL_LIBRARY = 1
 
 # The midl generated code include Windows headers which defines min and max
 # macros which conflicts with std::min/max.  Suppress the macros:
 OS_CXXFLAGS += -DNOMINMAX
 
-# we don't want the shared lib, but we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
-include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../msaa \
   -I$(srcdir)/../../base \
   -I$(srcdir)/../../generic \
   -I$(srcdir)/../../html \
--- a/accessible/src/windows/msaa/Makefile.in
+++ b/accessible/src/windows/msaa/Makefile.in
@@ -8,22 +8,19 @@ srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_toolkit_msaa_s
 EXPORT_LIBRARY = 1
 LIBXUL_LIBRARY = 1
 
-# we don't want the shared lib, but we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
 include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/config/rules.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
-include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../../base \
   -I$(srcdir)/../../generic \
   -I$(srcdir)/../../html \
   -I$(srcdir)/../../xpcom \
   -I$(srcdir)/../../xul \
--- a/accessible/src/windows/sdn/Makefile.in
+++ b/accessible/src/windows/sdn/Makefile.in
@@ -11,20 +11,16 @@ include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_toolkit_sdn_s
 EXPORT_LIBRARY = 1
 LIBXUL_LIBRARY = 1
 # The midl generated code include Windows headers which defines min and max
 # macros which conflicts with std::min/max.  Suppress the macros:
 OS_CXXFLAGS += -DNOMINMAX
 
-# we don't want the shared lib, but we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
-include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../msaa \
   -I$(srcdir)/../../base \
   -I$(srcdir)/../../generic \
   -I$(srcdir)/../../html \
--- a/accessible/src/windows/uia/Makefile.in
+++ b/accessible/src/windows/uia/Makefile.in
@@ -11,20 +11,16 @@ include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME = accessibility_toolkit_uia_s
 EXPORT_LIBRARY = ..
 LIBXUL_LIBRARY = 1
 # The midl generated code include Windows headers which defines min and max
 # macros which conflicts with std::min/max.  Suppress the macros:
 OS_CXXFLAGS += -DNOMINMAX
 
-# we don't want the shared lib, but we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
-include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../msaa \
   -I$(srcdir)/../../base \
   -I$(srcdir)/../../generic \
   -I$(srcdir)/../../html \
--- a/accessible/src/xpcom/Makefile.in
+++ b/accessible/src/xpcom/Makefile.in
@@ -7,19 +7,16 @@ DEPTH = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBXUL_LIBRARY = 1
 
-# we don't want the shared lib, but we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
 EXTRA_MDDEPEND_FILES = xpcAccEvents.pp
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir)/../base \
   -I$(srcdir)/../generic \
   $(NULL)
--- a/accessible/src/xul/Makefile.in
+++ b/accessible/src/xul/Makefile.in
@@ -7,19 +7,16 @@ DEPTH = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBXUL_LIBRARY = 1
 
-# we don't want the shared lib, but we want to force the creation of a static lib.
-FORCE_STATIC_LIB = 1
-
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir) \
   -I$(srcdir)/../base \
   -I$(srcdir)/../generic \
   -I$(srcdir)/../html \
   -I$(srcdir)/../xpcom \
--- a/accessible/tests/mochitest/jsat/test_landmarks.html
+++ b/accessible/tests/mochitest/jsat/test_landmarks.html
@@ -67,19 +67,19 @@
       }, {
         accOrElmOrID: "main_element",
         expectedUtterance: [["main", "another main area"], [
           "another main area", "main"]],
         expectedBraille: [["main", "another main area"], ["another main area",
           "main"]]
       }, {
         accOrElmOrID: "complementary",
-        expectedUtterance: [["list 1 items", "complementary", "First item",
+        expectedUtterance: [["list 1 item", "complementary", "First item",
           "A complementary"], ["A complementary", "First item",
-          "complementary", "list 1 items"]],
+          "complementary", "list 1 item"]],
         // XXX: The '*' should probably come before all of the context
         // utterance.
         expectedBraille: [["complementary", "*", "A complementary"], ["*",
           "A complementary", "complementary"]]
       }, {
         accOrElmOrID: "parent_main",
         expectedUtterance: [["main", "a parent main", "complementary",
           "a child complementary"], ["a parent main", "a child complementary",
--- a/accessible/tests/mochitest/jsat/test_utterance_order.html
+++ b/accessible/tests/mochitest/jsat/test_utterance_order.html
@@ -34,30 +34,30 @@ https://bugzilla.mozilla.org/show_bug.cg
           accOrElmOrID: "heading",
           expected: [
             ["heading level 1", "Test heading"],
             ["Test heading", "heading level 1"]
           ]
         }, {
           accOrElmOrID: "list",
           expected: [
-            ["list 1 items", "First item", "1.", "list one"],
-            ["1.", "list one", "First item", "list 1 items"]
+            ["list 1 item", "First item", "1.", "list one"],
+            ["1.", "list one", "First item", "list 1 item"]
           ]
         }, {
           accOrElmOrID: "dlist",
           expected: [
             ["definition list 0.5 items", "dd one"],
             ["dd one", "definition list 0.5 items"]
           ]
         }, {
           accOrElmOrID: "li_one",
           expected: [
-            ["list 1 items", "First item", "1.", "list one"],
-            ["1.", "list one", "First item", "list 1 items"]
+            ["list 1 item", "First item", "1.", "list one"],
+            ["1.", "list one", "First item", "list 1 item"]
           ]
         }, {
           accOrElmOrID: "cell",
           expected: [[
             "table with 1 column and 1 row", "Fruits and vegetables",
             "Column 1 Row 1", "list 4 items", "First item", "link", "Apples",
             "link", "Bananas", "link", "Peaches", "Last item", "link", "Plums"
           ], [
@@ -66,18 +66,18 @@ https://bugzilla.mozilla.org/show_bug.cg
             "Column 1 Row 1", "Fruits and vegetables",
             "table with 1 column and 1 row"
           ]]
         }, {
           // Test pivot to list from li_one.
           accOrElmOrID: "list",
           oldAccOrElmOrID: "li_one",
           expected: [
-            ["list 1 items", "First item", "1.", "list one"],
-            ["1.", "list one", "First item", "list 1 items"]
+            ["list 1 item", "First item", "1.", "list one"],
+            ["1.", "list one", "First item", "list 1 item"]
           ]
         }, {
           // Test pivot to "apples" link from the table cell.
           accOrElmOrID: "apples",
           oldAccOrElmOrID: "cell",
           expected: [
             ["list 4 items", "First item", "link", "Apples"],
             ["Apples", "link", "First item", "list 4 items"]
--- a/accessible/tests/mochitest/pivot.js
+++ b/accessible/tests/mochitest/pivot.js
@@ -71,32 +71,42 @@ var ObjectTraversalRule =
 
 /**
  * A checker for virtual cursor changed events.
  */
 function VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets, aPivotMoveMethod)
 {
   this.__proto__ = new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc);
 
+  this.match = function VCChangedChecker_check(aEvent)
+  {
+    var event = null;
+    try {
+      event = aEvent.QueryInterface(nsIAccessibleVirtualCursorChangeEvent);
+    } catch (e) {
+      return false;
+    }
+
+    var expectedReason = VCChangedChecker.methodReasonMap[aPivotMoveMethod] ||
+      nsIAccessiblePivot.REASON_NONE;
+
+    return event.reason == expectedReason;
+  };
+
   this.check = function VCChangedChecker_check(aEvent)
   {
     SimpleTest.info("VCChangedChecker_check");
 
     var event = null;
     try {
       event = aEvent.QueryInterface(nsIAccessibleVirtualCursorChangeEvent);
     } catch (e) {
       SimpleTest.ok(false, "Does not support correct interface: " + e);
     }
 
-    SimpleTest.is(
-      event.reason,
-      VCChangedChecker.methodReasonMap[aPivotMoveMethod],
-      'wrong move reason');
-
     var position = aDocAcc.virtualCursor.position;
     var idMatches = position && position.DOMNode.id == aIdOrNameOrAcc;
     var nameMatches = position && position.name == aIdOrNameOrAcc;
     var accMatches = position == aIdOrNameOrAcc;
 
     SimpleTest.ok(idMatches || nameMatches || accMatches, "id or name matches",
                   "expecting " + aIdOrNameOrAcc + ", got '" +
                   prettyName(position));
@@ -191,19 +201,24 @@ function setVCRangeInvoker(aDocAcc, aTex
  */
 function setVCPosInvoker(aDocAcc, aPivotMoveMethod, aRule, aIdOrNameOrAcc)
 {
   var expectMove = (aIdOrNameOrAcc != false);
   this.invoke = function virtualCursorChangedInvoker_invoke()
   {
     VCChangedChecker.
       storePreviousPosAndOffset(aDocAcc.virtualCursor);
-    var moved = aDocAcc.virtualCursor[aPivotMoveMethod](aRule);
-    SimpleTest.ok((expectMove && moved) || (!expectMove && !moved),
-                  "moved pivot");
+    if (aPivotMoveMethod && aRule) {
+      var moved = aDocAcc.virtualCursor[aPivotMoveMethod](aRule);
+      SimpleTest.is(!!moved, !!expectMove,
+                    "moved pivot with " + aPivotMoveMethod +
+                    " to " + aIdOrNameOrAcc);
+    } else {
+      aDocAcc.virtualCursor.position = getAccessible(aIdOrNameOrAcc);
+    }
   };
 
   this.getID = function setVCPosInvoker_getID()
   {
     return "Do " + (expectMove ? "" : "no-op ") + aPivotMoveMethod;
   };
 
   if (expectMove) {
@@ -442,16 +457,16 @@ function removeVCRootInvoker(aRootNode)
   ];
 }
 
 /**
  * A debug utility for writing proper sequences for queueTraversalSequence.
  */
 function dumpTraversalSequence(aPivot, aRule)
 {
-  var sequence = []
+  var sequence = [];
   if (aPivot.moveFirst(aRule)) {
     do {
       sequence.push("'" + prettyName(aPivot.position) + "'");
     } while (aPivot.moveNext(aRule))
   }
   SimpleTest.info("\n[" + sequence.join(", ") + "]\n");
 }
--- a/accessible/tests/mochitest/pivot/doc_virtualcursor.html
+++ b/accessible/tests/mochitest/pivot/doc_virtualcursor.html
@@ -10,17 +10,17 @@
   <p id="paragraph-1">
     Lorem ipsum <strong>dolor</strong> sit amet. Integer vitae urna
     leo, id <a href="#">semper</a> nulla.
   </p>
   <h2 id="heading-2-2" aria-hidden="undefined">Second Section Title</h2>
   <p id="paragraph-2" aria-hidden="">
     Sed accumsan luctus lacus, vitae mollis arcu tristique vulputate.</p>
   <p id="paragraph-3" aria-hidden="true">
-    Maybe it was the other <i>George Michael</i>.
+    <a href="#" id="hidden-link">Maybe</a> it was the other <i>George Michael</i>.
     You know, the <a href="#">singer-songwriter</a>.
   </p>
   <iframe
      src="data:text/html,<html><body>An <i>embedded</i> document.</body></html>">
   </iframe>
   <div id="hide-me">Hide me</div>
   <p id="links" aria-hidden="false">
     <a href="http://mozilla.org" title="Link 1 title">Link 1</a>
--- a/accessible/tests/mochitest/pivot/test_virtualcursor.html
+++ b/accessible/tests/mochitest/pivot/test_virtualcursor.html
@@ -90,16 +90,22 @@
         gQueue, docAcc, ObjectTraversalRule,
         getAccessible(doc.getElementById('paragraph-1')),
         ['Lorem ipsum ', 'dolor', ' sit amet. Integer vitae urna leo, id ',
          'semper', ' nulla. ']);
 
       gQueue.push(new setModalRootInvoker(docAcc, docAcc.parent,
                                           NS_ERROR_INVALID_ARG));
 
+      // Put cursor in an ignored subtree
+      gQueue.push(new setVCPosInvoker(docAcc, null, null,
+                                      getAccessible(doc.getElementById("hidden-link"))));
+      // Next item shoud be outside of that subtree
+      gQueue.push(new setVCPosInvoker(docAcc, "moveNext", ObjectTraversalRule, "An "));
+
       gQueue.invoke();
     }
 
     SimpleTest.waitForExplicitFinish();
     addLoadEvent(function () {
       /* We open a new browser because we need to test with a top-level content
          document. */
       openBrowserWindow(
--- a/accessible/tests/mochitest/text/test_atcaretoffset.html
+++ b/accessible/tests/mochitest/text/test_atcaretoffset.html
@@ -39,57 +39,57 @@
       this.__proto__ = new synthFocus("textarea");
 
       this.finalCheck = function moveToLastLineEnd_finalCheck()
       {
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_START, "", 15, 15,
                             ["textarea"]);
 
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_END, "", 15, 15,
-                            "textarea", kOk, kTodo, kTodo);
+                            [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_START, "words", 10, 15,
                          [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_END, "words", 10, 15,
                          [ "textarea" ]);
 
-        testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_START, "words", 10, 15,
-                             "textarea", kOk, kOk, kOk);
+        testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_START, "two ", 6, 10,
+                             [ "textarea" ]);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_END, "\ntwo ", 5, 10,
-                             "textarea", kTodo, kTodo, kTodo);
+                             "textarea", kTodo, kTodo, kOk);
       }
 
       this.getID = function moveToLastLineEnd_getID()
       {
         return "move to last line end";
       }
     }
 
     function moveToLastLineStart()
     {
       this.__proto__ = new moveToLineStart("textarea", 10);
 
       this.finalCheck = function moveToLastLineStart_finalCheck()
       {
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_START, "", 15, 15,
-                            "textarea", kTodo, kTodo, kOk);
+                            [ "textarea" ]);
 
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_END, "", 15, 15,
-                            "textarea", kTodo, kTodo, kOk);
+                            [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_START, "words", 10, 15,
                          [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_END, "words", 10, 15,
                          [ "textarea" ]);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_START, "two ", 6, 10,
-                             "textarea", kTodo, kTodo, kOk);
+                             [ "textarea" ]);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_END, "\ntwo ", 5, 10,
                              "textarea", kTodo, kTodo, kOk);
       }
 
       this.getID = function moveToLastLineStart_getID()
       {
         return "move to last line start";
@@ -99,91 +99,91 @@
     function moveToMiddleLineStart()
     {
       this.__proto__ = new synthUpKey("textarea",
                                       new caretMoveChecker(6, "textarea"));
 
       this.finalCheck = function moveToMiddleLineStart_finalCheck()
       {
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_START, "words", 10, 15,
-                            "textarea", kTodo, kTodo, kTodo);
+                            [ "textarea" ]);
 
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_END, "words", 10, 15,
-                            "textarea", kTodo, kTodo, kTodo);
+                            [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_START, "two ", 6, 10,
                          [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_END, "\ntwo ", 5, 10,
                          [ "textarea" ]);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_START, "aword\n", 0, 6,
-                             "textarea", kTodo, kTodo, kOk);
+                             [ "textarea" ]);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_END, "aword", 0, 5,
-                             "textarea", kTodo, kTodo, kTodo);
+                             [ "textarea" ]);
       }
 
       this.getID = function moveToMiddleLineStart_getID()
       {
         return "move to middle line start";
       }
     }
 
     function moveToMiddleLineEnd()
     {
       this.__proto__ = new moveToLineEnd("textarea", 10);
 
       this.finalCheck = function moveToMiddleLineEnd_finalCheck()
       {
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_START, "words", 10, 15,
-                            "textarea", kTodo, kTodo, kTodo);
+                            [ "textarea" ]);
 
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_END, "words", 10, 15,
-                            "textarea", kTodo, kTodo, kOk);
+                            [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_START, "two ", 6, 10,
                          [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_END, "\ntwo ", 5, 10,
                          [ "textarea" ]);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_START, "aword\n", 0, 6,
-                             "textarea", kTodo, kTodo, kTodo);
+                             [ "textarea" ]);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_END, "aword", 0, 5,
-                             "textarea", kTodo, kTodo, kTodo);
+                             [ "textarea" ]);
       }
 
       this.getID = function moveToMiddleLineEnd_getID()
       {
         return "move to middle line end";
       }
     }
 
     function moveToFirstLineStart()
     {
       this.__proto__ = new moveToTextStart("textarea");
 
       this.finalCheck = function moveToFirstLineStart_finalCheck()
       {
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_START, "two ", 6, 10,
-                            "textarea", kTodo, kTodo, kTodo);
+                            [ "textarea" ]);
 
-        testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_END, "aword", 0, 5,
-                            "textarea", kOk, kOk, kOk);
+        testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_END, "\ntwo ", 5, 10,
+                            [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_START, "aword\n", 0, 6,
                          [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_END, "aword", 0, 5,
                          [ "textarea" ]);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_START, "", 0, 0,
-                             "textarea", kOk, kOk, kOk);
+                             [ "textarea" ]);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_END, "", 0, 0,
                              "textarea", kOk, kOk, kOk);
       }
 
       this.getID = function moveToFirstLineStart_getID()
       {
         return "move to first line start";
@@ -192,45 +192,43 @@
 
     function moveToFirstLineEnd()
     {
       this.__proto__ = new moveToLineEnd("textarea", 5);
 
       this.finalCheck = function moveToFirstLineStart_finalCheck()
       {
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_START, "two ", 6, 10,
-                            "textarea", kTodo, kTodo, kTodo);
+                            [ "textarea" ]);
 
         testTextAfterOffset(kCaretOffset, BOUNDARY_LINE_END, "\ntwo ", 5, 10,
-                            "textarea", kTodo, kTodo, kTodo);
+                            [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_START, "aword\n", 0, 6,
                          [ "textarea" ]);
 
         testTextAtOffset(kCaretOffset, BOUNDARY_LINE_END, "aword", 0, 5,
                          [ "textarea" ]);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_START, "", 0, 0,
-                             "textarea", kTodo, kOk, kTodo);
+                             [ "textarea" ]);
 
         testTextBeforeOffset(kCaretOffset, BOUNDARY_LINE_END, "", 0, 0,
-                             "textarea", kTodo, kOk, kTodo);
+                             [ "textarea" ]);
       }
 
       this.getID = function moveToFirstLineEnd_getID()
       {
         return "move to first line end";
       }
     }
 
     var gQueue = null;
     function doTest()
     {
-      SimpleTest.expectAssertions(6);
-
       gQueue = new eventQueue();
       gQueue.push(new moveToLastLineEnd());
       gQueue.push(new moveToLastLineStart());
       gQueue.push(new moveToMiddleLineStart());
       gQueue.push(new moveToMiddleLineEnd());
       gQueue.push(new moveToFirstLineStart());
       gQueue.push(new moveToFirstLineEnd());
       gQueue.invoke(); // will call SimpleTest.finish();
--- a/accessible/tests/mochitest/text/test_multiline.html
+++ b/accessible/tests/mochitest/text/test_multiline.html
@@ -11,175 +11,63 @@
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../text.js"></script>
   <script type="application/javascript">
 
     function doTest()
     {
-      SimpleTest.expectAssertions(35);
-
       // __o__n__e__w__o__r__d__\n
       //  0  1  2  3  4  5  6  7
       // __\n
       //  8
       // __t__w__o__ __w__o__r__d__s__\n
       //  9 10 11 12 13 14 15 16 17 18
 
       ////////////////////////////////////////////////////////////////////////
       // getText
 
       var IDs = ["div", "divbr", "editable", "editablebr", "textarea"];
 
       ////////////////////////////////////////////////////////////////////////
       // getTextAfterOffset
 
       // BOUNDARY_LINE_START
-      testTextAfterOffset(0, BOUNDARY_LINE_START, "\n", 8, 9,
-                          "div", kTodo, kTodo, kTodo,
-                          "divbr", kTodo, kTodo, kTodo,
-                          "editable", kTodo, kTodo, kTodo,
-                          "editablebr", kTodo, kTodo, kTodo,
-                          "textarea", kTodo, kTodo, kTodo);
-      testTextAfterOffset(7, BOUNDARY_LINE_START, "\n", 8, 9,
-                          "div", kOk, kTodo, kTodo,
-                          "divbr", kOk, kTodo, kTodo,
-                          "editable", kOk, kTodo, kTodo,
-                          "editablebr", kOk, kTodo, kTodo,
-                          "textarea", kOk, kTodo, kTodo);
-      testTextAfterOffset(8, BOUNDARY_LINE_START, "two words\n", 9, 19,
-                          "div", kTodo, kTodo, kTodo,
-                          "divbr", kTodo, kTodo, kTodo,
-                          "editable", kTodo, kTodo, kTodo,
-                          "editablebr", kTodo, kTodo, kTodo,
-                          "textarea", kTodo, kTodo, kTodo);
-      testTextAfterOffset(9, BOUNDARY_LINE_START, "", 19, 19,
-                          "div", kTodo, kTodo, kTodo,
-                          "divbr", kTodo, kTodo, kTodo,
-                          "editable", kTodo, kTodo, kTodo,
-                          "editablebr", kTodo, kTodo, kTodo,
-                          "textarea", kTodo, kTodo, kTodo);
-      testTextAfterOffset(19, BOUNDARY_LINE_START, "", 19, 19,
-                          "div", kOk, kOk, kTodo,
-                          "divbr", kOk, kOk, kTodo,
-                          "editable", kOk, kOk, kTodo,
-                          "editablebr", kOk, kOk, kTodo,
-                          "textarea", kOk, kOk, kTodo);
+      testTextAfterOffset(0, BOUNDARY_LINE_START, "\n", 8, 9, IDs);
+      testTextAfterOffset(7, BOUNDARY_LINE_START, "\n", 8, 9, IDs);
+      testTextAfterOffset(8, BOUNDARY_LINE_START, "two words\n", 9, 19, IDs);
+      testTextAfterOffset(9, BOUNDARY_LINE_START, "", 19, 19, IDs);
+      testTextAfterOffset(19, BOUNDARY_LINE_START, "", 19, 19, IDs);
 
       // BOUNDARY_LINE_END
-      testTextAfterOffset(0, BOUNDARY_LINE_END, "\n", 7, 8,
-                          "div", kTodo, kTodo, kTodo,
-                          "divbr", kTodo, kTodo, kTodo,
-                          "editable", kTodo, kTodo, kTodo,
-                          "editablebr", kTodo, kTodo, kTodo,
-                          "textarea", kTodo, kTodo, kTodo);
-      testTextAfterOffset(7, BOUNDARY_LINE_END, "\n", 7, 8,
-                          "div", kOk, kOk, kOk,
-                          "divbr", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "editablebr", kOk, kOk, kOk,
-                          "textarea", kOk, kOk, kOk);
-      testTextAfterOffset(8, BOUNDARY_LINE_END, "\ntwo words", 8, 18,
-                          "div", kOk, kOk, kOk,
-                          "divbr", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "editablebr", kOk, kOk, kOk,
-                          "textarea", kOk, kOk, kOk);
-      testTextAfterOffset(9, BOUNDARY_LINE_END, "\n", 18, 19,
-                          "div", kTodo, kTodo, kTodo,
-                          "divbr", kTodo, kTodo, kTodo,
-                          "editable", kTodo, kTodo, kTodo,
-                          "editablebr", kTodo, kTodo, kTodo,
-                          "textarea", kTodo, kTodo, kTodo);
-      testTextAfterOffset(18, BOUNDARY_LINE_END, "\n", 18, 19,
-                          "div", kOk, kOk, kOk,
-                          "divbr", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "editablebr", kOk, kOk, kOk,
-                          "textarea", kOk, kOk, kOk);
-      testTextAfterOffset(19, BOUNDARY_LINE_END, "", 19, 19,
-                          "div", kOk, kTodo, kTodo,
-                          "divbr", kOk, kTodo, kTodo,
-                          "editable", kOk, kTodo, kTodo,
-                          "editablebr", kOk, kTodo, kTodo,
-                          "textarea", kOk, kTodo, kTodo);
+      testTextAfterOffset(0, BOUNDARY_LINE_END, "\n", 7, 8, IDs);
+      testTextAfterOffset(7, BOUNDARY_LINE_END, "\n", 7, 8, IDs);
+      testTextAfterOffset(8, BOUNDARY_LINE_END, "\ntwo words", 8, 18, IDs);
+      testTextAfterOffset(9, BOUNDARY_LINE_END, "\n", 18, 19, IDs);
+      testTextAfterOffset(18, BOUNDARY_LINE_END, "\n", 18, 19, IDs);
+      testTextAfterOffset(19, BOUNDARY_LINE_END, "", 19, 19, IDs);
 
       ////////////////////////////////////////////////////////////////////////
       // getTextBeforeOffset
 
       // BOUNDARY_LINE_START
-      testTextBeforeOffset(0, BOUNDARY_LINE_START, "", 0, 0,
-                           "div", kOk, kOk, kOk,
-                           "divbr", kOk, kOk, kOk,
-                           "editable", kOk, kOk, kOk,
-                           "editablebr", kOk, kOk, kOk,
-                           "textarea", kOk, kOk, kOk);
-      testTextBeforeOffset(8, BOUNDARY_LINE_START, "oneword\n", 0, 8,
-                           "div", kTodo, kTodo, kOk,
-                           "divbr", kTodo, kTodo, kOk,
-                           "editable", kTodo, kTodo, kOk,
-                           "editablebr", kTodo, kTodo, kOk,
-                           "textarea", kTodo, kTodo, kOk);
-      testTextBeforeOffset(9, BOUNDARY_LINE_START, "\n", 8, 9,
-                           "div", kTodo, kTodo, kOk,
-                           "divbr", kTodo, kTodo, kOk,
-                           "editable", kTodo, kTodo, kOk,
-                           "editablebr", kTodo, kTodo, kOk,
-                           "textarea", kTodo, kTodo, kOk);
-      testTextBeforeOffset(18, BOUNDARY_LINE_START, "\n", 8, 9,
-                           "div", kTodo, kTodo, kTodo,
-                           "divbr", kTodo, kTodo, kTodo,
-                           "editable", kTodo, kTodo, kTodo,
-                           "editablebr", kTodo, kTodo, kTodo,
-                           "textarea", kTodo, kTodo, kTodo);
-      testTextBeforeOffset(19, BOUNDARY_LINE_START, "two words \n", 9, 19,
-                           "div", kTodo, kOk, kOk,
-                           "divbr", kTodo, kOk, kOk,
-                           "editable", kTodo, kOk, kOk,
-                           "editablebr", kTodo, kOk, kOk,
-                           "textarea", kTodo, kOk, kOk);
+      testTextBeforeOffset(0, BOUNDARY_LINE_START, "", 0, 0, IDs);
+      testTextBeforeOffset(8, BOUNDARY_LINE_START, "oneword\n", 0, 8, IDs);
+      testTextBeforeOffset(9, BOUNDARY_LINE_START, "\n", 8, 9, IDs);
+      testTextBeforeOffset(18, BOUNDARY_LINE_START, "\n", 8, 9, IDs);
+      testTextBeforeOffset(19, BOUNDARY_LINE_START, "two words\n", 9, 19, IDs);
 
       // BOUNDARY_LINE_END
-      testTextBeforeOffset(0, BOUNDARY_LINE_END, "", 0, 0,
-                           "div", kOk, kOk, kOk,
-                           "divbr", kOk, kOk, kOk,
-                           "editable", kOk, kOk, kOk,
-                           "editablebr", kOk, kOk, kOk,
-                           "textarea", kOk, kOk, kOk);
-      testTextBeforeOffset(7, BOUNDARY_LINE_END, "", 0, 0,
-                           "div", kOk, kTodo, kTodo,
-                           "divbr", kOk, kTodo, kTodo,
-                           "editable", kOk, kTodo, kTodo,
-                           "editablebr", kOk, kTodo, kTodo,
-                           "textarea", kOk, kTodo, kTodo);
-      testTextBeforeOffset(8, BOUNDARY_LINE_END, "oneword", 0, 7,
-                           "div", kTodo, kTodo, kTodo,
-                           "divbr", kTodo, kTodo, kTodo,
-                           "editable", kTodo, kTodo, kTodo,
-                           "editablebr", kTodo, kTodo, kTodo,
-                           "textarea", kTodo, kTodo, kTodo);
-      testTextBeforeOffset(9, BOUNDARY_LINE_END, "\n", 7, 8,
-                           "div", kOk, kTodo, kTodo,
-                           "divbr", kOk, kTodo, kTodo,
-                           "editable", kOk, kTodo, kTodo,
-                           "editablebr", kOk, kTodo, kTodo,
-                           "textarea", kOk, kTodo, kTodo);
-      testTextBeforeOffset(18, BOUNDARY_LINE_END, "\n", 7, 8,
-                           "div", kTodo, kTodo, kTodo,
-                           "divbr", kTodo, kTodo, kTodo,
-                           "editable", kTodo, kTodo, kTodo,
-                           "editablebr", kTodo, kTodo, kTodo,
-                           "textarea", kTodo, kTodo, kTodo);
-      testTextBeforeOffset(19, BOUNDARY_LINE_END, "\ntwo words", 8, 18,
-                           "div", kTodo, kTodo, kTodo,
-                           "divbr", kTodo, kTodo, kTodo,
-                           "editable", kTodo, kTodo, kTodo,
-                           "editablebr", kTodo, kTodo, kTodo,
-                           "textarea", kTodo, kTodo, kTodo);
+      testTextBeforeOffset(0, BOUNDARY_LINE_END, "", 0, 0, IDs);
+      testTextBeforeOffset(7, BOUNDARY_LINE_END, "", 0, 0, IDs);
+      testTextBeforeOffset(8, BOUNDARY_LINE_END, "oneword", 0, 7, IDs);
+      testTextBeforeOffset(9, BOUNDARY_LINE_END, "\n", 7, 8, IDs);
+      testTextBeforeOffset(18, BOUNDARY_LINE_END, "\n", 7, 8, IDs);
+      testTextBeforeOffset(19, BOUNDARY_LINE_END, "\ntwo words", 8, 18, IDs);
 
       ////////////////////////////////////////////////////////////////////////
       // getTextAtOffset
 
       // BOUNDARY_LINE_START
       testTextAtOffset(0, BOUNDARY_LINE_START, "oneword\n", 0, 8, IDs);
       testTextAtOffset(7, BOUNDARY_LINE_START, "oneword\n", 0, 8, IDs);
       testTextAtOffset(8, BOUNDARY_LINE_START, "\n", 8, 9, IDs);
@@ -216,16 +104,21 @@
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=853340">
     Bug 853340
   </a>
   <a target="_blank"
      title="getTextBeforeOffset for word boundaries: evolving"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=855732">
     Bug 855732
   </a>
+  <a target="_blank"
+     title=" getTextAfterOffset for line boundary on new rails"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=882292">
+    Bug 882292
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
 
   <div id="div">oneword
 
 two words
 </div>
--- a/accessible/tests/mochitest/text/test_singleline.html
+++ b/accessible/tests/mochitest/text/test_singleline.html
@@ -6,120 +6,54 @@
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../text.js"></script>
   <script type="application/javascript">
-    if (navigator.platform.startsWith("Mac")) {
-      SimpleTest.expectAssertions(0, 12);
-    } else {
-      SimpleTest.expectAssertions(12);
-    }
-
     function doTest()
     {
       // __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__
       //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
 
       ////////////////////////////////////////////////////////////////////////
       // getTextAfterOffset
 
       var IDs = [ "input", "div", "editable", "textarea" ];
       var regularIDs = [ "input", "div", "editable" ];
 
       // BOUNDARY_LINE_START
-      testTextAfterOffset(0, BOUNDARY_LINE_START, "", 15, 15,
-                          "input", kTodo, kTodo, kOk,
-                          "div", kTodo, kTodo, kOk,
-                          "editable", kTodo, kTodo, kOk,
-                          "textarea", kTodo, kTodo, kOk);
-      testTextAfterOffset(1, BOUNDARY_LINE_START, "", 15, 15,
-                          "input", kTodo, kTodo, kOk,
-                          "div", kTodo, kTodo, kOk,
-                          "editable", kTodo, kTodo, kOk,
-                          "textarea", kTodo, kTodo, kOk);
-      testTextAfterOffset(14, BOUNDARY_LINE_START, "", 15, 15,
-                          "input", kTodo, kTodo, kOk,
-                          "div", kTodo, kTodo, kOk,
-                          "editable", kTodo, kTodo, kOk,
-                          "textarea", kTodo, kTodo, kOk);
-      testTextAfterOffset(15, BOUNDARY_LINE_START, "", 15, 15,
-                          "input", kOk, kOk, kOk,
-                          "div", kOk, kOk, kOk,
-                          "editable", kOk, kOk, kOk,
-                          "textarea", kOk, kOk, kOk);
+      testTextAfterOffset(0, BOUNDARY_LINE_START, "", 15, 15, IDs);
+      testTextAfterOffset(1, BOUNDARY_LINE_START, "", 15, 15, IDs);
+      testTextAfterOffset(14, BOUNDARY_LINE_START, "", 15, 15, IDs);
+      testTextAfterOffset(15, BOUNDARY_LINE_START, "", 15, 15, IDs);
 
       // BOUNDARY_LINE_END
-      testTextAfterOffset(0, BOUNDARY_LINE_END, "", 15, 15,
-                          "input", kTodo, kTodo, kOk,
-                          "div", kTodo, kTodo, kOk,
-                          "editable", kTodo, kTodo, kOk,
-                          "textarea", kTodo, kTodo, kOk);
-      testTextAfterOffset(1, BOUNDARY_LINE_END, "", 15, 15,
-                          "input", kTodo, kTodo, kOk,
-                          "div", kTodo, kTodo, kOk,
-                          "editable", kTodo, kTodo, kOk,
-                          "textarea", kTodo, kTodo, kOk);
-      testTextAfterOffset(14, BOUNDARY_LINE_END, "", 15, 15,
-                          "input", kTodo, kTodo, kOk,
-                          "div", kTodo, kTodo, kOk,
-                          "editable", kTodo, kTodo, kOk,
-                          "textarea", kTodo, kTodo, kOk);
-      testTextAfterOffset(15, BOUNDARY_LINE_END, "", 15, 15,
-                          "input", kOk, kTodo, kTodo,
-                          "div", kOk, kTodo, kTodo,
-                          "editable", kOk, kTodo, kTodo,
-                          "textarea", kOk, kTodo, kTodo);
+      testTextAfterOffset(0, BOUNDARY_LINE_END, "", 15, 15, IDs);
+      testTextAfterOffset(1, BOUNDARY_LINE_END, "", 15, 15, IDs);
+      testTextAfterOffset(14, BOUNDARY_LINE_END, "", 15, 15, IDs);
+      testTextAfterOffset(15, BOUNDARY_LINE_END, "", 15, 15, IDs);
 
       ////////////////////////////////////////////////////////////////////////
       // getTextBeforeOffset
 
       var IDs = [ "input", "div", "editable", "textarea" ];
 
       // BOUNDARY_LINE_START
-      testTextBeforeOffset(0, BOUNDARY_LINE_START, "", 0, 0,
-                           "input", kOk, kOk, kOk,
-                           "div", kOk, kOk, kOk,
-                           "editable", kOk, kOk, kOk,
-                           "textarea", kOk, kOk, kOk);
-      testTextBeforeOffset(1, BOUNDARY_LINE_START, "", 0, 0,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
-      testTextBeforeOffset(14, BOUNDARY_LINE_START, "", 0, 0,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
-      testTextBeforeOffset(15, BOUNDARY_LINE_START, "", 0, 0,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+      testTextBeforeOffset(0, BOUNDARY_LINE_START, "", 0, 0, IDs);
+      testTextBeforeOffset(1, BOUNDARY_LINE_START, "", 0, 0, IDs);
+      testTextBeforeOffset(14, BOUNDARY_LINE_START, "", 0, 0, IDs);
+      testTextBeforeOffset(15, BOUNDARY_LINE_START, "", 0, 0, IDs);
 
       // BOUNDARY_LINE_END
-      testTextBeforeOffset(0, BOUNDARY_LINE_END, "", 0, 0,
-                           "input", kOk, kOk, kOk,
-                           "div", kOk, kOk, kOk,
-                           "editable", kOk, kOk, kOk,
-                           "textarea", kOk, kOk, kOk);
-      testTextBeforeOffset(1, BOUNDARY_LINE_END, "", 0, 0,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
-      testTextBeforeOffset(14, BOUNDARY_LINE_END, "", 0, 0,
-                           "input", kTodo, kOk, kTodo,
-                           "div", kTodo, kOk, kTodo,
-                           "editable", kTodo, kOk, kTodo,
-                           "textarea", kTodo, kOk, kTodo);
+      testTextBeforeOffset(0, BOUNDARY_LINE_END, "", 0, 0, IDs);
+      testTextBeforeOffset(1, BOUNDARY_LINE_END, "", 0, 0, IDs);
+      testTextBeforeOffset(14, BOUNDARY_LINE_END, "", 0, 0, IDs);
       testTextBeforeOffset(15, BOUNDARY_LINE_END, "", 0, 0, IDs);
 
       ////////////////////////////////////////////////////////////////////////
       // getTextAtOffset
 
       IDs = [ "input", "div", "editable", "textarea" ];
       regularIDs = [ "input", "div", "editable" ];
 
@@ -154,16 +88,21 @@
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=853340">
     Bug 853340
   </a>
   <a target="_blank"
      title="getTextBeforeOffset for word boundaries: evolving"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=855732">
     Bug 855732
   </a>
+  <a target="_blank"
+     title=" getTextAfterOffset for line boundary on new rails"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=882292">
+    Bug 882292
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <input id="input" value="hello my friend"/>
   <div id="div">hello my friend</div>
   <div id="editable" contenteditable="true">hello my friend</div>
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/bin/activate.fish
@@ -0,0 +1,66 @@
+# 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/.
+
+# This file must be used with "source bin/activate.fish" *from fish*
+# you cannot run it directly
+
+# Much of this code is based off of the activate.fish file for the
+# virtualenv project. http://ur1.ca/ehmd6
+
+function deactivate -d "Exit addon-sdk and return to normal shell environment"
+    if test -n "$_OLD_VIRTUAL_PATH"
+        set -gx PATH $_OLD_VIRTUAL_PATH
+        set -e _OLD_VIRTUAL_PATH
+    end
+
+    if test -n "$_OLD_PYTHONPATH"
+        set -gx PYTHONPATH $_OLD_PYTHONPATH
+        set -e _OLD_PYTHONPATH
+    end
+
+    if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
+        functions -e fish_prompt
+        set -e _OLD_FISH_PROMPT_OVERRIDE
+        . ( begin
+                printf "function fish_prompt\n\t#"
+                functions _old_fish_prompt
+            end | psub )
+
+        functions -e _old_fish_prompt
+    end
+
+    set -e CUDDLEFISH_ROOT
+    set -e VIRTUAL_ENV
+
+    if test "$argv[1]" != "nondestructive"
+        functions -e deactivate
+    end
+end
+
+# unset irrelavent variables
+deactivate nondestructive
+
+set -gx _OLD_PYTHONPATH $PYTHONPATH
+set -gx _OLD_VIRTUAL_PATH $PATH
+set -gx _OLD_FISH_PROMPT_OVERRIDE "true"
+
+set VIRTUAL_ENV (pwd)
+
+set -gx CUDDLEFISH_ROOT $VIRTUAL_ENV
+set -gx PYTHONPATH "$VIRTUAL_ENV/python-lib" $PYTHONPATH
+set -gx PATH "$VIRTUAL_ENV/bin" $PATH
+
+# save the current fish_prompt function as the function _old_fish_prompt
+. ( begin
+        printf "function _old_fish_prompt\n\t#"
+        functions fish_prompt
+    end | psub )
+
+# with the original prompt function renamed, we can override with our own.
+function fish_prompt
+    printf "(%s)%s%s" (basename "$VIRTUAL_ENV") (set_color normal) (_old_fish_prompt)
+    return
+end 
+
+python -c "from jetpack_sdk_env import welcome; welcome()"
--- a/addon-sdk/source/doc/dev-guide-source/credits.md
+++ b/addon-sdk/source/doc/dev-guide-source/credits.md
@@ -38,16 +38,17 @@ We'd like to thank our many Jetpack proj
 
 * dexter
 * Christopher Dorn
 * Connor Dunn
 * dynamis
 
 ### F ###
 
+* [Corey Farwell](http://github.com/frewsxcv)
 * [Matteo Ferretti](https://github.com/ZER0)
 * fuzzykiller
 
 ### G ###
 
 * [Marcio Galli](https://github.com/taboca)
 * [Ben Gillbanks](http://www.iconfinder.com/browse/iconset/circular_icons/)
 * Felipe Gomes
deleted file mode 100644
--- a/addon-sdk/source/doc/module-source/sdk/page-mod/match-pattern.md
+++ /dev/null
@@ -1,259 +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/. -->
-
-The `match-pattern` module can be used to test strings containing URLs
-against simple patterns.
-
-## Specifying Patterns ##
-
-There are three ways you can specify patterns:
-
-* as an exact match string
-* using a wildcard in a string
-* using a regular expression
-
-### Exact Matches ###
-
-**A URL** matches only that URL. The URL must start with a scheme, end with a
-slash, and contain no wildcards.
-
-<table>
-
-  <colgroup>
-    <col width="20%">
-    <col width="25%">
-    <col width="55%">
-  </colgroup>
-
-  <tr>
-    <th>Example pattern</th>
-    <th>Example matching URLs</th>
-    <th>Example non-matching URLs</th>
-  </tr>
-
-  <tr>
-    <td><code>"http://example.com/"</code></td>
-    <td><code>http://example.com/</code></td>
-    <td><code>http://example.com</code><br>
-        <code>http://example.com/foo</code><br>
-        <code>https://example.com/</code><br>
-        <code>http://foo.example.com/</code></td>
-  </tr>
-
-</table>
-
-### Wildcards ###
-
-**A single asterisk** matches any URL with an `http`, `https`, or `ftp`
-scheme. For other schemes like `file`, `resource`, or `data`, use a scheme
-followed by an asterisk, as below.
-
-<table>
-
-  <colgroup>
-    <col width="20%">
-    <col width="25%">
-    <col width="55%">
-  </colgroup>
-
-  <tr>
-    <th>Example pattern</th>
-    <th>Example matching URLs</th>
-    <th>Example non-matching URLs</th>
-  </tr>
-
-  <tr>
-    <td><code>"*"</code></td>
-    <td><code>http://example.com/</code><br>
-        <code>https://example.com/</code><br>
-        <code>ftp://example.com/</code><br>
-        <code>http://bar.com/foo.js</code><br>
-        <code>http://foo.com/</code></td>
-    <td><code>file://example.js</code><br>
-        <code>resource://me/my-addon/data/file.html</code><br>
-        <code>data:text/html,Hi there</code></td>
-  </tr>
-
-</table>
-
-**A domain name prefixed with an asterisk and dot** matches any URL of that
-domain or a subdomain, using any of `http`, `https`, `ftp`.
-
-<table>
-
-  <colgroup>
-    <col width="20%">
-    <col width="25%">
-    <col width="55%">
-  </colgroup>
-
-  <tr>
-    <th>Example pattern</th>
-    <th>Example matching URLs</th>
-    <th>Example non-matching URLs</th>
-  </tr>
-
-  <tr>
-    <td><code>"*.example.com"</code></td>
-    <td><code>http://example.com/</code><br>
-        <code>http://foo.example.com/</code><br>
-        <code>https://example.com/</code><br>
-        <code>http://example.com/foo</code><br>
-        <code>ftp://foo.example.com/</code></td>
-    <td><code>ldap://example.com</code><br>
-        <code>http://example.foo.com/</code></td>
-  </tr>
-
-</table>
-
-**A URL followed by an asterisk** matches that URL and any URL prefixed with
-the pattern.
-
-<table>
-
-  <colgroup>
-    <col width="20%">
-    <col width="25%">
-    <col width="55%">
-  </colgroup>
-
-  <tr>
-    <th>Example pattern</th>
-    <th>Example matching URLs</th>
-    <th>Example non-matching URLs</th>
-  </tr>
-
-  <tr>
-    <td><code>"https://foo.com/*"</code></td>
-    <td><code>https://foo.com/</code><br>
-        <code>https://foo.com/bar</code></td>
-    <td><code>http://foo.com/</code><br>
-        <code>https://foo.com</code><br>
-        <code>https://bar.foo.com/</code></td>
-  </tr>
-
-</table>
-
-**A scheme followed by an asterisk** matches all URLs with that scheme. To
-match local files, use `file://*`, and to match files loaded from your
-add-on's [data](modules/sdk/self.html#data) directory, use `resource://`.
-
-<table>
-
-  <colgroup>
-    <col width="20%">
-    <col width="80%">
-  </colgroup>
-
-  <tr>
-    <th>Example pattern</th>
-    <th>Example matching URLs</th>
-  </tr>
-
-  <tr>
-    <td><code>"file://*"</code></td>
-    <td><code>file://C:/file.html</code><br>
-        <code>file:///home/file.png</code></td>
-  </tr>
-
-  <tr>
-    <td><code>"resource://*"</code></td>
-    <td><code>resource://my-addon-at-me-dot-org/my-addon/data/file.html</code></td>
-  </tr>
-
-  <tr>
-    <td><code>"data:*"</code></td>
-    <td><code>data:text/html,Hi there</code></td>
-  </tr>
-
-</table>
-
-### Regular Expressions ###
-
-You can specify patterns using a
-[regular expression](https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions):
-
-    var { MatchPattern } = require("sdk/page-mod/match-pattern");
-    var pattern = new MatchPattern(/.*example.*/);
-
-The regular expression is subject to restrictions based on those applied to the
-[HTML5 pattern attribute](http://dev.w3.org/html5/spec/common-input-element-attributes.html#attr-input-pattern). In particular:
-
-* The pattern must match the entire value, not just any subset. For example, the
-pattern `/moz.*/` will not match the URL `http://mozilla.org`.
-
-* The expression is compiled with the `global`, `ignoreCase`, and `multiline` flags
-  disabled. The `MatchPattern` constructor will throw an exception
-  if you try to set any of these flags.
-
-<table>
-
-  <colgroup>
-    <col width="30%">
-    <col width="35%">
-    <col width="35%">
-  </colgroup>
-
-  <tr>
-    <th>Example pattern</th>
-    <th>Example matching URLs</th>
-    <th>Example non-matching URLs</th>
-  </tr>
-
-  <tr>
-    <td><code>/.*moz.*/</code></td>
-    <td><code>http://foo.mozilla.org/</code><br>
-        <code>http://mozilla.org</code><br>
-        <code>https://mozilla.org</code><br>
-        <code>http://foo.com/mozilla</code><br>
-        <code>http://hemozoon.org</code><br>
-        <code>mozscheme://foo.org</code><br></td>
-    <td><code>http://foo.org</code><br>
-  </tr>
-
-  <tr>
-    <td><code>/http:\/\/moz.*/</code></td>
-    <td><code>http://mozilla.org</code><br>
-        <code>http://mozzarella.com</code></td>
-    <td><code>https://mozilla.org</code><br>
-        <code>http://foo.mozilla.org/</code><br>
-        <code>http://foo.com/moz</code></td>
-  </tr>
-
-  <tr>
-    <td><code>/http.*moz.*/</code><br></td>
-    <td><code>http://foo.mozilla.org/</code><br>
-        <code>http://mozilla.org</code><br>
-        <code>http://hemozoon.org/</code></td>
-        <td><code>ftp://http/mozilla.org</code></td>
-  </tr>
-
-</table>
-
-## Examples ##
-
-    var { MatchPattern } = require("sdk/page-mod/match-pattern");
-    var pattern = new MatchPattern("http://example.com/*");
-    console.log(pattern.test("http://example.com/"));       // true
-    console.log(pattern.test("http://example.com/foo"));    // true
-    console.log(pattern.test("http://foo.com/"));           // false!
-
-<api name="MatchPattern">
-@class
-<api name="MatchPattern">
-@constructor
-  This constructor creates match pattern objects that can be used to test URLs.
-@param pattern {string}
-  The pattern to use.  See Patterns above.
-</api>
-
-<api name="test">
-@method
-  Tests a URL against the match pattern.
-@param url {string}
-  The URL to test.
-@returns {boolean}
-  True if the URL matches the pattern and false otherwise.
-</api>
-</api>
deleted file mode 100644
index 639faaa2be35fbe53f23e4f21197d5fdd516ca3e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/addon-sdk/source/lib/sdk/core/promise.js
+++ b/addon-sdk/source/lib/sdk/core/promise.js
@@ -17,16 +17,18 @@
       // Avoid failures on different toolkit configurations.
     }
     factory(function require(uri) {
       var imports = {};
       this['Components'].utils.import(uri, imports);
       return imports;
     }, this[factory.name], { uri: __URI__, id: id });
     this.EXPORTED_SYMBOLS = [factory.name];
+  } else if (~String(this).indexOf('Sandbox')) { // Sandbox
+    factory(function require(uri) {}, this, { id: id });
   } else {  // Browser or alike
     var globals = this;
     factory(function require(id) {
       return globals[id];
     }, (globals[id] = {}), { uri: document.location.href + '#' + id, id: id });
   }
 }).call(this, 'promise/core', function Promise(require, exports, module) {
 
--- a/addon-sdk/source/lib/sdk/indexed-db.js
+++ b/addon-sdk/source/lib/sdk/indexed-db.js
@@ -51,13 +51,12 @@ exports.indexedDB = Object.freeze({
   cmp: indexedDB.cmp
 });
 
 exports.IDBKeyRange = IDBKeyRange;
 exports.DOMException = Ci.nsIDOMDOMException;
 exports.IDBCursor = Ci.nsIIDBCursor;
 exports.IDBTransaction = Ci.nsIIDBTransaction;
 exports.IDBOpenDBRequest = Ci.nsIIDBOpenDBRequest;
-exports.IDBVersionChangeEvent = Ci.nsIIDBVersionChangeEvent;
 exports.IDBDatabase = Ci.nsIIDBDatabase;
 exports.IDBIndex = Ci.nsIIDBIndex;
 exports.IDBObjectStore = Ci.nsIIDBObjectStore;
 exports.IDBRequest = Ci.nsIIDBRequest;
--- a/addon-sdk/source/lib/sdk/panel/window.js
+++ b/addon-sdk/source/lib/sdk/panel/window.js
@@ -1,13 +1,22 @@
 /* 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/. */
 'use strict';
 
+// The panel module currently supports only Firefox.
+// See: https://bugzilla.mozilla.org/show_bug.cgi?id=jetpack-panel-apps
+module.metadata = {
+  'stability': 'unstable',
+  'engines': {
+    'Firefox': '*'
+  }
+};
+
 const { getMostRecentBrowserWindow, windows: getWindows } = require('../window/utils');
 const { ignoreWindow } = require('../private-browsing/utils');
 const { isPrivateBrowsingSupported } = require('../self');
 const { isGlobalPBSupported } = require('../private-browsing/utils');
 
 function getWindow(anchor) {
   let window;
   let windows = getWindows("navigator:browser", {
--- a/addon-sdk/source/lib/sdk/places/favicon.js
+++ b/addon-sdk/source/lib/sdk/places/favicon.js
@@ -1,16 +1,19 @@
 /* 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/. */
 
 "use strict";
 
 module.metadata = {
-  "stability": "unstable"
+  "stability": "unstable",
+  "engines": {
+    "Firefox": "*"
+  }
 };
 
 const { Cc, Ci, Cu } = require("chrome");
 const { defer, reject } = require("../core/promise");
 const FaviconService = Cc["@mozilla.org/browser/favicon-service;1"].
                           getService(Ci.nsIFaviconService);
 const AsyncFavicons = FaviconService.QueryInterface(Ci.mozIAsyncFavicons);
 const { isValidURI } = require("../url");
--- a/addon-sdk/source/lib/sdk/test/utils.js
+++ b/addon-sdk/source/lib/sdk/test/utils.js
@@ -7,89 +7,90 @@
 
 module.metadata = {
   'stability': 'unstable'
 };
 
 function getTestNames (exports)
   Object.keys(exports).filter(name => /^test/.test(name))
 
-function isAsync (fn) fn.length > 1
+function isTestAsync (fn) fn.length > 1
+function isHelperAsync (fn) fn.length > 2
 
 /*
  * Takes an `exports` object of a test file and a function `beforeFn`
  * to be run before each test. `beforeFn` is called with a `name` string
  * as the first argument of the test name, and may specify a second
  * argument function `done` to indicate that this function should
  * resolve asynchronously
  */
 function before (exports, beforeFn) {
   getTestNames(exports).map(name => {
     let testFn = exports[name];
-    if (!isAsync(testFn) && !isAsync(beforeFn)) {
+    if (!isTestAsync(testFn) && !isHelperAsync(beforeFn)) {
       exports[name] = function (assert) {
-        beforeFn(name);
+        beforeFn(name, assert);
         testFn(assert);
       };
     }
-    else if (isAsync(testFn) && !isAsync(beforeFn)) {
+    else if (isTestAsync(testFn) && !isHelperAsync(beforeFn)) {
       exports[name] = function (assert, done) {
-        beforeFn(name);
+        beforeFn(name, assert);
         testFn(assert, done);
-      }
+      };
     }
-    else if (!isAsync(testFn) && isAsync(beforeFn)) {
+    else if (!isTestAsync(testFn) && isHelperAsync(beforeFn)) {
       exports[name] = function (assert, done) {
-        beforeFn(name, () => {
+        beforeFn(name, assert, () => {
           testFn(assert);
           done();
         });
-      }
-    } else if (isAsync(testFn) && isAsync(beforeFn)) {
+      };
+    } else if (isTestAsync(testFn) && isHelperAsync(beforeFn)) {
       exports[name] = function (assert, done) {
-        beforeFn(name, () => {
+        beforeFn(name, assert, () => {
           testFn(assert, done);
         });
-      }
+      };
     }
   });
 }
 exports.before = before;
 
 /*
  * Takes an `exports` object of a test file and a function `afterFn`
  * to be run after each test. `afterFn` is called with a `name` string
  * as the first argument of the test name, and may specify a second
  * argument function `done` to indicate that this function should
  * resolve asynchronously
  */
 function after (exports, afterFn) {
   getTestNames(exports).map(name => {
     let testFn = exports[name];
-    if (!isAsync(testFn) && !isAsync(afterFn)) {
+    if (!isTestAsync(testFn) && !isHelperAsync(afterFn)) {
       exports[name] = function (assert) {
         testFn(assert);
-        afterFn(name);
+        afterFn(name, assert);
       };
     }
-    else if (isAsync(testFn) && !isAsync(afterFn)) {
+    else if (isTestAsync(testFn) && !isHelperAsync(afterFn)) {
       exports[name] = function (assert, done) {
         testFn(assert, () => {
-          afterFn(name);
+          afterFn(name, assert);
           done();
         });
-      }
+      };
     }
-    else if (!isAsync(testFn) && isAsync(afterFn)) {
+    else if (!isTestAsync(testFn) && isHelperAsync(afterFn)) {
       exports[name] = function (assert, done) {
         testFn(assert);
-        afterFn(name, done);
-      }
-    } else if (isAsync(testFn) && isAsync(afterFn)) {
+        afterFn(name, assert, done);
+      };
+    } else if (isTestAsync(testFn) && isHelperAsync(afterFn)) {
       exports[name] = function (assert, done) {
         testFn(assert, () => {
-          afterFn(name, done);
+          afterFn(name, assert, done);
         });
-      }
+      };
     }
   });
 }
 exports.after = after;
--- a/addon-sdk/source/test/tabs/test-firefox-tabs.js
+++ b/addon-sdk/source/test/tabs/test-firefox-tabs.js
@@ -3,19 +3,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 const { Cc, Ci } = require('chrome');
 const { Loader } = require('sdk/test/loader');
 const timer = require('sdk/timers');
 const { getOwnerWindow } = require('sdk/private-browsing/window/utils');
 const { windows, onFocus, getMostRecentBrowserWindow } = require('sdk/window/utils');
-const { open, focus } = require('sdk/window/helpers');
+const { open, focus, close } = require('sdk/window/helpers');
 const { StringBundle } = require('sdk/deprecated/app-strings');
 const tabs = require('sdk/tabs');
+const { browserWindows } = require('sdk/windows');
 
 const base64png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYA" +
                   "AABzenr0AAAASUlEQVRYhe3O0QkAIAwD0eyqe3Q993AQ3cBSUKpygfsNTy" +
                   "N5ugbQpK0BAADgP0BRDWXWlwEAAAAAgPsA3rzDaAAAAHgPcGrpgAnzQ2FG" +
                   "bWRR9AAAAABJRU5ErkJggg%3D%3D";
 
 // Bug 682681 - tab.title should never be empty
 exports.testBug682681_aboutURI = function(test) {
@@ -88,24 +89,61 @@ exports.testAutomaticDestroy = function(
 
   loader.unload();
 
   // Fire a tab event and ensure that the destroyed tab is inactive
   tabs.once('open', function (tab) {
     timer.setTimeout(function () {
       test.assert(!called, "Unloaded tab module is destroyed and inactive");
       tab.close(test.done.bind(test));
-    }, 0);
+    });
   });
-
   tabs.open("data:text/html;charset=utf-8,foo");
 };
 
-// test tab properties
-exports.testTabProperties = function(test) {
+exports.testTabPropertiesInNewWindow = function(test) {
+  test.waitUntilDone();
+
+  let count = 0;
+  function onReadyOrLoad (tab) {
+    if (count++) {
+      close(getOwnerWindow(tab)).then(test.done.bind(test));
+    }
+  }
+
+  let url = "data:text/html;charset=utf-8,<html><head><title>foo</title></head><body>foo</body></html>";
+  tabs.open({
+    inNewWindow: true,
+    url: url,
+    onReady: function(tab) {
+      test.assertEqual(tab.title, "foo", "title of the new tab matches");
+      test.assertEqual(tab.url, url, "URL of the new tab matches");
+      test.assert(tab.favicon, "favicon of the new tab is not empty");
+      test.assertEqual(tab.style, null, "style of the new tab matches");
+      test.assertEqual(tab.index, 0, "index of the new tab matches");
+      test.assertNotEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
+      test.assertNotEqual(tab.id, null, "a tab object always has an id property.");
+
+      onReadyOrLoad(tab);
+    },
+    onLoad: function(tab) {
+      test.assertEqual(tab.title, "foo", "title of the new tab matches");
+      test.assertEqual(tab.url, url, "URL of the new tab matches");
+      test.assert(tab.favicon, "favicon of the new tab is not empty");
+      test.assertEqual(tab.style, null, "style of the new tab matches");
+      test.assertEqual(tab.index, 0, "index of the new tab matches");
+      test.assertNotEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
+      test.assertNotEqual(tab.id, null, "a tab object always has an id property.");
+
+      onReadyOrLoad(tab);
+    }
+  });
+};
+
+exports.testTabPropertiesInSameWindow = function(test) {
   test.waitUntilDone();
 
   let count = 0;
   function onReadyOrLoad (tab) {
     if (count++) {
       tab.close(test.done.bind(test));
     }
   }
@@ -116,26 +154,28 @@ exports.testTabProperties = function(tes
     onReady: function(tab) {
       test.assertEqual(tab.title, "foo", "title of the new tab matches");
       test.assertEqual(tab.url, url, "URL of the new tab matches");
       test.assert(tab.favicon, "favicon of the new tab is not empty");
       test.assertEqual(tab.style, null, "style of the new tab matches");
       test.assertEqual(tab.index, 1, "index of the new tab matches");
       test.assertNotEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
       test.assertNotEqual(tab.id, null, "a tab object always has an id property.");
+
       onReadyOrLoad(tab);
     },
     onLoad: function(tab) {
       test.assertEqual(tab.title, "foo", "title of the new tab matches");
       test.assertEqual(tab.url, url, "URL of the new tab matches");
       test.assert(tab.favicon, "favicon of the new tab is not empty");
       test.assertEqual(tab.style, null, "style of the new tab matches");
       test.assertEqual(tab.index, 1, "index of the new tab matches");
       test.assertNotEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
       test.assertNotEqual(tab.id, null, "a tab object always has an id property.");
+
       onReadyOrLoad(tab);
     }
   });
 };
 
 // TEST: tab properties
 exports.testTabContentTypeAndReload = function(test) {
   test.waitUntilDone();
@@ -239,17 +279,17 @@ exports.testTabClose = function(test) {
 
   tabs.open(url);
 };
 
 // TEST: tab.move()
 exports.testTabMove = function(test) {
   test.waitUntilDone();
 
-  open().then(function(window) {
+  open().then(focus).then(function(window) {
     let url = "data:text/html;charset=utf-8,foo";
 
     tabs.open({
       url: url,
       onOpen: function(tab) {
         test.assertEqual(tab.index, 1, "tab index before move matches");
         tab.index = 0;
         test.assertEqual(tab.index, 0, "tab index after move matches");
@@ -960,18 +1000,16 @@ exports.testFaviconGetterDeprecation = f
       test.assert(msg.indexOf('tab.favicon is deprecated') !== -1,
         'message contains the given message');
       tab.close(test.done.bind(test));
       loader.unload();
     }
   });
 }
 
-
-
 /******************* helpers *********************/
 
 // Helper for getting the active window
 this.__defineGetter__("activeWindow", function activeWindow() {
   return Cc["@mozilla.org/appshell/window-mediator;1"].
          getService(Ci.nsIWindowMediator).
          getMostRecentWindow("navigator:browser");
 });
--- a/addon-sdk/source/test/test-indexed-db.js
+++ b/addon-sdk/source/test/test-indexed-db.js
@@ -4,33 +4,32 @@
 
 "use strict";
 
 let xulApp = require("sdk/system/xul-app");
 if (xulApp.versionInRange(xulApp.platformVersion, "16.0a1", "*")) {
 new function tests() {
 
 const { indexedDB, IDBKeyRange, DOMException, IDBCursor, IDBTransaction,
-        IDBOpenDBRequest, IDBVersionChangeEvent, IDBDatabase, IDBIndex, 
-        IDBObjectStore, IDBRequest
+        IDBOpenDBRequest, IDBDatabase, IDBIndex, IDBObjectStore, IDBRequest
       } = require("sdk/indexed-db");
 
 exports["test indexedDB is frozen"] = function(assert){
   let original = indexedDB.open;
   let f = function(){};
   assert.throws(function(){indexedDB.open = f});
   assert.equal(indexedDB.open,original);
   assert.notEqual(indexedDB.open,f);
 
 };
 
 exports["test db variables"] = function(assert) {
   [ indexedDB, IDBKeyRange, DOMException, IDBCursor, IDBTransaction,
-    IDBOpenDBRequest, IDBOpenDBRequest, IDBVersionChangeEvent,
-    IDBDatabase, IDBIndex, IDBObjectStore, IDBRequest
+    IDBOpenDBRequest, IDBOpenDBRequest, IDBDatabase, IDBIndex,
+    IDBObjectStore, IDBRequest
   ].forEach(function(value) {
     assert.notEqual(typeof(value), "undefined", "variable is defined");
   });
 }
 
 exports["test open"] = function(assert, done) {
   let request = indexedDB.open("MyTestDatabase");
   request.onerror = function(event) {
--- a/addon-sdk/source/test/test-panel.js
+++ b/addon-sdk/source/test/test-panel.js
@@ -1,12 +1,18 @@
 /* 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/. */
- 'use strict';
+'use strict';
+
+module.metadata = {
+  'engines': {
+    'Firefox': '*'
+  }
+};
 
 const { Cc, Ci } = require("chrome");
 const { Loader } = require('sdk/test/loader');
 const { LoaderWithHookedConsole } = require("sdk/test/loader");
 const timer = require("sdk/timers");
 const self = require('sdk/self');
 const { open, close, focus } = require('sdk/window/helpers');
 const { isPrivate } = require('sdk/private-browsing');
@@ -918,23 +924,9 @@ else if (isGlobalPBSupported) {
         pb.once('stop', done);
         pb.deactivate();
       })
     });
     pb.activate();
   }
 }
 
-try {
-  require("sdk/panel");
-}
-catch (e) {
-  if (!/^Unsupported Application/.test(e.message))
-    throw e;
-
-  module.exports = {
-    "test Unsupported Application": function Unsupported (assert) {
-      assert.pass(e.message);
-    }
-  }
-}
-
 require("test").run(exports);
--- a/addon-sdk/source/test/test-path.js
+++ b/addon-sdk/source/test/test-path.js
@@ -330,18 +330,21 @@ if (isWindows) {
        [['c:/', '///some//dir'], 'c:\\some\\dir']
       ];
 } else {
   // Posix
   var resolveTests =
       // arguments result
       [[['/var/lib', '../', 'file/'], '/var/file'],
        [['/var/lib', '/../', 'file/'], '/file'],
-       [['a/b/c/', '../../..'], process.cwd()],
-       [['.'], process.cwd()],
+       // For some mysterious reasons OSX debug builds resolve incorrectly
+       // https://tbpl.mozilla.org/php/getParsedLog.php?id=25105489&tree=Mozilla-Inbound
+       // Disable this tests until Bug 891698 is fixed.
+       // [['a/b/c/', '../../..'], process.cwd()],
+       // [['.'], process.cwd()],
        [['/some/dir', '.', '/absolute/'], '/absolute']];
 }
 var failures = [];
 resolveTests.forEach(function(test) {
   var actual = path.resolve.apply(path, test[0]);
   var expected = test[1];
   var message = 'path.resolve(' + test[0].map(JSON.stringify).join(',') + ')' +
                 '\n expect=' + JSON.stringify(expected) +
--- a/addon-sdk/source/test/test-places-bookmarks.js
+++ b/addon-sdk/source/test/test-places-bookmarks.js
@@ -1,41 +1,44 @@
 /* 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/. */
 'use strict';
 
+module.metadata = {
+  'engines': {
+    'Firefox': '*'
+  }
+};
+
 const { Cc, Ci } = require('chrome');
 const { request } = require('sdk/addon/host');
 const { filter } = require('sdk/event/utils');
 const { on, off } = require('sdk/event/core');
 const { setTimeout } = require('sdk/timers');
 const { newURI } = require('sdk/url/utils');
 const { defer, all } = require('sdk/core/promise');
 const { defer: async } = require('sdk/lang/functional');
 const { before, after } = require('sdk/test/utils');
 
-// Test for unsupported platforms
-try {
 const {
   Bookmark, Group, Separator,
   save, search, remove,
   MENU, TOOLBAR, UNSORTED
 } = require('sdk/places/bookmarks');
 const {
   invalidResolve, invalidReject, clearBookmarks, createTree,
   compareWithHost, clearAllBookmarks, createBookmark, createBookmarkItem,
   createBookmarkTree, addVisits
 } = require('./places-helper');
 const { promisedEmitter } = require('sdk/places/utils');
 const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1'].
                     getService(Ci.nsINavBookmarksService);
 const tagsrv = Cc['@mozilla.org/browser/tagging-service;1'].
                     getService(Ci.nsITaggingService);
-} catch (e) { unsupported(e); }
 
 exports.testDefaultFolders = function (assert) {
   var ids = [
     bmsrv.bookmarksMenuFolder,
     bmsrv.toolbarFolder,
     bmsrv.unfiledBookmarksFolder
   ];
   [MENU, TOOLBAR, UNSORTED].forEach(function (g, i) {
@@ -941,30 +944,16 @@ exports.testCheckSaveOrder = function (a
 before(exports, name => {
   clearAllBookmarks();
 });
 
 after(exports, name => {
   clearAllBookmarks();
 });
 
-// If the module doesn't support the app we're being run in, require() will
-// throw.  In that case, remove all tests above from exports, and add one dummy
-// test that passes.
-function unsupported (err) {
-  if (!/^Unsupported Application/.test(err.message))
-    throw err;
-
-  module.exports = {
-    "test Unsupported Application": function Unsupported (assert) {
-      assert.pass(err.message);
-    }
-  };
-}
-
 function saveP () {
   return promisedEmitter(save.apply(null, Array.slice(arguments)));
 }
 
 function searchP () {
   return promisedEmitter(search.apply(null, Array.slice(arguments)));
 }
 require('test').run(exports);
--- a/addon-sdk/source/test/test-places-favicon.js
+++ b/addon-sdk/source/test/test-places-favicon.js
@@ -1,12 +1,20 @@
 /* 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/. */
 
+'use strict';
+
+module.metadata = {
+  'engines': {
+    'Firefox': '*'
+  }
+};
+
 const { Cc, Ci, Cu } = require('chrome');
 const { getFavicon } = require('sdk/places/favicon');
 const tabs = require('sdk/tabs');
 const open = tabs.open;
 const port = 8099;
 const host = 'http://localhost:' + port;
 const { onFaviconChange, serve, binFavicon } = require('./favicon-helpers');
 const { once } = require('sdk/system/events');
--- a/addon-sdk/source/test/test-places-history.js
+++ b/addon-sdk/source/test/test-places-history.js
@@ -1,30 +1,34 @@
 /* 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/. */
- 'use strict'
+'use strict';
+
+module.metadata = {
+  'engines': {
+    'Firefox': '*'
+  }
+};
 
 const { Cc, Ci } = require('chrome');
 const { defer, all } = require('sdk/core/promise');
 const { has } = require('sdk/util/array');
 const { setTimeout } = require('sdk/timers');
 const { before, after } = require('sdk/test/utils');
-try {
 const {
   search 
 } = require('sdk/places/history');
 const {
   invalidResolve, invalidReject, clearBookmarks, createTree,
   compareWithHost, clearAllBookmarks, addVisits, clearHistory
 } = require('./places-helper');
 const { promisedEmitter } = require('sdk/places/utils');
 const hsrv = Cc['@mozilla.org/browser/nav-history-service;1'].
               getService(Ci.nsINavHistoryService);
-} catch(e) { unsupported(e); }
 
 exports.testEmptyQuery = function (assert, done) {
   let within = toBeWithin();
   addVisits([
     'http://simplequery-1.com', 'http://simplequery-2.com'
   ]).then(searchP).then(results => {
     assert.equal(results.length, 2, 'Correct number of entries returned');
     assert.equal(results[0].url, 'http://simplequery-1.com/',
@@ -235,30 +239,16 @@ function toBeWithin (range) {
   };
 }
 
 function clear (done) {
   clearAllBookmarks();
   clearHistory(done);
 }
 
-// If the module doesn't support the app we're being run in, require() will
-// throw.  In that case, remove all tests above from exports, and add one dummy
-// test that passes.
-function unsupported (err) {
-  if (!/^Unsupported Application/.test(err.message))
-    throw err;
-
-  module.exports = {
-    "test Unsupported Application": function Unsupported (assert) {
-      assert.pass(err.message);
-    }
-  };
-}
-
 function searchP () {
   return promisedEmitter(search.apply(null, Array.slice(arguments)));
 }
 
-before(exports, (name, done) => clear(done));
-after(exports, (name, done) => clear(done));
+before(exports, (name, assert, done) => clear(done));
+after(exports, (name, assert, done) => clear(done));
 
 require('test').run(exports);
--- a/addon-sdk/source/test/test-places-host.js
+++ b/addon-sdk/source/test/test-places-host.js
@@ -1,35 +1,40 @@
 /* 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/. */
 'use strict';
 
+module.metadata = {
+  'engines': {
+    'Firefox': '*'
+  }
+};
+
 const { Cc, Ci } = require('chrome');
 const { defer, all } = require('sdk/core/promise');
 const { setTimeout } = require('sdk/timers');
 const { newURI } = require('sdk/url/utils');
 const { send } = require('sdk/addon/events');
-try {
+
 require('sdk/places/host/host-bookmarks');
 require('sdk/places/host/host-tags');
 require('sdk/places/host/host-query');
 const {
   invalidResolve, invalidReject, clearBookmarks, createTree,
   compareWithHost, clearAllBookmarks, createBookmark, createBookmarkTree
 } = require('./places-helper');
 
 const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1'].
                     getService(Ci.nsINavBookmarksService);
 const hsrv = Cc['@mozilla.org/browser/nav-history-service;1'].
               getService(Ci.nsINavHistoryService);
 const tagsrv = Cc['@mozilla.org/browser/tagging-service;1'].
               getService(Ci.nsITaggingService);
 clearAllBookmarks();
-} catch(e) { unsupported(e); }
 
 exports.testBookmarksCreate = function (assert, done) {
   let items = [{
     title: 'my title',
     url: 'http://moz.com',
     tags: ['some', 'tags', 'yeah'],
     type: 'bookmark'
   }, {
@@ -271,22 +276,9 @@ exports.testGetAllChildren = function (a
   }).then(results => {
     assert.equal(results.length, 5,
       'should return all children and folders at a single depth');
     clearAllBookmarks();
     done();
   });
 };
 
-// If the module doesn't support the app we're being run in, require() will
-// throw.  In that case, remove all tests above from exports, and add one dummy
-// test that passes.
-function unsupported (err) {
-  if (!/^Unsupported Application/.test(err.message))
-    throw err;
-
-  module.exports = {
-    "test Unsupported Application": function Unsupported (assert) {
-      assert.pass(err.message);
-    }
-  };
-}
 require('test').run(exports);
--- a/addon-sdk/source/test/test-places-utils.js
+++ b/addon-sdk/source/test/test-places-utils.js
@@ -1,18 +1,22 @@
 /* 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/. */
 'use strict';
 
+module.metadata = {
+  'engines': {
+    'Firefox': '*'
+  }
+};
+
 const { defer, all } = require('sdk/core/promise');
 const { setTimeout } = require('sdk/timers');
-try {
 const { TreeNode } = require('sdk/places/utils');
-} catch(e) { unsupported(e); }
 
 exports['test construct tree'] = function (assert) {
   let tree = TreeNode(1);
   tree.add([2, 3, 4]);
   tree.get(2).add([2.1, 2.2, 2.3]);
   let newTreeNode = TreeNode(4.3);
   newTreeNode.add([4.31, 4.32]);
   tree.get(4).add([4.1, 4.2, newTreeNode]);
@@ -69,23 +73,9 @@ exports['test async walk'] = function (a
     assert.ok(resultsAll.indexOf(2) < resultsAll.indexOf(2.1),
       'child should wait for parent to complete');
     assert.ok(resultsAll.indexOf(2) < resultsAll.indexOf(2.2),
       'child should wait for parent to complete');
     done();
   });
 };
 
-// If the module doesn't support the app we're being run in, require() will
-// throw.  In that case, remove all tests above from exports, and add one dummy
-// test that passes.
-function unsupported (err) {
-  if (!/^Unsupported Application/.test(err.message))
-    throw err;
-
-  module.exports = {
-    "test Unsupported Application": function Unsupported (assert) {
-      assert.pass(err.message);
-    }
-  };
-}
-
 require('test').run(exports);
--- a/addon-sdk/source/test/test-selection.js
+++ b/addon-sdk/source/test/test-selection.js
@@ -1,13 +1,19 @@
 /* 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/. */
 
-"use strict";
+'use strict';
+
+module.metadata = {
+  'engines': {
+    'Firefox': '*'
+  }
+};
 
 const HTML = "<html>\
   <body>\
     <div>foo</div>\
     <div>and</div>\
     <textarea>noodles</textarea>\
   </body>\
 </html>";
@@ -983,26 +989,9 @@ if (!require("sdk/private-browsing/utils
     if (key.indexOf("test PBPW") === 0) {
       module.exports[key] = function Unsupported (assert) {
         assert.pass("Private Window Per Browsing is not supported on this platform.");
       }
     }
   });
 }
 
-// If the module doesn't support the app we're being run in, require() will
-// throw.  In that case, remove all tests above from exports, and add one dummy
-// test that passes.
-try {
-  require("sdk/selection");
-}
-catch (err) {
-  if (!/^Unsupported Application/.test(err.message))
-    throw err;
-
-  module.exports = {
-    "test Unsupported Application": function Unsupported (assert) {
-      assert.pass(err.message);
-    }
-  }
-}
-
 require("test").run(exports)
--- a/addon-sdk/source/test/test-tab-browser.js
+++ b/addon-sdk/source/test/test-tab-browser.js
@@ -1,12 +1,18 @@
 /* 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/. */
-"use strict";
+'use strict';
+
+module.metadata = {
+  'engines': {
+    'Firefox': '*'
+  }
+};
 
 var timer = require("sdk/timers");
 var { Cc, Ci } = require("chrome");
 
 function onBrowserLoad(callback, event) {
   if (event.target && event.target.defaultView == this) {
     this.removeEventListener("load", onBrowserLoad, true);
     let browsers = this.document.getElementsByTagName("tabbrowser");
@@ -487,26 +493,9 @@ exports.testModuleListenersDontInteract 
 
 /******************* helpers *********************/
 
 // Helper for getting the active window
 function activeWindow() {
   return Cc["@mozilla.org/appshell/window-mediator;1"].
          getService(Ci.nsIWindowMediator).
          getMostRecentWindow("navigator:browser");
-};
-
-// If the module doesn't support the app we're being run in, require() will
-// throw.  In that case, remove all tests above from exports, and add one dummy
-// test that passes.
-try {
-  require("sdk/deprecated/tab-browser");
 }
-catch (err) {
-  if (!/^Unsupported Application/.test(err.message))
-    throw err;
-
-  module.exports = {
-    testAppNotSupported: function (test) {
-      test.pass(err.message);
-    }
-  };
-}
--- a/addon-sdk/source/test/test-test-utils-async.js
+++ b/addon-sdk/source/test/test-test-utils-async.js
@@ -50,27 +50,29 @@ exports.testSyncABefore = function (asse
 };
 
 exports.testSyncAfter = function (assert) {
   assert.equal(AFTER_RUN, 1, 'after function was called for sync test');
   BEFORE_RUN = 0;
   AFTER_RUN = 0;
 };
 
-before(exports, (name, done) => {
+before(exports, (name, assert, done) => {
   if (name === 'testABeforeNameAsync')
     BEFORE_RUN = 2;
   else
     BEFORE_RUN = 1;
+  assert.pass('assert passed into before function');
   async(done)();
 });
 
-after(exports, (name, done) => {
+after(exports, (name, assert, done) => {
   // testAfterName runs after testAfter, which is where this
   // check occurs in the assertation
   if (name === 'testAfterAsync')
     AFTER_RUN = 2;
   else
     AFTER_RUN = 1;
+  assert.pass('assert passed into after function');
   async(done)();
 });
 
 require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-test-utils-sync.js
+++ b/addon-sdk/source/test/test-test-utils-sync.js
@@ -50,25 +50,27 @@ exports.testSyncABefore = function (asse
 };
 
 exports.testSyncAfter = function (assert) {
   assert.equal(AFTER_RUN, 1, 'after function was called for sync test');
   BEFORE_RUN = 0;
   AFTER_RUN = 0;
 };
 
-before(exports, (name) => {
+before(exports, (name, assert) => {
   if (name === 'testABeforeNameAsync')
     BEFORE_RUN = 2;
   else
     BEFORE_RUN = 1;
+  assert.pass('assert passed into before function');
 });
 
-after(exports, (name) => {
+after(exports, (name, assert) => {
   // testAfterName runs after testAfter, which is where this
   // check occurs in the assertation
   if (name === 'testAfterAsync')
     AFTER_RUN = 2;
   else
     AFTER_RUN = 1;
+  assert.pass('assert passed into after function');
 });
 
 require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-widget.js
+++ b/addon-sdk/source/test/test-widget.js
@@ -1,13 +1,20 @@
 /* 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/. */
-"use strict";
+'use strict';
 
+module.metadata = {
+  'engines': {
+    'Firefox': '*'
+  }
+};
+
+const widgets = require("sdk/widget");
 const { Cc, Ci } = require("chrome");
 const { Loader } = require('sdk/test/loader');
 const url = require("sdk/url");
 const timer = require("sdk/timers");
 const self = require("sdk/self");
 const windowUtils = require("sdk/deprecated/window-utils");
 const { getMostRecentBrowserWindow } = require('sdk/window/utils');
 
@@ -1169,27 +1176,8 @@ function closeBrowserWindow(window, call
   timer.setTimeout(function() {
     window.addEventListener("unload", function onUnload() {
       window.removeEventListener("unload", onUnload, false);
       callback();
     }, false);
     window.close();
   }, 0);
 }
-
-// ADD NO TESTS BELOW THIS LINE! ///////////////////////////////////////////////
-
-// If the module doesn't support the app we're being run in, require() will
-// throw.  In that case, remove all tests above from exports, and add one dummy
-// test that passes.
-try {
-  const widgets = require("sdk/widget");
-}
-catch (err) {
-  if (!/^Unsupported Application/.test(err.message))
-    throw err;
-
-  module.exports = {
-    testAppNotSupported: function (test) {
-      test.pass(err.message);
-    }
-  };
-}
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -554,20 +554,23 @@ pref("dom.experimental_forms", true);
 pref("gfx.gralloc.enabled", false);
 
 // XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging
 pref("javascript.options.mem.log", false);
 
 // Increase mark slice time from 10ms to 30ms
 pref("javascript.options.mem.gc_incremental_slice_ms", 30);
 
-pref("javascript.options.mem.gc_high_frequency_heap_growth_max", 150);
+// Increase time to get more high frequency GC on benchmarks from 1000ms to 1500ms
+pref("javascript.options.mem.gc_high_frequency_time_limit_ms", 1500);
+
+pref("javascript.options.mem.gc_high_frequency_heap_growth_max", 300);
 pref("javascript.options.mem.gc_high_frequency_heap_growth_min", 120);
 pref("javascript.options.mem.gc_high_frequency_high_limit_mb", 40);
-pref("javascript.options.mem.gc_high_frequency_low_limit_mb", 10);
+pref("javascript.options.mem.gc_high_frequency_low_limit_mb", 0);
 pref("javascript.options.mem.gc_low_frequency_heap_growth", 120);
 pref("javascript.options.mem.high_water_mark", 6);
 pref("javascript.options.mem.gc_allocation_threshold_mb", 1);
 pref("javascript.options.mem.gc_decommit_threshold_mb", 1);
 
 // Show/Hide scrollbars when active/inactive
 pref("ui.showHideScrollbars", 1);
 
@@ -643,16 +646,19 @@ pref("dom.ipc.processPrelaunch.delayMs",
 // whichever comes first.
 pref("dom.ipc.systemMessageCPULockTimeoutSec", 30);
 
 // Ignore the "dialog=1" feature in window.open.
 pref("dom.disable_window_open_dialog_feature", true);
 
 // Screen reader support
 pref("accessibility.accessfu.activate", 2);
+pref("accessibility.accessfu.quicknav_modes", "Link,Heading,FormElement,Landmark,ListItem");
+// Setting for an utterance order (0 - description first, 1 - description last).
+pref("accessibility.accessfu.utterance", 1);
 // Whether to skip images with empty alt text
 pref("accessibility.accessfu.skip_empty_images", true);
 
 // Enable hit-target fluffing
 pref("ui.touch.radius.enabled", false);
 pref("ui.touch.radius.leftmm", 3);
 pref("ui.touch.radius.topmm", 5);
 pref("ui.touch.radius.rightmm", 3);
@@ -732,11 +738,11 @@ pref("captivedetect.canonicalURL", "http
 pref("captivedetect.canonicalContent", "success\n");
 
 // The url of the manifest we use for ADU pings.
 pref("ping.manifestURL", "https://marketplace.firefox.com/packaged.webapp");
 
 // Enable the disk space watcher
 pref("disk_space_watcher.enabled", true);
 
-// Enable future
-pref("dom.future.enabled", false);
+// Enable promise
+pref("dom.promise.enabled", false);
 
--- a/b2g/chrome/content/forms.js
+++ b/b2g/chrome/content/forms.js
@@ -230,17 +230,23 @@ let FormAssistant = {
       this.focusedElement.removeEventListener('mouseup', this);
       if (!element) {
         this.focusedElement.blur();
       }
     }
 
     this._documentEncoder = null;
     if (this._editor) {
-      this._editor.removeEditorObserver(this);
+      // When the nsIFrame of the input element is reconstructed by
+      // CSS restyling, the editor observers are removed. Catch
+      // [nsIEditor.removeEditorObserver] failure exception if that
+      // happens.
+      try {
+        this._editor.removeEditorObserver(this);
+      } catch (e) {}
       this._editor = null;
     }
 
     if (element) {
       element.addEventListener('mousedown', this);
       element.addEventListener('mouseup', this);
       if (isContentEditable(element)) {
         this._documentEncoder = getDocumentEncoder(element);
@@ -670,17 +676,17 @@ function getListForElement(element) {
 
 // Create a plain text document encode from the focused element.
 function getDocumentEncoder(element) {
   let encoder = Cc["@mozilla.org/layout/documentEncoder;1?type=text/plain"]
                 .createInstance(Ci.nsIDocumentEncoder);
   let flags = Ci.nsIDocumentEncoder.SkipInvisibleContent |
               Ci.nsIDocumentEncoder.OutputRaw |
               Ci.nsIDocumentEncoder.OutputLFLineBreak |
-              Ci.nsIDocumentEncoder.OutputDropInvisibleBreak;
+              Ci.nsIDocumentEncoder.OutputNonTextContentAsPlaceholder;
   encoder.init(element.ownerDocument, "text/plain", flags);
   return encoder;
 }
 
 // Get the visible content text of a content editable element
 function getContentEditableText(element) {
   let doc = element.ownerDocument;
   let range = doc.createRange();
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -174,16 +174,26 @@ SettingsListener.observe('language.curre
     function(value) {
       Services.prefs.setBoolPref('ril.cellbroadcast.disabled', value);
   });
 
   SettingsListener.observe('ril.radio.disabled', false,
     function(value) {
       Services.prefs.setBoolPref('ril.radio.disabled', value);
   });
+
+  SettingsListener.observe('wap.UAProf.url', '',
+    function(value) {
+      Services.prefs.setCharPref('wap.UAProf.url', value);
+  });
+
+  SettingsListener.observe('wap.UAProf.tagname', 'x-wap-profile',
+    function(value) {
+      Services.prefs.setCharPref('wap.UAProf.tagname', value);
+  });
 })();
 
 //=================== DeviceInfo ====================
 Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
 Components.utils.import('resource://gre/modules/ctypes.jsm');
 (function DeviceInfoToSettings() {
   XPCOMUtils.defineLazyServiceGetter(this, 'gSettingsService',
                                      '@mozilla.org/settingsService;1',
--- a/b2g/components/DirectoryProvider.js
+++ b/b2g/components/DirectoryProvider.js
@@ -56,16 +56,25 @@ DirectoryProvider.prototype = {
                       "permissionDBPDir", "UpdRootD"];
     if (localProps.indexOf(prop) != -1) {
       let file = Cc["@mozilla.org/file/local;1"]
                    .createInstance(Ci.nsILocalFile)
       file.initWithPath(LOCAL_DIR);
       persistent.value = true;
       return file;
     }
+    if (prop == "ProfD") {
+      let dir = Cc["@mozilla.org/file/local;1"]
+                  .createInstance(Ci.nsILocalFile);
+      dir.initWithPath(LOCAL_DIR+"/tests/profile");
+      if (dir.exists()) {
+        persistent.value = true;
+        return dir;
+      }
+    }
     if (prop == "coreAppsDir") {
       let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile)
       file.initWithPath("/system/b2g");
       persistent.value = true;
       return file;
     }
     if (prop == UPDATE_ARCHIVE_DIR) {
       // getUpdateDir will set persistent to false since it may toggle between
--- a/b2g/components/moz.build
+++ b/b2g/components/moz.build
@@ -7,35 +7,38 @@
 TEST_DIRS += ['test']
 
 XPIDL_SOURCES += [
     'b2g.idl',
 ]
 
 MODULE = 'B2GComponents'
 
-EXTRA_PP_COMPONENTS += [
+EXTRA_COMPONENTS += [
     'ActivitiesGlue.js',
     'AlertsService.js',
     'B2GAboutRedirector.js',
-    'B2GComponents.manifest',
     'ContentHandler.js',
     'ContentPermissionPrompt.js',
-    'DirectoryProvider.js',
     'FilePicker.js',
     'MailtoProtocolHandler.js',
     'MozKeyboard.js',
     'PaymentGlue.js',
     'ProcessGlobal.js',
-    'RecoveryService.js',
     'SmsProtocolHandler.js',
     'TelProtocolHandler.js',
     'YoutubeProtocolHandler.js',
 ]
 
+EXTRA_PP_COMPONENTS += [
+    'B2GComponents.manifest',
+    'DirectoryProvider.js',
+    'RecoveryService.js',
+]
+
 if CONFIG['MOZ_UPDATER']:
     EXTRA_PP_COMPONENTS += [
         'UpdatePrompt.js',
     ]
 
 EXTRA_JS_MODULES += [
     'ErrorPage.jsm',
     'Keyboard.jsm',
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "9093c20568e0b754c5e288290ba68836d5f397f1", 
+    "revision": "34a53279dad496e201616f5e782bd58ef6d38ae5", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -520,16 +520,17 @@
 @BINPATH@/components/SystemMessageManager.js
 @BINPATH@/components/SystemMessageManager.manifest
 
 @BINPATH@/components/Activities.manifest
 @BINPATH@/components/ActivityOptions.js
 @BINPATH@/components/ActivityProxy.js
 @BINPATH@/components/ActivityRequestHandler.js
 @BINPATH@/components/ActivityWrapper.js
+@BINPATH@/components/ActivityMessageConfigurator.js
 
 @BINPATH@/components/TCPSocket.js
 @BINPATH@/components/TCPSocketParentIntermediary.js
 @BINPATH@/components/TCPSocket.manifest
 
 @BINPATH@/components/AppProtocolHandler.js
 @BINPATH@/components/AppProtocolHandler.manifest
 
--- a/browser/Makefile.in
+++ b/browser/Makefile.in
@@ -2,22 +2,23 @@
 # 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/.
 
 DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
-include $(topsrcdir)/config/config.mk
-
 include $(topsrcdir)/config/rules.mk
 
 ifdef MAKENSISU
 
 # For Windows build the uninstaller during the application build since the
 # uninstaller is included with the application for mar file generation.
 libs::
 	$(MAKE) -C installer/windows uninstaller
 ifdef MOZ_MAINTENANCE_SERVICE
 	$(MAKE) -C installer/windows maintenanceservice_installer
 endif
 endif
+
+check::
+	$(PYTHON) $(topsrcdir)/build/compare-mozconfig/compare-mozconfigs-wrapper.py
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1372700880000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1373408730000">
   <emItems>
       <emItem  blockID="i350" id="sqlmoz@facebook.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
@@ -214,20 +214,16 @@
       <emItem  blockID="i18" id="msntoolbar@msn.com">
                         <versionRange  minVersion=" " maxVersion="6.*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i228" id="crossriderapp5060@crossrider.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i386" id="7lffxtbr@CursorMania_7l.com">
-                        <versionRange  minVersion="0" maxVersion="*" severity="1">
-                    </versionRange>
-                  </emItem>
       <emItem  blockID="i4" id="{4B3803EA-5230-4DC3-A7FC-33638F3D3542}">
                         <versionRange  minVersion="1.2" maxVersion="1.2">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i75" os="Darwin,Linux" id="firebug@software.joehewitt.com">
@@ -280,20 +276,16 @@
       <emItem  blockID="i256" id="/^[0-9a-f]+@[0-9a-f]+\.info/">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i370" id="happylyrics@hpyproductions.net">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i388" id="5mffxtbr@MyFunCards_5m.com">
-                        <versionRange  minVersion="0" maxVersion="*" severity="1">
-                    </versionRange>
-                  </emItem>
       <emItem  blockID="i396" id="/@(ft|putlocker|clickmovie|m2k|sharerepo|smarter-?)downloader\.com$/">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i22" id="ShopperReports@ShopperReports.com">
                         <versionRange  minVersion="3.1.22.0" maxVersion="3.1.22.0">
                     </versionRange>
                   </emItem>
@@ -386,16 +378,20 @@
       <emItem  blockID="i394" id="{7D4F1959-3F72-49d5-8E59-F02F8AA6815D}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i344" id="lrcsTube@hansanddeta.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i426" id="addlyrics@addlyrics.net">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i404" id="{a9bb9fa0-4122-4c75-bd9a-bc27db3f9155}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i83" id="flash@adobee.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
@@ -571,20 +567,16 @@
       <emItem  blockID="i70" id="psid-vhvxQHMZBOzUZA@jetpack">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i306" id="{ADFA33FD-16F5-4355-8504-DF4D664CFE10}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i384" id="7lffxtbr@PopularScreensavers_7l.com">
-                        <versionRange  minVersion="0" maxVersion="*" severity="1">
-                    </versionRange>
-                  </emItem>
       <emItem  blockID="i165" id="{EEF73632-A085-4fd3-A778-ECD82C8CB297}">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i60" id="youtb3@youtb3.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
--- a/browser/app/firefox.exe.manifest
+++ b/browser/app/firefox.exe.manifest
@@ -28,12 +28,15 @@
 </ms_asmv3:trustInfo>
   <ms_asmv3:application xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
     <ms_asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
       <dpiAware>true</dpiAware>
     </ms_asmv3:windowsSettings>
   </ms_asmv3:application>
   <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
     <application>
-      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
+      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
     </application>
   </compatibility>
 </assembly>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -202,17 +202,16 @@ pref("extensions.update.interval", 86400
 pref("extensions.dss.enabled", false);          // Dynamic Skin Switching                                               
 pref("extensions.dss.switchPending", false);    // Non-dynamic switch pending after next
                                                 // restart.
 
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name", "chrome://browser/locale/browser.properties");
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description", "chrome://browser/locale/browser.properties");
 
 pref("xpinstall.whitelist.add", "addons.mozilla.org");
-pref("xpinstall.whitelist.add.36", "getpersonas.com");
 pref("xpinstall.whitelist.add.180", "marketplace.firefox.com");
 
 pref("lightweightThemes.update.enabled", true);
 
 pref("keyword.enabled", true);
 
 pref("general.useragent.locale", "@AB_CD@");
 pref("general.skins.selectedSkin", "classic/1.0");
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3663,20 +3663,18 @@ var XULBrowserWindow = {
   get isImage () {
     delete this.isImage;
     return this.isImage = document.getElementById("isImage");
   },
 
   init: function () {
     this.throbberElement = document.getElementById("navigator-throbber");
 
-    // Initialize the security button's state and tooltip text.  Remember to reset
-    // _hostChanged, otherwise onSecurityChange will short circuit.
+    // Initialize the security button's state and tooltip text.
     var securityUI = gBrowser.securityUI;
-    this._hostChanged = true;
     this.onSecurityChange(null, null, securityUI.state);
   },
 
   destroy: function () {
     // XXXjag to avoid leaks :-/, see bug 60729
     delete this.throbberElement;
     delete this.stopCommand;
     delete this.reloadCommand;
@@ -3857,17 +3855,16 @@ var XULBrowserWindow = {
         this.stopCommand.setAttribute("disabled", "true");
         CombinedStopReload.switchToReload(aRequest instanceof Ci.nsIRequest);
       }
     }
   },
 
   onLocationChange: function (aWebProgress, aRequest, aLocationURI, aFlags) {
     var location = aLocationURI ? aLocationURI.spec : "";
-    this._hostChanged = true;
 
     // Hide the form invalid popup.
     if (gFormSubmitObserver.panel) {
       gFormSubmitObserver.panel.hidePopup();
     }
 
     let pageTooltip = document.getElementById("aHTMLTooltip");
     let tooltipNode = pageTooltip.triggerNode;
@@ -3968,26 +3965,16 @@ var XULBrowserWindow = {
           if (content.document.readyState == "interactive" || content.document.readyState == "complete")
             disableFindCommands(shouldDisableFind(content.document));
           else {
             content.document.addEventListener("readystatechange", onContentRSChange);
           }
         }
       } else
         disableFindCommands(false);
-
-      if (gFindBarInitialized) {
-        if (gFindBar.findMode != gFindBar.FIND_NORMAL) {
-          // Close the Find toolbar if we're in old-style TAF mode
-          gFindBar.close();
-        }
-
-        // fix bug 253793 - turn off highlight when page changes
-        gFindBar.getElement("highlight").checked = false;
-      }
     }
     UpdateBackForwardCommands(gBrowser.webNavigation);
 
     gGestureSupport.restoreRotationState();
 
     // See bug 358202, when tabs are switched during a drag operation,
     // timers don't fire on windows (bug 203573)
     if (aRequest)
@@ -4009,47 +3996,28 @@ var XULBrowserWindow = {
 
   onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
     this.status = aMessage;
     this.updateStatusField();
   },
 
   // Properties used to cache security state used to update the UI
   _state: null,
-  _hostChanged: false, // onLocationChange will flip this bit
+  _lastLocation: null,
 
   onSecurityChange: function (aWebProgress, aRequest, aState) {
     // Don't need to do anything if the data we use to update the UI hasn't
     // changed
+    let uri = gBrowser.currentURI;
+    let spec = uri.spec;
     if (this._state == aState &&
-        !this._hostChanged) {
-#ifdef DEBUG
-      try {
-        var contentHost = gBrowser.contentWindow.location.host;
-        if (this._host !== undefined && this._host != contentHost) {
-            Components.utils.reportError(
-              "ASSERTION: browser.js host is inconsistent. Content window has " +
-              "<" + contentHost + "> but cached host is <" + this._host + ">.\n"
-            );
-        }
-      } catch (ex) {}
-#endif
+        this._lastLocation == spec)
       return;
-    }
     this._state = aState;
-
-#ifdef DEBUG
-    try {
-      this._host = gBrowser.contentWindow.location.host;
-    } catch(ex) {
-      this._host = null;
-    }
-#endif
-
-    this._hostChanged = false;
+    this._lastLocation = spec;
 
     // aState is defined as a bitmask that may be extended in the future.
     // We filter out any unknown bits before testing for known values.
     const wpl = Components.interfaces.nsIWebProgressListener;
     const wpl_security_bits = wpl.STATE_IS_SECURE |
                               wpl.STATE_IS_BROKEN |
                               wpl.STATE_IS_INSECURE;
     var level;
@@ -4068,17 +4036,16 @@ var XULBrowserWindow = {
       // anymore, but still set it for third-party themes.
       if (gURLBar)
         gURLBar.setAttribute("level", level);
     } else {
       if (gURLBar)
         gURLBar.removeAttribute("level");
     }
 
-    let uri = gBrowser.currentURI;
     try {
       uri = Services.uriFixup.createExposableURI(uri);
     } catch (e) {}
     gIdentityHandler.checkIdentity(this._state, uri);
   },
 
   // simulate all change notifications after switching tabs
   onUpdateCurrentBrowser: function XWB_onUpdateCurrentBrowser(aStateFlags, aStatus, aMessage, aTotalProgress) {
@@ -6896,17 +6863,17 @@ var gIdentityHandler = {
   _createPermissionItem: function (aPermission, aState) {
     let menulist = document.createElement("menulist");
     let menupopup = document.createElement("menupopup");
     for (let state of SitePermissions.getAvailableStates(aPermission)) {
       if (state == SitePermissions.UNKNOWN)
         continue;
       let menuitem = document.createElement("menuitem");
       menuitem.setAttribute("value", state);
-      menuitem.setAttribute("label", SitePermissions.getStateLabel(state));
+      menuitem.setAttribute("label", SitePermissions.getStateLabel(aPermission, state));
       menupopup.appendChild(menuitem);
     }
     menulist.appendChild(menupopup);
     menulist.setAttribute("value", aState);
     menulist.setAttribute("oncommand", "SitePermissions.set(gBrowser.currentURI, '" +
                                        aPermission + "', this.value)");
     menulist.setAttribute("id", "identity-popup-permission:" + aPermission);
 
--- a/browser/base/content/pageinfo/permissions.js
+++ b/browser/base/content/pageinfo/permissions.js
@@ -129,17 +129,17 @@ function createRow(aPartId) {
   controls.appendChild(spacer);
 
   let radiogroup = document.createElement("radiogroup");
   radiogroup.setAttribute("id", radiogroupId);
   radiogroup.setAttribute("orient", "horizontal");
   for (let state of SitePermissions.getAvailableStates(aPartId)) {
     let radio = document.createElement("radio");
     radio.setAttribute("id", aPartId + "#" + state);
-    radio.setAttribute("label", SitePermissions.getStateLabel(state));
+    radio.setAttribute("label", SitePermissions.getStateLabel(aPartId, state));
     radio.setAttribute("command", commandId);
     radiogroup.appendChild(radio);
   }
   controls.appendChild(radiogroup);
 
   row.appendChild(controls);
 
   document.getElementById("permList").appendChild(row);
--- a/browser/base/content/safeMode.js
+++ b/browser/base/content/safeMode.js
@@ -4,16 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cu = Components.utils;
 
 const appStartup = Services.startup;
 
+Cu.import("resource://gre/modules/ResetProfile.jsm");
+
 let defaultToReset = false;
 
 function restartApp() {
   appStartup.quit(appStartup.eForceQuit | appStartup.eRestart);
 }
 
 function resetProfile() {
   // Set the reset profile environment variable.
@@ -64,23 +66,23 @@ function onExtra1() {
   return false;
 }
 
 function onLoad() {
   let dialog = document.documentElement;
   if (appStartup.automaticSafeModeNecessary) {
     document.getElementById("autoSafeMode").hidden = false;
     document.getElementById("safeMode").hidden = true;
-    if (resetSupported()) {
+    if (ResetProfile.resetSupported()) {
       populateResetPane("resetProfileItems");
       document.getElementById("resetProfile").hidden = false;
     } else {
       // Hide the reset button is it's not supported.
       document.documentElement.getButton("extra1").hidden = true;
     }
   } else {
-    if (!resetSupported()) {
+    if (!ResetProfile.resetSupported()) {
       // Hide the reset button and text if it's not supported.
       document.documentElement.getButton("extra1").hidden = true;
       document.getElementById("resetProfileInstead").hidden = true;
     }
   }
 }
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -153,17 +153,18 @@
             aTab = this.selectedTab;
 
           if (aTab._findBar)
             return aTab._findBar;
 
           let findBar = document.createElementNS(this.namespaceURI, "findbar");
           let browser = this.getBrowserForTab(aTab);
           let browserContainer = this.getBrowserContainer(browser);
-          browserContainer.appendChild(findBar);
+          findBar.setAttribute("position", "top");
+          browserContainer.insertBefore(findBar, browserContainer.firstChild);
 
           // Force a style flush to ensure that our binding is attached.
           findBar.clientTop;
 
           findBar.browser = browser;
           findBar._findField.value = this._lastFindValue;
 
           aTab._findBar = findBar;
@@ -682,16 +683,27 @@
                 if (this.mBrowser.userTypedClear > 0 ||
                     (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE))
                   this.mBrowser.userTypedValue = null;
 
                 // Clear out the missing plugins list since it's related to the
                 // previous location.
                 this.mBrowser.missingPlugins = null;
 
+                if (this.mTabBrowser.isFindBarInitialized(this.mTab)) {
+                  let findBar = this.mTabBrowser.getFindBar(this.mTab);
+
+                  // Close the Find toolbar if we're in old-style TAF mode
+                  if (findBar.findMode != findBar.FIND_NORMAL)
+                    findBar.close();
+
+                  // fix bug 253793 - turn off highlight when page changes
+                  findBar.getElement("highlight").checked = false;
+                }
+
                 // Don't clear the favicon if this onLocationChange was
                 // triggered by a pushState or a replaceState.  See bug 550565.
                 if (!gMultiProcessBrowser) {
                   if (aWebProgress.isLoadingDocument &&
                       !(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE))
                     this.mBrowser.mIconURL = null;
                 }
 
@@ -1088,21 +1100,21 @@
                     gURLBar.focus();
                     break;
                   } else if (isTabEmpty(this.mCurrentTab)) {
                     focusAndSelectUrlBar();
                     break;
                   }
                 }
 
-                // If the find bar is focused, keep it focused.
-                if (gFindBarInitialized &&
-                    !gFindBar.hidden &&
-                    gFindBar.getElement("findbar-textbox").getAttribute("focused") == "true")
+                // If the find bar is open, focus it.
+                if (gFindBarInitialized && !gFindBar.hidden) {
+                  gFindBar._findField.focus();
                   break;
+                }
 
                 // Otherwise, focus the content area.
                 let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
                 let focusFlags = fm.FLAG_NOSCROLL;
 
                 if (!gMultiProcessBrowser) {
                   let newFocusedElement = fm.getFocusedElementForWindow(window.content, true, {});
 
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -6,101 +6,110 @@ DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_FILES = \
-		head_plain.js \
-		test_feed_discovery.html \
-		feed_discovery.html \
-		test_bug395533.html \
-		bug395533-data.txt \
-		ctxmenu-image.png \
-		video.ogg \
-		test_offlineNotification.html \
-		offlineChild.html \
-		offlineChild.cacheManifest \
-		offlineChild.cacheManifest^headers^ \
-		offlineChild2.html \
-		offlineChild2.cacheManifest \
-		offlineChild2.cacheManifest^headers^ \
-		offlineEvent.html \
-		offlineEvent.cacheManifest \
-		offlineEvent.cacheManifest^headers^ \
-		test_bug364677.html \
-		bug364677-data.xml \
-		bug364677-data.xml^headers^ \
-		test_offline_gzip.html \
-		gZipOfflineChild.html \
-		gZipOfflineChild.html^headers^ \
-		gZipOfflineChild.cacheManifest \
-		gZipOfflineChild.cacheManifest^headers^ \
-		$(NULL)
+        head_plain.js \
+        bug364677-data.xml \
+        bug364677-data.xml^headers^ \
+        bug395533-data.txt \
+        ctxmenu-image.png \
+        feed_discovery.html \
+        gZipOfflineChild.cacheManifest \
+        gZipOfflineChild.cacheManifest^headers^ \
+        gZipOfflineChild.html \
+        gZipOfflineChild.html^headers^ \
+        offlineChild.cacheManifest \
+        offlineChild.cacheManifest^headers^ \
+        offlineChild.html \
+        offlineChild2.cacheManifest \
+        offlineChild2.cacheManifest^headers^ \
+        offlineChild2.html \
+        offlineEvent.cacheManifest \
+        offlineEvent.cacheManifest^headers^ \
+        offlineEvent.html \
+        test_bug364677.html \
+        test_bug395533.html \
+        test_feed_discovery.html \
+        test_offline_gzip.html \
+        test_offlineNotification.html \
+        video.ogg \
+        $(NULL)
 
 # test_contextmenu.html is disabled on Linux due to bug 513558
 ifndef MOZ_WIDGET_GTK
 MOCHITEST_FILES += \
-		audio.ogg \
-		test_contextmenu.html \
-		subtst_contextmenu.html \
-		privateBrowsingMode.js \
-		$(NULL)
+        audio.ogg \
+        privateBrowsingMode.js \
+        subtst_contextmenu.html \
+        test_contextmenu.html \
+        $(NULL)
 endif
 
 # The following tests are disabled because they are unreliable:
 #   browser_bug423833.js is bug 428712
 #   browser_sanitize-download-history.js is bug 432425
 #
 # browser_sanitizeDialog_treeView.js is disabled until the tree view is added
 # back to the clear recent history dialog (sanitize.xul), if it ever is (bug
 # 480169)
 
 # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 
 # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
 
 MOCHITEST_BROWSER_FILES = \
                  head.js \
-                 browser_typeAheadFind.js \
-                 browser_keywordSearch.js \
-                 browser_keywordSearch_postData.js \
-                 POSTSearchEngine.xml \
-                 print_postdata.sjs \
+                 alltabslistener.html \
+                 app_bug575561.html \
+                 app_subframe_bug575561.html \
+                 authenticate.sjs \
+                 blockNoPlugins.xml \
+                 blockPluginHard.xml \
+                 blockPluginVulnerableNoUpdate.xml \
+                 blockPluginVulnerableUpdatable.xml \
+                 browser_aboutHealthReport.js \
+                 browser_aboutHome.js \
+                 browser_aboutSyncProgress.js \
+                 browser_addKeywordSearch.js \
+                 browser_addon_bar_aomlistener.js \
+                 browser_addon_bar_close_button.js \
+                 browser_addon_bar_shortcut.js \
                  browser_alltabslistener.js \
+                 browser_blob-channelname.js \
                  browser_bug304198.js \
-                 title_test.svg \
                  browser_bug329212.js \
                  browser_bug356571.js \
                  browser_bug380960.js \
-	         browser_bug386835.js \
+                 browser_bug386835.js \
                  browser_bug405137.js \
                  browser_bug406216.js \
                  browser_bug409481.js \
                  browser_bug409624.js \
                  browser_bug413915.js \
                  browser_bug416661.js \
                  browser_bug417483.js \
                  browser_bug419612.js \
-                 browser_identity_UI.js \
                  browser_bug422590.js \
                  browser_bug424101.js \
                  browser_bug427559.js \
                  browser_bug432599.js \
                  browser_bug435035.js \
                  browser_bug435325.js \
                  browser_bug441778.js \
                  browser_bug455852.js \
                  browser_bug460146.js \
                  browser_bug462673.js \
                  browser_bug477014.js \
+                 browser_bug479408_sample.html \
                  browser_bug479408.js \
-                 browser_bug479408_sample.html \
                  browser_bug481560.js \
                  browser_bug484315.js \
                  browser_bug491431.js \
                  browser_bug495058.js \
                  browser_bug517902.js \
                  browser_bug519216.js \
                  browser_bug520538.js \
                  browser_bug521216.js \
@@ -113,17 +122,16 @@ MOCHITEST_BROWSER_FILES = \
                  browser_bug555767.js \
                  browser_bug556061.js \
                  browser_bug559991.js \
                  browser_bug561623.js \
                  browser_bug562649.js \
                  browser_bug563588.js \
                  browser_bug565575.js \
                  browser_bug567306.js \
-                 browser_zbug569342.js \
                  browser_bug575561.js \
                  browser_bug575830.js \
                  browser_bug577121.js \
                  browser_bug578534.js \
                  browser_bug579872.js \
                  browser_bug580638.js \
                  browser_bug580956.js \
                  browser_bug581242.js \
@@ -143,196 +151,189 @@ MOCHITEST_BROWSER_FILES = \
                  browser_bug609700.js \
                  browser_bug616836.js \
                  browser_bug623155.js \
                  browser_bug623893.js \
                  browser_bug624734.js \
                  browser_bug647886.js \
                  browser_bug655584.js \
                  browser_bug664672.js \
-                 browser_bug678392.js \
+                 browser_bug676619.js \
                  browser_bug678392-1.html \
                  browser_bug678392-2.html \
+                 browser_bug678392.js \
                  browser_bug710878.js \
                  browser_bug719271.js \
                  browser_bug724239.js \
+                 browser_bug734076.js \
                  browser_bug735471.js \
                  browser_bug743421.js \
+                 browser_bug744745.js \
                  browser_bug749738.js \
                  browser_bug752516.js \
                  browser_bug763468_perwindowpb.js \
                  browser_bug767836_perwindowpb.js \
                  browser_bug771331.js \
                  browser_bug783614.js \
+                 browser_bug787619.js \
                  browser_bug797677.js \
+                 browser_bug812562.js \
                  browser_bug816527.js \
                  browser_bug817947.js \
+                 browser_bug818118.js \
+                 browser_bug820497.js \
                  browser_bug822367.js \
                  browser_bug832435.js \
                  browser_bug839103.js \
+                 browser_bug882977.js \
                  browser_canonizeURL.js \
-                 browser_customize.js \
-                 browser_findbarClose.js \
-                 browser_homeDrop.js \
-                 browser_keywordBookmarklets.js \
+                 browser_clearplugindata_noage.html \
+                 browser_clearplugindata.html \
+                 browser_clearplugindata.js \
+                 browser_contentAreaClick.js \
                  browser_contextSearchTabPosition.js \
+                 browser_CTP_drag_drop.js \
                  browser_ctrlTab.js \
                  browser_customize_popupNotification.js \
+                 browser_customize.js \
                  browser_disablechrome.js \
                  browser_discovery.js \
                  browser_duplicateIDs.js \
+                 browser_findbarClose.js \
                  browser_fullscreen-window-open.js \
-                 file_fullscreen-window-open.html \
                  browser_gestureSupport.js \
                  browser_getshortcutoruri.js \
                  browser_hide_removing.js \
-                 browser_overflowScroll.js \
+                 browser_homeDrop.js \
+                 browser_identity_UI.js \
+                 browser_keywordBookmarklets.js \
+                 browser_keywordSearch_postData.js \
+                 browser_keywordSearch.js \
+                 browser_lastAccessedTab.js \
                  browser_locationBarCommand.js \
                  browser_locationBarExternalLoad.js \
+                 browser_middleMouse_inherit.js \
+                 browser_minimize.js \
+                 browser_offlineQuotaNotification.js \
+                 browser_overflowScroll.js \
                  browser_page_style_menu.js \
+                 browser_pageInfo_plugins.js \
+                 browser_pageInfo.js \
                  browser_pinnedTabs.js \
                  browser_plainTextLinks.js \
+                 browser_pluginCrashCommentAndURL.js \
                  browser_pluginnotification.js \
-                 browser_plugins_added_dynamically.js \
-                 browser_CTP_drag_drop.js \
                  browser_pluginplaypreview.js \
                  browser_pluginplaypreview2.js \
+                 browser_plugins_added_dynamically.js \
+                 browser_popupUI.js \
                  browser_private_browsing_window.js \
+                 browser_private_no_prompt.js \
                  browser_relatedTabs.js \
                  browser_removeTabsToTheEnd.js \
                  browser_sanitize-passwordDisabledHosts.js \
                  browser_sanitize-sitepermissions.js \
                  browser_sanitize-timespans.js \
-                 browser_tabopen_reflows.js \
-                 browser_clearplugindata.js \
-                 browser_clearplugindata.html \
-                 browser_clearplugindata_noage.html \
-                 browser_popupUI.js \
                  browser_sanitizeDialog.js \
                  browser_save_link-perwindowpb.js \
                  browser_save_private_link_perwindowpb.js \
                  browser_save_video.js \
-                 browser_tabMatchesInAwesomebar_perwindowpb.js \
-                 browser_tab_drag_drop_perwindow.js \
-                 bug564387.html \
-                 bug564387_video1.ogv \
-                 bug564387_video1.ogv^headers^ \
-                 bug792517.html \
-                 bug792517-2.html \
-                 bug792517.sjs \
-                 test_bug839103.html \
-                 bug839103.css \
                  browser_scope.js \
                  browser_selectTabAtIndex.js \
+                 browser_tab_drag_drop_perwindow.js \
                  browser_tab_dragdrop.js \
+                 browser_tab_dragdrop2_frame1.xul \
                  browser_tab_dragdrop2.js \
-                 browser_tab_dragdrop2_frame1.xul \
+                 browser_tabDrop.js \
                  browser_tabfocus.js \
+                 browser_tabMatchesInAwesomebar_perwindowpb.js \
+                 browser_tabopen_reflows.js \
                  browser_tabs_isActive.js \
                  browser_tabs_owner.js \
+                 browser_typeAheadFind.js \
                  browser_unloaddialogs.js \
+                 browser_urlbar_search_healthreport.js \
                  browser_urlbarAutoFillTrimURLs.js \
                  browser_urlbarCopying.js \
                  browser_urlbarEnter.js \
                  browser_urlbarRevert.js \
+                 browser_URLBarSetURI.js \
                  browser_urlbarStop.js \
                  browser_urlbarTrimURLs.js \
-                 browser_urlbar_search_healthreport.js \
                  browser_urlHighlight.js \
+                 browser_utilityOverlay.js \
                  browser_visibleFindSelection.js \
-                 browser_visibleTabs.js \
-                 browser_visibleTabs_contextMenu.js \
                  browser_visibleTabs_bookmarkAllPages.js \
                  browser_visibleTabs_bookmarkAllTabs.js \
+                 browser_visibleTabs_contextMenu.js \
                  browser_visibleTabs_tabPreview.js \
+                 browser_visibleTabs.js \
+                 browser_wyciwyg_urlbarCopying.js \
+                 browser_zbug569342.js \
+                 bug564387_video1.ogv \
+                 bug564387_video1.ogv^headers^ \
+                 bug564387.html \
                  bug592338.html \
+                 bug792517-2.html \
+                 bug792517.html \
+                 bug792517.sjs \
+                 bug839103.css \
                  disablechrome.html \
                  discovery.html \
                  domplate_test.js \
+                 download_page.html \
+                 dummy_page.html \
+                 feed_tab.html \
+                 file_bug550565_favicon.ico \
+                 file_bug550565_popup.html \
                  file_bug822367_1.html \
                  file_bug822367_1.js \
                  file_bug822367_2.html \
                  file_bug822367_3.html \
                  file_bug822367_4.html \
                  file_bug822367_4.js \
                  file_bug822367_4B.html \
                  file_bug822367_5.html \
                  file_bug822367_6.html \
+                 file_fullscreen-window-open.html \
+                 healthreport_testRemoteCommands.html \
                  moz.png \
-                 video.ogg \
-                 test_bug435035.html \
-                 test_bug462673.html \
+                 offlineQuotaNotification.cacheManifest \
+                 offlineQuotaNotification.html \
                  page_style_sample.html \
-                 plugin_unknown.html \
-                 plugin_test.html \
-                 plugin_test2.html \
-                 plugin_test3.html \
+                 plugin_add_dynamically.html \
                  plugin_alternate_content.html \
                  plugin_both.html \
                  plugin_both2.html \
-                 plugin_add_dynamically.html \
-                 plugin_clickToPlayAllow.html \
-                 plugin_clickToPlayDeny.html \
                  plugin_bug744745.html \
                  plugin_bug749455.html \
                  plugin_bug752516.html \
                  plugin_bug787619.html \
                  plugin_bug797677.html \
                  plugin_bug820497.html \
+                 plugin_clickToPlayAllow.html \
+                 plugin_clickToPlayDeny.html \
                  plugin_hidden_to_visible.html \
+                 plugin_test.html \
+                 plugin_test2.html \
+                 plugin_test3.html \
                  plugin_two_types.html \
-                 alltabslistener.html \
-                 zoom_test.html \
-                 dummy_page.html \
-                 file_bug550565_popup.html \
-                 file_bug550565_favicon.ico \
-                 browser_aboutHome.js \
-                 app_bug575561.html \
-                 app_subframe_bug575561.html \
-                 browser_contentAreaClick.js \
-                 browser_addon_bar_close_button.js \
-                 browser_addon_bar_shortcut.js \
-                 browser_addon_bar_aomlistener.js \
-                 test_bug628179.html \
-                 browser_wyciwyg_urlbarCopying.js \
-                 test_wyciwyg_copying.html \
-                 authenticate.sjs \
-                 browser_minimize.js \
-                 browser_aboutSyncProgress.js \
-                 browser_middleMouse_inherit.js \
+                 plugin_unknown.html \
+                 pluginCrashCommentAndURL.html \
+                 POSTSearchEngine.xml \
+                 print_postdata.sjs \
                  redirect_bug623155.sjs \
-                 browser_tabDrop.js \
-                 browser_lastAccessedTab.js \
-                 browser_bug734076.js \
-                 browser_bug744745.js \
-                 browser_bug787619.js \
-                 browser_bug812562.js \
-                 browser_bug818118.js \
-                 browser_bug820497.js \
-                 blockPluginVulnerableUpdatable.xml \
-                 blockPluginVulnerableNoUpdate.xml \
-                 blockNoPlugins.xml \
-                 blockPluginHard.xml \
-                 browser_utilityOverlay.js \
-                 browser_bug676619.js \
-                 download_page.html \
-                 browser_URLBarSetURI.js \
-                 browser_pageInfo_plugins.js \
-                 browser_pageInfo.js \
-                 feed_tab.html \
-                 browser_pluginCrashCommentAndURL.js \
-                 pluginCrashCommentAndURL.html \
-                 browser_private_no_prompt.js \
-                 browser_blob-channelname.js \
-                 browser_aboutHealthReport.js \
-                 healthreport_testRemoteCommands.html \
-                 browser_offlineQuotaNotification.js \
-                 offlineQuotaNotification.html \
-                 offlineQuotaNotification.cacheManifest \
-                 browser_addKeywordSearch.js \
+                 test_bug435035.html \
+                 test_bug462673.html \
+                 test_bug628179.html \
+                 test_bug839103.html \
+                 test_wyciwyg_copying.html \
+                 title_test.svg \
+                 video.ogg \
+                 zoom_test.html \
                  $(NULL)
 
 # Disable tests on Windows due to frequent failures (bugs 825739, 841341)
 ifneq (windows,$(MOZ_WIDGET_TOOLKIT))
 MOCHITEST_BROWSER_FILES += \
                  browser_bookmark_titles.js \
                  browser_popupNotification.js \
                  $(NULL)
--- a/browser/base/content/test/browser_CTP_drag_drop.js
+++ b/browser/base/content/test/browser_CTP_drag_drop.js
@@ -82,17 +82,17 @@ function part7() {
   ok(PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser), "Should have a click-to-play notification in the tab in the new window");
   ok(!PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should not have a click-to-play notification in the old window now");
 
   let plugin = gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test");
   let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "plugin should not be activated");
 
   EventUtils.synthesizeMouseAtCenter(plugin, {}, gNewWindow.gBrowser.selectedBrowser.contentWindow);
-  let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser).dismissed;
+  let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser).dismissed && gNewWindow.PopupNotifications.panel.firstChild;
   waitForCondition(condition, part8, "waited too long for plugin to activate");
 }
 
 function part8() {
   // Click the activate button on doorhanger to make sure it works
   gNewWindow.PopupNotifications.panel.firstChild._primaryButton.click();
 
   let plugin = gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test");
--- a/browser/base/content/test/browser_aboutHome.js
+++ b/browser/base/content/test/browser_aboutHome.js
@@ -84,87 +84,55 @@ let gTests = [
        "Search engine logo's alt text is a nonempty string");
 
     isnot(altText, "undefined",
           "Search engine logo's alt text shouldn't be the string 'undefined'");
   }
 },
 
 {
-  desc: "Check that performing a search fires a search event.",
-  setup: function () { },
-  run: function () {
-    let deferred = Promise.defer();
-    let doc = gBrowser.contentDocument;
-
-    doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
-      is(e.detail, doc.documentElement.getAttribute("searchEngineName"), "Detail is search engine name");
-
-      gBrowser.stop();
-      deferred.resolve();
-    }, true, true);
-
-    doc.getElementById("searchText").value = "it works";
-    doc.getElementById("searchSubmit").click();
-    return deferred.promise;
-  }
-},
-
-{
-  desc: "Check that performing a search records to Firefox Health Report.",
+  desc: "Check that performing a search fires a search event and records to " +
+        "Firefox Health Report.",
   setup: function () { },
   run: function () {
     try {
       let cm = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
       cm.getCategoryEntry("healthreport-js-provider-default", "SearchesProvider");
     } catch (ex) {
       // Health Report disabled, or no SearchesProvider.
       return Promise.resolve();
     }
 
+    let numSearchesBefore = 0;
     let deferred = Promise.defer();
     let doc = gBrowser.contentDocument;
+    let engineName = doc.documentElement.getAttribute("searchEngineName");
 
     // We rely on the listener in browser.js being installed and fired before
     // this one. If this ever changes, we should add an executeSoon() or similar.
     doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
-      executeSoon(gBrowser.stop.bind(gBrowser));
-      let reporter = Components.classes["@mozilla.org/datareporting/service;1"]
-                                       .getService()
-                                       .wrappedJSObject
-                                       .healthReporter;
-      ok(reporter, "Health Reporter instance available.");
+      is(e.detail, engineName, "Detail is search engine name");
 
-      reporter.onInit().then(function onInit() {
-        let provider = reporter.getProvider("org.mozilla.searches");
-        ok(provider, "Searches provider is available.");
-
-        let engineName = doc.documentElement.getAttribute("searchEngineName");
-        let id = Services.search.getEngineByName(engineName).identifier;
+      gBrowser.stop();
 
-        let m = provider.getMeasurement("counts", 2);
-        m.getValues().then(function onValues(data) {
-          let now = new Date();
-          ok(data.days.hasDay(now), "Have data for today.");
-
-          let day = data.days.getDay(now);
-          let field = id + ".abouthome";
-          ok(day.has(field), "Have data for about home on this engine.");
-
-          // Note the search from the previous test.
-          is(day.get(field), 2, "Have searches recorded.");
-
-          deferred.resolve();
-        });
-
+      getNumberOfSearches(engineName).then(num => {
+        is(num, numSearchesBefore + 1, "One more search recorded.");
+        deferred.resolve();
       });
     }, true, true);
 
-    doc.getElementById("searchText").value = "a search";
-    doc.getElementById("searchSubmit").click();
+    // Get the current number of recorded searches.
+    getNumberOfSearches(engineName).then(num => {
+      numSearchesBefore = num;
+
+      info("Perform a search.");
+      doc.getElementById("searchText").value = "a search";
+      doc.getElementById("searchSubmit").click();
+    });
+
     return deferred.promise;
   }
 },
 
 {
   desc: "Check snippets map is cleared if cached version is old",
   setup: function (aSnippetsMap)
   {
@@ -290,16 +258,17 @@ let gTests = [
 }
 
 ];
 
 function test()
 {
   waitForExplicitFinish();
   requestLongerTimeout(2);
+  ignoreAllUncaughtExceptions();
 
   Task.spawn(function () {
     for (let test of gTests) {
       info(test.desc);
 
       if (test.beforeRun)
         yield test.beforeRun();
 
@@ -417,8 +386,60 @@ function promiseBrowserAttributes(aTab)
       }
     }
   });
   info("Add attributes observer");
   observer.observe(docElt, { attributes: true });
 
   return deferred.promise;
 }
+
+/**
+ * Retrieves the number of about:home searches recorded for the current day.
+ *
+ * @param aEngineName
+ *        name of the setup search engine.
+ *
+ * @return {Promise} Returns a promise resolving to the number of searches.
+ */
+function getNumberOfSearches(aEngineName) {
+  let reporter = Components.classes["@mozilla.org/datareporting/service;1"]
+                                   .getService()
+                                   .wrappedJSObject
+                                   .healthReporter;
+  ok(reporter, "Health Reporter instance available.");
+
+  return reporter.onInit().then(function onInit() {
+    let provider = reporter.getProvider("org.mozilla.searches");
+    ok(provider, "Searches provider is available.");
+
+    let m = provider.getMeasurement("counts", 2);
+    return m.getValues().then(data => {
+      let now = new Date();
+      let yday = new Date(now);
+      yday.setDate(yday.getDate() - 1);
+
+      // Add the number of searches recorded yesterday to the number of searches
+      // recorded today. This makes the test not fail intermittently when it is
+      // run at midnight and we accidentally compare the number of searches from
+      // different days. Tests are always run with an empty profile so there
+      // are no searches from yesterday, normally. Should the test happen to run
+      // past midnight we make sure to count them in as well.
+      return getNumberOfSearchesByDate(aEngineName, data, now) +
+             getNumberOfSearchesByDate(aEngineName, data, yday);
+    });
+  });
+}
+
+function getNumberOfSearchesByDate(aEngineName, aData, aDate) {
+  if (aData.days.hasDay(aDate)) {
+    let id = Services.search.getEngineByName(aEngineName).identifier;
+
+    let day = aData.days.getDay(aDate);
+    let field = id + ".abouthome";
+
+    if (day.has(field)) {
+      return day.get(field) || 0;
+    }
+  }
+
+  return 0; // No records found.
+}
--- a/browser/base/content/test/browser_bookmark_titles.js
+++ b/browser/base/content/test/browser_bookmark_titles.js
@@ -36,17 +36,17 @@ function generatorTest() {
         browser.removeEventListener("DOMContentLoaded", nextStep, true);
         gBrowser.removeCurrentTab();
     });
 
     // Test that a bookmark of each URI gets the corresponding default title.
     for (let i = 0; i < tests.length; ++i) {
         let [uri, title] = tests[i];
         content.location = uri;
-        yield;
+        yield undefined;
         checkBookmark(uri, title);
     }
 
     // Network failure test: now that dummy_page.html is in history, bookmarking
     // it should give the last known page title as the default bookmark title.
 
     // Simulate a network outage with offline mode. (Localhost is still
     // accessible in offline mode, so disable the test proxy as well.)
@@ -58,17 +58,17 @@ function generatorTest() {
         Services.prefs.setIntPref('network.proxy.type', proxy);
     });
 
     // LOAD_FLAGS_BYPASS_CACHE isn't good enough. So clear the cache.
     Services.cache.evictEntries(Services.cache.STORE_ANYWHERE);
 
     let [uri, title] = tests[0];
     content.location = uri;
-    yield;
+    yield undefined;
     // The offline mode test is only good if the page failed to load.
     is(content.document.documentURI.substring(0, 14), 'about:neterror',
         "Offline mode successfully simulated network outage.");
     checkBookmark(uri, title);
 }
 
 // Bookmark the current page and confirm that the new bookmark has the expected
 // title. (Then delete the bookmark.)
--- a/browser/base/content/test/browser_bug537013.js
+++ b/browser/base/content/test/browser_bug537013.js
@@ -34,33 +34,49 @@ function test() {
     }
   });
   texts.forEach(function(aText) addTabWithText(aText));
 
   // Set up the first tab
   gBrowser.selectedTab = tabs[0];
 
   setFindString(texts[0]);
+  // Turn on highlight for testing bug 891638
+  gFindBar.getElement("highlight").checked = true;
 
   // Make sure the second tab is correct, then set it up
   gBrowser.selectedTab = tabs[1];
   ok(gFindBar.hidden, "Second tab doesn't show find bar!");
   gFindBar.open();
   is(gFindBar._findField.value, texts[0],
      "Second tab kept old find value for new initialization!");
   setFindString(texts[1]);
 
   // Confirm the first tab is still correct, ensure re-hiding works as expected
   gBrowser.selectedTab = tabs[0];
   ok(!gFindBar.hidden, "First tab shows find bar!");
   is(gFindBar._findField.value, texts[0], "First tab persists find value!");
+  ok(gFindBar.getElement("highlight").checked,
+     "Highlight button state persists!");
+
+  // While we're here, let's test bug 253793
+  gBrowser.reload();
+  gBrowser.addEventListener("DOMContentLoaded", continueTests, true);
+}
+
+function continueTests() {
+  gBrowser.removeEventListener("DOMContentLoaded", continueTests, true);
+  ok(!gFindBar.getElement("highlight").checked, "Highlight button reset!");
   gFindBar.close();
   ok(gFindBar.hidden, "First tab doesn't show find bar!");
   gBrowser.selectedTab = tabs[1];
   ok(!gFindBar.hidden, "Second tab shows find bar!");
+  // Test for bug 892384
+  is(gFindBar._findField.getAttribute("focused"), "true",
+     "Open findbar refocused on tab change!");
   gBrowser.selectedTab = tabs[0];
   ok(gFindBar.hidden, "First tab doesn't show find bar!");
 
   // Set up a third tab, no tests here
   gBrowser.selectedTab = tabs[2];
   setFindString(texts[2]);
 
   // Now we jump to the second, then first, and then fourth
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug882977.js
@@ -0,0 +1,39 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function test() {
+  waitForExplicitFinish();
+
+  registerCleanupFunction(function() {
+    Services.prefs.clearUserPref("browser.startup.homepage");
+    Services.prefs.clearUserPref("browser.startup.page");
+    win.close();
+  });
+
+  let homepage = "about:home";
+  Services.prefs.setCharPref("browser.startup.homepage", homepage);
+  Services.prefs.setIntPref("browser.startup.page", 1);
+  let win = OpenBrowserWindow();
+  whenDelayedStartupFinished(win, function() {
+    let browser = win.gBrowser.selectedBrowser;
+    if (browser.contentDocument.readyState == "complete" &&
+        browser.currentURI.spec == homepage) {
+      checkIdentityMode(win);
+      return;
+    }
+
+    browser.addEventListener("load", function onLoad() {
+      if (browser.currentURI.spec != homepage)
+        return;
+      browser.removeEventListener("load", onLoad, true);
+      checkIdentityMode(win);
+    }, true);
+  });
+}
+
+function checkIdentityMode(win) {
+  let identityMode = win.document.getElementById("identity-box").className;
+  is(identityMode, "chromeUI", "Identity state should be chromeUI for about:home in a new window");
+  finish();
+}
--- a/browser/base/content/test/browser_sanitizeDialog.js
+++ b/browser/base/content/test/browser_sanitizeDialog.js
@@ -165,17 +165,17 @@ var gAllTests = [
    * Add form history entries for the next test.
    */
   function () {
     formEntries = [];
 
     let iter = function() {
       for (let i = 0; i < 5; i++) {
         formEntries.push(addFormEntryWithMinutesAgo(iter, i));
-        yield;
+        yield undefined;
       }
       doNextTest();
     }();
 
     iter.next();
   },
 
   /**
@@ -324,17 +324,17 @@ var gAllTests = [
   },
 
   /**
    * Add form history entry for the next test.
    */
   function () {
     let iter = function() {
       formEntries = [ addFormEntryWithMinutesAgo(iter, 10) ];
-      yield;
+      yield undefined;
       doNextTest();
     }();
 
     iter.next();
   },
 
   /**
    * The next three tests checks that when a certain history item cannot be
@@ -403,17 +403,17 @@ var gAllTests = [
   },
 
   /**
    * Add form history entry for the next test.
    */
   function () {
     let iter = function() {
       formEntries = [ addFormEntryWithMinutesAgo(iter, 10) ];
-      yield;
+      yield undefined;
       doNextTest();
     }();
 
     iter.next();
   },
 
   function () {
     let wh = new WindowHelper();
--- a/browser/base/content/test/browser_tabopen_reflows.js
+++ b/browser/base/content/test/browser_tabopen_reflows.js
@@ -34,17 +34,33 @@ const EXPECTED_REFLOWS = [
     "GroupItem_shouldStack@chrome://browser/content/tabview.js|" +
     "GroupItem_arrange@chrome://browser/content/tabview.js|" +
     "GroupItem_add@chrome://browser/content/tabview.js|" +
     "GroupItems_newTab@chrome://browser/content/tabview.js|" +
     "TabItem__reconnect@chrome://browser/content/tabview.js|" +
     "TabItem@chrome://browser/content/tabview.js|" +
     "TabItems_link@chrome://browser/content/tabview.js|" +
     "@chrome://browser/content/tabview.js|" +
-    "addTab@chrome://browser/content/tabbrowser.xml|"
+    "addTab@chrome://browser/content/tabbrowser.xml|",
+
+  // SessionStore.getWindowDimensions()
+  "ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm|" +
+    "@resource:///modules/sessionstore/SessionStore.jsm|" +
+    "ssi_updateWindowFeatures@resource:///modules/sessionstore/SessionStore.jsm|" +
+    "ssi_collectWindowData@resource:///modules/sessionstore/SessionStore.jsm|" +
+    "@resource:///modules/sessionstore/SessionStore.jsm|" +
+    "ssi_forEachBrowserWindow@resource:///modules/sessionstore/SessionStore.jsm|" +
+    "ssi_getCurrentState@resource:///modules/sessionstore/SessionStore.jsm|" +
+    "ssi_saveState@resource:///modules/sessionstore/SessionStore.jsm|" +
+    "ssi_onTimerCallback@resource:///modules/sessionstore/SessionStore.jsm|" +
+    "ssi_observe@resource:///modules/sessionstore/SessionStore.jsm|",
+
+  // tabPreviews.capture()
+  "tabPreviews_capture@chrome://browser/content/browser.js|" +
+    "tabPreviews_handleEvent/<@chrome://browser/content/browser.js|"
 ];
 
 const PREF_PRELOAD = "browser.newtab.preload";
 
 /*
  * This test ensures that there are no unexpected
  * uninterruptible reflows when opening new tabs.
  */
--- a/browser/base/content/test/browser_typeAheadFind.js
+++ b/browser/base/content/test/browser_typeAheadFind.js
@@ -5,19 +5,19 @@
 let testWindow = null;
 
 function test() {
   waitForExplicitFinish();
 
   testWindow = OpenBrowserWindow();
   whenDelayedStartupFinished(testWindow, function () {
     let selectedBrowser = testWindow.gBrowser.selectedBrowser;
-    selectedBrowser.addEventListener("pageshow", function() {
-      selectedBrowser.removeEventListener("pageshow", arguments.callee, true);
-      ok(true, "pageshow listener called");
+    selectedBrowser.addEventListener("load", function onLoad() {
+      selectedBrowser.removeEventListener("load", onLoad, true);
+      ok(true, "load listener called");
       waitForFocus(onFocus, testWindow.content);
     }, true);
     testWindow.gBrowser.loadURI("data:text/html,<h1>A Page</h1>");
   });
 }
 
 function onFocus() {
   ok(!testWindow.gFindBarInitialized, "find bar is not initialized");
--- a/browser/base/content/test/social/browser_addons.js
+++ b/browser/base/content/test/social/browser_addons.js
@@ -15,17 +15,18 @@ let manifest = { // builtin provider
   workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
   iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
 };
 let manifest2 = { // used for testing install
   name: "provider 2",
   origin: "https://test1.example.com",
   sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar.html",
   workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js",
-  iconURL: "https://test1.example.com/browser/browser/base/content/test/moz.png"
+  iconURL: "https://test1.example.com/browser/browser/base/content/test/moz.png",
+  version: 1
 };
 
 function test() {
   waitForExplicitFinish();
 
   let prefname = getManifestPrefname(manifest);
   setBuiltinManifestPref(prefname, manifest);
   // ensure that manifest2 is NOT showing as builtin
@@ -274,10 +275,54 @@ var tests = {
       Social.installProvider(doc, manifest2, function(addonManifest) {
         Services.prefs.clearUserPref("social.directories");
         SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
           Social.uninstallProvider(addonManifest.origin);
           gBrowser.removeTab(tab);
         });
       });
     });
+  },
+  testUpgradeProviderFromWorker: function(next) {
+    // add the provider, change the pref, add it again. The provider at that
+    // point should be upgraded
+    let activationURL = manifest2.origin + "/browser/browser/base/content/test/social/social_activate.html"
+    addTab(activationURL, function(tab) {
+      let doc = tab.linkedBrowser.contentDocument;
+      let installFrom = doc.nodePrincipal.origin;
+      Services.prefs.setCharPref("social.whitelist", installFrom);
+      Social.installProvider(doc, manifest2, function(addonManifest) {
+        SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
+          Social.enabled = true;
+          checkSocialUI();
+          is(Social.provider.manifest.version, 1, "manifest version is 1")
+          // watch for the provider-update and tell the worker to update
+          SocialService.registerProviderListener(function providerListener(topic, data) {
+            if (topic != "provider-update")
+              return;
+            SocialService.unregisterProviderListener(providerListener);
+            observeProviderSet(function() {
+              Services.prefs.clearUserPref("social.whitelist");
+              executeSoon(function() {
+                is(Social.provider.manifest.version, 2, "manifest version is 2");
+                Social.uninstallProvider(addonManifest.origin);
+                gBrowser.removeTab(tab);
+                next();
+              })
+            });
+          });
+          let port = Social.provider.getWorkerPort();
+          port.postMessage({topic: "worker.update", data: true});
+        });
+      });
+    });
   }
 }
+
+
+function observeProviderSet(cb) {
+  Services.obs.addObserver(function providerSet(subject, topic, data) {
+    Services.obs.removeObserver(providerSet, "social:provider-set");
+    info("social:provider-set observer was notified");
+    // executeSoon to let the browser UI observers run first
+    executeSoon(cb);
+  }, "social:provider-set", false);
+}
\ No newline at end of file
--- a/browser/base/content/test/social/head.js
+++ b/browser/base/content/test/social/head.js
@@ -195,52 +195,70 @@ function runSocialTests(tests, cbPreTest
 function checkSocialUI(win) {
   win = win || window;
   let doc = win.document;
   let provider = Social.provider;
   let enabled = win.SocialUI.enabled;
   let active = Social.providers.length > 0 && !win.SocialUI._chromeless &&
                !PrivateBrowsingUtils.isWindowPrivate(win);
 
+  // some local helpers to avoid log-spew for the many checks made here.
+  let numGoodTests = 0, numTests = 0;
+  function _ok(what, msg) {
+    numTests++;
+    if (!ok)
+      ok(what, msg)
+    else
+      ++numGoodTests;
+  }
+  function _is(a, b, msg) {
+    numTests++;
+    if (a != b)
+      is(a, b, msg)
+    else
+      ++numGoodTests;
+  }
   function isbool(a, b, msg) {
-    is(!!a, !!b, msg);
+    _is(!!a, !!b, msg);
   }
   isbool(win.SocialSidebar.canShow, enabled, "social sidebar active?");
   if (enabled)
     isbool(win.SocialSidebar.opened, enabled, "social sidebar open?");
   isbool(win.SocialChatBar.isAvailable, enabled && Social.haveLoggedInUser(), "chatbar available?");
   isbool(!win.SocialChatBar.chatbar.hidden, enabled && Social.haveLoggedInUser(), "chatbar visible?");
 
   let markVisible = enabled && provider.pageMarkInfo;
   let canMark = markVisible && win.SocialMark.canMarkPage(win.gBrowser.currentURI);
   isbool(!win.SocialMark.button.hidden, markVisible, "SocialMark button visible?");
   isbool(!win.SocialMark.button.disabled, canMark, "SocialMark button enabled?");
   isbool(!doc.getElementById("social-toolbar-item").hidden, active, "toolbar items visible?");
   if (active) {
     if (!enabled) {
-      ok(!win.SocialToolbar.button.style.listStyleImage, "toolbar button is default icon");
+      _ok(!win.SocialToolbar.button.style.listStyleImage, "toolbar button is default icon");
     } else {
-      is(win.SocialToolbar.button.style.listStyleImage, 'url("' + Social.defaultProvider.iconURL + '")', "toolbar button has provider icon");
+      _is(win.SocialToolbar.button.style.listStyleImage, 'url("' + Social.defaultProvider.iconURL + '")', "toolbar button has provider icon");
     }
   }
   // the menus should always have the provider name
   if (provider) {
     for (let id of ["menu_socialSidebar", "menu_socialAmbientMenu"])
-      is(document.getElementById(id).getAttribute("label"), Social.provider.name, "element has the provider name");
+      _is(document.getElementById(id).getAttribute("label"), Social.provider.name, "element has the provider name");
   }
 
   // and for good measure, check all the social commands.
   isbool(!doc.getElementById("Social:Toggle").hidden, active, "Social:Toggle visible?");
   isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
   isbool(!doc.getElementById("Social:FocusChat").hidden, enabled && Social.haveLoggedInUser(), "Social:FocusChat visible?");
   isbool(doc.getElementById("Social:FocusChat").getAttribute("disabled"), enabled ? "false" : "true", "Social:FocusChat disabled?");
-  is(doc.getElementById("Social:TogglePageMark").getAttribute("disabled"), canMark ? "false" : "true", "Social:TogglePageMark enabled?");
+  _is(doc.getElementById("Social:TogglePageMark").getAttribute("disabled"), canMark ? "false" : "true", "Social:TogglePageMark enabled?");
 
   // broadcasters.
   isbool(!doc.getElementById("socialActiveBroadcaster").hidden, active, "socialActiveBroadcaster hidden?");
+  // and report on overall success of failure of the various checks here.
+  is(numGoodTests, numTests, "The Social UI tests succeeded.")
 }
 
 // blocklist testing
 function updateBlocklist(aCallback) {
   var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
                           .getService(Ci.nsITimerCallback);
   var observer = function() {
     Services.obs.removeObserver(observer, "blocklist-updated");
--- a/browser/base/content/test/social/social_activate.html
+++ b/browser/base/content/test/social/social_activate.html
@@ -15,17 +15,17 @@ var data = {
   "sidebarURL": "/browser/browser/base/content/test/social/social_sidebar.html",
   "workerURL": "/browser/browser/base/content/test/social/social_worker.js",
 
   // should be available for display purposes
   "description": "A short paragraph about this provider",
   "author": "Shane Caraveo, Mozilla",
 
   // optional
-  "version": "1.0"
+  "version": 1
 }
 
 function activate(node) {
   node.setAttribute("data-service", JSON.stringify(data));
   var event = new CustomEvent("ActivateSocialFeature");
   node.dispatchEvent(event);
 }
 
--- a/browser/base/content/test/social/social_worker.js
+++ b/browser/base/content/test/social/social_worker.js
@@ -132,11 +132,18 @@ onconnect = function(e) {
         break;
       case "test-isVisible-response":
         testPort.postMessage({topic: "got-isVisible-response", result: event.data.result});
         break;
       case "share-data-message":
         if (testPort)
           testPort.postMessage({topic:"got-share-data-message", result: event.data.result});
         break;
+      case "worker.update":
+        apiPort.postMessage({topic: 'social.manifest-get'});
+        break;
+      case "social.manifest":
+        event.data.data.version = 2;
+        apiPort.postMessage({topic: 'social.manifest-set', data: event.data.data});
+        break;
     }
   }
 }
index afce613e2fd2d6dedb69c453ea978d9aeb7692ef..28f13894ed2873e7f2bbc76a31dea75b61c81956
GIT binary patch
literal 1800
zc$@(U2lx1iP)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#3000KhNkl<Zc-o!T
zdr*^S76$MSt5B6~D*}R6*HY370ufjRkr0tU0$RBQFx(+rloeM&<t9+17z0)y;99wP
z*+rOzT3xDc>#VI7iaJn55t-_Mc!63LXOZf1vBSI1alSAahOs;Q$8Wxq_c>=KCnoZ8
z{W%N%S0=EOXAB%`{)l7MoGv<>0s1fp3@6o_|DM&(vtlRTUdC#T7QX6hOW@jqxJh`e
z2L>=7mVhPCVxZF1@lm0j%R{w|b6>H;htx+iTzAI1QyGH_Zow$89a<nAQb7Z+78p4)
zn^3I>`s4Kii_xmLOGnD*cHw-CpzegW(du_pkUvuSy9$268O;GRIiNTH2Fx3*@e;Ks
znb%(pozvSapEXWU_go7%?CMBfe4-;|@v$G`=YP&GXu#dvX`xFFL%@E+CD4G;pvFY|
z<_-RRWN{2$4+DFhr)3LTo*pu*cy>%+PP6=*H*HT}mi@Kg+!tSMoXuY6n~-@OO-i%R
zyGvX?;F^-Gwd61XjCUD?-~;Wzrq~Tj@2f3o0sY4s>loA%z({YQ;L6XH_L9CsHsQSm
zf=)Wq^{{B!C&-qutD!UKlfSatHoHOg&IB;>WuV#ZdxzZrbR&1=-ZOqCJ#?n)^41TJ
zA#>)=#ySuacm`|=IV^?4(`1>H(bwQnrTG2!k5>)@({)Gf9Mx0iYTJ?TbYg1Osd7@^
zEpoA9txALL>h+?do@OtqJQgrr7m|c&w+^oJIu#~3KQ%iWzx*#(b6s4xzlN?MdBAx2
za2Iy+nGqa@CSW?QQAVHs_j_bTmv%`RY1t#wTuzntv}DOXMmD?SQ}2b%8Pen5rAe<*
zuJv82^u`^H_q(huetu23UEKlKC5)i{TZzYeeRYw-&+sp^=z584`O!e@vwxOZc2cf&
zNc#Sdw?A8N&uRQTNjosO2Y-M!fzu&|Gw=^+0tUC}M+|fRzBQ!tbYcj@^M3Q*V6O)!
z0!-*Pq5U7}+pJB#joTDoH71381K0T8E@X!EW6Tp<_hhd6faQv;`u~~hwfRY7m>tfI
zVHOxQrn+w{l-XTXd)fZ5&%>sZdNI?B%z{(-tS6(uKnx+^2HI>U6vI8Z4xPYYj9<X8
zMwu`M>_SGg{LJ>)&5g-QZ=BD>8P{_>cy4`STt#hM!u{H~_zpaOq+S^37qHynXfwXu
z!G@j9l4VpW-SUpbiz9GOnch#0;bw&!old8&7WQYjuINr%BYa4`n0ZOFT&BdIi~@r=
zcns&@4a)du1H6Pj_#PPiqFtaoEM*K>UE;P~72zpARY&i*`17ftw~*=e)+pxS^_R$B
zB70I5ncPaf@Lan<yq*1coUJ`O9KEhA(a~{mx0_Sz@V81!WHSfON13Lrb!tM-ugIPz
zyR7V@-UOk;2+eZa-4vu97#sw~Q-U_11&`n%<nZ}T?N_LDQ+8)@U=BMHky%bpQmsti
zflMD}^*1O?OM<fdp|2t;;{fHDxkIz`6^eCS-4kN9ie-9>Pt%hWC?ti*jNq-Ii%RDx
zq4U3@A=lUaB;}a7PqSQ{a|Fo)26thAufGO;2!uD`2K2!LK3DMz=oc&Ui}E)XFqNOW
zXP<AuAl2%C{g>_@k1{?Gs0z7N9&5VaUwwO@ulfl*ro2dzUrMv|CR2SRb-sc%Y?H01
zPj2NpM0Lz6@%1O?qiqw`xW_y=6D154x^)LF7d;KO5e-njOD3tOzt~)uLo6|cXTabK
z7~<;y&;xgfff8VRuPML4j4#sDEwf~0!+T_9Z0|=U=d-*^U)7%~3L~FikQ<gp?)NPU
zElAGyFRG+->ZKX}I$?0JMByeAtbO5WA!gxDk``~i&Iw+hI(8-gy@PQZ|CkrLL6hj=
z)kx>mOEWaf`P**MlEVZr7=UwN4pL}?2Yfcc_j0sA%DQTL>Z^h@F{mei?ewS`OqW$$
zJeQlc;$T>jVz+1I&0UhJ$CObI_41#-_Wm<3C&V|~b&1CWFn0^dkiWgOwe@I3Wbu}O
zJ>J%y_ap+z0A<uey);9!oVQhyu0R+DHXS~bYx`+|t)kk=t3<9}xiZPE_7|M7=}?yI
zUmiofG(!ulTqNbRSBdms{~YHf(*NL$O^33KP5#-`OEWafc?fn)Weh6lfN^*Z*WnY&
zbbD!mxYeh~<YlfVWuHZ|<Yeh)*M_cmms2m{#TM6w4xANJMm^L^Gqix6xeuAV%w5n#
zh(g7F^)8khdRHv;`E|u2pAlEVhVHPnesz>l5A|y2IFZH9{~Ik3wW?9qwAX3A)~8Ij
qmlm*EutDo}*J-MaK%aVaXZ{Nf!<PwAe958!0000<MNUMnLSTZx2ZDtF
index 531ff5dec0cd353a41a0c7799bcefcc47fbcd8d8..ff0e6cad2daf18e83e0350d514272b3e56b0231b
GIT binary patch
literal 4802
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
index afce613e2fd2d6dedb69c453ea978d9aeb7692ef..feba1607a9bb7fa8a5be6f335cdeb32fc3e70636
GIT binary patch
literal 1624
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
WVxXp!azq>e0000<MNUMnLSTZ|8Wx!V
index 531ff5dec0cd353a41a0c7799bcefcc47fbcd8d8..9b2d6bc66f21ff97506d6f09497049c5af18e4ab
GIT binary patch
literal 4283
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
index a39e493c1eb1eaacc6b40c32fb6eebe683021b3f..feba1607a9bb7fa8a5be6f335cdeb32fc3e70636
GIT binary patch
literal 1624
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
WVxXp!azq>e0000<MNUMnLSTZ|8Wx!V
index 794d54ecae5277de16d1b9ae6f030c7d7b0678f7..9b2d6bc66f21ff97506d6f09497049c5af18e4ab
GIT binary patch
literal 4283
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
--- a/browser/components/downloads/test/browser/browser_basic_functionality.js
+++ b/browser/components/downloads/test/browser/browser_basic_functionality.js
@@ -28,23 +28,23 @@ function gen_test()
   var originalCountLimit = DownloadsView.kItemCountLimit;
   DownloadsView.kItemCountLimit = DownloadData.length;
   registerCleanupFunction(function () {
     DownloadsView.kItemCountLimit = originalCountLimit;
   });
 
   try {
     // Ensure that state is reset in case previous tests didn't finish.
-    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield;
+    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
 
     // Populate the downloads database with the data required by this test.
-    for (let yy in gen_addDownloadRows(DownloadData)) yield;
+    for (let yy in gen_addDownloadRows(DownloadData)) yield undefined;
 
     // Open the user interface and wait for data to be fully loaded.
-    for (let yy in gen_openPanel(DownloadsCommon.getData(window))) yield;
+    for (let yy in gen_openPanel(DownloadsCommon.getData(window))) yield undefined;
 
     // Test item data and count.  This also tests the ordering of the display.
     let richlistbox = document.getElementById("downloadsListBox");
 /* disabled for failing intermittently (bug 767828)
     is(richlistbox.children.length, DownloadData.length,
        "There is the correct number of richlistitems");
 */
     for (let i = 0; i < richlistbox.children.length; i++) {
@@ -52,11 +52,11 @@ function gen_test()
       let dataItem = new DownloadsViewItemController(element).dataItem;
       is(dataItem.target, DownloadData[i].name, "Download names match up");
       is(dataItem.state, DownloadData[i].state, "Download states match up");
       is(dataItem.file, DownloadData[i].target, "Download targets match up");
       is(dataItem.uri, DownloadData[i].source, "Download sources match up");
     }
   } finally {
     // Clean up when the test finishes.
-    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield;
+    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
   }
 }
--- a/browser/components/downloads/test/browser/browser_first_download_panel.js
+++ b/browser/components/downloads/test/browser/browser_first_download_panel.js
@@ -7,42 +7,42 @@
  * Make sure the downloads panel only opens automatically on the first
  * download it notices. All subsequent downloads, even across sessions, should
  * not open the panel automatically.
  */
 function gen_test()
 {
   try {
     // Ensure that state is reset in case previous tests didn't finish.
-    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield;
+    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
 
     // With this set to false, we should automatically open the panel
     // the first time a download is started.
     DownloadsCommon.getData(window).panelHasShownBefore = false;
 
     prepareForPanelOpen();
     DownloadsCommon.getData(window)._notifyDownloadEvent("start");
-    yield;
+    yield undefined;
 
     // If we got here, that means the panel opened.
     DownloadsPanel.hidePanel();
 
     ok(DownloadsCommon.getData(window).panelHasShownBefore,
        "Should have recorded that the panel was opened on a download.")
 
     // Next, make sure that if we start another download, we don't open
     // the panel automatically.
     panelShouldNotOpen();
     DownloadsCommon.getData(window)._notifyDownloadEvent("start");
     yield waitFor(2);
   } catch(e) {
     ok(false, e);
   } finally {
     // Clean up when the test finishes.
-    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield;
+    for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
   }
 }
 
 /**
  * Call this to record a test failure for the next time the downloads panel
  * opens.
  */
 function panelShouldNotOpen()
--- a/browser/components/downloads/test/browser/head.js
+++ b/browser/components/downloads/test/browser/head.js
@@ -122,17 +122,17 @@ var testRunner = {
 ////////////////////////////////////////////////////////////////////////////////
 //// Asynchronous generator-based support subroutines
 
 //
 // The following functions are all generators that can be used inside the main
 // test generator to perform specific tasks asynchronously.  To invoke these
 // subroutines correctly, an iteration syntax should be used:
 //
-//   for (let yy in gen_example("Parameter")) yield;
+//   for (let yy in gen_example("Parameter")) yield undefined;
 //
 
 function gen_resetState(aData)
 {
   let statement = Services.downloads.DBConnection.createAsyncStatement(
                   "DELETE FROM moz_downloads");
   try {
     statement.executeAsync({
@@ -141,32 +141,32 @@ function gen_resetState(aData)
       {
         Cu.reportError(aError);
       },
       handleCompletion: function(aReason)
       {
         testRunner.continueTest();
       }
     });
-    yield;
+    yield undefined;
   } finally {
     statement.finalize();
   }
 
   // Reset any prefs that might have been changed.
   Services.prefs.clearUserPref("browser.download.panel.shown");
 
   // Ensure that the panel is closed and data is unloaded.
   aData.clear();
   aData._loadState = aData.kLoadNone;
   DownloadsPanel.hidePanel();
 
   // Wait for focus on the main window.
   waitForFocus(testRunner.continueTest);
-  yield;
+  yield undefined;
 }
 
 function gen_addDownloadRows(aDataRows)
 {
   let columnNames = Object.keys(gDownloadRowTemplate).join(", ");
   let parameterNames = Object.keys(gDownloadRowTemplate)
                              .map(function(n) ":" + n)
                              .join(", ");
@@ -195,17 +195,17 @@ function gen_addDownloadRows(aDataRows)
         {
           Cu.reportError(aError.message + " (Result = " + aError.result + ")");
         },
         handleCompletion: function(aReason)
         {
           testRunner.continueTest();
         }
       });
-      yield;
+      yield undefined;
 
       // At each iteration, ensure that the start and end time in the global
       // template is distinct, as these column are used to sort each download
       // in its category.
       gDownloadRowTemplate.startTime++;
       gDownloadRowTemplate.endTime++;
     }
   } finally {
@@ -223,21 +223,21 @@ function gen_openPanel(aData)
     testRunner.continueTest();
   };
 
   // Start loading all the downloads from the database asynchronously.
   aData.ensurePersistentDataLoaded(false);
 
   // Wait for focus on the main window.
   waitForFocus(testRunner.continueTest);
-  yield;
+  yield undefined;
 
   // Open the downloads panel, waiting until loading is completed.
   DownloadsPanel.showPanel();
-  yield;
+  yield undefined;
 }
 
 /**
  * Spin the event loop for aSeconds seconds, and then signal the test to
  * continue.
  *
  * @param aSeconds the number of seconds to wait.
  * @note This helper should _only_ be used when there's no valid event to
@@ -254,17 +254,17 @@ function waitFor(aSeconds)
  * Make it so that the next time the downloads panel opens, we signal to
  * continue the test. This function needs to be called each time you want
  * to wait for the panel to open.
  *
  * Example usage:
  *
  * prepareForPanelOpen();
  * // Do something to open the panel
- * yield;
+ * yield undefined;
  * // We can assume the panel is open now.
  */
 function prepareForPanelOpen()
 {
   // Hook to wait until the test data has been loaded.
   let originalOnPopupShown = DownloadsPanel.onPopupShown;
   DownloadsPanel.onPopupShown = function (aEvent) {
     DownloadsPanel.onPopupShown = originalOnPopupShown;
--- a/browser/components/migration/src/IEProfileMigrator.js
+++ b/browser/components/migration/src/IEProfileMigrator.js
@@ -406,17 +406,17 @@ Cookies.prototype = {
           // Importing even a single cookie file is considered a success.
           if (aSuccess)
             success = true;
           try {
             cookiesGenerator.next();
           } catch (ex) {}
         });
 
-        yield;
+        yield undefined;
       }
 
       CtypesHelpers.finalize();
 
       aCallback(success);
     }).apply(this);
     cookiesGenerator.next();
   },
--- a/browser/components/places/tests/chrome/test_bug631374_tags_selector_scroll.xul
+++ b/browser/components/places/tests/chrome/test_bug631374_tags_selector_scroll.xul
@@ -113,25 +113,30 @@
 
           // Doing this backwords tests more interesting paths.
           for (let i = tags.length - 1; i >= 0 ; i -= 2) {
             tagsSelector.selectedIndex = i;
             let listItem = tagsSelector.selectedItem;
             SimpleTest.isnot(listItem, null, "Valid listItem found");
 
             tagsSelector.ensureElementIsVisible(listItem);
-            let visibleIndex = tagsSelector.getIndexOfFirstVisibleRow();
+            let firstVisibleTag = tags[tagsSelector.getIndexOfFirstVisibleRow()];
 
             SimpleTest.ok(listItem.checked, "Item is checked " + i);
             let selectedTag = listItem.label;
 
             // Uncheck the tag.
             listItem.checked = false;
-            SimpleTest.is(tagsSelector.getIndexOfFirstVisibleRow(),
-                          Math.max(visibleIndex -1, 0),
+
+            // Ensure the first visible tag is still visible in the list.
+            let firstVisibleIndex = tagsSelector.getIndexOfFirstVisibleRow();
+            let lastVisibleIndex = firstVisibleIndex + tagsSelector.getNumberOfVisibleRows() -1;
+            let expectedTagIndex = tags.indexOf(firstVisibleTag);
+            SimpleTest.ok(expectedTagIndex >= firstVisibleIndex &&
+                          expectedTagIndex <= lastVisibleIndex,
                           "Scroll position is correct");
 
             // The listbox is rebuilt, so we have to get the new element.
             let newItem = tagsSelector.selectedItem;
             SimpleTest.isnot(newItem, null, "Valid new listItem found");
             SimpleTest.ok(newItem.checked, "New listItem is checked " + i);
             SimpleTest.is(tagsSelector.selectedItem.label,
                           tags[Math.min(i + 1, tags.length - 2)],
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -625,16 +625,17 @@ var gAdvancedPane = {
     var warnIncompatible = document.getElementById("warnIncompatible");
     // the warnIncompatible checkbox value is set by readAddonWarn
     warnIncompatible.disabled = radiogroup.disabled || modePref.locked ||
                                 !enabledPref.value || !autoPref.value;
 #ifdef XP_WIN
 #ifdef MOZ_METRO
     if (this._showingWin8Prefs) {
       warnIncompatible.disabled |= metroEnabledPref.value;
+      warnIncompatible.checked |= metroEnabledPref.value;
     }
 #endif
 #endif
 
 #ifdef MOZ_MAINTENANCE_SERVICE
     // Check to see if the maintenance service is installed.
     // If it is don't show the preference at all.
     var installed;
@@ -675,16 +676,17 @@ var gAdvancedPane = {
   /**
    * Sets the pref values based on the selected item of the radiogroup,
    * and sets the disabled state of the warnIncompatible checkbox accordingly.
    */
   updateWritePrefs: function ()
   {
     var enabledPref = document.getElementById("app.update.enabled");
     var autoPref = document.getElementById("app.update.auto");
+    var modePref = document.getElementById("app.update.mode");
 #ifdef XP_WIN
 #ifdef MOZ_METRO
     var metroEnabledPref = document.getElementById("app.update.metro.enabled");
     // Initialize the pref to false only if we're showing the option
     if (this._showingWin8Prefs) {
       metroEnabledPref.value = false;
     }
 #endif
@@ -696,38 +698,39 @@ var gAdvancedPane = {
         autoPref.value = true;
         break;
 #ifdef XP_WIN
 #ifdef MOZ_METRO
       case "autoMetro": // 0. Automatically install updates for both Metro and Desktop
         enabledPref.value = true;
         autoPref.value = true;
         metroEnabledPref.value = true;
+        modePref.value = 1;
         break;
 #endif
 #endif
       case "checkOnly": // 2. Check, but let me choose
         enabledPref.value = true;
         autoPref.value = false;
         break;
       case "manual":    // 3. Never check for updates.
         enabledPref.value = false;
         autoPref.value = false;
     }
 
     var warnIncompatible = document.getElementById("warnIncompatible");
-    var modePref = document.getElementById("app.update.mode");
     warnIncompatible.disabled = enabledPref.locked || !enabledPref.value ||
                                 autoPref.locked || !autoPref.value ||
                                 modePref.locked;
 
 #ifdef XP_WIN
 #ifdef MOZ_METRO
     if (this._showingWin8Prefs) {
       warnIncompatible.disabled |= metroEnabledPref.value;
+      warnIncompatible.checked |= metroEnabledPref.value;
     }
 #endif
 #endif
   },
 
   /**
    * Stores the value of the app.update.mode preference, which is a tristate
    * integer preference.  We store the value here so that we can properly
--- a/browser/components/preferences/in-content/advanced.js
+++ b/browser/components/preferences/in-content/advanced.js
@@ -608,16 +608,17 @@ var gAdvancedPane = {
     var warnIncompatible = document.getElementById("warnIncompatible");
     // the warnIncompatible checkbox value is set by readAddonWarn
     warnIncompatible.disabled = radiogroup.disabled || modePref.locked ||
                                 !enabledPref.value || !autoPref.value;
 #ifdef XP_WIN
 #ifdef MOZ_METRO
     if (this._showingWin8Prefs) {
       warnIncompatible.disabled |= metroEnabledPref.value;
+      warnIncompatible.checked |= metroEnabledPref.value;
     }
 #endif
 #endif
 
 #ifdef MOZ_MAINTENANCE_SERVICE
     // Check to see if the maintenance service is installed.
     // If it is don't show the preference at all.
     var installed;
@@ -640,16 +641,17 @@ var gAdvancedPane = {
   /**
    * Sets the pref values based on the selected item of the radiogroup,
    * and sets the disabled state of the warnIncompatible checkbox accordingly.
    */
   updateWritePrefs: function ()
   {
     var enabledPref = document.getElementById("app.update.enabled");
     var autoPref = document.getElementById("app.update.auto");
+    var modePref = document.getElementById("app.update.mode");
 #ifdef XP_WIN
 #ifdef MOZ_METRO
     var metroEnabledPref = document.getElementById("app.update.metro.enabled");
     // Initialize the pref to false only if we're showing the option
     if (this._showingWin8Prefs) {
       metroEnabledPref.value = false;
     }
 #endif
@@ -661,37 +663,38 @@ var gAdvancedPane = {
         autoPref.value = true;
         break;
 #ifdef XP_WIN
 #ifdef MOZ_METRO
       case "autoMetro": // 0. Automatically install updates for both Metro and Desktop
         enabledPref.value = true;
         autoPref.value = true;
         metroEnabledPref.value = true;
+        modePref.value = 1;
         break;
 #endif
 #endif
       case "checkOnly": // 2. Check, but let me choose
         enabledPref.value = true;
         autoPref.value = false;
         break;
       case "manual":    // 3. Never check for updates.
         enabledPref.value = false;
         autoPref.value = false;
     }
 
     var warnIncompatible = document.getElementById("warnIncompatible");
-    var modePref = document.getElementById("app.update.mode");
     warnIncompatible.disabled = enabledPref.locked || !enabledPref.value ||
                                 autoPref.locked || !autoPref.value ||
                                 modePref.locked;
 #ifdef XP_WIN
 #ifdef MOZ_METRO
     if (this._showingWin8Prefs) {
       warnIncompatible.disabled |= metroEnabledPref.value;
+      warnIncompatible.checked |= metroEnabledPref.value;
     }
 #endif
 #endif
   },
 
   /**
    * Stores the value of the app.update.mode preference, which is a tristate
    * integer preference.  We store the value here so that we can properly
--- a/browser/components/privatebrowsing/test/browser/Makefile.in
+++ b/browser/components/privatebrowsing/test/browser/Makefile.in
@@ -9,16 +9,17 @@ VPATH		= @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_FILES =  \
 		head.js \
                 browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js \
                 browser_privatebrowsing_aboutSessionRestore.js \
+                browser_privatebrowsing_cache.js \
 		browser_privatebrowsing_certexceptionsui.js \
 		browser_privatebrowsing_concurrent.js \
 		browser_privatebrowsing_concurrent_page.html \
 		browser_privatebrowsing_cookieacceptdialog.js \
 		browser_privatebrowsing_cookieacceptdialog.html \
 		browser_privatebrowsing_crh.js \
 		browser_privatebrowsing_downloadLastDir.js \
 		browser_privatebrowsing_downloadLastDir_c.js \
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cache.js
@@ -0,0 +1,121 @@
+/* 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/. */
+
+// Check about:cache after private browsing
+// This test covers MozTrap test 6047
+// bug 880621
+
+let tmp = {};
+
+Cc["@mozilla.org/moz/jssubscript-loader;1"]
+  .getService(Ci.mozIJSSubScriptLoader)
+  .loadSubScript("chrome://browser/content/sanitize.js", tmp);
+
+let Sanitizer = tmp.Sanitizer;
+
+function test() {
+
+  waitForExplicitFinish();
+
+  sanitizeCache();
+
+  let nrEntriesR1 = get_device_entry_count("disk");
+  is (nrEntriesR1, 0, "Disk cache reports 0KB and has no entries");
+
+  get_cache_for_private_window();
+}
+
+function cleanup() {
+  let prefs = Services.prefs.getBranch("privacy.cpd.");
+
+  prefs.clearUserPref("history");
+  prefs.clearUserPref("downloads");
+  prefs.clearUserPref("cache");
+  prefs.clearUserPref("cookies");
+  prefs.clearUserPref("formdata");
+  prefs.clearUserPref("offlineApps");
+  prefs.clearUserPref("passwords");
+  prefs.clearUserPref("sessions");
+  prefs.clearUserPref("siteSettings");
+}
+
+function sanitizeCache() {
+
+  let s = new Sanitizer();
+  s.ignoreTimespan = false;
+  s.prefDomain = "privacy.cpd.";
+
+  let prefs = gPrefService.getBranch(s.prefDomain);
+  prefs.setBoolPref("history", false);
+  prefs.setBoolPref("downloads", false);
+  prefs.setBoolPref("cache", true);
+  prefs.setBoolPref("cookies", false);
+  prefs.setBoolPref("formdata", false);
+  prefs.setBoolPref("offlineApps", false);
+  prefs.setBoolPref("passwords", false);
+  prefs.setBoolPref("sessions", false);
+  prefs.setBoolPref("siteSettings", false);
+
+  s.sanitize();
+}
+
+function get_cache_service() {
+  return Components.classes["@mozilla.org/network/cache-service;1"]
+                   .getService(Components.interfaces.nsICacheService);
+}
+
+function get_device_entry_count(device) {
+  var cs = get_cache_service();
+  var entry_count = -1;
+
+  var visitor = {
+    visitDevice: function (deviceID, deviceInfo) {
+      if (device == deviceID) {
+        entry_count = deviceInfo.entryCount;
+      }
+      return false;
+    },
+    visitEntry: function (deviceID, entryInfo) {
+      do_throw("nsICacheVisitor.visitEntry should not be called " +
+               "when checking the availability of devices");
+    }
+  };
+
+  cs.visitEntries(visitor);
+  return entry_count;
+}
+
+function get_cache_for_private_window () {
+  let win = OpenBrowserWindow({private: true});
+  win.addEventListener("load", function () {
+    win.removeEventListener("load", arguments.callee, false);
+
+    executeSoon(function() {
+
+      ok(true, "The private window got loaded");
+
+      let tab = win.gBrowser.addTab("http://example.org");
+      win.gBrowser.selectedTab = tab;
+      let newTabBrowser = win.gBrowser.getBrowserForTab(tab);
+
+      newTabBrowser.addEventListener("load", function eventHandler() {
+        newTabBrowser.removeEventListener("load", eventHandler, true);
+
+        executeSoon(function() {
+
+          let nrEntriesP = get_device_entry_count("memory");
+          is (nrEntriesP, 1, "Memory cache reports some entries from example.org domain");
+
+          let nrEntriesR2 = get_device_entry_count("disk");
+          is (nrEntriesR2, 0, "Disk cache reports 0KB and has no entries");
+
+          cleanup();
+
+          win.close();
+          finish();
+        });
+      }, true);
+    });
+  }, false);
+}
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -455,17 +455,21 @@ let SessionStoreInternal = {
           });
         }
       }
       catch (ex) { debug("The session file is invalid: " + ex); }
     }
 
     // A Lazy getter for the sessionstore.js backup promise.
     XPCOMUtils.defineLazyGetter(this, "_backupSessionFileOnce", function () {
-      return _SessionFile.createBackupCopy();
+      // We're creating a backup of sessionstore.js by moving it to .bak
+      // because that's a lot faster than creating a copy. sessionstore.js
+      // would be overwritten shortly afterwards anyway so we can save time
+      // and just move instead of copy.
+      return _SessionFile.moveToBackupPath();
     });
 
     // at this point, we've as good as resumed the session, so we can
     // clear the resume_session_once flag, if it's set
     if (this._loadState != STATE_QUITTING &&
         this._prefBranch.getBoolPref("sessionstore.resume_session_once"))
       this._prefBranch.setBoolPref("sessionstore.resume_session_once", false);
 
@@ -499,22 +503,22 @@ let SessionStoreInternal = {
     let buildID = Services.appinfo.platformBuildID;
     let latestBackup = this._prefBranch.getCharPref(PREF_UPGRADE);
     if (latestBackup == buildID) {
       return Promise.resolve();
     }
     return Task.spawn(function task() {
       try {
         // Perform background backup
-        yield _SessionFile.createUpgradeBackupCopy("-" + buildID);
+        yield _SessionFile.createBackupCopy("-" + buildID);
 
         this._prefBranch.setCharPref(PREF_UPGRADE, buildID);
 
         // In case of success, remove previous backup.
-        yield _SessionFile.removeUpgradeBackup("-" + latestBackup);
+        yield _SessionFile.removeBackupCopy("-" + latestBackup);
       } catch (ex) {
         debug("Could not perform upgrade backup " + ex);
         debug(ex.stack);
       }
     }.bind(this));
   },
 
   _initEncoding : function ssi_initEncoding() {
@@ -767,22 +771,22 @@ let SessionStoreInternal = {
           Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED, "");
         } else {
           TelemetryTimestamps.add("sessionRestoreRestoring");
           // make sure that the restored tabs are first in the window
           this._initialState._firstTabs = true;
           this._restoreCount = this._initialState.windows ? this._initialState.windows.length : 0;
           this.restoreWindow(aWindow, this._initialState,
                              this._isCmdLineEmpty(aWindow, this._initialState));
-
-          // _loadState changed from "stopped" to "running"
-          // force a save operation so that crashes happening during startup are correctly counted
-          this._initialState.session.state = STATE_RUNNING_STR;
-          this._saveStateObject(this._initialState);
           this._initialState = null;
+
+          // _loadState changed from "stopped" to "running". Save the session's
+          // load state immediately so that crashes happening during startup
+          // are correctly counted.
+          _SessionFile.writeLoadStateOnceAfterStartup(STATE_RUNNING_STR);
         }
       }
       else {
         // Nothing to restore, notify observers things are complete.
         Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED, "");
 
         // the next delayed save request should execute immediately
         this._lastSaveTime -= this._interval;
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/src/SessionWorker.js
@@ -0,0 +1,221 @@
+/* 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/. */
+
+/**
+ * A worker dedicated to handle I/O for Session Store.
+ */
+
+"use strict";
+
+importScripts("resource://gre/modules/osfile.jsm");
+
+let File = OS.File;
+let Encoder = new TextEncoder();
+let Decoder = new TextDecoder();
+
+/**
+ * Communications with the controller.
+ *
+ * Accepts messages:
+ * {fun:function_name, args:array_of_arguments_or_null, id: custom_id}
+ *
+ * Sends messages:
+ * {ok: result, id: custom_id} / {fail: serialized_form_of_OS.File.Error,
+ *                                id: custom_id}
+ */
+self.onmessage = function (msg) {
+  let data = msg.data;
+  if (!(data.fun in Agent)) {
+    throw new Error("Cannot find method " + data.fun);
+  }
+
+  let result;
+  let id = data.id;
+
+  try {
+    result = Agent[data.fun].apply(Agent, data.args);
+  } catch (ex if ex instanceof OS.File.Error) {
+    // Instances of OS.File.Error know how to serialize themselves
+    // (deserialization ensures that we end up with OS-specific
+    // instances of |OS.File.Error|)
+    self.postMessage({fail: OS.File.Error.toMsg(ex), id: id});
+    return;
+  }
+
+  // Other exceptions do not, and should be propagated through DOM's
+  // built-in mechanism for uncaught errors, although this mechanism
+  // may lose interesting information.
+  self.postMessage({ok: result, id: id});
+};
+
+let Agent = {
+  // The initial session string as read from disk.
+  initialState: null,
+
+  // Boolean that tells whether we already wrote
+  // the loadState to disk once after startup.
+  hasWrittenLoadStateOnce: false,
+
+  // The path to sessionstore.js
+  path: OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.js"),
+
+  // The path to sessionstore.bak
+  backupPath: OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.bak"),
+
+  /**
+   * This method is only intended to be called by _SessionFile.syncRead() and
+   * can be removed when we're not supporting synchronous SessionStore
+   * initialization anymore. When sessionstore.js is read from disk
+   * synchronously the state string must be supplied to the worker manually by
+   * calling this method.
+   */
+  setInitialState: function (aState) {
+    // _SessionFile.syncRead() should not be called after startup has finished.
+    // Thus we also don't support any setInitialState() calls after we already
+    // wrote the loadState to disk.
+    if (this.hasWrittenLoadStateOnce) {
+      throw new Error("writeLoadStateOnceAfterStartup() must only be called once.");
+    }
+
+    // Initial state might have been filled by read() already but yet we might
+    // be called by _SessionFile.syncRead() before SessionStore.jsm had a chance
+    // to call writeLoadStateOnceAfterStartup(). It's safe to ignore
+    // setInitialState() calls if this happens.
+    if (!this.initialState) {
+      this.initialState = aState;
+    }
+  },
+
+  /**
+   * Read the session from disk.
+   * In case sessionstore.js does not exist, attempt to read sessionstore.bak.
+   */
+  read: function () {
+    for (let path of [this.path, this.backupPath]) {
+      try {
+        return this.initialState = Decoder.decode(File.read(path));
+      } catch (ex if isNoSuchFileEx(ex)) {
+        // Ignore exceptions about non-existent files.
+      }
+    }
+
+    // No sessionstore data files found. Return an empty string.
+    return "";
+  },
+
+  /**
+   * Write the session to disk.
+   */
+  write: function (stateString) {
+    let bytes = Encoder.encode(stateString);
+    return File.writeAtomic(this.path, bytes, {tmpPath: this.path + ".tmp"});
+  },
+
+  /**
+   * Writes the session state to disk again but changes session.state to
+   * 'running' before doing so. This is intended to be called only once, shortly
+   * after startup so that we detect crashes on startup correctly.
+   */
+  writeLoadStateOnceAfterStartup: function (loadState) {
+    if (this.hasWrittenLoadStateOnce) {
+      throw new Error("writeLoadStateOnceAfterStartup() must only be called once.");
+    }
+
+    if (!this.initialState) {
+      throw new Error("writeLoadStateOnceAfterStartup() must not be called " +
+                      "without a valid session state or before it has been " +
+                      "read from disk.");
+    }
+
+    // Make sure we can't call this function twice.
+    this.hasWrittenLoadStateOnce = true;
+
+    let state;
+    try {
+      state = JSON.parse(this.initialState);
+    } finally {
+      this.initialState = null;
+    }
+
+    state.session = state.session || {};
+    state.session.state = loadState;
+    return this.write(JSON.stringify(state));
+  },
+
+  /**
+   * Moves sessionstore.js to sessionstore.bak.
+   */
+  moveToBackupPath: function () {
+    try {
+      return File.move(this.path, this.backupPath);
+    } catch (ex if isNoSuchFileEx(ex)) {
+      // Ignore exceptions about non-existent files.
+      return true;
+    }
+  },
+
+  /**
+   * Creates a copy of sessionstore.js.
+   */
+  createBackupCopy: function (ext) {
+    try {
+      return File.copy(this.path, this.backupPath + ext);
+    } catch (ex if isNoSuchFileEx(ex)) {
+      // Ignore exceptions about non-existent files.
+      return true;
+    }
+  },
+
+  /**
+   * Removes a backup copy.
+   */
+  removeBackupCopy: function (ext) {
+    try {
+      return File.remove(this.backupPath + ext);
+    } catch (ex if isNoSuchFileEx(ex)) {
+      // Ignore exceptions about non-existent files.
+      return true;
+    }
+  },
+
+  /**
+   * Wipes all files holding session data from disk.
+   */
+  wipe: function () {
+    let exn;
+
+    // Erase session state file
+    try {
+      File.remove(this.path);
+    } catch (ex if isNoSuchFileEx(ex)) {
+      // Ignore exceptions about non-existent files.
+    } catch (ex) {
+      // Don't stop immediately.
+      exn = ex;
+    }
+
+    // Erase any backup, any file named "sessionstore.bak[-buildID]".
+    let iter = new File.DirectoryIterator(OS.Constants.Path.profileDir);
+    for (let entry in iter) {
+      if (!entry.isDir && entry.path.startsWith(this.backupPath)) {
+        try {
+          File.remove(entry.path);
+        } catch (ex) {
+          // Don't stop immediately.
+          exn = exn || ex;
+        }
+      }
+    }
+
+    if (exn) {
+      throw exn;
+    }
+
+    return true;
+  }
+};
+
+function isNoSuchFileEx(aReason) {
+  return aReason instanceof OS.File.Error && aReason.becauseNoSuchFile;
+}
--- a/browser/components/sessionstore/src/_SessionFile.jsm
+++ b/browser/components/sessionstore/src/_SessionFile.jsm
@@ -27,88 +27,85 @@ this.EXPORTED_SYMBOLS = ["_SessionFile"]
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
+Cu.import("resource://gre/modules/osfile/_PromiseWorker.jsm", this);
 Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
 
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
   "resource://gre/modules/TelemetryStopwatch.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "Telemetry",
   "@mozilla.org/base/telemetry;1", "nsITelemetry");
-
-// An encoder to UTF-8.
-XPCOMUtils.defineLazyGetter(this, "gEncoder", function () {
-  return new TextEncoder();
-});
-// A decoder.
-XPCOMUtils.defineLazyGetter(this, "gDecoder", function () {
-  return new TextDecoder();
-});
+XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
+  "resource://gre/modules/Deprecated.jsm");
 
 this._SessionFile = {
   /**
-   * A promise fulfilled once initialization (either synchronous or
-   * asynchronous) is complete.
-   */
-  promiseInitialized: function SessionFile_initialized() {
-    return SessionFileInternal.promiseInitialized;
-  },
-  /**
    * Read the contents of the session file, asynchronously.
    */
-  read: function SessionFile_read() {
+  read: function () {
     return SessionFileInternal.read();
   },
   /**
    * Read the contents of the session file, synchronously.
    */
-  syncRead: function SessionFile_syncRead() {
+  syncRead: function () {
+    Deprecated.warning(
+      "syncRead is deprecated and will be removed in a future version",
+      "https://bugzilla.mozilla.org/show_bug.cgi?id=532150")
     return SessionFileInternal.syncRead();
   },
   /**
    * Write the contents of the session file, asynchronously.
    */
-  write: function SessionFile_write(aData) {
+  write: function (aData) {
     return SessionFileInternal.write(aData);
   },
   /**
+   * Writes the initial state to disk again only to change the session's load
+   * state. This must only be called once, it will throw an error otherwise.
+   */
+  writeLoadStateOnceAfterStartup: function (aLoadState) {
+    return SessionFileInternal.writeLoadStateOnceAfterStartup(aLoadState);
+  },
+  /**
    * Create a backup copy, asynchronously.
    */
-  createBackupCopy: function SessionFile_createBackupCopy() {
-    return SessionFileInternal.createBackupCopy();
+  moveToBackupPath: function () {
+    return SessionFileInternal.moveToBackupPath();
   },
   /**
    * Create a backup copy, asynchronously.
    * This is designed to perform backup on upgrade.
    */
-  createUpgradeBackupCopy: function(ext) {
-    return SessionFileInternal.createUpgradeBackupCopy(ext);
+  createBackupCopy: function (ext) {
+    return SessionFileInternal.createBackupCopy(ext);
   },
   /**
    * Remove a backup copy, asynchronously.
    * This is designed to clean up a backup on upgrade.
    */
-  removeUpgradeBackup: function(ext) {
-    return SessionFileInternal.removeUpgradeBackup(ext);
+  removeBackupCopy: function (ext) {
+    return SessionFileInternal.removeBackupCopy(ext);
   },
   /**
    * Wipe the contents of the session file, asynchronously.
    */
-  wipe: function SessionFile_wipe() {
+  wipe: function () {
     return SessionFileInternal.wipe();
   }
 };
 
 Object.freeze(_SessionFile);
 
 /**
  * Utilities for dealing with promises and Task.jsm
@@ -143,37 +140,32 @@ const TaskUtils = {
    */
   spawn: function spawn(gen) {
     return this.captureErrors(Task.spawn(gen));
   }
 };
 
 let SessionFileInternal = {
   /**
-   * A promise fulfilled once initialization is complete
-   */
-  promiseInitialized: Promise.defer(),
-
-  /**
    * The path to sessionstore.js
    */
   path: OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.js"),
 
   /**
    * The path to sessionstore.bak
    */
   backupPath: OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.bak"),
 
   /**
    * Utility function to safely read a file synchronously.
    * @param aPath
    *        A path to read the file from.
    * @returns string if successful, undefined otherwise.
    */
-  readAuxSync: function ssfi_readAuxSync(aPath) {
+  readAuxSync: function (aPath) {
     let text;
     try {
       let file = new FileUtils.File(aPath);
       let chan = NetUtil.newChannel(file);
       let stream = chan.open();
       text = NetUtil.readInputStreamToString(stream, stream.available(),
         {charset: "utf-8"});
     } catch (e if e.result == Components.results.NS_ERROR_FILE_NOT_FOUND) {
@@ -192,195 +184,96 @@ let SessionFileInternal = {
    * This function is meant to serve as a fallback in case of race
    * between a synchronous usage of the API and asynchronous
    * initialization.
    *
    * In case if sessionstore.js file does not exist or is corrupted (something
    * happened between backup and write), attempt to read the sessionstore.bak
    * instead.
    */
-  syncRead: function ssfi_syncRead() {
+  syncRead: function () {
     // Start measuring the duration of the synchronous read.
     TelemetryStopwatch.start("FX_SESSION_RESTORE_SYNC_READ_FILE_MS");
     // First read the sessionstore.js.
     let text = this.readAuxSync(this.path);
     if (typeof text === "undefined") {
       // If sessionstore.js does not exist or is corrupted, read sessionstore.bak.
       text = this.readAuxSync(this.backupPath);
     }
     // Finish the telemetry probe and return an empty string.
     TelemetryStopwatch.finish("FX_SESSION_RESTORE_SYNC_READ_FILE_MS");
-    return text || "";
-  },
+    text = text || "";
 
-  /**
-   * Utility function to safely read a file asynchronously.
-   * @param aPath
-   *        A path to read the file from.
-   * @param aReadOptions
-   *        Read operation options.
-   *        |outExecutionDuration| option will be reused and can be
-   *        incrementally updated by the worker process.
-   * @returns string if successful, undefined otherwise.
-   */
-  readAux: function ssfi_readAux(aPath, aReadOptions) {
-    let self = this;
-    return TaskUtils.spawn(function () {
-      let text;
-      try {
-        let bytes = yield OS.File.read(aPath, undefined, aReadOptions);
-        text = gDecoder.decode(bytes);
-        // If the file is read successfully, add a telemetry probe based on
-        // the updated duration value of the |outExecutionDuration| option.
-        let histogram = Telemetry.getHistogramById(
-          "FX_SESSION_RESTORE_READ_FILE_MS");
-        histogram.add(aReadOptions.outExecutionDuration);
-      } catch (ex if self._isNoSuchFile(ex)) {
-        // Ignore exceptions about non-existent files.
-      } catch (ex) {
-        Cu.reportError(ex);
-      }
-      throw new Task.Result(text);
-    });
+    // The worker needs to know the initial state read from
+    // disk so that writeLoadStateOnceAfterStartup() works.
+    SessionWorker.post("setInitialState", [text]);
+    return text;
   },
 
-  /**
-   * Read the sessionstore file asynchronously.
-   *
-   * In case sessionstore.js file does not exist or is corrupted (something
-   * happened between backup and write), attempt to read the sessionstore.bak
-   * instead.
-   */
-  read: function ssfi_read() {
-    let self = this;
-    return TaskUtils.spawn(function task() {
-      // Specify |outExecutionDuration| option to hold the combined duration of
-      // the asynchronous reads off the main thread (of both sessionstore.js and
-      // sessionstore.bak, if necessary). If sessionstore.js does not exist or
-      // is corrupted, |outExecutionDuration| will register the time it took to
-      // attempt to read the file. It will then be subsequently incremented by
-      // the read time of sessionsore.bak.
-      let readOptions = {
-        outExecutionDuration: null
-      };
-      // First read the sessionstore.js.
-      let text = yield self.readAux(self.path, readOptions);
-      if (typeof text === "undefined") {
-        // If sessionstore.js does not exist or is corrupted, read the
-        // sessionstore.bak.
-        text = yield self.readAux(self.backupPath, readOptions);
-      }
-      // Return either the content of the sessionstore.bak if it was read
-      // successfully or an empty string otherwise.
-      throw new Task.Result(text || "");
-    });
+  read: function () {
+    return SessionWorker.post("read").then(msg => msg.ok);
   },
 
-  write: function ssfi_write(aData) {
+  write: function (aData) {
     let refObj = {};
-    let self = this;
     return TaskUtils.spawn(function task() {
       TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
       TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
 
-      let bytes = gEncoder.encode(aData);
-
       try {
-        let promise = OS.File.writeAtomic(self.path, bytes, {tmpPath: self.path + ".tmp"});
+        let promise = SessionWorker.post("write", [aData]);
         // At this point, we measure how long we stop the main thread
         TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
 
         // Now wait for the result and measure how long we had to wait for the result
         yield promise;
         TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
       } catch (ex) {
         TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj);
         TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
-        Cu.reportError("Could not write session state file " + self.path
-                       + ": " + aReason);
-      }
-    });
-  },
-
-  createBackupCopy: function ssfi_createBackupCopy() {
-    let backupCopyOptions = {
-      outExecutionDuration: null
-    };
-    let self = this;
-    return TaskUtils.spawn(function task() {
-      try {
-        yield OS.File.move(self.path, self.backupPath, backupCopyOptions);
-        Telemetry.getHistogramById("FX_SESSION_RESTORE_BACKUP_FILE_MS").add(
-          backupCopyOptions.outExecutionDuration);
-      } catch (ex if self._isNoSuchFile(ex)) {
-        // Ignore exceptions about non-existent files.
-      } catch (ex) {
-        Cu.reportError("Could not backup session state file: " + ex);
-        throw ex;
-      }
-    });
-  },
-
-  createUpgradeBackupCopy: function(ext) {
-    return TaskUtils.spawn(function task() {
-      try {
-        yield OS.File.copy(this.path, this.backupPath + ext);
-      } catch (ex if this._isNoSuchFile(ex)) {
-        // Ignore exceptions about non-existent files.
-      } catch (ex) {
-        Cu.reportError("Could not backup session state file to " +
-                       dest + ": " + ex);
-        throw ex;
+        Cu.reportError("Could not write session state file " + this.path
+                       + ": " + ex);
       }
     }.bind(this));
   },
 
-  removeUpgradeBackup: function(ext) {
-    return TaskUtils.spawn(function task() {
-      try {
-        yield OS.File.remove(this.backupPath + ext);
-      } catch (ex if this._isNoSuchFile(ex)) {
-        // Ignore exceptions about non-existent files.
-      }
-    }.bind(this));
+  writeLoadStateOnceAfterStartup: function (aLoadState) {
+    return SessionWorker.post("writeLoadStateOnceAfterStartup", [aLoadState]);
+  },
+
+  moveToBackupPath: function () {
+    return SessionWorker.post("moveToBackupPath");
+  },
+
+  createBackupCopy: function (ext) {
+    return SessionWorker.post("createBackupCopy", [ext]);
+  },
+
+  removeBackupCopy: function (ext) {
+    return SessionWorker.post("removeBackupCopy", [ext]);
   },
 
-  wipe: function ssfi_wipe() {
-    let self = this;
-    return TaskUtils.spawn(function task() {
-      let exn;
-      // Erase session state file
-      try {
-        yield OS.File.remove(self.path);
-      } catch (ex if self._isNoSuchFile(ex)) {
-        // Ignore exceptions about non-existent files.
-      } catch (ex) {
-        // Report error, don't stop immediately
-        Cu.reportError("Could not remove session state file: " + ex);
-        exn = ex;
-      }
+  wipe: function () {
+    return SessionWorker.post("wipe");
+  }
+};
 
-      // Erase any backup, any file named "sessionstore.bak[-buildID]".
-      let iterator = new OS.File.DirectoryIterator(OS.Constants.Path.profileDir);
-      for (let promise of iterator) {
-        let entry = yield promise;
-        if (!entry.isDir && entry.path.startsWith(self.backupPath)) {
-          try {
-            yield OS.File.remove(entry.path);
-          } catch (ex) {
-            // Report error, don't stop immediately
-            Cu.reportError("Could not remove backup file " + entry.path + " : " + ex);
-            exn = exn || ex;
+// Interface to a dedicated thread handling I/O
+let SessionWorker = (function () {
+  let worker = new PromiseWorker("resource:///modules/sessionstore/SessionWorker.js",
+    OS.Shared.LOG.bind("SessionWorker"));
+  return {
+    post: function post(...args) {
+      let promise = worker.post.apply(worker, args);
+      return promise.then(
+        null,
+        function onError(error) {
+          // Decode any serialized error
+          if (error instanceof PromiseWorker.WorkerError) {
+            throw OS.File.Error.fromMsg(error.data);
+          } else {
+            throw error;
           }
         }
-      }
-
-      if (exn) {
-        throw exn;
-      }
-    });
-
-  },
-
-  _isNoSuchFile: function ssfi_isNoSuchFile(aReason) {
-    return aReason instanceof OS.File.Error && aReason.becauseNoSuchFile;
-  }
-};
+      );
+    }
+  };
+})();
--- a/browser/components/sessionstore/src/moz.build
+++ b/browser/components/sessionstore/src/moz.build
@@ -11,11 +11,12 @@ EXTRA_COMPONENTS += [
 ]
 
 JS_MODULES_PATH = 'modules/sessionstore'
 
 EXTRA_JS_MODULES = [
     'DocumentUtils.jsm',
     'SessionMigration.jsm',
     'SessionStorage.jsm',
+    'SessionWorker.js',
     'XPathGenerator.jsm',
     '_SessionFile.jsm',
 ]
--- a/browser/components/sessionstore/test/browser_354894_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_354894_perwindowpb.js
@@ -191,28 +191,23 @@ function test() {
     setPrefs();
 
     // Prepare a window; open it and add more tabs
     let options = {};
     if (aIsPrivateWindow) {
       options = {private: true};
     }
 
-    let newWin = OpenBrowserWindow(options);
-    newWin.addEventListener("load", function(aEvent) {
-      newWin.removeEventListener("load", arguments.callee, false);
-      newWin.gBrowser.addEventListener("load", function(aEvent) {
-        newWin.gBrowser.removeEventListener("load", arguments.callee, true);
-        TEST_URLS.forEach(function (url) {
-          newWin.gBrowser.addTab(url);
-        });
+    whenNewWindowLoaded(options, function (newWin) {
+      TEST_URLS.forEach(function (url) {
+        newWin.gBrowser.addTab(url);
+      });
 
-        executeSoon(function() testFn(newWin));
-      }, true);
-    }, false);
+      executeSoon(() => testFn(newWin));
+    });
   }
 
   /**
    * Test 1: Normal in-session restore
    * @note: Non-Mac only
    */
   function testOpenCloseNormal(nextFn) {
     setupTestAndRun(false, function(newWin) {
@@ -225,71 +220,59 @@ function test() {
       ok(!newWin.closed, "First close request was denied");
       if (!newWin.closed) {
         newWin.BrowserTryToCloseWindow();
         ok(newWin.closed, "Second close request was granted");
       }
 
       // Open a new window
       // The previously closed window should be restored
-      newWin = OpenBrowserWindow({});
-      newWin.addEventListener("load", function() {
-        this.removeEventListener("load", arguments.callee, true);
-        executeSoon(function() {
-          is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
-             "Restored window in-session with otherpopup windows around");
+      whenNewWindowLoaded({}, function (newWin) {
+        is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
+           "Restored window in-session with otherpopup windows around");
 
-          // Cleanup
-          newWin.close();
+        // Cleanup
+        newWin.close();
 
-          // Next please
-          executeSoon(nextFn);
-        });
-      }, true);
+        // Next please
+        executeSoon(nextFn);
+      });
     });
   }
 
   /**
    * Test 2: PrivateBrowsing in-session restore
    * @note: Non-Mac only
    */
   function testOpenClosePrivateBrowsing(nextFn) {
     setupTestAndRun(false, function(newWin) {
       // Close the window
       newWin.BrowserTryToCloseWindow();
 
       // Enter private browsing mode
       // Open a new window.
       // The previously closed window should NOT be restored
-      newWin = OpenBrowserWindow({private: true});
-      newWin.addEventListener("load", function() {
-        this.removeEventListener("load", arguments.callee, true);
-        executeSoon(function() {
-          is(newWin.gBrowser.browsers.length, 1,
-             "Did not restore in private browing mode");
+      whenNewWindowLoaded({private: true}, function (newWin) {
+        is(newWin.gBrowser.browsers.length, 1,
+           "Did not restore in private browing mode");
 
-          // Cleanup
-          newWin.BrowserTryToCloseWindow();
+        // Cleanup
+        newWin.BrowserTryToCloseWindow();
 
-          // Exit private browsing mode again
-          newWin = OpenBrowserWindow({});
-          newWin.addEventListener("load", function() {
-            this.removeEventListener("load", arguments.callee, true);
-            executeSoon(function() {
-              is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
-                 "Restored after leaving private browsing again");
+        // Exit private browsing mode again
+        whenNewWindowLoaded({}, function (newWin) {
+          is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
+             "Restored after leaving private browsing again");
 
-              newWin.close();
+          newWin.close();
 
-              // Next please
-              executeSoon(nextFn);
-            });
-          }, true);
+          // Next please
+          executeSoon(nextFn);
         });
-      }, true);
+      });
     });
   }
 
   /**
    * Test 3: Open some popup windows to check those aren't restored, but
    *         the browser window is
    * @note: Non-Mac only
    */
@@ -307,31 +290,27 @@ function test() {
           newWin.BrowserTryToCloseWindow();
 
           // Close the popup window
           // The test is successful when not this popup window is restored
           // but instead newWin
           popup2.close();
 
           // open a new window the previously closed window should be restored to
-          newWin = OpenBrowserWindow({});
-          newWin.addEventListener("load", function() {
-            this.removeEventListener("load", arguments.callee, true);
-            executeSoon(function() {
-              is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
-                 "Restored window and associated tabs in session");
+          whenNewWindowLoaded({}, function (newWin) {
+            is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1,
+               "Restored window and associated tabs in session");
 
-              // Cleanup
-              newWin.close();
-              popup.close();
+            // Cleanup
+            newWin.close();
+            popup.close();
 
-              // Next please
-              executeSoon(nextFn);
-            });
-          }, true);
+            // Next please
+            executeSoon(nextFn);
+          });
         }, true);
       }, false);
     });
   }
 
   /**
    * Test 4: Open some popup window to check it isn't restored.
    *         Instead nothing at all should be restored
@@ -361,32 +340,28 @@ function test() {
           is(popup.gBrowser.browsers.length, 2,
              "Did not restore to the popup window (2)");
 
           // Close the popup window
           // The test is successful when not this popup window is restored
           // but instead a new window is opened without restoring anything
           popup.close();
 
-          let newWin = OpenBrowserWindow({});
-          newWin.addEventListener("load", function() {
-            newWin.removeEventListener("load", arguments.callee, true);
-            executeSoon(function() {
-              isnot(newWin.gBrowser.browsers.length, 2,
-                    "Did not restore the popup window");
-              is(TEST_URLS.indexOf(newWin.gBrowser.browsers[0].currentURI.spec), -1,
-                 "Did not restore the popup window (2)");
+          whenNewWindowLoaded({}, function (newWin) {
+            isnot(newWin.gBrowser.browsers.length, 2,
+                  "Did not restore the popup window");
+            is(TEST_URLS.indexOf(newWin.gBrowser.browsers[0].currentURI.spec), -1,
+               "Did not restore the popup window (2)");
 
-              // Cleanup
-              newWin.close();
+            // Cleanup
+            newWin.close();
 
-              // Next please
-              executeSoon(nextFn);
-            });
-          }, true);
+            // Next please
+            executeSoon(nextFn);
+          });
         }, true);
       }, false);
     }, true);
   }
 
     /**
    * Test 5: Open some windows and do undoCloseWindow. This should prevent any
    *         restoring later in the test
@@ -397,37 +372,33 @@ function test() {
       setupTestAndRun(false, function(newWin2) {
         newWin.BrowserTryToCloseWindow();
         newWin2.BrowserTryToCloseWindow();
 
         browserWindowsCount([0, 1], "browser windows while running testOpenCloseRestoreFromPopup");
 
         newWin = undoCloseWindow(0);
 
-        newWin2 = OpenBrowserWindow({});
-        newWin2.addEventListener("load", function() {
-          newWin2.removeEventListener("load", arguments.callee, true);
-          executeSoon(function() {
-            is(newWin2.gBrowser.browsers.length, 1,
-               "Did not restore, as undoCloseWindow() was last called");
-            is(TEST_URLS.indexOf(newWin2.gBrowser.browsers[0].currentURI.spec), -1,
-               "Did not restore, as undoCloseWindow() was last called (2)");
+        whenNewWindowLoaded({}, function (newWin2) {
+          is(newWin2.gBrowser.browsers.length, 1,
+             "Did not restore, as undoCloseWindow() was last called");
+          is(TEST_URLS.indexOf(newWin2.gBrowser.browsers[0].currentURI.spec), -1,
+             "Did not restore, as undoCloseWindow() was last called (2)");
 
-            browserWindowsCount([2, 3], "browser windows while running testOpenCloseRestoreFromPopup");
+          browserWindowsCount([2, 3], "browser windows while running testOpenCloseRestoreFromPopup");
 
-            // Cleanup
-            newWin.close();
-            newWin2.close();
+          // Cleanup
+          newWin.close();
+          newWin2.close();
 
-            browserWindowsCount([0, 1], "browser windows while running testOpenCloseRestoreFromPopup");
+          browserWindowsCount([0, 1], "browser windows while running testOpenCloseRestoreFromPopup");
 
-            // Next please
-            executeSoon(nextFn);
-          });
-        }, true);
+          // Next please
+          executeSoon(nextFn);
+        });
       });
     });
   }
 
   /**
    * Test 7: Check whether the right number of notifications was received during
    *         the tests
    */
--- a/browser/components/sessionstore/test/browser_524745.js
+++ b/browser/components/sessionstore/test/browser_524745.js
@@ -5,42 +5,39 @@
 function test() {
   /** Test for Bug 524745 **/
 
   let uniqKey = "bug524745";
   let uniqVal = Date.now();
 
   waitForExplicitFinish();
 
-  let window_B = openDialog(location, "_blank", "chrome,all,dialog=no");
-  window_B.addEventListener("load", function(aEvent) {
-    window_B.removeEventListener("load", arguments.callee, false);
-
-      waitForFocus(function() {
-        // Add identifying information to window_B
-        ss.setWindowValue(window_B, uniqKey, uniqVal);
-        let state = JSON.parse(ss.getBrowserState());
-        let selectedWindow = state.windows[state.selectedWindow - 1];
-        is(selectedWindow.extData && selectedWindow.extData[uniqKey], uniqVal,
-           "selectedWindow is window_B");
+  whenNewWindowLoaded({ private: false }, function (window_B) {
+    waitForFocus(function() {
+      // Add identifying information to window_B
+      ss.setWindowValue(window_B, uniqKey, uniqVal);
+      let state = JSON.parse(ss.getBrowserState());
+      let selectedWindow = state.windows[state.selectedWindow - 1];
+      is(selectedWindow.extData && selectedWindow.extData[uniqKey], uniqVal,
+         "selectedWindow is window_B");
 
-        // Now minimize window_B. The selected window shouldn't have the secret data
-        window_B.minimize();
-        waitForFocus(function() {
-          state = JSON.parse(ss.getBrowserState());
-          selectedWindow = state.windows[state.selectedWindow - 1];
-          ok(!selectedWindow.extData || !selectedWindow.extData[uniqKey],
-             "selectedWindow is not window_B after minimizing it");
+      // Now minimize window_B. The selected window shouldn't have the secret data
+      window_B.minimize();
+      waitForFocus(function() {
+        state = JSON.parse(ss.getBrowserState());
+        selectedWindow = state.windows[state.selectedWindow - 1];
+        ok(!selectedWindow.extData || !selectedWindow.extData[uniqKey],
+           "selectedWindow is not window_B after minimizing it");
 
-          // Now minimize the last open window (assumes no other tests left windows open)
-          window.minimize();
-          state = JSON.parse(ss.getBrowserState());
-          is(state.selectedWindow, 0,
-             "selectedWindow should be 0 when all windows are minimized");
+        // Now minimize the last open window (assumes no other tests left windows open)
+        window.minimize();
+        state = JSON.parse(ss.getBrowserState());
+        is(state.selectedWindow, 0,
+           "selectedWindow should be 0 when all windows are minimized");
 
-          // Cleanup
-          window.restore();
-          window_B.close();
-          finish();
-        });
-      }, window_B);
-  }, false);
+        // Cleanup
+        window.restore();
+        window_B.close();
+        finish();
+      });
+    }, window_B);
+  });
 }
--- a/browser/components/sessionstore/test/browser_819510_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_819510_perwindowpb.js
@@ -169,33 +169,17 @@ function forceWriteState(aCallback) {
       aSubject.QueryInterface(Ci.nsISupportsString);
       aCallback(JSON.parse(aSubject.data));
     }
   }, "sessionstore-state-write", false);
   Services.prefs.setIntPref("browser.sessionstore.interval", 0);
 }
 
 function testOnWindow(aIsPrivate, aCallback) {
-  let win = OpenBrowserWindow({private: aIsPrivate});
-  let gotLoad = false;
-  let gotActivate = false;
-  win.addEventListener("activate", function onActivate() {
-    win.removeEventListener("activate", onActivate, false);
-    gotActivate = true;
-    if (gotLoad) {
-      executeSoon(function() { aCallback(win) });
-    }
-  }, false);
-  win.addEventListener("load", function onLoad() {
-    win.removeEventListener("load", onLoad, false);
-    gotLoad = true;
-    if (gotActivate) {
-      executeSoon(function() { aCallback(win) });
-    }
-  }, false);
+  whenNewWindowLoaded({private: aIsPrivate}, aCallback);
 }
 
 function waitForTabLoad(aWin, aURL, aCallback) {
   aWin.gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
     aWin.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
     executeSoon(aCallback);
   }, true);
   aWin.gBrowser.selectedBrowser.loadURI(aURL);
--- a/browser/components/sessionstore/test/browser_833286_atomic_backup.js
+++ b/browser/components/sessionstore/test/browser_833286_atomic_backup.js
@@ -73,19 +73,19 @@ function testWriteNoBackup() {
   ok(ssExists, "sessionstore.js should exist.");
   ok(!ssBackupExists, "sessionstore.bak should not have been created, yet");
 
   // Save sessionstore.js data to compare to the sessionstore.bak data in the
   // next test.
   let array = yield OS.File.read(path);
   gSSData = gDecoder.decode(array);
 
-  // Manually trigger _SessionFile.createBackupCopy since the backup once
+  // Manually trigger _SessionFile.moveToBackupPath since the backup once
   // promise is already resolved and backup would not be triggered again.
-  yield _SessionFile.createBackupCopy();
+  yield _SessionFile.moveToBackupPath();
 
   nextTest(testWriteBackup);
 }
 
 function testWriteBackup() {
   // Ensure sessionstore.bak is finally created.
   let ssExists = yield OS.File.exists(path);
   let ssBackupExists = yield OS.File.exists(backupPath);
@@ -135,9 +135,9 @@ function testNoWriteBackup() {
 
   // Read sessionstore.bak data.
   let array = yield OS.File.read(backupPath);
   let ssBakData = gDecoder.decode(array);
   // Ensure the sessionstore.bak did not change.
   is(ssBakData, gSSBakData, "sessionstore.bak is unchanged.");
 
   executeSoon(finish);
-}
\ No newline at end of file
+}
--- a/browser/components/sessionstore/test/browser_dying_cache.js
+++ b/browser/components/sessionstore/test/browser_dying_cache.js
@@ -9,20 +9,21 @@ function test() {
  * This test ensures that after closing a window we keep its state data around
  * as long as something keeps a reference to it. It should only be possible to
  * read data after closing - writing should fail.
  */
 
 function runTests() {
   // Open a new window.
   let win = OpenBrowserWindow();
-  yield whenWindowLoaded(win);
+  yield whenDelayedStartupFinished(win, next);
 
   // Load some URL in the current tab.
-  win.gBrowser.selectedBrowser.loadURI("about:robots");
+  let flags = Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY;
+  win.gBrowser.selectedBrowser.loadURIWithFlags("about:robots", flags);
   yield whenBrowserLoaded(win.gBrowser.selectedBrowser);
 
   // Open a second tab and close the first one.
   let tab = win.gBrowser.addTab("about:mozilla");
   yield whenBrowserLoaded(tab.linkedBrowser);
   win.gBrowser.removeTab(win.gBrowser.tabs[0]);
 
   // Make sure our window is still tracked by sessionstore
--- a/browser/components/sessionstore/test/browser_input.js
+++ b/browser/components/sessionstore/test/browser_input.js
@@ -14,17 +14,17 @@ function test() {
  * changed to be re-collected.
  */
 
 function runTests() {
   // Create a dummy window that is regarded as active. We need to do this
   // because we always collect data for tabs of active windows no matter if
   // the window is dirty or not.
   let win = OpenBrowserWindow();
-  yield waitForLoad(win);
+  yield whenDelayedStartupFinished(win, next);
 
   // Create a tab with some form fields.
   let tab = gBrowser.selectedTab = gBrowser.addTab(URL);
   let browser = gBrowser.selectedBrowser;
   yield waitForLoad(browser);
 
   // All windows currently marked as dirty will be written to disk
   // and thus marked clean afterwards.
--- a/browser/components/sessionstore/test/browser_pageshow.js
+++ b/browser/components/sessionstore/test/browser_pageshow.js
@@ -18,17 +18,17 @@ function test() {
 const URL = "data:text/html,<h1>first</h1>";
 const URL2 = "data:text/html,<h1>second</h1>";
 
 function runTests() {
   // Create a dummy window that is regarded as active. We need to do this
   // because we always collect data for tabs of active windows no matter if
   // the window is dirty or not.
   let win = OpenBrowserWindow();
-  yield waitForLoad(win);
+  yield whenDelayedStartupFinished(win, next);
 
   // Create a tab with two history entries.
   let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
   yield loadURI(URL);
   yield loadURI(URL2);
 
   // All windows currently marked as dirty will be written to disk
   // and thus marked clean afterwards.
--- a/browser/components/sessionstore/test/browser_windowRestore_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_windowRestore_perwindowpb.js
@@ -8,19 +8,17 @@ function test() {
   waitForExplicitFinish();
 
   // Purging the list of closed windows
   while(ss.getClosedWindowCount() > 0)
     ss.forgetClosedWindow(0);
 
   // Load a private window, then close it 
   // and verify it doesn't get remembered for restoring
-  var win = OpenBrowserWindow({private: true});
-
-  whenWindowLoaded(win, function onload() {
+  whenNewWindowLoaded({private: true}, function (win) {
     info("The private window got loaded");
     win.addEventListener("SSWindowClosing", function onclosing() {
       win.removeEventListener("SSWindowClosing", onclosing, false);
       executeSoon(function () {
         is (ss.getClosedWindowCount(), 0,
             "The private window should not have been stored");
         finish();
       });
--- a/browser/components/sessionstore/test/head.js
+++ b/browser/components/sessionstore/test/head.js
@@ -284,47 +284,42 @@ registerCleanupFunction(function () {
 function closeAllButPrimaryWindow() {
   for (let win in BrowserWindowIterator()) {
     if (win != window) {
       win.close();
     }
   }
 }
 
+/**
+ * When opening a new window it is not sufficient to wait for its load event.
+ * We need to use whenDelayedStartupFinshed() here as the browser window's
+ * delayedStartup() routine is executed one tick after the window's load event
+ * has been dispatched. browser-delayed-startup-finished might be deferred even
+ * further if parts of the window's initialization process take more time than
+ * expected (e.g. reading a big session state from disk).
+ */
 function whenNewWindowLoaded(aOptions, aCallback) {
   let win = OpenBrowserWindow(aOptions);
-  let gotLoad = false;
-  let gotActivate = (Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager).activeWindow == win);
-
-  function maybeRunCallback() {
-    if (gotLoad && gotActivate) {
-      win.BrowserChromeTest.runWhenReady(function() {
-        executeSoon(function() { aCallback(win); });
-      });
-    }
-  }
+  whenDelayedStartupFinished(win, () => aCallback(win));
+  return win;
+}
 
-  if (!gotActivate) {
-    win.addEventListener("activate", function onActivate() {
-      info("Got activate.");
-      win.removeEventListener("activate", onActivate, false);
-      gotActivate = true;
-      maybeRunCallback();
-    }, false);
-  } else {
-    info("Was activated.");
-  }
-
-  win.addEventListener("load", function onLoad() {
-    info("Got load");
-    win.removeEventListener("load", onLoad, false);
-    gotLoad = true;
-    maybeRunCallback();
-  }, false);
-  return win;
+/**
+ * This waits for the browser-delayed-startup-finished notification of a given
+ * window. It indicates that the windows has loaded completely and is ready to
+ * be used for testing.
+ */
+function whenDelayedStartupFinished(aWindow, aCallback) {
+  Services.obs.addObserver(function observer(aSubject, aTopic) {
+    if (aWindow == aSubject) {
+      Services.obs.removeObserver(observer, aTopic);
+      executeSoon(aCallback);
+    }
+  }, "browser-delayed-startup-finished", false);
 }
 
 /**
  * The test runner that controls the execution flow of our tests.
  */
 let TestRunner = {
   _iter: null,
 
--- a/browser/components/sessionstore/test/unit/test_backup.js
+++ b/browser/components/sessionstore/test/unit/test_backup.js
@@ -14,29 +14,29 @@ function run_test() {
 
 let pathStore;
 function pathBackup(ext) {
   return OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.bak" + ext);
 }
 
 // Ensure that things proceed smoothly if there is no file to back up
 add_task(function test_nothing_to_backup() {
-  yield _SessionFile.createUpgradeBackupCopy("");
+  yield _SessionFile.createBackupCopy("");
 });
 
 // Create a file, back it up, remove it
 add_task(function test_do_backup() {
   let content = "test_1";
   let ext = ".upgrade_test_1";
   yield OS.File.writeAtomic(pathStore, content, {tmpPath: pathStore + ".tmp"});
 
   do_print("Ensuring that the backup is created");
-  yield _SessionFile.createUpgradeBackupCopy(ext);
+  yield _SessionFile.createBackupCopy(ext);
   do_check_true((yield OS.File.exists(pathBackup(ext))));
 
   let data = yield OS.File.read(pathBackup(ext));
   do_check_eq((new TextDecoder()).decode(data), content);
 
   do_print("Ensuring that we can remove the backup");
-  yield _SessionFile.removeUpgradeBackup(ext);
+  yield _SessionFile.removeBackupCopy(ext);
   do_check_false((yield OS.File.exists(pathBackup(ext))));
 });
 
--- a/browser/config/mozconfigs/linux32/common-opt
+++ b/browser/config/mozconfigs/linux32/common-opt
@@ -1,12 +1,13 @@
 # This file is sourced by nightly, beta, and release mozconfigs.
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
+ac_add_options --with-google-api-keyfile=/builds/gapi.data
 
 . $topsrcdir/build/unix/mozconfig.linux32
 
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
--- a/browser/config/mozconfigs/linux32/nightly
+++ b/browser/config/mozconfigs/linux32/nightly
@@ -1,13 +1,14 @@
 . "$topsrcdir/browser/config/mozconfigs/linux32/common-opt"
 
 ac_add_options --enable-codesighs
 ac_add_options --enable-signmar
 ac_add_options --enable-profiling
+ac_add_options --disable-elf-hack # --enable-elf-hack conflicts with --enable-profiling
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
--- a/browser/config/mozconfigs/linux64/common-opt
+++ b/browser/config/mozconfigs/linux64/common-opt
@@ -1,12 +1,13 @@
 # This file is sourced by the nightly, beta, and release mozconfigs.
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
+ac_add_options --with-google-api-keyfile=/builds/gapi.data
 
 . $topsrcdir/build/unix/mozconfig.linux
 
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
--- a/browser/config/mozconfigs/linux64/nightly
+++ b/browser/config/mozconfigs/linux64/nightly
@@ -1,13 +1,14 @@
 . "$topsrcdir/browser/config/mozconfigs/linux64/common-opt"
 
 ac_add_options --enable-codesighs
 ac_add_options --enable-signmar
 ac_add_options --enable-profiling
+ac_add_options --disable-elf-hack # --enable-elf-hack conflicts with --enable-profiling
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
--- a/browser/config/mozconfigs/macosx-universal/common-opt
+++ b/browser/config/mozconfigs/macosx-universal/common-opt
@@ -2,16 +2,17 @@
 
 . $topsrcdir/build/macosx/universal/mozconfig
 
 # Universal builds override the default of browser (bug 575283 comment 29)
 ac_add_options --enable-application=browser
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
+ac_add_options --with-google-api-keyfile=/builds/gapi.data
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/whitelist
@@ -0,0 +1,90 @@
+# 'nightly' contains things that are in nightly mozconfigs and allowed to be missing from release builds.
+# Other keys in whitelist contain things are in that branches mozconfigs and allowed to be missing from nightly builds.
+whitelist = {
+    'release': {},
+    'nightly': {},
+    }
+
+all_platforms = ['win32', 'linux32', 'linux64', 'macosx-universal']
+
+for platform in all_platforms:
+    whitelist['nightly'][platform] = [
+        'ac_add_options --enable-update-channel=nightly',
+        'ac_add_options --enable-profiling',
+        'mk_add_options CLIENT_PY_ARGS="--hg-options=\'--verbose --time\' --hgtool=../tools/buildfarm/utils/hgtool.py --skip-chatzilla --skip-comm --skip-inspector --skip-venkman --tinderbox-print"'
+    ]
+
+for platform in ['linux32', 'linux64', 'macosx-universal']:
+    whitelist['nightly'][platform] += [
+        'ac_add_options --enable-codesighs',
+        'mk_add_options MOZ_MAKE_FLAGS="-j4"',
+    ]
+
+for platform in ['linux32', 'linux64', 'macosx-universal', 'win32']:
+    whitelist['nightly'][platform] += ['ac_add_options --enable-signmar']
+    whitelist['nightly'][platform] += ['ac_add_options --enable-js-diagnostics']
+
+whitelist['nightly']['linux32'] += [
+    'CXX=$REAL_CXX',
+    'CXX="ccache $REAL_CXX"',
+    'CC="ccache $REAL_CC"',
+    'mk_add_options PROFILE_GEN_SCRIPT=@TOPSRCDIR@/build/profile_pageloader.pl',
+    'ac_add_options --with-ccache=/usr/bin/ccache',
+    'export MOZILLA_OFFICIAL=1',
+    'export MOZ_TELEMETRY_REPORTING=1',
+    "mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
+    'STRIP_FLAGS="--strip-debug"',
+    'ac_add_options --disable-elf-hack # --enable-elf-hack conflicts with --enable-profiling',
+]
+
+whitelist['nightly']['linux64'] += [
+    'export MOZILLA_OFFICIAL=1',
+    'export MOZ_TELEMETRY_REPORTING=1',
+    "mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
+    'STRIP_FLAGS="--strip-debug"',
+    'ac_add_options --with-ccache=/usr/bin/ccache',
+    'ac_add_options --disable-elf-hack # --enable-elf-hack conflicts with --enable-profiling',
+]
+
+whitelist['nightly']['macosx-universal'] += [
+    'ac_add_options --with-macbundlename-prefix=Firefox',
+    'mk_add_options MOZ_MAKE_FLAGS="-j12"',
+    'ac_add_options --with-ccache',
+    'ac_add_options --disable-install-strip',
+    'ac_add_options --enable-instruments',
+    'ac_add_options --enable-dtrace',
+]
+
+whitelist['nightly']['win32'] += [
+    '. $topsrcdir/configs/mozilla2/win32/include/choose-make-flags',
+    'mk_add_options MOZ_MAKE_FLAGS=-j1',
+    'if test "$IS_NIGHTLY" != ""; then',
+    'ac_add_options --disable-auto-deps',
+    'fi',
+    'ac_add_options --enable-metro',
+]
+
+for platform in all_platforms:
+    whitelist['release'][platform] = [
+        'ac_add_options --enable-update-channel=release',
+        'ac_add_options --enable-official-branding',
+        'mk_add_options MOZ_MAKE_FLAGS="-j4"',
+        'export BUILDING_RELEASE=1',
+    ]
+whitelist['release']['win32'] += ['mk_add_options MOZ_PGO=1']
+whitelist['release']['linux32'] += [
+    'export MOZILLA_OFFICIAL=1',
+    'export MOZ_TELEMETRY_REPORTING=1',
+    'mk_add_options MOZ_PGO=1',
+    "mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
+]
+whitelist['release']['linux64'] += [
+    'export MOZILLA_OFFICIAL=1',
+    'export MOZ_TELEMETRY_REPORTING=1',
+    'mk_add_options MOZ_PGO=1',
+    "mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
+]
+
+if __name__ == '__main__':
+    import pprint
+    pprint.pprint(whitelist)
--- a/browser/config/mozconfigs/win32/common-opt
+++ b/browser/config/mozconfigs/win32/common-opt
@@ -1,15 +1,16 @@
 # This file is sourced by the nightly, beta, and release mozconfigs.
 
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
+ac_add_options --with-google-api-keyfile=/e/builds/gapi.data
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 if test -z "${_PYMAKE}"; then
   mk_add_options MOZ_MAKE_FLAGS=-j1
--- a/browser/config/tooltool-manifests/linux32/asan.manifest
+++ b/browser/config/tooltool-manifests/linux32/asan.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r170890"
+"clang_version": "r185949"
 }, 
 {
-"filename": "setup.sh", 
+"size": 47, 
+"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa", 
 "algorithm": "sha512", 
-"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa", 
-"size": 47
+"filename": "setup.sh"
 }, 
 {
-"filename": "clang.tar.bz2", 
+"size": 72573411, 
+"digest": "491753968f34d1bd3c58280688349499a92f31a118eb6f28e86746be62615004370394b8e1b10d48dc3fba4bc6d4fbb4ce6c7dbc4fadb39447de9aa55573c58e", 
 "algorithm": "sha512", 
-"digest": "0bcfc19f05cc0f042befb3823c7ecce9ba411b152921aa29e97e7adc846e0258fd7da521b1620cb1e61a19d2fcac9b60e6d613c922b6c153e01b9b0766651d09", 
-"size": 62708281
+"filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/linux32/clang.manifest
+++ b/browser/config/tooltool-manifests/linux32/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r170890"
+"clang_version": "r183744"
 }, 
 {
-"filename": "setup.sh", 
+"size": 47, 
+"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa", 
 "algorithm": "sha512", 
-"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa", 
-"size": 47
+"filename": "setup.sh"
 }, 
 {
-"filename": "clang.tar.bz2", 
+"size": 70206124, 
+"digest": "a6b8046bd9485f9387dcb1c14b8d442822f02b1caa61b653e8b6cfd96906deadfb4b29809f2cd2b71f919b321d97dd2ebec6020c15f6d485f1641c0f710a762f", 
 "algorithm": "sha512", 
-"digest": "0bcfc19f05cc0f042befb3823c7ecce9ba411b152921aa29e97e7adc846e0258fd7da521b1620cb1e61a19d2fcac9b60e6d613c922b6c153e01b9b0766651d09", 
-"size": 62708281
+"filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/asan.manifest
+++ b/browser/config/tooltool-manifests/linux64/asan.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r170890"
-},
+"clang_version": "r185949"
+}, 
 {
-"filename": "setup.sh",
-"algorithm": "sha512",
-"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
-"size": 47
-},
+"size": 47, 
+"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa", 
+"algorithm": "sha512", 
+"filename": "setup.sh"
+}, 
 {
-"filename": "clang.tar.bz2",
-"algorithm": "sha512",
-"digest": "e14ccefd965372a57c540647b2b99e21a4aa82f81a8b9a9e18dac7cba4c3436181bef0dfab8c51bcb5c343f504a693fdcfbe7d609f10291b5dd65ab059979d29",
-"size": 63034761
+"size": 73050713, 
+"digest": "2c5c26a44402f974c2a4ccffb07ea1ac2d01d84dc3e4281fef6e047a62606811a16534d034477dfd9be055a07d931b17ca4e883c8edcd1f8d3a8c91b150e2288", 
+"algorithm": "sha512", 
+"filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r170890"
-},
+"clang_version": "r183744"
+}, 
 {
-"filename": "setup.sh",
-"algorithm": "sha512",
-"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
-"size": 47
-},
+"size": 47, 
+"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa", 
+"algorithm": "sha512", 
+"filename": "setup.sh"
+}, 
 {
-"filename": "clang.tar.bz2",
-"algorithm": "sha512",
-"digest": "e14ccefd965372a57c540647b2b99e21a4aa82f81a8b9a9e18dac7cba4c3436181bef0dfab8c51bcb5c343f504a693fdcfbe7d609f10291b5dd65ab059979d29",
-"size": 63034761
+"size": 70350828, 
+"digest": "6cd04e8ec44c6fef159349c22bd0476891e4a2d46479f9586283eaf3305e42f79c720d40dfec0e78d8899c1651189b12e285de60862ffd0612b0dac7a0c336c6", 
+"algorithm": "sha512", 
+"filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx64/asan.manifest
+++ b/browser/config/tooltool-manifests/macosx64/asan.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r170890"
-},
+"clang_version": "r185949"
+}, 
 {
-"size": 47,
-"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
-"algorithm": "sha512",
+"size": 47, 
+"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa", 
+"algorithm": "sha512", 
 "filename": "setup.sh"
-},
+}, 
 {
-"size": 56126352,
-"digest": "e156e2a39abd5bf272ee30748a6825f22ddd27565b097c66662a2a6f2e9892bc5b4bf30a3552dffbe867dbfc39e7ee086e0b2cd7935f6ea216c0cf936178a88f",
-"algorithm": "sha512",
+"size": 61779086, 
+"digest": "b2f2861da7583e859b4fb40e1304dd284df02466c909893684341b16e2f58c4c100891504938cf62f26ac82254b9e87135ba98f8196dd26e9b58d3242f1cf811", 
+"algorithm": "sha512", 
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx64/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r170890"
-},
+"clang_version": "r183744"
+}, 
 {
-"size": 47,
-"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
-"algorithm": "sha512",
+"size": 47, 
+"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa", 
+"algorithm": "sha512", 
 "filename": "setup.sh"
-},
+}, 
 {
-"size": 56126352,
-"digest": "e156e2a39abd5bf272ee30748a6825f22ddd27565b097c66662a2a6f2e9892bc5b4bf30a3552dffbe867dbfc39e7ee086e0b2cd7935f6ea216c0cf936178a88f",
-"algorithm": "sha512",
+"size": 59602619, 
+"digest": "86662ebc0ef650490559005948c4f0cb015dad72c7cac43732c2bf2995247081e30c139cf8008d19670a0009fc302c4eee2676981ee3f9ff4a15c01af22b783b", 
+"algorithm": "sha512", 
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -52,8 +52,9 @@ MAR_CHANNEL_ID=firefox-mozilla-central
 MOZ_PROFILE_MIGRATOR=1
 MOZ_EXTENSION_MANAGER=1
 MOZ_APP_STATIC_INI=1
 MOZ_WEBAPP_RUNTIME=1
 MOZ_MEDIA_NAVIGATOR=1
 if test "$OS_TARGET" = "WINNT" -o "$OS_TARGET" = "Darwin"; then
   MOZ_FOLD_LIBS=1
 fi
+MOZ_WEBGL_CONFORMANT=1
--- a/browser/devtools/Makefile.in
+++ b/browser/devtools/Makefile.in
@@ -2,14 +2,12 @@
 # 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/.
 
 DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
-include $(topsrcdir)/config/config.mk
-
 include $(topsrcdir)/config/rules.mk
 
 libs::
 	$(NSINSTALL) $(srcdir)/main.js $(FINAL_TARGET)/modules/devtools
--- a/browser/devtools/commandline/BuiltinCommands.jsm
+++ b/browser/devtools/commandline/BuiltinCommands.jsm
@@ -8,17 +8,17 @@ const BRAND_SHORT_NAME = Cc["@mozilla.or
                            .getService(Ci.nsIStringBundleService)
                            .createBundle("chrome://branding/locale/brand.properties")
                            .GetStringFromName("brandShortName");
 
 this.EXPORTED_SYMBOLS = [ "CmdAddonFlags", "CmdCommands", "DEFAULT_DEBUG_PORT", "connect" ];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
+let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 Cu.import("resource://gre/modules/osfile.jsm");
 
 Cu.import("resource://gre/modules/devtools/gcli.jsm");
 Cu.import("resource:///modules/devtools/shared/event-emitter.js");
 
 var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 let Telemetry = require("devtools/shared/telemetry");
 let telemetry = new Telemetry();
@@ -641,35 +641,35 @@ XPCOMUtils.defineLazyModuleGetter(this, 
         let dirService = Cc["@mozilla.org/file/directory_service;1"]
                           .getService(Ci.nsIProperties);
         let homeDirFile = dirService.get("Home", Ci.nsIFile);
         let homeDir = homeDirFile.path;
         dirName = dirName.substr(1);
         dirName = homeDir + dirName;
       }
 
-      let promise = OS.File.stat(dirName);
-      promise = promise.then(
+      let statPromise = OS.File.stat(dirName);
+      statPromise = statPromise.then(
         function onSuccess(stat) {
           if (!stat.isDir) {
             throw new Error('\'' + dirName + '\' is not a directory.');
           } else {
             return dirName;
           }
         },
         function onFailure(reason) {
           if (reason instanceof OS.File.Error && reason.becauseNoSuchFile) {
             throw new Error('\'' + dirName + '\' does not exist.');
           } else {
             throw reason;
           }
         }
       );
 
-      promise.then(
+      statPromise.then(
         function onSuccess() {
           let iterator = new OS.File.DirectoryIterator(dirName);
           let iterPromise = iterator.forEach(
             function onEntry(entry) {
               if (entry.name.match(/.*\.mozcmd$/) && !entry.isDir) {
                 loadCommandFile(entry, aSandboxPrincipal);
               }
             }
@@ -692,18 +692,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   /**
    * Load the commands from a single file
    * @param OS.File.DirectoryIterator.Entry aFileEntry The DirectoryIterator
    * Entry of the file containing the commands that we should read
    * @param nsIPrincipal aSandboxPrincipal Scope object for the Sandbox in which
    * we eval the script from the .mozcmd file. This should be a chrome window.
    */
   function loadCommandFile(aFileEntry, aSandboxPrincipal) {
-    let promise = OS.File.read(aFileEntry.path);
-    promise = promise.then(
+    let readPromise = OS.File.read(aFileEntry.path);
+    readPromise = readPromise.then(
       function onSuccess(array) {
         let decoder = new TextDecoder();
         let source = decoder.decode(array);
 
         let sandbox = new Cu.Sandbox(aSandboxPrincipal, {
           sandboxPrototype: aSandboxPrincipal,
           wantXrays: false,
           sandboxName: aFileEntry.path
--- a/browser/devtools/commandline/test/browser_cmd_addon.js
+++ b/browser/devtools/commandline/test/browser_cmd_addon.js
@@ -9,17 +9,17 @@ let tests = {};
 
 function test() {
   helpers.addTabWithToolbar("about:blank", function(options) {
     return helpers.runTests(options, tests);
   }).then(finish);
 }
 
 tests.gatTest = function(options) {
-  let deferred = Promise.defer();
+  let deferred = promise.defer();
 
   let onGatReady = function() {
     Services.obs.removeObserver(onGatReady, "gcli_addon_commands_ready");
     info("gcli_addon_commands_ready notification received, running tests");
 
     let auditDone = helpers.audit(options, [
       {
         setup: 'addon list dictionary',
--- a/browser/devtools/commandline/test/browser_cmd_appcache_invalid.js
+++ b/browser/devtools/commandline/test/browser_cmd_appcache_invalid.js
@@ -6,17 +6,17 @@
 
 const TEST_URI = "http://sub1.test1.example.com/browser/browser/devtools/commandline/" +
                  "test/browser_cmd_appcache_invalid_index.html";
 
 let tests = {};
 
 function test() {
   helpers.addTabWithToolbar(TEST_URI, function(options) {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
 
     // Wait for site to be cached.
     gBrowser.contentWindow.applicationCache.addEventListener('error', function BCAI_error() {
       gBrowser.contentWindow.applicationCache.removeEventListener('error', BCAI_error);
 
       info("Site now cached, running tests.");
 
       deferred.resolve(helpers.audit(options, [
--- a/browser/devtools/commandline/test/browser_cmd_appcache_valid.js
+++ b/browser/devtools/commandline/test/browser_cmd_appcache_valid.js
@@ -4,17 +4,17 @@
 // Tests that the appcache commands works as they should
 
 const TEST_URI = "http://sub1.test2.example.com/browser/browser/devtools/" +
                  "commandline/test/browser_cmd_appcache_valid_index.html";
 let tests = {};
 
 function test() {
   helpers.addTabWithToolbar(TEST_URI, function(options) {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
 
     info("adding cache listener.");
 
     // Wait for site to be cached.
     gBrowser.contentWindow.applicationCache.addEventListener('cached', function BCAV_cached() {
       gBrowser.contentWindow.applicationCache.removeEventListener('cached', BCAV_cached);
 
       info("Site now cached, running tests.");
--- a/browser/devtools/commandline/test/browser_cmd_calllog.js
+++ b/browser/devtools/commandline/test/browser_cmd_calllog.js
@@ -43,17 +43,17 @@ tests.testCallLogStatus = function(optio
         markup: 'VVVVVVVVVVVV',
         status: 'VALID'
       }
     },
   ]);
 };
 
 tests.testCallLogExec = function(options) {
-  var deferred = Promise.defer();
+  var deferred = promise.defer();
 
   var onWebConsoleOpen = function(subject) {
     Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
 
     subject.QueryInterface(Ci.nsISupportsString);
     let hud = HUDService.getHudReferenceById(subject.data);
     ok(hud.hudId in HUDService.hudReferences, "console open");
 
@@ -92,17 +92,17 @@ tests.testCallLogExec = function(options
       exec: {
         output: /No call logging/,
       }
     },
     {
       name: "calllog start",
       setup: function() {
         // This test wants to be in a different event
-        var deferred = Promise.defer();
+        var deferred = promise.defer();
         executeSoon(function() {
           helpers.setInput(options, "calllog start");
           deferred.resolve();
         });
         return deferred.promise;
       },
       exec: {
         output: /Call logging started/,
--- a/browser/devtools/commandline/test/browser_cmd_calllog_chrome.js
+++ b/browser/devtools/commandline/test/browser_cmd_calllog_chrome.js
@@ -44,17 +44,17 @@ tests.testCallLogStatus = function(optio
         status: "VALID",
         emptyParameters: [ " " ]
       }
     },
   ]);
 };
 
 tests.testCallLogExec = function(options) {
-  let deferred = Promise.defer();
+  let deferred = promise.defer();
 
   function onWebConsoleOpen(subject) {
     Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
 
     subject.QueryInterface(Ci.nsISupportsString);
     let hud = HUDService.getHudReferenceById(subject.data);
     ok(hud.hudId in HUDService.hudReferences, "console open");
 
--- a/browser/devtools/commandline/test/browser_cmd_commands.js
+++ b/browser/devtools/commandline/test/browser_cmd_commands.js
@@ -11,17 +11,17 @@ let tests = {};
 
 function test() {
   helpers.addTabWithToolbar(TEST_URI, function(options) {
     return helpers.runTests(options, tests);
   }).then(finish);
 }
 
 tests.testConsole = function(options) {
-  let deferred = Promise.defer();
+  let deferred = promise.defer();
   let hud = null;
 
   let onWebConsoleOpen = function(subject) {
     Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
 
     subject.QueryInterface(Ci.nsISupportsString);
     hud = HUDService.getHudReferenceById(subject.data);
     ok(hud.hudId in HUDService.hudReferences, "console open");
--- a/browser/devtools/commandline/test/browser_cmd_jsb.js
+++ b/browser/devtools/commandline/test/browser_cmd_jsb.js
@@ -12,17 +12,17 @@ let tests = {};
 
 function test() {
   helpers.addTabWithToolbar("about:blank", function(options) {
     return helpers.runTests(options, tests);
   }).then(finish);
 }
 
 tests.jsbTest = function(options) {
-  let deferred = Promise.defer();
+  let deferred = promise.defer();
 
   let observer = {
     onReady: function() {
       scratchpad.removeObserver(observer);
 
       let result = scratchpad.getText();
       result = result.replace(/[\r\n]]*/g, "\n");
       let correct = "function somefunc() {\n" +
--- a/browser/devtools/commandline/test/browser_cmd_pagemod_export.js
+++ b/browser/devtools/commandline/test/browser_cmd_pagemod_export.js
@@ -304,17 +304,17 @@ function test() {
           args: {
             searchAttributes: { value: 'foo' },
             searchElements: { value: 'bar' },
             root: { value: undefined },
             ignoreCase: { value: false },
           }
         },
         post: function() {
-          let deferred = Promise.defer();
+          let deferred = promise.defer();
           executeSoon(function() {
             deferred.resolve();
           });
           return deferred.promise;
         }
       },
       {
         setup: 'pagemod remove attribute foo bar',
--- a/browser/devtools/commandline/test/browser_cmd_screenshot.js
+++ b/browser/devtools/commandline/test/browser_cmd_screenshot.js
@@ -161,29 +161,29 @@ function test() {
 function addTabWithToolbarRunTests(win) {
   return helpers.addTabWithToolbar(TEST_URI, function(options) {
     return helpers.runTests(options, tests);
   }, { chromeWindow: win });
 }
 
 function addWindow(windowOptions, callback) {
   waitForExplicitFinish();
-  let deferred = Promise.defer();
+  let deferred = promise.defer();
 
   let win = OpenBrowserWindow(windowOptions);
 
   let onLoad = function() {
     win.removeEventListener("load", onLoad, false);
 
     // Would like to get rid of this executeSoon, but without it the url
     // (TEST_URI) provided in addTabWithToolbarRunTests hasn't loaded
     executeSoon(function() {
       try {
         let reply = callback(win);
-        Promise.resolve(reply).then(function() {
+        promise.resolve(reply).then(function() {
           win.close();
           deferred.resolve();
         });
       }
       catch (ex) {
         deferred.reject(ex);
       }
     });
--- a/browser/devtools/commandline/test/browser_gcli_async.js
+++ b/browser/devtools/commandline/test/browser_gcli_async.js
@@ -22,21 +22,21 @@ function test() {
 }
 
 // <INJECTED SOURCE:END>
 
 'use strict';
 
 // var helpers = require('gclitest/helpers');
 var canon = require('gcli/canon');
-var Promise = require('util/promise');
+var promise = require('util/promise');
 
 exports.testBasic = function(options) {
   var getData = function() {
-    var deferred = Promise.defer();
+    var deferred = promise.defer();
 
     var resolve = function() {
       deferred.resolve([
         'Shalom', 'Namasté', 'Hallo', 'Dydd-da',
         'Chào', 'Hej', 'Saluton', 'Sawubona'
       ]);
     };
 
--- a/browser/devtools/commandline/test/helpers.js
+++ b/browser/devtools/commandline/test/helpers.js
@@ -21,17 +21,17 @@ this.EXPORTED_SYMBOLS = [ 'helpers' ];
 var helpers = {};
 this.helpers = helpers;
 let require = (Cu.import("resource://gre/modules/devtools/Require.jsm", {})).require;
 Components.utils.import("resource://gre/modules/devtools/gcli.jsm", {});
 
 let console = (Cu.import("resource://gre/modules/devtools/Console.jsm", {})).console;
 let TargetFactory = (Cu.import("resource://gre/modules/devtools/Loader.jsm", {})).devtools.TargetFactory;
 
-let Promise = (Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {})).Promise;
+let promise = (Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {})).Promise;
 let assert = { ok: ok, is: is, log: info };
 
 var util = require('util/util');
 
 var converters = require('gcli/converters');
 
 /**
  * Warning: For use with Firefox Mochitests only.
@@ -55,17 +55,17 @@ var converters = require('gcli/converter
  * 'options' parameter. This has the ability to customize the value of
  * chromeWindow or isFirefox, and to add new properties.
  *
  * @param url The URL for the new tab
  * @param callback The function to call on page load
  * @param options An optional set of options to customize the way the tests run
  */
 helpers.addTab = function(url, callback, options) {
-  var deferred = Promise.defer();
+  var deferred = promise.defer();
 
   waitForExplicitFinish();
 
   options = options || {};
   options.chromeWindow = options.chromeWindow || window;
   options.isFirefox = true;
 
   var tabbrowser = options.chromeWindow.gBrowser;
@@ -91,17 +91,17 @@ helpers.addTab = function(url, callback,
 
       delete options.chromeWindow;
       delete options.isFirefox;
 
       deferred.resolve();
     };
 
     var reply = callback(options);
-    Promise.resolve(reply).then(cleanUp, function(error) {
+    promise.resolve(reply).then(cleanUp, function(error) {
       ok(false, error);
       cleanUp();
     });
   };
 
   options.browser.contentWindow.location = url;
   options.browser.addEventListener("load", onPageLoad, true);
 
@@ -113,29 +113,29 @@ helpers.addTab = function(url, callback,
  *
  * As addTab, but that also opens the developer toolbar. In addition a new
  * 'display' property is added to the options object with the display from GCLI
  * in the developer toolbar
  */
 helpers.addTabWithToolbar = function(url, callback, options) {
   return helpers.addTab(url, function(innerOptions) {
     var win = innerOptions.chromeWindow;
-    var deferred = Promise.defer();
+    var deferred = promise.defer();
 
     win.DeveloperToolbar.show(true, function() {
       innerOptions.display = win.DeveloperToolbar.display;
 
       var cleanUp = function() {
         win.DeveloperToolbar.hide();
         delete innerOptions.display;
         deferred.resolve();
       };
 
       var reply = callback(innerOptions);
-      Promise.resolve(reply).then(cleanUp, function(error) {
+      promise.resolve(reply).then(cleanUp, function(error) {
         ok(false, error);
         cleanUp();
       });
     });
     return deferred.promise;
   }, options);
 };
 
@@ -158,42 +158,42 @@ helpers.runTests = function(options, tes
 
   var recover = function(error) {
     ok(false, error);
     console.error(error);
   };
 
   info("SETUP");
   var setupDone = (tests.setup != null) ?
-      Promise.resolve(tests.setup(options)) :
-      Promise.resolve();
+      promise.resolve(tests.setup(options)) :
+      promise.resolve();
 
   var testDone = setupDone.then(function() {
     return util.promiseEach(testNames, function(testName) {
       info(testName);
       var action = tests[testName];
 
       if (typeof action === "function") {
         var reply = action.call(tests, options);
-        return Promise.resolve(reply);
+        return promise.resolve(reply);
       }
       else if (Array.isArray(action)) {
         return helpers.audit(options, action);
       }
 
-      return Promise.reject("test action '" + testName +
+      return promise.reject("test action '" + testName +
                             "' is not a function or helpers.audit() object");
     });
   }, recover);
 
   return testDone.then(function() {
     info("SHUTDOWN");
     return (tests.shutdown != null) ?
-        Promise.resolve(tests.shutdown(options)) :
-        Promise.resolve();
+        promise.resolve(tests.shutdown(options)) :
+        promise.resolve();
   }, recover);
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 
 function checkOptions(options) {
   if (options == null) {
     console.trace();
@@ -221,17 +221,17 @@ helpers._actual = {
     var templateData = options.display.completer._getCompleterTemplateData();
     var join = function(directTabText, emptyParameters, arrowTabText) {
       return (directTabText + emptyParameters.join('') + arrowTabText)
                 .replace(/\u00a0/g, ' ')
                 .replace(/\u21E5/, '->')
                 .replace(/ $/, '');
     };
 
-    var promisedJoin = Promise.promised(join);
+    var promisedJoin = promise.promised(join);
     return promisedJoin(templateData.directTabText,
                         templateData.emptyParameters,
                         templateData.arrowTabText);
   },
 
   markup: function(options) {
     var cursor = options.display.inputter.element.selectionStart;
     var statusMarkup = options.display.requisition.getInputStatusMarkup(cursor);
@@ -309,17 +309,17 @@ helpers._createDebugCheck = function(opt
   var command = requisition.commandAssignment.value;
   var cursor = helpers._actual.cursor(options);
   var input = helpers._actual.input(options);
   var padding = Array(input.length + 1).join(' ');
 
   var hintsPromise = helpers._actual.hints(options);
   var predictionsPromise = helpers._actual.predictions(options);
 
-  return Promise.all(hintsPromise, predictionsPromise).then(function(values) {
+  return promise.all(hintsPromise, predictionsPromise).then(function(values) {
     var hints = values[0];
     var predictions = values[1];
     var output = '';
 
     output += 'return helpers.audit(options, [\n';
     output += '  {\n';
 
     if (cursor === input.length) {
@@ -454,53 +454,53 @@ var CHUNKER = /([^<]*)(<[A-Z]+>)/;
 
 /**
  * Alter the input to <code>typed</code> optionally leaving the cursor at
  * <code>cursor</code>.
  * @return A promise of the number of key-presses to respond
  */
 helpers.setInput = function(options, typed, cursor) {
   checkOptions(options);
-  var promise = undefined;
+  var inputPromise = undefined;
   var inputter = options.display.inputter;
   // We try to measure average keypress time, but setInput can simulate
   // several, so we try to keep track of how many
   var chunkLen = 1;
 
   // The easy case is a simple string without things like <TAB>
   if (typed.indexOf('<') === -1) {
-    promise = inputter.setInput(typed);
+    inputPromise = inputter.setInput(typed);
   }
   else {
     // Cut the input up into input strings separated by '<KEY>' tokens. The
     // CHUNKS RegExp leaves blanks so we filter them out.
     var chunks = typed.split(CHUNKER).filter(function(s) {
       return s != '';
     });
     chunkLen = chunks.length + 1;
 
     // We're working on this in chunks so first clear the input
-    promise = inputter.setInput('').then(function() {
+    inputPromise = inputter.setInput('').then(function() {
       return util.promiseEach(chunks, function(chunk) {
         if (chunk.charAt(0) === '<') {
           var action = ACTIONS[chunk];
           if (typeof action !== 'function') {
             console.error('Known actions: ' + Object.keys(ACTIONS).join());
             throw new Error('Key action not found "' + chunk + '"');
           }
           return action(options);
         }
         else {
           return inputter.setInput(inputter.element.value + chunk);
         }
       });
     });
   }
 
-  return promise.then(function() {
+  return inputPromise.then(function() {
     if (cursor != null) {
       options.display.inputter.setCursor({ start: cursor, end: cursor });
     }
     else {
       // This is a hack because jsdom appears to not handle cursor updates
       // in the same way as most browsers.
       if (options.isJsdom) {
         options.display.inputter.setCursor({
@@ -526,17 +526,17 @@ helpers.setInput = function(options, typ
  * Helper for helpers.audit() to ensure that all the 'check' properties match.
  * See helpers.audit for more information.
  * @param name The name to use in error messages
  * @param checks See helpers.audit for a list of available checks
  * @return A promise which resolves to undefined when the checks are complete
  */
 helpers._check = function(options, name, checks) {
   if (checks == null) {
-    return Promise.resolve();
+    return promise.resolve();
   }
 
   var outstanding = [];
   var suffix = name ? ' (for \'' + name + '\')' : '';
 
   if ('input' in checks) {
     assert.is(helpers._actual.input(options), checks.input, 'input' + suffix);
   }
@@ -695,58 +695,58 @@ helpers._check = function(options, name,
           assert.is(assignment.getMessage(),
                     check.message,
                     'arg.' + paramName + '.message' + suffix);
         }
       }
     });
   }
 
-  return Promise.all(outstanding).then(function() {
+  return promise.all(outstanding).then(function() {
     // Ensure the promise resolves to nothing
     return undefined;
   });
 };
 
 /**
  * Helper for helpers.audit() to ensure that all the 'exec' properties work.
  * See helpers.audit for more information.
  * @param name The name to use in error messages
  * @param expected See helpers.audit for a list of available exec checks
  * @return A promise which resolves to undefined when the checks are complete
  */
 helpers._exec = function(options, name, expected) {
   if (expected == null) {
-    return Promise.resolve({});
+    return promise.resolve({});
   }
 
   var output;
   try {
     output = options.display.requisition.exec({ hidden: true });
   }
   catch (ex) {
     assert.ok(false, 'Failure executing \'' + name + '\': ' + ex);
     util.errorHandler(ex);
 
-    return Promise.resolve({});
+    return promise.resolve({});
   }
 
   if ('completed' in expected) {
     assert.is(output.completed,
               expected.completed,
               'output.completed false for: ' + name);
   }
 
   if (!options.window.document.createElement) {
     assert.log('skipping output tests (missing doc.createElement) for ' + name);
-    return Promise.resolve({ output: output });
+    return promise.resolve({ output: output });
   }
 
   if (!('output' in expected)) {
-    return Promise.resolve({ output: output });
+    return promise.resolve({ output: output });
   }
 
   var checkOutput = function() {
     if ('type' in expected) {
       assert.is(output.type,
                 expected.type,
                 'output.type for: ' + name);
     }
@@ -799,30 +799,30 @@ helpers._exec = function(options, name, 
  * Helper to setup the test
  */
 helpers._setup = function(options, name, action) {
   if (typeof action === 'string') {
     return helpers.setInput(options, action);
   }
 
   if (typeof action === 'function') {
-    return Promise.resolve(action());
+    return promise.resolve(action());
   }
 
-  return Promise.reject('\'setup\' property must be a string or a function. Is ' + action);
+  return promise.reject('\'setup\' property must be a string or a function. Is ' + action);
 };
 
 /**
  * Helper to shutdown the test
  */
 helpers._post = function(name, action, data) {
   if (typeof action === 'function') {
-    return Promise.resolve(action(data.output, data.text));
+    return promise.resolve(action(data.output, data.text));
   }
-  return Promise.resolve(action);
+  return promise.resolve(action);
 };
 
 /*
  * We do some basic response time stats so we can see if we're getting slow
  */
 var totalResponseTime = 0;
 var averageOver = 0;
 var maxResponseTime = 0;
@@ -942,36 +942,36 @@ helpers.audit = function(options, audits
 
     if (audit.skipIf) {
       var skip = (typeof audit.skipIf === 'function') ?
           audit.skipIf(options) :
           !!audit.skipIf;
       if (skip) {
         var reason = audit.skipIf.name ? 'due to ' + audit.skipIf.name : '';
         assert.log('Skipped ' + name + ' ' + reason);
-        return Promise.resolve(undefined);
+        return promise.resolve(undefined);
       }
     }
 
     if (audit.skipRemainingIf) {
       var skipRemainingIf = (typeof audit.skipRemainingIf === 'function') ?
           audit.skipRemainingIf(options) :
           !!audit.skipRemainingIf;
       if (skipRemainingIf) {
         skipReason = audit.skipRemainingIf.name ?
             'due to ' + audit.skipRemainingIf.name :
             '';
         assert.log('Skipped ' + name + ' ' + skipReason);
-        return Promise.resolve(undefined);
+        return promise.resolve(undefined);
       }
     }
 
     if (skipReason != null) {
       assert.log('Skipped ' + name + ' ' + skipReason);
-      return Promise.resolve(undefined);
+      return promise.resolve(undefined);
     }
 
     var start = new Date().getTime();
 
     var setupDone = helpers._setup(options, name, audit.setup);
     return setupDone.then(function(chunkLen) {
 
       if (typeof chunkLen !== 'number') {
--- a/browser/devtools/debugger/DebuggerPanel.jsm
+++ b/browser/devtools/debugger/DebuggerPanel.jsm
@@ -7,18 +7,18 @@
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 this.EXPORTED_SYMBOLS = ["DebuggerPanel"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/shared/event-emitter.js");
 
-XPCOMUtils.defineLazyModuleGetter(this, "Promise",
-  "resource://gre/modules/commonjs/sdk/core/promise.js");
+XPCOMUtils.defineLazyModuleGetter(this, "promise",
+  "resource://gre/modules/commonjs/sdk/core/promise.js", "Promise");
 
 this.DebuggerPanel = function DebuggerPanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
   this._toolbox = toolbox;
 
   this._view = this.panelWin.DebuggerView;
   this._controller = this.panelWin.DebuggerController;
   this._controller._target = this.target;
@@ -30,29 +30,29 @@ this.DebuggerPanel = function DebuggerPa
   EventEmitter.decorate(this);
 }
 
 DebuggerPanel.prototype = {
   /**
    * Open is effectively an asynchronous constructor.
    *
    * @return object
-   *         A Promise that is resolved when the Debugger completes opening.
+   *         A promise that is resolved when the Debugger completes opening.
    */
   open: function DebuggerPanel_open() {
-    let promise;
+    let targetPromise;
 
     // Local debugging needs to make the target remote.
     if (!this.target.isRemote) {
-      promise = this.target.makeRemote();
+      targetPromise = this.target.makeRemote();
     } else {
-      promise = Promise.resolve(this.target);
+      targetPromise = promise.resolve(this.target);
     }
 
-    return promise
+    return targetPromise
       .then(() => this._controller.startupDebugger())
       .then(() => this._controller.connect())
       .then(() => {
         this.target.on("thread-paused", this.highlightWhenPaused);
         this.target.on("thread-resumed", this.unhighlightWhenResumed);
         this.isReady = true;
         this.emit("ready");
         return this;
@@ -65,17 +65,17 @@ DebuggerPanel.prototype = {
 
   // DevToolPanel API
   get target() this._toolbox.target,
 
   destroy: function() {
     this.target.off("thread-paused", this.highlightWhenPaused);
     this.target.off("thread-resumed", this.unhighlightWhenResumed);
     this.emit("destroyed");
-    return Promise.resolve(null);
+    return promise.resolve(null);
   },
 
   // DebuggerPanel API
 
   addBreakpoint: function() {
     this._bkp.addBreakpoint.apply(this._bkp, arguments);
   },
 
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -12,17 +12,17 @@ const NEW_SOURCE_IGNORED_URLS = ["debugg
 const NEW_SOURCE_DISPLAY_DELAY = 200; // ms
 const FETCH_SOURCE_RESPONSE_DELAY = 50; // ms
 const FRAME_STEP_CLEAR_DELAY = 100; // ms
 const CALL_STACK_PAGE_SIZE = 25; // frames
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
-Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
+let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 Cu.import("resource:///modules/source-editor.jsm");
 Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
 Cu.import("resource:///modules/devtools/BreadcrumbsWidget.jsm");
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/VariablesView.jsm");
 Cu.import("resource:///modules/devtools/VariablesViewController.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
@@ -68,17 +68,17 @@ let DebuggerController = {
     this._isInitialized = true;
 
     // Chrome debugging lives in a different process and needs to handle
     // debugger startup by itself.
     if (window._isChromeDebugger) {
       window.removeEventListener("DOMContentLoaded", this.startupDebugger, true);
     }
 
-    let deferred = this._startup = Promise.defer();
+    let deferred = this._startup = promise.defer();
 
     DebuggerView.initialize(() => {
       DebuggerView._isInitialized = true;
 
       // Chrome debugging needs to initiate the connection by itself.
       if (window._isChromeDebugger) {
         this.connect().then(deferred.resolve);
       } else {
@@ -103,17 +103,17 @@ let DebuggerController = {
     this._startup = null;
 
     // Chrome debugging lives in a different process and needs to handle
     // debugger shutdown by itself.
     if (window._isChromeDebugger) {
       window.removeEventListener("unload", this.shutdownDebugger, true);
     }
 
-    let deferred = this._shutdown = Promise.defer();
+    let deferred = this._shutdown = promise.defer();
 
     DebuggerView.destroy(() => {
       DebuggerView._isDestroyed = true;
 
       this.SourceScripts.disconnect();
       this.StackFrames.disconnect();
       this.ThreadState.disconnect();
 
@@ -137,17 +137,17 @@ let DebuggerController = {
    * @return object
    *         A promise that is resolved when the debugger finishes connecting.
    */
   connect: function() {
     if (this._connection) {
       return this._connection.promise;
     }
 
-    let deferred = this._connection = Promise.defer();
+    let deferred = this._connection = promise.defer();
 
     if (!window._isChromeDebugger) {
       let target = this._target;
       let { client, form, threadActor } = target;
       target.on("close", this._onTabDetached);
       target.on("navigate", this._onTabNavigated);
       target.on("will-navigate", this._onTabNavigated);
 
@@ -1016,17 +1016,17 @@ SourceScripts.prototype = {
    *         A promise that is resolved after the source text has been fetched.
    */
   getTextForSource: function(aSource, aOnTimeout, aDelay = FETCH_SOURCE_RESPONSE_DELAY) {
     // Fetch the source text only once.
     if (aSource._fetched) {
       return aSource._fetched;
     }
 
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
     aSource._fetched = deferred.promise;
 
     // If the source text takes a long time to fetch, invoke a callback.
     if (aOnTimeout) {
       var fetchTimeout = window.setTimeout(() => aOnTimeout(aSource), aDelay);
     }
 
     // Get the source text from the active thread.
@@ -1049,17 +1049,17 @@ SourceScripts.prototype = {
    *
    * @param array aUrls
    *        The urls for the sources to fetch. If fetching a source's text
    *        takes too long, it will be discarded.
    * @return object
    *         A promise that is resolved after source texts have been fetched.
    */
   getTextForSources: function(aUrls) {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
     let pending = new Set(aUrls);
     let fetched = [];
 
     // Can't use Promise.all, because if one fetch operation is rejected, then
     // everything is considered rejected, thus no other subsequent source will
     // be getting fetched. We don't want that. Something like Q's allSettled
     // would work like a charm here.
 
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -90,17 +90,16 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_bug740825_conditional-breakpoints-01.js \
 	browser_dbg_bug740825_conditional-breakpoints-02.js \
 	browser_dbg_bug727429_watch-expressions-01.js \
 	browser_dbg_bug727429_watch-expressions-02.js \
 	browser_dbg_bug731394_editor-contextmenu.js \
 	browser_dbg_bug737803_editor_actual_location.js \
 	browser_dbg_bug786070_hide_nonenums.js \
 	browser_dbg_bug868163_highight_on_pause.js \
-	browser_dbg_bug883220_raise_on_pause.js \
 	browser_dbg_displayName.js \
 	browser_dbg_pause-exceptions.js \
 	browser_dbg_pause-exceptions-reload.js \
 	browser_dbg_multiple-windows.js \
 	browser_dbg_iframes.js \
 	browser_dbg_bfcache.js \
 	browser_dbg_progress-listener-bug.js \
 	browser_dbg_chrome-debugging.js \
@@ -143,18 +142,21 @@ MOCHITEST_BROWSER_PAGES = \
 	binary_search.js \
 	binary_search.map \
 	test-location-changes-bp.js \
 	test-location-changes-bp.html \
 	test-step-out.html \
 	test-pause-exceptions-reload.html \
 	$(NULL)
 
+# Bug 888811 & bug 891176:
+#   Disable browser_dbg_bug883220_raise_on_pause.js due to frequent failures
 ifneq (Linux,$(OS_ARCH))
 MOCHITEST_BROWSER_TESTS += \
+	browser_dbg_bug883220_raise_on_pause.js \
 	browser_dbg_createChrome.js \
 	$(NULL)
 else
 $(browser_dbg_createChrome.js disabled to fix for ubuntu hangs, bug 847558)
 endif
 
 MOCHITEST_BROWSER_FILES_PARTS = MOCHITEST_BROWSER_TESTS MOCHITEST_BROWSER_PAGES
 
--- a/browser/devtools/debugger/test/browser_dbg_bug883220_raise_on_pause.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug883220_raise_on_pause.js
@@ -8,17 +8,17 @@
 // currently selected tool.
 
 var gTab = null;
 var gTab2 = null;
 var gDebugger = null;
 var gToolbox = null;
 var gToolboxTab = null;
 var gFocusedWindow = null;
-Promise._reportErrors = true;
+promise._reportErrors = true;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebugger = aPane.panelWin;
     gToolbox = aPane._toolbox;
     gToolboxTab = gToolbox.doc.getElementById("toolbox-tab-jsdebugger");
     gBrowser.selectedTab = gTab2 = gBrowser.addTab();
--- a/browser/devtools/debugger/test/browser_dbg_cmd.js
+++ b/browser/devtools/debugger/test/browser_dbg_cmd.js
@@ -2,17 +2,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   const TEST_URI = "http://example.com/browser/browser/devtools/debugger/" +
                    "test/browser_dbg_cmd.html";
 
   helpers.addTabWithToolbar(TEST_URI, function(options) {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
 
     let openDone = helpers.audit(options, [{
       setup: "dbg open",
       exec: { output: "", completed: false }
     }]);
 
     openDone.then(function() {
       gDevTools.showToolbox(options.target, "jsdebugger").then(function(toolbox) {
@@ -100,9 +100,9 @@ function test() {
             }]);
           });
         });
       });
     });
 
     return deferred.promise;
   }).then(finish);
-}
\ No newline at end of file
+}
--- a/browser/devtools/debugger/test/browser_dbg_cmd_break.js
+++ b/browser/devtools/debugger/test/browser_dbg_cmd_break.js
@@ -37,17 +37,17 @@ function test() {
           hints:                ' <file> <line>',
           markup: 'VVVVVVVVVVVVVV',
           status: 'ERROR'
         },
       },
       {
         name: 'open toolbox',
         setup: function() {
-          var deferred = Promise.defer();
+          var deferred = promise.defer();
 
           var openDone = gDevTools.showToolbox(options.target, "jsdebugger");
           openDone.then(function(toolbox) {
             let dbg = toolbox.getCurrentPanel();
             ok(dbg, "DebuggerPanel exists");
 
             // Wait for the initial resume...
             dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
@@ -123,17 +123,17 @@ function test() {
             /cmd_break\.html:13/
           ]
         },
       },
       {
         name: 'cleanup',
         setup: function() {
           // a.k.a "return client.activeThread.resume();"
-          var deferred = Promise.defer();
+          var deferred = promise.defer();
           client.activeThread.resume(function() {
             deferred.resolve();
           });
           return deferred.promise;
         },
       },
       {
         setup: 'break del 0',
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -6,17 +6,17 @@
 
 this.EXPORTED_SYMBOLS = [ "gDevTools", "DevTools", "gDevToolsBrowser" ];
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/shared/event-emitter.js");
-Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
+let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 Cu.import("resource://gre/modules/devtools/Loader.jsm");
 
 var ProfilerController = devtools.require("devtools/profiler/controller");
 
 const FORBIDDEN_IDS = new Set(["toolbox", ""]);
 const MAX_ORDINAL = 99;
 
 /**
@@ -182,32 +182,32 @@ DevTools.prototype = {
    *        The id of the tool to show
    * @param {Toolbox.HostType} hostType
    *        The type of host (bottom, window, side)
    *
    * @return {Toolbox} toolbox
    *        The toolbox that was opened
    */
   showToolbox: function(target, toolId, hostType) {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
 
     let toolbox = this._toolboxes.get(target);
     if (toolbox) {
 
-      let promise = (hostType != null && toolbox.hostType != hostType) ?
+      let hostPromise = (hostType != null && toolbox.hostType != hostType) ?
           toolbox.switchHost(hostType) :
-          Promise.resolve(null);
+          promise.resolve(null);
 
       if (toolId != null && toolbox.currentToolId != toolId) {
-        promise = promise.then(function() {
+        hostPromise = hostPromise.then(function() {
           return toolbox.selectTool(toolId);
         });
       }
 
-      return promise.then(function() {
+      return hostPromise.then(function() {
         toolbox.raise();
         return toolbox;
       });
     }
     else {
       // No toolbox for target, create one
       toolbox = new devtools.Toolbox(target, toolId, hostType);
 
--- a/browser/devtools/framework/sidebar.js
+++ b/browser/devtools/framework/sidebar.js
@@ -3,17 +3,17 @@
 /* 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 {Cu} = require("chrome");
 
 Cu.import("resource://gre/modules/Services.jsm");
 
-var Promise = require("sdk/core/promise");
+var promise = require("sdk/core/promise");
 var EventEmitter = require("devtools/shared/event-emitter");
 var Telemetry = require("devtools/shared/telemetry");
 
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 /**
  * ToolSidebar provides methods to register tabs in the sidebar.
  * It's assumed that the sidebar contains a xul:tabbox.
@@ -207,17 +207,17 @@ ToolSidebar.prototype = {
     return panel.firstChild.contentWindow;
   },
 
   /**
    * Clean-up.
    */
   destroy: function ToolSidebar_destroy() {
     if (this._destroyed) {
-      return Promise.resolve(null);
+      return promise.resolve(null);
     }
     this._destroyed = true;
 
     Services.prefs.setIntPref("devtools.toolsidebar-width." + this._uid, this._tabbox.width);
 
     this._tabbox.tabpanels.removeEventListener("select", this, true);
 
     while (this._tabbox.tabpanels.hasChildNodes()) {
@@ -232,11 +232,11 @@ ToolSidebar.prototype = {
       this._telemetry.toolClosed(this._currentTool);
     }
 
     this._tabs = null;
     this._tabbox = null;
     this._panelDoc = null;
     this._toolPanel = null;
 
-    return Promise.resolve(null);
+    return promise.resolve(null);
   },
 }
--- a/browser/devtools/framework/target.js
+++ b/browser/devtools/framework/target.js
@@ -1,17 +1,17 @@
 /* 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/. */
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 
-var Promise = require("sdk/core/promise");
+var promise = require("sdk/core/promise");
 var EventEmitter = require("devtools/shared/event-emitter");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DebuggerServer",
   "resource://gre/modules/devtools/dbg-server.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
   "resource://gre/modules/devtools/dbg-client.jsm");
 
@@ -48,23 +48,23 @@ exports.TargetFactory = {
    *          form: the remote protocol form of a tab,
    *          client: a DebuggerClient instance,
    *          chrome: true if the remote target is the whole process
    *        }
    *
    * @return A promise of a target object
    */
   forRemoteTab: function TF_forRemoteTab(options) {
-    let promise = promiseTargets.get(options);
-    if (promise == null) {
+    let targetPromise = promiseTargets.get(options);
+    if (targetPromise == null) {
       let target = new TabTarget(options);
-      promise = target.makeRemote().then(() => target);
-      promiseTargets.set(options, promise);
+      targetPromise = target.makeRemote().then(() => target);
+      promiseTargets.set(options, targetPromise);
     }
-    return promise;
+    return targetPromise;
   },
 
   /**
    * Creating a target for a tab that is being closed is a problem because it
    * allows a leak as a result of coming after the close event which normally
    * clears things up. This function allows us to ask if there is a known
    * target for a tab without creating a target
    * @return true/false
@@ -268,17 +268,17 @@ TabTarget.prototype = {
    * for tools that support the Remote Debugging Protocol even for local
    * connections.
    */
   makeRemote: function TabTarget_makeRemote() {
     if (this._remote) {
       return this._remote.promise;
     }
 
-    this._remote = Promise.defer();
+    this._remote = promise.defer();
 
     if (this.isLocalTab) {
       // Since a remote protocol connection will be made, let's start the
       // DebuggerServer here, once and for all tools.
       if (!DebuggerServer.initialized) {
         DebuggerServer.init();
         DebuggerServer.addBrowserActors();
       }
@@ -396,17 +396,17 @@ TabTarget.prototype = {
    */
   destroy: function() {
     // If several things call destroy then we give them all the same
     // destruction promise so we're sure to destroy only once
     if (this._destroyer) {
       return this._destroyer.promise;
     }
 
-    this._destroyer = Promise.defer();
+    this._destroyer = promise.defer();
 
     // Before taking any action, notify listeners that destruction is imminent.
     this.emit("close");
 
     // First of all, do cleanup tasks that pertain to both remoted and
     // non-remoted targets.
     this.off("thread-resumed", this._handleThreadState);
     this.off("thread-paused", this._handleThreadState);
@@ -600,15 +600,15 @@ WindowTarget.prototype = {
       this.off("thread-paused", this._handleThreadState);
       this.off("thread-resumed", this._handleThreadState);
       this.emit("close");
 
       targets.delete(this._window);
       this._window = null;
     }
 
-    return Promise.resolve(null);
+    return promise.resolve(null);
   },
 
   toString: function() {
     return 'WindowTarget:' + this.window;
   },
 };
--- a/browser/devtools/framework/test/browser_devtools_api.js
+++ b/browser/devtools/framework/test/browser_devtools_api.js
@@ -92,17 +92,17 @@ function DevToolPanel(iframeWindow, tool
   let textNode = doc.createTextNode("Some Tool");
 
   label.appendChild(textNode);
   doc.body.appendChild(label);*/
 }
 
 DevToolPanel.prototype = {
   open: function() {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
 
     executeSoon(function() {
       this._isReady = true;
       this.emit("ready");
       deferred.resolve(this);
     }.bind(this));
 
     return deferred.promise;
@@ -112,11 +112,11 @@ DevToolPanel.prototype = {
 
   get toolbox() this._toolbox,
 
   get isReady() this._isReady,
 
   _isReady: false,
 
   destroy: function DTI_destroy() {
-    return Promise.defer(null);
+    return promise.defer(null);
   },
 };
--- a/browser/devtools/framework/test/browser_toolbox_options_disablejs.js
+++ b/browser/devtools/framework/test/browser_toolbox_options_disablejs.js
@@ -60,17 +60,17 @@ function testJSEnabledIframe(secondPass)
   if (secondPass) {
     finishUp();
   } else {
     toggleJS().then(testJSDisabled);
   }
 }
 
 function toggleJS() {
-  let deferred = Promise.defer();
+  let deferred = promise.defer();
   let panel = toolbox.getCurrentPanel();
   let cbx = panel.panelDoc.getElementById("devtools-disable-javascript");
 
   cbx.scrollIntoView();
 
   if (cbx.checked) {
     info("Clearing checkbox to re-enable JS");
   } else {
--- a/browser/devtools/framework/test/browser_toolbox_sidebar.js
+++ b/browser/devtools/framework/test/browser_toolbox_sidebar.js
@@ -24,17 +24,17 @@ function test() {
 
   let toolDefinition = {
     id: "fakeTool4242",
     visibilityswitch: "devtools.fakeTool4242.enabled",
     url: toolURL,
     label: "FAKE TOOL!!!",
     isTargetSupported: function() true,
     build: function(iframeWindow, toolbox) {
-      let deferred = Promise.defer();
+      let deferred = promise.defer();
       executeSoon(function() {
         deferred.resolve({
           target: toolbox.target,
           toolbox: toolbox,
           isReady: true,
           destroy: function(){},
           panelDoc: iframeWindow.document,
         });
--- a/browser/devtools/framework/test/browser_toolbox_window_title_changes.js
+++ b/browser/devtools/framework/test/browser_toolbox_window_title_changes.js
@@ -32,17 +32,17 @@ function test() {
       .then(checkTitle.bind(null, LABEL_1, URL_1, "toolbox undocked"))
 
     // switch to different tool and check title
       .then(function () toolbox.selectTool(TOOL_ID_2))
       .then(checkTitle.bind(null, LABEL_2, URL_1, "tool changed"))
 
     // navigate to different url and check title
       .then(function () {
-        let deferred = Promise.defer();
+        let deferred = promise.defer();
         target.once("navigate", function () deferred.resolve());
         gBrowser.loadURI(URL_2);
         return deferred.promise;
       })
       .then(checkTitle.bind(null, LABEL_2, URL_2, "url changed"))
 
     // destroy toolbox, create new one hosted in a window (with a
     // different tool id), and check title
--- a/browser/devtools/framework/test/head.js
+++ b/browser/devtools/framework/test/head.js
@@ -3,34 +3,34 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 let TargetFactory = gDevTools.TargetFactory;
 
 let tempScope = {};
 Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
 let console = tempScope.console;
 Components.utils.import("resource://gre/modules/commonjs/sdk/core/promise.js", tempScope);
-let Promise = tempScope.Promise;
+let promise = tempScope.Promise;
 
 let {devtools} = Components.utils.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 
 /**
  * Open a new tab at a URL and call a callback on load
  */
 function addTab(aURL, aCallback)
 {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
   if (aURL != null) {
     content.location = aURL;
   }
 
-  let deferred = Promise.defer();
+  let deferred = promise.defer();
 
   let tab = gBrowser.selectedTab;
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   let browser = gBrowser.getBrowserForTab(tab);
 
   function onTabLoad() {
     browser.removeEventListener("load", onTabLoad, true);
 
--- a/browser/devtools/framework/toolbox-hosts.js
+++ b/browser/devtools/framework/toolbox-hosts.js
@@ -1,17 +1,17 @@
 /* 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/. */
 
 "use strict";
 
 const {Cu} = require("chrome");
 
-let Promise = require("sdk/core/promise");
+let promise = require("sdk/core/promise");
 let EventEmitter = require("devtools/shared/event-emitter");
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 /**
  * A toolbox host represents an object that contains a toolbox (e.g. the
  * sidebar or a separate window). Any host object should implement the
  * following functions:
@@ -39,17 +39,17 @@ BottomHost.prototype = {
   type: "bottom",
 
   heightPref: "devtools.toolbox.footer.height",
 
   /**
    * Create a box at the bottom of the host tab.
    */
   create: function BH_create() {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
 
     let gBrowser = this.hostTab.ownerDocument.defaultView.gBrowser;
     let ownerDocument = gBrowser.ownerDocument;
 
     this._splitter = ownerDocument.createElement("splitter");
     this._splitter.setAttribute("class", "devtools-horizontal-splitter");
 
     this.frame = ownerDocument.createElement("iframe");
@@ -99,17 +99,17 @@ BottomHost.prototype = {
     if (!this._destroyed) {
       this._destroyed = true;
 
       Services.prefs.setIntPref(this.heightPref, this.frame.height);
       this._nbox.removeChild(this._splitter);
       this._nbox.removeChild(this.frame);
     }
 
-    return Promise.resolve(null);
+    return promise.resolve(null);
   }
 }
 
 
 /**
  * Host object for the in-browser sidebar
  */
 function SidebarHost(hostTab) {
@@ -122,17 +122,17 @@ SidebarHost.prototype = {
   type: "side",
 
   widthPref: "devtools.toolbox.sidebar.width",
 
   /**
    * Create a box in the sidebar of the host tab.
    */
   create: function SH_create() {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
 
     let gBrowser = this.hostTab.ownerDocument.defaultView.gBrowser;
     let ownerDocument = gBrowser.ownerDocument;
 
     this._splitter = ownerDocument.createElement("splitter");
     this._splitter.setAttribute("class", "devtools-side-splitter");
 
     this.frame = ownerDocument.createElement("iframe");
@@ -180,17 +180,17 @@ SidebarHost.prototype = {
     if (!this._destroyed) {
       this._destroyed = true;
 
       Services.prefs.setIntPref(this.widthPref, this.frame.width);
       this._sidebar.removeChild(this._splitter);
       this._sidebar.removeChild(this.frame);
     }
 
-    return Promise.resolve(null);
+    return promise.resolve(null);
   }
 }
 
 /**
  * Host object for the toolbox in a separate window
  */
 function WindowHost() {
   this._boundUnload = this._boundUnload.bind(this);
@@ -202,17 +202,17 @@ WindowHost.prototype = {
   type: "window",
 
   WINDOW_URL: "chrome://browser/content/devtools/framework/toolbox-window.xul",
 
   /**
    * Create a new xul window to contain the toolbox.
    */
   create: function WH_create() {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
 
     let flags = "chrome,centerscreen,resizable,dialog=no";
     let win = Services.ww.openWindow(null, this.WINDOW_URL, "_blank",
                                      flags, null);
 
     let frameLoad = function(event) {
       win.removeEventListener("load", frameLoad, true);
       this.frame = win.document.getElementById("toolbox-iframe");
@@ -263,17 +263,17 @@ WindowHost.prototype = {
   destroy: function WH_destroy() {
     if (!this._destroyed) {
       this._destroyed = true;
 
       this._window.removeEventListener("unload", this._boundUnload);
       this._window.close();
     }
 
-    return Promise.resolve(null);
+    return promise.resolve(null);
   }
 }
 
 /**
  *  Switch to the given tab in a browser and focus the browser window
  */
 function focusTab(tab) {
   let browserWindow = tab.ownerDocument.defaultView;
--- a/browser/devtools/framework/toolbox-options.js
+++ b/browser/devtools/framework/toolbox-options.js
@@ -1,17 +1,17 @@
 /* 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/. */
 
 "use strict";
 
 const {Cu, Cc, Ci} = require("chrome");
 
-let Promise = require("sdk/core/promise");
+let promise = require("sdk/core/promise");
 let EventEmitter = require("devtools/shared/event-emitter");
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
 exports.OptionsPanel = OptionsPanel;
 
@@ -48,17 +48,17 @@ function OptionsPanel(iframeWindow, tool
 
 OptionsPanel.prototype = {
 
   get target() {
     return this.toolbox.target;
   },
 
   open: function() {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
 
     this.setupToolsList();
     this.populatePreferences();
     this.prepareRestartPreferences();
 
     this._disableJSClicked = this._disableJSClicked.bind(this);
 
     let disableJSNode = this.panelDoc.getElementById("devtools-disable-javascript");
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -1,17 +1,17 @@
 /* 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/. */
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 const MAX_ORDINAL = 99;
-let Promise = require("sdk/core/promise");
+let promise = require("sdk/core/promise");
 let EventEmitter = require("devtools/shared/event-emitter");
 let Telemetry = require("devtools/shared/telemetry");
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
 loader.lazyGetter(this, "Hosts", () => require("devtools/framework/toolbox-hosts").Hosts);
@@ -186,17 +186,17 @@ Toolbox.prototype = {
   get doc() {
     return this.frame.contentDocument;
   },
 
   /**
    * Open the toolbox
    */
   open: function TBOX_open() {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
 
     this._host.create().then(iframe => {
       let domReady = () => {
         iframe.removeEventListener("DOMContentLoaded", domReady, true);
 
         this.isReady = true;
 
         let closeButton = this.doc.getElementById("toolbox-close");
@@ -422,17 +422,17 @@ Toolbox.prototype = {
 
   /**
    * Ensure the tool with the given id is loaded.
    *
    * @param {string} id
    *        The id of the tool to load.
    */
   loadTool: function TBOX_loadTool(id) {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
     let iframe = this.doc.getElementById("toolbox-panel-iframe-" + id);
 
     if (iframe) {
       let panel = this._toolPanels.get(id);
       if (panel) {
         deferred.resolve(panel);
       } else {
         this.once(id + "-ready", (panel) => {
@@ -456,17 +456,17 @@ Toolbox.prototype = {
 
     let vbox = this.doc.getElementById("toolbox-panel-" + id);
     vbox.appendChild(iframe);
 
     let onLoad = () => {
       iframe.removeEventListener("DOMContentLoaded", onLoad, true);
 
       let built = definition.build(iframe.contentWindow, this);
-      Promise.resolve(built).then((panel) => {
+      promise.resolve(built).then((panel) => {
         this._toolPanels.set(id, panel);
         this.emit(id + "-ready", panel);
         gDevTools.emit(id + "-ready", this, panel);
         deferred.resolve(panel);
       });
     };
 
     iframe.addEventListener("DOMContentLoaded", onLoad, true);
@@ -487,17 +487,17 @@ Toolbox.prototype = {
     }
     let tab = this.doc.getElementById("toolbox-tab-" + id);
     tab.setAttribute("selected", "true");
 
     let prevToolId = this._currentToolId;
 
     if (this._currentToolId == id) {
       // Return the existing panel in order to have a consistent return value.
-      return Promise.resolve(this._toolPanels.get(id));
+      return promise.resolve(this._toolPanels.get(id));
     }
 
     if (!this.isReady) {
       throw new Error("Can't select tool, wait for toolbox 'ready' event");
     }
     let tab = this.doc.getElementById("toolbox-tab-" + id);
 
     if (tab) {
@@ -729,17 +729,17 @@ Toolbox.prototype = {
     // If several things call destroy then we give them all the same
     // destruction promise so we're sure to destroy only once
     if (this._destroyer) {
       return this._destroyer;
     }
     // Assign the "_destroyer" property before calling the other
     // destroyer methods to guarantee that the Toolbox's destroy
     // method is only executed once.
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
     this._destroyer = deferred.promise;
 
     this._target.off("navigate", this._refreshHostTitle);
     this.off("select", this._refreshHostTitle);
     this.off("host-changed", this._refreshHostTitle);
 
     gDevTools.off("tool-registered", this._toolRegistered);
     gDevTools.off("tool-unregistered", this._toolUnregistered);
@@ -770,17 +770,17 @@ Toolbox.prototype = {
     // Targets need to be notified that the toolbox is being torn down, so that
     // remote protocol connections can be gracefully terminated.
     if (this._target) {
       this._target.off("close", this.destroy);
       outstanding.push(this._target.destroy());
     }
     this._target = null;
 
-    Promise.all(outstanding).then(function() {
+    promise.all(outstanding).then(function() {
       this.emit("destroyed");
       // Free _host after the call to destroyed in order to let a chance
       // to destroyed listeners to still query toolbox attributes
       this._host = null;
       deferred.resolve();
     }.bind(this));
 
     return this._destroyer;
--- a/browser/devtools/inspector/inspector-panel.js
+++ b/browser/devtools/inspector/inspector-panel.js
@@ -3,17 +3,17 @@
 /* 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, Ci, Cu, Cr} = require("chrome");
 
 Cu.import("resource://gre/modules/Services.jsm");
 
-let Promise = require("sdk/core/promise");
+let promise = require("sdk/core/promise");
 let EventEmitter = require("devtools/shared/event-emitter");
 let {CssLogic} = require("devtools/styleinspector/css-logic");
 
 loader.lazyGetter(this, "MarkupView", () => require("devtools/markupview/markup-view").MarkupView);
 loader.lazyGetter(this, "Selection", () => require("devtools/inspector/selection").Selection);
 loader.lazyGetter(this, "HTMLBreadcrumbs", () => require("devtools/inspector/breadcrumbs").HTMLBreadcrumbs);
 loader.lazyGetter(this, "Highlighter", () => require("devtools/inspector/highlighter").Highlighter);
 loader.lazyGetter(this, "ToolSidebar", () => require("devtools/framework/sidebar").ToolSidebar);
@@ -53,17 +53,17 @@ InspectorPanel.prototype = {
       this.walker = walker;
       return this._getDefaultNodeForSelection();
     }).then(defaultSelection => {
       return this._deferredOpen(defaultSelection);
     }).then(null, console.error);
   },
 
   _deferredOpen: function(defaultSelection) {
-    let deferred = Promise.defer();
+    let deferred = promise.defer();
 
     this.onNavigatedAway = this.onNavigatedAway.bind(this);
     this.target.on("navigate", this.onNavigatedAway);
 
     this.nodemenu = this.panelDoc.getElementById("inspector-node-popup");
     this.lastNodemenuItem = this.nodemenu.lastChild;
     this._setupNodeMenu = this._setupNodeMenu.bind(this);
     this._resetNodeMenu = this._resetNodeMenu.bind(this);
@@ -400,17 +400,17 @@ InspectorPanel.prototype = {
   destroy: function InspectorPanel__destroy() {
     if (this._destroyPromise) {
       return this._destroyPromise;
     }
     if (this.walker) {
       this._destroyPromise = this.walker.release().then(null, console.error);
       delete this.walker;
     } else {
-      this._destroyPromise = Promise.resolve(null);
+      this._destroyPromise = promise.resolve(null);
     }
 
     this.cancelUpdate();
     this.cancelLayoutChange();
 
     if (this.browser) {
       this.browser.removeEventListener("resize", this.scheduleLayoutChange, true);
       this.browser = null;
--- a/browser/devtools/inspector/test/browser_inspector_bug_840156_destroy_after_navigation.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_840156_destroy_after_navigation.js
@@ -1,27 +1,27 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-let Promise = devtools.require("sdk/core/promise");
+let promise = devtools.require("sdk/core/promise");
 let Toolbox = devtools.Toolbox;
 let TargetFactory = devtools.TargetFactory;
 
 function test() {
   waitForExplicitFinish();
 
   const URL_1 = "data:text/plain;charset=UTF-8,abcde";
   const URL_2 = "data:text/plain;charset=UTF-8,12345";
 
   let target, toolbox;
 
   // open tab, load URL_1, and wait for load to finish
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   let target = TargetFactory.forTab(gBrowser.selectedTab);
-  let deferred = Promise.defer();
+  let deferred = promise.defer();
   let browser = gBrowser.getBrowserForTab(tab);
   function onTabLoad() {
     browser.removeEventListener("load", onTabLoad, true);
     deferred.resolve(null);
   }
   browser.addEventListener("load", onTabLoad, true);
   browser.loadURI(URL_1);
 
@@ -30,17 +30,17 @@ function test() {
     .then(function () gDevTools.showToolbox(target, null, Toolbox.HostType.BOTTOM))
     .then(function (aToolbox) { toolbox = aToolbox; })
 
   // select the inspector
     .then(function () toolbox.selectTool("inspector"))
 
   // navigate to URL_2
     .then(function () {
-      let deferred = Promise.defer();
+      let deferred = promise.defer();
       target.once("navigate", function () deferred.resolve());
       browser.loadURI(URL_2);
       return deferred.promise;