Merge inbound to m-c
authorDaniel Holbert <dholbert@cs.stanford.edu>
Thu, 27 Dec 2012 13:53:16 -0800
changeset 126192 65de3fdfe8886222cba0f5a79481aa7d5a547fab
parent 126155 7e2048663a2ef74f107df95f01916c410e2cb3de (current diff)
parent 126191 580018b5f41b78f1fe73bb12f983b5b4bab2101d (diff)
child 126213 23549b4dffb1791a5509ce0b1d927720f08ebb46
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone20.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 inbound to m-c
browser/config/mozconfigs/macosx32/debug
browser/config/tooltool-manifests/macosx32/releng.manifest
build/macosx/mozconfig.leopard
content/html/content/src/nsHTMLHeadingElement.cpp
--- a/accessible/src/base/DocManager.cpp
+++ b/accessible/src/base/DocManager.cpp
@@ -353,17 +353,17 @@ DocManager::CreateDocOrRootAccessible(ns
   // Ignore temporary, hiding, resource documents and documents without
   // docshell.
   if (aDocument->IsInitialDocument() || !aDocument->IsVisible() ||
       aDocument->IsResourceDoc() || !aDocument->IsActive())
     return nullptr;
 
   // Ignore documents without presshell and not having root frame.
   nsIPresShell* presShell = aDocument->GetShell();
-  if (!presShell || !presShell->GetRootFrame() || presShell->IsDestroying())
+  if (!presShell || presShell->IsDestroying())
     return nullptr;
 
   bool isRootDoc = nsCoreUtils::IsRootDocument(aDocument);
 
   DocAccessible* parentDocAcc = nullptr;
   if (!isRootDoc) {
     // XXXaaronl: ideally we would traverse the presshell chain. Since there's
     // no easy way to do that, we cheat and use the document hierarchy.
--- a/accessible/src/base/NotificationController.cpp
+++ b/accessible/src/base/NotificationController.cpp
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "NotificationController.h"
 
 #include "Accessible-inl.h"
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
-#include "DocAccessible.h"
+#include "DocAccessible-inl.h"
 #include "nsEventShell.h"
 #include "FocusManager.h"
 #include "Role.h"
 #include "TextLeafAccessible.h"
 #include "TextUpdater.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
@@ -208,16 +208,20 @@ NotificationController::WillRefresh(mozi
 #endif
 
     mDocument->DoInitialUpdate();
 
     NS_ASSERTION(mContentInsertions.Length() == 0,
                  "Pending content insertions while initial accessible tree isn't created!");
   }
 
+  // Initialize scroll support if needed.
+  if (!(mDocument->mDocFlags & DocAccessible::eScrollInitialized))
+    mDocument->AddScrollListener();
+
   // Process content inserted notifications to update the tree. Process other
   // notifications like DOM events and then flush event queue. If any new
   // notifications are queued during this processing then they will be processed
   // on next refresh. If notification processing queues up new events then they
   // are processed in this refresh. If events processing queues up new events
   // then new events are processed on next refresh.
   // Note: notification processing or event handling may shut down the owning
   // document accessible.
--- a/accessible/src/generic/DocAccessible-inl.h
+++ b/accessible/src/generic/DocAccessible-inl.h
@@ -61,16 +61,43 @@ DocAccessible::UpdateText(nsIContent* aT
   NS_ASSERTION(mNotificationController, "The document was shut down!");
 
   // Ignore the notification if initial tree construction hasn't been done yet.
   if (mNotificationController && HasLoadState(eTreeConstructed))
     mNotificationController->ScheduleTextUpdate(aTextNode);
 }
 
 inline void
+DocAccessible::AddScrollListener()
+{
+  // Delay scroll initializing until the document has a root frame.
+  if (!mPresShell->GetRootFrame())
+    return;
+
+  mDocFlags |= eScrollInitialized;
+  nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollable();
+  if (sf) {
+    sf->AddScrollPositionListener(this);
+
+#ifdef A11Y_LOG
+    if (logging::IsEnabled(logging::eDocCreate))
+      logging::Text("add scroll listener");
+#endif
+  }
+}
+
+inline void
+DocAccessible::RemoveScrollListener()
+{
+  nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollable();
+  if (sf)
+    sf->RemoveScrollPositionListener(this);
+}
+
+inline void
 DocAccessible::NotifyOfLoad(uint32_t aLoadEventType)
 {
   mLoadState |= eDOMLoaded;
   mLoadEventType = aLoadEventType;
 
   // If the document is loaded completely then network activity was presumingly
   // caused by file loading. Fire busy state change event.
   if (HasLoadState(eCompletelyLoaded) && IsLoadEventTarget()) {
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -70,17 +70,17 @@ static const uint32_t kRelationAttrsLen 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/desctructor
 
 DocAccessible::
   DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
                   nsIPresShell* aPresShell) :
   HyperTextAccessibleWrap(aRootContent, this),
   mDocumentNode(aDocument), mScrollPositionChangedTicks(0),
-  mLoadState(eTreeConstructionPending), mLoadEventType(0),
+  mLoadState(eTreeConstructionPending), mDocFlags(0), mLoadEventType(0),
   mVirtualCursor(nullptr),
   mPresShell(aPresShell)
 {
   mGenericTypes |= eDocument;
   mStateFlags |= eNotNodeMapEntry;
 
   MOZ_ASSERT(mPresShell, "should have been given a pres shell");
   mPresShell->SetDocAccessible(this);
@@ -88,28 +88,16 @@ DocAccessible::
   mDependentIDsHash.Init();
   // XXX aaronl should we use an algorithm for the initial cache size?
   mAccessibleCache.Init(kDefaultCacheSize);
   mNodeToAccessibleMap.Init(kDefaultCacheSize);
 
   // If this is a XUL Document, it should not implement nsHyperText
   if (mDocumentNode && mDocumentNode->IsXUL())
     mGenericTypes &= ~eHyperText;
-
-  // For GTK+ native window, we do nothing here.
-  if (!mDocumentNode)
-    return;
-
-  // DocManager creates document accessible when scrollable frame is
-  // available already, it should be safe time to add scroll listener.
-  AddScrollListener();
-
-  // We provide a virtual cursor if this is a root doc or if it's a tab doc.
-  mIsCursorable = (!(mDocumentNode->GetParentDocument()) ||
-                   nsCoreUtils::IsTabDocument(mDocumentNode));
 }
 
 DocAccessible::~DocAccessible()
 {
   NS_ASSERTION(!mPresShell, "LastRelease was never called!?!");
 }
 
 
@@ -140,17 +128,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_INTERFACE_MAP_ENTRY(nsIAccessibleDocument)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsIAccessiblePivotObserver)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessibleDocument)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleCursorable,
-                                     mIsCursorable)
+                                     (mDocFlags & eCursorable))
     foundInterface = 0;
 
   nsresult status;
   if (!foundInterface) {
     // HTML document accessible must inherit from HyperTextAccessible to get
     // support text interfaces. XUL document accessible doesn't need this.
     // However at some point we may push <body> to implement the interfaces and
     // return DocAccessible to inherit from AccessibleWrap.
@@ -497,17 +485,18 @@ NS_IMETHODIMP
 DocAccessible::GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor)
 {
   NS_ENSURE_ARG_POINTER(aVirtualCursor);
   *aVirtualCursor = nullptr;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
-  NS_ENSURE_TRUE(mIsCursorable, NS_ERROR_NOT_IMPLEMENTED);
+  if (!(mDocFlags & eCursorable))
+    return NS_OK;
 
   if (!mVirtualCursor) {
     mVirtualCursor = new nsAccessiblePivot(this);
     mVirtualCursor->AddObserver(this);
   }
 
   NS_ADDREF(*aVirtualCursor = mVirtualCursor);
   return NS_OK;
@@ -793,46 +782,16 @@ DocAccessible::ScrollTimerCallback(nsITi
     if (docAcc->mScrollWatchTimer) {
       docAcc->mScrollWatchTimer->Cancel();
       docAcc->mScrollWatchTimer = nullptr;
       NS_RELEASE(docAcc); // Release kung fu death grip
     }
   }
 }
 
-// DocAccessible protected member
-void
-DocAccessible::AddScrollListener()
-{
-  if (!mPresShell)
-    return;
-
-  nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollableExternal();
-  if (sf) {
-    sf->AddScrollPositionListener(this);
-#ifdef A11Y_LOG
-    if (logging::IsEnabled(logging::eDocCreate))
-      logging::Text("add scroll listener");
-#endif
-  }
-}
-
-// DocAccessible protected member
-void
-DocAccessible::RemoveScrollListener()
-{
-  if (!mPresShell)
-    return;
- 
-  nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollableExternal();
-  if (sf) {
-    sf->RemoveScrollPositionListener(this);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsIScrollPositionListener
 
 void
 DocAccessible::ScrollPositionDidChange(nscoord aX, nscoord aY)
 {
   // Start new timer, if the timer cycles at least 1 full cycle without more scroll position changes,
   // then the ::Notify() method will fire the accessibility event for scroll position changes
@@ -1506,16 +1465,21 @@ DocAccessible::NotifyOfLoading(bool aIsR
   nsRefPtr<AccEvent> stateEvent =
     new AccStateChangeEvent(this, states::BUSY, true);
   FireDelayedEvent(stateEvent);
 }
 
 void
 DocAccessible::DoInitialUpdate()
 {
+  // We provide a virtual cursor if this is a root doc or if it's a tab doc.
+  if (!(mDocumentNode->GetParentDocument()) ||
+      nsCoreUtils::IsTabDocument(mDocumentNode))
+    mDocFlags |= eCursorable;
+
   mLoadState |= eTreeConstructed;
 
   // The content element may be changed before the initial update and then we
   // miss the notification (since content tree change notifications are ignored
   // prior to initial update). Make sure the content element is valid.
   nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode);
   if (mContent != contentElm) {
     mContent = contentElm;
--- a/accessible/src/generic/DocAccessible.h
+++ b/accessible/src/generic/DocAccessible.h
@@ -328,18 +328,21 @@ protected:
   virtual void DoInitialUpdate();
 
   /**
    * Process document load notification, fire document load and state busy
    * events if applicable.
    */
   void ProcessLoad();
 
-    void AddScrollListener();
-    void RemoveScrollListener();
+  /**
+   * Add/remove scroll listeners, @see nsIScrollPositionListener interface.
+   */
+  void AddScrollListener();
+  void RemoveScrollListener();
 
   /**
    * Append the given document accessible to this document's child document
    * accessibles.
    */
   bool AppendChildDocument(DocAccessible* aChildDocument)
   {
     return mChildDocuments.AppendElement(aChildDocument);
@@ -478,30 +481,46 @@ protected:
    * @param aTimer    [in] the timer object
    * @param aClosure  [in] the document accessible where scrolling happens
    */
   static void ScrollTimerCallback(nsITimer* aTimer, void* aClosure);
 
 protected:
 
   /**
+   * State and property flags, kept by mDocFlags.
+   */
+  enum {
+    // Whether scroll listeners were added.
+    eScrollInitialized = 1 << 0,
+
+    // Whether we support nsIAccessibleCursorable.
+    eCursorable = 1 << 1
+  };
+
+  /**
    * Cache of accessibles within this document accessible.
    */
   AccessibleHashtable mAccessibleCache;
   nsDataHashtable<nsPtrHashKey<const nsINode>, Accessible*>
     mNodeToAccessibleMap;
 
     nsCOMPtr<nsIDocument> mDocumentNode;
     nsCOMPtr<nsITimer> mScrollWatchTimer;
     uint16_t mScrollPositionChangedTicks; // Used for tracking scroll events
 
   /**
    * Bit mask of document load states (@see LoadState).
    */
-  uint32_t mLoadState;
+  uint32_t mLoadState : 3;
+
+  /**
+   * Bit mask of other states and props.
+   */
+  uint32_t mDocFlags : 28;
 
   /**
    * Type of document load event fired after the document is loaded completely.
    */
   uint32_t mLoadEventType;
 
   /**
    * Reference to anchor jump element.
@@ -512,21 +531,16 @@ protected:
    * Keep the ARIA attribute old value that is initialized by
    * AttributeWillChange and used by AttributeChanged notifications.
    */
   nsIAtom* mARIAAttrOldValue;
 
   nsTArray<nsRefPtr<DocAccessible> > mChildDocuments;
 
   /**
-   * Whether we support nsIAccessibleCursorable, used when querying the interface.
-   */
-  bool mIsCursorable;
-
-  /**
    * The virtual cursor of the document when it supports nsIAccessibleCursorable.
    */
   nsRefPtr<nsAccessiblePivot> mVirtualCursor;
 
   /**
    * A storage class for pairing content with one of its relation attributes.
    */
   class AttrRelProvider
--- a/accessible/src/jsat/EventManager.jsm
+++ b/accessible/src/jsat/EventManager.jsm
@@ -186,17 +186,17 @@ this.EventManager = {
             text = txtIface.
               getText(0, Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT);
           } catch (x) {
             // XXX we might have gotten an exception with of a
             // zero-length text. If we did, ignore it (bug #749810).
             if (txtIface.characterCount)
               throw x;
           }
-          this.present(Presentation, textChanged(
+          this.present(Presentation.textChanged(
                          isInserted, event.start, event.length,
                          text, event.modifiedText));
         }
         break;
       }
       case Ci.nsIAccessibleEvent.EVENT_FOCUS:
       {
         // Put vc where the focus is at
--- a/accessible/tests/mochitest/states/test_frames.html
+++ b/accessible/tests/mochitest/states/test_frames.html
@@ -27,17 +27,16 @@
       testStates(frameDoc, STATE_READONLY, 0, 0, 0,
                  "test1: frameDoc");
       testStates(frameDocArticle, STATE_READONLY, 0, 0, 0,
                  "test1: frameDocArticle");
       testStates(frameDocCheckbox, 0, 0, STATE_READONLY, 0,
                  "test1: frameDocCheckbox");
       testStates(frameDocTextbox, 0, EXT_STATE_EDITABLE, STATE_READONLY, 0,
                  "test1: frameDocTextbox");
-
       frameDoc.designMode = "on";
       testStates(frameDoc,  0, EXT_STATE_EDITABLE, STATE_READONLY, 0,
                  "test2: frameDoc");
       testStates(frameDocArticle, STATE_READONLY, 0, 0, 0,
                  "test2: frameDocArticle");
       testStates(frameDocCheckbox, 0, 0, STATE_READONLY, 0,
                  "test2: frameDocCheckbox");
       testStates(frameDocTextbox, 0, EXT_STATE_EDITABLE, STATE_READONLY, 0,
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -456,19 +456,16 @@ pref("marionette.defaultPrefs.port", 282
 #ifdef MOZ_UPDATER
 // When we're applying updates, we can't let anything hang us on
 // quit+restart.  The user has no recourse.
 pref("shutdown.watchdog.timeoutSecs", 5);
 // Timeout before the update prompt automatically installs the update
 pref("b2g.update.apply-prompt-timeout", 60000); // milliseconds
 // Amount of time to wait after the user is idle before prompting to apply an update
 pref("b2g.update.apply-idle-timeout", 600000); // milliseconds
-// Amount of time the updater waits for the process to exit cleanly before
-// forcefully exiting the process
-pref("b2g.update.self-destruct-timeout", 5000); // milliseconds
 
 pref("app.update.enabled", true);
 pref("app.update.auto", false);
 pref("app.update.silent", false);
 pref("app.update.mode", 0);
 pref("app.update.incompatible.mode", 0);
 pref("app.update.staging.enabled", true);
 pref("app.update.service.enabled", true);
--- a/b2g/components/UpdatePrompt.js
+++ b/b2g/components/UpdatePrompt.js
@@ -13,24 +13,19 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 
 const VERBOSE = 1;
 let log =
   VERBOSE ?
   function log_dump(msg) { dump("UpdatePrompt: "+ msg +"\n"); } :
   function log_noop(msg) { };
 
-const APPLY_PROMPT_TIMEOUT =
-      Services.prefs.getIntPref("b2g.update.apply-prompt-timeout");
-const APPLY_IDLE_TIMEOUT =
-      Services.prefs.getIntPref("b2g.update.apply-idle-timeout");
-const SELF_DESTRUCT_TIMEOUT =
-      Services.prefs.getIntPref("b2g.update.self-destruct-timeout");
+const PREF_APPLY_PROMPT_TIMEOUT = "b2g.update.apply-prompt-timeout";
+const PREF_APPLY_IDLE_TIMEOUT   = "b2g.update.apply-idle-timeout";
 
-const APPLY_IDLE_TIMEOUT_SECONDS = APPLY_IDLE_TIMEOUT / 1000;
 const NETWORK_ERROR_OFFLINE = 111;
 
 XPCOMUtils.defineLazyServiceGetter(Services, "aus",
                                    "@mozilla.org/updates/update-service;1",
                                    "nsIApplicationUpdateService");
 
 XPCOMUtils.defineLazyServiceGetter(Services, "um",
                                    "@mozilla.org/updates/update-manager;1",
@@ -103,16 +98,24 @@ UpdatePrompt.prototype = {
                                          Ci.nsIObserver]),
   _xpcom_factory: XPCOMUtils.generateSingletonFactory(UpdatePrompt),
 
   _update: null,
   _applyPromptTimer: null,
   _waitingForIdle: false,
   _updateCheckListner: null,
 
+  get applyPromptTimeout() {
+    return Services.prefs.getIntPref(PREF_APPLY_PROMPT_TIMEOUT);
+  },
+
+  get applyIdleTimeout() {
+    return Services.prefs.getIntPref(PREF_APPLY_IDLE_TIMEOUT);
+  },
+
   // nsIUpdatePrompt
 
   // FIXME/bug 737601: we should have users opt-in to downloading
   // updates when on a billed pipe.  Initially, opt-in for 3g, but
   // that doesn't cover all cases.
   checkForUpdates: function UP_checkForUpdates() { },
 
   showUpdateAvailable: function UP_showUpdateAvailable(aUpdate) {
@@ -125,24 +128,25 @@ UpdatePrompt.prototype = {
 
   showUpdateDownloaded: function UP_showUpdateDownloaded(aUpdate, aBackground) {
     // The update has been downloaded and staged. We send the update-downloaded
     // event right away. After the user has been idle for a while, we send the
     // update-prompt-restart event, increasing the chances that we can apply the
     // update quietly without user intervention.
     this.sendUpdateEvent("update-downloaded", aUpdate);
 
-    if (Services.idle.idleTime >= APPLY_IDLE_TIMEOUT) {
+    if (Services.idle.idleTime >= this.applyIdleTimeout) {
       this.showApplyPrompt(aUpdate);
       return;
     }
 
+    let applyIdleTimeoutSeconds = this.applyIdleTimeout / 1000;
     // We haven't been idle long enough, so register an observer
     log("Update is ready to apply, registering idle timeout of " +
-        APPLY_IDLE_TIMEOUT_SECONDS + " seconds before prompting.");
+        applyIdleTimeoutSeconds + " seconds before prompting.");
 
     this._update = aUpdate;
     this.waitForIdle();
   },
 
   showUpdateError: function UP_showUpdateError(aUpdate) {
     log("Update error, state: " + aUpdate.state + ", errorCode: " +
         aUpdate.errorCode);
@@ -160,17 +164,17 @@ UpdatePrompt.prototype = {
   // Custom functions
 
   waitForIdle: function UP_waitForIdle() {
     if (this._waitingForIdle) {
       return;
     }
 
     this._waitingForIdle = true;
-    Services.idle.addIdleObserver(this, APPLY_IDLE_TIMEOUT_SECONDS);
+    Services.idle.addIdleObserver(this, this.applyIdleTimeout / 1000);
     Services.obs.addObserver(this, "quit-application", false);
   },
 
   setUpdateStatus: function UP_setUpdateStatus(aStatus) {
     log("Setting gecko.updateStatus: " + aStatus);
 
     let lock = Services.settings.createLock();
     lock.set("gecko.updateStatus", aStatus, null);
@@ -180,17 +184,17 @@ UpdatePrompt.prototype = {
     if (!this.sendUpdateEvent("update-prompt-apply", aUpdate)) {
       log("Unable to prompt, forcing restart");
       this.restartProcess();
       return;
     }
 
     // Schedule a fallback timeout in case the UI is unable to respond or show
     // a prompt for some reason.
-    this._applyPromptTimer = this.createTimer(APPLY_PROMPT_TIMEOUT);
+    this._applyPromptTimer = this.createTimer(this.applyPromptTimeout);
   },
 
   sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate) {
     let detail = {
       displayVersion: aUpdate.displayVersion,
       detailsURL: aUpdate.detailsURL,
       statusText: aUpdate.statusText,
       state: aUpdate.state,
@@ -424,17 +428,17 @@ UpdatePrompt.prototype = {
 
   observe: function UP_observe(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "idle":
         this._waitingForIdle = false;
         this.showApplyPrompt(this._update);
         // Fall through
       case "quit-application":
-        Services.idle.removeIdleObserver(this, APPLY_IDLE_TIMEOUT_SECONDS);
+        Services.idle.removeIdleObserver(this, this.applyIdleTimeout / 1000);
         Services.obs.removeObserver(this, "quit-application");
         break;
       case "update-check-start":
         this.onUpdateCheckStart();
         break;
     }
   },
 
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -3723,16 +3723,19 @@ let SessionStoreInternal = {
       return;
     }
 
 #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
     // Forget about private windows.
     for (let i = oState.windows.length - 1; i >= 0; i--) {
       if (oState.windows[i].isPrivate) {
         oState.windows.splice(i, 1);
+        if (oState.selectedWindow >= i) {
+          oState.selectedWindow--;
+        }
       }
     }
     for (let i = oState._closedWindows.length - 1; i >= 0; i--) {
       if (oState._closedWindows[i].isPrivate) {
         oState._closedWindows.splice(i, 1);
       }
     }
 #endif
--- a/browser/components/sessionstore/test/Makefile.in
+++ b/browser/components/sessionstore/test/Makefile.in
@@ -136,16 +136,17 @@ MOCHITEST_BROWSER_FILES = \
 	$(filter disabled-for-intermittent-failures--bug-766044, browser_459906_sample.html) \
 	$(filter disabled-for-intermittent-failures--bug-765389, browser_461743_sample.html) \
 	$(NULL)
 
 ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
 MOCHITEST_BROWSER_FILES += \
 	browser_354894_perwindowpb.js \
 	browser_394759_perwindowpb.js \
+	browser_819510_perwindowpb.js \
 	$(NULL)
 else
 MOCHITEST_BROWSER_FILES += \
 	browser_248970_a.js \
 	browser_248970_b.js \
 	browser_248970_b_perwindowpb.js \
 	browser_354894.js \
 	browser_394759_privatebrowsing.js \
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser_819510_perwindowpb.js
@@ -0,0 +1,181 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const originalState = ss.getBrowserState();
+
+/** Private Browsing Test for Bug 819510 **/
+function test() {
+  waitForExplicitFinish();
+
+  registerCleanupFunction(function() {
+    Services.prefs.clearUserPref("browser.sessionstore.interval");
+    ss.setBrowserState(originalState);
+  });
+
+  runNextTest();
+}
+
+let tests = [test_1, test_2, test_3 ];
+
+const testState = {
+  windows: [{
+    tabs: [
+      { entries: [{ url: "about:blank" }] },
+    ]
+  }]
+};
+
+function runNextTest() {
+  // Set an empty state
+  closeAllButPrimaryWindow();
+
+  // Run the next test, or finish
+  if (tests.length) {
+    let currentTest = tests.shift();
+    waitForBrowserState(testState, currentTest);
+  } else {
+    Services.prefs.clearUserPref("browser.sessionstore.interval");
+    ss.setBrowserState(originalState);
+    finish();
+  }
+}
+
+// Test opening default mochitest-normal-private-normal-private windows
+// (saving the state with last window being private)
+function test_1() {
+  testOnWindow(false, function(aWindow) {
+    aWindow.gBrowser.addTab("http://www.example.com/1");
+    testOnWindow(true, function(aWindow) {
+      aWindow.gBrowser.addTab("http://www.example.com/2");
+      testOnWindow(false, function(aWindow) {
+        aWindow.gBrowser.addTab("http://www.example.com/3");
+        testOnWindow(true, function(aWindow) {
+          aWindow.gBrowser.addTab("http://www.example.com/4");
+
+          let curState = JSON.parse(ss.getBrowserState());
+          is (curState.windows.length, 5, "Browser has opened 5 windows");
+          is (curState.windows[2].isPrivate, true, "Window is private");
+          is (curState.windows[4].isPrivate, true, "Last window is private");
+          is (curState.selectedWindow, 5, "Last window opened is the one selected");
+
+          forceWriteState(function(state) {
+            is(state.windows.length, 3,
+               "sessionstore state: 3 windows in data being written to disk");
+            is (state.selectedWindow, 3,
+               "Selected window is updated to match one of the saved windows");
+            state.windows.forEach(function(win) {
+              is(!win.isPrivate, true, "Saved window is not private");
+            });
+            is(state._closedWindows.length, 0,
+               "sessionstore state: no closed windows in data being written to disk");
+            runNextTest();
+          });
+        });
+      });
+    });
+  });
+}
+
+// Test opening default mochitest window + 2 private windows
+function test_2() {
+  testOnWindow(true, function(aWindow) {
+    aWindow.gBrowser.addTab("http://www.example.com/1");
+    testOnWindow(true, function(aWindow) {
+      aWindow.gBrowser.addTab("http://www.example.com/2");
+
+      let curState = JSON.parse(ss.getBrowserState());
+      is (curState.windows.length, 3, "Browser has opened 3 windows");
+      is (curState.windows[1].isPrivate, true, "Window 1 is private");
+      is (curState.windows[2].isPrivate, true, "Window 2 is private");
+      is (curState.selectedWindow, 3, "Last window opened is the one selected");
+
+      forceWriteState(function(state) {
+        is(state.windows.length, 1,
+           "sessionstore state: 1 windows in data being writted to disk");
+        is (state.selectedWindow, 1,
+           "Selected window is updated to match one of the saved windows");
+        is(state._closedWindows.length, 0,
+           "sessionstore state: no closed windows in data being writted to disk");
+        runNextTest();
+      });
+    });
+  });
+}
+
+// Test opening default-normal-private-normal windows and closing a normal window
+function test_3() {
+  testOnWindow(false, function(normalWindow) {
+    let tab = normalWindow.gBrowser.addTab("http://www.example.com/1");
+    whenBrowserLoaded(tab.linkedBrowser, function() {
+      testOnWindow(true, function(aWindow) {
+        aWindow.gBrowser.addTab("http://www.example.com/2");
+        testOnWindow(false, function(aWindow) {
+          aWindow.gBrowser.addTab("http://www.example.com/3");
+
+          let curState = JSON.parse(ss.getBrowserState());
+          is (curState.windows.length, 4, "Browser has opened 4 windows");
+          is (curState.windows[2].isPrivate, true, "Window 2 is private");
+          is (curState.selectedWindow, 4, "Last window opened is the one selected");
+
+          waitForWindowClose(normalWindow, function() {
+            forceWriteState(function(state) {
+              is(state.windows.length, 2,
+                 "sessionstore state: 2 windows in data being writted to disk");
+              is(state.selectedWindow, 2,
+                 "Selected window is updated to match one of the saved windows");
+              state.windows.forEach(function(win) {
+                is(!win.isPrivate, true, "Saved window is not private");
+              });
+              is(state._closedWindows.length, 1,
+                 "sessionstore state: 1 closed window in data being writted to disk");
+              state._closedWindows.forEach(function(win) {
+                is(!win.isPrivate, true, "Closed window is not private");
+              });
+              runNextTest();
+            });
+          });
+        });
+      });
+    });
+  });
+}
+
+function waitForWindowClose(aWin, aCallback) {
+  Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
+    if (aTopic == "domwindowclosed" && aWin == aSubject) {
+      Services.obs.removeObserver(observe, aTopic);
+      checkWindowIsClosed(aWin, aCallback);
+    }
+  }, "domwindowclosed", false);
+  aWin.close();
+}
+
+function checkWindowIsClosed(aWin, aCallback) {
+  if (aWin.closed) {
+    info("Window is closed");
+    executeSoon(aCallback);
+  } else {
+    executeSoon(function() {
+      checkWindowIsClosed(aWin, aCallback);
+    });
+  }
+}
+
+function forceWriteState(aCallback) {
+  Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
+    if (aTopic == "sessionstore-state-write") {
+      Services.obs.removeObserver(observe, aTopic);
+      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});
+  win.addEventListener("load", function onLoad() {
+    win.removeEventListener("load", onLoad, false);
+    executeSoon(function() { aCallback(win); });
+  }, false);
+}
deleted file mode 100644
--- a/browser/config/mozconfigs/macosx32/debug
+++ /dev/null
@@ -1,16 +0,0 @@
-. $topsrcdir/build/macosx/mozconfig.leopard
-
-ac_add_options --enable-debug
-ac_add_options --enable-trace-malloc
-ac_add_options --enable-signmar
-ENABLE_MARIONETTE=1
-
-# Needed to enable breakpad in application.ini
-export MOZILLA_OFFICIAL=1
-
-ac_add_options --with-macbundlename-prefix=Firefox
-
-# Package js shell.
-export MOZ_PACKAGE_JSSHELL=1
-
-. "$topsrcdir/build/mozconfig.common.override"
deleted file mode 100644
--- a/browser/config/tooltool-manifests/macosx32/releng.manifest
+++ /dev/null
@@ -1,17 +0,0 @@
-[
-{
-"clang_version": "r170890"
-},
-{
-"size": 47,
-"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
-"algorithm": "sha512",
-"filename": "setup.sh"
-},
-{
-"size": 56126352,
-"digest": "e156e2a39abd5bf272ee30748a6825f22ddd27565b097c66662a2a6f2e9892bc5b4bf30a3552dffbe867dbfc39e7ee086e0b2cd7935f6ea216c0cf936178a88f",
-"algorithm": "sha512",
-"filename": "clang.tar.bz2"
-}
-]
--- a/browser/themes/gnomestripe/downloads/allDownloadsViewOverlay.css
+++ b/browser/themes/gnomestripe/downloads/allDownloadsViewOverlay.css
@@ -1,13 +1,14 @@
 /* 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/. */
 
 #downloadsRichListBox {
+  /** The default listbox appearance comes with an unwanted margin. **/
   -moz-appearance: none;
   margin: 0;
 }
 
 #downloadsRichListBox > richlistitem.download {
   height: 5em;
   padding: 5px 8px;
 }
--- a/browser/themes/pinstripe/downloads/allDownloadsViewOverlay.css
+++ b/browser/themes/pinstripe/downloads/allDownloadsViewOverlay.css
@@ -1,59 +1,56 @@
-richlistitem.download {
-  height: 7em;
+/* 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/. */
+
+#downloadsRichListBox {
+  /** The default listbox appearance comes with an unwanted margin. **/
+  -moz-appearance: none;
   margin: 0;
-  padding: 8px;
-  -moz-padding-end: 0;
 }
 
-richlistitem.download:first-child {
-  border-top: 1px solid transparent;
-}
-
-richlistitem.download:last-child {
-  border-bottom: 1px solid transparent;
+#downloadsRichListBox > richlistitem.download {
+  height: 6em;
+  padding: 5px 8px;
 }
 
 .downloadTypeIcon {
   -moz-margin-end: 8px;
   /* Prevent flickering when changing states. */
   min-height: 32px;
   min-width: 32px;
 }
 
 .blockedIcon {
   list-style-image: url("chrome://global/skin/icons/Error.png");
 }
 
 .downloadTarget {
-  margin-bottom: 6px;
+  margin-bottom: 3px;
   cursor: inherit;
 }
 
 .downloadDetails {
   opacity: 0.7;
   font-size: 95%;
   cursor: inherit;
 }
 
 .downloadButton {
   -moz-appearance: none;
+  background: transparent;
   min-width: 0;
   min-height: 0;
   margin: 3px;
   border: none;
   padding: 5px;
   list-style-image: url("chrome://browser/skin/downloads/buttons.png");
 }
 
-.downloadButton > .button-box {
-  padding: 0;
-}
-
 /*** Button icons ***/
 
 .downloadButton.downloadCancel {
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 
 .downloadButton.downloadShow {
   -moz-image-region: rect(16px, 16px, 32px, 0px);
--- a/browser/themes/winstripe/downloads/allDownloadsViewOverlay.css
+++ b/browser/themes/winstripe/downloads/allDownloadsViewOverlay.css
@@ -1,13 +1,14 @@
 /* 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/. */
 
 #downloadsRichListBox {
+  /** The default listbox appearance comes with an unwanted margin. **/
   -moz-appearance: none;
   margin: 0;
 }
 
 #downloadsRichListBox > richlistitem.download {
   height: 6em;
 %ifndef WINSTRIPE_AERO
   padding: 5px 8px;
deleted file mode 100644
--- a/build/macosx/mozconfig.leopard
+++ /dev/null
@@ -1,32 +0,0 @@
-. $topsrcdir/build/macosx/mozconfig.common
-
-# Mac builds don't normally have to be handled as cross
-# compilation, but some of the libraries on the bots
-# (IDL for example) are built only for one arch.
-
-HOST_CC=$CC
-HOST_CXX=$CXX
-
-# These must be set for cross builds, and don't hurt straight builds.
-RANLIB=ranlib
-AR=ar
-AS=$CC
-LD=ld
-STRIP="strip"
-
-MOZ_CAN_RUN_PROGRAMS=1
-
-# We do 32 bit builds for leopard
-TARGET_CPU=i386
-CC="$CC -arch $TARGET_CPU"
-CXX="$CXX -arch $TARGET_CPU"
-
-NATIVE_CPU=`$topsrcdir/build/autoconf/config.guess | cut -f1 -d-`
-
-if test "$NATIVE_CPU" != "$TARGET_CPU" ; then
-  CROSS_COMPILE=1
-fi
-
-# Note, the version (10) is used by libffi's configure.
-ac_add_options --target=i386-apple-darwin10
-ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.6.sdk
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -265,16 +265,17 @@ MOCHITEST_FILES_A = \
 		test_bug744830.html \
 		file_bug782342.txt \
 		test_bug782342.html \
 		test_bug282547.html \
 		bug282547.sjs \
 		test_domparser_null_char.html \
 		test_bug811701.html \
 		test_bug811701.xhtml \
+		test_bug820909.html \
 		$(NULL)
 
 MOCHITEST_FILES_B = \
 		test_bug459424.html \
 		bug461735-redirect1.sjs \
 		bug461735-redirect2.sjs \
 		bug461735-post-redirect.js \
 		test_bug513194.html \
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug820909.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=820909
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 820909</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=820909">Mozilla Bug 820909</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  <span dİsabled="CAPS"></span>
+</div>
+<pre id="test">
+<script>
+  var bogusScriptRan = false;
+</script>
+<script type="applİcation/javascript">
+  bogusScriptRan = true;
+</script>
+<script type="application/javascript">
+
+/** Test for Bug 820909 **/
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 1
+ok(!bogusScriptRan, "Script types should be ASCII case-insensitive");
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 2
+var input = document.createElement("input");
+input.type = "radİo";
+is(input.type, "text", "Input types should be ASCII case-insensitive");
+
+// XXX Not sure how to test items 3, 4, 5
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 6
+is(document.querySelector("[dİsabled='caps']"), null,
+   "Checking whether an attribute is case-sensitive for selector-matching " +
+   "purposes should be ASCII case-insensitive on the attr name");
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 7
+$("content").style.width = "0";
+$("content").style.width = "1İn";
+is($("content").style.width, "0px",
+   "CSS unit names should be ASCII case-insensitive");
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 8
+$("content").style.setProperty("animation-name", "a");
+$("content").style.setProperty("-moz-anİmation-name", "b");
+is($("content").style.animationName, "a",
+   "CSS property aliases should be ASCII case-insensitive");
+
+// XXXbz don't know how to test item 9
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 10
+$("content").innerHTML = "<table><input type='hİdden'></table>";
+is($("content").querySelector("input").parentNode, $("content"),
+   "Inputs that aren't actually type='hidden' should not be allowed as " +
+   "table kids");
+
+// XXXbz add test for item 11?
+
+// XXXbz add test for item 12?
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 13
+$("content").style.setProperty("animation-name", "a");
+$("content").style.setProperty("anİmation-name", "b");
+is($("content").style.animationName, "a",
+   "CSS property names should be ASCII case-insensitive");
+
+$("content").style.setProperty("display", "none");
+$("content").style.setProperty("display", "İnline");
+is($("content").style.display, "none",
+   "CSS keywords should be ASCII case-insensitive");
+
+$("content").style.setProperty("color", "white");
+$("content").style.setProperty("color", "İndigo");
+is($("content").style.color, "white",
+   "CSS color names should be ASCII case-insensitive");
+
+
+</script>
+</pre>
+</body>
+</html>
rename from content/html/content/src/nsHTMLHeadingElement.cpp
rename to content/html/content/src/HTMLHeadingElement.cpp
--- a/content/html/content/src/nsHTMLHeadingElement.cpp
+++ b/content/html/content/src/HTMLHeadingElement.cpp
@@ -1,100 +1,61 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/Util.h"
+#include "mozilla/dom/HTMLHeadingElement.h"
+#include "mozilla/dom/HTMLHeadingElementBinding.h"
 
-#include "nsIDOMHTMLHeadingElement.h"
-#include "nsIDOMEventTarget.h"
-#include "nsGenericHTMLElement.h"
+#include "mozilla/Util.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 #include "nsRuleData.h"
 #include "mozAutoDocUpdate.h"
 
-using namespace mozilla;
-using namespace mozilla::dom;
-
-class nsHTMLHeadingElement : public nsGenericHTMLElement,
-                             public nsIDOMHTMLHeadingElement
-{
-public:
-  nsHTMLHeadingElement(already_AddRefed<nsINodeInfo> aNodeInfo);
-  virtual ~nsHTMLHeadingElement();
-
-  // nsISupports
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // nsIDOMNode
-  NS_FORWARD_NSIDOMNODE_TO_NSINODE
-
-  // nsIDOMElement
-  NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
-
-  // nsIDOMHTMLElement
-  NS_FORWARD_NSIDOMHTMLELEMENT_TO_GENERIC
-
-  // nsIDOMHTMLHeadingElement
-  NS_DECL_NSIDOMHTMLHEADINGELEMENT
-
-  virtual bool ParseAttribute(int32_t aNamespaceID,
-                                nsIAtom* aAttribute,
-                                const nsAString& aValue,
-                                nsAttrValue& aResult);
-  NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
-  nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
-  virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
-  virtual nsXPCClassInfo* GetClassInfo();
-  virtual nsIDOMNode* AsDOMNode() { return this; }
-};
-
-
+DOMCI_NODE_DATA(HTMLHeadingElement, mozilla::dom::HTMLHeadingElement)
 NS_IMPL_NS_NEW_HTML_ELEMENT(Heading)
 
+namespace mozilla {
+namespace dom {
 
-nsHTMLHeadingElement::nsHTMLHeadingElement(already_AddRefed<nsINodeInfo> aNodeInfo)
-  : nsGenericHTMLElement(aNodeInfo)
+HTMLHeadingElement::~HTMLHeadingElement()
 {
 }
 
-nsHTMLHeadingElement::~nsHTMLHeadingElement()
-{
-}
-
-
-NS_IMPL_ADDREF_INHERITED(nsHTMLHeadingElement, Element)
-NS_IMPL_RELEASE_INHERITED(nsHTMLHeadingElement, Element)
+NS_IMPL_ADDREF_INHERITED(HTMLHeadingElement, Element)
+NS_IMPL_RELEASE_INHERITED(HTMLHeadingElement, Element)
 
-
-DOMCI_NODE_DATA(HTMLHeadingElement, nsHTMLHeadingElement)
-
-// QueryInterface implementation for nsHTMLHeadingElement
-NS_INTERFACE_TABLE_HEAD(nsHTMLHeadingElement)
-  NS_HTML_CONTENT_INTERFACE_TABLE1(nsHTMLHeadingElement,
+// QueryInterface implementation for HTMLHeadingElement
+NS_INTERFACE_TABLE_HEAD(HTMLHeadingElement)
+  NS_HTML_CONTENT_INTERFACE_TABLE1(HTMLHeadingElement,
                                    nsIDOMHTMLHeadingElement)
-  NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLHeadingElement,
+  NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(HTMLHeadingElement,
                                                nsGenericHTMLElement)
 NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLHeadingElement)
 
 
-NS_IMPL_ELEMENT_CLONE(nsHTMLHeadingElement)
+NS_IMPL_ELEMENT_CLONE(HTMLHeadingElement)
 
+JSObject*
+HTMLHeadingElement::WrapNode(JSContext *aCx, JSObject *aScope, bool *aTriedToWrap)
+{
+  return HTMLHeadingElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
 
-NS_IMPL_STRING_ATTR(nsHTMLHeadingElement, Align, align)
+NS_IMPL_STRING_ATTR(HTMLHeadingElement, Align, align)
 
 
 bool
-nsHTMLHeadingElement::ParseAttribute(int32_t aNamespaceID,
-                                     nsIAtom* aAttribute,
-                                     const nsAString& aValue,
-                                     nsAttrValue& aResult)
+HTMLHeadingElement::ParseAttribute(int32_t aNamespaceID,
+                                   nsIAtom* aAttribute,
+                                   const nsAString& aValue,
+                                   nsAttrValue& aResult)
 {
   if (aAttribute == nsGkAtoms::align && aNamespaceID == kNameSpaceID_None) {
     return ParseDivAlignValue(aValue, aResult);
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
@@ -102,24 +63,27 @@ nsHTMLHeadingElement::ParseAttribute(int
 static void
 MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData)
 {
   nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
 NS_IMETHODIMP_(bool)
-nsHTMLHeadingElement::IsAttributeMapped(const nsIAtom* aAttribute) const
+HTMLHeadingElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
   static const MappedAttributeEntry* const map[] = {
     sDivAlignAttributeMap,
     sCommonAttributeMap
   };
 
   return FindAttributeDependence(aAttribute, map);
 }
 
 
 nsMapRuleToAttributesFunc
-nsHTMLHeadingElement::GetAttributeMappingFunction() const
+HTMLHeadingElement::GetAttributeMappingFunction() const
 {
   return &MapAttributesIntoRule;
 }
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/html/content/src/HTMLHeadingElement.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_HTMLHeadingElement_h
+#define mozilla_dom_HTMLHeadingElement_h
+
+#include "nsIDOMHTMLHeadingElement.h"
+#include "nsGenericHTMLElement.h"
+
+namespace mozilla {
+namespace dom {
+
+class HTMLHeadingElement MOZ_FINAL : public nsGenericHTMLElement,
+				     public nsIDOMHTMLHeadingElement
+{
+public:
+  HTMLHeadingElement(already_AddRefed<nsINodeInfo> aNodeInfo)
+    : nsGenericHTMLElement(aNodeInfo)
+  {
+    SetIsDOMBinding();
+  }
+  virtual ~HTMLHeadingElement();
+
+  // nsISupports
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIDOMNode
+  NS_FORWARD_NSIDOMNODE_TO_NSINODE
+
+  // nsIDOMElement
+  NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
+
+  // nsIDOMHTMLElement
+  NS_FORWARD_NSIDOMHTMLELEMENT_TO_GENERIC
+
+  // nsIDOMHTMLHeadingElement
+  NS_DECL_NSIDOMHTMLHEADINGELEMENT
+
+  virtual bool ParseAttribute(int32_t aNamespaceID,
+                              nsIAtom* aAttribute,
+                              const nsAString& aValue,
+                              nsAttrValue& aResult);
+  NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
+  nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
+  virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
+  virtual nsXPCClassInfo* GetClassInfo();
+  virtual nsIDOMNode* AsDOMNode() { return this; }
+
+  // The XPCOM versions of GetAlign and SetAlign are fine for us for
+  // use from WebIDL.
+
+protected:
+  virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
+                             bool *aTriedToWrap) MOZ_OVERRIDE;
+};
+
+} // namespace mozilla
+} // namespace dom
+
+#endif // mozilla_dom_HTMLHeadingElement_h
--- a/content/html/content/src/Makefile.in
+++ b/content/html/content/src/Makefile.in
@@ -28,16 +28,17 @@ EXPORTS		= \
 EXPORTS_NAMESPACES = mozilla/dom
 
 EXPORTS_mozilla/dom = \
 		HTMLBodyElement.h \
 		HTMLDataListElement.h \
 		HTMLDivElement.h \
 		HTMLFontElement.h \
 		HTMLFrameSetElement.h \
+		HTMLHeadingElement.h \
 		HTMLLabelElement.h \
 		HTMLUnknownElement.h
 
 CPPSRCS		= \
 		HTMLPropertiesCollection.cpp \
 		nsClientRect.cpp \
 		nsHTMLDNSPrefetch.cpp \
 		nsGenericHTMLElement.cpp \
@@ -54,17 +55,17 @@ CPPSRCS		= \
 		HTMLDataListElement.cpp \
 		HTMLDivElement.cpp \
 		nsHTMLFieldSetElement.cpp \
 		HTMLFontElement.cpp \
 		nsHTMLFormElement.cpp \
 		nsHTMLFrameElement.cpp \
 		HTMLFrameSetElement.cpp \
 		nsHTMLHRElement.cpp \
-		nsHTMLHeadingElement.cpp \
+		HTMLHeadingElement.cpp \
 		nsHTMLIFrameElement.cpp \
 		nsHTMLImageElement.cpp \
 		nsHTMLInputElement.cpp \
 		nsHTMLLIElement.cpp \
 		HTMLLabelElement.cpp \
 		nsHTMLLegendElement.cpp \
 		nsHTMLLinkElement.cpp \
 		nsHTMLMapElement.cpp \
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -491,16 +491,17 @@ using mozilla::dom::indexedDB::IDBWrappe
 
 #include "nsIDOMNavigatorSystemMessages.h"
 #include "DOMCameraManager.h"
 #include "DOMCameraControl.h"
 #include "DOMCameraCapabilities.h"
 #include "DOMError.h"
 #include "DOMRequest.h"
 #include "nsIOpenWindowEventDetail.h"
+#include "nsIAsyncScrollEventDetail.h"
 #include "nsIDOMGlobalObjectConstructor.h"
 #include "nsIDOMCanvasRenderingContext2D.h"
 #include "DOMFileHandle.h"
 #include "FileRequest.h"
 #include "LockedFile.h"
 #include "GeneratedEvents.h"
 #include "nsDebug.h"
 
@@ -1539,16 +1540,18 @@ static nsDOMClassInfoData sClassInfoData
 
   NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DOMRequest, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(OpenWindowEventDetail, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(AsyncScrollEventDetail, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA_WITH_NAME(DOMFileHandle, FileHandle, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(FileRequest, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(LockedFile, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
 #ifdef MOZ_SYS_MSG
@@ -4011,16 +4014,20 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(OpenWindowEventDetail, nsIOpenWindowEventDetail)
     DOM_CLASSINFO_MAP_ENTRY(nsIOpenWindowEventDetail)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(AsyncScrollEventDetail, nsIAsyncScrollEventDetail)
+    DOM_CLASSINFO_MAP_ENTRY(nsIAsyncScrollEventDetail)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(DOMFileHandle, nsIDOMFileHandle)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMFileHandle)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(FileRequest, nsIDOMFileRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMFileRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -448,16 +448,17 @@ DOMCI_CLASS(BluetoothPropertyEvent)
 
 DOMCI_CLASS(CameraManager)
 DOMCI_CLASS(CameraControl)
 DOMCI_CLASS(CameraCapabilities)
 
 DOMCI_CLASS(DOMError)
 DOMCI_CLASS(DOMRequest)
 DOMCI_CLASS(OpenWindowEventDetail)
+DOMCI_CLASS(AsyncScrollEventDetail)
 
 DOMCI_CLASS(DOMFileHandle)
 DOMCI_CLASS(FileRequest)
 DOMCI_CLASS(LockedFile)
 
 #ifdef MOZ_SYS_MSG
 DOMCI_CLASS(MozActivity)
 #endif
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -297,16 +297,19 @@ DOMInterfaces = {
 'HTMLDataListElement': {
     'resultNotAddRefed': [
         'options'
     ]
 },
 
 'HTMLDocument': {
     'nativeType': 'nsHTMLDocument',
+    'register': False,
+    'hasXPConnectImpls': True,
+    'hasInstanceInterface': 'nsIDOMHTMLDocument',
     'resultNotAddRefed': [ 'body', 'head', 'images', 'embeds', 'plugins',
                            'links', 'forms', 'scripts', 'anchors', 'applets' ],
     'implicitJSContext': [ 'open', 'write', 'writeln' ]
 },
 
 'HTMLElement': {
     'nativeType': 'nsGenericHTMLElement',
     'hasXPConnectImpls': True,
--- a/dom/bluetooth/BluetoothUtils.cpp
+++ b/dom/bluetooth/BluetoothUtils.cpp
@@ -22,19 +22,19 @@ bool
 SetJsObject(JSContext* aContext,
             JSObject* aObj,
             const InfallibleTArray<BluetoothNamedValue>& aData)
 {
   for (uint32_t i = 0; i < aData.Length(); i++) {
     jsval v;
     if (aData[i].value().type() == BluetoothValue::TnsString) {
       nsString data = aData[i].value().get_nsString();
-      JSString* JsData = JS_NewStringCopyN(aContext,
-                                           NS_ConvertUTF16toUTF8(data).get(),
-                                           data.Length());
+      JSString* JsData = JS_NewUCStringCopyN(aContext,
+                                             data.BeginReading(),
+                                             data.Length());
       NS_ENSURE_TRUE(JsData, false);
       v = STRING_TO_JSVAL(JsData);
     } else if (aData[i].value().type() == BluetoothValue::Tuint32_t) {
       int data = aData[i].value().get_uint32_t();
       v = INT_TO_JSVAL(data);
     } else if (aData[i].value().type() == BluetoothValue::Tbool) {
       bool data = aData[i].value().get_bool();
       v = BOOLEAN_TO_JSVAL(data);
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -14,16 +14,17 @@
 
 #include "BrowserElementParent.h"
 #include "nsHTMLIFrameElement.h"
 #include "nsOpenWindowEventDetail.h"
 #include "nsEventDispatcher.h"
 #include "nsIDOMCustomEvent.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsVariant.h"
+#include "nsAsyncScrollEventDetail.h"
 
 using mozilla::dom::Element;
 using mozilla::dom::TabParent;
 
 namespace {
 
 /**
  * Create an <iframe mozbrowser> owned by the same document as
@@ -63,16 +64,50 @@ CreateIframe(Element* aOpenerFrameElemen
   popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::Remote,
                              aRemote ? NS_LITERAL_STRING("true") :
                                        NS_LITERAL_STRING("false"),
                              /* aNotify = */ false);
 
   return popupFrameElement.forget();
 }
 
+bool
+DispatchCustomDOMEvent(Element* aFrameElement, const nsAString& aEventName,
+                       nsISupports *aDetailValue)
+{
+  NS_ENSURE_TRUE(aFrameElement, false);
+  nsIPresShell *shell = aFrameElement->OwnerDoc()->GetShell();
+  nsRefPtr<nsPresContext> presContext;
+  if (shell) {
+    presContext = shell->GetPresContext();
+  }
+
+  nsCOMPtr<nsIDOMEvent> domEvent;
+  nsEventDispatcher::CreateEvent(presContext, nullptr,
+                                 NS_LITERAL_STRING("customevent"),
+                                 getter_AddRefs(domEvent));
+  NS_ENSURE_TRUE(domEvent, false);
+
+  nsCOMPtr<nsIWritableVariant> detailVariant = new nsVariant();
+  nsresult rv = detailVariant->SetAsISupports(aDetailValue);
+  NS_ENSURE_SUCCESS(rv, false);
+  nsCOMPtr<nsIDOMCustomEvent> customEvent = do_QueryInterface(domEvent);
+  NS_ENSURE_TRUE(customEvent, false);
+  customEvent->InitCustomEvent(aEventName,
+                               /* bubbles = */ true,
+                               /* cancelable = */ false,
+                               detailVariant);
+  customEvent->SetTrusted(true);
+  // Dispatch the event.
+  nsEventStatus status = nsEventStatus_eIgnore;
+  rv = nsEventDispatcher::DispatchDOMEvent(aFrameElement, nullptr,
+                                           domEvent, presContext, &status);
+  return NS_SUCCEEDED(rv);
+}
+
 /**
  * Dispatch a mozbrowseropenwindow event to the given opener frame element.
  * The "popup iframe" (event.detail.frameElement) will be |aPopupFrameElement|.
  *
  * Returns true iff there were no unexpected failures and the window.open call
  * was accepted by the embedder.
  */
 bool
@@ -85,59 +120,34 @@ DispatchOpenWindowEvent(Element* aOpener
   // Dispatch a CustomEvent at aOpenerFrameElement with a detail object
   // (nsIOpenWindowEventDetail) containing aPopupFrameElement, aURL, aName, and
   // aFeatures.
 
   // Create the event's detail object.
   nsRefPtr<nsOpenWindowEventDetail> detail =
     new nsOpenWindowEventDetail(aURL, aName, aFeatures,
                                 aPopupFrameElement->AsDOMNode());
-  nsCOMPtr<nsIWritableVariant> detailVariant = new nsVariant();
-  nsresult rv = detailVariant->SetAsISupports(detail);
-  NS_ENSURE_SUCCESS(rv, false);
 
-  // Create the CustomEvent.
-  nsIPresShell *shell = aOpenerFrameElement->OwnerDoc()->GetShell();
-  nsRefPtr<nsPresContext> presContext;
-  if (shell) {
-    presContext = shell->GetPresContext();
-  }
-
-  nsCOMPtr<nsIDOMEvent> domEvent;
-  nsEventDispatcher::CreateEvent(presContext, nullptr,
-                                 NS_LITERAL_STRING("customevent"),
-                                 getter_AddRefs(domEvent));
-  NS_ENSURE_TRUE(domEvent, false);
-
-  nsCOMPtr<nsIDOMCustomEvent> customEvent = do_QueryInterface(domEvent);
-  NS_ENSURE_TRUE(customEvent, false);
-  customEvent->InitCustomEvent(NS_LITERAL_STRING("mozbrowseropenwindow"),
-                               /* bubbles = */ true,
-                               /* cancelable = */ false,
-                               detailVariant);
-  customEvent->SetTrusted(true);
-
-  // Dispatch the event.
-  nsEventStatus status = nsEventStatus_eIgnore;
-  rv = nsEventDispatcher::DispatchDOMEvent(aOpenerFrameElement, nullptr,
-                                           domEvent, presContext, &status);
-  NS_ENSURE_SUCCESS(rv, false);
+  bool dispatchSucceeded =
+    DispatchCustomDOMEvent(aOpenerFrameElement,
+                           NS_LITERAL_STRING("mozbrowseropenwindow"),
+                           detail);
 
   // If the iframe is not in some document's DOM at this point, the embedder
   // has "blocked" the popup.
-  return aPopupFrameElement->IsInDoc();
+  return (dispatchSucceeded && aPopupFrameElement->IsInDoc());
 }
 
 } // anonymous namespace
 
 namespace mozilla {
 
 /*static*/ bool
-BrowserElementParent::OpenWindowOOP(mozilla::dom::TabParent* aOpenerTabParent,
-                                    mozilla::dom::TabParent* aPopupTabParent,
+BrowserElementParent::OpenWindowOOP(TabParent* aOpenerTabParent,
+                                    TabParent* aPopupTabParent,
                                     const nsAString& aURL,
                                     const nsAString& aName,
                                     const nsAString& aFeatures)
 {
   // Create an iframe owned by the same document which owns openerFrameElement.
   nsCOMPtr<Element> openerFrameElement =
     do_QueryInterface(aOpenerTabParent->GetOwnerElement());
   NS_ENSURE_TRUE(openerFrameElement, false);
@@ -225,9 +235,26 @@ BrowserElementParent::OpenWindowInProces
   frameLoader->GetDocShell(getter_AddRefs(docshell));
   NS_ENSURE_TRUE(docshell, false);
 
   nsCOMPtr<nsIDOMWindow> window = do_GetInterface(docshell);
   window.forget(aReturnWindow);
   return !!*aReturnWindow;
 }
 
+bool
+BrowserElementParent::DispatchAsyncScrollEvent(TabParent* aTabParent,
+                                               const gfx::Rect& aContentRect,
+                                               const gfx::Size& aContentSize)
+{
+  nsIDOMElement* element = aTabParent->GetOwnerElement();
+  nsCOMPtr<Element> frameElement = do_QueryInterface(element);
+  // Create the event's detail object.
+  nsRefPtr<nsAsyncScrollEventDetail> detail =
+    new nsAsyncScrollEventDetail(aContentRect.x, aContentRect.y,
+                                 aContentRect.width, aContentRect.height,
+                                 aContentSize.width, aContentSize.height);
+  return DispatchCustomDOMEvent(frameElement,
+                                NS_LITERAL_STRING("mozbrowserasyncscroll"),
+                                detail);
+}
+
 } // namespace mozilla
--- a/dom/browser-element/BrowserElementParent.h
+++ b/dom/browser-element/BrowserElementParent.h
@@ -11,16 +11,21 @@ class nsIDOMWindow;
 class nsIURI;
 
 namespace mozilla {
 
 namespace dom {
 class TabParent;
 }
 
+namespace gfx{
+struct Rect;
+struct Size;
+}
+
 /**
  * BrowserElementParent implements a portion of the parent-process side of
  * <iframe mozbrowser>.
  *
  * Most of the parent-process side of <iframe mozbrowser> is implemented in
  * BrowserElementParent.js.  This file implements the few parts of this
  * functionality which must be written in C++.
  *
@@ -58,18 +63,18 @@ public:
    * @param aOpenerTabParent the TabParent whose TabChild called window.open.
    * @param aPopupTabParent the TabParent inside which the opened window will
    *                        live.
    * @return true on success, false otherwise.  Failure is not (necessarily)
    *         an error; it may indicate that the embedder simply rejected the
    *         window.open request.
    */
   static bool
-  OpenWindowOOP(mozilla::dom::TabParent* aOpenerTabParent,
-                mozilla::dom::TabParent* aPopupTabParent,
+  OpenWindowOOP(dom::TabParent* aOpenerTabParent,
+                dom::TabParent* aPopupTabParent,
                 const nsAString& aURL,
                 const nsAString& aName,
                 const nsAString& aFeatures);
 
   /**
    * Handle a window.open call from an in-process <iframe mozbrowser>.
    *
    * As with OpenWindowOOP, we return true if the window.open request
@@ -81,13 +86,33 @@ public:
    * @param aURI the URI the new window should load.  May be null.
    */
   static bool
   OpenWindowInProcess(nsIDOMWindow* aOpenerWindow,
                       nsIURI* aURI,
                       const nsAString& aName,
                       const nsACString& aFeatures,
                       nsIDOMWindow** aReturnWindow);
+
+  /**
+   * Fire a mozbrowserasyncscroll CustomEvent on the given TabParent's frame element.
+   * This event's detail is an instance of nsIAsyncScrollEventDetail.
+   *
+   * @param aContentRect: The portion of the page which is currently visible
+   *                      onscreen in CSS pixels.
+   *
+   * @param aContentSize: The content width/height in CSS pixels.
+   *
+   * aContentRect.top + aContentRect.height may be larger than aContentSize.height.
+   * This indicates that the content is over-scrolled, which occurs when the
+   * page "rubber-bands" after being scrolled all the way to the bottom.
+   * Similarly, aContentRect.left + aContentRect.width may be greater than
+   * contentSize.width, and both left and top may be negative.
+   */
+  static bool
+  DispatchAsyncScrollEvent(dom::TabParent* aTabParent,
+                           const gfx::Rect& aContentRect,
+                           const gfx::Size& aContentSize);
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/browser-element/BrowserElementScrolling.js
+++ b/dom/browser-element/BrowserElementScrolling.js
@@ -1,8 +1,11 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 sts=2 et: */
+
 /* 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 ContentPanning = {
   init: function cp_init() {
     ['mousedown', 'mouseup', 'mousemove'].forEach(function(type) {
       addEventListener(type, ContentPanning, false);
@@ -179,30 +182,51 @@ const ContentPanning = {
     return null;
   },
 
   _generateCallback: function cp_generateCallback(content) {
     let firstScroll = true;
     let target;
     let isScrolling = false;
     let oldX, oldY, newX, newY;
+    let win, doc, htmlNode, bodyNode;
 
     function doScroll(node, delta) {
       if (node instanceof Ci.nsIDOMHTMLElement) {
         oldX = node.scrollLeft, oldY = node.scrollTop;
         node.scrollLeft += delta.x;
         node.scrollTop += delta.y;
         newX = node.scrollLeft, newY = node.scrollTop;
         return (newX != oldX || newY != oldY);
-      } else {
+      } else if (node instanceof Ci.nsIDOMWindow) {
+        win = node;
+        doc = win.document;
+
+        // "overflow:hidden" on either the <html> or the <body> node should
+        // prevent the user from scrolling the root viewport.
+        if (doc instanceof Ci.nsIDOMHTMLDocument) {
+          htmlNode = doc.documentElement;
+          bodyNode = doc.body;
+          if (win.getComputedStyle(htmlNode, null).overflowX == "hidden" ||
+              win.getComputedStyle(bodyNode, null).overflowX == "hidden") {
+            delta.x = 0;
+          }
+          if (win.getComputedStyle(htmlNode, null).overflowY == "hidden" ||
+              win.getComputedStyle(bodyNode, null).overflowY == "hidden") {
+            delta.y = 0;
+          }
+        }
         oldX = node.scrollX, oldY = node.scrollY;
         node.scrollBy(delta.x, delta.y);
         newX = node.scrollX, newY = node.scrollY;
         return (newX != oldX || newY != oldY);
       }
+      // If we get here, |node| isn't an HTML element and it's not a window,
+      // but findPannable apparently thought it was scrollable... What is it?
+      return false;
     };
 
     function scroll(delta) {
       for (target = content; target;
           target = ContentPanning._findPannable(target.parentNode)) {
         isScrolling = doScroll(target, delta);
         if (isScrolling || !firstScroll) {
           break;
--- a/dom/browser-element/Makefile.in
+++ b/dom/browser-element/Makefile.in
@@ -17,29 +17,32 @@ FORCE_STATIC_LIB = 1
 FAIL_ON_WARNINGS := 1
 
 include $(topsrcdir)/dom/dom-config.mk
 
 TEST_DIRS += mochitest
 
 XPIDLSRCS = \
   nsIOpenWindowEventDetail.idl \
+  nsIAsyncScrollEventDetail.idl \
   $(NULL)
 
 EXPORTS = \
   nsOpenWindowEventDetail.h \
+  nsAsyncScrollEventDetail.h \
   $(NULL)
 
 EXPORTS_NAMESPACES = mozilla
 EXPORTS_mozilla = \
   BrowserElementParent.h \
   $(NULL)
 
 CPPSRCS = \
   nsOpenWindowEventDetail.cpp \
+  nsAsyncScrollEventDetail.cpp \
   BrowserElementParent.cpp \
   $(NULL)
 
 EXTRA_COMPONENTS = \
   BrowserElementParent.js \
   BrowserElementParent.manifest \
   $(NULL)
 
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/nsAsyncScrollEventDetail.cpp
@@ -0,0 +1,62 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsAsyncScrollEventDetail.h"
+#include "nsDOMClassInfoID.h"
+#include "nsIDOMClassInfo.h"
+#include "nsIClassInfo.h"
+#include "nsDOMClassInfo.h"
+
+NS_IMPL_ADDREF(nsAsyncScrollEventDetail)
+NS_IMPL_RELEASE(nsAsyncScrollEventDetail)
+NS_INTERFACE_MAP_BEGIN(nsAsyncScrollEventDetail)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIAsyncScrollEventDetail)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(AsyncScrollEventDetail)
+NS_INTERFACE_MAP_END
+
+DOMCI_DATA(AsyncScrollEventDetail, nsAsyncScrollEventDetail)
+
+/* readonly attribute float top; */
+NS_IMETHODIMP nsAsyncScrollEventDetail::GetTop(float *aTop)
+{
+  *aTop = mTop;
+  return NS_OK;
+}
+
+/* readonly attribute float left; */
+NS_IMETHODIMP nsAsyncScrollEventDetail::GetLeft(float *aLeft)
+{
+  *aLeft = mLeft;
+  return NS_OK;
+}
+
+/* readonly attribute float width; */
+NS_IMETHODIMP nsAsyncScrollEventDetail::GetWidth(float *aWidth)
+{
+  *aWidth = mWidth;
+  return NS_OK;
+}
+
+/* readonly attribute float height; */
+NS_IMETHODIMP nsAsyncScrollEventDetail::GetHeight(float *aHeight)
+{
+  *aHeight = mHeight;
+  return NS_OK;
+}
+
+/* readonly attribute float scrollWidth; */
+NS_IMETHODIMP nsAsyncScrollEventDetail::GetScrollWidth(float *aScrollWidth)
+{
+  *aScrollWidth = mScrollWidth;
+  return NS_OK;
+}
+
+/* readonly attribute float scrollHeight; */
+NS_IMETHODIMP nsAsyncScrollEventDetail::GetScrollHeight(float *aScrollHeight)
+{
+  *aScrollHeight = mScrollHeight;
+  return NS_OK;
+}
+
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/nsAsyncScrollEventDetail.h
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIAsyncScrollEventDetail.h"
+
+/**
+ * When we send a mozbrowserasyncscroll event (an instance of CustomEvent), we
+ * use an instance of this class as the event's detail.
+ */
+class nsAsyncScrollEventDetail : public nsIAsyncScrollEventDetail
+{
+public:
+  nsAsyncScrollEventDetail(const float left, const float top,
+                           const float width, const float height,
+                           const float contentWidth, const float contentHeigh)
+    : mTop(top)
+    , mLeft(left)
+    , mWidth(width)
+    , mHeight(height)
+    , mScrollWidth(contentWidth)
+    , mScrollHeight(contentHeigh)
+  {}
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIASYNCSCROLLEVENTDETAIL
+
+private:
+  virtual ~nsAsyncScrollEventDetail() {}
+  const float mTop;
+  const float mLeft;
+  const float mWidth;
+  const float mHeight;
+  const float mScrollWidth;
+  const float mScrollHeight;
+};
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/nsIAsyncScrollEventDetail.idl
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+/**
+ * When we send a mozbrowserasyncscroll event (an instance of CustomEvent), we
+ * use an instance of this interface as the event's detail.
+ * [left, top, width, height]: The portion of the page which is currently 
+ * visible onscreen in CSS pixels.
+ * [scrollWidth, scrollHeight]: The content width/height in CSS pixels.
+ *
+ * top + height may be larger than scrollHeight.
+ * This indicates that the content is over-scrolled, which occurs when the
+ * page "rubber-bands" after being scrolled all the way to the bottom.
+ * Similarly, left + width may be greater than scrollWidth, 
+ * and both left and top may be negative.
+ */
+[scriptable, uuid(d0c13577-31e6-4701-b9b7-3535bbe19fe6)]
+interface nsIAsyncScrollEventDetail : nsISupports
+{
+  readonly attribute float top;
+  readonly attribute float left;
+  readonly attribute float width;
+  readonly attribute float height;
+  readonly attribute float scrollWidth;
+  readonly attribute float scrollHeight;
+};
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -644,18 +644,20 @@ ContentParent::ActorDestroy(ActorDestroy
         if (AbnormalShutdown == why) {
             props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true);
 
 #ifdef MOZ_CRASHREPORTER
             MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0);
             CrashReporterParent* crashReporter =
                     static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
 
+            crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("AppManifestURL"),
+                                               NS_ConvertUTF16toUTF8(mAppManifestURL));
             crashReporter->GenerateCrashReport(this, NULL);
- 
+
             nsAutoString dumpID(crashReporter->ChildDumpID());
             props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID);
 #endif
         }
         obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr);
     }
 
     MessageLoop::current()->
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -131,18 +131,18 @@ MobileICCInfo.prototype = {
   iccid: null,
   mcc: 0,
   lastKnownMcc: 0,
   mnc: 0,
   spn: null,
   msisdn: null
 };
 
-function MobileVoicemailInfo() {}
-MobileVoicemailInfo.prototype = {
+function VoicemailInfo() {}
+VoicemailInfo.prototype = {
   number: null,
   displayName: null
 };
 
 function MobileConnectionInfo() {}
 MobileConnectionInfo.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileConnectionInfo]),
   classID:        MOBILECONNECTIONINFO_CID,
@@ -314,34 +314,33 @@ CellBroadcastEtwsInfo.prototype = {
   emergencyUserAlert: null,
   popup: null
 };
 
 function RILContentHelper() {
   this.iccInfo = new MobileICCInfo();
   this.voiceConnectionInfo = new MobileConnectionInfo();
   this.dataConnectionInfo = new MobileConnectionInfo();
-  this.voicemailInfo = new MobileVoicemailInfo();
+  this.voicemailInfo = new VoicemailInfo();
 
   this.initRequests();
   this.initMessageListener(RIL_IPC_MSG_NAMES);
   Services.obs.addObserver(this, "xpcom-shutdown", false);
 
   // Request initial context.
   let rilContext = cpmm.sendSyncMessage("RIL:GetRilContext")[0];
 
   if (!rilContext) {
     debug("Received null rilContext from chrome process.");
     return;
   }
   this.cardState = rilContext.cardState;
   this.updateICCInfo(rilContext.icc, this.iccInfo);
   this.updateConnectionInfo(rilContext.voice, this.voiceConnectionInfo);
   this.updateConnectionInfo(rilContext.data, this.dataConnectionInfo);
-  this.updateVoicemailInfo(rilContext.voicemail, this.voicemailInfo);
 }
 
 RILContentHelper.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionProvider,
                                          Ci.nsIRILContentHelper,
                                          Ci.nsIObserver]),
@@ -646,21 +645,35 @@ RILContentHelper.prototype = {
     return request;
   },
 
   _telephonyCallbacks: null,
   _voicemailCallbacks: null,
   _enumerateTelephonyCallbacks: null,
 
   voicemailStatus: null,
+
+  getVoicemailInfo: function getVoicemailInfo() {
+    // Get voicemail infomation by IPC only on first time.
+    this.getVoicemailInfo = function getVoicemailInfo() {
+      return this.voicemailInfo;
+    };
+
+    let voicemailInfo = cpmm.sendSyncMessage("RIL:GetVoicemailInfo")[0];
+    if (voicemailInfo) {
+      this.updateVoicemailInfo(voicemailInfo, this.voicemailInfo);
+    }
+
+    return this.voicemailInfo;
+  },
   get voicemailNumber() {
-    return this.voicemailInfo.number;
+    return this.getVoicemailInfo().number;
   },
   get voicemailDisplayName() {
-    return this.voicemailInfo.displayName;
+    return this.getVoicemailInfo().displayName;
   },
 
   registerCallback: function registerCallback(callbackType, callback) {
     let callbacks = this[callbackType];
     if (!callbacks) {
       callbacks = this[callbackType] = [];
     }
 
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -94,17 +94,18 @@ const RIL_IPC_MOBILECONNECTION_MSG_NAMES
   "RIL:SendStkTimerExpiration",
   "RIL:SendStkEventDownload",
   "RIL:RegisterMobileConnectionMsg",
   "RIL:SetCallForwardingOption",
   "RIL:GetCallForwardingOption"
 ];
 
 const RIL_IPC_VOICEMAIL_MSG_NAMES = [
-  "RIL:RegisterVoicemailMsg"
+  "RIL:RegisterVoicemailMsg",
+  "RIL:GetVoicemailInfo"
 ];
 
 const RIL_IPC_CELLBROADCAST_MSG_NAMES = [
   "RIL:RegisterCellBroadcastMsg"
 ];
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
                                    "@mozilla.org/sms/smsservice;1",
@@ -199,18 +200,16 @@ function RadioInterfaceLayer() {
   this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
   this.worker.onerror = this.onerror.bind(this);
   this.worker.onmessage = this.onmessage.bind(this);
 
   this.rilContext = {
     radioState:     RIL.GECKO_RADIOSTATE_UNAVAILABLE,
     cardState:      RIL.GECKO_CARDSTATE_UNAVAILABLE,
     icc:            null,
-    voicemail:      {number: null,
-                     displayName: null},
 
     // These objects implement the nsIDOMMozMobileConnectionInfo interface,
     // although the actual implementation lives in the content process. So are
     // the child attributes `network` and `cell`, which implement
     // nsIDOMMozMobileNetworkInfo and nsIDOMMozMobileCellInfo respectively.
     voice:          {connected: false,
                      emergencyCallsOnly: false,
                      roaming: false,
@@ -224,16 +223,21 @@ function RadioInterfaceLayer() {
                      roaming: false,
                      network: null,
                      cell: null,
                      type: null,
                      signalStrength: null,
                      relSignalStrength: null},
   };
 
+  this.voicemailInfo = {
+    number: null,
+    displayName: null
+  };
+
   this.callWaitingStatus = null;
 
   // Read the 'ril.radio.disabled' setting in order to start with a known
   // value at boot time.
   let lock = gSettingsService.createLock();
   lock.get("ril.radio.disabled", this);
 
   // Read preferred network type from the setting DB.
@@ -474,16 +478,19 @@ RadioInterfaceLayer.prototype = {
         break;
       case "RIL:GetCallForwardingOption":
         this.saveRequestTarget(msg);
         this.getCallForwardingOption(msg.json);
         break;
       case "RIL:RegisterCellBroadcastMsg":
         this.registerMessageTarget("cellbroadcast", msg.target);
         break;
+      case "RIL:GetVoicemailInfo":
+        // This message is sync.
+        return this.voicemailInfo;
     }
   },
 
   onerror: function onerror(event) {
     debug("Got an error: " + event.filename + ":" +
           event.lineno + ": " + event.message + "\n");
     event.preventDefault();
   },
@@ -1571,22 +1578,22 @@ RadioInterfaceLayer.prototype = {
 
     // Set the received NITZ time if the setting is enabled.
     if (this._nitzAutomaticUpdateEnabled) {
       this.setNitzTime(message);
     }
   },
 
   handleICCMbdn: function handleICCMbdn(message) {
-    let voicemail = this.rilContext.voicemail;
+    let voicemailInfo = this.voicemailInfo;
 
-    voicemail.number = message.number;
-    voicemail.displayName = message.alphaId;
+    voicemailInfo.number = message.number;
+    voicemailInfo.displayName = message.alphaId;
 
-    this._sendTargetMessage("voicemail", "RIL:VoicemailInfoChanged", voicemail);
+    this._sendTargetMessage("voicemail", "RIL:VoicemailInfoChanged", voicemailInfo);
   },
 
   handleICCInfoChange: function handleICCInfoChange(message) {
     let oldIcc = this.rilContext.icc;
     this.rilContext.icc = message;
    
     let iccInfoChanged = !oldIcc ||
                          oldIcc.iccid != message.iccid ||
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -258,31 +258,39 @@ interface nsIICCRecords : nsISupports
   readonly attribute jsval adn;
 
   /**
    * Fixed Dialling Numbers
    */
   readonly attribute jsval fdn;
 };
 
+[scriptable, uuid(c0c5cb9f-6372-4b5a-b74c-baacc2da5e4f)]
+interface nsIVoicemailInfo : nsISupports
+{
+  readonly attribute DOMString number;
+
+  readonly attribute DOMString displayName;
+};
+
 [scriptable, uuid(e6dc89f2-0d4e-46fc-902c-cfeeaee15e40)]
 interface nsIRilContext : nsISupports
 {
   readonly attribute DOMString radioState;
 
   readonly attribute DOMString cardState;
 
   readonly attribute nsIICCRecords icc;
 
   readonly attribute nsIDOMMozMobileConnectionInfo voice;
 
   readonly attribute nsIDOMMozMobileConnectionInfo data;
 };
 
-[scriptable, uuid(a90fef2c-44aa-4f2b-a0ee-a590e9dd345e)]
+[scriptable, uuid(f9c586ee-71ce-4172-9b2e-d89f0ff9c6d9)]
 interface nsIRadioInterfaceLayer : nsISupports
 {
   const unsigned short CALL_STATE_UNKNOWN = 0;
   const unsigned short CALL_STATE_DIALING = 1;
   const unsigned short CALL_STATE_ALERTING = 2;
   const unsigned short CALL_STATE_BUSY = 3;
   const unsigned short CALL_STATE_CONNECTING = 4;
   const unsigned short CALL_STATE_CONNECTED = 5;
@@ -295,16 +303,18 @@ interface nsIRadioInterfaceLayer : nsISu
 
   /**
    * Activates or deactivates radio power.
    */
   void setRadioEnabled(in bool value);
 
   readonly attribute nsIRilContext rilContext;
 
+  readonly attribute nsIVoicemailInfo voicemailInfo;
+
   /**
    * PDP APIs
    */
   void setupDataCallByType(in DOMString apntype);
   void deactivateDataCallByType(in DOMString apntype);
   long getDataCallStateByType(in DOMString apntype);
   void setupDataCall(in long radioTech,
                      in DOMString apn,
--- a/dom/system/gonk/tests/marionette/manifest.ini
+++ b/dom/system/gonk/tests/marionette/manifest.ini
@@ -1,8 +1,8 @@
 [DEFAULT]
 b2g = true
 browser = false
 qemu = true
 
 [test_geolocation.js]
 disabled = Bug 808783
-
+[test_get_voicemailInfo.js]
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/marionette/test_get_voicemailInfo.js
@@ -0,0 +1,26 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let Cc = SpecialPowers.Cc;
+let Ci = SpecialPowers.Ci;
+
+// Get system worker manager.
+let systemWorkerManager = Cc["@mozilla.org/telephony/system-worker-manager;1"];
+ok(systemWorkerManager);
+
+// Get RadioIntefaceLayer interface.
+let RIL = systemWorkerManager.getService(Ci.nsIInterfaceRequestor).
+          getInterface(Ci.nsIRadioInterfaceLayer);
+ok(RIL);
+
+// Check voicemail information accessible.
+ok(RIL.voicemailInfo);
+ok(RIL.voicemailInfo.number);
+ok(RIL.voicemailInfo.displayName);
+// These are the emulator's hard coded voicemail number and alphaId.
+is(RIL.voicemailInfo.number, "+15552175049");
+is(RIL.voicemailInfo.displayName, "Voicemail");
+
+finish();
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -523,17 +523,18 @@ var interfaceNamesInGlobalScope =
     "MozNetworkStatsManager",
     "MozNetworkStats",
     "MozNetworkStatsData",
     "RTCSessionDescription",
     "RTCIceCandidate",
     "RTCPeerConnection",
     "LocalMediaStream",
     "CSSConditionRule",
-    "CSSGroupingRule"
+    "CSSGroupingRule",
+    "AsyncScrollEventDetail"
   ]
 
 for (var i in SpecialPowers.Components.interfaces) {
   var s = i.toString();
   var name = null;
   if (s.indexOf("nsIDOM") == 0) {
     name = s.substring("nsIDOM".length);
   } else if (s.indexOf("nsI") == 0) {
new file mode 100644
--- /dev/null
+++ b/dom/webidl/HTMLHeadingElement.webidl
@@ -0,0 +1,22 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://www.whatwg.org/specs/web-apps/current-work/#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements
+ * http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
+ * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
+ * Opera Software ASA. You are granted a license to use, reproduce
+ * and create derivative works of this document.
+ */
+
+// http://www.whatwg.org/specs/web-apps/current-work/#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements
+interface HTMLHeadingElement : HTMLElement {
+/*};
+
+// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
+partial interface HTMLHeadingElement {
+*/
+           attribute DOMString align;
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -46,19 +46,21 @@ webidl_files = \
   FileReaderSync.webidl \
   FormData.webidl \
   Function.webidl \
   GainNode.webidl \
   HTMLBodyElement.webidl \
   HTMLCollection.webidl \
   HTMLDataListElement.webidl \
   HTMLDivElement.webidl \
+  HTMLDocument.webidl \
   HTMLElement.webidl \
   HTMLFontElement.webidl \
   HTMLFrameSetElement.webidl \
+  HTMLHeadingElement.webidl \
   HTMLLabelElement.webidl \
   HTMLOptionsCollection.webidl \
   HTMLPropertiesCollection.webidl \
   ImageData.webidl \
   Location.webidl \
   MutationObserver.webidl \
   Node.webidl \
   NodeFilter.webidl \
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -87,33 +87,43 @@ AsyncPanZoomController::AsyncPanZoomCont
      mX(this),
      mY(this),
      mAllowZoom(true),
      mMinZoom(MIN_ZOOM),
      mMaxZoom(MAX_ZOOM),
      mMonitor("AsyncPanZoomController"),
      mLastSampleTime(TimeStamp::Now()),
      mState(NOTHING),
+     mLastAsyncScrollTime(TimeStamp::Now()),
+     mLastAsyncScrollOffset(0, 0),
+     mCurrentAsyncScrollOffset(0, 0),
+     mAsyncScrollTimeoutTask(nullptr),
+     mAsyncScrollThrottleTime(100),
+     mAsyncScrollTimeout(300),
      mDPI(72),
      mWaitingForContentToPaint(false),
      mDisableNextTouchBatch(false),
      mHandlingTouchQueue(false)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   if (aGestures == USE_GESTURE_DETECTOR) {
     mGestureEventListener = new GestureEventListener(this);
   }
 
   SetDPI(mDPI);
 
   if (!gComputedTimingFunction) {
     gComputedTimingFunction = new ComputedTimingFunction();
     gComputedTimingFunction->Init(
       nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
     ClearOnShutdown(&gComputedTimingFunction);
   }
+
+  Preferences::GetUint("apzc.asyncscroll.throttle", &mAsyncScrollThrottleTime);
+  Preferences::GetUint("apzc.asyncscroll.timeout", &mAsyncScrollTimeout);
 }
 
 AsyncPanZoomController::~AsyncPanZoomController() {
 
 }
 
 static gfx::Point
 WidgetSpaceToCompensatedViewportSpace(const gfx::Point& aPoint,
@@ -362,16 +372,21 @@ nsEventStatus AsyncPanZoomController::On
 }
 
 nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent) {
   if (mDisableNextTouchBatch) {
     mDisableNextTouchBatch = false;
     return nsEventStatus_eIgnore;
   }
 
+  {
+    MonitorAutoLock monitor(mMonitor);
+    SendAsyncScrollEvent();
+  }
+
   switch (mState) {
   case FLING:
     // Should never happen.
     NS_WARNING("Received impossible touch end in OnTouchEnd.");
     // Fall through.
   case ANIMATING_ZOOM:
   case NOTHING:
     // May happen if the user double-taps and drags without lifting after the
@@ -674,16 +689,17 @@ bool AsyncPanZoomController::DoFling(con
 
   bool shouldContinueFlingX = mX.FlingApplyFrictionOrCancel(aDelta),
        shouldContinueFlingY = mY.FlingApplyFrictionOrCancel(aDelta);
   // If we shouldn't continue the fling, let's just stop and repaint.
   if (!shouldContinueFlingX && !shouldContinueFlingY) {
     // Bring the resolution back in sync with the zoom, in case we scaled down
     // the zoom while accelerating.
     SetZoomAndResolution(mFrameMetrics.mZoom.width);
+    SendAsyncScrollEvent();
     RequestContentRepaint();
     mState = NOTHING;
     return false;
   }
 
   // We want to inversely scale it because when you're zoomed further in, a
   // larger swipe should move you a shorter distance.
   gfxFloat inverseResolution = 1 / CalculateResolution(mFrameMetrics).width;
@@ -948,16 +964,18 @@ void AsyncPanZoomController::RequestCont
   if (fabsf(oldDisplayPort.x - newDisplayPort.x) < EPSILON &&
       fabsf(oldDisplayPort.y - newDisplayPort.y) < EPSILON &&
       fabsf(oldDisplayPort.width - newDisplayPort.width) < EPSILON &&
       fabsf(oldDisplayPort.height - newDisplayPort.height) < EPSILON &&
       mFrameMetrics.mResolution.width == mLastPaintRequestMetrics.mResolution.width) {
     return;
   }
 
+  SendAsyncScrollEvent();
+
   // Cache the zoom since we're temporarily changing it for
   // acceleration-scaled painting.
   gfxFloat actualZoom = mFrameMetrics.mZoom.width;
   // Calculate the factor of acceleration based on the faster of the two axes.
   float accelerationFactor =
     clamped(NS_MAX(mX.GetAccelerationFactor(), mY.GetAccelerationFactor()),
             float(MIN_ZOOM) / 2.0f, float(MAX_ZOOM));
   // Scale down the resolution a bit based on acceleration.
@@ -974,16 +992,26 @@ void AsyncPanZoomController::RequestCont
                       mFrameMetrics));
   mLastPaintRequestMetrics = mFrameMetrics;
   mWaitingForContentToPaint = true;
 
   // Set the zoom back to what it was for the purpose of logic control.
   mFrameMetrics.mZoom = gfxSize(actualZoom, actualZoom);
 }
 
+void
+AsyncPanZoomController::FireAsyncScrollOnTimeout()
+{
+  if (mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
+    MonitorAutoLock monitor(mMonitor);
+    SendAsyncScrollEvent();
+  }
+  mAsyncScrollTimeoutTask = nullptr;
+}
+
 bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime,
                                                             ContainerLayer* aLayer,
                                                             ViewTransform* aNewTransform) {
   // The eventual return value of this function. The compositor needs to know
   // whether or not to advance by a frame as soon as it can. For example, if a
   // fling is happening, it has to keep compositing so that the animation is
   // smooth. If an animation frame is requested, it is the compositor's
   // responsibility to schedule a composite.
@@ -1031,16 +1059,17 @@ bool AsyncPanZoomController::SampleConte
       );
 
       requestAnimationFrame = true;
 
       if (aSampleTime - mAnimationStartTime >= ZOOM_TO_DURATION) {
         // Bring the resolution in sync with the zoom.
         SetZoomAndResolution(mFrameMetrics.mZoom.width);
         mState = NOTHING;
+        SendAsyncScrollEvent();
         RequestContentRepaint();
       }
 
       break;
     }
     default:
       break;
     }
@@ -1051,16 +1080,44 @@ bool AsyncPanZoomController::SampleConte
     // during runtime, but we must wait for Gecko to repaint.
     localScale = CalculateResolution(mFrameMetrics);
 
     if (frame.IsScrollable()) {
       metricsScrollOffset = frame.GetScrollOffsetInLayerPixels();
     }
 
     scrollOffset = gfxPoint(mFrameMetrics.mScrollOffset.x, mFrameMetrics.mScrollOffset.y);
+    mCurrentAsyncScrollOffset = mFrameMetrics.mScrollOffset;
+  }
+
+  // Cancel the mAsyncScrollTimeoutTask because we will fire a
+  // mozbrowserasyncscroll event or renew the mAsyncScrollTimeoutTask again.
+  if (mAsyncScrollTimeoutTask) {
+    mAsyncScrollTimeoutTask->Cancel();
+    mAsyncScrollTimeoutTask = nullptr;
+  }
+  // Fire the mozbrowserasyncscroll event immediately if it's been
+  // sAsyncScrollThrottleTime ms since the last time we fired the event and the
+  // current scroll offset is different than the mLastAsyncScrollOffset we sent
+  // with the last event.
+  // Otherwise, start a timer to fire the event sAsyncScrollTimeout ms from now.
+  TimeDuration delta = aSampleTime - mLastAsyncScrollTime;
+  if (delta.ToMilliseconds() > mAsyncScrollThrottleTime &&
+      mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
+    MonitorAutoLock monitor(mMonitor);
+    mLastAsyncScrollTime = aSampleTime;
+    mLastAsyncScrollOffset = mCurrentAsyncScrollOffset;
+    SendAsyncScrollEvent();
+  }
+  else {
+    mAsyncScrollTimeoutTask =
+      NewRunnableMethod(this, &AsyncPanZoomController::FireAsyncScrollOnTimeout);
+    MessageLoop::current()->PostDelayedTask(FROM_HERE,
+                                            mAsyncScrollTimeoutTask,
+                                            mAsyncScrollTimeout);
   }
 
   nsIntPoint scrollCompensation(
     ((scrollOffset / rootScale - metricsScrollOffset) * localScale)
     .RoundedAwayFromZero());
   *aNewTransform = ViewTransform(-scrollCompensation, localScale);
 
   mLastSampleTime = aSampleTime;
@@ -1307,10 +1364,27 @@ void AsyncPanZoomController::SetZoomAndR
 void AsyncPanZoomController::UpdateZoomConstraints(bool aAllowZoom,
                                                    float aMinZoom,
                                                    float aMaxZoom) {
   mAllowZoom = aAllowZoom;
   mMinZoom = aMinZoom;
   mMaxZoom = aMaxZoom;
 }
 
+void AsyncPanZoomController::SendAsyncScrollEvent() {
+  if (!mGeckoContentController) {
+    return;
+  }
+
+  gfx::Rect contentRect;
+  gfx::Size scrollableSize;
+  {
+    scrollableSize = gfx::Size(mFrameMetrics.mScrollableRect.width,
+                               mFrameMetrics.mScrollableRect.height);
+    contentRect =
+      AsyncPanZoomController::CalculateCompositedRectInCssPixels(mFrameMetrics);
+    contentRect.MoveTo(mCurrentAsyncScrollOffset);
+  }
+
+  mGeckoContentController->SendAsyncScrollDOMEvent(contentRect, scrollableSize);
 }
 }
+}
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -222,16 +222,22 @@ public:
    * the configuration in aFrameMetrics: viewport dimensions, zoom
    * factor, etc.  (The mResolution member of aFrameMetrics is
    * ignored.)
    */
   static gfxSize CalculateResolution(const FrameMetrics& aMetrics);
 
   static gfx::Rect CalculateCompositedRectInCssPixels(const FrameMetrics& aMetrics);
 
+  /**
+   * Send an mozbrowserasyncscroll event.
+   * *** The monitor must be held while calling this.
+   */
+  void SendAsyncScrollEvent();
+
 protected:
   /**
    * Internal handler for ReceiveInputEvent(). Does all the actual work.
    */
   nsEventStatus HandleInputEvent(const InputData& aEvent);
 
   /**
    * Helper method for touches beginning. Sets everything up for panning and any
@@ -434,16 +440,24 @@ protected:
   /**
    * Utility function that sets the zoom and resolution simultaneously. This is
    * useful when we want to repaint at the current zoom level.
    *
    * *** The monitor must be held while calling this.
    */
   void SetZoomAndResolution(float aScale);
 
+  /**
+   * Timeout function for mozbrowserasyncscroll event. Because we throttle
+   * mozbrowserasyncscroll events in some conditions, this function ensures
+   * that the last mozbrowserasyncscroll event will be fired after a period of
+   * time.
+   */
+  void FireAsyncScrollOnTimeout();
+
 private:
   enum PanZoomState {
     NOTHING,        /* no touch-start events received */
     FLING,          /* all touches removed, but we're still scrolling page */
     TOUCHING,       /* one touch-start event received */
     PANNING,        /* panning the frame */
     PINCHING,       /* nth touch-start, where n > 1. this mode allows pan and zoom */
     ANIMATING_ZOOM, /* animated zoom to a new rect */
@@ -527,16 +541,37 @@ private:
 
   // How long it took in the past to paint after a series of previous requests.
   nsTArray<TimeDuration> mPreviousPaintDurations;
 
   // When the last paint request started. Used to determine the duration of
   // previous paints.
   TimeStamp mPreviousPaintStartTime;
 
+  // The last time and offset we fire the mozbrowserasyncscroll event when
+  // compositor has sampled the content transform for this frame.
+  TimeStamp mLastAsyncScrollTime;
+  gfx::Point mLastAsyncScrollOffset;
+
+  // The current offset drawn on the screen, it may not be sent since we have
+  // throttling policy for mozbrowserasyncscroll event.
+  gfx::Point mCurrentAsyncScrollOffset;
+
+  // The delay task triggered by the throttling mozbrowserasyncscroll event
+  // ensures the last mozbrowserasyncscroll event is always been fired.
+  CancelableTask* mAsyncScrollTimeoutTask;
+
+  // The time period in ms that throttles mozbrowserasyncscroll event.
+  // Default is 100ms if there is no "apzc.asyncscroll.throttle" in preference.
+  uint32_t mAsyncScrollThrottleTime;
+
+  // The timeout in ms for mAsyncScrollTimeoutTask delay task.
+  // Default is 300ms if there is no "apzc.asyncscroll.timeout" in preference.
+  uint32_t mAsyncScrollTimeout;
+
   int mDPI;
 
   // Stores the current paint status of the frame that we're managing. Repaints
   // may be triggered by other things (like content doing things), in which case
   // this status will not be updated. It is only changed when this class
   // requests a repaint.
   bool mWaitingForContentToPaint;
 
--- a/gfx/layers/ipc/GeckoContentController.h
+++ b/gfx/layers/ipc/GeckoContentController.h
@@ -39,16 +39,24 @@ public:
   virtual void HandleSingleTap(const nsIntPoint& aPoint) = 0;
 
   /**
    * Requests handling a long tap. |aPoint| is in CSS pixels, relative to the
    * current scroll offset.
    */
   virtual void HandleLongTap(const nsIntPoint& aPoint) = 0;
 
+  /**
+   * Requests sending a mozbrowserasyncscroll domevent to embedder.
+   * |aContentRect| is in CSS pixels, relative to the current cssPage.
+   * |aScrollableSize| is the current content width/height in CSS pixels.
+   */
+  virtual void SendAsyncScrollDOMEvent(const gfx::Rect &aContentRect,
+                                       const gfx::Size &aScrollableSize) = 0;
+
   GeckoContentController() {}
   virtual ~GeckoContentController() {}
 };
 
 }
 }
 
 #endif // mozilla_layers_GeckoContentController_h
--- a/js/src/ion/VMFunctions.cpp
+++ b/js/src/ion/VMFunctions.cpp
@@ -359,17 +359,18 @@ ArrayConcatDense(JSContext *cx, HandleOb
     if (!js::array_concat(cx, 1, argv))
         return NULL;
     return &argv[0].toObject();
 }
 
 bool
 CharCodeAt(JSContext *cx, HandleString str, int32_t index, uint32_t *code)
 {
-    JS_ASSERT(index < str->length());
+    JS_ASSERT(index >= 0 &&
+              static_cast<uint32_t>(index) < str->length());
 
     const jschar *chars = str->getChars(cx);
     if (!chars)
         return false;
 
     *code = chars[index];
     return true;
 }
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -128,29 +128,16 @@ members = [
     'nsIDOMHTMLAnchorElement.hash',
     'nsIDOMHTMLBaseElement.href',
     'nsIDOMHTMLBaseElement.target',
     'nsIDOMHTMLButtonElement.name',
     'nsIDOMHTMLButtonElement.form',
     'nsIDOMHTMLButtonElement.value',
     'nsIDOMHTMLButtonElement.disabled',
     'nsIDOMHTMLCommandElement.*',
-    'nsIDOMHTMLDocument.body',
-    'nsIDOMHTMLDocument.getElementsByName',
-    'nsIDOMHTMLDocument.anchors',
-    'nsIDOMHTMLDocument.links',
-    'nsIDOMHTMLDocument.forms',
-    'nsIDOMHTMLDocument.cookie',
-    'nsIDOMHTMLDocument.images',
-    'nsIDOMHTMLDocument.write',
-    'nsIDOMHTMLDocument.writeln',
-    'nsIDOMHTMLDocument.domain',
-    'nsIDOMHTMLDocument.getSelection',
-    'nsIDOMHTMLDocument.designMode',
-    'nsIDOMHTMLDocument.head',
     'nsIDOMHTMLFormElement.elements',
     'nsIDOMHTMLFormElement.name',
     'nsIDOMHTMLFormElement.submit',
     'nsIDOMHTMLFormElement.length',
     'nsIDOMHTMLFormElement.target',
     'nsIDOMHTMLFormElement.action',
     'nsIDOMHTMLFrameElement.src',
     'nsIDOMHTMLFrameElement.contentDocument',
@@ -367,90 +354,47 @@ irregularFilenames = {
     'nsIDOMWindowPerformance': 'nsIDOMWindow',
     }
 
 customIncludes = [
     'nsINode.h',
     'nsIContent.h',
     'nsIDocument.h',
     'nsCSSPropertiesQS.h',
-    'nsDocument.h',
     'nsDOMTokenList.h',
     'nsGenericDOMDataNode.h',
     'mozilla/dom/Element.h',
     'nsGenericHTMLElement.h',
     'nsSVGElement.h',
-    'nsHTMLDocument.h',
     'nsDOMQS.h',
     'nsDOMStringMap.h',
     'HTMLPropertiesCollection.h',
     'nsHTMLMenuElement.h',
     'nsICSSDeclaration.h',
     'mozilla/dom/NodeBinding.h',
     'mozilla/dom/ElementBinding.h',
     'mozilla/dom/HTMLElementBinding.h',
     'mozilla/dom/DocumentBinding.h',
     'mozilla/dom/SVGElementBinding.h',
     'nsPerformance.h',
+    'mozilla/dom/HTMLDocumentBinding.h',
     ]
 
 customReturnInterfaces = [
     'nsIDOMCanvasPattern',
     'nsIDOMCanvasGradient',
     ]
 
-nsIDOMHTMLDocument_Write_customMethodCallCode = """
-    nsAString &str = arg0;
-    for (unsigned i = 1; i < argc; ++i) {
-      xpc_qsDOMString next_arg(cx, argv[i], &argv[i],
-                               xpc_qsDOMString::eStringify,
-                               xpc_qsDOMString::eStringify);
-      if (!next_arg.IsValid())
-        return JS_FALSE;
-
-      str.Append(next_arg);
-    }
-
-    rv = self->%s(arg0, cx);
-"""
-
 nsIDOMStorage_Clear_customMethodCallCode = """
     rv = self->Clear();
     if (NS_SUCCEEDED(rv))
         JS_ClearNonGlobalObject(cx, obj);
 """
 
 customMethodCalls = {
-    'nsIDOMHTMLDocument_': {
-        'thisType': 'nsHTMLDocument'
-        },
-    'nsIDOMHTMLDocument_Write': {
-        'thisType': 'nsHTMLDocument',
-        'code': nsIDOMHTMLDocument_Write_customMethodCallCode % 'Write'
-        },
-    'nsIDOMHTMLDocument_Writeln': {
-        'thisType': 'nsHTMLDocument',
-        'code': nsIDOMHTMLDocument_Write_customMethodCallCode % 'Writeln'
-        },
-    'nsIDOMHTMLDocument_GetBody': {
-        'thisType': 'nsHTMLDocument',
-        'code': '    nsIContent *result = self->GetBody();',
-        'canFail': False
-        },
-    'nsIDOMHTMLDocument_GetHead': {
-        'thisType': 'nsHTMLDocument',
-        'code': '    nsIContent *result = self->GetHead();',
-        'canFail': False
-        },
-    'nsIDOMHTMLDocument_GetElementsByName': {
-        'thisType': 'nsHTMLDocument',
-        'code': '    nsRefPtr<nsContentList> result = '
-                'self->GetElementsByName(arg0);',
-        'canFail': False
-        },
     'nsIDOMStorage_Clear': {
         'code': nsIDOMStorage_Clear_customMethodCallCode
         },
     'nsIDOMElementCSSInlineStyle_GetStyle': {
         'thisType': 'nsStyledElement',
         'code': '    /* XXXbz MathML elements inherit from nsStyledElement but\n'
                 '       don\'t actually implement GetStyle. */\n'
                 '    if (self->GetNameSpaceID() == kNameSpaceID_MathML)\n'
@@ -481,10 +425,11 @@ customMethodCalls = {
         },
     }
 
 newBindingProperties = {
     'nsIDOMNode': 'mozilla::dom::NodeBinding::sNativePropertyHooks.mNativeProperties.regular',
     'nsIDOMElement': 'mozilla::dom::ElementBinding::sNativePropertyHooks.mNativeProperties.regular',
     'nsIDOMHTMLElement': 'mozilla::dom::HTMLElementBinding::sNativePropertyHooks.mNativeProperties.regular',
     'nsIDOMDocument': 'mozilla::dom::DocumentBinding::sNativePropertyHooks.mNativeProperties.regular',
-    'nsIDOMSVGElement': 'mozilla::dom::SVGElementBinding::sNativePropertyHooks.mNativeProperties.regular'
+    'nsIDOMSVGElement': 'mozilla::dom::SVGElementBinding::sNativePropertyHooks.mNativeProperties.regular',
+    'nsIDOMHTMLDocument': 'mozilla::dom::HTMLDocumentBinding::sNativePropertyHooks.mNativeProperties.regular',
     }
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -3,16 +3,17 @@
 
 /* This Source Code is subject to the terms of the Mozilla Public License
  * version 2.0 (the "License"). You can obtain a copy of the License at
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: flex" */
 
 #include "nsFlexContainerFrame.h"
+#include "nsContentUtils.h"
 #include "nsDisplayList.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "prlog.h"
 
 using namespace mozilla::css;
 
@@ -217,56 +218,16 @@ public:
       nsSize(aCrossSize, aMainSize);
   }
 
 private:
   AxisOrientationType mMainAxis;
   AxisOrientationType mCrossAxis;
 };
 
-// Encapsulates a frame for a flex item, with enough information for us to
-// sort by 'order' (and by the frame's actual index inside the parent's
-// child-frames array, among frames with the same 'order').
-class SortableFrame {
-public:
-  SortableFrame(nsIFrame* aFrame,
-                int32_t aOrderValue,
-                uint32_t aIndexInFrameList)
-  : mFrame(aFrame),
-    mOrderValue(aOrderValue),
-    mIndexInFrameList(aIndexInFrameList)
-  {
-    MOZ_ASSERT(aFrame, "expecting a non-null child frame");
-  }
-
-  // Implement operator== and operator< so that we can use nsDefaultComparator
-  bool operator==(const SortableFrame& rhs) const {
-    MOZ_ASSERT(mFrame != rhs.mFrame ||
-               (mOrderValue == rhs.mOrderValue &&
-                mIndexInFrameList == rhs.mIndexInFrameList),
-               "if frames are equal, the other member data should be too");
-    return mFrame == rhs.mFrame;
-  }
-
-  bool operator<(const SortableFrame& rhs) const {
-    if (mOrderValue == rhs.mOrderValue) {
-      return mIndexInFrameList < rhs.mIndexInFrameList;
-    }
-    return mOrderValue < rhs.mOrderValue;
-  }
-
-  // Accessor for the frame
-  inline nsIFrame* Frame() const { return mFrame; }
-
-protected:
-  nsIFrame* const mFrame;     // The flex item's frame
-  int32_t   const mOrderValue; // mFrame's computed value of 'order' property
-  uint32_t  const mIndexInFrameList; // mFrame's idx in parent's child frames
-};
-
 // Represents a flex item.
 // Includes the various pieces of input that the Flexbox Layout Algorithm uses
 // to resolve a flexible width.
 class FlexItem {
 public:
   FlexItem(nsIFrame* aChildFrame,
            float aFlexGrow, float aFlexShrink, nscoord aMainBaseSize,
            nscoord aMainMinSize, nscoord aMainMaxSize,
@@ -485,16 +446,111 @@ protected:
 
   // Misc:
   bool mIsStretched; // See IsStretched() documentation
   uint8_t mAlignSelf; // My "align-self" computed value (with "auto"
                       // swapped out for parent"s "align-items" value,
                       // in our constructor).
 };
 
+/**
+ * Helper-function to find the nsIContent* that we should use for comparing the
+ * DOM tree position of the given flex-item frame.
+ *
+ * In most cases, this will be aFrame->GetContent(), but if aFrame is an
+ * anonymous container, then its GetContent() won't be what we want. In such
+ * cases, we need to find aFrame's first non-anonymous-container descendant.
+ */
+static nsIContent*
+GetContentForComparison(const nsIFrame* aFrame)
+{
+  MOZ_ASSERT(aFrame, "null frame passed to GetContentForComparison()");
+  MOZ_ASSERT(aFrame->IsFlexItem(), "only intended for flex items");
+
+  while (true) {
+    nsIAtom* pseudoTag = aFrame->GetStyleContext()->GetPseudo();
+
+    // If aFrame isn't an anonymous container, then it'll do.
+    if (!pseudoTag ||                                 // No pseudotag.
+        !nsCSSAnonBoxes::IsAnonBox(pseudoTag) ||      // Pseudotag isn't anon.
+        pseudoTag == nsCSSAnonBoxes::mozNonElement) { // Text, not a container.
+      return aFrame->GetContent();
+    }
+
+    // Otherwise, descend to its first child and repeat.
+    aFrame = aFrame->GetFirstPrincipalChild();
+    MOZ_ASSERT(aFrame, "why do we have an anonymous box without any children?");
+  }
+}
+
+/**
+ * Sorting helper-function that compares two frames' "order" property-values,
+ * and if they're equal, compares the DOM positions of their corresponding
+ * content nodes. Returns true if aFrame1 is "less than or equal to" aFrame2
+ * according to this comparison.
+ *
+ * Note: This can't be a static function, because we need to pass it as a
+ * template argument. (Only functions with external linkage can be passed as
+ * template arguments.)
+ *
+ * @return true if the computed "order" property of aFrame1 is less than that
+ *         of aFrame2, or if the computed "order" values are equal and aFrame1's
+ *         corresponding DOM node is earlier than aFrame2's in the DOM tree.
+ *         Otherwise, returns false.
+ */
+bool
+IsOrderLEQWithDOMFallback(nsIFrame* aFrame1,
+                          nsIFrame* aFrame2)
+{
+  if (aFrame1 == aFrame2) {
+    // Anything is trivially LEQ itself, so we return "true" here... but it's
+    // probably bad if we end up actually needing this, so let's assert.
+    NS_ERROR("Why are we checking if a frame is LEQ itself?");
+    return true;
+  }
+
+  int32_t order1 = aFrame1->GetStylePosition()->mOrder;
+  int32_t order2 = aFrame2->GetStylePosition()->mOrder;
+
+  if (order1 != order2) {
+    return order1 < order2;
+  }
+
+  // Same "order" value --> use DOM position.
+  nsIContent* content1 = GetContentForComparison(aFrame1);
+  nsIContent* content2 = GetContentForComparison(aFrame2);
+  MOZ_ASSERT(content1 != content2,
+             "Two different flex items are using the same nsIContent node for "
+             "comparison, so we may be sorting them in an arbitrary order");
+
+  return nsContentUtils::PositionIsBefore(content1, content2);
+}
+
+/**
+ * Sorting helper-function that compares two frames' "order" property-values.
+ * Returns true if aFrame1 is "less than or equal to" aFrame2 according to this
+ * comparison.
+ *
+ * Note: This can't be a static function, because we need to pass it as a
+ * template argument. (Only functions with external linkage can be passed as
+ * template arguments.)
+ *
+ * @return true if the computed "order" property of aFrame1 is less than or
+ *         equal to that of aFrame2.  Otherwise, returns false.
+ */
+bool
+IsOrderLEQ(nsIFrame* aFrame1,
+           nsIFrame* aFrame2)
+{
+  int32_t order1 = aFrame1->GetStylePosition()->mOrder;
+  int32_t order2 = aFrame2->GetStylePosition()->mOrder;
+
+  return order1 <= order2;
+}
+
 bool
 nsFlexContainerFrame::IsHorizontal()
 {
   const FlexboxAxisTracker axisTracker(this);
   return IsAxisHorizontal(axisTracker.GetMainAxis());
 }
 
 nsresult
@@ -559,24 +615,19 @@ nsFlexContainerFrame::AppendFlexItemForC
                                 0, 0, NS_FRAME_NO_MOVE_FRAME,
                                 childReflowStatus);
       NS_ENSURE_SUCCESS(rv, rv);
 
       MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus),
                  "We gave flex item unconstrained available height, so it "
                  "should be complete");
 
-      // Call DidReflow to clear NS_FRAME_IN_REFLOW and any other state on the
-      // child before our next ReflowChild call.
-      // NOTE: We're intentionally calling DidReflow() instead of the wrapper
-      // FinishReflowChild() because we don't want the rest of the stuff in
-      // FinishReflowChild() (e.g. moving the frame's rect) to happen until we
-      // do our "real" reflow of the child.
-      rv = aChildFrame->DidReflow(aPresContext, &childRSForMeasuringHeight,
-                                  nsDidReflowStatus::FINISHED);
+      rv = FinishReflowChild(aChildFrame, aPresContext,
+                             &childRSForMeasuringHeight, childDesiredSize,
+                             0, 0, 0);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // Subtract border/padding in vertical axis, to get _just_
       // the effective computed value of the "height" property.
       nscoord childDesiredHeight = childDesiredSize.height -
         childRS.mComputedBorderPadding.TopBottom();
       childDesiredHeight = NS_MAX(0, childDesiredHeight);
 
@@ -935,16 +986,28 @@ NS_NewFlexContainerFrame(nsIPresShell* a
 // nsFlexContainerFrame Method Implementations
 // ===========================================
 
 /* virtual */
 nsFlexContainerFrame::~nsFlexContainerFrame()
 {
 }
 
+template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
+/* static */ bool
+nsFlexContainerFrame::SortChildrenIfNeeded()
+{
+  if (nsLayoutUtils::IsFrameListSorted<IsLessThanOrEqual>(mFrames)) {
+    return false;
+  }
+
+  nsLayoutUtils::SortFrameList<IsLessThanOrEqual>(mFrames);
+  return true;
+}
+
 /* virtual */
 nsIAtom*
 nsFlexContainerFrame::GetType() const
 {
   return nsGkAtoms::flexContainerFrame;
 }
 
 #ifdef DEBUG
@@ -973,16 +1036,19 @@ GetDisplayFlagsForFlexItem(nsIFrame* aFr
   return 0;
 }
 
 NS_IMETHODIMP
 nsFlexContainerFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                        const nsRect&           aDirtyRect,
                                        const nsDisplayListSet& aLists)
 {
+  MOZ_ASSERT(nsLayoutUtils::IsFrameListSorted<IsOrderLEQWithDOMFallback>(mFrames),
+             "Frame list should've been sorted in reflow");
+
   nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Our children are all block-level, so their borders/backgrounds all go on
   // the BlockBorderBackgrounds list.
   nsDisplayListSet childLists(aLists, aLists.BlockBorderBackgrounds());
   for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
     rv = BuildDisplayListForChild(aBuilder, e.get(), aDirtyRect, childLists,
@@ -1295,35 +1361,16 @@ nsFlexContainerFrame::ResolveFlexibleLen
 #ifdef DEBUG
   for (uint32_t i = 0; i < aItems.Length(); ++i) {
     MOZ_ASSERT(aItems[i].IsFrozen(),
                "All flexible lengths should've been resolved");
   }
 #endif // DEBUG
 }
 
-void
-BuildSortedChildArray(const nsFrameList& aChildren,
-		      nsTArray<SortableFrame>& aSortedChildren)
-{
-  aSortedChildren.SetCapacity(aChildren.GetLength());
-
-  // Throw all our children in the array...
-  uint32_t indexInFrameList = 0;
-  for (nsFrameList::Enumerator e(aChildren); !e.AtEnd(); e.Next()) {
-    int32_t orderValue = e.get()->GetStylePosition()->mOrder;
-    aSortedChildren.AppendElement(SortableFrame(e.get(), orderValue,
-						indexInFrameList));
-    indexInFrameList++;
-  }
-
-  // ... and sort (by 'order' property)
-  aSortedChildren.Sort();
-}
-
 MainAxisPositionTracker::
   MainAxisPositionTracker(nsFlexContainerFrame* aFlexContainerFrame,
                           const FlexboxAxisTracker& aAxisTracker,
                           const nsHTMLReflowState& aReflowState,
                           const nsTArray<FlexItem>& aItems)
   : PositionTracker(aAxisTracker.GetMainAxis()),
     mNumAutoMarginsInMainAxis(0),
     mNumPackingSpacesRemaining(0)
@@ -1782,28 +1829,21 @@ nsresult
 nsFlexContainerFrame::GenerateFlexItems(
   nsPresContext* aPresContext,
   const nsHTMLReflowState& aReflowState,
   const FlexboxAxisTracker& aAxisTracker,
   nsTArray<FlexItem>& aFlexItems)
 {
   MOZ_ASSERT(aFlexItems.IsEmpty(), "Expecting outparam to start out empty");
 
-  // Sort by 'order' property:
-  nsTArray<SortableFrame> sortedChildren;
-  BuildSortedChildArray(mFrames, sortedChildren);
-
-  // Build list of unresolved flex items:
-
   // XXXdholbert When we support multi-line, we  might want this to be a linked
   // list, so we can easily split into multiple lines.
-  aFlexItems.SetCapacity(sortedChildren.Length());
-  for (uint32_t i = 0; i < sortedChildren.Length(); ++i) {
-    nsresult rv = AppendFlexItemForChild(aPresContext,
-                                         sortedChildren[i].Frame(),
+  aFlexItems.SetCapacity(mFrames.GetLength());
+  for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
+    nsresult rv = AppendFlexItemForChild(aPresContext, e.get(),
                                          aReflowState, aAxisTracker,
                                          aFlexItems);
     NS_ENSURE_SUCCESS(rv,rv);
   }
 
   return NS_OK;
 }
 
@@ -1993,16 +2033,32 @@ nsFlexContainerFrame::Reflow(nsPresConte
 
   // If our subtree is dirty (i.e. some of our descendants have changed), we
   // reflow _all_ of our children.  We have to do this -- we can't just reflow
   // select children, as we would in other frame classes.  This is because flex
   // items' sizes (in both axes) are highly dependent on their siblings' sizes.
   bool shouldReflowChildren =
     NS_SUBTREE_DIRTY(this) || aReflowState.ShouldReflowAllKids();
 
+  // If we've never reordered our children, then we can trust that they're
+  // already in DOM-order, and we only need to consider their "order" property
+  // when checking them for sortedness & sorting them.
+  //
+  // After we actually sort them, though, we can't trust that they're in DOM
+  // order anymore.  So, from that point on, our sort & sorted-order-checking
+  // operations need to use a fancier LEQ function that also takes DOM order
+  // into account, so that we can honor the spec's requirement that frames w/
+  // equal "order" values are laid out in DOM order.
+  if (!mChildrenHaveBeenReordered) {
+    mChildrenHaveBeenReordered =
+      SortChildrenIfNeeded<IsOrderLEQ>();
+  } else {
+    SortChildrenIfNeeded<IsOrderLEQWithDOMFallback>();
+  }
+
   const FlexboxAxisTracker axisTracker(this);
 
   // Generate a list of our flex items (already sorted), and get our main
   // size (which may depend on those items).
   nsTArray<FlexItem> items;
   nsresult rv = GenerateFlexItems(aPresContext, aReflowState,
                                   axisTracker, items);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -2137,16 +2193,18 @@ nsFlexContainerFrame::Reflow(nsPresConte
 
       // Override reflow state's computed cross-size, for stretched items.
       if (curItem.IsStretched()) {
         MOZ_ASSERT(curItem.GetAlignSelf() == NS_STYLE_ALIGN_ITEMS_STRETCH,
                    "stretched item w/o 'align-self: stretch'?");
         if (IsAxisHorizontal(axisTracker.GetCrossAxis())) {
           childReflowState.SetComputedWidth(curItem.GetCrossSize());
         } else {
+          // If this item's height is stretched, it's a relative height.
+          curItem.Frame()->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
           childReflowState.SetComputedHeight(curItem.GetCrossSize());
         }
       }
 
       // XXXdholbert Might need to actually set the correct margins in the
       // reflow state at some point, so that they can be saved on the frame for
       // UsedMarginPropeorty().  Maybe doesn't matter though...?
 
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -56,20 +56,33 @@ public:
   // Flexbox-specific public methods
   bool IsHorizontal();
 
 protected:
   // Protected constructor & destructor
   nsFlexContainerFrame(nsStyleContext* aContext) :
     nsFlexContainerFrameSuper(aContext),
     mCachedContentBoxCrossSize(nscoord_MIN),
-    mCachedAscent(nscoord_MIN)
+    mCachedAscent(nscoord_MIN),
+    mChildrenHaveBeenReordered(false)
   {}
   virtual ~nsFlexContainerFrame();
 
+  /**
+   * Checks whether our child-frame list "mFrames" is sorted, using the given
+   * IsLessThanOrEqual function, and sorts it if it's not already sorted.
+   *
+   * XXXdholbert Once we support pagination, we need to make this function
+   * check our continuations as well (or wrap it in a function that does).
+   *
+   * @return true if we had to sort mFrames, false if it was already sorted.
+   */
+  template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
+  bool SortChildrenIfNeeded();
+
   // Protected flex-container-specific methods / member-vars
 #ifdef DEBUG
   void SanityCheckAnonymousFlexItems() const;
 #endif // DEBUG
 
 
   // Returns nsresult because we might have to reflow aChildFrame (to get its
   // vertical intrinsic size in a vertical flexbox), and if that reflow fails
@@ -108,11 +121,13 @@ protected:
     SingleLineCrossAxisPositionTracker& aLineCrossAxisPosnTracker,
     FlexItem& aItem);
 
   // Cached values from running flexbox layout algorithm, used in setting our
   // reflow metrics w/out actually reflowing all of our children, in any
   // reflows where we're not dirty:
   nscoord mCachedContentBoxCrossSize; // Cross size of our content-box.
   nscoord mCachedAscent;              // Our ascent, in prev. reflow.
+  bool    mChildrenHaveBeenReordered; // Have we ever had to reorder our kids
+                                      // to satisfy their 'order' values?
 };
 
 #endif /* nsFlexContainerFrame_h___ */
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -8,16 +8,17 @@
 #include "base/basictypes.h"
 
 #include "BasicLayers.h"
 #include "gfx3DMatrix.h"
 #include "LayerManagerOGL.h"
 #ifdef MOZ_ENABLE_D3D9_LAYER
 # include "LayerManagerD3D9.h"
 #endif //MOZ_ENABLE_D3D9_LAYER
+#include "mozilla/BrowserElementParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/layers/AsyncPanZoomController.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/ShadowLayersParent.h"
 #include "nsContentUtils.h"
 #include "nsFrameLoader.h"
 #include "nsIObserver.h"
 #include "nsSubDocumentFrame.h"
@@ -545,16 +546,34 @@ public:
     if (mRenderFrame) {
       TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
       browser->HandleLongTap(aPoint);
     }
   }
 
   void ClearRenderFrame() { mRenderFrame = nullptr; }
 
+  virtual void SendAsyncScrollDOMEvent(const gfx::Rect& aContentRect,
+                                       const gfx::Size& aContentSize) MOZ_OVERRIDE
+  {
+    if (MessageLoop::current() != mUILoop) {
+      mUILoop->PostTask(
+        FROM_HERE,
+        NewRunnableMethod(this,
+                          &RemoteContentController::SendAsyncScrollDOMEvent,
+                          aContentRect, aContentSize));
+      return;
+    }
+    if (mRenderFrame) {
+      TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
+      BrowserElementParent::DispatchAsyncScrollEvent(browser, aContentRect,
+                                                     aContentSize);
+    }
+  }
+
 private:
   void DoRequestContentRepaint(const FrameMetrics& aFrameMetrics)
   {
     if (mRenderFrame) {
       TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
       browser->UpdateFrame(aFrameMetrics);
     }
   }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/flexbox/flexbox-dyn-changePadding-1-ref.xhtml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <style>
+      #container {
+        display: flex;
+        width: 100px;
+        height: 100px;
+        background: lime;
+      }
+    </style>
+  </head>
+  <body>
+    <div id="container"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/flexbox/flexbox-dyn-changePadding-1a.xhtml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!--
+    This test checks that we reflow sufficiently when a grandchild of a
+    flex container needs an incremental reflow.  This test should end up
+    rendering as a lime square, 100px by 100px.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml"
+      class="reftest-wait">
+  <head>
+    <style>
+      #container {
+        display: flex;
+        flex-direction: column;
+        width: 100px;
+      }
+      #item {
+        background: red;
+      }
+      #tweakMe {
+        height: 100px;
+        background: orange;
+        padding-left: 1px;
+      }
+    </style>
+    <script>
+      function tweak() {
+        var tweakMe = document.getElementById("tweakMe");
+        tweakMe.style.paddingLeft = "0";
+        tweakMe.style.background = "lime";
+        document.documentElement.removeAttribute("class");
+      }
+      window.addEventListener("MozReftestInvalidate", tweak, false);
+    </script>
+  </head>
+  <body>
+    <div id="container">
+      <div id="item">
+        <div id="tweakMe"></div>
+      </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/flexbox/flexbox-dyn-changePadding-1b.xhtml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!--
+    This test checks that we reflow sufficiently when a stretched, nested
+    flex container needs an incremental reflow.  This test should end up
+    rendering as a lime square, 100px by 100px.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml"
+      class="reftest-wait">
+  <head>
+    <style>
+      #outerContainer {
+        display: flex;
+        width: 100px;
+        height: 100px;
+        background: red;
+      }
+      #tweakMe {
+        display: flex;
+        background: orange;
+        width: 100px;
+        /* height should stretch to fill parent's height, via
+         * parent's "align-items: stretch" (the default) */
+
+        padding-left: 1px;
+      }
+    </style>
+    <script>
+      function tweak() {
+        var tweakMe = document.getElementById("tweakMe");
+        tweakMe.style.paddingLeft = "0";
+        tweakMe.style.background = "lime";
+        document.documentElement.removeAttribute("class");
+      }
+      window.addEventListener("MozReftestInvalidate", tweak, false);
+    </script>
+  </head>
+  <body>
+    <div id="outerContainer">
+      <div id="tweakMe"></div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/flexbox/flexbox-paint-ordering-2-ref.xhtml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!-- Reference case for flex items containing overlapping content.
+     This reference uses inline-block in place of inline-flex, with floated
+     children in place of flex items, and with hardcoded DOM-reordering in
+     place of "order" reordering. -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <style>
+      body {
+        line-height: 0;
+      }
+
+      .flexbox {
+        display: inline-block;
+        width: 20px;
+        height: 10px;
+        border: 2px solid gray;
+        margin-bottom: 10px;
+        margin-right: 10px;
+      }
+      .a {
+        width: 10px;
+        height: 10px;
+        background: lightblue;
+        float: left; /* to stack horizontally, like a flex item */
+      }
+      .b {
+        width: 10px;
+        height: 10px;
+        background: pink;
+        float: left; /* to stack horizontally, like a flex item */
+      }
+      .aKid {
+         margin-left: 3px;
+         margin-top:  3px;
+         width: 10px;
+         height: 10px;
+         background: steelblue;
+         border: 1px solid blue;
+      }
+      .bKid {
+         margin-left: 3px;
+         margin-top:  6px;
+         width: 10px;
+         height: 10px;
+         background: violet;
+         border: 1px solid purple;
+      }
+
+      /* Need to set 'position' for z-index to take effect. */
+      .zn2 { z-index: -2; position: relative; }
+      .zn1 { z-index: -1; position: relative; }
+      .z0  { z-index:  0; position: relative; }
+      .z1  { z-index:  1; position: relative; }
+
+    </style>
+  </head>
+  <body>
+    <!-- order not set: -->
+    <div class="flexbox">
+      <div class="a"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div>
+
+    <br/>
+
+    <!-- order set, but it matches content order, so it shouldn't matter: -->
+    <div class="flexbox">
+      <div class="a"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div>
+
+    <br/>
+
+    <!-- order set to reverse of content-order: -->
+    <div class="flexbox">
+      <div class="b"><div class="bKid"/></div>
+      <div class="a"><div class="aKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="b"><div class="bKid"/></div>
+      <div class="a"><div class="aKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="b"><div class="bKid"/></div>
+      <div class="a"><div class="aKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="b"><div class="bKid"/></div>
+      <div class="a"><div class="aKid"/></div>
+    </div>
+
+    <br/>
+
+    <!-- order set to reverse of content-order, AND with z-index set on
+         one or both items, but not such that it changes the paint order -->
+    <div class="flexbox">
+      <div class="b"><div class="bKid"/></div>
+      <div class="a"><div class="aKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="b"><div class="bKid"/></div>
+      <div class="a"><div class="aKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="b"><div class="bKid"/></div>
+      <div class="a"><div class="aKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="b"><div class="bKid"/></div>
+      <div class="a"><div class="aKid"/></div>
+    </div>
+
+    <br/>
+
+    <!-- order set to reverse of content-order, AND with z-index set on
+         one or both items, in such a way that it affects paint order -->
+    <div class="flexbox">
+      <!-- 'a' is behind the container's border -->
+      <div class="b"><div class="bKid"/></div>
+      <div class="a zn1"><div class="aKid"/></div>
+    </div
+    ><div class="flexbox">
+      <!-- 'a' and 'b' are both behind the container's border -->
+      <div class="b zn1"><div class="bKid"/></div>
+      <div class="a zn1"><div class="aKid"/></div>
+    </div
+    ><div class="flexbox">
+      <!-- 'a' and 'b' are both behind the container's border,
+           and 'a' is behind 'b' despite coming after it in the 'order'
+           ordering-->
+      <div class="b zn1"><div class="bKid"/></div>
+      <div class="a zn2"><div class="aKid"/></div>
+    </div
+    ><div class="flexbox">
+      <!-- 'a' and 'b' are both in front of the container's border,
+           and 'a' is behind 'b' despite coming after it in the 'order'
+           ordering-->
+      <div class="b z1"><div class="bKid"/></div>
+      <div class="a z0"><div class="aKid"/></div>
+    </div>
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/flexbox/flexbox-paint-ordering-2.xhtml
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!-- Testcase with flex items containing overlapping content, with
+     "order" and "z-index" set on some of them, to test how that affects
+     paint-order. -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <style>
+      body {
+        line-height: 0;
+      }
+
+      .flexbox {
+        display: inline-flex;
+        width: 20px;
+        height: 10px;
+        border: 2px solid gray;
+        margin-bottom: 10px;
+        margin-right: 10px;
+      }
+      .a {
+        width: 10px;
+        height: 10px;
+        background: lightblue;
+        min-width: 0;
+      }
+      .b {
+        width: 10px;
+        height: 10px;
+        background: pink;
+        min-width: 0;
+      }
+
+      .aKid {
+         margin-left: 3px;
+         margin-top:  3px;
+         width: 10px;
+         height: 10px;
+         background: steelblue;
+         border: 1px solid blue;
+      }
+      .bKid {
+         margin-left: 3px;
+         margin-top:  6px;
+         width: 10px;
+         height: 10px;
+         background: violet;
+         border: 1px solid purple;
+      }
+
+      .on1 { order: -1; }
+      .o0  { order:  0; }
+      .o1  { order:  1; }
+      .o2  { order:  2; }
+
+      .zn2 { z-index: -2; }
+      .zn1 { z-index: -1; }
+      .z0  { z-index:  0; }
+      .z1  { z-index:  1; }
+
+    </style>
+  </head>
+  <body>
+    <!-- order not set: -->
+    <div class="flexbox">
+      <div class="a"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div>
+
+    <br/>
+
+    <!-- order set, but it matches content order, so it shouldn't matter: -->
+    <div class="flexbox">
+      <div class="a on1"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a o0"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a o0"><div class="aKid"/></div>
+      <div class="b o0"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a o2"><div class="aKid"/></div>
+      <div class="b o2"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a"><div class="aKid"/></div>
+      <div class="b o0"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a"><div class="aKid"/></div>
+      <div class="b o1"><div class="bKid"/></div>
+    </div>
+
+    <br/>
+
+    <!-- order set to reverse of content-order: -->
+    <div class="flexbox">
+      <div class="a o1"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a"><div class="aKid"/></div>
+      <div class="b on1"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a o0"><div class="aKid"/></div>
+      <div class="b on1"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a o2"><div class="aKid"/></div>
+      <div class="b o1"><div class="bKid"/></div>
+    </div>
+
+    <br/>
+
+    <!-- order set to reverse of content-order, AND with z-index set on
+         one or both items, but not such that it changes the paint order -->
+    <div class="flexbox">
+      <div class="a o1 z0"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a o1 z1"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a o1 z0"><div class="aKid"/></div>
+      <div class="b z0"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <div class="a o1 z1"><div class="aKid"/></div>
+      <div class="b z0"><div class="bKid"/></div>
+    </div>
+
+    <br/>
+
+    <!-- order set to reverse of content-order, AND with z-index set on
+         one or both items, in such a way that it affects paint order -->
+    <div class="flexbox">
+      <!-- 'a' is behind the container's border -->
+      <div class="a o1 zn1"><div class="aKid"/></div>
+      <div class="b"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <!-- 'a' and 'b' are both behind the container's border -->
+      <div class="a o1 zn1"><div class="aKid"/></div>
+      <div class="b zn1"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <!-- 'a' and 'b' are both behind the container's border,
+           and 'a' is behind 'b' despite coming after it in the 'order'
+           ordering-->
+      <div class="a o1 zn2"><div class="aKid"/></div>
+      <div class="b zn1"><div class="bKid"/></div>
+    </div
+    ><div class="flexbox">
+      <!-- 'a' and 'b' are both in front of the container's border,
+           and 'a' is behind 'b' despite coming after it in the 'order'
+           ordering-->
+      <div class="a o1 z0"><div class="aKid"/></div>
+      <div class="b z1"><div class="bKid"/></div>
+    </div>
+
+  </body>
+</html>
--- a/layout/reftests/flexbox/reftest.list
+++ b/layout/reftests/flexbox/reftest.list
@@ -53,17 +53,21 @@ fails == flexbox-basic-img-vert-2.xhtml 
 == flexbox-basic-textarea-horiz-2.xhtml flexbox-basic-textarea-horiz-2-ref.xhtml
 == flexbox-basic-textarea-vert-1.xhtml  flexbox-basic-textarea-vert-1-ref.xhtml
 == flexbox-basic-textarea-vert-2.xhtml  flexbox-basic-textarea-vert-2-ref.xhtml
 == flexbox-basic-video-horiz-1.xhtml    flexbox-basic-video-horiz-1-ref.xhtml
 == flexbox-basic-video-horiz-2.xhtml    flexbox-basic-video-horiz-2-ref.xhtml
 == flexbox-basic-video-vert-1.xhtml     flexbox-basic-video-vert-1-ref.xhtml
 fails == flexbox-basic-video-vert-2.xhtml flexbox-basic-video-vert-2-ref.xhtml # bug 794660
 
-# Tests for dynamic modifications to flexboxes
+# Tests for dynamic modifications of content inside a flex container
+== flexbox-dyn-changePadding-1a.xhtml flexbox-dyn-changePadding-1-ref.xhtml
+== flexbox-dyn-changePadding-1b.xhtml flexbox-dyn-changePadding-1-ref.xhtml
+
+# Tests for dynamic insertions of content into a flex container
 # (with existing [div | span | text] inside the flexbox, and new content
 # inserted adjacent to that existing content.)
 == flexbox-dyn-insertAroundDiv-1.xhtml flexbox-dyn-insertAroundDiv-1-ref.xhtml
 == flexbox-dyn-insertAroundDiv-2.xhtml flexbox-dyn-insertAroundDiv-2-ref.xhtml
 == flexbox-dyn-insertAroundDiv-3.xhtml flexbox-dyn-insertAroundDiv-3-ref.xhtml
 
 == flexbox-dyn-insertAroundSpan-1.xhtml flexbox-dyn-insertAroundDiv-1-ref.xhtml
 == flexbox-dyn-insertAroundSpan-2.xhtml flexbox-dyn-insertAroundDiv-2-ref.xhtml
@@ -92,16 +96,17 @@ fails == flexbox-basic-video-vert-2.xhtm
 == flexbox-items-as-stacking-contexts-1.xhtml flexbox-items-as-stacking-contexts-1-ref.xhtml
 
 # Tests for (default) "min-width: auto" / "min-height: auto" in flex containers
 == flexbox-minSize-horiz-1.xhtml flexbox-minSize-horiz-1-ref.xhtml
 == flexbox-minSize-vert-1.xhtml  flexbox-minSize-vert-1-ref.xhtml
 
 # Tests for the order in which we paint flex items
 == flexbox-paint-ordering-1.xhtml flexbox-paint-ordering-1-ref.xhtml
+== flexbox-paint-ordering-2.xhtml flexbox-paint-ordering-2-ref.xhtml
 
 # Tests for handling of absolutely/fixed/relatively-positioned flex items.
 == flexbox-position-absolute-1.xhtml  flexbox-position-absolute-1-ref.xhtml
 == flexbox-position-absolute-2.xhtml  flexbox-position-absolute-2-ref.xhtml
 == flexbox-position-absolute-3.xhtml  flexbox-position-absolute-3-ref.xhtml
 == flexbox-position-absolute-4.xhtml  flexbox-position-absolute-4-ref.xhtml
 == flexbox-position-fixed-3.xhtml     flexbox-position-fixed-3-ref.xhtml
 == flexbox-position-fixed-1.xhtml     flexbox-position-fixed-1-ref.xhtml
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -1294,16 +1294,19 @@ nsRuleNode::nsRuleNode(nsPresContext* aC
   : mPresContext(aContext),
     mParent(aParent),
     mRule(aRule),
     mDependentBits((uint32_t(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
                    (aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
     mNoneBits(0),
     mRefCnt(0)
 {
+  NS_ABORT_IF_FALSE(IsRoot() == !aRule,
+                    "non-root rule nodes must have a rule");
+
   mChildren.asVoid = nullptr;
   MOZ_COUNT_CTOR(nsRuleNode);
   NS_IF_ADDREF(mRule);
 
   NS_ASSERTION(IsRoot() || GetLevel() == aLevel, "not enough bits");
   NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes");
   /* If IsRoot(), then aContext->StyleSet() is typically null at this
      point.  In any case, we don't want to treat the root rulenode as
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -265,41 +265,45 @@ nsTransitionManager::UpdateThrottledStyl
   nsStyleContext* oldStyle = primaryFrame->GetStyleContext();
   nsRuleNode* ruleNode = oldStyle->GetRuleNode();
   nsTArray<nsStyleSet::RuleAndLevel> rules;
   do {
     if (ruleNode->IsRoot()) {
       break;
     }
 
-    nsStyleSet::RuleAndLevel* curRule = rules.AppendElement();
-    curRule->mLevel = ruleNode->GetLevel();
+    nsStyleSet::RuleAndLevel curRule;
+    curRule.mLevel = ruleNode->GetLevel();
 
-    if (curRule->mLevel == nsStyleSet::eAnimationSheet) {
+    if (curRule.mLevel == nsStyleSet::eAnimationSheet) {
       ElementAnimations* ea = 
         mPresContext->AnimationManager()->GetElementAnimations(aElement,
                                                                oldStyle->GetPseudoType(),
                                                                false);
       NS_ASSERTION(ea, "Rule has level eAnimationSheet without animation on manager");
 
       mPresContext->AnimationManager()->EnsureStyleRuleFor(ea);
-      curRule->mRule = ea->mStyleRule;
+      curRule.mRule = ea->mStyleRule;
 
       ForceLayerRerendering(primaryFrame, ea);
-    } else if (curRule->mLevel == nsStyleSet::eTransitionSheet) {
+    } else if (curRule.mLevel == nsStyleSet::eTransitionSheet) {
       ElementTransitions *et =
         GetElementTransitions(aElement, oldStyle->GetPseudoType(), false);
       NS_ASSERTION(et, "Rule has level eTransitionSheet without transition on manager");
       
       et->EnsureStyleRuleFor(mPresContext->RefreshDriver()->MostRecentRefresh());
-      curRule->mRule = et->mStyleRule;
+      curRule.mRule = et->mStyleRule;
 
       ForceLayerRerendering(primaryFrame, et);
     } else {
-      curRule->mRule = ruleNode->GetRule();
+      curRule.mRule = ruleNode->GetRule();
+    }
+
+    if (curRule.mRule) {
+      rules.AppendElement(curRule);
     }
   } while ((ruleNode = ruleNode->GetParent()));
 
   nsRefPtr<nsStyleContext> newStyle = mPresContext->PresShell()->StyleSet()->
     ResolveStyleForRules(aParentStyle, oldStyle, rules);
   primaryFrame->SetStyleContextWithoutNotification(newStyle);
 
   ReparentBeforeAndAfter(aElement, primaryFrame, newStyle, mPresContext->PresShell()->StyleSet());
@@ -324,17 +328,16 @@ nsTransitionManager::UpdateThrottledStyl
   if (element &&
       (et = GetElementTransitions(element,
                                   nsCSSPseudoElements::ePseudo_NotPseudoElement,
                                   false))) {
     // re-resolve our style
     newStyle = UpdateThrottledStyle(element, aParentStyle);
     // remove the current transition from the working set
     et->mFlushGeneration = mPresContext->RefreshDriver()->MostRecentRefresh();
-;
   } else {
     // reparent the element's style
     nsStyleSet* styleSet = mPresContext->PresShell()->StyleSet();
     nsIFrame* primaryFrame = aContent->GetPrimaryFrame();
     if (!primaryFrame) {
       return;
     }
 
--- a/mobile/android/base/AwesomeBarTabs.java
+++ b/mobile/android/base/AwesomeBarTabs.java
@@ -15,20 +15,23 @@ import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.TabHost;
 import android.widget.TabWidget;
 
-public class AwesomeBarTabs extends TabHost {
+public class AwesomeBarTabs extends TabHost
+                            implements LightweightTheme.OnChangeListener { 
     private static final String LOGTAG = "GeckoAwesomeBarTabs";
 
     private Context mContext;
+    private GeckoActivity mActivity;
+
     private boolean mInflated;
     private LayoutInflater mInflater;
     private OnUrlOpenListener mUrlOpenListener;
     private View.OnTouchListener mListTouchListener;
     private boolean mSearching = false;
     private String mTarget;
     private Background mBackground;
     private ViewPager mViewPager;
@@ -100,16 +103,18 @@ public class AwesomeBarTabs extends TabH
     }
 
     public AwesomeBarTabs(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         Log.d(LOGTAG, "Creating AwesomeBarTabs");
 
         mContext = context;
+        mActivity = (GeckoActivity) context;
+
         mInflated = false;
         mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
@@ -169,30 +174,60 @@ public class AwesomeBarTabs extends TabH
         tabWidget.setCurrentTab(0);
 
         styleSelectedTab();
 
         // Initialize "App Pages" list with no filter
         filter("");
     }
 
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mActivity.getLightweightTheme().addListener(this);
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mActivity.getLightweightTheme().removeListener(this);
+    }
+
+    @Override
+    public void onLightweightThemeChanged() {
+        styleSelectedTab();
+    }
+
+    @Override
+    public void onLightweightThemeReset() {
+        styleSelectedTab();
+    }
+
     private void styleSelectedTab() {
         int selIndex = mViewPager.getCurrentItem();
         TabWidget tabWidget = getTabWidget();
+        boolean isPrivate = false;
+
+        if (mTarget != null && mTarget.equals(AwesomeBar.Target.CURRENT_TAB.name())) {
+            Tab tab = Tabs.getInstance().getSelectedTab();
+            if (tab != null)
+                isPrivate = tab.isPrivate();
+        }
 
         for (int i = 0; i < tabWidget.getTabCount(); i++) {
             GeckoTextView view = (GeckoTextView) tabWidget.getChildTabViewAt(i);
-            if (mTarget != null && mTarget.equals(AwesomeBar.Target.CURRENT_TAB.name())) {
-                Tab tab = Tabs.getInstance().getSelectedTab();
-                if (tab != null && tab.isPrivate()) {
-                    if (i == selIndex)
-                        view.setPrivateMode(false);
-                    else
-                        view.setPrivateMode(true);
-                }
+            if (isPrivate) {
+                view.setPrivateMode((i == selIndex) ? false : true);
+            } else {
+                if (i == selIndex)
+                    view.resetTheme();
+                else if (mActivity.getLightweightTheme().isEnabled())
+                    view.setTheme(mActivity.getLightweightTheme().isLightTheme());
+                else
+                    view.resetTheme();
             }
 
             if (i == selIndex)
                 continue;
 
             if (i == (selIndex - 1))
                 view.getBackground().setLevel(1);
             else if (i == (selIndex + 1))
@@ -323,17 +358,17 @@ public class AwesomeBarTabs extends TabH
         public void onLightweightThemeChanged() {
             LightweightThemeDrawable drawable = mActivity.getLightweightTheme().getColorDrawable(this);
             if (drawable == null)
                 return;
 
             drawable.setAlpha(255, 0);
 
             StateListDrawable stateList = new StateListDrawable();
-            stateList.addState(new int[] { R.attr.state_private }, mActivity.getResources().getDrawable(R.drawable.address_bar_bg_private));
+            stateList.addState(new int[] { R.attr.state_private }, mActivity.getResources().getDrawable(R.drawable.abouthome_bg_pb_repeat));
             stateList.addState(new int[] {}, drawable);
 
             int[] padding =  new int[] { getPaddingLeft(),
                                          getPaddingTop(),
                                          getPaddingRight(),
                                          getPaddingBottom()
                                        };
             setBackgroundDrawable(stateList);
--- a/mobile/android/base/LightweightTheme.java
+++ b/mobile/android/base/LightweightTheme.java
@@ -108,28 +108,30 @@ public class LightweightTheme implements
         } catch(java.net.MalformedURLException e) {
             mBitmap = null;
         } catch(java.io.IOException e) {
             mBitmap = null;
         }
     }
 
     public void resetLightweightTheme() {
-        // Reset the bitmap.
-        mBitmap = null;
+        if (mBitmap != null) {
+            // Reset the bitmap.
+            mBitmap = null;
 
-        // Post the reset on the UI thread.
-        for (OnChangeListener listener : mListeners) {
-             final OnChangeListener oneListener = listener;
-             oneListener.post(new Runnable() {
-                 @Override
-                 public void run() {
-                     oneListener.onLightweightThemeReset();
-                 }
-             });
+            // Post the reset on the UI thread.
+            for (OnChangeListener listener : mListeners) {
+                 final OnChangeListener oneListener = listener;
+                 oneListener.post(new Runnable() {
+                     @Override
+                     public void run() {
+                         oneListener.onLightweightThemeReset();
+                     }
+                 });
+            }
         }
     }
 
     public void notifyListeners() {
         if (mBitmap == null)
             return;
 
         // Post the change on the UI thread.
@@ -157,16 +159,31 @@ public class LightweightTheme implements
             } else if (event.equals("LightweightTheme:Disable")) {
                 resetLightweightTheme();
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
+
+    /**
+     * A lightweight theme is enabled only if there is an active bitmap.
+     *
+     * @return True if the theme is enabled.
+     */
+    public boolean isEnabled() {
+        return (mBitmap != null);
+    }
+
+    /**
+     * Based on the luminance of the domanint color, a theme is classified as light or dark.
+     *
+     * @return True if the theme is light.
+     */
     public boolean isLightTheme() {
         return mIsLight;
     }
 
     /**
      * Crop the image based on the position of the view on the window.
      * Either the View or one of its ancestors might have scrolled or translated.
      * This value should be taken into account while mapping the View to the Bitmap.
--- a/mobile/android/base/TabsPanel.java
+++ b/mobile/android/base/TabsPanel.java
@@ -405,16 +405,19 @@ public class TabsPanel extends TabHost
         }
     }
 
     public void hide() {
         if (mVisible) {
             mVisible = false;
             mPopupMenu.dismiss();
             dispatchLayoutChange(0, 0);
+
+            mPanel.hide();
+            mPanel = null;
         }
     }
 
     public void refresh() {
         clearAllTabs();
         removeAllViews();
 
         LayoutInflater.from(mContext).inflate(R.layout.tabs_panel, this);
--- a/mobile/android/base/TabsTray.java
+++ b/mobile/android/base/TabsTray.java
@@ -217,17 +217,17 @@ public class TabsTray extends ListView
         private int getPositionForTab(Tab tab) {
             if (mTabs == null || tab == null)
                 return -1;
 
             return mTabs.indexOf(tab);
         }
 
         private void removeTab(Tab tab) {
-            if (tab.isPrivate() == mIsPrivate) {
+            if (tab.isPrivate() == mIsPrivate && mTabs != null) {
                 mTabs.remove(tab);
                 notifyDataSetChanged(); // Be sure to call this whenever mTabs changes.
             }
         }
 
         private void assignValues(TabRow row, Tab tab) {
             if (row == null || tab == null)
                 return;
--- a/mobile/android/base/resources/color/awesome_bar_title.xml.in
+++ b/mobile/android/base/resources/color/awesome_bar_title.xml.in
@@ -5,12 +5,18 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:gecko="http://schemas.android.com/apk/res/@ANDROID_PACKAGE_NAME@">
 
     <!-- private browsing mode -->
     <item gecko:state_private="true" android:color="#FFDDDDDD" />
 
+    <!-- dark theme -->
+    <item gecko:state_dark="true" android:color="#FFDDDDDD"/>
+
+    <!-- light theme -->
+    <item gecko:state_light="true" android:color="#FF222222"/>
+
     <!-- normal mode -->
     <item android:color="#FF222222"/>
 
 </selector>
index 1a25b9b8d2109024fb8e4c180d3a1c0842f2163c..70b7c58fffc02aa964348a6a2abc1657a56adc36
GIT binary patch
literal 3579
zc$}SAc|4Ts+n=mQL&V8JXbd_r#%yMoVMf!8kz>hDWNQotGovxg7+XZym$K_9mEE+E
zw2(w(O<7wM6%{3MvPIr;-a7C5c|X6;`QyDm&-2{(b=}wZdtdjp{P85)+L+61SJ@5#
z0Awr<lI?}_{;l^H5#d)GIGrq<lsRUu90!&khwH<p0f@e=qco5O!^fXyPxJAOIMzio
z0RTh;=#H)&S8FRAmBrBa*|O2+F+u=a!^D&q;zJFhaX?3D{&XfD{P|7`7)1BQgI&<p
zaO)5fEr5QI&!#!>Z5*lmAS%`uY)Sx`@Nhx`294tb;xU4mp*S8M{5LO7xZYC3z@WcP
zI6-*ue>>%BZ3`l?*fbDY9|fht5eN_lqmM8^V=xFk5E70+!r;OO14S6%&=?%j5cFe!
zg{QH7{c!eV%8#>z5*{4D;e_B|FfNy?&qe98*#0mC7K`2DKq8?+3utHrljFmKGD9_g
zGLUJZR5m??LuWBTTe8nlRu~5l2LHSQBgESJA7W<ck3b1S2IKjJz!3Uy7=r=(X&uV3
zr}_Q6b*N)R2n}XW3uT3|slt5tY5uRH{vEnyDD(z*h)owJ#V44|qJ}YOOpXN^4;Jp|
z`_g@J6eB|l0%2$XH$=iQMhJuv+z3TEfW#89Br_xuh4{(wpRh(~426Wn5DiddA%__f
zYeqtoFeo?)YbKOQ$e&mXW+=ypNu~Y7(*FmG{Z}lG#HRUhSZqfYEBI#x*aomTtk3{f
z2#Dl>0qwK)q0*UK3Z1P4{qU8>riasfDQp%4^ml}D^#9-il7uy&kcdPy9EtdOb20@>
zq+sAiSS*GF{(<%V|3nQYbO!c+%H^j@Sc6;3e~Moy{L?-(rm$z&!sfWEVgCvM*sfzi
zCOYz-af%MJ-x^7aKd*~UOwPEq2_5e_f0nH)GdyH&1_etUjo<-RmmWQe_44wHjk+7N
zvG#TO^Q-0MWz*R2y`yi8VxpP}1j6+4DqOayscHS;tZ*0AmKGfuxp-~I;fvFYO^ab2
z{iDibok}+qRkA7SBMY4o(-Ys;@$$X?9jfPG=KXN854HaIxpxnwH4|ETPjwD;#?=yf
zM^{a1<|9h%_~GcyI>pmzj=^=sF5{UVRUaez{L4w?Q3_e2Qj}|Srau$q8*}Vj{kjRJ
zWz_khVGF87A+W1(dqhs;TcRLLGH>FF<=`T5Hcb^JZd~{-1iFOz{NC?-(P7@XIFxU4
zPuqIsKz(;_d4`v%m)mJC*PJWNhVCbqWLv^W>j^oFlDmt!_$RTsQigxZrcM1e<YkDq
zxm}aeZ$i$VOL5doHyr7b$?cJmv+;M@TU&~ZDsVbxf)CUQyJUAn{oYf#`wbz2nO}f!
z%z^=T5K=hYayfVA;4{no5K~;iTDa&enku6{AUa!*r)Z>uQ(|hreP4Zz*h9IoTC28W
zzJiIu6=dJmJQ-?*w>Ly(ty|_^d?o?zKb`}uU8&t>7Z<-PL#ikAYqrwr+-=7Um3)g-
z=tfGr4Q*@^`%ues(ypN9p!US}!RSsx#q3&u##6zSv<_H3<)X6r?+1nw*^f+2tn}z&
z)MR)Kq)rU+2~!}*{PR0~x_a$vnT?$TQnTM9cVd?3p|Gy<(l^*1va-;B??AlzKDK)L
zP|W_seQoPb+|EOeR}0DClH7Q}s-lMC8(su2v9{X#qE>V2Y2a+f<NQHah@8w3qQbH9
zCt&!R^jv~#rM0za)%_j1ZzKFrWpF`owV3%{aJyQn%22M_5i7C`Fg!<k(rRp9@5Zkg
za!I{Ts{W58_<!bg5g#hp7mLAhLFY@1jR&+}=qezpR@@Cf%HOk*Dkle-fdVBuvt?R2
zVR?k2Mc}WMl6EQ<!;-*PRiE{oRULr^{Ts#G?p?bOIS7r{Jr10VIR)?CV@1B?l2mt8
zLtJoH8KKdhXJ!Ayz8s2jFs2Clo%2Vqv_0MvZxDaQ`KQi~L*ktDbqMe8?0t}dOz7Sd
z=VHI>`N%I*!(qC^k6sRpn_Y0vmQzl=k1MN6xRNe5_^ldC_8kdt1GhWOJPQU$sJQ5J
z#5dR@-2$tDXOZ25k_3WRpEJ6=rE;bGfSr5#uU1{sDxrvzoo}5*F83iJZ{YSW^bzXw
z_pS}4@Z*~+d_hyqRB<k_JoN;6Oh3BN%WO{mkeOFczG<COR-)p3<cZc_$}8bo&JEg4
z^68h~XUz@hP5~J0szeLL>u0OwwxRb!%DjN2z?!1RGuim#9?;fe$v7A{-dpy(!<PUT
z^I)>b&Vcux6{)gD2ARt0YXJG#S<E)aro}gLBU64_8wwTPi>Iyu2}Q&yQ+^4j>{iF+
zG`xI$DIjnXyx=-|k!Lvx&NVh9o1w&v6z;{_9dT$b(r&*Ke#Eh>nqDC1F&}lJ`ctL^
z2f;;$$<fU=b0yEKF740@ziJVr@--o_xOy(6AI3efcc8(PD+#`^GuJ&9RzryYqu@6L
zN4nv_rL{=Nev6#1Z7CDO(^<xPc6zpFBc`vTwNNyaVx{?+%^3p7Rw2f+F!yBZ9=WIY
zz3qC8D~qqT8+=)_v2jur7>F4?t^AN>l^`rftE%n0E__Nhc6{y<_Q{^p<pgmJin`{s
zUo#1j_<dcjZlf(yyl>(LSLKS#QHXSv((CRvTkAzY!ME!m&pl(OsnM}xFQmbL;9O1J
z=fPZ;zJ(p`E@8WT7*puow!FmEOQ1JiTEyW~gC&KoT2)pFHW3RVcW)#IFK`%Vw6_N~
zt`LT|?_%uJ@<hL__@Mu7rFk6q?QqZC(+cYQ(2cAq7a9`x{APo<+{&Fz7C0t4M0aq#
zt-(#zNd85R&1Foxyol6@RFaqRX7eA;RUfTyrCJioO{wW;a-o15RS6JxnMvto`_kd%
z*S~T97}e8HY>iFnLH39%J){EX6DF80hr*(KGCpVtKJA>S^)72(AI@|C_QhB5<@gsM
zQ+G(xr1}I|jgeN(Qiwt6JD-`-oH{Be@_50!M)A>T`}bV^XBCGn-CdMqU+E2i)v(V#
z!PE0!FJ1aVpQRxZo&Fk<sv$H@y;O*BYf!s!tl)m{6L3SxxZ}}-4SGkOXLZb+(lz_I
z<XtU@*j?@-J8KLtQ4DCcnYi(O#Iq)^o_Dh`ZTsphyuOEe$m&`KhnAI|m8)Df^}C7t
zt;R5I<s3kY<Hx5v5*xsLw7lDN_w8(ZbZYWJsirIn-&4cTPTU`Mi{f=^LgG%Lr6ykl
z9Q>QX*%_Sl2EX@apm;sb4j&vI44rt~rQFUqpHi{#d9Pout_N|@85rFAG{N+cgjKUM
zyueOzux>Z0;mpg$mYRsiy)#wkd0gb(E8YxZt;$C;ORi3u9Pn|&%jRS0)?>MDi+@$+
z+E&&0guGboSl9+BcJ5-Z3j5uZx-1?v<|#`^^h<rcdSa*}M<;lvQ~bQ|#ie*xz*Gbd
z@*H6ibXF1a>E^)VJrUXjJ|-s*qivY(wmcE%<ea>C%%gB+f&J*6RTd;|;P7tfGDcB_
zu>=(zcIWj5j$3NFcBnp?6)#wRec)x=EyD}=vS5oq?)lcMyw*U66I8~lRMcAIHM^1K
zqOlSHV&25~y868wJr=Oa-}lvJ<wWxw;Oj2}8-B)hrk;l4HjqaPDI(L~**UtvGB6PG
zAU*Fg=vq4Bd!T8jlE=Hg5q#arydL>HJ~8y%J5h+#k;TUT84D?}+hd&z2~UekWoz@?
zJyMzR1bXcGQAl^2dz`Dp_3>!ToObBa4QbKLFg3lb4;Y%U%#?g}3EXv?!#-d`S=p2$
z{?-}WB!sMzhlcjHoHKzmVwZ}z!g7FJ()9<g6Q*TIM`9H`yA7=OB8!IIOd3v_)#f9D
zunsz<){M+&j}J%xDsCB*LdARNVaC|a-8onC#|Bo<aVo?mWqjXxw&&`&G6(|iIsZ4%
zn=`G=#^PG<{pR{`t&<-eH22Jgmx$FA_Ea)@?3s-z(aLoO9RkJth;p;1gSxd=6{8@X
zq$^AO;<cV)S|U)HFI{%Cd2O%v@{KANbG<2kVph`W2Y($IralZSonhEnHoee-b?VW-
z?41nEy!?GKaOXo2J9D5Y>O<hO$wwXcZYxLGw^b|~x)@hIxxVhPoHY`SB2vHRkV`6{
zqfZ1*oeQOm`BUnBYI!>$xXnxytff)HP;PgkNSX4dmu2pfKy|kz-1KcqlqYtUR_-hf
z4tBsxG!Q)VrCl^MiX!-p-rl8(kfr#U8S5^k;NSPui2j};sE4}ul|+4=xMWy=`FR%B
zIjB@q&29AgP)@U9&$>2+1y^0JUk?*pae?-{<VOxv$Nssr6H6&A3$0?JNSSr+8-f4?
f!F*v;ObJlK+c9n>W;C(&J7!^KL%w{#JN~}_8R#B6
--- a/widget/windows/nsWindowGfx.cpp
+++ b/widget/windows/nsWindowGfx.cpp
@@ -512,17 +512,17 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t
       case LAYERS_OPENGL:
         static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager())->
           SetClippingRegion(region);
         result = listener->PaintWindow(this, region, nsIWidgetListener::SENT_WILL_PAINT | nsIWidgetListener::WILL_SEND_DID_PAINT);
         break;
 #ifdef MOZ_ENABLE_D3D9_LAYER
       case LAYERS_D3D9:
         {
-          LayerManagerD3D9 *layerManagerD3D9 =
+          nsRefPtr<LayerManagerD3D9> layerManagerD3D9 =
             static_cast<mozilla::layers::LayerManagerD3D9*>(GetLayerManager());
           layerManagerD3D9->SetClippingRegion(region);
           result = listener->PaintWindow(this, region, nsIWidgetListener::SENT_WILL_PAINT | nsIWidgetListener::WILL_SEND_DID_PAINT);
           if (layerManagerD3D9->DeviceWasRemoved()) {
             mLayerManager->Destroy();
             mLayerManager = nullptr;
             // When our device was removed, we should have gfxWindowsPlatform
             // check if its render mode is up to date!
@@ -572,16 +572,18 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t
     }
     ::ReleaseDC(mWnd, debugPaintFlashDC);
     ::DeleteObject(debugPaintFlashRegion);
   }
 #endif // WIDGET_DEBUG_OUTPUT
 
   mPainting = false;
 
+  // Re-get the listener since painting may have killed it.
+  listener = GetPaintListener();
   if (listener)
     listener->DidPaintWindow();
 
   if (aNestingLevel == 0 && ::GetUpdateRect(mWnd, NULL, false)) {
     OnPaint(aDC, 1);
   }
 
   return result;
--- a/xpcom/string/public/nsCharTraits.h
+++ b/xpcom/string/public/nsCharTraits.h
@@ -234,42 +234,27 @@ struct nsCharTraits<PRUnichar>
 
         if ( *s2 )
           return -1;
 
         return 0;
       }
 
     /**
-     * Convert c to its lower-case form, but only if the lower-case form is
-     * ASCII. Otherwise leave it alone.
-     *
-     * There are only two non-ASCII Unicode characters whose lowercase
-     * equivalents are ASCII: KELVIN SIGN and LATIN CAPITAL LETTER I WITH
-     * DOT ABOVE. So it's a simple matter to handle those explicitly.
+     * Convert c to its lower-case form, but only if c is in the ASCII
+     * range. Otherwise leave it alone.
      */
     static
     char_type
     ASCIIToLower( char_type c )
       {
-        if (c < 0x100)
-          {
-            if (c >= 'A' && c <= 'Z')
-              return char_type(c + ('a' - 'A'));
+        if (c >= 'A' && c <= 'Z')
+          return char_type(c + ('a' - 'A'));
           
-            return c;
-          }
-        else
-          {
-            if (c == 0x212A) // KELVIN SIGN
-              return 'k';
-            if (c == 0x0130) // LATIN CAPITAL LETTER I WITH DOT ABOVE
-              return 'i';
-            return c;
-          }
+        return c;
       }
 
     static
     int
     compareLowerCaseToASCII( const char_type* s1, const char* s2, size_t n )
       {
         for ( ; n--; ++s1, ++s2 )
           {
--- a/xpcom/string/public/nsTSubstring.h
+++ b/xpcom/string/public/nsTSubstring.h
@@ -294,21 +294,22 @@ class nsTSubstring_CharT
       template<int N>
       inline bool EqualsLiteral( char (&str)[N] ) const
         {
           const char* s = str;
           return EqualsASCII(s, N-1);
         }
 #endif
 
-    // The LowerCaseEquals methods compare the lower case version of
-    // this string to some ASCII/Literal string. The ASCII string is
-    // *not* lowercased for you. If you compare to an ASCII or literal
-    // string that contains an uppercase character, it is guaranteed to
-    // return false. We will throw assertions too.
+    // The LowerCaseEquals methods compare the ASCII-lowercase version of
+    // this string (lowercasing only ASCII uppercase characters) to some
+    // ASCII/Literal string. The ASCII string is *not* lowercased for
+    // you. If you compare to an ASCII or literal string that contains an
+    // uppercase character, it is guaranteed to return false. We will
+    // throw assertions too.
       bool NS_FASTCALL LowerCaseEqualsASCII( const char* data, size_type len ) const;
       bool NS_FASTCALL LowerCaseEqualsASCII( const char* data ) const;
 
     // LowerCaseEqualsLiteral must ONLY be applied to an actual
     // literal string.  Do not attempt to use it with a regular char*
     // pointer, or with a char array variable. Use
     // LowerCaseEqualsASCII for them.
 #ifdef NS_DISABLE_LITERAL_TEMPLATE