Merge m-c to s-c.
authorRichard Newman <rnewman@mozilla.com>
Tue, 18 Dec 2012 11:43:03 -0800
changeset 117360 2aff055f9d1829077423c7c67b85d2d43b7cb442
parent 117359 afa37a092db548a746a3e60e89cd718b4db3052d (current diff)
parent 116382 9de611848111237f46893ccf838fdaa878374523 (diff)
child 117361 5c5e1e93e3a91b5a0a1b2f2fd0ef8346ea64a6a3
push id24098
push userrnewman@mozilla.com
push dateThu, 03 Jan 2013 03:39:06 +0000
treeherdermozilla-central@6955309291ee [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 m-c to s-c.
browser/components/sessionstore/test/browser_819510_perwindowpb.js
content/canvas/test/test_mozIsPointInStroke.html
db/sqlite3/src/test_quota.c
db/sqlite3/src/test_quota.h
docshell/test/chrome/test_bug818371.xul
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElement-null.html
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElement-null.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElement-null.xhtml
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount-dynamic-add.html
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount-dynamic-add.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount-dynamic-add.xhtml
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount-dynamic-remove.html
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount-dynamic-remove.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount-dynamic-remove.xhtml
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount-nochild.html
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount-nochild.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount-nochild.xhtml
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount.html
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-childElementCount.xhtml
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-firstElementChild-entity.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-firstElementChild-entity.xhtml
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-firstElementChild-namespace.html
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-firstElementChild-namespace.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-firstElementChild-namespace.xhtml
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-firstElementChild.html
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-firstElementChild.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-firstElementChild.xhtml
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-lastElementChild.html
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-lastElementChild.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-lastElementChild.xhtml
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-nextElementSibling.html
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-nextElementSibling.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-nextElementSibling.xhtml
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-previousElementSibling.html
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-previousElementSibling.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-previousElementSibling.xhtml
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-siblingElement-null.html
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-siblingElement-null.svg
dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-siblingElement-null.xhtml
dom/indexedDB/FileStream.cpp
dom/indexedDB/FileStream.h
dom/indexedDB/nsIStandardFileStream.idl
dom/interfaces/core/nsIDOMMutationObserver.idl
dom/tests/mochitest/bugs/test_bug317448.html
storage/public/mozIStorageServiceQuotaManagement.idl
--- a/accessible/src/base/AccTypes.h
+++ b/accessible/src/base/AccTypes.h
@@ -9,36 +9,36 @@
 namespace mozilla {
 namespace a11y {
 
 /**
  * Accessible object types used when creating an accessible based on the frame.
  */
 enum AccType {
   eNoType,
-  eHTMLBR,
-  eHTMLButton,
-  eHTMLCanvas,
-  eHTMLCaption,
-  eHTMLCheckbox,
-  eHTMLCombobox,
-  eHTMLFileInput,
-  eHTMLGroupbox,
-  eHTMLHR,
-  eHTMLImageMap,
-  eHTMLLabel,
-  eHTMLLi,
-  eHTMLSelectList,
-  eHTMLMedia,
-  eHTMLRadioButton,
-  eHTMLTable,
-  eHTMLTableCell,
-  eHTMLTableRow,
-  eHTMLTextField,
-  eHyperText,
-  eImage,
-  eOuterDoc,
+  eHTMLBRType,
+  eHTMLButtonType,
+  eHTMLCanvasType,
+  eHTMLCaptionType,
+  eHTMLCheckboxType,
+  eHTMLComboboxType,
+  eHTMLFileInputType,
+  eHTMLGroupboxType,
+  eHTMLHRType,
+  eHTMLImageMapType,
+  eHTMLLabelType,
+  eHTMLLiType,
+  eHTMLSelectListType,
+  eHTMLMediaType,
+  eHTMLRadioButtonType,
+  eHTMLTableType,
+  eHTMLTableCellType,
+  eHTMLTableRowType,
+  eHTMLTextFieldType,
+  eHyperTextType,
+  eImageType,
+  eOuterDocType,
   ePlugin,
-  eTextLeaf
+  eTextLeafType
 };
 }
 }
 
--- a/accessible/src/base/DocManager.cpp
+++ b/accessible/src/base/DocManager.cpp
@@ -25,16 +25,17 @@
 #include "nsIDOMDocument.h"
 #include "nsEventListenerManager.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIWebNavigation.h"
 #include "nsServiceManagerUtils.h"
 
+using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocManager
 ////////////////////////////////////////////////////////////////////////////////
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocManager public
@@ -324,26 +325,26 @@ DocManager::HandleDOMDocumentLoad(nsIDoc
 void
 DocManager::AddListeners(nsIDocument* aDocument,
                          bool aAddDOMContentLoadedListener)
 {
   nsPIDOMWindow *window = aDocument->GetWindow();
   nsIDOMEventTarget *target = window->GetChromeEventHandler();
   nsEventListenerManager* elm = target->GetListenerManager(true);
   elm->AddEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
-                              NS_EVENT_FLAG_CAPTURE);
+                              dom::TrustedEventsAtCapture());
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eDocCreate))
     logging::Text("added 'pagehide' listener");
 #endif
 
   if (aAddDOMContentLoadedListener) {
     elm->AddEventListenerByType(this, NS_LITERAL_STRING("DOMContentLoaded"),
-                                NS_EVENT_FLAG_CAPTURE);
+                                dom::TrustedEventsAtCapture());
 #ifdef A11Y_LOG
     if (logging::IsEnabled(logging::eDocCreate))
       logging::Text("added 'DOMContentLoaded' listener");
 #endif
   }
 }
 
 DocAccessible*
--- a/accessible/src/base/NotificationController.cpp
+++ b/accessible/src/base/NotificationController.cpp
@@ -102,17 +102,17 @@ NotificationController::Shutdown()
   mContentInsertions.Clear();
   mNotifications.Clear();
   mEvents.Clear();
 }
 
 void
 NotificationController::QueueEvent(AccEvent* aEvent)
 {
-  NS_ASSERTION(aEvent->mAccessible && aEvent->mAccessible->IsApplication() ||
+  NS_ASSERTION((aEvent->mAccessible && aEvent->mAccessible->IsApplication()) ||
                aEvent->GetDocAccessible() == mDocument,
                "Queued event belongs to another document!");
 
   if (!mEvents.AppendElement(aEvent))
     return;
 
   // Filter events.
   CoalesceEvents();
@@ -312,18 +312,18 @@ NotificationController::WillRefresh(mozi
       mPresShell->RemoveRefreshObserver(this, Flush_Display)) {
     mObservingState = eNotObservingRefresh;
   }
 }
 
 void
 NotificationController::CoalesceEvents()
 {
-  uint32_t numQueuedEvents = mEvents.Length();
-  int32_t tail = numQueuedEvents - 1;
+  NS_ASSERTION(mEvents.Length(), "There should be at least one pending event!");
+  uint32_t tail = mEvents.Length() - 1;
   AccEvent* tailEvent = mEvents[tail];
 
   switch(tailEvent->mEventRule) {
     case AccEvent::eCoalesceReorder:
       CoalesceReorderEvents(tailEvent);
       break; // case eCoalesceReorder
 
     case AccEvent::eCoalesceMutationTextChange:
@@ -389,18 +389,17 @@ NotificationController::CoalesceEvents()
           return;
         }
       }
     } break; // case eRemoveDupes
 
     case AccEvent::eCoalesceSelectionChange:
     {
       AccSelChangeEvent* tailSelChangeEvent = downcast_accEvent(tailEvent);
-      int32_t index = tail - 1;
-      for (; index >= 0; index--) {
+      for (uint32_t index = tail - 1; index < tail; index--) {
         AccEvent* thisEvent = mEvents[index];
         if (thisEvent->mEventRule == tailEvent->mEventRule) {
           AccSelChangeEvent* thisSelChangeEvent =
             downcast_accEvent(thisEvent);
 
           // Coalesce selection change events within same control.
           if (tailSelChangeEvent->mWidget == thisSelChangeEvent->mWidget) {
             CoalesceSelChangeEvents(tailSelChangeEvent, thisSelChangeEvent, index);
@@ -503,17 +502,17 @@ NotificationController::CoalesceReorderE
     }
 
   } // for (index)
 }
 
 void
 NotificationController::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
                                                 AccSelChangeEvent* aThisEvent,
-                                                int32_t aThisIndex)
+                                                uint32_t aThisIndex)
 {
   aTailEvent->mPreceedingCount = aThisEvent->mPreceedingCount + 1;
 
   // Pack all preceding events into single selection within event
   // when we receive too much selection add/remove events.
   if (aTailEvent->mPreceedingCount >= kSelChangeCountToPack) {
     aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_WITHIN;
     aTailEvent->mAccessible = aTailEvent->mWidget;
--- a/accessible/src/base/NotificationController.h
+++ b/accessible/src/base/NotificationController.h
@@ -209,17 +209,17 @@ private:
    */
   void CoalesceReorderEvents(AccEvent* aTailEvent);
 
   /**
    * Coalesce two selection change events within the same select control.
    */
   void CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
                                AccSelChangeEvent* aThisEvent,
-                               int32_t aThisIndex);
+                               uint32_t aThisIndex);
 
   /**
    * Coalesce text change events caused by sibling hide events.
    */
   void CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
                                    AccHideEvent* aThisEvent);
   void CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
                                    AccShowEvent* aThisEvent);
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -794,53 +794,53 @@ nsAccessibilityService::GetOrCreateAcces
   }
 
   if (!newAcc && isHTML) {  // HTML accessibles
     if (roleMapEntry) {
       // Create pure ARIA grid/treegrid related accessibles if they weren't used
       // on accessible HTML table elements.
       if ((roleMapEntry->accTypes & Accessible::eTableCellAccessible)) {
         if (aContext->IsOfType(Accessible::eTableRowAccessible) &&
-            (frame->AccessibleType() != eHTMLTableCell ||
+            (frame->AccessibleType() != eHTMLTableCellType ||
              aContext->GetContent() != content->GetParent())) {
           newAcc = new ARIAGridCellAccessibleWrap(content, document);
         }
 
       } else if ((roleMapEntry->accTypes & Accessible::eTableAccessible) &&
-                 frame->AccessibleType() != eHTMLTable) {
+                 frame->AccessibleType() != eHTMLTableType) {
         newAcc = new ARIAGridAccessibleWrap(content, document);
       }
     }
 
     if (!newAcc) {
       // Prefer to use markup (mostly tag name, perhaps attributes) to decide if
       // and what kind of accessible to create.
       newAcc = CreateHTMLAccessibleByMarkup(frame, content, aContext);
 
       // Try using frame to do it.
       if (!newAcc)
         newAcc = CreateAccessibleByFrameType(frame, content, aContext);
 
       // If table has strong ARIA role then all table descendants shouldn't
       // expose their native roles.
       if (!roleMapEntry && newAcc) {
-        if (frame->AccessibleType() == eHTMLTableRow) {
+        if (frame->AccessibleType() == eHTMLTableRowType) {
           nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap();
           if (contextRoleMap &&
               !(contextRoleMap->accTypes & Accessible::eTableAccessible))
             roleMapEntry = &nsARIAMap::gEmptyRoleMap;
 
-        } else if (frame->AccessibleType() == eHTMLTableCell &&
+        } else if (frame->AccessibleType() == eHTMLTableCellType &&
                    aContext->ARIARoleMap() == &nsARIAMap::gEmptyRoleMap) {
           roleMapEntry = &nsARIAMap::gEmptyRoleMap;
 
         } else if (content->Tag() == nsGkAtoms::dt ||
                    content->Tag() == nsGkAtoms::li ||
                    content->Tag() == nsGkAtoms::dd ||
-                   frame->AccessibleType() == eHTMLLi) {
+                   frame->AccessibleType() == eHTMLLiType) {
           nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap();
           if (contextRoleMap &&
               !(contextRoleMap->accTypes & Accessible::eListAccessible))
             roleMapEntry = &nsARIAMap::gEmptyRoleMap;
         }
       }
     }
   }
@@ -1303,77 +1303,77 @@ nsAccessibilityService::CreateAccessible
                                                     Accessible* aContext)
 {
   DocAccessible* document = aContext->Document();
 
   nsRefPtr<Accessible> newAcc;
   switch (aFrame->AccessibleType()) {
     case eNoType:
       return nullptr;
-    case eHTMLBR:
+    case eHTMLBRType:
       newAcc = new HTMLBRAccessible(aContent, document);
       break;
-    case eHTMLButton:
+    case eHTMLButtonType:
       newAcc = new HTMLButtonAccessible(aContent, document);
       break;
-    case eHTMLCanvas:
+    case eHTMLCanvasType:
       newAcc = new HTMLCanvasAccessible(aContent, document);
       break;
-    case eHTMLCaption:
+    case eHTMLCaptionType:
       if (aContext->IsOfType(Accessible::eTableAccessible) &&
           aContext->GetContent() == aContent->GetParent()) {
         newAcc = new HTMLCaptionAccessible(aContent, document);
       }
       break;
-    case eHTMLCheckbox:
+    case eHTMLCheckboxType:
       newAcc = new HTMLCheckboxAccessible(aContent, document);
       break;
-    case eHTMLCombobox:
+    case eHTMLComboboxType:
       newAcc = new HTMLComboboxAccessible(aContent, document);
       break;
-    case eHTMLFileInput:
+    case eHTMLFileInputType:
       newAcc = new HTMLFileInputAccessible(aContent, document);
       break;
-    case eHTMLGroupbox:
+    case eHTMLGroupboxType:
       newAcc = new HTMLGroupboxAccessible(aContent, document);
       break;
-    case eHTMLHR:
+    case eHTMLHRType:
       newAcc = new HTMLHRAccessible(aContent, document);
       break;
-    case eHTMLImageMap:
+    case eHTMLImageMapType:
       newAcc = new HTMLImageMapAccessible(aContent, document);
       break;
-    case eHTMLLabel:
+    case eHTMLLabelType:
       newAcc = new HTMLLabelAccessible(aContent, document);
       break;
-    case eHTMLLi:
+    case eHTMLLiType:
       if (aContext->IsOfType(Accessible::eListAccessible) &&
           aContext->GetContent() == aContent->GetParent()) {
         newAcc = new HTMLLIAccessible(aContent, document);
       }
       break;
-    case eHTMLSelectList:
+    case eHTMLSelectListType:
       newAcc = new HTMLSelectListAccessible(aContent, document);
       break;
-    case eHTMLMedia:
+    case eHTMLMediaType:
       newAcc = new EnumRoleAccessible(aContent, document, roles::GROUPING);
       break;
-    case eHTMLRadioButton:
+    case eHTMLRadioButtonType:
       newAcc = new HTMLRadioButtonAccessible(aContent, document);
       break;
-    case eHTMLTable:
+    case eHTMLTableType:
       newAcc = new HTMLTableAccessibleWrap(aContent, document);
       break;
-    case eHTMLTableCell:
+    case eHTMLTableCellType:
       // Accessible HTML table cell must be a child of accessible HTML table row.
       if (aContext->IsOfType(Accessible::eHTMLTableRowAccessible))
         newAcc = new HTMLTableCellAccessibleWrap(aContent, document);
       break;
 
-    case eHTMLTableRow: {
+    case eHTMLTableRowType: {
       // Accessible HTML table row must be a child of tbody/tfoot/thead of
       // accessible HTML table or must be a child of accessible of HTML table.
       if (aContext->IsOfType(Accessible::eTableAccessible)) {
         nsIContent* parentContent = aContent->GetParent();
         nsIFrame* parentFrame = parentContent->GetPrimaryFrame();
         if (parentFrame->GetType() == nsGkAtoms::tableRowGroupFrame) {
           parentContent = parentContent->GetParent();
           parentFrame = parentContent->GetPrimaryFrame();
@@ -1381,36 +1381,36 @@ nsAccessibilityService::CreateAccessible
 
         if (parentFrame->GetType() == nsGkAtoms::tableOuterFrame &&
             aContext->GetContent() == parentContent) {
           newAcc = new HTMLTableRowAccessible(aContent, document);
         }
       }
       break;
     }
-    case eHTMLTextField:
+    case eHTMLTextFieldType:
       newAcc = new HTMLTextFieldAccessible(aContent, document);
       break;
-    case eHyperText:
+    case eHyperTextType:
       if (aContent->Tag() != nsGkAtoms::dt && aContent->Tag() != nsGkAtoms::dd)
         newAcc = new HyperTextAccessibleWrap(aContent, document);
       break;
 
-    case eImage:
+    case eImageType:
       newAcc = new ImageAccessibleWrap(aContent, document);
       break;
-    case eOuterDoc:
+    case eOuterDocType:
       newAcc = new OuterDocAccessible(aContent, document);
       break;
     case ePlugin: {
       nsObjectFrame* objectFrame = do_QueryFrame(aFrame);
       newAcc = CreatePluginAccessible(objectFrame, aContent, aContext);
       break;
     }
-    case eTextLeaf:
+    case eTextLeafType:
       newAcc = new TextLeafAccessibleWrap(aContent, document);
       break;
   }
 
   return newAcc.forget();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/html/HTMLTableAccessible.cpp
+++ b/accessible/src/html/HTMLTableAccessible.cpp
@@ -1,13 +1,15 @@
 /* -*- 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/DebugOnly.h"
+
 #include "HTMLTableAccessible.h"
 
 #include "Accessible-inl.h"
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "DocAccessible.h"
 #include "nsIAccessibleRelation.h"
 #include "nsTextEquivUtils.h"
--- a/accessible/src/msaa/AccessibleWrap.cpp
+++ b/accessible/src/msaa/AccessibleWrap.cpp
@@ -1557,22 +1557,20 @@ AccessibleWrap::HandleAccEvent(AccEvent*
 ////////////////////////////////////////////////////////////////////////////////
 // AccessibleWrap
 
 nsresult
 AccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
 {
   uint32_t eventType = aEvent->GetEventType();
 
-  NS_ENSURE_TRUE(eventType > 0 &&
-                 eventType < nsIAccessibleEvent::EVENT_LAST_ENTRY,
-                 NS_ERROR_FAILURE);
+  MOZ_STATIC_ASSERT(sizeof(gWinEventMap)/sizeof(gWinEventMap[0]) == nsIAccessibleEvent::EVENT_LAST_ENTRY,
+                    "MSAA event map skewed");
 
-  NS_ASSERTION(gWinEventMap[nsIAccessibleEvent::EVENT_LAST_ENTRY] == kEVENT_LAST_ENTRY,
-               "MSAA event map skewed");
+  NS_ENSURE_TRUE(eventType > 0 && eventType < ArrayLength(gWinEventMap), NS_ERROR_FAILURE);
 
   uint32_t winEvent = gWinEventMap[eventType];
   if (!winEvent)
     return NS_OK;
 
   // Means we're not active.
   NS_ENSURE_TRUE(!IsDefunct(), NS_ERROR_FAILURE);
 
--- a/accessible/src/msaa/nsEventMap.h
+++ b/accessible/src/msaa/nsEventMap.h
@@ -4,17 +4,16 @@
 /* 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 <winuser.h>
 #include "AccessibleEventId.h"
 
 const uint32_t kEVENT_WIN_UNKNOWN = 0x00000000;
-const uint32_t kEVENT_LAST_ENTRY  = 0xffffffff;
 
 static const uint32_t gWinEventMap[] = {
   kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent doesn't have 0 constant
   EVENT_OBJECT_SHOW,                                 // nsIAccessibleEvent::EVENT_SHOW
   EVENT_OBJECT_HIDE,                                 // nsIAccessibleEvent::EVENT_HIDE
   EVENT_OBJECT_REORDER,                              // nsIAccessibleEvent::EVENT_REORDER
   IA2_EVENT_ACTIVE_DECENDENT_CHANGED,                // nsIAccessibleEvent::EVENT_ACTIVE_DECENDENT_CHANGED
   EVENT_OBJECT_FOCUS,                                // nsIAccessibleEvent::EVENT_FOCUS
@@ -93,12 +92,11 @@ static const uint32_t gWinEventMap[] = {
   IA2_EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED,     // nsIAccessibleEvent::EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED
   IA2_EVENT_HYPERLINK_SELECTED_LINK_CHANGED,         // nsIAccessibleEvent::EVENT_HYPERLINK_SELECTED_LINK_CHANGED
   IA2_EVENT_HYPERTEXT_LINK_ACTIVATED,                // nsIAccessibleEvent::EVENT_HYPERTEXT_LINK_ACTIVATED
   IA2_EVENT_HYPERTEXT_LINK_SELECTED,                 // nsIAccessibleEvent::EVENT_HYPERTEXT_LINK_SELECTED
   IA2_EVENT_HYPERLINK_START_INDEX_CHANGED,           // nsIAccessibleEvent::EVENT_HYPERLINK_START_INDEX_CHANGED
   IA2_EVENT_HYPERTEXT_CHANGED,                       // nsIAccessibleEvent::EVENT_HYPERTEXT_CHANGED
   IA2_EVENT_HYPERTEXT_NLINKS_CHANGED,                // nsIAccessibleEvent::EVENT_HYPERTEXT_NLINKS_CHANGED
   IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED,                // nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED
-  kEVENT_WIN_UNKNOWN,                                // nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED
-  kEVENT_LAST_ENTRY                                  // nsIAccessibleEvent::EVENT_LAST_ENTRY
+  kEVENT_WIN_UNKNOWN                                 // nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED
 };
 
--- a/accessible/tests/mochitest/editabletext/editabletext.js
+++ b/accessible/tests/mochitest/editabletext/editabletext.js
@@ -29,16 +29,36 @@ function editableTextTestRun()
 }
 
 /**
  * Used to test nsIEditableTextAccessible methods.
  */
 function editableTextTest(aID)
 {
   /**
+   * Schedule a test, the given function with its arguments will be executed
+   * when preceding test is complete.
+   */
+  this.scheduleTest = function scheduleTest(aFunc)
+  {
+    // A data container acts like a dummy invoker, it's never invoked but
+    // it's used to generate real invoker when previous invoker was handled.
+    var dataContainer = {
+      func: aFunc,
+      funcArgs: Array.slice(arguments, 1)
+    };
+    this.mEventQueue.push(dataContainer);
+
+    if (!this.mEventQueueReady) {
+      this.unwrapNextTest();
+      this.mEventQueueReady = true;
+    }
+  }
+
+  /**
    * setTextContents test.
    */
   this.setTextContents = function setTextContents(aValue, aTrailChar)
   {
     var testID = "setTextContents '" + aValue + "' for " + prettyName(aID);
 
     function setTextContentsInvoke()
     {
@@ -46,17 +66,17 @@ function editableTextTest(aID)
       acc.setTextContents(aValue);
     }
 
     var newValue = aValue + (aTrailChar ? aTrailChar : "");
     var insertTripple = newValue ? [0, newValue.length, newValue] : null;
     var oldValue = getValue(aID);
     var removeTripple = oldValue ? [0, oldValue.length, oldValue] : null;
 
-    this.scheduleTest(aID, removeTripple, insertTripple, setTextContentsInvoke,
+    this.generateTest(aID, removeTripple, insertTripple, setTextContentsInvoke,
                       getValueChecker(aID, aValue), testID);
   }
 
   /**
    * insertText test.
    */
   this.insertText = function insertText(aStr, aPos, aResStr, aResPos)
   {
@@ -65,17 +85,17 @@ function editableTextTest(aID)
 
     function insertTextInvoke()
     {
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.insertText(aStr, aPos);
     }
 
     var resPos = (aResPos != undefined) ? aResPos : aPos;
-    this.scheduleTest(aID, null, [resPos, resPos + aStr.length, aStr],
+    this.generateTest(aID, null, [resPos, resPos + aStr.length, aStr],
                       insertTextInvoke, getValueChecker(aID, aResStr), testID);
   }
 
   /**
    * copyText test.
    */
   this.copyText = function copyText(aStartPos, aEndPos, aClipboardStr)
   {
@@ -83,17 +103,17 @@ function editableTextTest(aID)
       prettyName(aID);
 
     function copyTextInvoke()
     {
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.copyText(aStartPos, aEndPos);
     }
 
-    this.scheduleTest(aID, null, null, copyTextInvoke,
+    this.generateTest(aID, null, null, copyTextInvoke,
                       getClipboardChecker(aID, aClipboardStr), testID);
   }
 
   /**
    * copyText and pasteText test.
    */
   this.copyNPasteText = function copyNPasteText(aStartPos, aEndPos,
                                                 aPos, aResStr)
@@ -103,17 +123,17 @@ function editableTextTest(aID)
 
     function copyNPasteTextInvoke()
     {
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.copyText(aStartPos, aEndPos);
       acc.pasteText(aPos);
     }
 
-    this.scheduleTest(aID, null, [aStartPos, aEndPos, getTextFromClipboard],
+    this.generateTest(aID, null, [aStartPos, aEndPos, getTextFromClipboard],
                       copyNPasteInvoke, getValueChecker(aID, aResStr), testID);
   }
 
   /**
    * cutText test.
    */
   this.cutText = function cutText(aStartPos, aEndPos, aResStr,
                                   aResStartPos, aResEndPos)
@@ -124,17 +144,17 @@ function editableTextTest(aID)
     function cutTextInvoke()
     {
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.cutText(aStartPos, aEndPos);
     }
 
     var resStartPos = (aResStartPos != undefined) ? aResStartPos : aStartPos;
     var resEndPos = (aResEndPos != undefined) ? aResEndPos : aEndPos;
-    this.scheduleTest(aID, [resStartPos, resEndPos, getTextFromClipboard], null,
+    this.generateTest(aID, [resStartPos, resEndPos, getTextFromClipboard], null,
                       cutTextInvoke, getValueChecker(aID, aResStr), testID);
   }
 
   /**
    * cutText and pasteText test.
    */
   this.cutNPasteText = function copyNPasteText(aStartPos, aEndPos,
                                                aPos, aResStr)
@@ -144,17 +164,17 @@ function editableTextTest(aID)
 
     function cutNPasteTextInvoke()
     {
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.cutText(aStartPos, aEndPos);
       acc.pasteText(aPos);
     }
 
-    this.scheduleTest(aID, [aStartPos, aEndPos, getTextFromClipboard],
+    this.generateTest(aID, [aStartPos, aEndPos, getTextFromClipboard],
                       [aPos, -1, getTextFromClipboard],
                       cutNPasteTextInvoke, getValueChecker(aID, aResStr),
                       testID);
   }
 
   /**
    * pasteText test.
    */
@@ -163,54 +183,39 @@ function editableTextTest(aID)
     var testID = "pasteText at " + aPos + " for " + prettyName(aID);
 
     function pasteTextInvoke()
     {
       var acc = getAccessible(aID, nsIAccessibleEditableText);
       acc.pasteText(aPos);
     }
 
-    this.scheduleTest(aID, null, [aPos, -1, getTextFromClipboard],
+    this.generateTest(aID, null, [aPos, -1, getTextFromClipboard],
                       pasteTextInvoke, getValueChecker(aID, aResStr), testID);
   }
 
   /**
    * deleteText test.
    */
   this.deleteText = function deleteText(aStartPos, aEndPos, aResStr)
   {
-    function getRemovedText() { return invoker.removedText; }
-
-    var invoker = {
-      eventSeq: [
-        new textChangeChecker(aID, aStartPos, aEndPos, getRemovedText, false)
-      ],
+    var testID = "deleteText from " + aStartPos + " to " + aEndPos +
+      " for " + prettyName(aID);
 
-      invoke: function invoke()
-      {
-        var acc = getAccessible(aID,
-                               [nsIAccessibleText, nsIAccessibleEditableText]);
-
-        this.removedText = acc.getText(aStartPos, aEndPos);
+    var oldValue = getValue(aID).substring(aStartPos, aEndPos);
+    var removeTripple = oldValue ? [aStartPos, aEndPos, oldValue] : null;
 
-        acc.deleteText(aStartPos, aEndPos);
-      },
-
-      finalCheck: function finalCheck()
-      {
-        getValueChecker(aID, aResStr).check();
-      },
+    function deleteTextInvoke()
+    {
+      var acc = getAccessible(aID, [nsIAccessibleEditableText]);
+      acc.deleteText(aStartPos, aEndPos);
+    }
 
-      getID: function getID()
-      {
-        return "deleteText from " + aStartPos + " to " + aEndPos + " for " +
-          prettyName(aID);
-      }
-    };
-    this.mEventQueue.push(invoker);
+    this.generateTest(aID, removeTripple, null, deleteTextInvoke,
+                      getValueChecker(aID, aResStr), testID);
   }
 
   //////////////////////////////////////////////////////////////////////////////
   // Implementation details.
 
   function getValue(aID)
   {
     var value = "";
@@ -260,26 +265,41 @@ function editableTextTest(aID)
         valueChecker.check();
         clipboardChecker.check();
       }
     };
     return checker;
   }
 
   /**
-   * Create an invoker for the test and push it into event queue.
+   * Process next scheduled test.
    */
-  this.scheduleTest = function scheduleTest(aID, aRemoveTriple, aInsertTriple,
+  this.unwrapNextTest = function unwrapNextTest()
+  {
+    var data = this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1];
+    if (data)
+      data.func.apply(this, data.funcArgs);
+  }
+
+  /**
+   * Used to generate an invoker object for the sheduled test.
+   */
+  this.generateTest = function generateTest(aID, aRemoveTriple, aInsertTriple,
                                             aInvokeFunc, aChecker, aInvokerID)
   {
+    var et = this;
     var invoker = {
       eventSeq: [],
 
       invoke: aInvokeFunc,
-      finalCheck: function finalCheck() { aChecker.check(); },
+      finalCheck: function finalCheck()
+      {
+        aChecker.check();
+        et.unwrapNextTest(); // replace dummy invoker on real invoker object.
+      },
       getID: function getID() { return aInvokerID; }
     };
 
     if (aRemoveTriple) {
       var checker = new textChangeChecker(aID, aRemoveTriple[0],
                                           aRemoveTriple[1], aRemoveTriple[2],
                                           false);
       invoker.eventSeq.push(checker);
@@ -287,17 +307,17 @@ function editableTextTest(aID)
 
     if (aInsertTriple) {
       var checker = new textChangeChecker(aID, aInsertTriple[0],
                                           aInsertTriple[1], aInsertTriple[2],
                                           true);
       invoker.eventSeq.push(checker);
     }
 
-    this.mEventQueue.push(invoker);
+    this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1] = invoker;
   }
 
   /**
    * Run the tests.
    */
   this.startTest = function startTest(aTestRun)
   {
     var testRunObj = aTestRun;
@@ -313,10 +333,11 @@ function editableTextTest(aID)
 
       return DO_NOT_FINISH_TEST;
     }
 
     this.mEventQueue.invoke();
   }
 
   this.mEventQueue = new eventQueue();
+  this.mEventQueueReady = false;
 }
 
--- a/accessible/tests/mochitest/editabletext/test_1.html
+++ b/accessible/tests/mochitest/editabletext/test_1.html
@@ -20,26 +20,26 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   <script type="application/javascript">
     function addTestEditable(aID, aTestRun, aTrailChar)
     {
       var et = new editableTextTest(aID);
 
       //////////////////////////////////////////////////////////////////////////
       // setTextContents
-      et.setTextContents("hello");
-      et.setTextContents("olleh", aTrailChar); // due to some reason this reports '\n' in the end
-      et.setTextContents("");
+      et.scheduleTest(et.setTextContents, "hello");
+      et.scheduleTest(et.setTextContents, "olleh", aTrailChar); // due to some reason this reports '\n' in the end
+      et.scheduleTest(et.setTextContents, "");
 
       //////////////////////////////////////////////////////////////////////////
       // insertText
-      et.insertText("hello", 0, "hello");
-      et.insertText("ma ", 0, "ma hello");
-      et.insertText("ma", 2, "mama hello");
-      et.insertText(" hello", 10, "mama hello hello");
+      et.scheduleTest(et.insertText, "hello", 0, "hello");
+      et.scheduleTest(et.insertText, "ma ", 0, "ma hello");
+      et.scheduleTest(et.insertText, "ma", 2, "mama hello");
+      et.scheduleTest(et.insertText, " hello", 10, "mama hello hello");
 
       // XXX: bug 452584
 
       //////////////////////////////////////////////////////////////////////////
       // deleteText
 //      et.deleteText(0, 5, "hello hello");
 //      et.deleteText(5, 6, "hellohello");
 //      et.deleteText(5, 10, "hello");
--- a/accessible/tests/mochitest/editabletext/test_2.html
+++ b/accessible/tests/mochitest/editabletext/test_2.html
@@ -17,24 +17,24 @@
 
   <script type="application/javascript">
     function doTest()
     {
       var et = new editableTextTest("input");
 
       // 'ee' insertion/removal at 1 or 2 offset of 'hello'/'heeello' string
       // reports 'ee' text was inserted/removed at 2 offset.
-      et.insertText("ee", 1, "heeello", 2);
-      et.copyText(1, 3, "ee");
-      et.cutText(1, 3, "hello", 2, 4);
-      et.insertText("ee", 2, "heeello", 2);
-      et.cutText(2, 4, "hello", 2, 4);
+      et.scheduleTest(et.insertText, "ee", 1, "heeello", 2);
+      et.scheduleTest(et.copyText, 1, 3, "ee");
+      et.scheduleTest(et.cutText, 1, 3, "hello", 2, 4);
+      et.scheduleTest(et.insertText, "ee", 2, "heeello", 2);
+      et.scheduleTest(et.cutText, 2, 4, "hello", 2, 4);
 
-      et.deleteText(1, 3, "hlo");
-      et.pasteText(1, "heelo");
+      et.scheduleTest(et.deleteText, 1, 3, "hlo");
+      et.scheduleTest(et.pasteText, 1, "heelo");
 
       var testRun = new editableTextTestRun();
       testRun.add(et);
       testRun.run(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -169,17 +169,18 @@ pref("geo.enabled", true);
 // see https://bugzilla.mozilla.org/show_bug.cgi?id=481566#c9
 pref("content.sink.enable_perf_mode",  2); // 0 - switch, 1 - interactive, 2 - perf
 pref("content.sink.pending_event_mode", 0);
 pref("content.sink.perf_deflect_count", 1000000);
 pref("content.sink.perf_parse_time", 50000000);
 
 // Maximum scripts runtime before showing an alert
 pref("dom.max_chrome_script_run_time", 0); // disable slow script dialog for chrome
-pref("dom.max_script_run_time", 20);
+// Bug 817230 - disable the dialog until we implement its checkbox properly
+pref("dom.max_script_run_time", 0);
 
 // plugins
 pref("plugin.disable", true);
 pref("dom.ipc.plugins.enabled", true);
 
 // product URLs
 // The breakpad report server to link to in about:crashes
 pref("breakpad.reportURL", "http://crash-stats.mozilla.com/report/index/");
@@ -476,16 +477,24 @@ pref("app.update.service.enabled", true)
 pref("app.update.url", "http://update.boot2gecko.org/%CHANNEL%/update.xml");
 pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@");
 
 // Interval at which update manifest is fetched.  In units of seconds.
 pref("app.update.interval", 86400); // 1 day
 // Don't throttle background updates.
 pref("app.update.download.backgroundInterval", 0);
 
+// Retry update socket connections every 30 seconds in the cases of certain kinds of errors
+pref("app.update.socket.retryTimeout", 30000);
+
+// Max of 20 consecutive retries (total 10 minutes) before giving up and marking
+// the update download as failed.
+// Note: Offline errors will always retry when the network comes online.
+pref("app.update.socket.maxErrors", 20);
+
 // Enable update logging for now, to diagnose growing pains in the
 // field.
 pref("app.update.log", true);
 #else
 // Explicitly disable the shutdown watchdog.  It's enabled by default.
 // When the updater is disabled, we want to know about shutdown hangs.
 pref("shutdown.watchdog.timeoutSecs", -1);
 #endif
--- a/b2g/components/ProcessGlobal.js
+++ b/b2g/components/ProcessGlobal.js
@@ -17,16 +17,19 @@
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 
+// Preloading the CSP jsm in this process early on.
+Cu.import("resource://gre/modules/CSPUtils.jsm");
+
 function debug(msg) {
   log(msg);
 }
 function log(msg) {
   // This file implements console.log(), so use dump().
   //dump('ProcessGlobal: ' + msg + '\n');
 }
 
--- a/browser/base/content/browser-charsetmenu.inc
+++ b/browser/base/content/browser-charsetmenu.inc
@@ -127,31 +127,16 @@
             <menupopup>
             <menuitem uri="..." label="rdf:http://home.netscape.com/NC-rdf#Name"/>
             </menupopup>
           </rule>
         </template>
         <menupopup>
         </menupopup>
       </menu>
-      <menu label="&charsetMenuUnicode.label;"
-#ifndef OMIT_ACCESSKEYS
-            accesskey="&charsetMenuUnicode.accesskey;"
-#endif
-            datasources="rdf:charset-menu" ref="NC:BrowserUnicodeCharsetMenuRoot">
-        <template>
-          <rule>
-            <menupopup>
-            <menuitem uri="..." label="rdf:http://home.netscape.com/NC-rdf#Name"/>
-            </menupopup>
-          </rule>
-        </template>
-        <menupopup>
-        </menupopup>
-      </menu>
       <menuseparator />
     </menupopup>
   </menu>
   <menuitem name="charsetCustomize"
 #ifndef OMIT_ACCESSKEYS
             accesskey="&charsetCustomize.accesskey;"
 #endif
             label="&charsetCustomize.label;"
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -1,73 +1,71 @@
 # -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-const PLUGIN_SCRIPTED_STATE_NONE = 0;
-const PLUGIN_SCRIPTED_STATE_FIRED = 1;
-const PLUGIN_SCRIPTED_STATE_DONE = 2;
-
-function getPluginInfo(pluginElement)
-{
-  var tagMimetype;
-  var pluginsPage;
-  var pluginName = gNavigatorBundle.getString("pluginInfo.unknownPlugin");
-  if (pluginElement instanceof HTMLAppletElement) {
-    tagMimetype = "application/x-java-vm";
-  } else {
-    if (pluginElement instanceof HTMLObjectElement) {
-      pluginsPage = pluginElement.getAttribute("codebase");
-    } else {
-      pluginsPage = pluginElement.getAttribute("pluginspage");
-    }
-
-    // only attempt if a pluginsPage is defined.
-    if (pluginsPage) {
-      var doc = pluginElement.ownerDocument;
-      var docShell = findChildShell(doc, gBrowser.docShell, null);
-      try {
-        pluginsPage = makeURI(pluginsPage, doc.characterSet, docShell.currentURI).spec;
-      } catch (ex) {
-        pluginsPage = "";
-      }
-    }
-
-    tagMimetype = pluginElement.QueryInterface(Components.interfaces.nsIObjectLoadingContent)
-                               .actualType;
-
-    if (tagMimetype == "") {
-      tagMimetype = pluginElement.type;
-    }
-  }
-
-  if (tagMimetype) {
-    let navMimeType = navigator.mimeTypes.namedItem(tagMimetype);
-    if (navMimeType && navMimeType.enabledPlugin) {
-      pluginName = navMimeType.enabledPlugin.name;
-      pluginName = gPluginHandler.makeNicePluginName(pluginName);
-    }
-  }
-
-  return { mimetype: tagMimetype,
-           pluginsPage: pluginsPage,
-           pluginName: pluginName };
-}
-
 var gPluginHandler = {
+  PLUGIN_SCRIPTED_STATE_NONE: 0,
+  PLUGIN_SCRIPTED_STATE_FIRED: 1,
+  PLUGIN_SCRIPTED_STATE_DONE: 2,
 
 #ifdef MOZ_CRASHREPORTER
   get CrashSubmit() {
     delete this.CrashSubmit;
     Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
     return this.CrashSubmit;
   },
 #endif
 
+  _getPluginInfo: function (pluginElement) {
+    let tagMimetype;
+    let pluginsPage;
+    let pluginName = gNavigatorBundle.getString("pluginInfo.unknownPlugin");
+    if (pluginElement instanceof HTMLAppletElement) {
+      tagMimetype = "application/x-java-vm";
+    } else {
+      if (pluginElement instanceof HTMLObjectElement) {
+        pluginsPage = pluginElement.getAttribute("codebase");
+      } else {
+        pluginsPage = pluginElement.getAttribute("pluginspage");
+      }
+
+      // only attempt if a pluginsPage is defined.
+      if (pluginsPage) {
+        let doc = pluginElement.ownerDocument;
+        let docShell = findChildShell(doc, gBrowser.docShell, null);
+        try {
+          pluginsPage = makeURI(pluginsPage, doc.characterSet, docShell.currentURI).spec;
+        } catch (ex) {
+          pluginsPage = "";
+        }
+      }
+
+      tagMimetype = pluginElement.QueryInterface(Ci.nsIObjectLoadingContent)
+                                 .actualType;
+
+      if (tagMimetype == "") {
+        tagMimetype = pluginElement.type;
+      }
+    }
+
+    if (tagMimetype) {
+      let navMimeType = navigator.mimeTypes.namedItem(tagMimetype);
+      if (navMimeType && navMimeType.enabledPlugin) {
+        pluginName = navMimeType.enabledPlugin.name;
+        pluginName = gPluginHandler.makeNicePluginName(pluginName);
+      }
+    }
+
+    return { mimetype: tagMimetype,
+             pluginsPage: pluginsPage,
+             pluginName: pluginName };
+  },
+
   // Map the plugin's name to a filtered version more suitable for user UI.
   makeNicePluginName : function (aName) {
     if (aName == "Shockwave Flash")
       return "Adobe Flash";
 
     // Clean up the plugin name by stripping off any trailing version numbers
     // or "plugin". EG, "Foo Bar Plugin 1.23_02" --> "Foo Bar"
     // Do this by first stripping the numbers, etc. off the end, and then
@@ -206,17 +204,17 @@ var gPluginHandler = {
         let updateLink = doc.getAnonymousElementByAttribute(plugin, "class", "checkForUpdatesLink");
         self.addLinkClickCallback(updateLink, "openPluginUpdatePage");
         /* FALLTHRU */
 
       case "PluginVulnerableNoUpdate":
       case "PluginClickToPlay":
         self._handleClickToPlayEvent(plugin);
         let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
-        let pluginName = getPluginInfo(plugin).pluginName;
+        let pluginName = self._getPluginInfo(plugin).pluginName;
         let messageString = gNavigatorBundle.getFormattedString("PluginClickToPlay", [pluginName]);
         let overlayText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgClickToPlay");
         overlayText.textContent = messageString;
         if (eventType == "PluginVulnerableUpdatable" ||
             eventType == "PluginVulnerableNoUpdate") {
           let vulnerabilityString = gNavigatorBundle.getString(eventType);
           let vulnerabilityText = doc.getAnonymousElementByAttribute(plugin, "anonid", "vulnerabilityStatus");
           vulnerabilityText.textContent = vulnerabilityString;
@@ -229,18 +227,18 @@ var gPluginHandler = {
 
       case "PluginDisabled":
         let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink");
         self.addLinkClickCallback(manageLink, "managePlugins");
         break;
 
       case "PluginScripted":
         let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
-        if (browser._pluginScriptedState == PLUGIN_SCRIPTED_STATE_NONE) {
-          browser._pluginScriptedState = PLUGIN_SCRIPTED_STATE_FIRED;
+        if (browser._pluginScriptedState == this.PLUGIN_SCRIPTED_STATE_NONE) {
+          browser._pluginScriptedState = this.PLUGIN_SCRIPTED_STATE_FIRED;
           setTimeout(function() {
             gPluginHandler.handlePluginScripted(this);
           }.bind(browser), 500);
         }
         break;
     }
 
     // Hide the in-content UI if it's too big. The crashed plugin handler already did this.
@@ -280,17 +278,17 @@ var gPluginHandler = {
 
     let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
     if (notification && !haveVisibleCTPPlugin && !this._notificationDisplayedOnce) {
       notification.dismissed = false;
       PopupNotifications._update(notification.anchorElement);
       this._notificationDisplayedOnce = true;
     }
 
-    aBrowser._pluginScriptedState = PLUGIN_SCRIPTED_STATE_DONE;
+    aBrowser._pluginScriptedState = this.PLUGIN_SCRIPTED_STATE_DONE;
   },
 
   isKnownPlugin: function PH_isKnownPlugin(objLoadingContent) {
     return (objLoadingContent.getContentTypeForMIMEType(objLoadingContent.actualType) ==
             Ci.nsIObjectLoadingContent.TYPE_PLUGIN);
   },
 
   canActivatePlugin: function PH_canActivatePlugin(objLoadingContent) {
@@ -333,17 +331,16 @@ var gPluginHandler = {
       objLoadingContent.playPlugin();
 
     let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIDOMWindowUtils);
     let pluginNeedsActivation = gPluginHandler._pluginNeedsActivationExceptThese([aPlugin]);
     let browser = gBrowser.getBrowserForDocument(aContentWindow.document);
     let notification = PopupNotifications.getNotification("click-to-play-plugins", browser);
     if (notification) {
-      browser._clickToPlayDoorhangerShown = false;
       notification.remove();
     }
     if (pluginNeedsActivation) {
       gPluginHandler._showClickToPlayNotification(browser);
     }
   },
 
   stopPlayPreview: function PH_stopPlayPreview(aPlugin, aPlayPlugin) {
@@ -371,17 +368,17 @@ var gPluginHandler = {
     // reload the browser to make the new plugin show.
     browser.reload();
   },
 
   // Callback for user clicking on a missing (unsupported) plugin.
   installSinglePlugin: function (plugin) {
     var missingPlugins = new Map();
 
-    var pluginInfo = getPluginInfo(plugin);
+    var pluginInfo = this._getPluginInfo(plugin);
     missingPlugins.set(pluginInfo.mimetype, pluginInfo);
 
     openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
                "PFSWindow", "chrome,centerscreen,resizable=yes",
                {plugins: missingPlugins, browser: gBrowser.selectedBrowser});
   },
 
   // Callback for user clicking on a disabled plugin
@@ -449,34 +446,33 @@ var gPluginHandler = {
             aEvent.button == 0 && aEvent.isTrusted) {
           gPluginHandler.activateSinglePlugin(aEvent.target.ownerDocument.defaultView.top, aPlugin);
           aEvent.stopPropagation();
           aEvent.preventDefault();
         }
       }, true);
     }
 
-    if (!browser._clickToPlayDoorhangerShown)
-      gPluginHandler._showClickToPlayNotification(browser);
+    gPluginHandler._showClickToPlayNotification(browser);
   },
 
   _handlePlayPreviewEvent: function PH_handlePlayPreviewEvent(aPlugin) {
     let doc = aPlugin.ownerDocument;
     let previewContent = doc.getAnonymousElementByAttribute(aPlugin, "class", "previewPluginContent");
     let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
     if (!iframe) {
       // lazy initialization of the iframe
       iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
       iframe.className = "previewPluginContentFrame";
       previewContent.appendChild(iframe);
 
       // Force a style flush, so that we ensure our binding is attached.
       aPlugin.clientTop;
     }
-    let pluginInfo = getPluginInfo(aPlugin);
+    let pluginInfo = this._getPluginInfo(aPlugin);
     let playPreviewUri = "data:application/x-moz-playpreview;," + pluginInfo.mimetype;
     iframe.src = playPreviewUri;
 
     // MozPlayPlugin event can be dispatched from the extension chrome
     // code to replace the preview content with the native plugin
     previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(aEvent) {
       if (!aEvent.isTrusted)
         return;
@@ -515,34 +511,34 @@ var gPluginHandler = {
   },
 
   /* Gets all plugins currently in the page of the given name */
   _getPluginsByName: function PH_getPluginsByName(aDOMWindowUtils, aName) {
     let plugins = [];
     for (let plugin of aDOMWindowUtils.plugins) {
       let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
       if (gPluginHandler.canActivatePlugin(objLoadingContent)) {
-        let pluginName = getPluginInfo(plugin).pluginName;
+        let pluginName = this._getPluginInfo(plugin).pluginName;
         if (aName == pluginName) {
           plugins.push(objLoadingContent);
         }
       }
     }
     return plugins;
   },
 
   _makeCenterActions: function PH_makeCenterActions(aBrowser) {
     let contentWindow = aBrowser.contentWindow;
     let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIDOMWindowUtils);
     let pluginsDictionary = new Map();
     for (let plugin of cwu.plugins) {
       let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
       if (gPluginHandler.canActivatePlugin(objLoadingContent)) {
-        let pluginName = getPluginInfo(plugin).pluginName;
+        let pluginName = this._getPluginInfo(plugin).pluginName;
         if (!pluginsDictionary.has(pluginName))
           pluginsDictionary.set(pluginName, []);
         pluginsDictionary.get(pluginName).push(objLoadingContent);
       }
     }
 
     let centerActions = [];
     for (let [pluginName, namedPluginArray] of pluginsDictionary) {
@@ -598,19 +594,17 @@ var gPluginHandler = {
       if (gPluginHandler.canActivatePlugin(objLoadingContent)) {
         let permissionString = pluginHost.getPermissionStringForType(objLoadingContent.actualType);
         Services.perms.add(aBrowser.currentURI, permissionString, aPermission);
       }
     }
   },
 
   _showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser) {
-    aBrowser._clickToPlayDoorhangerShown = true;
     let contentWindow = aBrowser.contentWindow;
-
     let messageString = gNavigatorBundle.getString("activatePluginsMessage.message");
     let mainAction = {
       label: gNavigatorBundle.getString("activateAllPluginsMessage.label"),
       accessKey: gNavigatorBundle.getString("activatePluginsMessage.accesskey"),
       callback: function() { gPluginHandler.activatePlugins(contentWindow); }
     };
     let centerActions = gPluginHandler._makeCenterActions(aBrowser);
     let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
@@ -665,17 +659,17 @@ var gPluginHandler = {
 
   // event listener for missing/blocklisted/outdated/carbonFailure plugins.
   pluginUnavailable: function (plugin, eventType) {
     let browser = gBrowser.getBrowserForDocument(plugin.ownerDocument
                                                        .defaultView.top.document);
     if (!browser.missingPlugins)
       browser.missingPlugins = new Map();
 
-    var pluginInfo = getPluginInfo(plugin);
+    var pluginInfo = this._getPluginInfo(plugin);
     browser.missingPlugins.set(pluginInfo.mimetype, pluginInfo);
 
     var notificationBox = gBrowser.getNotificationBox(browser);
 
     // Should only display one of these warnings per page.
     // In order of priority, they are: outdated > missing > blocklisted
     let outdatedNotification = notificationBox.getNotificationWithValue("outdated-plugins");
     let blockedNotification  = notificationBox.getNotificationWithValue("blocked-plugins");
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2316,16 +2316,20 @@ function BrowserPageInfo(doc, initialTab
 }
 
 function URLBarSetURI(aURI) {
   var value = gBrowser.userTypedValue;
   var valid = false;
 
   if (value == null) {
     let uri = aURI || gBrowser.currentURI;
+    // Strip off "wyciwyg://" and passwords for the location bar
+    try {
+      uri = Services.uriFixup.createExposableURI(uri);
+    } catch (e) {}
 
     // Replace initial page URIs with an empty string
     // only if there's no opener (bug 370555).
     if (gInitialPages.indexOf(uri.spec) != -1)
       value = content.opener ? uri.spec : "";
     else
       value = losslessDecodeURI(uri);
 
@@ -3490,17 +3494,17 @@ function OpenBrowserWindow(options)
   var charsetArg = new String();
   var handler = Components.classes["@mozilla.org/browser/clh;1"]
                           .getService(Components.interfaces.nsIBrowserHandler);
   var defaultArgs = handler.defaultArgs;
   var wintype = document.documentElement.getAttribute('windowtype');
 
   var extraFeatures = "";
 #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
-  if (typeof options == "object" && options.private) {
+  if (options && options.private) {
 #else
   if (gPrivateBrowsingUI.privateBrowsingEnabled) {
 #endif
     extraFeatures = ",private";
     // Force the new window to load about:privatebrowsing instead of the default home page
     defaultArgs = "about:privatebrowsing";
   } else {
     extraFeatures = ",non-private";
@@ -3796,21 +3800,16 @@ var XULBrowserWindow = {
   get statusTextField () {
     delete this.statusTextField;
     return this.statusTextField = document.getElementById("statusbar-display");
   },
   get isImage () {
     delete this.isImage;
     return this.isImage = document.getElementById("isImage");
   },
-  get _uriFixup () {
-    delete this._uriFixup;
-    return this._uriFixup = Cc["@mozilla.org/docshell/urifixup;1"]
-                              .getService(Ci.nsIURIFixup);
-  },
 
   init: function () {
     this.throbberElement = document.getElementById("navigator-throbber");
 
 #ifdef MOZ_E10S_COMPAT
     // Bug 666809 - SecurityUI support for e10s
 #else
     // Initialize the security button's state and tooltip text.  Remember to reset
@@ -4094,22 +4093,17 @@ var XULBrowserWindow = {
           location == "") {  // Second condition is for new tabs, otherwise
                              // reload function is enabled until tab is refreshed.
         this.reloadCommand.setAttribute("disabled", "true");
       } else {
         this.reloadCommand.removeAttribute("disabled");
       }
 
       if (gURLBar) {
-        // Strip off "wyciwyg://" and passwords for the location bar
-        let uri = aLocationURI;
-        try {
-          uri = this._uriFixup.createExposableURI(uri);
-        } catch (e) {}
-        URLBarSetURI(uri);
+        URLBarSetURI(aLocationURI);
 
         // Update starring UI
         PlacesStarButton.updateState();
         SocialShareButton.updateShareState();
       }
 
       // Show or hide browser chrome based on the whitelist
       if (this.hideChromeForLocation(location)) {
@@ -4519,19 +4513,18 @@ var TabsProgressListener = {
   onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI,
                               aFlags) {
     // Filter out any sub-frame loads
     if (aBrowser.contentWindow == aWebProgress.DOMWindow) {
       // Filter out any onLocationChanges triggered by anchor navigation
       // or history.push/pop/replaceState.
       if (aRequest) {
         // Initialize the click-to-play state.
-        aBrowser._clickToPlayDoorhangerShown = false;
         aBrowser._clickToPlayPluginsActivated = false;
-        aBrowser._pluginScriptedState = PLUGIN_SCRIPTED_STATE_NONE;
+        aBrowser._pluginScriptedState = gPluginHandler.PLUGIN_SCRIPTED_STATE_NONE;
       }
       FullZoom.onLocationChange(aLocationURI, false, aBrowser);
     }
   },
 
   onRefreshAttempted: function (aBrowser, aWebProgress, aURI, aDelay, aSameURI) {
     if (gPrefService.getBoolPref("accessibility.blockautorefresh")) {
       let brandBundle = document.getElementById("bundle_brand");
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -250,16 +250,17 @@ endif
                  plugin_both.html \
                  plugin_both2.html \
                  plugin_bug743421.html \
                  plugin_clickToPlayAllow.html \
                  plugin_clickToPlayDeny.html \
                  plugin_bug749455.html \
                  plugin_bug797677.html \
                  plugin_bug818009.html \
+                 plugin_bug820497.html \
                  plugin_hidden_to_visible.html \
                  plugin_two_types.html \
                  alltabslistener.html \
                  zoom_test.html \
                  dummy_page.html \
                  file_bug550565_popup.html \
                  file_bug550565_favicon.ico \
                  browser_aboutHome.js \
@@ -278,22 +279,24 @@ endif
                  browser_middleMouse_inherit.js \
                  redirect_bug623155.sjs \
                  browser_tabDrop.js \
                  browser_lastAccessedTab.js \
                  browser_bug734076.js \
                  browser_bug812562.js \
                  browser_bug818009.js \
                  browser_bug818118.js \
+                 browser_bug820497.js \
                  blockPluginVulnerableUpdatable.xml \
                  blockPluginVulnerableNoUpdate.xml \
                  blockNoPlugins.xml \
                  browser_utilityOverlay.js \
                  browser_bug676619.js \
                  download_page.html \
+                 browser_URLBarSetURI.js \
                  $(NULL)
 
 ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 _BROWSER_FILES += \
 		browser_bug462289.js \
 		$(NULL)
 else
 _BROWSER_FILES += \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_URLBarSetURI.js
@@ -0,0 +1,82 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function test() {
+  waitForExplicitFinish();
+
+  // avoid prompting about phishing
+  Services.prefs.setIntPref(phishyUserPassPref, 32);
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref(phishyUserPassPref);
+  });
+
+  nextTest();
+}
+
+const phishyUserPassPref = "network.http.phishy-userpass-length";
+
+function nextTest() {
+  let test = tests.shift();
+  if (test) {
+    test(function () {
+      executeSoon(nextTest);
+    });
+  } else {
+    executeSoon(finish);
+  }
+}
+
+let tests = [
+  function revert(next) {
+    loadTabInWindow(window, function (tab) {
+      gURLBar.handleRevert();
+      is(gURLBar.value, "example.com", "URL bar had user/pass stripped after reverting");
+      gBrowser.removeTab(tab);
+      next();
+    });
+  },
+  function customize(next) {
+    whenNewWindowLoaded(undefined, function (win) {
+      // Need to wait for delayedStartup for the customization part of the test,
+      // since that's where BrowserToolboxCustomizeDone is set.
+      whenDelayedStartupFinished(win, function () {
+        loadTabInWindow(win, function () {
+          openToolbarCustomizationUI(function () {
+            closeToolbarCustomizationUI(function () {
+              is(win.gURLBar.value, "example.com", "URL bar had user/pass stripped after customize");
+              win.close();
+              next();
+            }, win);
+          }, win);
+        });
+      });
+    });
+  },
+  function pageloaderror(next) {
+    loadTabInWindow(window, function (tab) {
+      // Load a new URL and then immediately stop it, to simulate a page load
+      // error.
+      tab.linkedBrowser.loadURI("http://test1.example.com");
+      tab.linkedBrowser.stop();
+      is(gURLBar.value, "example.com", "URL bar had user/pass stripped after load error");
+      gBrowser.removeTab(tab);
+      next();
+    });
+  }
+];
+
+function loadTabInWindow(win, callback) {
+  info("Loading tab");
+  let url = "http://user:pass@example.com/";
+  let tab = win.gBrowser.selectedTab = win.gBrowser.addTab(url);
+  tab.linkedBrowser.addEventListener("load", function listener() {
+    info("Tab loaded");
+    if (tab.linkedBrowser.currentURI.spec != url)
+      return;
+    tab.linkedBrowser.removeEventListener("load", listener, true);
+
+    is(win.gURLBar.value, "example.com", "URL bar had user/pass stripped initially");
+    callback(tab);
+  }, true);
+}
--- a/browser/base/content/test/browser_bug567306.js
+++ b/browser/base/content/test/browser_bug567306.js
@@ -1,47 +1,44 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 let Ci = Components.interfaces;
-let testWindow = null;
 
 function test() {
   waitForExplicitFinish();
 
-  testWindow = OpenBrowserWindow();
-  testWindow.addEventListener("load", function(aEvent) {
-    testWindow.removeEventListener("load", arguments.callee, false);
-    ok(true, "Load listener called");
-
-    executeSoon(function() {
-      let selectedBrowser = testWindow.gBrowser.selectedBrowser;
+  whenNewWindowLoaded(undefined, function (win) {
+    whenDelayedStartupFinished(win, function () {
+      let selectedBrowser = win.gBrowser.selectedBrowser;
       selectedBrowser.addEventListener("pageshow", function() {
         selectedBrowser.removeEventListener("pageshow", arguments.callee, true);
-        ok(true, "pageshow listener called");
-        waitForFocus(onFocus, testWindow.contentWindow);
+        ok(true, "pageshow listener called: " + win.content.location);
+        waitForFocus(function () {
+          onFocus(win);
+        }, selectedBrowser.contentWindow);
       }, true);
-      testWindow.content.location = "data:text/html,<h1 id='h1'>Select Me</h1>";
+      selectedBrowser.loadURI("data:text/html,<h1 id='h1'>Select Me</h1>");
     });
-  }, false);
+  });
 }
 
-function selectText() {
-  let elt = testWindow.content.document.getElementById("h1");
-  let selection = testWindow.content.getSelection();
-  let range = testWindow.content.document.createRange();
+function selectText(win) {
+  let elt = win.document.getElementById("h1");
+  let selection = win.getSelection();
+  let range = win.document.createRange();
   range.setStart(elt, 0);
   range.setEnd(elt, 1);
   selection.removeAllRanges();
   selection.addRange(range);
 }
 
-function onFocus() {
-  ok(!testWindow.gFindBarInitialized, "find bar is not yet initialized");
-  let findBar = testWindow.gFindBar;
-  selectText();
+function onFocus(win) {
+  ok(!win.gFindBarInitialized, "find bar is not yet initialized");
+  let findBar = win.gFindBar;
+  selectText(win.content);
   findBar.onFindCommand();
   is(findBar._findField.value, "Select Me", "Findbar is initialized with selection");
   findBar.close();
-  testWindow.close();
+  win.close();
   finish();
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug820497.js
@@ -0,0 +1,53 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ *  License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var gTestBrowser = null;
+var gNumPluginBindingsAttached = 0;
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+function test() {
+  waitForExplicitFinish();
+  registerCleanupFunction(function() {
+    Services.prefs.clearUserPref("plugins.click_to_play");
+    gTestBrowser.removeEventListener("PluginBindingAttached", pluginBindingAttached, true, true);
+    gBrowser.removeCurrentTab();
+    window.focus();
+  });
+
+  Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gTestBrowser = gBrowser.selectedBrowser;
+  gTestBrowser.addEventListener("PluginBindingAttached", pluginBindingAttached, true, true);
+  var gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+  gTestBrowser.contentWindow.location = gHttpTestRoot + "plugin_bug820497.html";
+}
+
+function pluginBindingAttached() {
+  gNumPluginBindingsAttached++;
+
+  if (gNumPluginBindingsAttached == 1) {
+    var doc = gTestBrowser.contentDocument;
+    var testplugin = doc.getElementById("test");
+    ok(testplugin, "should have test plugin");
+    var secondtestplugin = doc.getElementById("secondtest");
+    ok(!secondtestplugin, "should not yet have second test plugin");
+    var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+    ok(notification, "should have popup notification");
+    is(notification.options.centerActions.length, 1, "should be 1 type of plugin in the popup notification");
+  } else if (gNumPluginBindingsAttached == 2) {
+    var doc = gTestBrowser.contentDocument;
+    var testplugin = doc.getElementById("test");
+    ok(testplugin, "should have test plugin");
+    var secondtestplugin = doc.getElementById("secondtest");
+    ok(secondtestplugin, "should have second test plugin");
+    var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+    ok(notification, "should have popup notification");
+    is(notification.options.centerActions.length, 2, "should be 2 types of plugin in the popup notification");
+    finish();
+  } else {
+    ok(false, "if we've gotten here, something is quite wrong");
+  }
+}
--- a/browser/base/content/test/browser_clickToPlayPluginScriptAccessPopup.js
+++ b/browser/base/content/test/browser_clickToPlayPluginScriptAccessPopup.js
@@ -94,17 +94,17 @@ function testNoEventFired() {
 }
 
 function testExpectNoPopupPart1() {
   var condition = function() gPluginScriptedFired;
   waitForCondition(condition, testExpectNoPopupPart2, "waited too long for PluginScripted event (" + getCurrentTestLocation() + ")");
 }
 
 function testExpectNoPopupPart2() {
-  var condition = function() gTestBrowser._pluginScriptedState == PLUGIN_SCRIPTED_STATE_DONE;
+  var condition = function() gTestBrowser._pluginScriptedState == gPluginHandler.PLUGIN_SCRIPTED_STATE_DONE;
   waitForCondition(condition, testExpectNoPopupPart3, "waited too long for PluginScripted event handling (" + getCurrentTestLocation() + ")");
 }
 
 function testExpectNoPopupPart3() {
   var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(notification, "should have a click-to-play notification (" + getCurrentTestLocation() + ")");
   ok(notification.dismissed, "notification should not be showing (" + getCurrentTestLocation() + ")");
 
--- a/browser/base/content/test/browser_pluginnotification.js
+++ b/browser/base/content/test/browser_pluginnotification.js
@@ -1,16 +1,17 @@
 var rootDir = getRootDirectory(gTestPath);
 const gTestRoot = rootDir;
 const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
 
 var gTestBrowser = null;
 var gNextTest = null;
 var gClickToPlayPluginActualEvents = 0;
 var gClickToPlayPluginExpectedEvents = 5;
+var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 // This listens for the next opened tab and checks it is of the right url.
 // opencallback is called when the new tab is fully loaded
 // closecallback is called when the tab is closed
 function TabOpenListener(url, opencallback, closecallback) {
   this.url = url;
@@ -415,17 +416,17 @@ function test12d() {
   var secondtestB = gTestBrowser.contentDocument.getElementById("secondtestB");
   var objLoadingContent = test.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 12d, Test plugin should be activated");
   var objLoadingContent = secondtestA.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "Test 12d, Second Test plugin (A) should not be activated");
   var objLoadingContent = secondtestB.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "Test 12d, Second Test plugin (B) should not be activated");
 
-  Services.perms.removeAll();
+  Services.perms.remove("127.0.0.1:8888", gPluginHost.getPermissionStringForType("application/x-test"));
   prepareTest(test13a, gHttpTestRoot + "plugin_clickToPlayDeny.html");
 }
 
 // Tests that the "Deny Always" permission works for click-to-play plugins (part 1/3)
 function test13a() {
   var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(popupNotification, "Test 13a, Should have a click-to-play notification");
   var plugin = gTestBrowser.contentDocument.getElementById("test");
@@ -505,31 +506,30 @@ function test13e() {
   var secondtestA = gTestBrowser.contentDocument.getElementById("secondtestA");
   var objLoadingContent = secondtestA.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 13e, Second Test plugin (A) should be activated");
 
   var secondtestB = gTestBrowser.contentDocument.getElementById("secondtestB");
   var objLoadingContent = secondtestB.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 13e, Second Test plugin (B) should be activated");
 
-  Services.perms.removeAll();
+  Services.perms.remove("127.0.0.1:8888", gPluginHost.getPermissionStringForType("application/x-test"));
   Services.prefs.setBoolPref("plugins.click_to_play", false);
   prepareTest(test14, gTestRoot + "plugin_test2.html");
 }
 
 // Tests that the plugin's "activated" property is true for working plugins with click-to-play disabled.
 function test14() {
   var plugin = gTestBrowser.contentDocument.getElementById("test1");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 14, Plugin should be activated");
 
   var plugin = getTestPlugin();
   plugin.disabled = false;
   plugin.blocklisted = false;
-  Services.perms.removeAll();
   Services.prefs.setBoolPref("plugins.click_to_play", true);
   prepareTest(test15, gTestRoot + "plugin_alternate_content.html");
 }
 
 // Tests that the overlay is shown instead of alternate content when
 // plugins are click to play
 function test15() {
   var plugin = gTestBrowser.contentDocument.getElementById("test");
@@ -652,17 +652,17 @@ function test18c() {
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE, "Test 18c, plugin fallback type should be PLUGIN_VULNERABLE_NO_UPDATE");
   ok(!objLoadingContent.activated, "Test 18c, Plugin should not be activated");
   var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
   ok(overlay.style.visibility != "hidden", "Test 18c, Plugin overlay should exist, not be hidden");
   var updateLink = doc.getAnonymousElementByAttribute(plugin, "class", "checkForUpdatesLink");
   ok(updateLink.style.display != "block", "Test 18c, Plugin should not have an update link");
 
-  // check that click "Always allow" works with blocklisted plugins (for now)
+  // check that click "Always allow" works with blocklisted plugins
   clickToPlayNotification.secondaryActions[0].callback();
   var condition = function() objLoadingContent.activated;
   waitForCondition(condition, test18d, "Test 18d, Waited too long for plugin to activate");
 }
 
 // continue testing "Always allow"
 function test18d() {
   var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
@@ -677,17 +677,17 @@ function test18d() {
 // continue testing "Always allow"
 function test18e() {
   var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(!popupNotification, "Test 18e, Should not have a click-to-play notification");
   var plugin = gTestBrowser.contentDocument.getElementById("test");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 18e, Plugin should be activated");
 
-  Services.perms.removeAll();
+  Services.perms.remove("127.0.0.1:8888", gPluginHost.getPermissionStringForType("application/x-test"));
   setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml",
   function() {
     resetBlocklist();
     prepareTest(test19a, gTestRoot + "plugin_test.html");
   });
 }
 
 // Tests that clicking the icon of the overlay activates the plugin
@@ -1055,19 +1055,22 @@ function test24c() {
 function test24d() {
   var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(!notification, "Test 24d, Should not have a click-to-play notification");
   var plugin = gTestBrowser.contentDocument.getElementById("test");
   ok(plugin, "Test 24d, Found plugin in page");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 24d, plugin should be activated");
 
-  Services.perms.removeAll();
+  // this resets the vulnerable plugin permission
+  Services.perms.remove("127.0.0.1:8888", gPluginHost.getPermissionStringForType("application/x-test"));
   setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml",
   function() {
+    // this resets the normal plugin permission
+    Services.perms.remove("127.0.0.1:8888", gPluginHost.getPermissionStringForType("application/x-test"));
     resetBlocklist();
     prepareTest(test25a, gHttpTestRoot + "plugin_test.html");
   });
 }
 
 // Test that clicking "always allow" or "always deny" doesn't affect plugins
 // that already have permission given to them
 function test25a() {
@@ -1115,12 +1118,13 @@ function test25c() {
 
   var secondtest = gTestBrowser.contentDocument.getElementById("secondtestA");
   ok(secondtest, "Test 25c, Found second test plugin in page");
   var objLoadingContent = secondtest.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "Test 25c, second test plugin should not be activated");
   var overlay = gTestBrowser.contentDocument.getAnonymousElementByAttribute(secondtest, "class", "mainBox");
   ok(overlay.style.visibility == "hidden", "Test 25c, second test plugin should not have visible overlay");
 
-  Services.perms.removeAll();
+  Services.perms.remove("127.0.0.1:8888", gPluginHost.getPermissionStringForType("application/x-test"));
+  Services.perms.remove("127.0.0.1:8888", gPluginHost.getPermissionStringForType("application/x-second-test"));
 
   finishTest();
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/plugin_bug820497.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head><meta charset="utf-8"/></head>
+<body onload="addSecondPlugin()">
+<object id="test" type="application/x-test" width=200 height=200></object>
+<script>
+  function addSecondPlugin() {
+    var object = document.createElement("object");
+    object.type = "application/x-second-test";
+    object.width = 200;
+    object.height = 200;
+    object.id = "secondtest";
+    document.body.appendChild(object);
+  }
+</script>
+</body>
+</html>
--- a/browser/base/content/test/social/Makefile.in
+++ b/browser/base/content/test/social/Makefile.in
@@ -15,17 +15,17 @@ include $(DEPTH)/config/autoconf.mk
                  browser_social.js \
                  browser_social_toolbar.js \
                  browser_social_shareButton.js \
                  browser_social_sidebar.js \
                  browser_social_flyout.js \
                  browser_social_mozSocial_API.js \
                  browser_social_isVisible.js \
                  browser_social_chatwindow.js \
-                 browser_social_multiprovider.js \
+                 $(filter disabled-temporarily--bug-820489, browser_social_multiprovider.js) \
                  social_panel.html \
                  social_share_image.png \
                  social_sidebar.html \
                  social_chat.html \
                  social_flyout.html \
                  social_window.html \
                  social_worker.js \
                  $(NULL)
--- a/browser/base/content/test/social/head.js
+++ b/browser/base/content/test/social/head.js
@@ -39,18 +39,47 @@ function runSocialTestWithProvider(manif
           ensureSocialUrlNotRemembered(m[what]);
         }
       }
     });
   });
 
   info("runSocialTestWithProvider: " + manifests.toSource());
 
+  let finishCount = 0;
+  function finishIfDone(callFinish) {
+    finishCount++;
+    if (finishCount == manifests.length)
+      finish();
+  }
+  function removeAddedProviders(cleanup) {
+    manifests.forEach(function (m) {
+      // If we're "cleaning up", don't call finish when done.
+      let callback = cleanup ? function () {} : finishIfDone;
+      // Similarly, if we're cleaning up, catch exceptions from removeProvider
+      let removeProvider = SocialService.removeProvider.bind(SocialService);
+      if (cleanup) {
+        removeProvider = function (origin, cb) {
+          try {
+            SocialService.removeProvider(origin, cb);
+          } catch (ex) {
+            // Ignore "provider doesn't exist" errors.
+            if (ex.message == "SocialService.removeProvider: no provider with this origin exists!")
+              return;
+            info("Failed to clean up provider " + origin + ": " + ex);
+          }
+        }
+      }
+      removeProvider(m.origin, callback);
+    });
+  }
+
   let providersAdded = 0;
   let firstProvider;
+
   manifests.forEach(function (m) {
     SocialService.addProvider(m, function(provider) {
       provider.active = true;
 
       providersAdded++;
       info("runSocialTestWithProvider: provider added");
 
       // we want to set the first specified provider as the UI's provider
@@ -60,33 +89,25 @@ function runSocialTestWithProvider(manif
 
       // If we've added all the providers we need, call the callback to start
       // the tests (and give it a callback it can call to finish them)
       if (providersAdded == manifests.length) {
         // Set the UI's provider and enable the feature
         Social.provider = firstProvider;
         Social.enabled = true;
 
-        registerCleanupFunction(function () {
+        function finishSocialTest(cleanup) {
           // disable social before removing the providers to avoid providers
           // being activated immediately before we get around to removing it.
           Services.prefs.clearUserPref("social.enabled");
-          // if one test happens to fail, it is likely finishSocialTest will not
-          // be called, causing most future social tests to also fail as they
-          // attempt to add a provider which already exists - so work
-          // around that by also attempting to remove the test provider.
-          manifests.forEach(function (m) {
-            try {
-              SocialService.removeProvider(m.origin, finish);
-            } catch (ex) {}
-          });
+          removeAddedProviders(cleanup);
+        }
+        registerCleanupFunction(function () {
+          finishSocialTest(true);
         });
-        function finishSocialTest() {
-          SocialService.removeProvider(provider.origin, finish);
-        }
         callback(finishSocialTest);
       }
     });
   });
 }
 
 function runSocialTests(tests, cbPreTest, cbPostTest, cbFinish) {
   let testIter = Iterator(tests);
--- a/browser/components/downloads/content/downloads.css
+++ b/browser/components/downloads/content/downloads.css
@@ -49,17 +49,17 @@ richlistitem[type="download"]:not([selec
                                            .downloadCancelMenuItem,
 
 .download-state:not(:-moz-any([state="1"], /* Finished           */
                               [state="2"], /* Failed             */
                               [state="3"], /* Canceled           */
                               [state="6"], /* Blocked (parental) */
                               [state="8"], /* Blocked (dirty)    */
                               [state="9"]) /* Blocked (policy)   */)
-                                           .downloadRemoveFromListMenuItem,
+                                           .downloadRemoveFromHistoryMenuItem,
 
 .download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
                               [state="5"], /* Starting (queued)  */
                               [state="0"], /* Downloading        */
                               [state="4"]) /* Paused             */)
                                            .downloadShowMenuItem,
 
 .download-state[state="7"]                 .downloadCommandsSeparator
--- a/browser/components/downloads/content/downloads.js
+++ b/browser/components/downloads/content/downloads.js
@@ -41,16 +41,20 @@
 //// Globals
 
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
                                   "resource://gre/modules/DownloadUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
                                   "resource:///modules/DownloadsCommon.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+                                  "resource://gre/modules/PlacesUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+                                  "resource://gre/modules/NetUtil.jsm");
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsPanel
 
 /**
  * Main entry point for the downloads panel interface.
  */
 const DownloadsPanel = {
@@ -330,17 +334,17 @@ const DownloadsPanel = {
       let [url, name] = data.value
                             .QueryInterface(Ci.nsISupportsString)
                             .data
                             .split("\n");
       if (!url) {
         return;
       }
 
-      let uri = Services.io.newURI(url, null, null);
+      let uri = NetUtil.newURI(url);
       saveURL(uri.spec, name || uri.spec, null, true, true,
               undefined, document);
     } catch (ex) {}
   },
 
   /**
    * Move focus to the main element in the downloads panel, unless another
    * element in the panel is already focused.
@@ -1183,22 +1187,16 @@ const DownloadsViewController = {
  */
 function DownloadsViewItemController(aElement) {
   let downloadGuid = aElement.getAttribute("downloadGuid");
   this.dataItem = DownloadsCommon.getData(window).dataItems[downloadGuid];
 }
 
 DownloadsViewItemController.prototype = {
   //////////////////////////////////////////////////////////////////////////////
-  //// Constants
-
-  get kPrefBdmAlertOnExeOpen() "browser.download.manager.alertOnEXEOpen",
-  get kPrefBdmScanWhenDone() "browser.download.manager.scanWhenDone",
-
-  //////////////////////////////////////////////////////////////////////////////
   //// Command dispatching
 
   /**
    * The DownloadDataItem controlled by this object.
    */
   dataItem: null,
 
   isCommandEnabled: function DVIC_isCommandEnabled(aCommand)
@@ -1239,152 +1237,56 @@ DownloadsViewItemController.prototype = 
   /**
    * This object contains one key for each command that operates on this item.
    *
    * In commands, the "this" identifier points to the controller item.
    */
   commands: {
     cmd_delete: function DVIC_cmd_delete()
     {
-      this.dataItem.getDownload(function (aDownload) {
-        if (this.dataItem.inProgress) {
-          aDownload.cancel();
-          this._ensureLocalFileRemoved();
-        }
-        aDownload.remove();
-      }.bind(this));
+      this.dataItem.remove();
+      PlacesUtils.bhistory.removePage(NetUtil.newURI(this.dataItem.uri));
     },
 
     downloadsCmd_cancel: function DVIC_downloadsCmd_cancel()
     {
-      if (this.dataItem.inProgress) {
-        this.dataItem.getDownload(function (aDownload) {
-          aDownload.cancel();
-          this._ensureLocalFileRemoved();
-        }.bind(this));
-      }
+      this.dataItem.cancel();
     },
 
     downloadsCmd_open: function DVIC_downloadsCmd_open()
     {
-      // Confirm opening executable files if required.
-      let localFile = this.dataItem.localFile;
-      if (localFile.isExecutable()) {
-        let showAlert = true;
-        try {
-          showAlert = Services.prefs.getBoolPref(this.kPrefBdmAlertOnExeOpen);
-        } catch (ex) { }
-
-        // On Vista and above, we rely on native security prompting for
-        // downloaded content unless it's disabled.
-        if (DownloadsCommon.isWinVistaOrHigher) {
-          try {
-            if (Services.prefs.getBoolPref(this.kPrefBdmScanWhenDone)) {
-              showAlert = false;
-            }
-          } catch (ex) { }
-        }
-
-        if (showAlert) {
-          let name = this.dataItem.target;
-          let message =
-              DownloadsCommon.strings.fileExecutableSecurityWarning(name, name);
-          let title =
-              DownloadsCommon.strings.fileExecutableSecurityWarningTitle;
-          let dontAsk =
-              DownloadsCommon.strings.fileExecutableSecurityWarningDontAsk;
-
-          let checkbox = { value: false };
-          let open = Services.prompt.confirmCheck(window, title, message,
-                                                  dontAsk, checkbox);
-          if (!open) {
-            return;
-          }
-
-          Services.prefs.setBoolPref(this.kPrefBdmAlertOnExeOpen,
-                                     !checkbox.value);
-        }
-      }
-
-      // Actually open the file.
-      this.dataItem.getDownload(function (aDownload) {
-        try {
-          let launched = false;
-          try {
-            let mimeInfo = aDownload.MIMEInfo;
-            if (mimeInfo.preferredAction == mimeInfo.useHelperApp) {
-              mimeInfo.launchWithFile(localFile);
-              launched = true;
-            }
-          } catch (ex) { }
-          if (!launched) {
-            localFile.launch();
-          }
-        } catch (ex) {
-          // If launch fails, try sending it through the system's external "file:"
-          // URL handler.
-          this._openExternal(localFile);
-        }
-      }.bind(this));
-
+      this.dataItem.openLocalFile();
       // We explicitly close the panel here to give the user the feedback that
       // their click has been received, and we're handling the action.
       // Otherwise, we'd have to wait for the file-type handler to execute
       // before the panel would close. This also helps to prevent the user from
       // accidentally opening a file several times.
       DownloadsPanel.hidePanel();
     },
 
     downloadsCmd_show: function DVIC_downloadsCmd_show()
     {
-      let localFile = this.dataItem.localFile;
-
-      try {
-        // Show the directory containing the file and select the file.
-        localFile.reveal();
-      } catch (ex) {
-        // If reveal fails for some reason (e.g., it's not implemented on unix
-        // or the file doesn't exist), try using the parent if we have it.
-        let parent = localFile.parent.QueryInterface(Ci.nsILocalFile);
-        if (parent) {
-          try {
-            // Open the parent directory to show where the file should be.
-            parent.launch();
-          } catch (ex) {
-            // If launch also fails (probably because it's not implemented), let
-            // the OS handler try to open the parent.
-            this._openExternal(parent);
-          }
-        }
-      }
+      this.dataItem.showLocalFile();
 
       // We explicitly close the panel here to give the user the feedback that
       // their click has been received, and we're handling the action.
       // Otherwise, we'd have to wait for the operating system file manager
       // window to open before the panel closed. This also helps to prevent the
       // user from opening the containing folder several times.
       DownloadsPanel.hidePanel();
     },
 
     downloadsCmd_pauseResume: function DVIC_downloadsCmd_pauseResume()
     {
-      this.dataItem.getDownload(function (aDownload) {
-        if (this.dataItem.paused) {
-          aDownload.resume();
-        } else {
-          aDownload.pause();
-        }
-      }.bind(this));
+      this.dataItem.togglePauseResume();
     },
 
     downloadsCmd_retry: function DVIC_downloadsCmd_retry()
     {
-      this.dataItem.getDownload(function (aDownload) {
-        aDownload.retry();
-      });
+      this.dataItem.retry();
     },
 
     downloadsCmd_openReferrer: function DVIC_downloadsCmd_openReferrer()
     {
       openURL(this.dataItem.referrer);
     },
 
     downloadsCmd_copyLocation: function DVIC_downloadsCmd_copyLocation()
@@ -1413,41 +1315,16 @@ DownloadsViewItemController.prototype = 
           case nsIDM.DOWNLOAD_DIRTY:            return "downloadsCmd_openReferrer";
           case nsIDM.DOWNLOAD_BLOCKED_POLICY:   return "downloadsCmd_openReferrer";
         }
         return null;
       }.apply(this);
       // Invoke the command.
       this.doCommand(defaultCommand);
     }
-  },
-
-  /**
-   * Support function to open the specified nsIFile.
-   */
-  _openExternal: function DVIC_openExternal(aFile)
-  {
-    let protocolSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"]
-                      .getService(Ci.nsIExternalProtocolService);
-    protocolSvc.loadUrl(makeFileURI(aFile));
-  },
-
-  /**
-   * Support function that deletes the local file for a download. This is
-   * used in cases where the Download Manager service doesn't delete the file
-   * from disk when cancelling. See bug 732924.
-   */
-  _ensureLocalFileRemoved: function DVIC_ensureLocalFileRemoved()
-  {
-    try {
-      let localFile = this.dataItem.localFile;
-      if (localFile.exists()) {
-        localFile.remove(false);
-      }
-    } catch (ex) { }
   }
 };
 
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsSummary
 
 /**
--- a/browser/components/downloads/content/downloadsOverlay.xul
+++ b/browser/components/downloads/content/downloadsOverlay.xul
@@ -63,18 +63,18 @@
                   label="&cmd.resume.label;"
                   accesskey="&cmd.resume.accesskey;"/>
         <menuitem command="downloadsCmd_cancel"
                   class="downloadCancelMenuItem"
                   label="&cmd.cancel.label;"
                   accesskey="&cmd.cancel.accesskey;"/>
         <menuitem command="cmd_delete"
                   class="downloadRemoveFromListMenuItem"
-                  label="&cmd.removeFromList.label;"
-                  accesskey="&cmd.removeFromList.accesskey;"/>
+                  label="&cmd.removeFromHistory.label;"
+                  accesskey="&cmd.removeFromHistory.accesskey;"/>
         <menuitem command="downloadsCmd_show"
                   class="downloadShowMenuItem"
 #ifdef XP_MACOSX
                   label="&cmd.showMac.label;"
                   accesskey="&cmd.showMac.accesskey;"
 #else
                   label="&cmd.show.label;"
                   accesskey="&cmd.show.accesskey;"
--- a/browser/components/downloads/src/DownloadsCommon.jsm
+++ b/browser/components/downloads/src/DownloadsCommon.jsm
@@ -58,16 +58,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
                                   "resource:///modules/RecentWindow.jsm");
 
 const nsIDM = Ci.nsIDownloadManager;
 
 const kDownloadsStringBundleUrl =
   "chrome://browser/locale/downloads/downloads.properties";
 
+const kPrefBdmScanWhenDone =   "browser.download.manager.scanWhenDone";
+const kPrefBdmAlertOnExeOpen = "browser.download.manager.alertOnEXEOpen";
+
 const kDownloadsStringsRequiringFormatting = {
   sizeWithUnits: true,
   shortTimeLeftSeconds: true,
   shortTimeLeftMinutes: true,
   shortTimeLeftHours: true,
   shortTimeLeftDays: true,
   statusSeparator: true,
   statusSeparatorBeforeNumber: true,
@@ -391,16 +394,127 @@ this.DownloadsCommon = {
         aSeconds = aLastSeconds - (diff < 0 ? .4 : .2);
       }
     }
 
     // In the last few seconds of downloading, we are always subtracting and
     // never adding to the time left.  Ensure that we never fall below one
     // second left until all downloads are actually finished.
     return aLastSeconds = Math.max(aSeconds, 1);
+  },
+
+  /**
+   * Opens a downloaded file.
+   * If you've a dataItem, you should call dataItem.openLocalFile.
+   * @param aFile
+   *        the downloaded file to be opened.
+   * @param aMimeInfo
+   *        the mime type info object.  May be null.
+   * @param aOwnerWindow
+   *        the window with which this action is associated.
+   */
+  openDownloadedFile: function DC_openDownloadedFile(aFile, aMimeInfo, aOwnerWindow) {
+    if (!(aFile instanceof Ci.nsIFile))
+      throw new Error("aFile must be a nsIFile object");
+    if (aMimeInfo && !(aMimeInfo instanceof Ci.nsIMIMEInfo))
+      throw new Error("Invalid value passed for aMimeInfo");
+    if (!(aOwnerWindow instanceof Ci.nsIDOMWindow))
+      throw new Error("aOwnerWindow must be a dom-window object");
+
+    // Confirm opening executable files if required.
+    if (aFile.isExecutable()) {
+      let showAlert = true;
+      try {
+        showAlert = Services.prefs.getBoolPref(kPrefBdmAlertOnExeOpen);
+      } catch (ex) { }
+
+      // On Vista and above, we rely on native security prompting for
+      // downloaded content unless it's disabled.
+      if (DownloadsCommon.isWinVistaOrHigher) {
+        try {
+          if (Services.prefs.getBoolPref(kPrefBdmScanWhenDone)) {
+            showAlert = false;
+          }
+        } catch (ex) { }
+      }
+
+      if (showAlert) {
+        let name = this.dataItem.target;
+        let message =
+          DownloadsCommon.strings.fileExecutableSecurityWarning(name, name);
+        let title =
+          DownloadsCommon.strings.fileExecutableSecurityWarningTitle;
+        let dontAsk =
+          DownloadsCommon.strings.fileExecutableSecurityWarningDontAsk;
+
+        let checkbox = { value: false };
+        let open = Services.prompt.confirmCheck(aOwnerWindow, title, message,
+                                                dontAsk, checkbox);
+        if (!open) {
+          return;
+        }
+
+        Services.prefs.setBoolPref(kPrefBdmAlertOnExeOpen,
+                                   !checkbox.value);
+      }
+    }
+
+    // Actually open the file.
+    try {
+      if (aMimeInfo && aMimeInfo.preferredAction == aMimeInfo.useHelperApp) {
+        aMimeInfo.launchWithFile(aFile);
+        return;
+      }
+    }
+    catch(ex) { }
+
+    // If either we don't have the mime info, or the preferred action failed,
+    // attempt to launch the file directly.
+    try {
+      aFile.launch();
+    }
+    catch(ex) {
+      // If launch fails, try sending it through the system's external "file:"
+      // URL handler.
+      Cc["@mozilla.org/uriloader/external-protocol-service;1"]
+        .getService(Ci.nsIExternalProtocolService)
+        .loadUrl(NetUtil.newURI(aFile));
+    }
+  },
+
+  /**
+   * Show a donwloaded file in the system file manager.
+   * If you have a dataItem, use dataItem.showLocalFile.
+   *
+   * @param aFile
+   *        a downloaded file.
+   */
+  showDownloadedFile: function DC_showDownloadedFile(aFile) {
+    if (!(aFile instanceof Ci.nsIFile))
+      throw new Error("aFile must be a nsIFile object");
+    try {
+      // Show the directory containing the file and select the file.
+      aFile.reveal();
+    } catch (ex) {
+      // If reveal fails for some reason (e.g., it's not implemented on unix
+      // or the file doesn't exist), try using the parent if we have it.
+      let parent = aFile.parent;
+      if (parent) {
+        try {
+          // Open the parent directory to show where the file should be.
+          parent.launch();
+        } catch (ex) {
+          // If launch also fails (probably because it's not implemented), let
+          // the OS handler try to open the parent.
+          Cc["@mozilla.org/uriloader/external-protocol-service;1"]
+            .getService(Ci.nsIExternalProtocolService)
+            .loadUrl(NetUtil.newURI(parent));
+        }
+      }
+    }
   }
 };
 
 /**
  * Returns true if we are executing on Windows Vista or a later version.
  */
 XPCOMUtils.defineLazyGetter(DownloadsCommon, "isWinVistaOrHigher", function () {
   let os = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
@@ -1207,16 +1321,111 @@ DownloadsDataItem.prototype = {
       // "spec" property of the target has the UTF-8 charset.
       let fileUrl = NetUtil.newURI(aFilename).QueryInterface(Ci.nsIFileURL);
       return fileUrl.file.clone().QueryInterface(Ci.nsILocalFile);
     } else {
       // The downloads database contains a native path.  Try to create a local
       // file, though this may throw an exception if the path is invalid.
       return new DownloadsLocalFileCtor(aFilename);
     }
+  },
+
+  /**
+   * Open the target file for this download.
+   *
+   * @param aOwnerWindow
+   *        The window with which the required action is associated.
+   * @throws if the file cannot be opened.
+   */
+  openLocalFile: function DDI_openLocalFile(aOwnerWindow) {
+    this.getDownload(function(aDownload) {
+      DownloadsCommon.openDownloadedFile(this.localFile,
+                                         aDownload.MIMEInfo,
+                                         aOwnerWindow);
+    }.bind(this));
+  },
+
+  /**
+   * Show the downloaded file in the system file manager.
+   */
+  showLocalFile: function DDI_showLocalFile() {
+    DownloadsCommon.showDownloadedFile(this.localFile);
+  },
+
+  /**
+   * Resumes the download if paused, pauses it if active.
+   * @throws if the download is not resumable or if has already done.
+   */
+  togglePauseResume: function DDI_togglePauseResume() {
+    if (!this.inProgress || !this.resumable)
+      throw new Error("The given download cannot be paused or resumed");
+
+    this.getDownload(function(aDownload) {
+      if (this.inProgress) {
+        if (this.paused)
+          aDownload.resume();
+        else
+          aDownload.pause();
+      }
+    }.bind(this));
+  },
+
+  /**
+   * Attempts to retry the download.
+   * @throws if we cannot.
+   */
+  retry: function DDI_retry() {
+    if (!this.canRetry)
+      throw new Error("Cannot rerty this download");
+
+    this.getDownload(function(aDownload) {
+      aDownload.retry();
+    });
+  },
+
+  /**
+   * Support function that deletes the local file for a download. This is
+   * used in cases where the Download Manager service doesn't delete the file
+   * from disk when cancelling. See bug 732924.
+   */
+  _ensureLocalFileRemoved: function DDI__ensureLocalFileRemoved()
+  {
+    try {
+      let localFile = this.localFile;
+      if (localFile.exists()) {
+        localFile.remove(false);
+      }
+    } catch (ex) { }
+  },
+
+  /**
+   * Cancels the download.
+   * @throws if the download is already done.
+   */
+  cancel: function() {
+    if (!this.inProgress)
+      throw new Error("Cannot cancel this download");
+
+    this.getDownload(function (aDownload) {
+      aDownload.cancel();
+      this._ensureLocalFileRemoved();
+    }.bind(this));
+  },
+
+  /**
+   * Remove the download.
+   */
+  remove: function DDI_remove() {
+    this.getDownload(function (aDownload) {
+      if (this.inProgress) {
+        aDownload.cancel();
+        this._ensureLocalFileRemoved();
+      }
+      aDownload.remove();
+    }.bind(this));
   }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsViewPrototype
 
 /**
  * A prototype for an object that registers itself with DownloadsData as soon
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -15,16 +15,18 @@ function PlacesViewBase(aPlace) {
   this._viewElt.controllers.appendController(this._controller);
 }
 
 PlacesViewBase.prototype = {
   // The xul element that holds the entire view.
   _viewElt: null,
   get viewElt() this._viewElt,
 
+  get associatedElement() this._viewElt,
+
   get controllers() this._viewElt.controllers,
 
   // The xul element that represents the root container.
   _rootElt: null,
 
   // Set to true for views that are represented by native widgets (i.e.
   // the native mac menu).
   _nativeView: false,
new file mode 100644
--- /dev/null
+++ b/browser/components/places/content/download.css
@@ -0,0 +1,45 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+richlistitem.download button {
+  /* These buttons should never get focus, as that would "disable"
+     the downloads view controller (it's only used when the richlistbox
+     is focused). */
+  -moz-user-focus: none;
+}
+
+/*** Visibility of controls inside download items ***/
+
+.download-state:-moz-any(     [state="6"], /* Blocked (parental) */
+                              [state="8"], /* Blocked (dirty)    */
+                              [state="9"]) /* Blocked (policy)   */
+                                           .downloadTypeIcon:not(.blockedIcon),
+
+.download-state:not(:-moz-any([state="6"], /* Blocked (parental) */
+                              [state="8"], /* Blocked (dirty)    */
+                              [state="9"]) /* Blocked (policy)   */)
+                                           .downloadTypeIcon.blockedIcon,
+
+.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
+                              [state="5"], /* Starting (queued)  */
+                              [state="0"], /* Downloading        */
+                              [state="4"], /* Paused             */
+                              [state="7"]) /* Scanning           */)
+                                           .downloadProgress,
+
+.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
+                              [state="5"], /* Starting (queued)  */
+                              [state="0"], /* Downloading        */
+                              [state="4"]) /* Paused             */)
+                                           .downloadCancel,
+
+.download-state:not(:-moz-any([state="2"], /* Failed             */
+                              [state="3"]) /* Canceled           */)
+                                           .downloadRetry,
+
+.download-state:not(          [state="1"]  /* Finished           */)
+                                           .downloadShow
+{
+  visibility: hidden;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/places/content/download.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!-- -*- Mode: HTML; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- -->
+<!-- vim: set ts=2 et sw=2 tw=80: -->
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this file,
+   - You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE bindings SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
+
+<bindings id="downloadBindings"
+          xmlns="http://www.mozilla.org/xbl"
+          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+          xmlns:xbl="http://www.mozilla.org/xbl">
+
+  <binding id="download"
+           extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
+   <resources>
+     <stylesheet src="chrome://browser/content/places/download.css"/>
+   </resources>
+
+    <content orient="horizontal" align="center">
+      <xul:image class="downloadTypeIcon"
+                 validate="always"
+                 xbl:inherits="src=image"/>
+      <xul:image class="downloadTypeIcon blockedIcon"/>
+      <xul:vbox pack="center" flex="1">
+        <xul:description class="downloadTarget"
+                         crop="center"
+                         xbl:inherits="value=displayName,tooltiptext=displayName"/>
+        <xul:progressmeter anonid="progressmeter"
+                           class="downloadProgress"
+                           min="0"
+                           max="100"
+                           xbl:inherits="mode=progressmode,value=progress"/>
+        <xul:description class="downloadDetails"
+                         style="width: &downloadDetails.width;"
+                         crop="end"
+                         xbl:inherits="value=status,tooltiptext=statusTip"/>
+      </xul:vbox>
+      <xul:stack>
+        <xul:button class="downloadButton downloadCancel"
+                    command="downloadsCmd_cancel"
+                    tooltiptext="&cmd.cancel.label;"/>
+        <xul:button class="downloadButton downloadRetry"
+                    command="downloadsCmd_retry"
+                    tooltiptext="&cmd.retry.label;"/>
+        <xul:button class="downloadButton downloadShow"
+                    command="downloadsCmd_show"
+                    tooltiptext="&cmd.show.label;"/>
+      </xul:stack>
+    </content>
+  </binding>
+</bindings>
new file mode 100644
--- /dev/null
+++ b/browser/components/places/content/downloadsView.js
@@ -0,0 +1,1028 @@
+/* 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 PLACES VIEW IMPLEMENTED IN THIS FILE HAS A VERY PARTICULAR USE CASE.
+ * IT IS HIGHLY RECOMMENDED NOT TO EXTEND IT FOR ANY OTHER USE CASES OR RELY
+ * ON IT AS AN API.
+ */
+
+let Cu = Components.utils;
+let Ci = Components.interfaces;
+let Cc = Components.classes;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/DownloadUtils.jsm");
+Cu.import("resource:///modules/DownloadsCommon.jsm");
+
+const nsIDM = Ci.nsIDownloadManager;
+
+const DESTINATION_FILE_URI_ANNO  = "downloads/destinationFileURI";
+const DESTINATION_FILE_NAME_ANNO = "downloads/destinationFileName";
+const DOWNLOAD_STATE_ANNO        = "downloads/state";
+
+const DOWNLOAD_VIEW_SUPPORTED_COMMANDS =
+ ["cmd_delete", "cmd_copy", "cmd_paste", "cmd_selectAll",
+  "downloadsCmd_pauseResume", "downloadsCmd_cancel",
+  "downloadsCmd_open", "downloadsCmd_show", "downloadsCmd_retry",
+  "downloadsCmd_openReferrer"];
+
+function GetFileForFileURI(aFileURI)
+  Cc["@mozilla.org/network/protocol;1?name=file"]
+    .getService(Ci.nsIFileProtocolHandler)
+    .getFileFromURLSpec(aFileURI);
+
+/**
+ * A download element shell is responsible for handling the commands and the
+ * displayed data for a single download view element. The download element
+ * could represent either a past download (for which we get data from places)  or
+ * a "session" download (using a data-item object. See DownloadsCommon.jsm), or both.
+ *
+ * Once initialized with either a data item or a places node, the created richlistitem
+ * can be accessed through the |element| getter, and can then be inserted/removed from
+ * a richlistbox.
+ *
+ * The shell doesn't take care of inserting the item, or removing it when it's no longer
+ * valid. That's the caller (a DownloadsPlacesView object) responsibility.
+ *
+ * The caller is also responsible for "passing over" notification from both the
+ * download-view and the places-result-observer, in the following manner:
+ *  - The DownloadsPlacesView object implements getViewItem of the download-view
+ *    pseudo interface.  It returns this object (therefore we implement
+ *    onStateChangea and onProgressChange here).
+ *  - The DownloadsPlacesView object adds itself as a places result observer and
+ *    calls this object's placesNodeIconChanged, placesNodeTitleChanged and
+ *    placeNodeAnnotationChanged from its callbacks.
+ *
+ * @param [optional] aDataItem
+ *        The data item of a the session download. Required if aPlacesNode is not set
+ * @param [optional] aPlacesNode
+ *        The places node for a past download. Required if aDataItem is not set.
+ */
+function DownloadElementShell(aDataItem, aPlacesNode) {
+  this._element = document.createElement("richlistitem");
+  this._element._shell = this;
+
+  this._element.classList.add("download");
+  this._element.classList.add("download-state");
+
+  if (aDataItem)
+    this.dataItem = aDataItem;
+  if (aPlacesNode)
+    this.placesNode = aPlacesNode;
+}
+
+DownloadElementShell.prototype = {
+  // The richlistitem for the download
+  get element() this._element,
+
+  // The data item for the download
+  get dataItem() this._dataItem,
+
+  set dataItem(aValue) {
+    if (this._dataItem = aValue) {
+      this._wasDone = this._dataItem.done;
+      this._wasInProgress = this._dataItem.inProgress;
+    }
+    else if (this._placesNode) {
+      this._wasInProgress = false;
+      this._wasDone = this._state == nsIDM.DOWNLOAD_FINISHED;
+    }
+
+    this._updateStatusUI();
+    return aValue;
+  },
+
+  get placesNode() this._placesNode,
+  set placesNode(aNode) {
+    if (this._placesNode != aNode) {
+      this._annotations = new Map();
+      this._placesNode = aNode;
+      if (!this._dataItem && this._placesNode) {
+        this._wasInProgress = false;
+        this._wasDone = this._state == nsIDM.DOWNLOAD_FINISHED;
+        this._updateStatusUI();
+      }
+    }
+    return aNode;
+  },
+
+  // The download uri (as a string)
+  get downloadURI() {
+    if (this._dataItem)
+     return this._dataItem.uri;
+    if (this._placesNode)
+      return this._placesNode.uri;
+    throw new Error("Unexpected download element state");
+  },
+
+  get _icon() {
+    if (this._targetFileURI)
+      return "moz-icon://" + this._targetFileURI + "?size=32";
+    if (this._placesNode)
+      return this.placesNode.icon;
+    if (this._dataItem)
+      throw new Error("Session-download items should always have a target file uri");
+    throw new Error("Unexpected download element state");
+  },
+
+  // Helper for getting a places annotation set for the download.
+  _getAnnotation: function DES__getAnnotation(aAnnotation, aDefaultValue) {
+    if (this._annotations.has(aAnnotation))
+      return this._annotations.get(aAnnotation);
+
+    let value;
+    try {
+      value = PlacesUtils.annotations.getPageAnnotation(
+        NetUtil.newURI(this.downloadURI), aAnnotation);
+    }
+    catch(ex) {
+      if (aDefaultValue === undefined) {
+        throw new Error("Could not get required annotation '" + aAnnotation +
+                        "' for download with url '" + this.downloadURI + "'");
+      }
+      value = aDefaultValue;
+    }
+    this._annotations.set(aAnnotation, value);
+    return value;
+  },
+
+  // The uri (as a string) of the target file, if any.
+  get _targetFileURI() {
+    if (this._dataItem)
+      return this._dataItem.file;
+
+    return this._getAnnotation(DESTINATION_FILE_URI_ANNO, "");
+  },
+
+  // The label for the download
+  get _displayName() {
+    if (this._dataItem)
+      return this._dataItem.target;
+
+    try {
+      return this._getAnnotation(DESTINATION_FILE_NAME_ANNO, "");
+    }
+    catch(ex) { }
+
+    // Fallback to the places title, or, at last, to the download uri.
+    return this._placesNode.title || this.downloadURI;
+  },
+
+  // If there's a target file for the download, this is its nsIFile object.
+  get _file() {
+    if (!("__file" in this)) {
+      if (this._dataItem) {
+        this.__file = this._dataItem.localFile;
+      }
+      else {
+        this.__file = this._targetFileURI ?
+          GetFileForFileURI(this._targetFileURI) : null;
+      }
+    }
+    return this.__file;
+  },
+
+  // The target's file size in bytes. If there's no target file, or If we
+  // cannot determine its size, 0 is returned.
+  get _fileSize() {
+    if (!this._file || !this._file.exists())
+      return 0;
+    try {
+      return this._file.fileSize;
+    }
+    catch(ex) {
+      Cu.reportError(ex);
+      return 0;
+    }
+  },
+
+  // The download state (see nsIDownloadManager).
+  get _state() {
+    if (this._dataItem)
+      return this._dataItem.state;
+
+    let state = -1;
+    try {
+      return this._getAnnotation(DOWNLOAD_STATE_ANNO);
+    }
+    catch (ex) {
+      // The state annotation didn't exist in past releases.
+      if (!this._file) {
+        state = nsIDM.DOWNLOAD_FAILED;
+      }
+      else if (this._file.exists()) {
+        state = this._fileSize > 0 ?
+          nsIDM.DOWNLOAD_FINISHED : nsIDM.DOWNLOAD_FAILED;
+      }
+      else {
+        // XXXmano I'm not sure if this right. We should probably show no
+        // status text at all in this case.
+        state = nsIDM.DOWNLOAD_CANCELED;
+      }
+    }
+    return state;
+  },
+
+  // The status text for the download
+  get _statusText() {
+    let s = DownloadsCommon.strings;
+    if (this._dataItem && this._dataItem.inProgress) {
+      if (this._dataItem.paused) {
+        let transfer =
+          DownloadUtils.getTransferTotal(this._dataItem.currBytes,
+                                         this._dataItem.maxBytes);
+
+         // We use the same XUL label to display both the state and the amount
+         // transferred, for example "Paused -  1.1 MB".
+         return s.statusSeparatorBeforeNumber(s.statePaused, transfer);
+      }
+      if (this._dataItem.state == nsIDM.DOWNLOAD_DOWNLOADING) {
+        let [status, newEstimatedSecondsLeft] =
+          DownloadUtils.getDownloadStatus(this.dataItem.currBytes,
+                                          this.dataItem.maxBytes,
+                                          this.dataItem.speed,
+                                          this._lastEstimatedSecondsLeft);
+        this._lastEstimatedSecondsLeft = newEstimatedSecondsLeft;
+        return status;
+      }
+      if (this._dataItem.starting) {
+        return s.stateStarting;
+      }
+      if (this._dataItem.state == nsIDM.DOWNLOAD_SCANNING) {
+        return s.stateScanning;
+      }
+
+      let [displayHost, fullHost] =
+        DownloadUtils.getURIHost(this._dataItem.referrer ||
+                                 this._dataItem.uri);
+
+      let end = new Date(this.dataItem.endTime);
+      let [displayDate, fullDate] = DownloadUtils.getReadableDates(end);
+      return s.statusSeparator(fullHost, fullDate);
+    }
+
+    switch (this._state) {
+      case nsIDM.DOWNLOAD_FAILED:
+        return s.stateFailed;
+      case nsIDM.DOWNLOAD_CANCELED:
+        return s.stateCanceled;
+      case nsIDM.DOWNLOAD_BLOCKED_PARENTAL:
+        return s.stateBlockedParentalControls;
+      case nsIDM.DOWNLOAD_BLOCKED_POLICY:
+        return s.stateBlockedPolicy;
+      case nsIDM.DOWNLOAD_DIRTY:
+        return s.stateDirty;
+      case nsIDM.DOWNLOAD_FINISHED:{
+        // For completed downloads, show the file size (e.g. "1.5 MB")
+        if (this._fileSize > 0) {
+          let [size, unit] = DownloadUtils.convertByteUnits(this._fileSize);
+          return s.sizeWithUnits(size, unit);
+        }
+        break;
+      }
+    }
+
+    return "";
+  },
+
+  // The progressmeter element for the download
+  get _progressElement() {
+    let progressElement = document.getAnonymousElementByAttribute(
+      this._element, "anonid", "progressmeter");
+    if (progressElement) {
+      delete this._progressElement;
+      return this._progressElement = progressElement;
+    }
+    return null;
+  },
+
+  // Updates the download state attribute (and by that hide/unhide the
+  // appropriate buttons and context menu items), the status text label,
+  // and the progress meter.
+  _updateDownloadStatusUI: function  DES__updateDownloadStatusUI() {
+    this._element.setAttribute("state", this._state);
+    this._element.setAttribute("status", this._statusText);
+
+    // For past-downloads, we're done. For session-downloads, we may also need
+    // to update the progress-meter.
+    if (!this._dataItem)
+      return;
+
+    // Copied from updateProgress in downloads.js.
+    if (this._dataItem.starting) {
+      // Before the download starts, the progress meter has its initial value.
+      this._element.setAttribute("progressmode", "normal");
+      this._element.setAttribute("progress", "0");
+    }
+    else if (this._dataItem.state == nsIDM.DOWNLOAD_SCANNING ||
+             this._dataItem.percentComplete == -1) {
+      // We might not know the progress of a running download, and we don't know
+      // the remaining time during the malware scanning phase.
+      this._element.setAttribute("progressmode", "undetermined");
+    }
+    else {
+      // This is a running download of which we know the progress.
+      this._element.setAttribute("progressmode", "normal");
+      this._element.setAttribute("progress", this._dataItem.percentComplete);
+    }
+
+    // Dispatch the ValueChange event for accessibility, if possible.
+    if (this._progressElement) {
+      let event = document.createEvent("Events");
+      event.initEvent("ValueChange", true, true);
+      this._progressElement.dispatchEvent(event);
+    }
+
+    goUpdateDownloadCommands();
+  },
+
+  _updateStatusUI: function DES__updateStatusUI() {
+    this._updateDownloadStatusUI();
+    this._element.setAttribute("image", this._icon);
+    this._element.setAttribute("displayName", this._displayName);
+  },
+
+  placesNodeIconChanged: function DES_placesNodeIconChanged() {
+    if (!this._dataItem)
+      this._element.setAttribute("image", this._icon);
+  },
+
+  placesNodeTitleChanged: function DES_placesNodeTitleChanged() {
+    if (!this._dataItem)
+      this._element.setAttribute("displayName", this._displayName);
+  },
+
+  placesNodeAnnotationChanged: function DES_placesNodeAnnotationChanged(aAnnoName) {
+    this._annotations.delete(aAnnoName);
+    if (!this._dataItem) {
+      if (aAnnoName == DESTINATION_FILE_URI_ANNO) {
+        this._element.setAttribute("image", this._icon);
+        this._updateDownloadStatusUI();
+      }
+      else if (aAnnoName == DESTINATION_FILE_NAME_ANNO) {
+        this._element.setAttribute("displayName", this._displayName);
+      }
+      else if (aAnnoName == DOWNLOAD_STATE_ANNO) {
+        this._updateDownloadStatusUI();
+      }
+    }
+  },
+
+  /* DownloadView */
+  onStateChange: function DES_onStateChange() {
+    // See comment in DVI_onStateChange in downloads.js (the panel-view)
+    if (!this._wasDone && this._dataItem.done)
+      this._element.setAttribute("image", this._icon + "&state=normal");
+
+    this._wasDone = this._dataItem.done;
+
+    // Update the end time using the current time if required.
+    if (this._wasInProgress && !this._dataItem.inProgress) {
+      this._endTime = Date.now();
+    }
+
+    this._wasDone = this._dataItem.done;
+    this._wasInProgress = this._dataItem.inProgress;
+
+    this._updateDownloadStatusUI();
+  },
+
+  /* DownloadView */
+  onProgressChange: function DES_onProgressChange() {
+    this._updateDownloadStatusUI();
+  },
+
+  /* nsIController */
+  isCommandEnabled: function DES_isCommandEnabled(aCommand) {
+    switch (aCommand) {
+      case "downloadsCmd_open": {
+        return this._file.exists() &&
+               ((this._dataItem && this._dataItem.openable) ||
+                (this._state == nsIDM.DOWNLOAD_FINISHED));
+      }
+      case "downloadsCmd_show": {
+        return this._getTargetFileOrPartFileIfExists() != null;
+      }
+      case "downloadsCmd_pauseResume":
+        return this._dataItem && this._dataItem.inProgress && this._dataItem.resumable;
+      case "downloadsCmd_retry":
+        return ((this._dataItem && this._dataItem.canRetry) ||
+                (!this._dataItem && this._file))
+      case "downloadsCmd_openReferrer":
+        return this._dataItem && !!this._dataItem.referrer;
+      case "cmd_delete":
+        // The behavior in this case is somewhat unexpected, so we disallow that.
+        if (this._placesNode && this._dataItem && this._dataItem.inProgress)
+          return false;
+        return true;
+      case "downloadsCmd_cancel":
+        return this._dataItem != null;
+    }
+  },
+
+  _getTargetFileOrPartFileIfExists: function DES__getTargetFileOrPartFileIfExists() {
+    if (this._file && this._file.exists())
+      return this._file;
+    if (this._dataItem &&
+        this._dataItem.partFile && this._dataItem.partFile.exists())
+      return this._dataItem.partFile;
+    return null;
+  },
+
+  _retryAsHistoryDownload: function DES__retryAsHistoryDownload() {
+    // TODO: save in the right location (the current saveURL api does not allow this)
+    saveURL(this.downloadURI, this._displayName, null, true, true, undefined, document);
+  },
+
+  /* nsIController */
+  doCommand: function DES_doCommand(aCommand) {
+    switch (aCommand) {
+      case "downloadsCmd_open": {
+        if (this._dateItem)
+          this._dataItem.openLocalFile(window);
+        else
+          DownloadsCommon.openDownloadedFile(this._file, null, window);
+        break;
+      }
+      case "downloadsCmd_show": {
+        if (this._dataItem)
+          this._dataItem.showLocalFile();
+        else
+          DownloadsCommon.showDownloadedFile(this._getTargetFileOrPartFileIfExists());
+        break;
+      }
+      case "downloadsCmd_openReferrer": {
+        openURL(this._dataItem.referrer);
+        break;
+      }
+      case "downloadsCmd_cancel": {
+        this._dataItem.cancel();
+        break;
+      }
+      case "cmd_delete": {
+        if (this._dataItem)
+          this._dataItem.remove();
+        if (this._placesNode)
+          PlacesUtils.bhistory.removePage(NetUtil.newURI(this.downloadURI));
+        break;
+       }
+      case "downloadsCmd_retry": {
+        if (this._dataItem)
+          this._dataItem.retry();
+        else
+          this._retryAsHistoryDownload();
+        break;
+      }
+      case "downloadsCmd_pauseResume": {
+        this._dataItem.togglePauseResume();
+        break;
+      }
+    }
+  },
+
+  // Returns whether or not the download handled by this shell should
+  // show up in the search results for the given term.  Both the display
+  // name for the download and the url are searched.
+  matchesSearchTerm: function DES_matchesSearchTerm(aTerm) {
+    // Stub implemention until we figure out something better
+    aTerm = aTerm.toLowerCase();
+    return this._displayName.toLowerCase().indexOf(aTerm) != -1 ||
+           this.downloadURI.toLowerCase().indexOf(aTerm) != -1;
+  },
+
+  // Handles return kepress on the element (the keypress listener is
+  // set in the DownloadsPlacesView object).
+  doDefaultCommand: function DES_doDefaultCommand() {
+    function getDefaultCommandForState(aState) {
+      switch (aState) {
+        case nsIDM.DOWNLOAD_FINISHED:
+          return "downloadsCmd_open";
+        case nsIDM.DOWNLOAD_PAUSED:
+          return "downloadsCmd_pauseResume";
+        case nsIDM.DOWNLOAD_NOTSTARTED:
+        case nsIDM.DOWNLOAD_QUEUED:
+          return "downloadsCmd_cancel";
+        case nsIDM.DOWNLOAD_FAILED:
+        case nsIDM.DOWNLOAD_CANCELED:
+          return "downloadsCmd_retry";
+        case nsIDM.DOWNLOAD_DOWNLOADING:
+        case nsIDM.DOWNLOAD_SCANNING:
+          return "downloadsCmd_show";
+        case nsIDM.DOWNLOAD_BLOCKED_PARENTAL:
+        case nsIDM.DOWNLOAD_DIRTY:
+        case nsIDM.DOWNLOAD_BLOCKED_POLICY:
+          return "downloadsCmd_openReferrer";
+      }
+    }
+    let command = getDefaultCommandForState(this._state);
+    if (this.isCommandEnabled(command))
+      this.doCommand(command);
+  }
+};
+
+/**
+ * A Downloads Places View is a places view designed to show a places query
+ * for history donwloads alongside the current "session"-downloads.
+ *
+ * As we don't use the places controller, some methods implemented by other
+ * places views are not implemented by this view.
+ *
+ * A richlistitem in this view can represent either a past download or a session
+ * download, or both. Session downloads are shown first in the view, and as long
+ * as they exist they "collapses" their history "counterpart" (So we don't show two
+ * items for every download).
+ */
+function DownloadsPlacesView(aRichListBox) {
+  this._richlistbox = aRichListBox;
+  this._richlistbox._placesView = this;
+  this._richlistbox.controllers.appendController(this);
+
+  // Map download URLs to download element shells regardless of their type
+  this._downloadElementsShellsForURI = new Map();
+
+  // Map download data items to their element shells.
+  this._viewItemsForDataItems = new WeakMap();
+
+  // Points to the last session download element. We keep track of this
+  // in order to keep all session downloads above past downloads.
+  this._lastSessionDownloadElement = null;
+
+  this._searchTerm = "";
+
+  // Register as a downloads view. The places data will be initialized by
+  // the places setter.
+  let downloadsData = DownloadsCommon.getData(window.opener || window);
+  downloadsData.addView(this);
+
+  // Make sure to unregister the view if the window is closed.
+  window.addEventListener("unload", function() {
+    downloadsData.removeView(this);
+    this.result = null;
+  }.bind(this), true);
+}
+
+DownloadsPlacesView.prototype = {
+  get associatedElement() this._richlistbox,
+
+  _forEachDownloadElementShellForURI:
+  function DPV__forEachDownloadElementShellForURI(aURI, aCallback) {
+    if (this._downloadElementsShellsForURI.has(aURI)) {
+      let downloadElementShells = this._downloadElementsShellsForURI.get(aURI);
+      for (let des of downloadElementShells) {
+        aCallback(des);
+      }
+    }
+  },
+
+  // Given a data item for a session download, or a places node for a past
+  // download, updates the view as necessary.
+  // 1. If the given data is a places node, we check whether there are any
+  //    element for the same download url. If there are, then we just reset
+  //    their places node. Otherwise we add a new download element.
+  // 2. If the given data is a data item, we first check if there's an history
+  //    download in the list that is not associated with a data item. If we found
+  //    one, we use it for the data item as well and reposition it alongside the
+  //    other session downloads. If we don't, then we go ahead and create a new
+  //    element for the download.
+  _addDownloadData:
+  function DPV_addDownload(aDataItem, aPlacesNode, aNewest) {
+    let downloadURI = aPlacesNode ? aPlacesNode.uri : aDataItem.uri;
+    let shellsForURI = this._downloadElementsShellsForURI.get(downloadURI, null);
+    if (!shellsForURI) {
+      shellsForURI = new Set();
+      this._downloadElementsShellsForURI.set(downloadURI, shellsForURI);
+    }
+
+    let newOrUpdatedShell = null;
+
+    // Trivial: if there are no shells for this download URI, we always
+    // need to create one.
+    let shouldCreateShell = shellsForURI.size == 0;
+
+    // However, if we do have shells for this download uri, there are
+    // few options:
+    // 1) There's only one shell and it's for a history download (it has
+    //    no data item). In this case, we update this shell and move it
+    //    if necessary
+    // 2) There are multiple shells, indicicating multiple downloads for
+    //    the same download uri are running. In this case we create
+    //    anoter shell for the download (so we have one shell for each data
+    //    item).
+    //
+    // Note: If a cancelled session download is already in the list, and the
+    // download is retired, onDataItemAdded is called again for the same
+    // data item. Thus, we also check that we make sure we don't have a view item
+    // already.
+    if (!shouldCreateShell &&
+        aDataItem && this.getViewItem(aDataItem) == null) {
+      // If there's a past-download-only shell for this download-uri with no
+      // associated data item, use it for the new data item. Otherwise, go ahead
+      // and create another shell.
+      shouldCreateShell = true;
+      for (let shell of shellsForURI) {
+        if (!shell.dataItem) {
+          shouldCreateShell = false;
+          shell.dataItem = aDataItem;
+          newOrUpdatedShell = shell;
+          this._viewItemsForDataItems.set(aDataItem, shell);
+          break;
+        }
+      }
+    }
+
+    if (shouldCreateShell) {
+      let shell = new DownloadElementShell(aDataItem, aPlacesNode);
+      newOrUpdatedShell = shell;
+      element = shell.element;
+      shellsForURI.add(shell);
+      if (aDataItem)
+        this._viewItemsForDataItems.set(aDataItem, shell);
+    }
+    else if (aPlacesNode) {
+      for (let shell of shellsForURI) {
+        if (shell.placesNode != aPlacesNode)
+          shell.placesNode = aPlacesNode;
+      }
+    }
+
+    if (newOrUpdatedShell) {
+      if (aNewest) {
+        this._richlistbox.insertBefore(newOrUpdatedShell.element,
+                                       this._richlistbox.firstChild);
+        if (!this._lastSessionDownloadElement) {
+          this._lastSessionDownloadElement = newOrUpdatedShell.element;
+        }
+      }
+      else if (aDataItem) {
+        let before = this._lastSessionDownloadElement ?
+          this._lastSessionDownloadElement.nextSibling : this._richlistbox.firstChild
+        this._richlistbox.insertBefore(newOrUpdatedShell.element, before)
+        this._lastSessionDownloadElement = newOrUpdatedShell.element;
+      }
+      else {
+        this._richlistbox.appendChild(newOrUpdatedShell.element);
+      }
+
+      if (this.searchTerm) {
+        newOrUpdatedShell.element.hidden =
+          !newOrUpdatedShell.element._shell.matchesSearchTerm(this.searchTerm);
+      }
+    }
+  },
+
+  _removeElement: function DPV__removeElement(aElement) {
+    // If the element was selected exclusively, select its next
+    // sibling first, if any.
+    if (aElement.nextSibling &&
+        this._richlistbox.selectedItems &&
+        this._richlistbox.selectedItems[0] == aElement) {
+      this._richlistbox.selectItem(aElement.nextSibling);
+    }
+    this._richlistbox.removeChild(aElement);
+  },
+
+  _removeHistoryDownloadFromView:
+  function DPV__removeHistoryDownloadFromView(aPlacesNode) {
+    let downloadURI = aPlacesNode.uri;
+    let shellsForURI = this._downloadElementsShellsForURI.get(downloadURI, null);
+    if (shellsForURI) {
+      for (let shell of shellsForURI) {
+        if (shell.dataItem) {
+          shell.placesNode = null;
+        }
+        else {
+          this._removeElement(shell.element);
+          shellsForURI.delete(shell);
+          if (shellsForURI.size == 0)
+            this._downloadElementsShellsForURI.delete(downloadURI);
+        }
+      }
+    }
+  },
+
+  _removeSessionDownloadFromView:
+  function DPV__removeSessionDownloadFromView(aDataItem) {
+    let shells = this._downloadElementsShellsForURI.get(aDataItem.uri, null);
+    if (shells.size == 0)
+      throw new Error("Should have had at leaat one shell for this uri");
+
+    let shell = this.getViewItem(aDataItem);
+    if (!shells.has(shell))
+      throw new Error("Missing download element shell in shells list for url");
+
+    // If there's more than one item for this download uri, we can let the
+    // view item for this this particular data item go away.
+    // If there's only one item for this download uri, we should only
+    // keep it if it is associated with a history download.
+    if (shells.size > 1 || !shell.placesNode) {
+      this._removeElement(shell.element);
+      shells.delete(shell);
+      if (shells.size == 0)
+        this._downloadElementsShellsForURI.delete(aDataItem.uri);
+      return;
+    }
+    else {
+      shell.dataItem = null;
+      // Move it below the session-download items;
+      if (this._lastSessionDownloadElement == shell.dataItem) {
+        this._lastSessionDownloadElement = shell.dataItem.previousSibling;
+      }
+      else {
+        let before = this._lastSessionDownloadElement ?
+          this._lastSessionDownloadElement.nextSibling : this._richlistbox.firstchild;
+        this._richlistbox.insertBefore(shell.element, before);
+      }
+    }
+  },
+
+  get place() this._place,
+
+  set place(val) {
+    // Don't reload everything if we don't have to.
+    if (this._place == val) {
+      // XXXmano: places.js relies on this behavior (see Bug 822203).
+      this.searchTerm = "";
+      return val;
+    }
+
+    this._place = val;
+
+    let history = PlacesUtils.history;
+    let queries = { }, options = { };
+    history.queryStringToQueries(val, queries, { }, options);
+    if (!queries.value.length)
+      queries.value = [history.getNewQuery()];
+
+    let result = history.executeQueries(queries.value, queries.value.length,
+                                        options.value);
+    result.addObserver(this, false);
+    return val;
+  },
+
+  get result() this._result,
+  set result(val) {
+    if (this._result == val)
+      return val;
+
+    if (this._result) {
+      this._result.removeObserver(this);
+      this._resultNode.containerOpen = false;
+    }
+
+    if (val) {
+      this._result = val;
+      this._resultNode = val.root;
+      this._resultNode.containerOpen = true;
+    }
+    else {
+      delete this._resultNode;
+      delete this._result;
+    }
+
+    return val;
+  },
+
+  get selectedNodes() {
+    let placesNodes = [];
+    let selectedElements = this._richlistbox.selectedItems;
+    for (let elt of selectedElements) {
+      if (elt.placesNode)
+        placesNodes.push(elt.placesNode);
+    }
+    return placesNodes;
+  },
+
+  get selectedNode() {
+    let selectedNodes = this.selectedNodes;
+    return selectedNodes.length == 1 ? selectedNodes[0] : null;
+  },
+
+  get hasSelection() this.selectedNodes.length > 0,
+
+  containerStateChanged:
+  function DPV_containerStateChanged(aNode, aOldState, aNewState) {
+    this.invalidateContainer(aNode)
+  },
+
+  invalidateContainer:
+  function DPV_invalidateContainer(aContainer) {
+    if (aContainer != this._resultNode)
+      throw new Error("Unexpected container node");
+    if (!aContainer.containerOpen)
+      throw new Error("Root container for the downloads query cannot be closed");
+
+    // Remove the invalidated history downloads from the list and unset the
+    // places node for data downloads.
+    for (let element of this._richlistbox.childNodes) {
+      if (element._shell.placesNode)
+        this._removeHistoryDownloadFromView(element._shell.placesNode);
+    }
+
+    for (let i = 0; i < aContainer.childCount; i++) {
+      try {
+        this._addDownloadData(null, aContainer.getChild(i), false)
+      }
+      catch(ex) {
+        Cu.reportError(ex);
+      }
+    }
+  },
+
+  nodeInserted: function DPV_nodeInserted(aParent, aPlacesNode) {
+    this._addDownloadData(null, aPlacesNode, false);
+  },
+
+  nodeRemoved: function DPV_nodeRemoved(aParent, aPlacesNode, aOldIndex) {
+    this._removeHistoryDownloadFromView(aPlacesNode);
+  },
+
+  nodeIconChanged: function DPV_nodeIconChanged(aNode) {
+    this._forEachDownloadElementShellForURI(aNode.uri, function(aDownloadElementShell) {
+      aDownloadElementShell.placesNodeIconChanged();
+    });
+  },
+
+  nodeAnnotationChanged: function DPV_nodeAnnotationChanged(aNode, aAnnoName) {
+    this._forEachDownloadElementShellForURI(aNode.uri, function(aDownloadElementShell) {
+      aDownloadElementShell.placesNodeAnnotationChanged(aAnnoName);
+    });
+  },
+
+  nodeTitleChanged: function DPV_nodeTitleChanged(aNode, aNewTitle) {
+    this._forEachDownloadElementShellForURI(aNode.uri, function(aDownloadElementShell) {
+      aDownloadElementShell.placesNodeTitleChanged();
+    });
+  },
+
+  nodeKeywordChanged: function() {},
+  nodeDateAddedChanged: function() {},
+  nodeLastModifiedChanged: function() {},
+  nodeReplaced: function() {},
+  nodeHistoryDetailsChanged: function() {},
+  nodeTagsChanged: function() {},
+  sortingChanged: function() {},
+  nodeMoved: function() {},
+  nodeURIChanged: function() {},
+
+  get controller() this._richlistbox.controller,
+
+  get searchTerm() this._searchTerm,
+  set searchTerm(aValue) {
+    if (this._searchTerm != aValue) {
+      for (let element of this._richlistbox.childNodes) {
+        element.hidden = !element._shell.matchesSearchTerm(aValue);
+      }
+    }
+    return this._searchTerm = aValue;
+  },
+
+  applyFilter: function() {
+    throw new Error("applyFilter is not implemented by the DownloadsView")
+  },
+
+  load: function(aQueries, aOptions) {
+    throw new Error("|load| is not implemented by the Downloads View");
+  },
+
+  onDataLoadStarting: function() { },
+  onDataLoadCompleted: function() { },
+
+  onDataItemAdded: function DPV_onDataItemAdded(aDataItem, aNewest) {
+    this._addDownloadData(aDataItem, null, aNewest);
+  },
+
+  onDataItemRemoved: function DPV_onDataItemRemoved(aDataItem) {
+    this._removeSessionDownloadFromView(aDataItem)
+  },
+
+  getViewItem: function(aDataItem)
+    this._viewItemsForDataItems.get(aDataItem, null),
+
+  supportsCommand: function(aCommand)
+    DOWNLOAD_VIEW_SUPPORTED_COMMANDS.indexOf(aCommand) != -1,
+
+  isCommandEnabled: function DPV_isCommandEnabled(aCommand) {
+    let selectedElements = this._richlistbox.selectedItems;
+    switch (aCommand) {
+      case "cmd_copy":
+        return selectedElements && selectedElements.length > 0;
+      case "cmd_selectAll":
+        return true;
+      case "cmd_paste":
+        return this._canDownloadClipboardURL();
+      default:
+        return Array.every(selectedElements, function(element) {
+          return element._shell.isCommandEnabled(aCommand);
+        });
+    }
+  },
+
+  _copySelectedDownloadsToClipboard:
+  function DPV__copySelectedDownloadsToClipboard() {
+    let selectedElements = this._richlistbox.selectedItems;
+    let urls = [e._shell.downloadURI for each (e in selectedElements)];
+
+    Cc["@mozilla.org/widget/clipboardhelper;1"].
+    getService(Ci.nsIClipboardHelper).copyString(urls.join("\n"), document);
+  },
+
+  _getURLFromClipboardData: function DPV__getURLFromClipboardData() {
+    let trans = Cc["@mozilla.org/widget/transferable;1"].
+                createInstance(Ci.nsITransferable);
+    trans.init(null);
+
+    let flavors = ["text/x-moz-url", "text/unicode"];
+    flavors.forEach(trans.addDataFlavor);
+
+    Services.clipboard.getData(trans, Services.clipboard.kGlobalClipboard);
+
+    // Getting the data or creating the nsIURI might fail
+    try {
+      let data = {};
+      trans.getAnyTransferData({}, data, {});
+      let [url, name] = data.value.QueryInterface(Ci.nsISupportsString)
+                            .data.split("\n");
+      if (url)
+        return [NetUtil.newURI(url, null, null).spec, name];
+    }
+    catch(ex) { }
+
+    return ["", ""];
+  },
+
+  _canDownloadClipboardURL: function DPV__canDownloadClipboardURL() {
+    let [url, name] = this._getURLFromClipboardData();
+    return url != "";
+  },
+
+  _downloadURLFromClipboard: function DPV__downloadURLFromClipboard() {
+    let [url, name] = this._getURLFromClipboardData();
+    saveURL(url, name || url, null, true, true, undefined, document);
+  },
+
+  doCommand: function DPV_doCommand(aCommand) {
+    switch (aCommand) {
+      case "cmd_copy":
+        this._copySelectedDownloadsToClipboard();
+        break;
+      case "cmd_selectAll":
+        this._richlistbox.selectAll();
+        break;
+      case "cmd_paste":
+        this._downloadURLFromClipboard();
+        break;
+      default: {
+        let selectedElements = this._richlistbox.selectedItems;
+        for (let element of selectedElements) {
+          element._shell.doCommand(aCommand);
+        }
+      }
+    }
+  },
+
+  onEvent: function() { },
+
+  onContextMenu: function DPV_onContextMenu(aEvent)
+  {
+    let element = this._richlistbox.selectedItem;
+    if (!element || !element._shell)
+      return false;
+
+    // Set the state attribute so that only the appropriate items are displayed.
+    let contextMenu = document.getElementById("downloadsContextMenu");
+    contextMenu.setAttribute("state", element._shell._state);
+  },
+
+  onKeyPress: function DPV_onKeyPress(aEvent) {
+    let selectedElements = this._richlistbox.selectedItems;
+    if (!selectedElements)
+      return;
+
+    if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN) {
+      // In the content tree, opening bookmarks by pressing return is only
+      // supported when a single item is selected. To be consistent, do the
+      // same here.
+      if (selectedElements.length == 1) {
+        let element = selectedElements[0];
+        if (element._shell)
+          element._shell.doDefaultCommand();
+      }
+    }
+    else if (aEvent.charCode == " ".charCodeAt(0)) {
+      // Pausue/Resume every selected download
+      for (let element of selectedElements) {
+        if (element._shell.isCommandEnabled("downloadsCmd_pauseResume"))
+          element._shell.doCommand("downloadsCmd_pauseResume");
+      }
+    }
+  }
+};
+
+function goUpdateDownloadCommands() {
+  for (let command of DOWNLOAD_VIEW_SUPPORTED_COMMANDS) {
+    goUpdateCommand(command);
+  }
+}
--- a/browser/components/places/content/places.css
+++ b/browser/components/places/content/places.css
@@ -9,8 +9,38 @@ tree[type="places"] {
 .toolbar-drop-indicator {
   position: relative;
   z-index: 1;
 }
 
 menupopup[placespopup="true"] {
   -moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-base");
 }
+
+richlistitem.download {
+	-moz-binding: url('chrome://browser/content/places/download.xml#download');
+}
+
+.download-state:not(          [state="0"]  /* Downloading        */)
+                                           .downloadPauseMenuItem,
+.download-state:not(          [state="4"]  /* Paused             */)
+                                           .downloadResumeMenuItem,
+.download-state:not(:-moz-any([state="2"], /* Failed             */
+                              [state="4"]) /* Paused             */)
+                                           .downloadCancelMenuItem,
+.download-state:not(:-moz-any([state="1"], /* Finished           */
+                              [state="2"], /* Failed             */
+                              [state="3"], /* Canceled           */
+                              [state="6"], /* Blocked (parental) */
+                              [state="8"], /* Blocked (dirty)    */
+                              [state="9"]) /* Blocked (policy)   */)
+                                           .downloadRemoveFromHistoryMenuItem,
+.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
+                              [state="5"], /* Starting (queued)  */
+                              [state="0"], /* Downloading        */
+                              [state="4"]) /* Paused             */)
+                                           .downloadShowMenuItem,
+
+.download-state[state="7"]                 .downloadCommandsSeparator
+
+{
+  display: none;
+}
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -1,18 +1,22 @@
 /* -*- Mode: C++; tab-width: 8; 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/. */
 
 Components.utils.import("resource:///modules/MigrationUtils.jsm");
 
+const DOWNLOADS_QUERY = "place:transition=" +
+  Components.interfaces.nsINavHistoryService.TRANSITION_DOWNLOAD +
+  "&sort=" +
+  Components.interfaces.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING;
+
 var PlacesOrganizer = {
   _places: null,
-  _content: null,
 
   // IDs of fields from editBookmarkOverlay that should be hidden when infoBox
   // is minimal. IDs should be kept in sync with the IDs of the elements
   // observing additionalInfoBroadcaster.
   _additionalInfoFields: [
     "editBMPanel_descriptionRow",
     "editBMPanel_loadInSidebarCheckbox",
     "editBMPanel_keywordRow",
@@ -27,35 +31,30 @@ var PlacesOrganizer = {
     var itemId = PlacesUIUtils.leftPaneQueries[aQueryName];
     this._places.selectItems([itemId]);
     // Forcefully expand all-bookmarks
     if (aQueryName == "AllBookmarks")
       PlacesUtils.asContainer(this._places.selectedNode).containerOpen = true;
   },
 
   init: function PO_init() {
+    ContentArea.init();
+
     this._places = document.getElementById("placesList");
-    this._content = document.getElementById("placeContent");
     this._initFolderTree();
 
     var leftPaneSelection = "AllBookmarks"; // default to all-bookmarks
     if (window.arguments && window.arguments[0])
       leftPaneSelection = window.arguments[0];
 
     this.selectLeftPaneQuery(leftPaneSelection);
     // clear the back-stack
     this._backHistory.splice(0, this._backHistory.length);
     document.getElementById("OrganizerCommand:Back").setAttribute("disabled", true);
 
-    var view = this._content.treeBoxObject.view;
-    if (view.rowCount > 0)
-      view.selection.select(0);
-
-    this._content.focus();
-
     // Set up the search UI.
     PlacesSearchBox.init();
 
     window.addEventListener("AppCommand", this, true);
 #ifdef XP_MACOSX
     // 1. Map Edit->Find command to OrganizerCommand_find:all.  Need to map
     // both the menuitem and the Find key.
     var findMenuItem = document.getElementById("menu_find");
@@ -79,16 +78,23 @@ var PlacesOrganizer = {
 
     // remove the "Properties" context-menu item, we've our own details pane
     document.getElementById("placesContext")
             .removeChild(document.getElementById("placesContext_show:info"));
 
 #ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
     gPrivateBrowsingListener.init();
 #endif
+
+    // Select the first item in the content area view.
+    let view = ContentArea.currentView;
+    let root = view.result ? view.result.root : null;
+    if (root && root.containerOpen && root.childCount >= 0)
+      view.selectNode(root.getChild(0));
+    ContentArea.focus();
   },
 
   QueryInterface: function PO_QueryInterface(aIID) {
     if (aIID.equals(Components.interfaces.nsIDOMEventListener) ||
         aIID.equals(Components.interfaces.nsISupports))
       return this;
 
     throw Components.results.NS_NOINTERFACE;
@@ -134,19 +140,19 @@ var PlacesOrganizer = {
       this._forwardHistory.splice(0, this._forwardHistory.length);
     }
 
     this._location = aLocation;
     this._places.selectPlaceURI(aLocation);
 
     if (!this._places.hasSelection) {
       // If no node was found for the given place: uri, just load it directly
-      this._content.place = aLocation;
+      ContentArea.currentPlace = aLocation;
     }
-    this.onContentTreeSelect();
+    this.updateDetailsPane();
 
     // update navigation commands
     if (this._backHistory.length == 0)
       document.getElementById("OrganizerCommand:Back").setAttribute("disabled", true);
     else
       document.getElementById("OrganizerCommand:Back").removeAttribute("disabled");
     if (this._forwardHistory.length == 0)
       document.getElementById("OrganizerCommand:Forward").setAttribute("disabled", true);
@@ -196,18 +202,18 @@ var PlacesOrganizer = {
     options.excludeItems = false;
     var placeURI = PlacesUtils.history.queriesToQueryString(queries,
                                                             queries.length,
                                                             options);
 
     // If either the place of the content tree in the right pane has changed or
     // the user cleared the search box, update the place, hide the search UI,
     // and update the back/forward buttons by setting location.
-    if (this._content.place != placeURI || !resetSearchBox) {
-      this._content.place = placeURI;
+    if (ContentArea.currentPlace != placeURI || !resetSearchBox) {
+      ContentArea.currentPlace = placeURI;
       this.location = node.uri;
     }
 
     // When we invalidate a container we use suppressSelectionEvent, when it is
     // unset a select event is fired, in many cases the selection did not really
     // change, so we should check for it, and return early in such a case. Note
     // that we cannot return any earlier than this point, because when
     // !resetSearchBox, we need to update location and hide the UI as above,
@@ -216,18 +222,17 @@ var PlacesOrganizer = {
       return;
     this._cachedLeftPaneSelectedURI = node.uri;
 
     // At this point, resetSearchBox is true, because the left pane selection
     // has changed; otherwise we would have returned earlier.
 
     PlacesSearchBox.searchFilter.reset();
     this._setSearchScopeForNode(node);
-    if (this._places.treeBoxObject.focused)
-      this._fillDetailsPane([node]);
+    this.updateDetailsPane();
   },
 
   /**
    * Sets the search scope based on aNode's properties.
    * @param   aNode
    *          the node to set up scope from
    */
   _setSearchScopeForNode: function PO__setScopeForNode(aNode) {
@@ -242,88 +247,72 @@ var PlacesOrganizer = {
     }
     else {
       // Default to All Bookmarks for all other nodes, per bug 469437.
       PlacesQueryBuilder.setScope("bookmarks");
     }
   },
 
   /**
-   * Handle clicks on the tree.
+   * Handle clicks on the places list.
    * Single Left click, right click or modified click do not result in any
    * special action, since they're related to selection.
    * @param   aEvent
    *          The mouse event.
    */
-  onTreeClick: function PO_onTreeClick(aEvent) {
+  onPlacesListClick: function PO_onPlacesListClick(aEvent) {
     // Only handle clicks on tree children.
     if (aEvent.target.localName != "treechildren")
       return;
 
-    var currentView = aEvent.currentTarget;
-    var selectedNode = currentView.selectedNode;
-    if (selectedNode) {
-      var doubleClickOnFlatList = (aEvent.button == 0 && aEvent.detail == 2 &&
-                                   aEvent.target.parentNode.flatList);
-      var middleClick = (aEvent.button == 1 && aEvent.detail == 1);
-
-      if (PlacesUtils.nodeIsURI(selectedNode) &&
-          (doubleClickOnFlatList || middleClick)) {
-        // Open associated uri in the browser.
-        PlacesOrganizer.openSelectedNode(aEvent);
-      }
-      else if (middleClick &&
-               PlacesUtils.nodeIsContainer(selectedNode)) {
+    let node = this._places.selectedNode;
+    if (node) {
+      let middleClick = aEvent.button == 1 && aEvent.detail == 1;
+      if (middleClick && PlacesUtils.nodeIsContainer(node)) {
         // The command execution function will take care of seeing if the
         // selection is a folder or a different container type, and will
         // load its contents in tabs.
-        PlacesUIUtils.openContainerNodeInTabs(selectedNode, aEvent, currentView);
+        PlacesUIUtils.openContainerNodeInTabs(selectedNode, aEvent, this._places);
       }
     }
   },
 
   /**
-   * Handle focus changes on the trees.
-   * When moving focus between panes we should update the details pane contents.
-   * @param   aEvent
-   *          The mouse event.
+   * Handle focus changes on the places list and the current content view.
    */
-  onTreeFocus: function PO_onTreeFocus(aEvent) {
-    var currentView = aEvent.currentTarget;
-    var selectedNodes = currentView.selectedNode ? [currentView.selectedNode] :
-                        this._content.selectedNodes;
-    this._fillDetailsPane(selectedNodes);
+  updateDetailsPane: function PO_updateDetailsPane() {
+    let view = PlacesUIUtils.getViewForNode(document.activeElement);
+    if (view) {
+      let selectedNodes = view.selectedNode ?
+                          [view.selectedNode] : view.selectedNodes;
+      this._fillDetailsPane(selectedNodes);
+    }
   },
 
   openFlatContainer: function PO_openFlatContainerFlatContainer(aContainer) {
     if (aContainer.itemId != -1)
       this._places.selectItems([aContainer.itemId]);
     else if (PlacesUtils.nodeIsQuery(aContainer))
       this._places.selectPlaceURI(aContainer.uri);
   },
 
-  openSelectedNode: function PO_openSelectedNode(aEvent) {
-    PlacesUIUtils.openNodeWithEvent(this._content.selectedNode, aEvent,
-                                    this._content);
-  },
-
   /**
    * Returns the options associated with the query currently loaded in the
    * main places pane.
    */
   getCurrentOptions: function PO_getCurrentOptions() {
-    return PlacesUtils.asQuery(this._content.result.root).queryOptions;
+    return PlacesUtils.asQuery(ContentArea.currentView.result.root).queryOptions;
   },
 
   /**
    * Returns the queries associated with the query currently loaded in the
    * main places pane.
    */
   getCurrentQueries: function PO_getCurrentQueries() {
-    return PlacesUtils.asQuery(this._content.result.root).getQueries();
+    return PlacesUtils.asQuery(ContentArea.currentView.result.root).getQueries();
   },
 
   /**
    * Show the migration wizard for importing passwords,
    * cookies, history, preferences, and bookmarks.
    */
   importFromBrowser: function PO_importFromBrowser() {
     MigrationUtils.showMigrationWizard(window);
@@ -559,21 +548,16 @@ var PlacesOrganizer = {
     var previewBox = document.getElementById("previewBox");
     var canvas = document.getElementById("itemThumbnail");
     var height = previewBox.boxObject.height;
     var width = height * (screen.width / screen.height);
     canvas.width = width;
     canvas.height = height;
   },
 
-  onContentTreeSelect: function PO_onContentTreeSelect() {
-    if (this._content.treeBoxObject.focused)
-      this._fillDetailsPane(this._content.selectedNodes);
-  },
-
   _fillDetailsPane: function PO__fillDetailsPane(aNodeList) {
     var infoBox = document.getElementById("infoBox");
     var detailsDeck = document.getElementById("detailsDeck");
 
     // Make sure the infoBox UI is visible if we need to use it, we hide it
     // below when we don't.
     infoBox.hidden = false;
     var aSelectedNode = aNodeList.length == 1 ? aNodeList[0] : null;
@@ -666,28 +650,33 @@ var PlacesOrganizer = {
                                                 "keyword",
                                                 "description",
                                                 "name"]});
       this._detectAndSetDetailsPaneMinimalState(aSelectedNode);
     }
     else {
       detailsDeck.selectedIndex = 0;
       infoBox.hidden = true;
-      var selectItemDesc = document.getElementById("selectItemDescription");
-      var itemsCountLabel = document.getElementById("itemsCountText");
-      var rowCount = this._content.treeBoxObject.view.rowCount;
-      if (rowCount == 0) {
+      let selectItemDesc = document.getElementById("selectItemDescription");
+      let itemsCountLabel = document.getElementById("itemsCountText");
+      let itemsCount = 0;
+      if (ContentArea.currentView.result) {
+        let rootNode = ContentArea.currentView.result.root;
+        if (rootNode.containerOpen)
+          itemsCount = rootNode.childCount;
+      }
+      if (itemsCount == 0) {
         selectItemDesc.hidden = true;
         itemsCountLabel.value = PlacesUIUtils.getString("detailsPane.noItems");
       }
       else {
         selectItemDesc.hidden = false;
         itemsCountLabel.value =
           PlacesUIUtils.getPluralString("detailsPane.itemsCountLabel",
-                                        rowCount, [rowCount]);
+                                        itemsCount, [itemsCount]);
       }
     }
   },
 
   // NOT YET USED
   _updateThumbnail: function PO__updateThumbnail() {
     var bo = document.getElementById("previewBox").boxObject;
     var width  = bo.width;
@@ -774,59 +763,63 @@ var PlacesSearchBox = {
     // contents of the current scope.
     // XXX this might be to jumpy, maybe should search for "", so results
     // are ungrouped, and search box not reset
     if (filterString == "") {
       PO.onPlaceSelected(false);
       return;
     }
 
-    var currentOptions = PO.getCurrentOptions();
-    var content = PO._content;
+    let currentView = ContentArea.currentView;
+    let currentOptions = PO.getCurrentOptions();
 
     // Search according to the current scope, which was set by
     // PQB_setScope()
     switch (PlacesSearchBox.filterCollection) {
       case "bookmarks":
-        content.applyFilter(filterString, this.folders);
+        currentView.applyFilter(filterString, this.folders);
         break;
       case "history":
         if (currentOptions.queryType != Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY) {
           var query = PlacesUtils.history.getNewQuery();
           query.searchTerms = filterString;
           var options = currentOptions.clone();
           // Make sure we're getting uri results.
           options.resultType = currentOptions.RESULT_TYPE_URI;
           options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY;
           options.includeHidden = true;
-          content.load([query], options);
+          currentView.load([query], options);
         }
         else {
-          content.applyFilter(filterString, null, true);
+          currentView.applyFilter(filterString, null, true);
         }
         break;
-      case "downloads": {
+      case "downloads":
+        if (currentView == ContentTree.view) {
           let query = PlacesUtils.history.getNewQuery();
           query.searchTerms = filterString;
           query.setTransitions([Ci.nsINavHistoryService.TRANSITION_DOWNLOAD], 1);
           let options = currentOptions.clone();
           // Make sure we're getting uri results.
           options.resultType = currentOptions.RESULT_TYPE_URI;
           options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY;
           options.includeHidden = true;
-          content.load([query], options);
+          currentView.load([query], options);
+        }
+        else {
+          // The new downloads view doesn't use places for searching downloads.
+          currentView.searchTerm = filterString;
+        }
         break;
-    }
-    default:
-      throw "Invalid filterCollection on search";
-      break;
+      default:
+        throw "Invalid filterCollection on search";
     }
 
     // Update the details panel
-    PlacesOrganizer.onContentTreeSelect();
+    PlacesOrganizer.updateDetailsPane();
   },
 
   /**
    * Finds across all history, downloads or all bookmarks.
    */
   findAll: function PSB_findAll() {
     switch (this.filterCollection) {
       case "history":
@@ -1246,8 +1239,99 @@ let gPrivateBrowsingListener = {
   updateUI: function PO_PB_updateUI(PBmode) {
     if (PBmode)
       this._cmd_import.setAttribute("disabled", "true");
     else
       this._cmd_import.removeAttribute("disabled");
   }
 };
 #endif
+
+let ContentArea = {
+  init: function CA_init() {
+    this._deck = document.getElementById("placesViewsDeck");
+    this._specialViews = new Map();
+    ContentTree.init();
+  },
+
+  _shouldUseNewDownloadsView: function CA_shouldUseNewDownloadsView() {
+    try {
+      return Services.prefs.getBoolPref("browser.library.useNewDownloadsView");
+    }
+    catch(ex) { }
+    return false;
+  },
+
+  getContentViewForQueryString:
+  function CA_getContentViewForQueryString(aQueryString) {
+    if (this._specialViews.has(aQueryString))
+      return this._specialViews.get(aQueryString);
+    if (aQueryString == DOWNLOADS_QUERY && this._shouldUseNewDownloadsView()) {
+      let view = new DownloadsPlacesView(document.getElementById("downloadsRichListBox"));
+      this.setContentViewForQueryString(aQueryString, view);
+      return view;
+    }
+    return ContentTree.view;
+  },
+
+  setContentViewForQueryString:
+  function CA_setContentViewForQueryString(aQueryString, aView) {
+    this._specialViews.set(aQueryString, aView);
+  },
+
+  get currentView() PlacesUIUtils.getViewForNode(this._deck.selectedPanel),
+  set currentView(aView) {
+    if (this.currentView != aView)
+      this._deck.selectedPanel = aView.associatedElement;
+    return aView;
+  },
+
+  get currentPlace() this.currentView.place,
+  set currentPlace(aQueryString) {
+    this.currentView = this.getContentViewForQueryString(aQueryString);
+    this.currentView.place = aQueryString;
+    return aQueryString;
+  },
+
+  focus: function() {
+    this._deck.selectedPanel.focus();
+  }
+};
+
+let ContentTree = {
+  init: function CT_init() {
+    this._view = document.getElementById("placeContent");
+  },
+
+  get view() this._view,
+
+  openSelectedNode: function CT_openSelectedNode(aEvent) {
+    let view = this.view;
+    PlacesUIUtils.openNodeWithEvent(view.selectedNode, aEvent, view);
+  },
+
+  onClick: function CT_onClick(aEvent) {
+    // Only handle clicks on tree children.
+    if (aEvent.target.localName != "treechildren")
+      return;
+
+    let node = this.view.selectedNode;
+    if (node) {
+      let doubleClick = aEvent.button == 0 && aEvent.detail == 2;
+      let middleClick = aEvent.button == 1 && aEvent.detail == 1;
+      if (PlacesUtils.nodeIsURI(node) && (doubleClick || middleClick)) {
+        // Open associated uri in the browser.
+        this.openSelectedNode(aEvent);
+      }
+      else if (middleClick && PlacesUtils.nodeIsContainer(node)) {
+        // The command execution function will take care of seeing if the
+        // selection is a folder or a different container type, and will
+        // load its contents in tabs.
+        PlacesUIUtils.openContainerNodeInTabs(node, aEvent, this.view);
+      }
+    }
+  },
+
+  onKeyPress: function CT_onKeyPress(aEvent) {
+    if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN)
+      this.openSelectedNode(aEvent);
+  }
+};
--- a/browser/components/places/content/places.xul
+++ b/browser/components/places/content/places.xul
@@ -5,16 +5,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 <?xml-stylesheet href="chrome://browser/content/places/places.css"?>
 <?xml-stylesheet href="chrome://browser/content/places/organizer.css"?>
 
 <?xml-stylesheet href="chrome://global/skin/"?>
 <?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
 <?xml-stylesheet href="chrome://browser/skin/places/organizer.css"?>
+<?xml-stylesheet href="chrome://browser/skin/downloads/downloads.css"?>
 
 <?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
 
 #ifdef XP_MACOSX
 <?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
 #else
 <?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
@@ -23,36 +24,42 @@
 
 <!DOCTYPE window [
 <!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd">
 %placesDTD;
 <!ENTITY % editMenuOverlayDTD SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
 %editMenuOverlayDTD;
 <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
 %browserDTD;
+<!ENTITY % downloadsDTD SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
+%downloadsDTD;
 ]>
 
 <window id="places"
         title="&places.library.title;"
         windowtype="Places:Organizer"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         onload="PlacesOrganizer.init();"
         onunload="PlacesOrganizer.destroy();"
         width="&places.library.width;" height="&places.library.height;"
         screenX="10" screenY="10"
         toggletoolbar="true"
         persist="width height screenX screenY sizemode">
 
   <script type="application/javascript"
+          src="chrome://browser/content/places/downloadsView.js"/>
+  <script type="application/javascript"
           src="chrome://browser/content/places/places.js"/>
   <script type="application/javascript"
           src="chrome://browser/content/utilityOverlay.js"/>
   <script type="application/javascript"
           src="chrome://browser/content/places/editBookmarkOverlay.js"/>
+  <script type="application/javascript"
+          src="chrome://global/content/contentAreaUtils.js"/>
 
   <stringbundleset id="placesStringSet">
     <stringbundle id="brandStrings" src="chrome://branding/locale/brand.properties"/>
   </stringbundleset>
 
 
 #ifdef XP_MACOSX
 #include ../../../base/content/browserMountPoints.inc
@@ -339,73 +346,82 @@
   </toolbox>
 
   <hbox flex="1" id="placesView">
     <tree id="placesList"
           class="plain placesTree"
           type="places"
           hidecolumnpicker="true" context="placesContext"
           onselect="PlacesOrganizer.onPlaceSelected(true);"
-          onclick="PlacesOrganizer.onTreeClick(event);"
-          onfocus="PlacesOrganizer.onTreeFocus(event);"
+          onclick="PlacesOrganizer.onPlacesListClick(event);"
+          onfocus="PlacesOrganizer.updateDetailsPane(event);"
           seltype="single"
           persist="width"
           width="200"
           minwidth="100"
           maxwidth="400">
       <treecols>
         <treecol anonid="title" flex="1" primary="true" hideheader="true"/>
       </treecols>
       <treechildren flex="1"/>
     </tree>
     <splitter collapse="none" persist="state"></splitter>
     <vbox id="contentView" flex="4">
-      <tree id="placeContent"
-            class="plain placesTree"
-            context="placesContext"
-            hidecolumnpicker="true"
-            flex="1"
-            type="places"
-            flatList="true"
-            enableColumnDrag="true"
-            onkeypress="if (event.keyCode == KeyEvent.DOM_VK_RETURN) PlacesOrganizer.openSelectedNode(event);"
-            onopenflatcontainer="PlacesOrganizer.openFlatContainer(aContainer);"
-            onselect="PlacesOrganizer.onContentTreeSelect();"
-            onfocus="PlacesOrganizer.onTreeFocus(event);"
-            onclick="PlacesOrganizer.onTreeClick(event);">
-        <treecols id="placeContentColumns" context="placesColumnsContext">
-          <treecol label="&col.name.label;" id="placesContentTitle" anonid="title" flex="5" primary="true" ordinal="1" 
-                    persist="width hidden ordinal sortActive sortDirection"/>
-          <splitter class="tree-splitter"/>
-          <treecol label="&col.tags.label;" id="placesContentTags" anonid="tags" flex="2"
-                    persist="width hidden ordinal sortActive sortDirection"/>
-          <splitter class="tree-splitter"/>
-          <treecol label="&col.url.label;" id="placesContentUrl" anonid="url" flex="5"
-                    persist="width hidden ordinal sortActive sortDirection"/>
-          <splitter class="tree-splitter"/>
-          <treecol label="&col.lastvisit.label;" id="placesContentDate" anonid="date" flex="1" hidden="true"
-                    persist="width hidden ordinal sortActive sortDirection"/>
-          <splitter class="tree-splitter"/>
-          <treecol label="&col.visitcount.label;" id="placesContentVisitCount" anonid="visitCount" flex="1" hidden="true"
-                    persist="width hidden ordinal sortActive sortDirection"/>
-          <splitter class="tree-splitter"/>
-          <treecol label="&col.keyword.label;" id="placesContentKeyword" anonid="keyword" flex="1" hidden="true"
-                    persist="width hidden ordinal sortActive sortDirection"/>
-          <splitter class="tree-splitter"/>
-          <treecol label="&col.description.label;" id="placesContentDescription" anonid="description" flex="1" hidden="true"
-                    persist="width hidden ordinal sortActive sortDirection"/>
-          <splitter class="tree-splitter"/>
-          <treecol label="&col.dateadded.label;" id="placesContentDateAdded" anonid="dateAdded" flex="1" hidden="true"
-                    persist="width hidden ordinal sortActive sortDirection"/>
-          <splitter class="tree-splitter"/>
-          <treecol label="&col.lastmodified.label;" id="placesContentLastModified" anonid="lastModified" flex="1" hidden="true"
-                    persist="width hidden ordinal sortActive sortDirection"/>
-        </treecols>
-        <treechildren flex="1"/>
-      </tree>
+      <deck id="placesViewsDeck"
+            selectedIndex="0"
+            flex="1">
+        <tree id="placeContent"
+              class="plain placesTree"
+              context="placesContext"
+              hidecolumnpicker="true"
+              flex="1"
+              type="places"
+              flatList="true"
+              enableColumnDrag="true"
+              onfocus="PlacesOrganizer.updateDetailsPane(event)"
+              onselect="PlacesOrganizer.updateDetailsPane(event)"
+              onkeypress="ContentTree.onKeyPress(event);"
+              onopenflatcontainer="PlacesOrganizer.openFlatContainer(aContainer);"
+              onclick="ContentTree.onClick(event);">
+          <treecols id="placeContentColumns" context="placesColumnsContext">
+            <treecol label="&col.name.label;" id="placesContentTitle" anonid="title" flex="5" primary="true" ordinal="1" 
+                      persist="width hidden ordinal sortActive sortDirection"/>
+            <splitter class="tree-splitter"/>
+            <treecol label="&col.tags.label;" id="placesContentTags" anonid="tags" flex="2"
+                      persist="width hidden ordinal sortActive sortDirection"/>
+            <splitter class="tree-splitter"/>
+            <treecol label="&col.url.label;" id="placesContentUrl" anonid="url" flex="5"
+                      persist="width hidden ordinal sortActive sortDirection"/>
+            <splitter class="tree-splitter"/>
+            <treecol label="&col.lastvisit.label;" id="placesContentDate" anonid="date" flex="1" hidden="true"
+                      persist="width hidden ordinal sortActive sortDirection"/>
+            <splitter class="tree-splitter"/>
+            <treecol label="&col.visitcount.label;" id="placesContentVisitCount" anonid="visitCount" flex="1" hidden="true"
+                      persist="width hidden ordinal sortActive sortDirection"/>
+            <splitter class="tree-splitter"/>
+            <treecol label="&col.keyword.label;" id="placesContentKeyword" anonid="keyword" flex="1" hidden="true"
+                      persist="width hidden ordinal sortActive sortDirection"/>
+            <splitter class="tree-splitter"/>
+            <treecol label="&col.description.label;" id="placesContentDescription" anonid="description" flex="1" hidden="true"
+                      persist="width hidden ordinal sortActive sortDirection"/>
+            <splitter class="tree-splitter"/>
+            <treecol label="&col.dateadded.label;" id="placesContentDateAdded" anonid="dateAdded" flex="1" hidden="true"
+                      persist="width hidden ordinal sortActive sortDirection"/>
+            <splitter class="tree-splitter"/>
+            <treecol label="&col.lastmodified.label;" id="placesContentLastModified" anonid="lastModified" flex="1" hidden="true"
+                      persist="width hidden ordinal sortActive sortDirection"/>
+          </treecols>
+          <treechildren flex="1"/>
+        </tree>
+        <richlistbox flex="1"
+                     seltype="multiple"
+                     id="downloadsRichListBox" context="downloadsContextMenu"
+                     onkeypress="return this._placesView.onKeyPress(event);"
+                     oncontextmenu="return this._placesView.onContextMenu(event);"/>
+      </deck>
       <deck id="detailsDeck" style="height: 11em;">
         <vbox id="itemsCountBox" align="center">
           <spacer flex="3"/>
           <label id="itemsCountText"/>
           <spacer flex="1"/>
           <description id="selectItemDescription">
               &detailsPane.selectAnItemText.description;
           </description>
@@ -429,9 +445,66 @@
                     accesskey="&detailsPane.more.accesskey;"
                     control="infoBoxExpander"/>
 
           </hbox>
         </vbox>
       </deck>
     </vbox>
   </hbox>
+
+  <commandset id="downloadCommands"
+              commandupdater="true"
+              events="focus,select,contextmenu"
+              oncommandupdate="goUpdatePlacesCommands(); goUpdateDownloadCommands();">
+    <command id="downloadsCmd_pauseResume"
+             oncommand="goDoCommand('downloadsCmd_pauseResume')"/>
+    <command id="downloadsCmd_cancel"
+             oncommand="goDoCommand('downloadsCmd_cancel')"/>
+    <command id="downloadsCmd_open"
+             oncommand="goDoCommand('downloadsCmd_open')"/>
+    <command id="downloadsCmd_show"
+             oncommand="goDoCommand('downloadsCmd_show')"/>
+    <command id="downloadsCmd_retry"
+             oncommand="goDoCommand('downloadsCmd_retry')"/>
+    <command id="downloadsCmd_openReferrer"
+             oncommand="goDoCommand('downloadsCmd_openReferrer')"/>
+  </commandset>
+
+  <menupopup id="downloadsContextMenu"
+             class="download-state">
+    <menuitem command="downloadsCmd_pauseResume"
+              class="downloadPauseMenuItem"
+              label="&cmd.pause.label;"
+              accesskey="&cmd.pause.accesskey;"/>
+    <menuitem command="downloadsCmd_pauseResume"
+              class="downloadResumeMenuItem"
+              label="&cmd.resume.label;"
+              accesskey="&cmd.resume.accesskey;"/>
+    <menuitem command="downloadsCmd_cancel"
+              class="downloadCancelMenuItem"
+              label="&cmd.cancel.label;"
+              accesskey="&cmd.cancel.accesskey;"/>
+    <menuitem command="cmd_delete"
+              class="downloadRemoveFromHistoryMenuItem"
+              label="&cmd.removeFromHistory.label;"
+              accesskey="&cmd.removeFromHistory.accesskey;"/>
+    <menuitem command="downloadsCmd_show"
+              class="downloadShowMenuItem"
+#ifdef XP_MACOSX
+              label="&cmd.showMac.label;"
+              accesskey="&cmd.showMac.accesskey;"
+#else
+              label="&cmd.show.label;"
+              accesskey="&cmd.show.accesskey;"
+#endif
+              />
+
+    <menuseparator class="downloadCommandsSeparator"/>
+
+    <menuitem command="downloadsCmd_openReferrer"
+              label="&cmd.goToDownloadPage.label;"
+              accesskey="&cmd.goToDownloadPage.accesskey;"/>
+    <menuitem command="cmd_copy"
+              label="&cmd.copyDownloadLink.label;"
+              accesskey="&cmd.copyDownloadLink.accesskey;"/>
+  </menupopup>
 </window>
--- a/browser/components/places/content/tree.xml
+++ b/browser/components/places/content/tree.xml
@@ -51,16 +51,20 @@
             return null;
           }
         ]]></getter>
         <setter><![CDATA[
           return this.treeBoxObject.view = val;
         ]]></setter>
       </property>
 
+      <property name="associatedElement"
+                readonly="true"
+                onget="return this"/>
+
       <method name="applyFilter">
         <parameter name="filterString"/>
         <parameter name="folderRestrict"/>
         <parameter name="includeHidden"/>
         <body><![CDATA[
           // preserve grouping
           var queryNode = PlacesUtils.asQuery(this.result.root);
           var options = queryNode.queryOptions.clone();
--- a/browser/components/places/jar.mn
+++ b/browser/components/places/jar.mn
@@ -3,16 +3,19 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 browser.jar:
 # Provide another URI for the bookmarkProperties dialog so we can persist the
 # attributes separately
     content/browser/places/bookmarkProperties2.xul       (content/bookmarkProperties.xul)
 *   content/browser/places/places.xul                    (content/places.xul) 
 *   content/browser/places/places.js                     (content/places.js)
+    content/browser/places/downloadsView.js              (content/downloadsView.js)
+    content/browser/places/download.xml                  (content/download.xml)
+    content/browser/places/download.css                  (content/download.css)
     content/browser/places/places.css                    (content/places.css)
     content/browser/places/organizer.css                 (content/organizer.css)
     content/browser/places/bookmarkProperties.xul        (content/bookmarkProperties.xul)
     content/browser/places/bookmarkProperties.js         (content/bookmarkProperties.js)
     content/browser/places/placesOverlay.xul             (content/placesOverlay.xul)
 *   content/browser/places/menu.xml                      (content/menu.xml)
     content/browser/places/tree.xml                      (content/tree.xml)
     content/browser/places/controller.js                 (content/controller.js)
--- a/browser/components/places/src/PlacesUIUtils.jsm
+++ b/browser/components/places/src/PlacesUIUtils.jsm
@@ -617,17 +617,17 @@ this.PlacesUIUtils = {
    *          The DOM mouse/key event with modifier keys set that track the
    *          user's preferred destination window or tab.
    * @param   aView
    *          The controller associated with aNode.
    */
   openNodeWithEvent:
   function PUIU_openNodeWithEvent(aNode, aEvent, aView) {
     let window = aView.ownerWindow;
-    this._openNodeIn(aNode, window.whereToOpenLink(aEvent), window);
+    this._openNodeIn(aNode, window.whereToOpenLink(aEvent, false, true), window);
   },
 
   /**
    * Loads the node's URL in the appropriate tab or window or as a
    * web panel.
    * see also openUILinkIn
    */
   openNodeIn: function PUIU_openNodeIn(aNode, aWhere, aView) {
--- a/browser/components/places/tests/browser/browser_410196_paste_into_tags.js
+++ b/browser/components/places/tests/browser/browser_410196_paste_into_tags.js
@@ -16,29 +16,33 @@ function add_bookmark(aURI) {
 
 Components.utils.import("resource://gre/modules/NetUtil.jsm");
 
 const TEST_URL = "http://example.com/";
 const MOZURISPEC = "http://mozilla.com/";
 
 let gLibrary;
 let PlacesOrganizer;
+let ContentTree;
 
 function test() {
   waitForExplicitFinish();
   gLibrary = openLibrary(onLibraryReady);
 }
 
 function onLibraryReady() {
   ok(PlacesUtils, "PlacesUtils in scope");
   ok(PlacesUIUtils, "PlacesUIUtils in scope");
 
   PlacesOrganizer = gLibrary.PlacesOrganizer;
   ok(PlacesOrganizer, "Places organizer in scope");
 
+  ContentTree = gLibrary.ContentTree;
+  ok(ContentTree, "ContentTree is in scope");
+
   tests.makeHistVisit();
   tests.makeTag();
   tests.focusTag();
   waitForClipboard(function(aData) !!aData,
                    tests.copyHistNode,
                    onClipboardReady,
                    PlacesUtils.TYPE_X_MOZ_PLACE);
 }
@@ -96,46 +100,46 @@ let tests = {
 
   copyHistNode: function (){
     // focus the history object
     PlacesOrganizer.selectLeftPaneQuery("History");
     let histContainer = PlacesOrganizer._places.selectedNode;
     PlacesUtils.asContainer(histContainer);
     histContainer.containerOpen = true;
     PlacesOrganizer._places.selectNode(histContainer.getChild(0));
-    let histNode = PlacesOrganizer._content.view.nodeForTreeIndex(0);
-    PlacesOrganizer._content.selectNode(histNode);
+    let histNode = ContentTree.view.view.nodeForTreeIndex(0);
+    ContentTree.view.selectNode(histNode);
     is(histNode.uri, MOZURISPEC,
        "historyNode exists: " + histNode.uri);
     // copy the history node
-    PlacesOrganizer._content.controller.copy();
+    ContentTree.view.controller.copy();
   },
 
   historyNode: function (){
     // re-focus the history again
     PlacesOrganizer.selectLeftPaneQuery("History");
     let histContainer = PlacesOrganizer._places.selectedNode;
     PlacesUtils.asContainer(histContainer);
     histContainer.containerOpen = true;
     PlacesOrganizer._places.selectNode(histContainer.getChild(0));
-    let histNode = PlacesOrganizer._content.view.nodeForTreeIndex(0);
+    let histNode = ContentTree.view.view.nodeForTreeIndex(0);
     ok(histNode, "histNode exists: " + histNode.title);
     // check to see if the history node is tagged!
     let tags = PlacesUtils.tagging.getTagsForURI(NetUtil.newURI(MOZURISPEC));
     ok(tags.length == 1, "history node is tagged: " + tags.length);
     // check if a bookmark was created
     let isBookmarked = PlacesUtils.bookmarks.isBookmarked(NetUtil.newURI(MOZURISPEC));
     is(isBookmarked, true, MOZURISPEC + " is bookmarked");
     let bookmarkIds = PlacesUtils.bookmarks.getBookmarkIdsForURI(
                         NetUtil.newURI(histNode.uri));
     ok(bookmarkIds.length > 0, "bookmark exists for the tagged history item: " + bookmarkIds);
   },
 
   checkForBookmarkInUI: function(){
     // is the bookmark visible in the UI?
     // get the Unsorted Bookmarks node
     PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
-    // now we can see what is in the _content tree
-    let unsortedNode = PlacesOrganizer._content.view.nodeForTreeIndex(1);
+    // now we can see what is in the ContentTree tree
+    let unsortedNode = ContentTree.view.view.nodeForTreeIndex(1);
     ok(unsortedNode, "unsortedNode is not null: " + unsortedNode.uri);
     is(unsortedNode.uri, MOZURISPEC, "node uri's are the same");
   },
 };
--- a/browser/components/places/tests/browser/browser_416459_cut.js
+++ b/browser/components/places/tests/browser/browser_416459_cut.js
@@ -2,29 +2,32 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 const TEST_URL = "http://example.com/";
 
 let gLibrary;
 let gItemId;
 let PlacesOrganizer;
+let ContentTree;
 
 function test() {
   waitForExplicitFinish();
   gLibrary = openLibrary(onLibraryReady);
 }
 
 function onLibraryReady() {
   PlacesOrganizer = gLibrary.PlacesOrganizer;
+  ContentTree = gLibrary.ContentTree;
 
   // Sanity checks.
   ok(PlacesUtils, "PlacesUtils in scope");
   ok(PlacesUIUtils, "PlacesUIUtils in scope");
   ok(PlacesOrganizer, "PlacesOrganizer in scope");
+  ok(ContentTree, "ContentTree is in scope");
 
   gItemId = PlacesUtils.bookmarks.insertBookmark(
     PlacesUtils.toolbarFolderId, NetUtil.newURI(TEST_URL),
     PlacesUtils.bookmarks.DEFAULT_INDEX, "test"
   );
 
   selectBookmarkIn("BookmarksToolbar");
 
@@ -36,31 +39,31 @@ function onLibraryReady() {
 
 function selectBookmarkIn(aLeftPaneQuery) {
   info("Selecting " + aLeftPaneQuery + " in the left pane");
   PlacesOrganizer.selectLeftPaneQuery(aLeftPaneQuery);
   let rootId = PlacesUtils.getConcreteItemId(PlacesOrganizer._places.selectedNode);
   is(PlacesUtils.bookmarks.getFolderIdForItem(gItemId), rootId,
      "Bookmark has the right parent");
   info("Selecting the bookmark in the right pane");
-  PlacesOrganizer._content.selectItems([gItemId]);
-  let bookmarkNode = PlacesOrganizer._content.selectedNode;
+  ContentTree.view.selectItems([gItemId]);
+  let bookmarkNode = ContentTree.view.selectedNode;
   is(bookmarkNode.uri, TEST_URL, "Found the expected bookmark");
 }
 
 function cutSelection() {
   info("Cutting selection");
-  PlacesOrganizer._content.controller.cut();
+  ContentTree.view.controller.cut();
 }
 
 function pasteClipboard(aLeftPaneQuery) {
   info("Selecting " + aLeftPaneQuery + " in the left pane");
   PlacesOrganizer.selectLeftPaneQuery(aLeftPaneQuery);
   info("Pasting clipboard");
-  PlacesOrganizer._content.controller.paste();
+  ContentTree.view.controller.paste();
 }
 
 function onClipboardReady() {
   pasteClipboard("UnfiledBookmarks");
   selectBookmarkIn("UnfiledBookmarks");
 
   // Cleanup.
   gLibrary.close();
--- a/browser/components/places/tests/browser/browser_library_batch_delete.js
+++ b/browser/components/places/tests/browser/browser_library_batch_delete.js
@@ -64,29 +64,30 @@ gTests.push({
 });
 
 //------------------------------------------------------------------------------
 
 gTests.push({
   desc: "Ensure correct selection and functionality in Library",
   run: function() {
     let PO = gLibrary.PlacesOrganizer;
+    let ContentTree = gLibrary.ContentTree;
     // Move selection forth and back.
     PO.selectLeftPaneQuery("History");
     PO.selectLeftPaneQuery("UnfiledBookmarks");
     // Now select the "keepme" folder in the right pane and delete it.
-    PO._content.selectNode(PO._content.result.root.getChild(0));
-    is(PO._content.selectedNode.title, "keepme",
+    ContentTree.view.selectNode(ContentTree.view.result.root.getChild(0));
+    is(ContentTree.view.selectedNode.title, "keepme",
        "Found folder in content pane");
     // Test live update.
     PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
                                          makeURI(TEST_URL),
                                          PlacesUtils.bookmarks.DEFAULT_INDEX,
                                          "bm");
-    is(PO._content.result.root.childCount, 2,
+    is(ContentTree.view.result.root.childCount, 2,
        "Right pane was correctly updated");
     nextTest();
   }
 });
 
 //------------------------------------------------------------------------------
 
 function test() {
--- a/browser/components/places/tests/browser/browser_library_infoBox.js
+++ b/browser/components/places/tests/browser/browser_library_infoBox.js
@@ -13,16 +13,17 @@ var gTests = [];
 var gLibrary;
 
 //------------------------------------------------------------------------------
 
 gTests.push({
   desc: "Bug 430148 - Remove or hide the more/less button in details pane...",
   run: function() {
     var PO = gLibrary.PlacesOrganizer;
+    let ContentTree = gLibrary.ContentTree;
     var infoBoxExpanderWrapper = getAndCheckElmtById("infoBoxExpanderWrapper");
 
     // add a visit to browser history
     var bhist = PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory);
     PlacesUtils.history.addVisit(PlacesUtils._uri(TEST_URI), Date.now() * 1000,
                                  null, PlacesUtils.history.TRANSITION_TYPED,
                                  false, 0);
     ok(bhist.isVisited(PlacesUtils._uri(TEST_URI)), "Visit has been added.");
@@ -52,17 +53,17 @@ gTests.push({
     isnot(childNode, null, "History node first child is not null.");
     PO._places.selectNode(childNode);
     checkInfoBoxSelected(PO);
     ok(infoBoxExpanderWrapper.hidden,
        "Expander button is hidden for history child node.");
     checkAddInfoFieldsCollapsed(PO);
 
     // open history item
-    var view = PO._content.treeBoxObject.view;
+    var view = ContentTree.view.treeBoxObject.view;
     ok(view.rowCount > 0, "History item exists.");
     view.selection.select(0);
     ok(infoBoxExpanderWrapper.hidden,
        "Expander button is hidden for history item.");
     checkAddInfoFieldsCollapsed(PO);
 
     historyNode.containerOpen = false;
 
@@ -89,17 +90,17 @@ gTests.push({
        "Correctly selected recently bookmarked node.");
     PO._places.selectNode(childNode);
     checkInfoBoxSelected(PO);
     ok(!infoBoxExpanderWrapper.hidden,
        "Expander button is not hidden for recently bookmarked node.");
     checkAddInfoFieldsNotCollapsed(PO);
 
     // open first bookmark
-    var view = PO._content.treeBoxObject.view;
+    var view = ContentTree.view.treeBoxObject.view;
     ok(view.rowCount > 0, "Bookmark item exists.");
     view.selection.select(0);
     checkInfoBoxSelected(PO);
     ok(!infoBoxExpanderWrapper.hidden,
        "Expander button is not hidden for bookmark item.");
     checkAddInfoFieldsNotCollapsed(PO);
     checkAddInfoFields(PO, "bookmark item");
 
--- a/browser/components/places/tests/browser/browser_library_middleclick.js
+++ b/browser/components/places/tests/browser/browser_library_middleclick.js
@@ -83,17 +83,17 @@ gTests.push({
                                      PlacesUtils._uri(this.URIs[0]),
                                      bs.DEFAULT_INDEX,
                                      "Title");
     // Select unsorted bookmarks root in the left pane.
     gLibrary.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
     isnot(gLibrary.PlacesOrganizer._places.selectedNode, null,
           "We correctly have selection in the Library left pane");
     // Get our bookmark in the right pane.
-    var bookmarkNode = gLibrary.PlacesOrganizer._content.view.nodeForTreeIndex(0);
+    var bookmarkNode = gLibrary.ContentTree.view.view.nodeForTreeIndex(0);
     is(bookmarkNode.uri, this.URIs[0], "Found bookmark in the right pane");
   },
 
   finish: function() {
     setTimeout(runNextTest, 0);
   },
 
   cleanup: function() {
@@ -125,17 +125,17 @@ gTests.push({
                         "Title");
     });
 
     // Select unsorted bookmarks root in the left pane.
     gLibrary.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
     isnot(gLibrary.PlacesOrganizer._places.selectedNode, null,
           "We correctly have selection in the Library left pane");
     // Get our bookmark in the right pane.
-    var folderNode = gLibrary.PlacesOrganizer._content.view.nodeForTreeIndex(0);
+    var folderNode = gLibrary.ContentTree.view.view.nodeForTreeIndex(0);
     is(folderNode.title, "Folder", "Found folder in the right pane");
   },
 
   finish: function() {
     setTimeout(runNextTest, 0);
   },
 
   cleanup: function() {
@@ -182,17 +182,17 @@ gTests.push({
                                      0, // It must be the first.
                                      "Query");
 
     // Select unsorted bookmarks root in the left pane.
     gLibrary.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
     isnot(gLibrary.PlacesOrganizer._places.selectedNode, null,
           "We correctly have selection in the Library left pane");
     // Get our bookmark in the right pane.
-    var folderNode = gLibrary.PlacesOrganizer._content.view.nodeForTreeIndex(0);
+    var folderNode = gLibrary.ContentTree.view.view.nodeForTreeIndex(0);
     is(folderNode.title, "Query", "Found query in the right pane");
   },
 
   finish: function() {
     setTimeout(runNextTest, 0);
   },
 
   cleanup: function() {
@@ -238,17 +238,17 @@ function runNextTest() {
     info("Start of test: " + gCurrentTest.desc);
     // Test setup will set Library so that the bookmark to be opened is the
     // first node in the content (right pane) tree.
     gCurrentTest.setup();
 
     // Middle click on first node in the content tree of the Library.
     gLibrary.focus();
     waitForFocus(function() {
-      mouseEventOnCell(gLibrary.PlacesOrganizer._content, 0, 0, { button: 1 });
+      mouseEventOnCell(gLibrary.ContentTree.view, 0, 0, { button: 1 });
     }, gLibrary);
   }
   else {
     // No more tests.
 
     // Close Library window.
     gLibrary.close();
 
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -3706,19 +3706,16 @@ 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
@@ -132,17 +132,16 @@ 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_354894.js \
 	browser_394759_privatebrowsing.js \
 	$(NULL)
deleted file mode 100644
--- a/browser/components/sessionstore/test/browser_819510_perwindowpb.js
+++ /dev/null
@@ -1,171 +0,0 @@
-/* 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
-  let windowsEnum = Services.wm.getEnumerator("navigator:browser");
-  while (windowsEnum.hasMoreElements()) {
-    let currentWindow = windowsEnum.getNext();
-    if (currentWindow != window) {
-      currentWindow.close();
-    }
-  }
-
-  // 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");
-
-          Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
-            Services.obs.removeObserver(observe, aTopic);
-            aSubject.QueryInterface(Ci.nsISupportsString);
-            let state = JSON.parse(aSubject.data);
-            is(state.windows.length, 3,
-              "sessionstore state: 3 windows in data being writted 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 writted to disk");
-            runNextTest();
-          }, "sessionstore-state-write", false);
-
-          Services.prefs.setIntPref("browser.sessionstore.interval", 0);
-        });
-      });
-    });
-  });
-}
-
-// 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");
-
-      Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
-        Services.obs.removeObserver(observe, aTopic);
-        aSubject.QueryInterface(Ci.nsISupportsString);
-        let state = JSON.parse(aSubject.data);
-        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();
-      }, "sessionstore-state-write", false);
-      Services.prefs.setIntPref("browser.sessionstore.interval", 0);
-  });
-});
-}
-
-// Test opening default-normal-private-normal windows and closing a normal window
-function test_3() {
-  testOnWindow(false, function(normalWindow) {
-    normalWindow.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");
-
-        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");
-
-        normalWindow.close();
-        Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
-          Services.obs.removeObserver(observe, aTopic);
-          aSubject.QueryInterface(Ci.nsISupportsString);
-          let state = JSON.parse(aSubject.data);
-          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();
-        }, "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);
-}
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -79,25 +79,32 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_bug727429_watch-expressions-01.js \
 	browser_dbg_bug727429_watch-expressions-02.js \
 	browser_dbg_bug731394_editor-contextmenu.js \
 	browser_dbg_bug786070_hide_nonenums.js \
 	browser_dbg_displayName.js \
 	browser_dbg_iframes.js \
 	browser_dbg_pause-exceptions.js \
 	browser_dbg_multiple-windows.js \
-	browser_dbg_bfcache.js \
 	browser_dbg_breakpoint-new-script.js \
 	browser_dbg_bug737803_editor_actual_location.js \
 	browser_dbg_progress-listener-bug.js \
 	$(filter disabled-for-intermittent-crashes--bug-821701, browser_dbg_chrome-debugging.js) \
 	$(filter disabled-for-intermittent-failures--bug-753225, browser_dbg_createRemote.js) \
 	head.js \
 	$(NULL)
 
+ifneq ($(OS_ARCH),WINNT)
+MOCHITEST_BROWSER_TESTS += \
+	browser_dbg_bfcache.js \
+	$(NULL)
+else
+$(filter disabled-temporarily--bug-774619, browser_dbg_bfcache.js)
+endif
+
 MOCHITEST_BROWSER_PAGES = \
 	browser_dbg_tab1.html \
 	browser_dbg_tab2.html \
 	browser_dbg_debuggerstatement.html \
 	browser_dbg_stack.html \
 	browser_dbg_script-switching.html \
 	test-script-switching-01.js \
 	test-script-switching-02.js \
--- a/browser/devtools/inspector/test/head.js
+++ b/browser/devtools/inspector/test/head.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const Cu = Components.utils;
 let tempScope = {};
 Cu.import("resource:///modules/devtools/LayoutHelpers.jsm", tempScope);
 let LayoutHelpers = tempScope.LayoutHelpers;
 Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
 let TargetFactory = tempScope.TargetFactory;
-Components.utils.import("resource:///modules/devtools/Console.jsm", tempScope);
+Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
 let console = tempScope.console;
 
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
 
 function openInspector(callback)
 {
--- a/browser/devtools/profiler/ProfilerPanel.jsm
+++ b/browser/devtools/profiler/ProfilerPanel.jsm
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const Cu = Components.utils;
 
 Cu.import("resource:///modules/devtools/ProfilerController.jsm");
 Cu.import("resource://gre/modules/commonjs/promise/core.js");
-Cu.import("resource://gre/modules/devtools/EventEmitter.jsm");
+Cu.import("resource:///modules/devtools/EventEmitter.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 this.EXPORTED_SYMBOLS = ["ProfilerPanel"];
 
 XPCOMUtils.defineLazyGetter(this, "DebuggerServer", function () {
   Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
   return DebuggerServer;
 });
@@ -385,9 +385,9 @@ ProfilerPanel.prototype = {
     this.target = null;
     this.controller = null;
     this.profiles = null;
     this._uid = null;
     this._activeUid = null;
 
     this.emit("destroyed");
   }
-};
\ No newline at end of file
+};
--- a/browser/devtools/styleeditor/test/head.js
+++ b/browser/devtools/styleeditor/test/head.js
@@ -4,17 +4,17 @@
 const TEST_BASE = "chrome://mochitests/content/browser/browser/devtools/styleeditor/test/";
 const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/styleeditor/test/";
 const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/styleeditor/test/";
 const TEST_HOST = 'mochi.test:8888';
 
 let tempScope = {};
 Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
 let TargetFactory = tempScope.TargetFactory;
-Components.utils.import("resource:///modules/devtools/Console.jsm", tempScope);
+Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
 let console = tempScope.console;
 
 let gChromeWindow;               //StyleEditorChrome window
 let cache = Cc["@mozilla.org/network/cache-service;1"]
               .getService(Ci.nsICacheService);
 
 
 // Import the GCLI test helper
--- a/browser/devtools/styleinspector/test/head.js
+++ b/browser/devtools/styleinspector/test/head.js
@@ -8,17 +8,17 @@ Cu.import("resource:///modules/devtools/
 Cu.import("resource:///modules/devtools/CssHtmlTree.jsm", tempScope);
 Cu.import("resource:///modules/devtools/gDevTools.jsm", tempScope);
 let ConsoleUtils = tempScope.ConsoleUtils;
 let CssLogic = tempScope.CssLogic;
 let CssHtmlTree = tempScope.CssHtmlTree;
 let gDevTools = tempScope.gDevTools;
 Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
 let TargetFactory = tempScope.TargetFactory;
-Components.utils.import("resource:///modules/devtools/Console.jsm", tempScope);
+Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
 let console = tempScope.console;
 
 let browser, hudId, hud, hudBox, filterBox, outputNode, cs;
 
 function addTab(aURL)
 {
   gBrowser.selectedTab = gBrowser.addTab();
   content.location = aURL;
--- a/browser/devtools/webconsole/test/head.js
+++ b/browser/devtools/webconsole/test/head.js
@@ -7,17 +7,17 @@ let tempScope = {};
 Cu.import("resource:///modules/HUDService.jsm", tempScope);
 let HUDService = tempScope.HUDService;
 Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", tempScope);
 let WebConsoleUtils = tempScope.WebConsoleUtils;
 Cu.import("resource:///modules/devtools/gDevTools.jsm", tempScope);
 let gDevTools = tempScope.gDevTools;
 Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
 let TargetFactory = tempScope.TargetFactory;
-Components.utils.import("resource:///modules/devtools/Console.jsm", tempScope);
+Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
 let console = tempScope.console;
 
 const WEBCONSOLE_STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
 let WCU_l10n = new WebConsoleUtils.l10n(WEBCONSOLE_STRINGS_URI);
 
 function log(aMsg)
 {
   dump("*** WebConsoleTest: " + aMsg + "\n");
--- a/browser/locales/en-US/chrome/browser/downloads/downloads.dtd
+++ b/browser/locales/en-US/chrome/browser/downloads/downloads.dtd
@@ -55,18 +55,18 @@
 <!ENTITY cmd.show.accesskey               "F">
 <!ENTITY cmd.showMac.label                "Show In Finder">
 <!ENTITY cmd.showMac.accesskey            "F">
 <!ENTITY cmd.retry.label                  "Retry">
 <!ENTITY cmd.goToDownloadPage.label       "Go To Download Page">
 <!ENTITY cmd.goToDownloadPage.accesskey   "G">
 <!ENTITY cmd.copyDownloadLink.label       "Copy Download Link">
 <!ENTITY cmd.copyDownloadLink.accesskey   "L">
-<!ENTITY cmd.removeFromList.label         "Remove From List">
-<!ENTITY cmd.removeFromList.accesskey     "e">
+<!ENTITY cmd.removeFromHistory.label      "Remove From History">
+<!ENTITY cmd.removeFromHistory.accesskey  "e">
 <!ENTITY cmd.clearList.label              "Clear List">
 <!ENTITY cmd.clearList.accesskey          "a">
 
 <!-- LOCALIZATION NOTE (downloadsHistory.label, downloadsHistory.accesskey):
      This string is shown at the bottom of the Downloads Panel when all the
      downloads fit in the available space, or when there are no downloads in
      the panel at all.
      -->
--- a/browser/themes/gnomestripe/downloads/downloads.css
+++ b/browser/themes/gnomestripe/downloads/downloads.css
@@ -21,17 +21,17 @@
 #downloadsHistory {
   background: transparent;
   color: -moz-nativehyperlinktext;
   cursor: pointer;
 }
 
 #downloadsPanel[hasdownloads] > #downloadsFooter {
   border-top: 1px solid ThreeDShadow;
-  background-image: -moz-linear-gradient(hsla(0,0%,0%,.15), hsla(0,0%,0%,.08) 6px);
+  background-image: linear-gradient(hsla(0,0%,0%,.15), hsla(0,0%,0%,.08) 6px);
 }
 
 #downloadsHistory > .button-box {
   margin: 1em;
 }
 
 #downloadsHistory:-moz-focusring > .button-box {
   outline: 1px -moz-dialogtext dotted;
@@ -131,17 +131,17 @@ richlistitem[type="download"]:last-child
 }
 /*** Highlighted list items ***/
 
 richlistitem[type="download"][state="1"]:hover {
   border-radius: 3px;
   border-top: 1px solid hsla(0,0%,100%,.3);
   border-bottom: 1px solid hsla(0,0%,0%,.2);
   background-color: Highlight;
-  background-image: -moz-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,100%,0));
+  background-image: linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,100%,0));
   color: HighlightText;
   cursor: pointer;
 }
 
 /*** Button icons ***/
 
 .downloadButton.downloadCancel {
   -moz-image-region: rect(0px, 16px, 16px, 0px);
@@ -295,22 +295,22 @@ toolbar[iconsize="large"] > #downloads-i
   border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
   border-radius: 2px 0 0 2px;
 }
 
 #downloads-indicator-progress > .progress-remainder {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  background-image: -moz-linear-gradient(#505050, #575757);
+  background-image: linear-gradient(#505050, #575757);
   border: 1px solid;
   border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.4) hsla(0,0%,0%,.4);
   -moz-border-start: none;
   border-radius: 0 2px 2px 0;
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
   background-color: rgb(220, 230, 81);
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
-  background-image: -moz-linear-gradient(#4b5000, #515700);
+  background-image: linear-gradient(#4b5000, #515700);
 }
--- a/browser/themes/gnomestripe/newtab/newTab.css
+++ b/browser/themes/gnomestripe/newtab/newTab.css
@@ -6,17 +6,17 @@
   -moz-appearance: none;
   background-color: transparent;
 }
 
 /* SCROLLBOX */
 #newtab-scrollbox:not([page-disabled]) {
   background-color: rgb(229,229,229);
   background-image: url(chrome://browser/skin/newtab/noise.png),
-                    -moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
+                    linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
   background-attachment: fixed;
 }
 
 /* TOGGLE */
 #newtab-toggle {
   width: 16px;
   height: 16px;
   padding: 0;
--- a/browser/themes/pinstripe/downloads/downloads.css
+++ b/browser/themes/pinstripe/downloads/downloads.css
@@ -145,17 +145,17 @@ richlistitem[type="download"]:last-child
 
 /*** Highlighted list items ***/
 
 richlistitem[type="download"][state="1"]:hover {
   border-radius: 3px;
   border-top: 1px solid hsla(0,0%,100%,.2);
   border-bottom: 1px solid hsla(0,0%,0%,.4);
   background-color: Highlight;
-  background-image: -moz-linear-gradient(hsl(210,100%,50%), hsl(210,96%,41%));
+  background-image: linear-gradient(hsl(210,100%,50%), hsl(210,96%,41%));
   color: HighlightText;
   cursor: pointer;
 }
 
 /*** Button icons ***/
 
 .downloadButton.downloadCancel {
   -moz-image-region: rect(0px, 16px, 16px, 0px);
@@ -298,22 +298,22 @@ richlistitem[type="download"][state="1"]
   border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
   border-radius: 2px 0 0 2px;
 }
 
 #downloads-indicator-progress > .progress-remainder {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  background-image: -moz-linear-gradient(#505050, #575757);
+  background-image: linear-gradient(#505050, #575757);
   border: 1px solid;
   border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.4) hsla(0,0%,0%,.4);
   -moz-border-start: none;
   border-radius: 0 2px 2px 0;
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
   background-color: rgb(220, 230, 81);
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
-  background-image: -moz-linear-gradient(#4b5000, #515700);
+  background-image: linear-gradient(#4b5000, #515700);
 }
--- a/browser/themes/pinstripe/newtab/newTab.css
+++ b/browser/themes/pinstripe/newtab/newTab.css
@@ -6,17 +6,17 @@
   -moz-appearance: none;
   background-color: transparent;
 }
 
 /* SCROLLBOX */
 #newtab-scrollbox:not([page-disabled]) {
   background-color: rgb(229,229,229);
   background-image: url(chrome://browser/skin/newtab/noise.png),
-                    -moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
+                    linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
   background-attachment: fixed;
 }
 
 /* TOGGLE */
 #newtab-toggle {
   width: 16px;
   height: 16px;
   padding: 0;
--- a/browser/themes/pinstripe/places/places.css
+++ b/browser/themes/pinstripe/places/places.css
@@ -197,8 +197,76 @@ treechildren::-moz-tree-twisty(title, se
 
 treechildren::-moz-tree-image(cutting) {
   opacity: 0.5;
 }
 
 treechildren::-moz-tree-cell-text(cutting) {
   opacity: 0.7;
 }
+
+
+/** Downloads View **/
+
+richlistitem.download {
+  height: 7em;
+  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;
+}
+
+.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;
+  cursor: inherit;
+}
+
+.downloadDetails {
+  opacity: 0.7;
+  font-size: 95%;
+  cursor: inherit;
+}
+
+.downloadButton {
+  -moz-appearance: none;
+  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);
+}
+
+.downloadButton.downloadRetry {
+  -moz-image-region: rect(32px, 16px, 48px, 0px);
+}
--- a/browser/themes/winstripe/downloads/downloads-aero.css
+++ b/browser/themes/winstripe/downloads/downloads-aero.css
@@ -11,17 +11,17 @@
     border: 1px solid transparent;
     border-bottom: 1px solid hsl(213,40%,90%);
   }
 
   richlistitem[type="download"][state="1"]:hover {
     border: 1px solid hsl(213,45%,65%);
     box-shadow: 0 0 0 1px hsla(0,0%,100%,.5) inset,
                 0 1px 0 hsla(0,0%,100%,.3) inset;
-    background-image: -moz-linear-gradient(hsl(212,86%,92%), hsl(212,91%,86%));
+    background-image: linear-gradient(hsl(212,86%,92%), hsl(212,91%,86%));
     color: black;
   }
 }
 
 @media (-moz-windows-compositor) {
   #toolbar-menubar #downloads-indicator-icon:not(:-moz-lwtheme),
   #TabsToolbar[tabsontop=true] #downloads-indicator-icon:not(:-moz-lwtheme),
   #navigator-toolbox[tabsontop=false] > #nav-bar #downloads-indicator-icon:not(:-moz-lwtheme),
--- a/browser/themes/winstripe/downloads/downloads.css
+++ b/browser/themes/winstripe/downloads/downloads.css
@@ -298,22 +298,22 @@ richlistitem[type="download"][state="1"]
   border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
   border-radius: 2px 0 0 2px;
 }
 
 #downloads-indicator-progress > .progress-remainder {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  background-image: -moz-linear-gradient(#505050, #575757);
+  background-image: linear-gradient(#505050, #575757);
   border: 1px solid;
   border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.4) hsla(0,0%,0%,.4);
   -moz-border-start: none;
   border-radius: 0 2px 2px 0;
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
   background-color: rgb(220, 230, 81);
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
-  background-image: -moz-linear-gradient(#4b5000, #515700);
+  background-image: linear-gradient(#4b5000, #515700);
 }
--- a/browser/themes/winstripe/newtab/newTab.css
+++ b/browser/themes/winstripe/newtab/newTab.css
@@ -6,17 +6,17 @@
   -moz-appearance: none;
   background-color: transparent;
 }
 
 /* SCROLLBOX */
 #newtab-scrollbox:not([page-disabled]) {
   background-color: rgb(229,229,229);
   background-image: url(chrome://browser/skin/newtab/noise.png),
-                    -moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
+                    linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
   background-attachment: fixed;
 }
 
 /* TOGGLE */
 #newtab-toggle {
   width: 16px;
   height: 16px;
   padding: 0;
--- a/config/makefiles/xpcshell.mk
+++ b/config/makefiles/xpcshell.mk
@@ -44,16 +44,17 @@ xpcshell-tests:
       -I$(DEPTH)/_tests/mozbase/mozinfo \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --tests-root-dir=$(testxpcobjdir) \
 	  --testing-modules-dir=$(DEPTH)/_tests/modules \
 	  --xunit-file=$(testxpcobjdir)/$(relativesrcdir)/results.xml \
 	  --xunit-suite-name=xpcshell \
+	  --test-plugin-path=$(DIST)/plugins \
 	  $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
 xpcshell-tests-remote: DM_TRANS?=adb
 xpcshell-tests-remote:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
 	  -I$(topsrcdir)/build \
@@ -78,31 +79,33 @@ check-interactive:
 	  -I$(topsrcdir)/build \
       -I$(DEPTH)/_tests/mozbase/mozinfo \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --test-path=$(SOLO_FILE) \
 	  --testing-modules-dir=$(DEPTH)/_tests/modules \
 	  --profile-name=$(MOZ_APP_NAME) \
+	  --test-plugin-path=$(DIST)/plugins \
 	  --interactive \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
 # Execute a single test, specified in $(SOLO_FILE)
 check-one:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
 	  -I$(topsrcdir)/build \
       -I$(DEPTH)/_tests/mozbase/mozinfo \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --test-path=$(SOLO_FILE) \
 	  --testing-modules-dir=$(DEPTH)/_tests/modules \
 	  --profile-name=$(MOZ_APP_NAME) \
+	  --test-plugin-path=$(DIST)/plugins \
 	  --verbose \
 	  $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
 check-one-remote: DM_TRANS?=adb
 check-one-remote:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
new file mode 100644
--- /dev/null
+++ b/content/base/crashtests/815477.html
@@ -0,0 +1,15 @@
+<head dir=auto id=test1><ul id=test2>
+7. If no matching font face is within the "font-family" being processed by steps
+</ul>
+
+<h2 id=test3><p id=test5>* XHB7R%[+z^NvLp5	n$C
+<p id=test4>
+<script>
+var docElement = document.body;
+document.addEventListener("DOMContentLoaded", CFcrash, false);
+function CFcrash() {
+setTimeout('try { test5.appendChild(test4); } catch(e) {}', 50);
+try { test4.parentNode.removeChild(test4); test4 = test1; } catch(e) {}
+try { test4.insertBefore(test2, test4.firstChils); } catch(e) { }
+try { test2.textContent = test3.textContent; } catch(e) {}
+}</script>>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/content/base/crashtests/815500.html
@@ -0,0 +1,14 @@
+>><address id=test1> A,*/^㰞﷑ dq豑><script>
+function initCF() {
+try { test2 = document.createElementNS("http://www.w3.org/1999/xhtml", "tt"); } catch(e) {}
+try { test2.setAttribute("dir", "auto"); } catch(e) {}
+setTimeout("CFcrash()", 253);
+}
+document.addEventListener("DOMContentLoaded", initCF, false);
+function editFuzz() {
+}
+function CFcrash() {
+try { test2.appendChild(test1); } catch(e) {}
+setTimeout('try { test2.setAttribute("dir", "&locale.dir;"); } catch(e) {}', 462);
+try { test1.innerHTML = "Z3 ᜃ 洿G0겨=#⨝  g B 	md^뛳 j # 	 鮪  8媾䝀 &#x30054;ᖾd煏됚M:㕑,i⼷  Geኔ	≴핛 "; } catch(e) {}
+}</script>>
\ No newline at end of file
--- a/content/base/crashtests/crashtests.list
+++ b/content/base/crashtests/crashtests.list
@@ -111,9 +111,11 @@ load 715056.html
 load 741163-1.html
 load 766426.html
 load 771639.html
 load 752226-1.html
 load 752226-2.html
 HTTP(..) load xhr_abortinprogress.html
 load 786854.html
 load xhr_empty_datauri.html
+load 815477.html
+load 815500.html
 load 816253.html
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -40,16 +40,17 @@
 #include "nsContentUtils.h"
 #include "nsINodeList.h"
 #include "mozilla/ErrorResult.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDOMAttr.h"
 #include "nsISMILAttr.h"
 #include "nsClientRect.h"
 #include "nsIDOMDOMTokenList.h"
+#include "nsEvent.h"
 
 class nsIDOMEventListener;
 class nsIFrame;
 class nsIDOMNamedNodeMap;
 class nsIDOMCSSStyleDeclaration;
 class nsIURI;
 class nsINodeInfo;
 class nsIControllers;
@@ -717,22 +718,25 @@ public:
   static bool ShouldBlur(nsIContent *aContent);
 
   /**
    * Method to create and dispatch a left-click event loosely based on
    * aSourceEvent. If aFullDispatch is true, the event will be dispatched
    * through the full dispatching of the presshell of the aPresContext; if it's
    * false the event will be dispatched only as a DOM event.
    * If aPresContext is nullptr, this does nothing.
+   *
+   * @param aFlags      Extra flags for the dispatching event.  The true flags
+   *                    will be respected.
    */
   static nsresult DispatchClickEvent(nsPresContext* aPresContext,
                                      nsInputEvent* aSourceEvent,
                                      nsIContent* aTarget,
                                      bool aFullDispatch,
-                                     uint32_t aFlags,
+                                     const mozilla::widget::EventFlags* aFlags,
                                      nsEventStatus* aStatus);
 
   /**
    * Method to dispatch aEvent to aTarget. If aFullDispatch is true, the event
    * will be dispatched through the full dispatching of the presshell of the
    * aPresContext; if it's false the event will be dispatched only as a DOM
    * event.
    * If aPresContext is nullptr, this does nothing.
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -35,16 +35,17 @@ nsIXPathEvaluatorInternal.h \
 nsCaseTreatment.h \
 nsContentCID.h \
 nsCopySupport.h \
 nsContentCreatorFunctions.h \
 nsDOMFile.h \
 nsLineBreaker.h \
 nsReferencedElement.h \
 nsTreeSanitizer.h \
+nsViewportInfo.h \
 nsXMLNameSpaceMap.h \
 nsHostObjectProtocolHandler.h \
 $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/dom mozilla
 
 EXPORTS_mozilla/dom = \
 		DirectionalityUtils.h \
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -96,16 +96,18 @@ class nsIObserver;
 class nsPresContext;
 class nsIChannel;
 class nsAutoScriptBlockerSuppressNodeRemoved;
 struct nsIntMargin;
 class nsPIDOMWindow;
 class nsIDocumentLoaderFactory;
 class nsIDOMHTMLInputElement;
 
+class nsViewportInfo;
+
 namespace mozilla {
 
 class Selection;
 
 namespace layers {
   class LayerManager;
 } // namespace layers
 
@@ -125,50 +127,16 @@ enum EventNameType {
   EventNameType_SVGSVG = 0x0008, // the svg element
   EventNameType_SMIL = 0x0010, // smil elements
   EventNameType_HTMLBodyOrFramesetOnly = 0x0020,
 
   EventNameType_HTMLXUL = 0x0003,
   EventNameType_All = 0xFFFF
 };
 
-/**
- * Information retrieved from the <meta name="viewport"> tag. See
- * GetViewportInfo for more information on this functionality.
- */
-struct ViewportInfo
-{
-    // Default zoom indicates the level at which the display is 'zoomed in'
-    // initially for the user, upon loading of the page.
-    double defaultZoom;
-
-    // The minimum zoom level permitted by the page.
-    double minZoom;
-
-    // The maximum zoom level permitted by the page.
-    double maxZoom;
-
-    // The width of the viewport, specified by the <meta name="viewport"> tag,
-    // in CSS pixels.
-    uint32_t width;
-
-    // The height of the viewport, specified by the <meta name="viewport"> tag,
-    // in CSS pixels.
-    uint32_t height;
-
-    // Whether or not we should automatically size the viewport to the device's
-    // width. This is true if the document has been optimized for mobile, and
-    // the width property of a specified <meta name="viewport"> tag is either
-    // not specified, or is set to the special value 'device-width'.
-    bool autoSize;
-
-    // Whether or not the user can zoom in and out on the page. Default is true.
-    bool allowZoom;
-};
-
 struct EventNameMapping
 {
   nsIAtom* mAtom;
   uint32_t mId;
   int32_t  mType;
   uint32_t mStructType;
 };
 
@@ -1544,26 +1512,19 @@ public:
    * @param aDisplayWidth width of the on-screen display area for this
    * document, in device pixels.
    * @param aDisplayHeight height of the on-screen display area for this
    * document, in device pixels.
    *
    * NOTE: If the site is optimized for mobile (via the doctype), this
    * will return viewport information that specifies default information.
    */
-  static ViewportInfo GetViewportInfo(nsIDocument* aDocument,
-                                      uint32_t aDisplayWidth,
-                                      uint32_t aDisplayHeight);
-
-  /**
-   * Constrain the viewport calculations from the GetViewportInfo() function
-   * in order to always return sane minimum/maximum values. This modifies the
-   * ViewportInfo struct passed as an input parameter, in place.
-   */
-  static void ConstrainViewportValues(ViewportInfo& aViewInfo);
+  static nsViewportInfo GetViewportInfo(nsIDocument* aDocument,
+                                        uint32_t aDisplayWidth,
+                                        uint32_t aDisplayHeight);
 
   /**
    * The device-pixel-to-CSS-px ratio used to adjust meta viewport values.
    */
   static double GetDevicePixelsPerMetaViewportPixel(nsIWidget* aWidget);
 
   // Call EnterMicroTask when you're entering JS execution.
   // Usually the best way to do this is to use nsAutoMicroTask.
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -74,18 +74,18 @@ class ImageLoader;
 
 namespace dom {
 class Link;
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 #define NS_IDOCUMENT_IID \
-{ 0xcb362f1b, 0x8a05, 0x4d4f, \
-  { 0x90, 0x63, 0xf2, 0x5f, 0x8b, 0x8c, 0xb2, 0xe1 } }
+{ 0x1517f31a, 0x0ef9, 0x4629, \
+ { 0xb4, 0x7f, 0x56, 0x31, 0x0d, 0x80, 0x61, 0xaf } }
 
 // Flag for AddStyleSheet().
 #define NS_STYLESHEET_FROM_CATALOG                (1 << 0)
 
 // Enum for requesting a particular type of document when creating a doc
 enum DocumentFlavor {
   DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant
   DocumentFlavorHTML, // HTMLDocument with HTMLness bit set to true
@@ -1680,19 +1680,17 @@ public:
 #define DEPRECATED_OPERATION(_op) e##_op,
   enum DeprecatedOperations {
 #include "nsDeprecatedOperationList.h"
     eDeprecatedOperationCount
   };
 #undef DEPRECATED_OPERATION
   void WarnOnceAbout(DeprecatedOperations aOperation, bool asError = false);
 
-  // This method may fire a DOM event; if it does so it will happen
-  // synchronously if aFireEventSync is true, asynchronously otherwise.
-  virtual void UpdateVisibilityState(bool aFireEventSync) = 0;
+  virtual void PostVisibilityUpdateEvent() = 0;
   
   bool IsSyntheticDocument() { return mIsSyntheticDocument; }
 
   void SetNeedLayoutFlush() {
     mNeedLayoutFlush = true;
     if (mDisplayDocument) {
       mDisplayDocument->SetNeedLayoutFlush();
     }
new file mode 100644
--- /dev/null
+++ b/content/base/public/nsViewportInfo.h
@@ -0,0 +1,107 @@
+/* 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 nsViewportInfo_h___
+#define nsViewportInfo_h___
+
+#include "nsContentUtils.h"
+
+/**
+ * Default values for the nsViewportInfo class.
+ */
+static const double   kViewportMinScale = 0.0;
+static const double   kViewportMaxScale = 10.0;
+static const uint32_t kViewportMinWidth = 200;
+static const uint32_t kViewportMaxWidth = 10000;
+static const uint32_t kViewportMinHeight = 223;
+static const uint32_t kViewportMaxHeight = 10000;
+static const int32_t  kViewportDefaultScreenWidth = 980;
+
+/**
+ * Information retrieved from the <meta name="viewport"> tag. See
+ * nsContentUtils::GetViewportInfo for more information on this functionality.
+ */
+class NS_STACK_CLASS nsViewportInfo
+{
+  public:
+    nsViewportInfo(uint32_t aDisplayWidth, uint32_t aDisplayHeight) :
+      mDefaultZoom(1.0),
+      mMinZoom(kViewportMinScale),
+      mMaxZoom(kViewportMaxScale),
+      mWidth(aDisplayWidth),
+      mHeight(aDisplayHeight),
+      mAutoSize(true),
+      mAllowZoom(true)
+    {
+        ConstrainViewportValues();
+    }
+
+    nsViewportInfo(double aDefaultZoom,
+                   double aMinZoom,
+                   double aMaxZoom,
+                   uint32_t aWidth,
+                   uint32_t aHeight,
+                   bool aAutoSize,
+                   bool aAllowZoom) :
+                     mDefaultZoom(aDefaultZoom),
+                     mMinZoom(aMinZoom),
+                     mMaxZoom(aMaxZoom),
+                     mWidth(aWidth),
+                     mHeight(aHeight),
+                     mAutoSize(aAutoSize),
+                     mAllowZoom(aAllowZoom)
+    {
+      ConstrainViewportValues();
+    }
+
+    double GetDefaultZoom() { return mDefaultZoom; }
+    void SetDefaultZoom(const double aDefaultZoom);
+    double GetMinZoom() { return mMinZoom; }
+    double GetMaxZoom() { return mMaxZoom; }
+
+    uint32_t GetWidth() { return mWidth; }
+    uint32_t GetHeight() { return mHeight; }
+
+    bool IsAutoSizeEnabled() { return mAutoSize; }
+    bool IsZoomAllowed() { return mAllowZoom; }
+
+  private:
+
+    /**
+     * Constrain the viewport calculations from the
+     * nsContentUtils::GetViewportInfo() function in order to always return
+     * sane minimum/maximum values.
+     */
+    void ConstrainViewportValues();
+
+    // Default zoom indicates the level at which the display is 'zoomed in'
+    // initially for the user, upon loading of the page.
+    double mDefaultZoom;
+
+    // The minimum zoom level permitted by the page.
+    double mMinZoom;
+
+    // The maximum zoom level permitted by the page.
+    double mMaxZoom;
+
+    // The width of the viewport, specified by the <meta name="viewport"> tag,
+    // in CSS pixels.
+    uint32_t mWidth;
+
+    // The height of the viewport, specified by the <meta name="viewport"> tag,
+    // in CSS pixels.
+    uint32_t mHeight;
+
+    // Whether or not we should automatically size the viewport to the device's
+    // width. This is true if the document has been optimized for mobile, and
+    // the width property of a specified <meta name="viewport"> tag is either
+    // not specified, or is set to the special value 'device-width'.
+    bool mAutoSize;
+
+    // Whether or not the user can zoom in and out on the page. Default is true.
+    bool mAllowZoom;
+};
+
+#endif
+
--- a/content/base/src/CSPUtils.jsm
+++ b/content/base/src/CSPUtils.jsm
@@ -1238,17 +1238,17 @@ CSPSource.prototype = {
    * @returns
    *        true if the URI matches a source in this source list.
    */
   permits:
   function(aSource) {
     if (!aSource) return false;
 
     if (!(aSource instanceof CSPSource))
-      return this.permits(CSPSource.create(aSource, this._CSPRep));
+      aSource = CSPSource.create(aSource, this._CSPRep);
 
     // verify scheme
     if (this.scheme != aSource.scheme)
       return false;
 
     // port is defined in 'this' (undefined means it may not be relevant
     // to the scheme) AND this port (implicit or explicit) matches
     // aSource's port
@@ -1464,17 +1464,17 @@ CSPHost.prototype = {
    * @returns
    */
   permits:
   function(aHost) {
     if (!aHost) aHost = CSPHost.fromString("*");
 
     if (!(aHost instanceof CSPHost)) {
       // -- compare CSPHost to String
-      return this.permits(CSPHost.fromString(aHost));
+      aHost =  CSPHost.fromString(aHost);
     }
     var thislen = this._segments.length;
     var thatlen = aHost._segments.length;
 
     // don't accept a less specific host:
     //   \--> *.b.a doesn't accept b.a.
     if (thatlen < thislen) { return false; }
 
--- a/content/base/src/DirectionalityUtils.cpp
+++ b/content/base/src/DirectionalityUtils.cpp
@@ -485,16 +485,19 @@ private:
     // run the downward propagation algorithm
     // and remove the text node from the map
     nsINode* startAfterNode = static_cast<Element*>(aData);
     Element* rootNode = aEntry->GetKey();
     nsINode* textNode = WalkDescendantsSetDirectionFromText(rootNode, true,
                                                             startAfterNode);
     if (textNode) {
       nsTextNodeDirectionalityMap::AddEntryToMap(textNode, rootNode);
+    } else {
+      rootNode->ClearHasDirAutoSet();
+      rootNode->UnsetProperty(nsGkAtoms::dirAutoSetBy);
     }
     return PL_DHASH_REMOVE;
   }
 
 public:
   void UpdateAutoDirection(Directionality aDir)
   {
     mElements.EnumerateEntries(SetNodeDirection, &aDir);
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * Base class for all element classes; this provides an implementation
  * of DOM Core's nsIDOMElement, implements nsIContent, provides
  * utility methods for subclasses, and so forth.
  */
 
-#include "mozilla/Util.h"
+#include "mozilla/DebugOnly.h"
 
 #include "mozilla/dom/Element.h"
 
 #include "nsDOMAttribute.h"
 #include "nsDOMAttributeMap.h"
 #include "nsIAtom.h"
 #include "nsINodeInfo.h"
 #include "nsIDocument.h"
@@ -1583,41 +1583,44 @@ Element::DispatchEvent(nsPresContext* aP
 }
 
 /* static */
 nsresult
 Element::DispatchClickEvent(nsPresContext* aPresContext,
                             nsInputEvent* aSourceEvent,
                             nsIContent* aTarget,
                             bool aFullDispatch,
-                            uint32_t aFlags,
+                            const widget::EventFlags* aExtraEventFlags,
                             nsEventStatus* aStatus)
 {
   NS_PRECONDITION(aTarget, "Must have target");
   NS_PRECONDITION(aSourceEvent, "Must have source event");
   NS_PRECONDITION(aStatus, "Null out param?");
 
-  nsMouseEvent event(NS_IS_TRUSTED_EVENT(aSourceEvent), NS_MOUSE_CLICK,
+  nsMouseEvent event(aSourceEvent->mFlags.mIsTrusted, NS_MOUSE_CLICK,
                      aSourceEvent->widget, nsMouseEvent::eReal);
   event.refPoint = aSourceEvent->refPoint;
   uint32_t clickCount = 1;
   float pressure = 0;
   uint16_t inputSource = 0;
   if (aSourceEvent->eventStructType == NS_MOUSE_EVENT) {
     clickCount = static_cast<nsMouseEvent*>(aSourceEvent)->clickCount;
     pressure = static_cast<nsMouseEvent*>(aSourceEvent)->pressure;
     inputSource = static_cast<nsMouseEvent*>(aSourceEvent)->inputSource;
   } else if (aSourceEvent->eventStructType == NS_KEY_EVENT) {
     inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
   }
   event.pressure = pressure;
   event.clickCount = clickCount;
   event.inputSource = inputSource;
   event.modifiers = aSourceEvent->modifiers;
-  event.flags |= aFlags; // Be careful not to overwrite existing flags!
+  if (aExtraEventFlags) {
+    // Be careful not to overwrite existing flags!
+    event.mFlags |= *aExtraEventFlags;
+  }
 
   return DispatchEvent(aPresContext, &event, aTarget, aFullDispatch, aStatus);
 }
 
 nsIFrame*
 Element::GetPrimaryFrame(mozFlushType aType)
 {
   nsIDocument* doc = GetCurrentDoc();
@@ -2306,22 +2309,22 @@ Element::DumpContent(FILE* out, int32_t 
 }
 #endif
 
 bool
 Element::CheckHandleEventForLinksPrecondition(nsEventChainVisitor& aVisitor,
                                               nsIURI** aURI) const
 {
   if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
-      (!NS_IS_TRUSTED_EVENT(aVisitor.mEvent) &&
+      (!aVisitor.mEvent->mFlags.mIsTrusted &&
        (aVisitor.mEvent->message != NS_MOUSE_CLICK) &&
        (aVisitor.mEvent->message != NS_KEY_PRESS) &&
        (aVisitor.mEvent->message != NS_UI_ACTIVATE)) ||
       !aVisitor.mPresContext ||
-      (aVisitor.mEvent->flags & NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS)) {
+      aVisitor.mEvent->mFlags.mMultipleActionsPrevented) {
     return false;
   }
 
   // Make sure we actually are a link
   return IsLink(aURI);
 }
 
 nsresult
@@ -2357,27 +2360,27 @@ Element::PreHandleEventForLinks(nsEventC
   case NS_FOCUS_CONTENT:
     if (aVisitor.mEvent->eventStructType != NS_FOCUS_EVENT ||
         !static_cast<nsFocusEvent*>(aVisitor.mEvent)->isRefocus) {
       nsAutoString target;
       GetLinkTarget(target);
       nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
                                   false, true, true);
       // Make sure any ancestor links don't also TriggerLink
-      aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS;
+      aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
     }
     break;
 
   case NS_MOUSE_EXIT_SYNTH:
     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
     // FALL THROUGH
   case NS_BLUR_CONTENT:
     rv = LeaveLink(aVisitor.mPresContext);
     if (NS_SUCCEEDED(rv)) {
-      aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS;
+      aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
     }
     break;
 
   default:
     // switch not in sync with the optimization switch earlier in this function
     NS_NOTREACHED("switch statements not in sync");
     return NS_ERROR_UNEXPECTED;
   }
@@ -2415,17 +2418,17 @@ Element::PostHandleEventForLinks(nsEvent
           static_cast<nsMouseEvent*>(aVisitor.mEvent)->button ==
           nsMouseEvent::eLeftButton) {
         // don't make the link grab the focus if there is no link handler
         nsILinkHandler *handler = aVisitor.mPresContext->GetLinkHandler();
         nsIDocument *document = GetCurrentDoc();
         if (handler && document) {
           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
           if (fm) {
-            aVisitor.mEvent->flags |= NS_EVENT_FLAG_PREVENT_MULTIPLE_ACTIONS;
+            aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
             nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this);
             fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOUSE |
                                nsIFocusManager::FLAG_NOSCROLL);
           }
 
           nsEventStateManager::SetActiveManager(
             aVisitor.mPresContext->EventStateManager(), this);
         }
@@ -2441,47 +2444,48 @@ Element::PostHandleEventForLinks(nsEvent
         break;
       }
 
       // The default action is simply to dispatch DOMActivate
       nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
       if (shell) {
         // single-click
         nsEventStatus status = nsEventStatus_eIgnore;
-        nsUIEvent actEvent(NS_IS_TRUSTED_EVENT(aVisitor.mEvent),
+        nsUIEvent actEvent(aVisitor.mEvent->mFlags.mIsTrusted,
                            NS_UI_ACTIVATE, 1);
 
         rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
         if (NS_SUCCEEDED(rv)) {
           aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
         }
       }
     }
     break;
 
   case NS_UI_ACTIVATE:
     {
       if (aVisitor.mEvent->originalTarget == this) {
         nsAutoString target;
         GetLinkTarget(target);
         nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
-                                    true, true, NS_IS_TRUSTED_EVENT(aVisitor.mEvent));
+                                    true, true,
+                                    aVisitor.mEvent->mFlags.mIsTrusted);
         aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
       }
     }
     break;
 
   case NS_KEY_PRESS:
     {
       if (aVisitor.mEvent->eventStructType == NS_KEY_EVENT) {
         nsKeyEvent* keyEvent = static_cast<nsKeyEvent*>(aVisitor.mEvent);
         if (keyEvent->keyCode == NS_VK_RETURN) {
           nsEventStatus status = nsEventStatus_eIgnore;
           rv = DispatchClickEvent(aVisitor.mPresContext, keyEvent, this,
-                                  false, 0, &status);
+                                  false, nullptr, &status);
           if (NS_SUCCEEDED(rv)) {
             aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
           }
         }
       }
     }
     break;
 
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -115,16 +115,17 @@ CPPSRCS		= \
 		nsStyledElement.cpp \
 		nsStyleLinkElement.cpp \
 		nsSyncLoadService.cpp \
 		nsTextFragment.cpp \
 		nsTextNode.cpp \
 		nsTraversal.cpp \
 		nsTreeSanitizer.cpp \
 		nsTreeWalker.cpp \
+                nsViewportInfo.cpp \
 		WebSocket.cpp \
 		nsXHTMLContentSerializer.cpp \
 		nsXMLContentSerializer.cpp \
 		nsXMLHttpRequest.cpp \
 		nsXMLNameSpaceMap.cpp \
 		FragmentOrElement.cpp \
 		Link.cpp \
 		nsHostObjectProtocolHandler.cpp \
@@ -156,24 +157,27 @@ GQI_SRCS = contentbase.gqi
 
 # we don't want the shared lib, but we want to force the creation of a
 # static lib.
 FORCE_STATIC_LIB = 1
 
 EXTRA_COMPONENTS = \
 		$(srcdir)/nsBadCertHandler.js \
 		nsBadCertHandler.manifest \
-		contentSecurityPolicy.js \
 		contentSecurityPolicy.manifest \
 		contentAreaDropListener.js \
 		contentAreaDropListener.manifest \
 		messageWakeupService.js \
 		messageWakeupService.manifest \
 		$(NULL)
 
+EXTRA_PP_COMPONENTS = \
+		contentSecurityPolicy.js \
+		$(NULL)
+
 EXTRA_JS_MODULES = \
 		CSPUtils.jsm \
 		$(NULL)
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
--- a/content/base/src/contentSecurityPolicy.js
+++ b/content/base/src/contentSecurityPolicy.js
@@ -37,16 +37,18 @@ function ContentSecurityPolicy() {
   this._policy._allowEval = true;
 
   this._request = "";
   this._requestOrigin = "";
   this._requestPrincipal = "";
   this._referrer = "";
   this._docRequest = null;
   CSPdebug("CSP POLICY INITED TO 'default-src *'");
+
+  this._cache = { };
 }
 
 /*
  * Set up mappings from nsIContentPolicy content types to CSP directives.
  */
 {
   let cp = Ci.nsIContentPolicy;
   let csp = ContentSecurityPolicy;
@@ -219,16 +221,17 @@ ContentSecurityPolicy.prototype = {
                                       this);
 
     // (2) Intersect the currently installed CSPRep object with the new one
     var intersect = this._policy.intersectWith(newpolicy);
 
     // (3) Save the result
     this._policy = intersect;
     this._isInitialized = true;
+    this._cache = {};
   },
 
   /**
    * Generates and sends a violation report to the specified report URIs.
    */
   sendReports:
   function(blockedUri, originalUri, violatedDirective,
            aSourceFile, aScriptSample, aLineNum) {
@@ -417,26 +420,27 @@ ContentSecurityPolicy.prototype = {
    */
   shouldLoad:
   function csp_shouldLoad(aContentType,
                           aContentLocation,
                           aRequestOrigin,
                           aContext,
                           aMimeTypeGuess,
                           aOriginalUri) {
-
-    // don't filter chrome stuff
-    if (aContentLocation.scheme === 'chrome' ||
-        aContentLocation.scheme === 'resource') {
-      return Ci.nsIContentPolicy.ACCEPT;
+    let key = aContentLocation.spec + "!" + aContentType;
+    if (this._cache[key]) {
+      return this._cache[key];
     }
 
-    // interpret the context, and then pass off to the decision structure
+#ifndef MOZ_B2G
+    // Try to remove as much as possible from the hot path on b2g.
     CSPdebug("shouldLoad location = " + aContentLocation.asciiSpec);
     CSPdebug("shouldLoad content type = " + aContentType);
+#endif
+    // interpret the context, and then pass off to the decision structure
     var cspContext = ContentSecurityPolicy._MAPPINGS[aContentType];
 
     // if the mapping is null, there's no policy, let it through.
     if (!cspContext) {
       return Ci.nsIContentPolicy.ACCEPT;
     }
 
     // otherwise, honor the translation
@@ -456,17 +460,19 @@ ContentSecurityPolicy.prototype = {
                                 ? 'default-src' : cspContext)
                                 + ' ' + directive.toString();
         this._asyncReportViolation(aContentLocation, aOriginalUri, violatedPolicy);
       } catch(e) {
         CSPdebug('---------------- ERROR: ' + e);
       }
     }
 
-    return (this._reportOnlyMode ? Ci.nsIContentPolicy.ACCEPT : res);
+    let ret = this._cache[key] =
+      (this._reportOnlyMode ? Ci.nsIContentPolicy.ACCEPT : res);
+    return ret;
   },
 
   shouldProcess:
   function csp_shouldProcess(aContentType,
                              aContentLocation,
                              aRequestOrigin,
                              aContext,
                              aMimeType,
--- a/content/base/src/nsAttrValue.cpp
+++ b/content/base/src/nsAttrValue.cpp
@@ -3,26 +3,28 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * A struct that represents the value (type and actual data) of an
  * attribute.
  */
 
+#include "mozilla/DebugOnly.h"
+#include "mozilla/HashFunctions.h"
+
 #include "nsAttrValue.h"
 #include "nsAttrValueInlines.h"
 #include "nsIAtom.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/css/StyleRule.h"
 #include "mozilla/css/Declaration.h"
 #include "nsContentUtils.h"
 #include "nsReadableUtils.h"
 #include "prprf.h"
-#include "mozilla/HashFunctions.h"
 #include "nsHTMLCSSStyleSheet.h"
 #include "nsCSSParser.h"
 #include "nsStyledElement.h"
 
 using namespace mozilla;
 
 #define MISC_STR_PTR(_cont) \
   reinterpret_cast<void*>((_cont)->mStringBits & NS_ATTRVALUE_POINTERVALUE_MASK)
--- a/content/base/src/nsCSPService.cpp
+++ b/content/base/src/nsCSPService.cpp
@@ -73,16 +73,42 @@ CSPService::ShouldLoad(uint32_t aContent
 #endif
     // default decision, CSP can revise it if there's a policy to enforce
     *aDecision = nsIContentPolicy::ACCEPT;
 
     // No need to continue processing if CSP is disabled
     if (!sCSPEnabled)
         return NS_OK;
 
+    // shortcut for about: chrome: and resource: and javascript: uris since
+    // they're not subject to CSP content policy checks.
+    bool schemeMatch = false;
+    NS_ENSURE_SUCCESS(aContentLocation->SchemeIs("about", &schemeMatch), NS_OK);
+    if (schemeMatch)
+        return NS_OK;
+    NS_ENSURE_SUCCESS(aContentLocation->SchemeIs("chrome", &schemeMatch), NS_OK);
+    if (schemeMatch)
+        return NS_OK;
+    NS_ENSURE_SUCCESS(aContentLocation->SchemeIs("resource", &schemeMatch), NS_OK);
+    if (schemeMatch)
+        return NS_OK;
+    NS_ENSURE_SUCCESS(aContentLocation->SchemeIs("javascript", &schemeMatch), NS_OK);
+    if (schemeMatch)
+        return NS_OK;
+
+
+    // These content types are not subject to CSP content policy checks:
+    // TYPE_CSP_REPORT, TYPE_REFRESH, TYPE_DOCUMENT
+    // (their mappings are null in contentSecurityPolicy.js)
+    if (aContentType == nsIContentPolicy::TYPE_CSP_REPORT ||
+        aContentType == nsIContentPolicy::TYPE_REFRESH ||
+        aContentType == nsIContentPolicy::TYPE_DOCUMENT) {
+        return NS_OK;
+    }
+
     // find the principal of the document that initiated this request and see
     // if it has a CSP policy object
     nsCOMPtr<nsINode> node(do_QueryInterface(aRequestContext));
     nsCOMPtr<nsIPrincipal> principal;
     nsCOMPtr<nsIContentSecurityPolicy> csp;
     if (node) {
         principal = node->NodePrincipal();
         principal->GetCsp(getter_AddRefs(csp));
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 sw=2 et tw=78: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* A namespace class for static layout utilities. */
 
+#include "mozilla/DebugOnly.h"
 #include "mozilla/Util.h"
 #include "mozilla/Likely.h"
 
 #include "jsapi.h"
 #include "jsdbgapi.h"
 #include "jsfriendapi.h"
 
 #include <math.h>
@@ -163,16 +164,17 @@
 #include "nsIParserService.h"
 #include "nsIDOMScriptObjectFactory.h"
 #include "nsSandboxFlags.h"
 #include "nsSVGFeatures.h"
 #include "MediaDecoder.h"
 #include "DecoderTraits.h"
 
 #include "nsWrapperCacheInlines.h"
+#include "nsViewportInfo.h"
 
 extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end,
                                       const char** next, PRUnichar* result);
 extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
                                  int ns_aware, const char** colon);
 
 class imgLoader;
 
@@ -235,27 +237,16 @@ uint32_t nsContentUtils::sHandlingInputT
 
 nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
 nsIParser* nsContentUtils::sXMLFragmentParser = nullptr;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
 bool nsContentUtils::sFragmentParsingActive = false;
 
 namespace {
 
-/**
- * Default values for the ViewportInfo structure.
- */
-static const double   kViewportMinScale = 0.0;
-static const double   kViewportMaxScale = 10.0;
-static const uint32_t kViewportMinWidth = 200;
-static const uint32_t kViewportMaxWidth = 10000;
-static const uint32_t kViewportMinHeight = 223;
-static const uint32_t kViewportMaxHeight = 10000;
-static const int32_t  kViewportDefaultScreenWidth = 980;
-
 static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
 static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 
 static PLDHashTable sEventListenerManagersHash;
 
 class EventListenerManagerMapEntry : public PLDHashEntryHdr
 {
@@ -5032,68 +5023,47 @@ static void ProcessViewportToken(nsIDocu
   else if (key_atom == nsGkAtoms::user_scalable)
     aDocument->SetHeaderData(nsGkAtoms::viewport_user_scalable, value);
 }
 
 #define IS_SEPARATOR(c) ((c == '=') || (c == ',') || (c == ';') || \
                          (c == '\t') || (c == '\n') || (c == '\r'))
 
 /* static */
-void
-nsContentUtils::ConstrainViewportValues(ViewportInfo& aViewInfo)
-{
-  // Constrain the min/max zoom as specified at:
-  // dev.w3.org/csswg/css-device-adapt section 6.2
-  aViewInfo.maxZoom = NS_MAX(aViewInfo.minZoom, aViewInfo.maxZoom);
-
-  aViewInfo.defaultZoom = NS_MIN(aViewInfo.defaultZoom, aViewInfo.maxZoom);
-  aViewInfo.defaultZoom = NS_MAX(aViewInfo.defaultZoom, aViewInfo.minZoom);
-}
-
-/* static */
-ViewportInfo
+nsViewportInfo
 nsContentUtils::GetViewportInfo(nsIDocument *aDocument,
                                 uint32_t aDisplayWidth,
                                 uint32_t aDisplayHeight)
 {
-  ViewportInfo ret;
-  ret.defaultZoom = 1.0;
-  ret.autoSize = true;
-  ret.allowZoom = true;
-  ret.width = aDisplayWidth;
-  ret.height = aDisplayHeight;
-  ret.minZoom = kViewportMinScale;
-  ret.maxZoom = kViewportMaxScale;
-
   nsAutoString viewport;
   aDocument->GetHeaderData(nsGkAtoms::viewport, viewport);
   if (viewport.IsEmpty()) {
     // If the docType specifies that we are on a site optimized for mobile,
     // then we want to return specially crafted defaults for the viewport info.
     nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(aDocument));
     nsCOMPtr<nsIDOMDocumentType> docType;
     nsresult rv = domDoc->GetDoctype(getter_AddRefs(docType));
     if (NS_SUCCEEDED(rv) && docType) {
       nsAutoString docId;
       rv = docType->GetPublicId(docId);
       if (NS_SUCCEEDED(rv)) {
         if ((docId.Find("WAP") != -1) ||
             (docId.Find("Mobile") != -1) ||
             (docId.Find("WML") != -1))
         {
-          nsContentUtils::ConstrainViewportValues(ret);
+          nsViewportInfo ret(aDisplayWidth, aDisplayHeight);
           return ret;
         }
       }
     }
 
     nsAutoString handheldFriendly;
     aDocument->GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
     if (handheldFriendly.EqualsLiteral("true")) {
-      nsContentUtils::ConstrainViewportValues(ret);
+      nsViewportInfo ret(aDisplayWidth, aDisplayHeight);
       return ret;
     }
   }
 
   nsAutoString minScaleStr;
   aDocument->GetHeaderData(nsGkAtoms::viewport_minimum_scale, minScaleStr);
 
   nsresult errorCode;
@@ -5213,25 +5183,18 @@ nsContentUtils::GetViewportInfo(nsIDocum
   aDocument->GetHeaderData(nsGkAtoms::viewport_user_scalable, userScalable);
 
   if ((userScalable.EqualsLiteral("0")) ||
       (userScalable.EqualsLiteral("no")) ||
       (userScalable.EqualsLiteral("false"))) {
     allowZoom = false;
   }
 
-  ret.allowZoom = allowZoom;
-  ret.width = width;
-  ret.height = height;
-  ret.defaultZoom = scaleFloat;
-  ret.minZoom = scaleMinFloat;
-  ret.maxZoom = scaleMaxFloat;
-  ret.autoSize = autoSize;
-
-  nsContentUtils::ConstrainViewportValues(ret);
+  nsViewportInfo ret(scaleFloat, scaleMinFloat, scaleMaxFloat, width, height,
+                     autoSize, allowZoom);
   return ret;
 }
 
 /* static */
 double
 nsContentUtils::GetDevicePixelsPerMetaViewportPixel(nsIWidget* aWidget)
 {
   int32_t prefValue = Preferences::GetInt("browser.viewport.scaleRatio", 0);
@@ -5333,17 +5296,17 @@ nsContentUtils::GetDragSession()
     dragService->GetCurrentSession(&dragSession);
   return dragSession;
 }
 
 /* static */
 nsresult
 nsContentUtils::SetDataTransferInEvent(nsDragEvent* aDragEvent)
 {
-  if (aDragEvent->dataTransfer || !NS_IS_TRUSTED_EVENT(aDragEvent))
+  if (aDragEvent->dataTransfer || !aDragEvent->mFlags.mIsTrusted)
     return NS_OK;
 
   // For draggesture and dragstart events, the data transfer object is
   // created before the event fires, so it should already be set. For other
   // drag events, get the object from the drag session.
   NS_ASSERTION(aDragEvent->message != NS_DRAGDROP_GESTURE &&
                aDragEvent->message != NS_DRAGDROP_START,
                "draggesture event created without a dataTransfer");
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -186,25 +186,25 @@ nsDOMMultipartFile::InitBlob(JSContext* 
 {
   bool nativeEOL = false;
   if (aArgc > 1) {
     if (NS_IsMainThread()) {
       BlobPropertyBag d;
       if (!d.Init(aCx, nullptr, aArgv[1])) {
         return NS_ERROR_TYPE_ERR;
       }
-      mContentType = d.type;
-      nativeEOL = d.endings == EndingTypesValues::Native;
+      mContentType = d.mType;
+      nativeEOL = d.mEndings == EndingTypesValues::Native;
     } else {
       BlobPropertyBagWorkers d;
       if (!d.Init(aCx, nullptr, aArgv[1])) {
         return NS_ERROR_TYPE_ERR;
       }
-      mContentType = d.type;
-      nativeEOL = d.endings == EndingTypesValues::Native;
+      mContentType = d.mType;
+      nativeEOL = d.mEndings == EndingTypesValues::Native;
     }
   }
 
   if (aArgc > 0) {
     if (!aArgv[0].isObject()) {
       return NS_ERROR_TYPE_ERR; // We're not interested
     }
 
@@ -281,19 +281,19 @@ nsDOMMultipartFile::InitFile(JSContext* 
   NS_ENSURE_TRUE(aArgc > 0, NS_ERROR_UNEXPECTED);
 
   bool nativeEOL = false;
   if (aArgc > 1) {
     FilePropertyBag d;
     if (!d.Init(aCx, nullptr, aArgv[1])) {
       return NS_ERROR_TYPE_ERR;
     }
-    mName = d.name;
-    mContentType = d.type;
-    nativeEOL = d.endings == EndingTypesValues::Native;
+    mName = d.mName;
+    mContentType = d.mType;
+    nativeEOL = d.mEndings == EndingTypesValues::Native;
   }
 
   // We expect to get a path to represent as a File object,
   // an nsIFile, or an nsIDOMFile.
   nsCOMPtr<nsIFile> file;
   nsCOMPtr<nsIDOMFile> domFile;
   if (!aArgv[0].isString()) {
     // Lets see if it's an nsIFile
--- a/content/base/src/nsDOMMutationObserver.cpp
+++ b/content/base/src/nsDOMMutationObserver.cpp
@@ -2,164 +2,119 @@
 /* vim: set sw=4 ts=8 et tw=80 : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsDOMMutationObserver.h"        
 #include "nsDOMClassInfoID.h"
 #include "nsError.h"
-#include "nsIClassInfo.h"
-#include "nsIXPCScriptable.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsTextFragment.h"
 #include "jsapi.h"
 #include "nsServiceManagerUtils.h"
-#include "DictionaryHelpers.h"
 
-nsCOMArray<nsIDOMMutationObserver>*
+nsTArray<nsRefPtr<nsDOMMutationObserver> >*
   nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
 
-nsIDOMMutationObserver* nsDOMMutationObserver::sCurrentObserver = nullptr;
+nsDOMMutationObserver* nsDOMMutationObserver::sCurrentObserver = nullptr;
 
 uint32_t nsDOMMutationObserver::sMutationLevel = 0;
 uint64_t nsDOMMutationObserver::sCount = 0;
 
-nsAutoTArray<nsCOMArray<nsIDOMMutationObserver>, 4>*
+nsAutoTArray<nsTArray<nsRefPtr<nsDOMMutationObserver> >, 4>*
 nsDOMMutationObserver::sCurrentlyHandlingObservers = nullptr;
 
+nsINodeList*
+nsDOMMutationRecord::AddedNodes()
+{
+  if (!mAddedNodes) {
+    mAddedNodes = new nsSimpleContentList(mTarget);
+  }
+  return mAddedNodes;
+}
+
+nsINodeList*
+nsDOMMutationRecord::RemovedNodes()
+{
+  if (!mRemovedNodes) {
+    mRemovedNodes = new nsSimpleContentList(mTarget);
+  }
+  return mRemovedNodes;
+}
+
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMutationRecord)
 
-DOMCI_DATA(MutationRecord, nsDOMMutationRecord)
-
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationRecord)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMMutationRecord)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MutationRecord)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationRecord)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationRecord)
 
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMMutationRecord)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMMutationRecord)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTarget)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreviousSibling)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNextSibling)
   tmp->mAddedNodes = nullptr;
   tmp->mRemovedNodes = nullptr;
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMMutationRecord)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTarget)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreviousSibling)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNextSibling)
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mAddedNodes");
   cb.NoteXPCOMChild(static_cast<nsIDOMNodeList*>(tmp->mAddedNodes));
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRemovedNodes");
   cb.NoteXPCOMChild(static_cast<nsIDOMNodeList*>(tmp->mRemovedNodes));
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMETHODIMP
-nsDOMMutationRecord::GetType(nsAString& aType)
-{
-  aType = mType;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMutationRecord::GetTarget(nsIDOMNode** aTarget)
-{
-  nsCOMPtr<nsIDOMNode> n = do_QueryInterface(mTarget);
-  n.forget(aTarget);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMutationRecord::GetAddedNodes(nsIDOMNodeList** aAddedNodes)
-{
-  if (!mAddedNodes && mTarget) {
-    mAddedNodes = new nsSimpleContentList(mTarget);
-  }
-  NS_IF_ADDREF(*aAddedNodes = mAddedNodes);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMutationRecord::GetRemovedNodes(nsIDOMNodeList** aRemovedNodes)
-{
-  if (!mRemovedNodes && mTarget) {
-    mRemovedNodes = new nsSimpleContentList(mTarget);
-  }
-  NS_IF_ADDREF(*aRemovedNodes = mRemovedNodes);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMutationRecord::GetPreviousSibling(nsIDOMNode** aPreviousSibling)
-{
-  nsCOMPtr<nsIDOMNode> n = do_QueryInterface(mPreviousSibling);
-  *aPreviousSibling = n.forget().get();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMutationRecord::GetNextSibling(nsIDOMNode** aNextSibling)
-{
-  nsCOMPtr<nsIDOMNode> n = do_QueryInterface(mNextSibling);
-  *aNextSibling = n.forget().get();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMutationRecord::GetAttributeName(nsAString& aAttrName)
-{
-  aAttrName = mAttrName;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMutationRecord::GetAttributeNamespace(nsAString& aAttrNamespace)
-{
-  aAttrNamespace = mAttrNamespace;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMutationRecord::GetOldValue(nsAString& aPrevValue)
-{
-  aPrevValue = mPrevValue;
-  return NS_OK;
-}
-
 // Observer
 
 NS_IMPL_ADDREF(nsMutationReceiver)
 NS_IMPL_RELEASE(nsMutationReceiver)
 
 NS_INTERFACE_MAP_BEGIN(nsMutationReceiver)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsMutationReceiver)
 NS_INTERFACE_MAP_END
 
+nsMutationReceiver::nsMutationReceiver(nsINode* aTarget,
+                                       nsDOMMutationObserver* aObserver)
+: nsMutationReceiverBase(aTarget, aObserver)
+{
+  mTarget->BindObject(aObserver);
+}
+
 void
 nsMutationReceiver::Disconnect(bool aRemoveFromObserver)
 {
   if (mRegisterTarget) {
     mRegisterTarget->RemoveMutationObserver(this);
     mRegisterTarget = nullptr;
   }
 
   mParent = nullptr;
   nsINode* target = mTarget;
   mTarget = nullptr;
-  nsIDOMMutationObserver* observer = mObserver;
+  nsDOMMutationObserver* observer = mObserver;
   mObserver = nullptr;
   RemoveClones();
 
   if (target && observer) {
     if (aRemoveFromObserver) {
       static_cast<nsDOMMutationObserver*>(observer)->RemoveReceiver(this);
     }
     // UnbindObject may delete 'this'!
@@ -382,49 +337,42 @@ void nsMutationReceiver::NodeWillBeDestr
   NS_ASSERTION(!mParent, "Shouldn't have mParent here!");
   Disconnect(true);
 }
 
 // Observer
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMutationObserver)
 
-DOMCI_DATA(MutationObserver, nsDOMMutationObserver)
-
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationObserver)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMutationObserver)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMMutationObserver)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MutationObserver)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationObserver)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationObserver)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMMutationObserver)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMMutationObserver)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
   for (int32_t i = 0; i < tmp->mReceivers.Count(); ++i) {
     tmp->mReceivers[i]->Disconnect(false);
   }
   tmp->mReceivers.Clear();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingMutations)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
   // No need to handle mTransientReceivers
   NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMMutationObserver)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReceivers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingMutations)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
   // No need to handle mTransientReceivers
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 nsMutationReceiver*
@@ -500,151 +448,128 @@ nsDOMMutationObserver::ScheduleForRun()
   mWaitingForRun = true;
   RescheduleForRun();
 }
 
 void
 nsDOMMutationObserver::RescheduleForRun()
 {
   if (!sScheduledMutationObservers) {
-    sScheduledMutationObservers = new nsCOMArray<nsIDOMMutationObserver>;
+    sScheduledMutationObservers = new nsTArray<nsRefPtr<nsDOMMutationObserver> >;
   }
 
   bool didInsert = false;
-  for (int32_t i = 0; i < sScheduledMutationObservers->Count(); ++i) {
+  for (uint32_t i = 0; i < sScheduledMutationObservers->Length(); ++i) {
     if (static_cast<nsDOMMutationObserver*>((*sScheduledMutationObservers)[i])
           ->mId > mId) {
-      sScheduledMutationObservers->InsertObjectAt(this, i);
+      sScheduledMutationObservers->InsertElementAt(i, this);
       didInsert = true;
       break;
     }
   }
   if (!didInsert) {
-    sScheduledMutationObservers->AppendObject(this);
+    sScheduledMutationObservers->AppendElement(this);
   }
 }
 
-NS_IMETHODIMP
-nsDOMMutationObserver::Observe(nsIDOMNode* aTarget,
-                               const JS::Value& aOptions,
-                               JSContext* aCx)
+void
+nsDOMMutationObserver::Observe(nsINode& aTarget,
+                               const mozilla::dom::MutationObserverInit& aOptions,
+                               mozilla::ErrorResult& aRv)
 {
-  nsCOMPtr<nsINode> target = do_QueryInterface(aTarget);
-  NS_ENSURE_STATE(target);
 
-  mozilla::dom::MutationObserverInit d;
-  nsresult rv = d.Init(aCx, &aOptions);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  NS_ENSURE_TRUE(d.childList || d.attributes || d.characterData,
-                 NS_ERROR_DOM_SYNTAX_ERR);
-  NS_ENSURE_TRUE(!d.attributeOldValue || d.attributes,
-                 NS_ERROR_DOM_SYNTAX_ERR);
-  NS_ENSURE_TRUE(!d.characterDataOldValue || d.characterData,
-                 NS_ERROR_DOM_SYNTAX_ERR);
+  if (!(aOptions.mChildList || aOptions.mAttributes || aOptions.mCharacterData)) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
+  if (aOptions.mAttributeOldValue && !aOptions.mAttributes) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
+  if (aOptions.mCharacterDataOldValue && !aOptions.mCharacterData) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
 
   nsCOMArray<nsIAtom> filters;
   bool allAttrs = true;
-  if (!d.attributeFilter.isUndefined()) {
+  if (aOptions.mAttributeFilter.WasPassed()) {
     allAttrs = false;
-    rv = nsContentUtils::JSArrayToAtomArray(aCx, d.attributeFilter, filters);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(filters.Count() == 0 || d.attributes,
-                   NS_ERROR_DOM_SYNTAX_ERR);
+    const mozilla::dom::Sequence<nsString>& filtersAsString =
+      aOptions.mAttributeFilter.Value();
+    uint32_t len = filtersAsString.Length();
+
+    if (len != 0 && !aOptions.mAttributes) {
+      aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+      return;
+    }
+    if (!filters.SetCapacity(len)) {
+      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+      return;
+    }
+
+    for (uint32_t i = 0; i < len; ++i) {
+      nsCOMPtr<nsIAtom> a = do_GetAtom(filtersAsString[i]);
+      filters.AppendObject(a);
+    }
   }
 
-  nsMutationReceiver* r = GetReceiverFor(target, true);
-  r->SetChildList(d.childList);
-  r->SetAttributes(d.attributes);
-  r->SetCharacterData(d.characterData);
-  r->SetSubtree(d.subtree);
-  r->SetAttributeOldValue(d.attributeOldValue);
-  r->SetCharacterDataOldValue(d.characterDataOldValue);
+  nsMutationReceiver* r = GetReceiverFor(&aTarget, true);
+  r->SetChildList(aOptions.mChildList);
+  r->SetAttributes(aOptions.mAttributes);
+  r->SetCharacterData(aOptions.mCharacterData);
+  r->SetSubtree(aOptions.mSubtree);
+  r->SetAttributeOldValue(aOptions.mAttributeOldValue);
+  r->SetCharacterDataOldValue(aOptions.mCharacterDataOldValue);
   r->SetAttributeFilter(filters);
   r->SetAllAttributes(allAttrs);
   r->RemoveClones();
 
 #ifdef DEBUG
   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     NS_WARN_IF_FALSE(mReceivers[i]->Target(),
                      "All the receivers should have a target!");
   }
 #endif
-
-  return NS_OK;
 }
 
-NS_IMETHODIMP
+void
 nsDOMMutationObserver::Disconnect()
 {
   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     mReceivers[i]->Disconnect(false);
   }
   mReceivers.Clear();
   mCurrentMutations.Clear();
   mPendingMutations.Clear();
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMMutationObserver::TakeRecords(nsIVariant** aRetVal)
+void
+nsDOMMutationObserver::TakeRecords(
+                         nsTArray<nsRefPtr<nsDOMMutationRecord> >& aRetVal)
 {
-  *aRetVal = TakeRecords().get();
-  return NS_OK;
+  aRetVal.Clear();
+  mPendingMutations.SwapElements(aRetVal);
 }
 
-already_AddRefed<nsIVariant>
-nsDOMMutationObserver::TakeRecords()
+// static
+already_AddRefed<nsDOMMutationObserver>
+nsDOMMutationObserver::Constructor(nsISupports* aGlobal,
+                                   mozilla::dom::MutationCallback& aCb,
+                                   mozilla::ErrorResult& aRv)
 {
-  nsCOMPtr<nsIWritableVariant> mutations =
-    do_CreateInstance("@mozilla.org/variant;1");
-  int32_t len = mPendingMutations.Count();
-  if (len == 0) {
-    mutations->SetAsEmptyArray();
-  } else {
-    nsTArray<nsIDOMMutationRecord*> mods(len);
-    for (int32_t i = 0; i < len; ++i) {
-      mods.AppendElement(mPendingMutations[i]);
-    }
-
-    mutations->SetAsArray(nsIDataType::VTYPE_INTERFACE,
-                          &NS_GET_IID(nsIDOMMutationRecord),
-                          mods.Length(),
-                          const_cast<void*>(
-                            static_cast<const void*>(mods.Elements())));
-    mPendingMutations.Clear();
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal);
+  if (!window) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
-  return mutations.forget();
-}
-
-NS_IMETHODIMP
-nsDOMMutationObserver::Initialize(nsISupports* aOwner, JSContext* cx,
-                                  JSObject* obj, uint32_t argc, jsval* argv)
-{
-  mOwner = do_QueryInterface(aOwner);
-  if (!mOwner) {
-    NS_WARNING("Unexpected nsIJSNativeInitializer owner");
-    return NS_OK;
-  }
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(sgo);
-  mScriptContext = sgo->GetContext();
-  NS_ENSURE_STATE(mScriptContext);
-  
-  NS_ENSURE_STATE(argc >= 1);
-  NS_ENSURE_STATE(!JSVAL_IS_PRIMITIVE(argv[0]));
-
-  nsCOMPtr<nsISupports> tmp;
-  nsContentUtils::XPConnect()->WrapJS(cx, JSVAL_TO_OBJECT(argv[0]),
-                                      NS_GET_IID(nsIMutationObserverCallback),
-                                      getter_AddRefs(tmp));
-  mCallback = do_QueryInterface(tmp);
-  NS_ENSURE_STATE(mCallback);
-  
-  return NS_OK;
+  MOZ_ASSERT(window->IsInnerWindow());
+  nsRefPtr<nsDOMMutationObserver> observer =
+    new nsDOMMutationObserver(window.forget(), aCb);
+  return observer.forget();
 }
 
 void
 nsDOMMutationObserver::HandleMutation()
 {
   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "Whaat!");
   NS_ASSERTION(mCurrentMutations.IsEmpty(),
                "Still generating MutationRecords?");
@@ -652,33 +577,33 @@ nsDOMMutationObserver::HandleMutation()
   mWaitingForRun = false;
 
   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     mReceivers[i]->RemoveClones();
   }
   mTransientReceivers.Clear();
 
   nsPIDOMWindow* outer = mOwner->GetOuterWindow();
-  if (!mPendingMutations.Count() || !outer ||
+  if (!mPendingMutations.Length() || !outer ||
       outer->GetCurrentInnerWindow() != mOwner) {
     mPendingMutations.Clear();
     return;
   }
-  nsCxPusher pusher;
-  nsCOMPtr<nsIDOMEventTarget> et = do_QueryInterface(mOwner);
-  if (!mCallback || !pusher.Push(et)) {
-    mPendingMutations.Clear();
-    return;
+
+  nsTArray<nsRefPtr<nsDOMMutationRecord> > mutationsArray;
+  TakeRecords(mutationsArray);
+  mozilla::dom::Sequence<mozilla::dom::OwningNonNull<nsDOMMutationRecord> >
+    mutations;
+  uint32_t len = mutationsArray.Length();
+  NS_ENSURE_TRUE_VOID(mutations.SetCapacity(len));
+  for (uint32_t i = 0; i < len; ++i) {
+    *mutations.AppendElement() = mutationsArray[i].forget();
   }
-
-  nsCOMPtr<nsIVariant> mutations = TakeRecords();
-  nsAutoMicroTask mt;
-  sCurrentObserver = this; // For 'this' handling.
-  mCallback->HandleMutations(mutations, this);
-  sCurrentObserver = nullptr;
+  mozilla::ErrorResult rv;
+  mCallback->Call(this, mutations, *this, rv);
 }
 
 class AsyncMutationHandler : public nsRunnable
 {
 public:
   NS_IMETHOD Run()
   {
     nsDOMMutationObserver::HandleMutations();
@@ -699,40 +624,40 @@ nsDOMMutationObserver::HandleMutationsIn
     // after previous mutations are handled. But in case some
     // callback calls a sync API, which spins the eventloop, we need to still
     // process other mutations happening during that sync call.
     // This does *not* catch all cases, but should work for stuff running
     // in separate tabs.
     return;
   }
 
-  nsCOMArray<nsIDOMMutationObserver>* suppressedObservers = nullptr;
+  nsTArray<nsRefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
 
   while (sScheduledMutationObservers) {
-    nsCOMArray<nsIDOMMutationObserver>* observers = sScheduledMutationObservers;
+    nsTArray<nsRefPtr<nsDOMMutationObserver> >* observers = sScheduledMutationObservers;
     sScheduledMutationObservers = nullptr;
-    for (int32_t i = 0; i < observers->Count(); ++i) {
+    for (uint32_t i = 0; i < observers->Length(); ++i) {
       sCurrentObserver = static_cast<nsDOMMutationObserver*>((*observers)[i]);
       if (!sCurrentObserver->Suppressed()) {
         sCurrentObserver->HandleMutation();
       } else {
         if (!suppressedObservers) {
-          suppressedObservers = new nsCOMArray<nsIDOMMutationObserver>;
+          suppressedObservers = new nsTArray<nsRefPtr<nsDOMMutationObserver> >;
         }
-        if (suppressedObservers->IndexOf(sCurrentObserver) < 0) {
-          suppressedObservers->AppendObject(sCurrentObserver);
+        if (!suppressedObservers->Contains(sCurrentObserver)) {
+          suppressedObservers->AppendElement(sCurrentObserver);
         }
       }
     }
     delete observers;
   }
 
   if (suppressedObservers) {
-    for (int32_t i = 0; i < suppressedObservers->Count(); ++i) {
-      static_cast<nsDOMMutationObserver*>(suppressedObservers->ObjectAt(i))->
+    for (uint32_t i = 0; i < suppressedObservers->Length(); ++i) {
+      static_cast<nsDOMMutationObserver*>(suppressedObservers->ElementAt(i))->
         RescheduleForRun();
     }
     delete suppressedObservers;
     suppressedObservers = nullptr;
   }
   sCurrentObserver = nullptr;
 }
 
@@ -742,53 +667,53 @@ nsDOMMutationObserver::CurrentRecord(con
   NS_ASSERTION(sMutationLevel > 0, "Unexpected mutation level!");
 
   while (mCurrentMutations.Length() < sMutationLevel) {
     mCurrentMutations.AppendElement(static_cast<nsDOMMutationRecord*>(nullptr));
   }
 
   uint32_t last = sMutationLevel - 1;
   if (!mCurrentMutations[last]) {
-    nsDOMMutationRecord* r = new nsDOMMutationRecord(aType);
+    nsDOMMutationRecord* r = new nsDOMMutationRecord(aType, GetParentObject());
     mCurrentMutations[last] = r;
-    mPendingMutations.AppendObject(r);
+    mPendingMutations.AppendElement(r);
     ScheduleForRun();
   }
 
   NS_ASSERTION(mCurrentMutations[last]->mType.Equals(aType),
                "Unexpected MutationRecord type!");
 
   return mCurrentMutations[last];
 }
 
 nsDOMMutationObserver::~nsDOMMutationObserver()
 {
   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     mReceivers[i]->RemoveClones();
   }
-}                                   
+}
 
 void
 nsDOMMutationObserver::EnterMutationHandling()
 {
   ++sMutationLevel;
 }
 
 // Leave the current mutation level (there can be several levels if in case
 // of nested calls to the nsIMutationObserver methods).
 // The most recent mutation record is removed from mCurrentMutations, so
 // that is doesn't get modified anymore by receivers.
 void
 nsDOMMutationObserver::LeaveMutationHandling()
 {
   if (sCurrentlyHandlingObservers &&
       sCurrentlyHandlingObservers->Length() == sMutationLevel) {
-    nsCOMArray<nsIDOMMutationObserver>& obs =
+    nsTArray<nsRefPtr<nsDOMMutationObserver> >& obs =
       sCurrentlyHandlingObservers->ElementAt(sMutationLevel - 1);
-    for (int32_t i = 0; i < obs.Count(); ++i) {
+    for (uint32_t i = 0; i < obs.Length(); ++i) {
       nsDOMMutationObserver* o =
         static_cast<nsDOMMutationObserver*>(obs[i]);
       if (o->mCurrentMutations.Length() == sMutationLevel) {
         // It is already in pending mutations.
         o->mCurrentMutations.RemoveElementAt(sMutationLevel - 1);
       }
     }
     sCurrentlyHandlingObservers->RemoveElementAt(sMutationLevel - 1);
@@ -798,27 +723,27 @@ nsDOMMutationObserver::LeaveMutationHand
 
 void
 nsDOMMutationObserver::AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver)
 {
   NS_ASSERTION(sMutationLevel > 0, "Unexpected mutation level!");
 
   if (!sCurrentlyHandlingObservers) {
     sCurrentlyHandlingObservers =
-      new nsAutoTArray<nsCOMArray<nsIDOMMutationObserver>, 4>;
+      new nsAutoTArray<nsTArray<nsRefPtr<nsDOMMutationObserver> >, 4>;
   }
 
   while (sCurrentlyHandlingObservers->Length() < sMutationLevel) {
     sCurrentlyHandlingObservers->InsertElementAt(
       sCurrentlyHandlingObservers->Length());
   }
 
   uint32_t last = sMutationLevel - 1;
-  if (sCurrentlyHandlingObservers->ElementAt(last).IndexOf(aObserver) < 0) {
-    sCurrentlyHandlingObservers->ElementAt(last).AppendObject(aObserver);
+  if (!sCurrentlyHandlingObservers->ElementAt(last).Contains(aObserver)) {
+    sCurrentlyHandlingObservers->ElementAt(last).AppendElement(aObserver);
   }
 }
 
 void
 nsDOMMutationObserver::Shutdown()
 {
   delete sCurrentlyHandlingObservers;
   sCurrentlyHandlingObservers = nullptr;
@@ -884,18 +809,19 @@ nsAutoMutationBatch::Done()
     }
     if (wantsChildList && (mRemovedNodes.Length() || mAddedNodes.Length())) {
       nsRefPtr<nsSimpleContentList> addedList =
         new nsSimpleContentList(mBatchTarget);
       for (uint32_t i = 0; i < mAddedNodes.Length(); ++i) {
         addedList->AppendElement(mAddedNodes[i]);
       }
       nsDOMMutationRecord* m =
-        new nsDOMMutationRecord(NS_LITERAL_STRING("childList"));
-      ob->mPendingMutations.AppendObject(m);
+        new nsDOMMutationRecord(NS_LITERAL_STRING("childList"),
+                                ob->GetParentObject());
+      ob->mPendingMutations.AppendElement(m);
       m->mTarget = mBatchTarget;
       m->mRemovedNodes = removedList;
       m->mAddedNodes = addedList;
       m->mPreviousSibling = mPrevSibling;
       m->mNextSibling = mNextSibling;
     }
     // Always schedule the observer so that transient receivers are
     // removed correctly.
--- a/content/base/src/nsDOMMutationObserver.h
+++ b/content/base/src/nsDOMMutationObserver.h
@@ -2,58 +2,112 @@
 /* vim: set sw=4 ts=8 et tw=80 : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsDOMMutationObserver_h
 #define nsDOMMutationObserver_h
 
-#include "nsIDOMMutationObserver.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsIJSNativeInitializer.h"
 #include "nsPIDOMWindow.h"
 #include "nsIScriptContext.h"
 #include "nsStubMutationObserver.h"
 #include "nsCOMArray.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
 #include "nsIVariant.h"
 #include "nsContentList.h"
 #include "mozilla/dom/Element.h"
 #include "nsClassHashtable.h"
 #include "nsNodeUtils.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsWrapperCache.h"
+#include "mozilla/dom/MutationObserverBinding.h"
 
 class nsDOMMutationObserver;
 
-class nsDOMMutationRecord : public nsIDOMMutationRecord
+class nsDOMMutationRecord : public nsISupports,
+                            public nsWrapperCache
 {
 public:
-  nsDOMMutationRecord(const nsAString& aType) : mType(aType)
+  nsDOMMutationRecord(const nsAString& aType, nsISupports* aOwner)
+  : mType(aType), mOwner(aOwner)
   {
     mAttrName.SetIsVoid(PR_TRUE);
     mAttrNamespace.SetIsVoid(PR_TRUE);
     mPrevValue.SetIsVoid(PR_TRUE);
+    SetIsDOMBinding();
   }
   virtual ~nsDOMMutationRecord() {}
+
+  nsISupports* GetParentObject() const
+  {
+    return mOwner;
+  }
+
+  virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
+                               bool* aTriedToWrap)
+  {
+    return mozilla::dom::MutationRecordBinding::Wrap(aCx, aScope, this,
+                                                     aTriedToWrap);
+  }
+
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMMutationRecord)
-  NS_DECL_NSIDOMMUTATIONRECORD
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMMutationRecord)
+
+  void GetType(nsString& aRetVal) const
+  {
+    aRetVal = mType;
+  }
+
+  nsINode* GetTarget() const
+  {
+    return mTarget;
+  }
+
+  nsINodeList* AddedNodes();
+
+  nsINodeList* RemovedNodes();
+
+  nsINode* GetPreviousSibling() const
+  {
+    return mPreviousSibling;
+  }
+
+  nsINode* GetNextSibling() const
+  {
+    return mNextSibling;
+  }
+
+  void GetAttributeName(nsString& aRetVal) const
+  {
+    aRetVal = mAttrName;
+  }
+
+  void GetAttributeNamespace(nsString& aRetVal) const
+  {
+    aRetVal = mAttrNamespace;
+  }
+
+  void GetOldValue(nsString& aRetVal) const
+  {
+    aRetVal = mPrevValue;
+  }
 
   nsCOMPtr<nsINode>             mTarget;
   nsString                      mType;
   nsString                      mAttrName;
   nsString                      mAttrNamespace;
   nsString                      mPrevValue;
   nsRefPtr<nsSimpleContentList> mAddedNodes;
   nsRefPtr<nsSimpleContentList> mRemovedNodes;
   nsCOMPtr<nsINode>             mPreviousSibling;
   nsCOMPtr<nsINode>             mNextSibling;
+  nsCOMPtr<nsISupports>         mOwner;
 };
  
 // Base class just prevents direct access to
 // members to make sure we go through getters/setters.
 class nsMutationReceiverBase : public nsStubMutationObserver
 {
 public:
   virtual ~nsMutationReceiverBase() { }
@@ -138,17 +192,17 @@ public:
   }
 
   void RemoveClone(nsMutationReceiverBase* aClone)
   {
     mTransientReceivers.RemoveObject(aClone);
   }
   
 protected:
-  nsMutationReceiverBase(nsINode* aTarget, nsIDOMMutationObserver* aObserver)
+  nsMutationReceiverBase(nsINode* aTarget, nsDOMMutationObserver* aObserver)
   : mTarget(aTarget), mObserver(aObserver), mRegisterTarget(aTarget)
   {
     mRegisterTarget->AddMutationObserver(this);
     mRegisterTarget->SetMayHaveDOMMutationObserver();
     mRegisterTarget->OwnerDoc()->SetMayHaveDOMMutationObservers();
   }
 
   nsMutationReceiverBase(nsINode* aRegisterTarget,
@@ -176,27 +230,27 @@ protected:
       return true;
     }
 
     if (aNameSpaceID != kNameSpaceID_None) {
       return false;
     }
 
     nsCOMArray<nsIAtom>& filters = AttributeFilter();
-    for (int32_t i = 0; i < filters.Count(); ++i) {         
+    for (int32_t i = 0; i < filters.Count(); ++i) {
       if (filters[i] == aAttr) {
         return true;
       }
     }
     return false;
   }
 
   // The target for the MutationObserver.observe() method.
   nsINode*                           mTarget;
-  nsIDOMMutationObserver*            mObserver;
+  nsDOMMutationObserver*             mObserver;
   nsRefPtr<nsMutationReceiverBase>   mParent; // Cleared after microtask.
   // The node to which Gecko-internal nsIMutationObserver was registered to.
   // This is different than mTarget when dealing with transient observers.
   nsINode*                           mRegisterTarget;
   nsCOMArray<nsMutationReceiverBase> mTransientReceivers;
   // While we have transient receivers, keep the original mutation receiver
   // alive so it doesn't go away and disconnect all its transient receivers.
   nsCOMPtr<nsINode>                  mKungFuDeathGrip;
@@ -215,21 +269,17 @@ private:
 
 #define NS_MUTATION_OBSERVER_IID \
 { 0xe628f313, 0x8129, 0x4f90, \
   { 0x8e, 0xc3, 0x85, 0xe8, 0x28, 0x22, 0xe7, 0xab } }
 
 class nsMutationReceiver : public nsMutationReceiverBase
 {
 public:
-  nsMutationReceiver(nsINode* aTarget, nsIDOMMutationObserver* aObserver)
-  : nsMutationReceiverBase(aTarget, aObserver)
-  {
-    mTarget->BindObject(aObserver);
-  }
+  nsMutationReceiver(nsINode* aTarget, nsDOMMutationObserver* aObserver);
 
   nsMutationReceiver(nsINode* aRegisterTarget, nsMutationReceiverBase* aParent)
   : nsMutationReceiverBase(aRegisterTarget, aParent)
   {
     NS_ASSERTION(!static_cast<nsMutationReceiver*>(aParent)->GetParent(),
                  "Shouldn't create deep observer hierarchies!");
     aParent->AddClone(this);
   }
@@ -284,80 +334,68 @@ public:
     // We can reuse AttributeWillChange implementation.
     AttributeWillChange(aDocument, aElement, aNameSpaceID, aAttribute,
                         nsIDOMMutationEvent::MODIFICATION);
   }
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsMutationReceiver, NS_MUTATION_OBSERVER_IID)
 
-class nsDOMMutationObserver : public nsIDOMMutationObserver,
-                              public nsIJSNativeInitializer,
+class nsDOMMutationObserver : public nsISupports,
                               public nsWrapperCache
 {
 public:
-  nsDOMMutationObserver() : mWaitingForRun(false), mId(++sCount)
+  nsDOMMutationObserver(already_AddRefed<nsPIDOMWindow> aOwner,
+                        mozilla::dom::MutationCallback& aCb)
+  : mOwner(aOwner), mCallback(&aCb), mWaitingForRun(false), mId(++sCount)
   {
     mTransientReceivers.Init();
+    SetIsDOMBinding();
   }
   virtual ~nsDOMMutationObserver();
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDOMMutationObserver,
-                                                         nsIDOMMutationObserver)
-  NS_DECL_NSIDOMMUTATIONOBSERVER
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMMutationObserver)
 
-  NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
-                        uint32_t argc, jsval* argv);
+  static already_AddRefed<nsDOMMutationObserver>
+  Constructor(nsISupports* aGlobal, mozilla::dom::MutationCallback& aCb,
+              mozilla::ErrorResult& aRv);
 
-  void GetParentObject(nsIScriptGlobalObject** aParentObject)
+  virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
+                               bool* aTriedToWrap)
   {
-    if (mOwner) {
-      CallQueryInterface(mOwner, aParentObject);
-    } else {
-      *aParentObject = nullptr;
-    }
+    return mozilla::dom::MutationObserverBinding::Wrap(aCx, aScope,
+                                                       this, aTriedToWrap);
   }
 
-  static nsDOMMutationObserver* FromSupports(nsISupports* aSupports)
+  nsISupports* GetParentObject() const
   {
-    nsIDOMMutationObserver* mutationObserver =
-      static_cast<nsIDOMMutationObserver*>(aSupports);
-#ifdef DEBUG
-    {
-      nsCOMPtr<nsIDOMMutationObserver> mutationObserver_qi =
-        do_QueryInterface(aSupports);
+    return mOwner;
+  }
 
-      // If this assertion fires the QI implementation for the object in
-      // question doesn't use the nsIDOMMutationObserver pointer as the
-      // nsISupports pointer. That must be fixed, or we'll crash...
-      NS_ASSERTION(mutationObserver_qi == mutationObserver, "Uh, fix QI!");
-    }
-#endif
+  void Observe(nsINode& aTarget,
+               const mozilla::dom::MutationObserverInit& aOptions,
+               mozilla::ErrorResult& aRv);
 
-    return static_cast<nsDOMMutationObserver*>(mutationObserver);
-  }
+  void Disconnect();
+
+  void TakeRecords(nsTArray<nsRefPtr<nsDOMMutationRecord> >& aRetVal);
 
   void HandleMutation();
 
   // static methods
   static void HandleMutations()
   {
     if (sScheduledMutationObservers) {
       HandleMutationsInternal();
     }
   }
 
   static void EnterMutationHandling();
   static void LeaveMutationHandling();
 
-  static nsIDOMMutationObserver* CurrentObserver()
-  {
-    return sCurrentObserver;
-  }
-
   static void Shutdown();
 protected:
   friend class nsMutationReceiver;
   friend class nsAutoMutationBatch;
   nsMutationReceiver* GetReceiverFor(nsINode* aNode, bool aMayCreate);
   void RemoveReceiver(nsMutationReceiver* aReceiver);
 
   already_AddRefed<nsIVariant> TakeRecords();
@@ -378,39 +416,38 @@ protected:
     }
     return false;
   }
 
   static void HandleMutationsInternal();
 
   static void AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver);
 
-  nsCOMPtr<nsIScriptContext>                         mScriptContext;
   nsCOMPtr<nsPIDOMWindow>                            mOwner;
 
   nsCOMArray<nsMutationReceiver>                     mReceivers;
   nsClassHashtable<nsISupportsHashKey,
-                   nsCOMArray<nsMutationReceiver> >  mTransientReceivers;  
+                   nsCOMArray<nsMutationReceiver> >  mTransientReceivers;
   // MutationRecords which are being constructed.
   nsAutoTArray<nsDOMMutationRecord*, 4>              mCurrentMutations;
   // MutationRecords which will be handed to the callback at the end of
   // the microtask.
-  nsCOMArray<nsDOMMutationRecord>                    mPendingMutations;
-  nsCOMPtr<nsIMutationObserverCallback>              mCallback;
+  nsTArray<nsRefPtr<nsDOMMutationRecord> >           mPendingMutations;
+  nsRefPtr<mozilla::dom::MutationCallback>           mCallback;
 
   bool                                               mWaitingForRun;
 
   uint64_t                                           mId;
 
   static uint64_t                                    sCount;
-  static nsCOMArray<nsIDOMMutationObserver>*         sScheduledMutationObservers;
-  static nsIDOMMutationObserver*                     sCurrentObserver;
+  static nsTArray<nsRefPtr<nsDOMMutationObserver> >* sScheduledMutationObservers;
+  static nsDOMMutationObserver*                      sCurrentObserver;
 
   static uint32_t                                    sMutationLevel;
-  static nsAutoTArray<nsCOMArray<nsIDOMMutationObserver>, 4>*
+  static nsAutoTArray<nsTArray<nsRefPtr<nsDOMMutationObserver> >, 4>*
                                                      sCurrentlyHandlingObservers;
 };
 
 class nsAutoMutationBatch
 {
 public:
   nsAutoMutationBatch()
   : mPreviousBatch(nullptr), mBatchTarget(nullptr), mRemovalDone(false),
@@ -532,17 +569,9 @@ private:
 inline
 nsDOMMutationObserver*
 nsMutationReceiverBase::Observer()
 {
   return mParent ?
     mParent->Observer() : static_cast<nsDOMMutationObserver*>(mObserver);
 }
 
-#define NS_DOMMUTATIONOBSERVER_CID           \
- { /* b66b9490-52f7-4f2a-b998-dbb1d59bc13e */ \
-  0xb66b9490, 0x52f7, 0x4f2a,                 \
-  { 0xb9, 0x98, 0xdb, 0xb1, 0xd5, 0x9b, 0xc1, 0x3e } }
-
-#define NS_DOMMUTATIONOBSERVER_CONTRACTID \
-  "@mozilla.org/dommutationobserver;1"
-
 #endif
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * Base class for all our document implementations.
  */
 
+#include "mozilla/DebugOnly.h"
 #include "mozilla/Util.h"
 #include "mozilla/Likely.h"
 
 #ifdef MOZ_LOGGING
 // so we can get logging even in release builds
 #define FORCE_PR_LOG 1
 #endif
 #include "prlog.h"
@@ -7059,17 +7060,17 @@ nsDocument::OnPageShow(bool aPersisted,
   if (mAnimationController) {
     mAnimationController->OnPageShow();
   }
 
   if (aPersisted) {
     SetImagesNeedAnimating(true);
   }
 
-  UpdateVisibilityState(true);
+  UpdateVisibilityState();
 
   nsCOMPtr<nsIDOMEventTarget> target = aDispatchStartTarget;
   if (!target) {
     target = do_QueryInterface(GetWindow());
   }
   DispatchPageTransition(target, NS_LITERAL_STRING("pageshow"), aPersisted);
 }
 
@@ -7121,17 +7122,17 @@ nsDocument::OnPageHide(bool aPersisted,
   nsCOMPtr<nsIDOMEventTarget> target = aDispatchStartTarget;
   if (!target) {
     target = do_QueryInterface(GetWindow());
   }
   DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted);
 
   mVisible = false;
 
-  UpdateVisibilityState(true);
+  UpdateVisibilityState();
 
   EnumerateExternalResources(NotifyPageHide, &aPersisted);
   EnumerateFreezableElements(NotifyActivityChanged, nullptr);
 
   if (IsFullScreenDoc()) {
     // A full-screen doc has been hidden. We need to ensure we exit
     // full-screen, i.e. remove full-screen state from all full-screen
     // documents, and exit the top-level window from full-screen mode.
@@ -9479,47 +9480,35 @@ nsDocument::GetMozPointerLockElement(nsI
   }
 #define TOUCH_EVENT EVENT
 #define DOCUMENT_ONLY_EVENT EVENT
 #include "nsEventNameList.h"
 #undef DOCUMENT_ONLY_EVENT
 #undef TOUCH_EVENT
 #undef EVENT
 
-/* virtual */ void
-nsDocument::UpdateVisibilityState(bool aFireEventSync)
+void
+nsDocument::UpdateVisibilityState()
 {
   VisibilityState oldState = mVisibilityState;
   mVisibilityState = GetVisibilityState();
   if (oldState != mVisibilityState) {
-    if (aFireEventSync) {
-      FireVisibilityChangeEvent();
-    } else {
-      nsCOMPtr<nsIRunnable> event =
-        NS_NewRunnableMethod(this, &nsDocument::FireVisibilityChangeEvent);
-      NS_DispatchToMainThread(event);
-    }
+    nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
+                                         NS_LITERAL_STRING("visibilitychange"),
+                                         /* bubbles = */ true,
+                                         /* cancelable = */ false);
+    nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
+                                         NS_LITERAL_STRING("mozvisibilitychange"),
+                                         /* bubbles = */ true,
+                                         /* cancelable = */ false);
 
     EnumerateFreezableElements(NotifyActivityChanged, nullptr);
   }
 }
 
-void
-nsDocument::FireVisibilityChangeEvent()
-{
-  nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
-                                       NS_LITERAL_STRING("visibilitychange"),
-                                       /* bubbles = */ true,
-                                       /* cancelable = */ false);
-  nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
-                                       NS_LITERAL_STRING("mozvisibilitychange"),
-                                       /* bubbles = */ true,
-                                       /* cancelable = */ false);
-}
-
 nsDocument::VisibilityState
 nsDocument::GetVisibilityState() const
 {
   // We have to check a few pieces of information here:
   // 1)  Are we in bfcache (!IsVisible())?  If so, nothing else matters.
   // 2)  Do we have an outer window?  If not, we're hidden.  Note that we don't
   //     want to use GetWindow here because it does weird groveling for windows
   //     in some cases.
@@ -9528,16 +9517,24 @@ nsDocument::GetVisibilityState() const
   if (!IsVisible() || !mWindow || !mWindow->GetOuterWindow() ||
       mWindow->GetOuterWindow()->IsBackground()) {
     return eHidden;
   }
 
   return eVisible;
 }
 
+/* virtual */ void
+nsDocument::PostVisibilityUpdateEvent()
+{
+  nsCOMPtr<nsIRunnable> event =
+    NS_NewRunnableMethod(this, &nsDocument::UpdateVisibilityState);
+  NS_DispatchToMainThread(event);
+}
+
 NS_IMETHODIMP
 nsDocument::GetMozHidden(bool* aHidden)
 {
   WarnOnceAbout(ePrefixedVisibilityAPI);
   return GetHidden(aHidden);
 }
 
 NS_IMETHODIMP
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -990,18 +990,21 @@ public:
   // Returns the top element from the full-screen stack.
   Element* FullScreenStackTop();
 
   void RequestPointerLock(Element* aElement);
   bool ShouldLockPointer(Element* aElement);
   bool SetPointerLock(Element* aElement, int aCursorStyle);
   static void UnlockPointer();
 
-  virtual void UpdateVisibilityState(bool aFireEventSync);
-  void FireVisibilityChangeEvent();
+  // This method may fire a DOM event; if it does so it will happen
+  // synchronously.
+  void UpdateVisibilityState();
+  // Posts an event to call UpdateVisibilityState
+  virtual void PostVisibilityUpdateEvent();
 
   virtual void DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const;
   // DocSizeOfIncludingThis is inherited from nsIDocument.
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
 protected:
   friend class nsNodeUtils;
 
--- a/content/base/src/nsEventSource.cpp
+++ b/content/base/src/nsEventSource.cpp
@@ -1,13 +1,14 @@
 /* -*- 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/DebugOnly.h"
 #include "mozilla/Util.h"
 
 #include "nsEventSource.h"
 #include "nsNetUtil.h"
 #include "nsMimeTypes.h"
 #include "nsDOMMessageEvent.h"
 #include "nsIJSContextStack.h"
 #include "nsIPromptFactory.h"
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -3,16 +3,18 @@
  * 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/. */
 
 /*
  * Base class for DOM Core's nsIDOMComment, nsIDOMDocumentType, nsIDOMText,
  * nsIDOMCDATASection, and nsIDOMProcessingInstruction nodes.
  */
 
+#include "mozilla/DebugOnly.h"
+
 #include "nsGenericDOMDataNode.h"
 #include "mozilla/dom/Element.h"
 #include "nsIDocument.h"
 #include "nsEventListenerManager.h"
 #include "nsIDOMDocument.h"
 #include "nsReadableUtils.h"
 #include "nsMutationEvent.h"
 #include "nsINameSpaceManager.h"
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -240,17 +240,17 @@ nsPluginCrashedEvent::Run()
   nsCOMPtr<nsIDOMDataContainerEvent> containerEvent(do_QueryInterface(event));
   if (!containerEvent) {
     NS_WARNING("Couldn't QI event for PluginCrashed event!");
     return NS_OK;
   }
 
   event->InitEvent(NS_LITERAL_STRING("PluginCrashed"), true, true);
   event->SetTrusted(true);
-  event->GetInternalNSEvent()->flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
+  event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
 
   nsCOMPtr<nsIWritableVariant> variant;
 
   // add a "pluginDumpID" property to this event
   variant = do_CreateInstance("@mozilla.org/variant;1");
   if (!variant) {
     NS_WARNING("Couldn't create pluginDumpID variant for PluginCrashed event!");
     return NS_OK;
@@ -1957,22 +1957,24 @@ nsObjectLoadingContent::LoadObject(bool 
 
   rv = NS_OK;
   if (doSpawnPlugin) {
     rv = InstantiatePluginInstance(true);
     NS_ENSURE_TRUE(mIsLoading, NS_OK);
     // Create the final listener if we're loading with a channel. We can't do
     // this in the loading block above as it requires an instance.
     if (aLoadingChannel && NS_SUCCEEDED(rv)) {
-      // Plugins can continue to run even if their initial stream dies. Some
-      // plugins will even return failure codes to reject the stream, but expect
-      // to continue running, so ignore the error code. rv is thus the result of
-      // spawning the plugin above
       if (NS_SUCCEEDED(rv) && MakePluginListener()) {
-        mFinalListener->OnStartRequest(mChannel, nullptr);
+        rv = mFinalListener->OnStartRequest(mChannel, nullptr);
+        if (NS_FAILED(rv)) {
+          // Plugins can reject their initial stream, but continue to run.
+          CloseChannel();
+          NS_ENSURE_TRUE(mIsLoading, NS_OK);
+          rv = NS_OK;
+        }
       }
     }
   } else if (finalListener) {
     NS_ASSERTION(mType != eType_Null && mType != eType_Loading,
                  "We should not have a final listener with a non-loaded type");
     mFinalListener = finalListener;
     rv = finalListener->OnStartRequest(mChannel, nullptr);
   }
--- a/content/base/src/nsScriptElement.cpp
+++ b/content/base/src/nsScriptElement.cpp
@@ -54,20 +54,18 @@ nsScriptElement::ScriptEvaluated(nsresul
       do_QueryInterface((nsIScriptElement*) this);
 
     nsRefPtr<nsPresContext> presContext =
       nsContentUtils::GetContextForContent(cont);
 
     nsEventStatus status = nsEventStatus_eIgnore;
     uint32_t type = NS_SUCCEEDED(aResult) ? NS_LOAD : NS_LOAD_ERROR;
     nsEvent event(true, type);
-    if (type == NS_LOAD) {
-      // Load event doesn't bubble.
-      event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
-    }
+    // Load event doesn't bubble.
+    event.mFlags.mBubbles = (type != NS_LOAD);
 
     nsEventDispatcher::Dispatch(cont, presContext, &event, nullptr, &status);
   }
 
   return rv;
 }
 
 void
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsViewportInfo.cpp
@@ -0,0 +1,23 @@
+/* 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 "nsViewportInfo.h"
+
+void
+nsViewportInfo::SetDefaultZoom(const double aDefaultZoom)
+{
+  MOZ_ASSERT(aDefaultZoom >= 0.0f);
+  mDefaultZoom = aDefaultZoom;
+}
+
+void
+nsViewportInfo::ConstrainViewportValues()
+{
+  // Constrain the min/max zoom as specified at:
+  // dev.w3.org/csswg/css-device-adapt section 6.2
+  mMaxZoom = NS_MAX(mMinZoom, mMaxZoom);
+
+  mDefaultZoom = NS_MIN(mDefaultZoom, mMaxZoom);
+  mDefaultZoom = NS_MAX(mDefaultZoom, mMinZoom);
+}
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -366,21 +366,18 @@ NS_IMPL_EVENT_HANDLER(nsXHREventTarget, 
 void
 nsXHREventTarget::DisconnectFromOwner()
 {
   nsDOMEventTargetHelper::DisconnectFromOwner();
 }
 
 /////////////////////////////////////////////
 
-DOMCI_DATA(XMLHttpRequestUpload, nsXMLHttpRequestUpload)
-
 NS_INTERFACE_MAP_BEGIN(nsXMLHttpRequestUpload)
   NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequestUpload)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XMLHttpRequestUpload)
 NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
 
 NS_IMPL_ADDREF_INHERITED(nsXMLHttpRequestUpload, nsXHREventTarget)
 NS_IMPL_RELEASE_INHERITED(nsXMLHttpRequestUpload, nsXHREventTarget)
 
 /////////////////////////////////////////////
 //
 //
@@ -628,31 +625,28 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsXMLHttpRequest,
                                                nsXHREventTarget)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultArrayBuffer)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResultJSON)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-DOMCI_DATA(XMLHttpRequest, nsXMLHttpRequest)
-
 // QueryInterface implementation for nsXMLHttpRequest
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLHttpRequest)
   NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequest)
   NS_INTERFACE_MAP_ENTRY(nsIJSXMLHttpRequest)
   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
   NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XMLHttpRequest)
 NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
 
 NS_IMPL_ADDREF_INHERITED(nsXMLHttpRequest, nsXHREventTarget)
 NS_IMPL_RELEASE_INHERITED(nsXMLHttpRequest, nsXHREventTarget)
 
 NS_IMPL_EVENT_HANDLER(nsXMLHttpRequest, readystatechange)
 
 void
@@ -2333,18 +2327,17 @@ nsXMLHttpRequest::OnStopRequest(nsIReque
   }
   if (mIsHtml) {
     NS_ASSERTION(!(mState & XML_HTTP_REQUEST_SYNCLOOPING),
       "We weren't supposed to support HTML parsing with XHR!");
     nsCOMPtr<nsIDOMEventTarget> eventTarget = do_QueryInterface(mResponseXML);
     nsEventListenerManager* manager = eventTarget->GetListenerManager(true);
     manager->AddEventListenerByType(new nsXHRParseEndListener(this),
                                     NS_LITERAL_STRING("DOMContentLoaded"),
-                                    NS_EVENT_FLAG_BUBBLE |
-                                    NS_EVENT_FLAG_SYSTEM_EVENT);
+                                    dom::TrustedEventsAtSystemGroupBubble());
     return NS_OK;
   }
   // We might have been sent non-XML data. If that was the case,
   // we should null out the document member. The idea in this
   // check here is that if there is no document element it is not
   // an XML document. We might need a fancier check...
   if (!mResponseXML->GetRootElement()) {
     mResponseXML = nullptr;
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -154,17 +154,17 @@ public:
     nsCOMPtr<nsIScriptObjectPrincipal> principal = do_QueryInterface(aGlobal);
     if (!window || ! principal) {
       aRv.Throw(NS_ERROR_FAILURE);
       return NULL;
     }
 
     nsRefPtr<nsXMLHttpRequest> req = new nsXMLHttpRequest();
     req->Construct(principal->GetPrincipal(), window);
-    req->InitParameters(aParams.mozAnon, aParams.mozSystem);
+    req->InitParameters(aParams.mMozAnon, aParams.mMozSystem);
     return req.forget();
   }
 
   static already_AddRefed<nsXMLHttpRequest>
   Constructor(JSContext* aCx,
               nsISupports* aGlobal,
               const nsAString& ignored,
               ErrorResult& aRv)
--- a/content/base/test/test_bug435425.html
+++ b/content/base/test/test_bug435425.html
@@ -166,18 +166,18 @@ for (var smallLength = 0; smallLength < 
 for (var midLength = 0; midLength < (0x00000FFF + 2); ++midLength) {
   mid += "A";
 }
 
 for (var largeLength = 0; largeLength < (0x0000FFFF + 2); ++largeLength) {
   large += "A";
 }
 
-const XHR = SpecialPowers.Ci.nsIXMLHttpRequest;
-const UPLOAD = SpecialPowers.Ci.nsIXMLHttpRequestUpload;
+const XHR = XMLHttpRequest;
+const UPLOAD = XMLHttpRequestUpload;
 
 var tests = 
   [
     { method: "GET", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: false,
       expectedEvents: [{target: XHR, type: "loadstart", optional: false},
                        {target: XHR, type: "progress", optional: true},
                        {target: XHR, type: "load", optional: false},
                        {target: XHR, type: "loadend", optional: false}]},
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -520,18 +520,16 @@ NS_INTERFACE_MAP_END
 
 /**
  ** CanvasRenderingContext2D impl
  **/
 
 
 // Initialize our static variables.
 uint32_t CanvasRenderingContext2D::sNumLivingContexts = 0;
-uint8_t (*CanvasRenderingContext2D::sUnpremultiplyTable)[256] = nullptr;
-uint8_t (*CanvasRenderingContext2D::sPremultiplyTable)[256] = nullptr;
 DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
 
 
 
 CanvasRenderingContext2D::CanvasRenderingContext2D()
   : mZero(false), mOpaque(false), mResetLayer(true)
   , mIPC(false)
   , mIsEntireFrameInvalid(false)
@@ -546,20 +544,16 @@ CanvasRenderingContext2D::~CanvasRenderi
 {
   Reset();
   // Drop references from all CanvasRenderingContext2DUserData to this context
   for (uint32_t i = 0; i < mUserDatas.Length(); ++i) {
     mUserDatas[i]->Forget();
   }
   sNumLivingContexts--;
   if (!sNumLivingContexts) {
-    delete[] sUnpremultiplyTable;
-    delete[] sPremultiplyTable;
-    sUnpremultiplyTable = nullptr;
-    sPremultiplyTable = nullptr;
     NS_IF_RELEASE(sErrorTarget);
   }
 }
 
 JSObject*
 CanvasRenderingContext2D::WrapObject(JSContext *cx, JSObject *scope,
                                      bool *triedToWrap)
 {
@@ -2854,17 +2848,17 @@ CanvasRenderingContext2D::IsPointInPath(
   }
   if (mPathTransformWillUpdate) {
     return mPath->ContainsPoint(Point(x, y), mPathToDS);
   }
   return mPath->ContainsPoint(Point(x, y), mTarget->GetTransform());
 }
 
 bool
-CanvasRenderingContext2D::MozIsPointInStroke(double x, double y)
+CanvasRenderingContext2D::IsPointInStroke(double x, double y)
 {
   if (!FloatValidate(x,y)) {
     return false;
   }
 
   EnsureUserSpacePath();
   if (!mPath) {
     return false;
@@ -3320,43 +3314,16 @@ CanvasRenderingContext2D::AsyncDrawXULEl
   }
 #endif
 }
 
 //
 // device pixel getting/setting
 //
 
-void
-CanvasRenderingContext2D::EnsureUnpremultiplyTable() {
-  if (sUnpremultiplyTable)
-    return;
-
-  // Infallably alloc the unpremultiply table.
-  sUnpremultiplyTable = new uint8_t[256][256];
-
-  // It's important that the array be indexed first by alpha and then by rgb
-  // value.  When we unpremultiply a pixel, we're guaranteed to do three
-  // lookups with the same alpha; indexing by alpha first makes it likely that
-  // those three lookups will be close to one another in memory, thus
-  // increasing the chance of a cache hit.
-
-  // a == 0 case
-  for (uint32_t c = 0; c <= 255; c++) {
-    sUnpremultiplyTable[0][c] = c;
-  }
-
-  for (int a = 1; a <= 255; a++) {
-    for (int c = 0; c <= 255; c++) {
-      sUnpremultiplyTable[a][c] = (uint8_t)((c * 255) / a);
-    }
-  }
-}
-
-
 already_AddRefed<ImageData>
 CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx,
                                        double aSy, double aSw,
                                        double aSh, ErrorResult& error)
 {
   EnsureTarget();
   if (!IsTargetValid()) {
     error.Throw(NS_ERROR_FAILURE);
@@ -3479,19 +3446,16 @@ CanvasRenderingContext2D::GetImageDataAr
     if (snapshot) {
       readback = snapshot->GetDataSurface();
 
       srcStride = readback->Stride();
       src = readback->GetData() + srcReadRect.y * srcStride + srcReadRect.x * 4;
     }
   }
 
-  // make sure sUnpremultiplyTable has been created
-  EnsureUnpremultiplyTable();
-
   // NOTE! dst is the same as src, and this relies on reading
   // from src and advancing that ptr before writing to dst.
   // NOTE! I'm not sure that it is, I think this comment might have been
   // inherited from Thebes canvas and is no longer true
   uint8_t* dst = data + dstWriteRect.y * (aWidth * 4) + dstWriteRect.x * 4;
 
   for (int32_t j = 0; j < dstWriteRect.height; ++j) {
     for (int32_t i = 0; i < dstWriteRect.width; ++i) {
@@ -3503,49 +3467,30 @@ CanvasRenderingContext2D::GetImageDataAr
       uint8_t a = *src++;
 #else
       uint8_t a = *src++;
       uint8_t r = *src++;
       uint8_t g = *src++;
       uint8_t b = *src++;
 #endif
       // Convert to non-premultiplied color
-      *dst++ = sUnpremultiplyTable[a][r];
-      *dst++ = sUnpremultiplyTable[a][g];
-      *dst++ = sUnpremultiplyTable[a][b];
+      *dst++ = gfxUtils::sUnpremultiplyTable[a * 256 + r];
+      *dst++ = gfxUtils::sUnpremultiplyTable[a * 256 + g];
+      *dst++ = gfxUtils::sUnpremultiplyTable[a * 256 + b];
       *dst++ = a;
     }
     src += srcStride - (dstWriteRect.width * 4);
     dst += (aWidth * 4) - (dstWriteRect.width * 4);
   }
 
   *aRetval = darray;
   return NS_OK;
 }
 
 void
-CanvasRenderingContext2D::EnsurePremultiplyTable() {
-  if (sPremultiplyTable)
-    return;
-
-  // Infallably alloc the premultiply table.
-  sPremultiplyTable = new uint8_t[256][256];
-
-  // Like the unpremultiply table, it's important that we index the premultiply
-  // table with the alpha value as the first index to ensure good cache
-  // performance.
-
-  for (int a = 0; a <= 255; a++) {
-    for (int c = 0; c <= 255; c++) {
-      sPremultiplyTable[a][c] = (a * c + 254) / 255;
-    }
-  }
-}
-
-void
 CanvasRenderingContext2D::EnsureErrorTarget()
 {
   if (sErrorTarget) {
     return;
   }
 
   RefPtr<DrawTarget> errorTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1, 1), FORMAT_B8G8R8A8);
   NS_ABORT_IF_FALSE(errorTarget, "Failed to allocate the error target!");
@@ -3657,40 +3602,37 @@ CanvasRenderingContext2D::PutImageData_e
 
   nsRefPtr<gfxImageSurface> imgsurf = new gfxImageSurface(gfxIntSize(w, h),
                                                           gfxASurface::ImageFormatARGB32,
                                                           false);
   if (!imgsurf || imgsurf->CairoStatus()) {
     return NS_ERROR_FAILURE;
   }
 
-  // ensure premultiply table has been created
-  EnsurePremultiplyTable();
-
   uint8_t *src = aData;
   uint8_t *dst = imgsurf->Data();
 
   for (uint32_t j = 0; j < h; j++) {
     for (uint32_t i = 0; i < w; i++) {
       uint8_t r = *src++;
       uint8_t g = *src++;
       uint8_t b = *src++;
       uint8_t a = *src++;
 
       // Convert to premultiplied color (losslessly if the input came from getImageData)
 #ifdef IS_LITTLE_ENDIAN
-      *dst++ = sPremultiplyTable[a][b];
-      *dst++ = sPremultiplyTable[a][g];
-      *dst++ = sPremultiplyTable[a][r];
+      *dst++ = gfxUtils::sPremultiplyTable[a * 256 + b];
+      *dst++ = gfxUtils::sPremultiplyTable[a * 256 + g];
+      *dst++ = gfxUtils::sPremultiplyTable[a * 256 + r];
       *dst++ = a;
 #else
       *dst++ = a;
-      *dst++ = sPremultiplyTable[a][r];
-      *dst++ = sPremultiplyTable[a][g];
-      *dst++ = sPremultiplyTable[a][b];
+      *dst++ = gfxUtils::sPremultiplyTable[a * 256 + r];
+      *dst++ = gfxUtils::sPremultiplyTable[a * 256 + g];
+      *dst++ = gfxUtils::sPremultiplyTable[a * 256 + b];
 #endif
     }
   }
 
   EnsureTarget();
   if (!IsTargetValid()) {
     return NS_ERROR_FAILURE;
   }
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -237,17 +237,17 @@ public:
   void ClearRect(double x, double y, double w, double h);
   void FillRect(double x, double y, double w, double h);
   void StrokeRect(double x, double y, double w, double h);
   void BeginPath();
   void Fill();
   void Stroke();
   void Clip();
   bool IsPointInPath(double x, double y);
-  bool MozIsPointInStroke(double x, double y);
+  bool IsPointInStroke(double x, double y);
   void FillText(const nsAString& text, double x, double y,
                 const mozilla::dom::Optional<double>& maxWidth,
                 mozilla::ErrorResult& error);
   void StrokeText(const nsAString& text, double x, double y,
                   const mozilla::dom::Optional<double>& maxWidth,
                   mozilla::ErrorResult& error);
   already_AddRefed<nsIDOMTextMetrics>
     MeasureText(const nsAString& rawText, mozilla::ErrorResult& error);
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -891,22 +891,22 @@ WebGLContext::GetContextAttributes(Nulla
 {
     retval.SetNull();
     if (!IsContextStable())
         return;
 
     dom::WebGLContextAttributes& result = retval.SetValue();
 
     gl::ContextFormat cf = gl->ActualFormat();
-    result.alpha = cf.alpha > 0;
-    result.depth = cf.depth > 0;
-    result.stencil = cf.stencil > 0;
-    result.antialias = cf.samples > 1;
-    result.premultipliedAlpha = mOptions.premultipliedAlpha;
-    result.preserveDrawingBuffer = mOptions.preserveDrawingBuffer;
+    result.mAlpha = cf.alpha > 0;
+    result.mDepth = cf.depth > 0;
+    result.mStencil = cf.stencil > 0;
+    result.mAntialias = cf.samples > 1;
+    result.mPremultipliedAlpha = mOptions.premultipliedAlpha;
+    result.mPreserveDrawingBuffer = mOptions.preserveDrawingBuffer;
 }
 
 bool
 WebGLContext::IsExtensionEnabled(WebGLExtensionID ext) const {
     return mExtensions.SafeElementAt(ext);
 }
 
 /* [noscript] DOMString mozGetUnderlyingParamString(in WebGLenum pname); */
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -973,17 +973,16 @@ protected:
                       WebGLTexelFormat srcFormat, bool srcPremultiplied,
                       WebGLTexelFormat dstFormat, bool dstPremultiplied,
                       size_t dstTexelSize);
 
     template<class ElementType>
     nsLayoutUtils::SurfaceFromElementResult SurfaceFromElement(ElementType* aElement) {
         MOZ_ASSERT(aElement);
         uint32_t flags =
-            nsLayoutUtils::SFE_WANT_NEW_SURFACE |
             nsLayoutUtils::SFE_WANT_IMAGE_SURFACE;
 
         if (mPixelStoreColorspaceConversion == LOCAL_GL_NONE)
             flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
         if (!mPixelStorePremultiplyAlpha)
             flags |= nsLayoutUtils::SFE_NO_PREMULTIPLY_ALPHA;
         return nsLayoutUtils::SurfaceFromElement(aElement, flags);
     }
--- a/content/canvas/test/Makefile.in
+++ b/content/canvas/test/Makefile.in
@@ -8,16 +8,17 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = @relativesrcdir@
 DIRS		+= webgl crossorigin chrome
 
 include $(DEPTH)/config/autoconf.mk
 MOCHITEST_FILES = \
 	test_canvas.html \
+	test_isPointInStroke.html \
 	image_transparent50.png \
 	image_redtransparent.png \
 	image_yellow.png \
 	image_anim-poster-gr.png \
 	image_green-16x16.png \
 	image_red-16x16.png \
 	image_green-1x1.png \
 	image_ggrr-256x256.png \
@@ -93,17 +94,16 @@ MOCHITEST_FILES = \
 	test_2d.composite.uncovered.fill.luminosity.html \
 	test_2d.drawImage.zerocanvas.html \
 	test_2d.strokeRect.zero.5.html \
 	test_toBlob.html \
 	test_toDataURL_alpha.html \
 	test_toDataURL_lowercase_ascii.html \
 	test_toDataURL_parameters.html \
 	test_mozGetAsFile.html \
-	test_mozIsPointInStroke.html \
 	test_canvas_strokeStyle_getter.html \
 	test_bug613794.html \
 	test_bug753758.html \
 	test_bug764125.html \
 	test_drawImage_edge_cases.html \
 	test_drawImage_document_domain.html \
   test_mozDashOffset.html \
 	file_drawImage_document_domain.html \
--- a/content/canvas/test/reftest/reftest.list
+++ b/content/canvas/test/reftest/reftest.list
@@ -1,188 +1,188 @@
-# WebGL Reftests!
-# If you add new tests, don't forget to add sanity (&nogl) tests! (if needed)
-
-# Check that disabling works:
-                           == webgl-disable-test.html?nogl  wrapper.html?green.png
-pref(webgl.disabled,true)  == webgl-disable-test.html       wrapper.html?green.png
-
-# Basic WebGL tests:
-# Do we get pixels to the screen at all?
-# Try to just hit the different rendering paths here.
-# Test: {aa, alpha, preserve, readback} = 16
-== webgl-clear-test.html?nogl  wrapper.html?green.png
-
-== webgl-clear-test.html?__&_____&________  wrapper.html?green.png
-== webgl-clear-test.html?aa&_____&________  wrapper.html?green.png
-== webgl-clear-test.html?__&alpha&________  wrapper.html?green.png
-== webgl-clear-test.html?aa&alpha&________  wrapper.html?green.png
-== webgl-clear-test.html?__&_____&preserve  wrapper.html?green.png
-== webgl-clear-test.html?aa&_____&preserve  wrapper.html?green.png
-== webgl-clear-test.html?__&alpha&preserve  wrapper.html?green.png
-== webgl-clear-test.html?aa&alpha&preserve  wrapper.html?green.png
-
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&__&_____&________  wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&aa&_____&________  wrapper.html?green.png
-pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&__&alpha&________  wrapper.html?green.png
-pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&aa&alpha&________  wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&__&_____&preserve  wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&aa&_____&preserve  wrapper.html?green.png
-pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&__&alpha&preserve  wrapper.html?green.png
-pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&aa&alpha&preserve  wrapper.html?green.png
-
-# Check orientation:
-== webgl-orientation-test.html?nogl  wrapper.html?white-top-left.png
-
-== webgl-orientation-test.html?__&_____&________  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?aa&_____&________  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?__&alpha&________  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?aa&alpha&________  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?__&_____&preserve  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?aa&_____&preserve  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?__&alpha&preserve  wrapper.html?white-top-left.png
-== webgl-orientation-test.html?aa&alpha&preserve  wrapper.html?white-top-left.png
-
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&__&_____&________  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&aa&_____&________  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&__&alpha&________  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&aa&alpha&________  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&__&_____&preserve  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&aa&_____&preserve  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&__&alpha&preserve  wrapper.html?white-top-left.png
-pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&aa&alpha&preserve  wrapper.html?white-top-left.png
-
-# Does we draw the correct color in the correct places with all context creation options?
-# (Note that our context creation option matrix is 2^6 = 64)
-== webgl-color-test.html?nogl  wrapper.html?colors.png
-
-== webgl-color-test.html?__&_____&_____&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&_______&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&_____&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&premult&________&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&premult&________&_______  wrapper.html?colors.png
-
-== webgl-color-test.html?__&_____&_____&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&_______&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&_____&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&premult&preserve&_______  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&premult&preserve&_______  wrapper.html?colors.png
-
-== webgl-color-test.html?__&_____&_____&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&_______&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&_____&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&premult&________&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&premult&________&stencil  wrapper.html?colors.png
-
-== webgl-color-test.html?__&_____&_____&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&_______&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&_____&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&_____&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&_____&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&_____&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&_____&depth&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&_____&depth&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?__&alpha&depth&premult&preserve&stencil  wrapper.html?colors.png
-== webgl-color-test.html?aa&alpha&depth&premult&preserve&stencil  wrapper.html?colors.png
-
-
-# Check a smaller selection for readback:
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&__&_____&________  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&aa&_____&________  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&__&alpha&________  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&aa&alpha&________  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&__&_____&preserve  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&aa&_____&preserve  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&__&alpha&preserve  wrapper.html?colors.png
-pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&aa&alpha&preserve  wrapper.html?colors.png
-
-
-# Check alpha behavior:
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0&nogl        wrapper.html?colors.png
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0             wrapper.html?colors.png
-== webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0&nogl        wrapper.html?black.png
-== webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0             wrapper.html?black.png
-
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&nogl        wrapper.html?colors.png
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0             wrapper.html?colors.png
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha&nogl  wrapper.html?white.png
-== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha       wrapper.html?white.png
-
-fuzzy(1,65536) fuzzy-if(Android,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0&nogl  wrapper.html?half-colors.png
-fuzzy(1,65536) fuzzy-if(Android,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0       wrapper.html?half-colors.png
-
-# Test premult:
-fuzzy(1,65536) fuzzy-if(Android,9,65536)                                == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&nogl          wrapper.html?colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android,9,65536)                                == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha               wrapper.html?colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android,9,65536)                                == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&nogl          wrapper.html?half-colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android,9,65536) fails-if(cocoaWidget||Android) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha               wrapper.html?half-colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android,9,65536)                                == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult&nogl  wrapper.html?colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android,9,65536)                                == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult       wrapper.html?colors-half-alpha.png
-
-# Test over-bright premult:
-fuzzy(1,65536) fuzzy-if(Android,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult&nogl  wrapper.html?colors-half-alpha.png
-fuzzy(1,65536) fuzzy-if(Android,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult       wrapper.html?colors-half-alpha.png
-
-
-# Check for hanging framebuffer bindings:
-== webgl-hanging-fb-test.html?nogl  wrapper.html?green.png
-
-== webgl-hanging-fb-test.html       wrapper.html?green.png
-== webgl-hanging-fb-test.html?aa    wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-fb-test.html?readback     wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-fb-test.html?readback&aa  wrapper.html?green.png
-
-== webgl-hanging-scissor-test.html       wrapper.html?green.png
-== webgl-hanging-scissor-test.html?aa    wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-scissor-test.html?readback     wrapper.html?green.png
-pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-scissor-test.html?readback&aa  wrapper.html?green.png
-
-
-# Check that our experimental prefs still work:
-
-# 16bpp:
-pref(webgl.prefer-16bpp,true)                                                               == webgl-color-test.html?16bpp           wrapper.html?colors.png
-pref(webgl.prefer-16bpp,true) pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-color-test.html?16bpp&readback  wrapper.html?colors.png
-
-# Force native GL (Windows):
-skip-if(!winWidget) pref(webgl.prefer-native-gl,true)                                == webgl-clear-test.html?native-gl        wrapper.html?green.png
-skip-if(!winWidget) pref(webgl.prefer-native-gl,true)                                == webgl-orientation-test.html?native-gl  wrapper.html?white-top-left.png
-skip-if(!winWidget) pref(webgl.prefer-native-gl,true)                                == webgl-color-test.html?native-gl        wrapper.html?colors.png
-skip-if(!winWidget) pref(webgl.prefer-native-gl,true) pref(webgl.prefer-16bpp,true)  == webgl-color-test.html?native-gl&16bpp  wrapper.html?colors.png
+# WebGL Reftests!
+# If you add new tests, don't forget to add sanity (&nogl) tests! (if needed)
+
+# Check that disabling works:
+                           == webgl-disable-test.html?nogl  wrapper.html?green.png
+pref(webgl.disabled,true)  == webgl-disable-test.html       wrapper.html?green.png
+
+# Basic WebGL tests:
+# Do we get pixels to the screen at all?
+# Try to just hit the different rendering paths here.
+# Test: {aa, alpha, preserve, readback} = 16
+== webgl-clear-test.html?nogl  wrapper.html?green.png
+
+== webgl-clear-test.html?__&_____&________  wrapper.html?green.png
+== webgl-clear-test.html?aa&_____&________  wrapper.html?green.png
+== webgl-clear-test.html?__&alpha&________  wrapper.html?green.png
+== webgl-clear-test.html?aa&alpha&________  wrapper.html?green.png
+== webgl-clear-test.html?__&_____&preserve  wrapper.html?green.png
+== webgl-clear-test.html?aa&_____&preserve  wrapper.html?green.png
+== webgl-clear-test.html?__&alpha&preserve  wrapper.html?green.png
+== webgl-clear-test.html?aa&alpha&preserve  wrapper.html?green.png
+
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&__&_____&________  wrapper.html?green.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&aa&_____&________  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&__&alpha&________  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&aa&alpha&________  wrapper.html?green.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&__&_____&preserve  wrapper.html?green.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-clear-test.html?readback&aa&_____&preserve  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&__&alpha&preserve  wrapper.html?green.png
+pref(webgl.force-layers-readback,true)                         == webgl-clear-test.html?readback&aa&alpha&preserve  wrapper.html?green.png
+
+# Check orientation:
+== webgl-orientation-test.html?nogl  wrapper.html?white-top-left.png
+
+== webgl-orientation-test.html?__&_____&________  wrapper.html?white-top-left.png
+== webgl-orientation-test.html?aa&_____&________  wrapper.html?white-top-left.png
+== webgl-orientation-test.html?__&alpha&________  wrapper.html?white-top-left.png
+== webgl-orientation-test.html?aa&alpha&________  wrapper.html?white-top-left.png
+== webgl-orientation-test.html?__&_____&preserve  wrapper.html?white-top-left.png
+== webgl-orientation-test.html?aa&_____&preserve  wrapper.html?white-top-left.png
+== webgl-orientation-test.html?__&alpha&preserve  wrapper.html?white-top-left.png
+== webgl-orientation-test.html?aa&alpha&preserve  wrapper.html?white-top-left.png
+
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&__&_____&________  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&aa&_____&________  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&__&alpha&________  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&aa&alpha&________  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&__&_____&preserve  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-orientation-test.html?readback&aa&_____&preserve  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&__&alpha&preserve  wrapper.html?white-top-left.png
+pref(webgl.force-layers-readback,true)                         == webgl-orientation-test.html?readback&aa&alpha&preserve  wrapper.html?white-top-left.png
+
+# Does we draw the correct color in the correct places with all context creation options?
+# (Note that our context creation option matrix is 2^6 = 64)
+== webgl-color-test.html?nogl  wrapper.html?colors.png
+
+== webgl-color-test.html?__&_____&_____&_______&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&_____&_______&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&_____&_______&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&_____&_______&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&depth&_______&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&depth&_______&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&depth&_______&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&depth&_______&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&_____&premult&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&_____&premult&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&_____&premult&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&_____&premult&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&depth&premult&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&depth&premult&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&depth&premult&________&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&depth&premult&________&_______  wrapper.html?colors.png
+
+== webgl-color-test.html?__&_____&_____&_______&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&_____&_______&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&_____&_______&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&_____&_______&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&depth&_______&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&depth&_______&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&depth&_______&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&depth&_______&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&_____&premult&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&_____&premult&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&_____&premult&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&_____&premult&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&depth&premult&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&depth&premult&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&depth&premult&preserve&_______  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&depth&premult&preserve&_______  wrapper.html?colors.png
+
+== webgl-color-test.html?__&_____&_____&_______&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&_____&_______&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&_____&_______&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&_____&_______&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&depth&_______&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&depth&_______&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&depth&_______&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&depth&_______&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&_____&premult&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&_____&premult&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&_____&premult&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&_____&premult&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&depth&premult&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&depth&premult&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&depth&premult&________&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&depth&premult&________&stencil  wrapper.html?colors.png
+
+== webgl-color-test.html?__&_____&_____&_______&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&_____&_______&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&_____&_______&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&_____&_______&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&depth&_______&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&depth&_______&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&depth&_______&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&depth&_______&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&_____&premult&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&_____&premult&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&_____&premult&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&_____&premult&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&_____&depth&premult&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&_____&depth&premult&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?__&alpha&depth&premult&preserve&stencil  wrapper.html?colors.png
+== webgl-color-test.html?aa&alpha&depth&premult&preserve&stencil  wrapper.html?colors.png
+
+
+# Check a smaller selection for readback:
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&__&_____&________  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&aa&_____&________  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&__&alpha&________  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&aa&alpha&________  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&__&_____&preserve  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-color-test.html?readback&aa&_____&preserve  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&__&alpha&preserve  wrapper.html?colors.png
+pref(webgl.force-layers-readback,true)                         == webgl-color-test.html?readback&aa&alpha&preserve  wrapper.html?colors.png
+
+
+# Check alpha behavior:
+== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0&nogl        wrapper.html?colors.png
+== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0             wrapper.html?colors.png
+== webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0&nogl        wrapper.html?black.png
+== webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0             wrapper.html?black.png
+
+== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&nogl        wrapper.html?colors.png
+== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0             wrapper.html?colors.png
+== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha&nogl  wrapper.html?white.png
+== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha       wrapper.html?white.png
+
+fuzzy(1,65536) fuzzy-if(Android,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0&nogl  wrapper.html?half-colors.png
+fuzzy(1,65536) fuzzy-if(Android,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0       wrapper.html?half-colors.png
+
+# Test premult:
+fuzzy(1,65536) fuzzy-if(Android,9,65536)                                == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&nogl          wrapper.html?colors-half-alpha.png
+fuzzy(1,65536) fuzzy-if(Android,9,65536)                                == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha               wrapper.html?colors-half-alpha.png
+fuzzy(1,65536) fuzzy-if(Android,9,65536)                                == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&nogl          wrapper.html?half-colors-half-alpha.png
+fuzzy(1,65536) fuzzy-if(Android,9,65536) fails-if(cocoaWidget||Android) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha               wrapper.html?half-colors-half-alpha.png
+fuzzy(1,65536) fuzzy-if(Android,9,65536)                                == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult&nogl  wrapper.html?colors-half-alpha.png
+fuzzy(1,65536) fuzzy-if(Android,9,65536)                                == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult       wrapper.html?colors-half-alpha.png
+
+# Test over-bright premult:
+fuzzy(1,65536) fuzzy-if(Android,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult&nogl  wrapper.html?colors-half-alpha.png
+fuzzy(1,65536) fuzzy-if(Android,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult       wrapper.html?colors-half-alpha.png
+
+
+# Check for hanging framebuffer bindings:
+== webgl-hanging-fb-test.html?nogl  wrapper.html?green.png
+
+== webgl-hanging-fb-test.html       wrapper.html?green.png
+== webgl-hanging-fb-test.html?aa    wrapper.html?green.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-fb-test.html?readback     wrapper.html?green.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-fb-test.html?readback&aa  wrapper.html?green.png
+
+== webgl-hanging-scissor-test.html       wrapper.html?green.png
+== webgl-hanging-scissor-test.html?aa    wrapper.html?green.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-scissor-test.html?readback     wrapper.html?green.png
+pref(webgl.force-layers-readback,true) fails-if(nativeFennec)  == webgl-hanging-scissor-test.html?readback&aa  wrapper.html?green.png
+
+
+# Check that our experimental prefs still work:
+
+# 16bpp:
+pref(webgl.prefer-16bpp,true)                                                               == webgl-color-test.html?16bpp           wrapper.html?colors.png
+pref(webgl.prefer-16bpp,true) pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-color-test.html?16bpp&readback  wrapper.html?colors.png
+
+# Force native GL (Windows):
+skip-if(!winWidget) pref(webgl.prefer-native-gl,true)                                == webgl-clear-test.html?native-gl        wrapper.html?green.png
+skip-if(!winWidget) pref(webgl.prefer-native-gl,true)                                == webgl-orientation-test.html?native-gl  wrapper.html?white-top-left.png
+skip-if(!winWidget) pref(webgl.prefer-native-gl,true)                                == webgl-color-test.html?native-gl        wrapper.html?colors.png
+skip-if(!winWidget) pref(webgl.prefer-native-gl,true) pref(webgl.prefer-16bpp,true)  == webgl-color-test.html?native-gl&16bpp  wrapper.html?colors.png
rename from content/canvas/test/test_mozIsPointInStroke.html
rename to content/canvas/test/test_isPointInStroke.html
--- a/content/canvas/test/test_mozIsPointInStroke.html
+++ b/content/canvas/test/test_isPointInStroke.html
@@ -1,244 +1,244 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
-  <title>Canvas test: mozIsPointInStroke</title>
+  <title>Canvas test: isPointInStroke</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
 <script type="application/javascript">
 
 var canvas = document.getElementById('c');
 var ctx = canvas.getContext('2d');
 
 
 ctx.lineWidth = 5;
 
 
-ok(ctx.mozIsPointInStroke(50, 25) === false, 'ctx.mozIsPointInStroke(50, 25) === false');
+ok(ctx.isPointInStroke(50, 25) === false, 'ctx.isPointInStroke(50, 25) === false');
 
 
 ctx.beginPath();
 ctx.rect(0, 0, 20, 20);
 
-ok(ctx.mozIsPointInStroke(-4, -4) === false, 'ctx.mozIsPointInStroke(-4, -4) === false');
-ok(ctx.mozIsPointInStroke(4, 4) === false, 'ctx.mozIsPointInStroke(4, 4) === false');
-ok(ctx.mozIsPointInStroke(16, 16) === false, 'ctx.mozIsPointInStroke(16, 16) === false');
-ok(ctx.mozIsPointInStroke(24, 24) === false, 'ctx.mozIsPointInStroke(24, 24) === false');
+ok(ctx.isPointInStroke(-4, -4) === false, 'ctx.isPointInStroke(-4, -4) === false');
+ok(ctx.isPointInStroke(4, 4) === false, 'ctx.isPointInStroke(4, 4) === false');
+ok(ctx.isPointInStroke(16, 16) === false, 'ctx.isPointInStroke(16, 16) === false');
+ok(ctx.isPointInStroke(24, 24) === false, 'ctx.isPointInStroke(24, 24) === false');
 
-ok(ctx.mozIsPointInStroke(-2, -2) === true, 'ctx.mozIsPointInStroke(-2, -2) === true');
-ok(ctx.mozIsPointInStroke(2, 2) === true, 'ctx.mozIsPointInStroke(2, 2) === true');
-ok(ctx.mozIsPointInStroke(18, 18) === true, 'ctx.mozIsPointInStroke(18, 18) === true');
-ok(ctx.mozIsPointInStroke(22, 22) === true, 'ctx.mozIsPointInStroke(22, 22) === true');
+ok(ctx.isPointInStroke(-2, -2) === true, 'ctx.isPointInStroke(-2, -2) === true');
+ok(ctx.isPointInStroke(2, 2) === true, 'ctx.isPointInStroke(2, 2) === true');
+ok(ctx.isPointInStroke(18, 18) === true, 'ctx.isPointInStroke(18, 18) === true');
+ok(ctx.isPointInStroke(22, 22) === true, 'ctx.isPointInStroke(22, 22) === true');
 
 
 ctx.beginPath();
 ctx.rect(25, 25, 20, 20);
 
-ok(ctx.mozIsPointInStroke(21, 21) === false, 'ctx.mozIsPointInStroke(21, 21) === false');
-ok(ctx.mozIsPointInStroke(29, 29) === false, 'ctx.mozIsPointInStroke(29, 29) === false');
-ok(ctx.mozIsPointInStroke(42, 42) === false, 'ctx.mozIsPointInStroke(42, 42) === false');
-ok(ctx.mozIsPointInStroke(50, 50) === false, 'ctx.mozIsPointInStroke(50, 50) === false');
+ok(ctx.isPointInStroke(21, 21) === false, 'ctx.isPointInStroke(21, 21) === false');
+ok(ctx.isPointInStroke(29, 29) === false, 'ctx.isPointInStroke(29, 29) === false');
+ok(ctx.isPointInStroke(42, 42) === false, 'ctx.isPointInStroke(42, 42) === false');
+ok(ctx.isPointInStroke(50, 50) === false, 'ctx.isPointInStroke(50, 50) === false');
 
-ok(ctx.mozIsPointInStroke(23, 23) === true, 'ctx.mozIsPointInStroke(23, 23) === true');
-ok(ctx.mozIsPointInStroke(27, 27) === true, 'ctx.mozIsPointInStroke(27, 27) === true');
-ok(ctx.mozIsPointInStroke(43, 43) === true, 'ctx.mozIsPointInStroke(43, 43) === true');
-ok(ctx.mozIsPointInStroke(47, 47) === true, 'ctx.mozIsPointInStroke(47, 47) === true');
+ok(ctx.isPointInStroke(23, 23) === true, 'ctx.isPointInStroke(23, 23) === true');
+ok(ctx.isPointInStroke(27, 27) === true, 'ctx.isPointInStroke(27, 27) === true');
+ok(ctx.isPointInStroke(43, 43) === true, 'ctx.isPointInStroke(43, 43) === true');
+ok(ctx.isPointInStroke(47, 47) === true, 'ctx.isPointInStroke(47, 47) === true');
 
 
 ctx.beginPath();
 ctx.moveTo(25, 25);
 ctx.bezierCurveTo(50, -50, 50, 100, 75, 25);
 
-ok(ctx.mozIsPointInStroke(23, 26) === false, 'ctx.mozIsPointInStroke(23, 26) === false');
-ok(ctx.mozIsPointInStroke(75, 23) === false, 'ctx.mozIsPointInStroke(75, 23) === false');
-ok(ctx.mozIsPointInStroke(37, 8) === false, 'ctx.mozIsPointInStroke(37, 8) === false');
-ok(ctx.mozIsPointInStroke(61, 42) === false, 'ctx.mozIsPointInStroke(61, 42) === false');
+ok(ctx.isPointInStroke(23, 26) === false, 'ctx.isPointInStroke(23, 26) === false');
+ok(ctx.isPointInStroke(75, 23) === false, 'ctx.isPointInStroke(75, 23) === false');
+ok(ctx.isPointInStroke(37, 8) === false, 'ctx.isPointInStroke(37, 8) === false');
+ok(ctx.isPointInStroke(61, 42) === false, 'ctx.isPointInStroke(61, 42) === false');
 
-ok(ctx.mozIsPointInStroke(24, 24) === true, 'ctx.mozIsPointInStroke(24, 24) === true');
-ok(ctx.mozIsPointInStroke(74, 25) === true, 'ctx.mozIsPointInStroke(74, 25) === true');
-ok(ctx.mozIsPointInStroke(37, 2) === true, 'ctx.mozIsPointInStroke(37, 2) === true');
-ok(ctx.mozIsPointInStroke(61, 47) === true, 'ctx.mozIsPointInStroke(61, 47) === true');
+ok(ctx.isPointInStroke(24, 24) === true, 'ctx.isPointInStroke(24, 24) === true');
+ok(ctx.isPointInStroke(74, 25) === true, 'ctx.isPointInStroke(74, 25) === true');
+ok(ctx.isPointInStroke(37, 2) === true, 'ctx.isPointInStroke(37, 2) === true');
+ok(ctx.isPointInStroke(61, 47) === true, 'ctx.isPointInStroke(61, 47) === true');
 
 
 ctx.beginPath();
 ctx.arc(50, 25, 10, 0, Math.PI, false);
 
-ok(ctx.mozIsPointInStroke(39, 23) === false, 'ctx.mozIsPointInStroke(39, 23) === false');
-ok(ctx.mozIsPointInStroke(50, 15) === false, 'ctx.mozIsPointInStroke(50, 15) === false');
-ok(ctx.mozIsPointInStroke(60, 23) === false, 'ctx.mozIsPointInStroke(60, 23) === false');
-ok(ctx.mozIsPointInStroke(50, 25) === false, 'ctx.mozIsPointInStroke(50, 25) === false');
+ok(ctx.isPointInStroke(39, 23) === false, 'ctx.isPointInStroke(39, 23) === false');
+ok(ctx.isPointInStroke(50, 15) === false, 'ctx.isPointInStroke(50, 15) === false');
+ok(ctx.isPointInStroke(60, 23) === false, 'ctx.isPointInStroke(60, 23) === false');
+ok(ctx.isPointInStroke(50, 25) === false, 'ctx.isPointInStroke(50, 25) === false');
 
-ok(ctx.mozIsPointInStroke(39, 26) === true, 'ctx.mozIsPointInStroke(39, 26) === true');
-ok(ctx.mozIsPointInStroke(45, 33) === true, 'ctx.mozIsPointInStroke(45, 33) === true');
-ok(ctx.mozIsPointInStroke(53, 33) === true, 'ctx.mozIsPointInStroke(53, 33) === true');
-ok(ctx.mozIsPointInStroke(59, 26) === true, 'ctx.mozIsPointInStroke(59, 26) === true');
+ok(ctx.isPointInStroke(39, 26) === true, 'ctx.isPointInStroke(39, 26) === true');
+ok(ctx.isPointInStroke(45, 33) === true, 'ctx.isPointInStroke(45, 33) === true');
+ok(ctx.isPointInStroke(53, 33) === true, 'ctx.isPointInStroke(53, 33) === true');
+ok(ctx.isPointInStroke(59, 26) === true, 'ctx.isPointInStroke(59, 26) === true');
 
 
 ctx.beginPath();
 ctx.arc(50, 25, 10, 0, 2 * Math.PI, false);
 
-ok(ctx.mozIsPointInStroke(34, 25) === false, 'ctx.mozIsPointInStroke(34, 25) === false');
-ok(ctx.mozIsPointInStroke(44, 25) === false, 'ctx.mozIsPointInStroke(44, 25) === false');
-ok(ctx.mozIsPointInStroke(49, 30) === false, 'ctx.mozIsPointInStroke(49, 30) === false');
-ok(ctx.mozIsPointInStroke(49, 40) === false, 'ctx.mozIsPointInStroke(49, 40) === false');
+ok(ctx.isPointInStroke(34, 25) === false, 'ctx.isPointInStroke(34, 25) === false');
+ok(ctx.isPointInStroke(44, 25) === false, 'ctx.isPointInStroke(44, 25) === false');
+ok(ctx.isPointInStroke(49, 30) === false, 'ctx.isPointInStroke(49, 30) === false');
+ok(ctx.isPointInStroke(49, 40) === false, 'ctx.isPointInStroke(49, 40) === false');
 
-ok(ctx.mozIsPointInStroke(39, 23) === true, 'ctx.mozIsPointInStroke(39, 23) === true');
-ok(ctx.mozIsPointInStroke(50, 15) === true, 'ctx.mozIsPointInStroke(50, 15) === true');
-ok(ctx.mozIsPointInStroke(60, 23) === true, 'ctx.mozIsPointInStroke(60, 23) === true');
-ok(ctx.mozIsPointInStroke(49, 34) === true, 'ctx.mozIsPointInStroke(49, 34) === true');
+ok(ctx.isPointInStroke(39, 23) === true, 'ctx.isPointInStroke(39, 23) === true');
+ok(ctx.isPointInStroke(50, 15) === true, 'ctx.isPointInStroke(50, 15) === true');
+ok(ctx.isPointInStroke(60, 23) === true, 'ctx.isPointInStroke(60, 23) === true');
+ok(ctx.isPointInStroke(49, 34) === true, 'ctx.isPointInStroke(49, 34) === true');
 
 
 ctx.beginPath();
 ctx.save();
 ctx.translate(20, 20);
 ctx.rect(0, 0, 20, 20);
 
-ok(ctx.mozIsPointInStroke(16, 16) === false, 'ctx.mozIsPointInStroke(16, 16) === false');
-ok(ctx.mozIsPointInStroke(24, 24) === false, 'ctx.mozIsPointInStroke(24, 24) === false');
-ok(ctx.mozIsPointInStroke(36, 36) === false, 'ctx.mozIsPointInStroke(36, 36) === false');
-ok(ctx.mozIsPointInStroke(44, 44) === false, 'ctx.mozIsPointInStroke(44, 44) === false');
+ok(ctx.isPointInStroke(16, 16) === false, 'ctx.isPointInStroke(16, 16) === false');
+ok(ctx.isPointInStroke(24, 24) === false, 'ctx.isPointInStroke(24, 24) === false');
+ok(ctx.isPointInStroke(36, 36) === false, 'ctx.isPointInStroke(36, 36) === false');
+ok(ctx.isPointInStroke(44, 44) === false, 'ctx.isPointInStroke(44, 44) === false');
 
-ok(ctx.mozIsPointInStroke(18, 18) === true, 'ctx.mozIsPointInStroke(18, 18) === true');
-ok(ctx.mozIsPointInStroke(22, 22) === true, 'ctx.mozIsPointInStroke(22, 22) === true');
-ok(ctx.mozIsPointInStroke(38, 38) === true, 'ctx.mozIsPointInStroke(38, 38) === true');
-ok(ctx.mozIsPointInStroke(42, 42) === true, 'ctx.mozIsPointInStroke(42, 42) === true');
+ok(ctx.isPointInStroke(18, 18) === true, 'ctx.isPointInStroke(18, 18) === true');
+ok(ctx.isPointInStroke(22, 22) === true, 'ctx.isPointInStroke(22, 22) === true');
+ok(ctx.isPointInStroke(38, 38) === true, 'ctx.isPointInStroke(38, 38) === true');
+ok(ctx.isPointInStroke(42, 42) === true, 'ctx.isPointInStroke(42, 42) === true');
 
 ctx.restore();
 
 
 ctx.beginPath();
 ctx.save();
 ctx.scale(-1, 1);
 ctx.rect(-30, 20, 20, 20);
 
-ok(ctx.mozIsPointInStroke(16, 16) === false, 'ctx.mozIsPointInStroke(16, 16) === false');
-ok(ctx.mozIsPointInStroke(14, 24) === false, 'ctx.mozIsPointInStroke(14, 24) === false');
-ok(ctx.mozIsPointInStroke(26, 36) === false, 'ctx.mozIsPointInStroke(26, 36) === false');
-ok(ctx.mozIsPointInStroke(34, 44) === false, 'ctx.mozIsPointInStroke(34, 44) === false');
+ok(ctx.isPointInStroke(16, 16) === false, 'ctx.isPointInStroke(16, 16) === false');
+ok(ctx.isPointInStroke(14, 24) === false, 'ctx.isPointInStroke(14, 24) === false');
+ok(ctx.isPointInStroke(26, 36) === false, 'ctx.isPointInStroke(26, 36) === false');
+ok(ctx.isPointInStroke(34, 44) === false, 'ctx.isPointInStroke(34, 44) === false');
 
-ok(ctx.mozIsPointInStroke(8, 18) === true, 'ctx.mozIsPointInStroke(8, 18) === true');
-ok(ctx.mozIsPointInStroke(12, 22) === true, 'ctx.mozIsPointInStroke(12, 22) === true');
-ok(ctx.mozIsPointInStroke(28, 38) === true, 'ctx.mozIsPointInStroke(28, 38) === true');
-ok(ctx.mozIsPointInStroke(32, 42) === true, 'ctx.mozIsPointInStroke(32, 42) === true');
+ok(ctx.isPointInStroke(8, 18) === true, 'ctx.isPointInStroke(8, 18) === true');
+ok(ctx.isPointInStroke(12, 22) === true, 'ctx.isPointInStroke(12, 22) === true');
+ok(ctx.isPointInStroke(28, 38) === true, 'ctx.isPointInStroke(28, 38) === true');
+ok(ctx.isPointInStroke(32, 42) === true, 'ctx.isPointInStroke(32, 42) === true');
 
 ctx.restore();
 
 
 ctx.beginPath();
 ctx.save();
 ctx.lineWidth = 2;
 ctx.translate(50, 25);
 ctx.rotate(180 * Math.PI / 180);
 ctx.scale(5, 5);
 ctx.arc(0, 0, 2, 0, Math.PI, false);
 
-ok(ctx.mozIsPointInStroke(39, 26) === false, 'ctx.mozIsPointInStroke(39, 26) === false');
-ok(ctx.mozIsPointInStroke(45, 33) === false, 'ctx.mozIsPointInStroke(45, 33) === false');
-ok(ctx.mozIsPointInStroke(53, 33) === false, 'ctx.mozIsPointInStroke(53, 33) === false');
-ok(ctx.mozIsPointInStroke(59, 26) === false, 'ctx.mozIsPointInStroke(59, 26) === false');
+ok(ctx.isPointInStroke(39, 26) === false, 'ctx.isPointInStroke(39, 26) === false');
+ok(ctx.isPointInStroke(45, 33) === false, 'ctx.isPointInStroke(45, 33) === false');
+ok(ctx.isPointInStroke(53, 33) === false, 'ctx.isPointInStroke(53, 33) === false');
+ok(ctx.isPointInStroke(59, 26) === false, 'ctx.isPointInStroke(59, 26) === false');
 
-ok(ctx.mozIsPointInStroke(39, 23) === true, 'ctx.mozIsPointInStroke(39, 23) === true');
-ok(ctx.mozIsPointInStroke(45, 15) === true, 'ctx.mozIsPointInStroke(50, 15) === true');
-ok(ctx.mozIsPointInStroke(55, 15) === true, 'ctx.mozIsPointInStroke(50, 25) === true');
-ok(ctx.mozIsPointInStroke(60, 23) === true, 'ctx.mozIsPointInStroke(60, 23) === true');
+ok(ctx.isPointInStroke(39, 23) === true, 'ctx.isPointInStroke(39, 23) === true');
+ok(ctx.isPointInStroke(45, 15) === true, 'ctx.isPointInStroke(50, 15) === true');
+ok(ctx.isPointInStroke(55, 15) === true, 'ctx.isPointInStroke(50, 25) === true');
+ok(ctx.isPointInStroke(60, 23) === true, 'ctx.isPointInStroke(60, 23) === true');
 
 ctx.restore();
 
 
 ctx.beginPath();
 
 ctx.moveTo(10, 10);
 ctx.lineTo(30, 10);
 ctx.save();
 ctx.lineWidth = 2;
 ctx.scale(5, 5);
 ctx.lineTo(6, 6);
 ctx.lineTo(2, 6);
 ctx.restore();
 ctx.closePath();
 
-ok(ctx.mozIsPointInStroke(6, 6) === false, 'ctx.mozIsPointInStroke(6, 6) === false');
-ok(ctx.mozIsPointInStroke(14, 14) === false, 'ctx.mozIsPointInStroke(14, 14) === false');
-ok(ctx.mozIsPointInStroke(26, 26) === false, 'ctx.mozIsPointInStroke(26, 26) === false');
-ok(ctx.mozIsPointInStroke(34, 34) === false, 'ctx.mozIsPointInStroke(34, 34) === false');
+ok(ctx.isPointInStroke(6, 6) === false, 'ctx.isPointInStroke(6, 6) === false');
+ok(ctx.isPointInStroke(14, 14) === false, 'ctx.isPointInStroke(14, 14) === false');
+ok(ctx.isPointInStroke(26, 26) === false, 'ctx.isPointInStroke(26, 26) === false');
+ok(ctx.isPointInStroke(34, 34) === false, 'ctx.isPointInStroke(34, 34) === false');
 
-ok(ctx.mozIsPointInStroke(8, 8) === true, 'ctx.mozIsPointInStroke(8, 8) === true');
-ok(ctx.mozIsPointInStroke(12, 12) === true, 'ctx.mozIsPointInStroke(12, 12) === true');
-ok(ctx.mozIsPointInStroke(28, 28) === true, 'ctx.mozIsPointInStroke(28, 28) === true');
-ok(ctx.mozIsPointInStroke(32, 32) === true, 'ctx.mozIsPointInStroke(32, 32) === true');
+ok(ctx.isPointInStroke(8, 8) === true, 'ctx.isPointInStroke(8, 8) === true');
+ok(ctx.isPointInStroke(12, 12) === true, 'ctx.isPointInStroke(12, 12) === true');
+ok(ctx.isPointInStroke(28, 28) === true, 'ctx.isPointInStroke(28, 28) === true');
+ok(ctx.isPointInStroke(32, 32) === true, 'ctx.isPointInStroke(32, 32) === true');
 
 
 ctx.beginPath();
 ctx.rect(-30, -30, 20, 20);
 
-ok(ctx.mozIsPointInStroke(-34, -34) === false, 'ctx.mozIsPointInStroke(-34, -34) === false');
-ok(ctx.mozIsPointInStroke(-26, -26) === false, 'ctx.mozIsPointInStroke(-26, -26) === false');
-ok(ctx.mozIsPointInStroke(-14, -14) === false, 'ctx.mozIsPointInStroke(-14, -14) === false');
-ok(ctx.mozIsPointInStroke(-6, -6) === false, 'ctx.mozIsPointInStroke(-6, -6) === false');
+ok(ctx.isPointInStroke(-34, -34) === false, 'ctx.isPointInStroke(-34, -34) === false');
+ok(ctx.isPointInStroke(-26, -26) === false, 'ctx.isPointInStroke(-26, -26) === false');
+ok(ctx.isPointInStroke(-14, -14) === false, 'ctx.isPointInStroke(-14, -14) === false');
+ok(ctx.isPointInStroke(-6, -6) === false, 'ctx.isPointInStroke(-6, -6) === false');
 
-ok(ctx.mozIsPointInStroke(-32, -32) === true, 'ctx.mozIsPointInStroke(-32, -32) === true');
-ok(ctx.mozIsPointInStroke(-28, -28) === true, 'ctx.mozIsPointInStroke(-28, -28) === true');
-ok(ctx.mozIsPointInStroke(-12, -12) === true, 'ctx.mozIsPointInStroke(-12, -12) === true');
-ok(ctx.mozIsPointInStroke(-8, -8) === true, 'ctx.mozIsPointInStroke(-8, -8) === true');
+ok(ctx.isPointInStroke(-32, -32) === true, 'ctx.isPointInStroke(-32, -32) === true');
+ok(ctx.isPointInStroke(-28, -28) === true, 'ctx.isPointInStroke(-28, -28) === true');
+ok(ctx.isPointInStroke(-12, -12) === true, 'ctx.isPointInStroke(-12, -12) === true');
+ok(ctx.isPointInStroke(-8, -8) === true, 'ctx.isPointInStroke(-8, -8) === true');
 
 
 ctx.beginPath();
 ctx.moveTo(20, 25);
 ctx.lineTo(80, 25);
 
-ok(ctx.mozIsPointInStroke(19, 25) === false, 'ctx.mozIsPointInStroke(19, 25) === false');
-ok(ctx.mozIsPointInStroke(50, 21) === false, 'ctx.mozIsPointInStroke(50, 21) === false');
-ok(ctx.mozIsPointInStroke(81, 25) === false, 'ctx.mozIsPointInStroke(81, 25) === false');
-ok(ctx.mozIsPointInStroke(50, 29) === false, 'ctx.mozIsPointInStroke(50, 29) === false');
+ok(ctx.isPointInStroke(19, 25) === false, 'ctx.isPointInStroke(19, 25) === false');
+ok(ctx.isPointInStroke(50, 21) === false, 'ctx.isPointInStroke(50, 21) === false');
+ok(ctx.isPointInStroke(81, 25) === false, 'ctx.isPointInStroke(81, 25) === false');
+ok(ctx.isPointInStroke(50, 29) === false, 'ctx.isPointInStroke(50, 29) === false');
 
-ok(ctx.mozIsPointInStroke(21, 25) === true, 'ctx.mozIsPointInStroke(21, 25) === true');
-ok(ctx.mozIsPointInStroke(50, 23) === true, 'ctx.mozIsPointInStroke(50, 23) === true');
-ok(ctx.mozIsPointInStroke(79, 25) === true, 'ctx.mozIsPointInStroke(79, 25) === true');
-ok(ctx.mozIsPointInStroke(50, 27) === true, 'ctx.mozIsPointInStroke(50, 27) === true');
+ok(ctx.isPointInStroke(21, 25) === true, 'ctx.isPointInStroke(21, 25) === true');
+ok(ctx.isPointInStroke(50, 23) === true, 'ctx.isPointInStroke(50, 23) === true');
+ok(ctx.isPointInStroke(79, 25) === true, 'ctx.isPointInStroke(79, 25) === true');
+ok(ctx.isPointInStroke(50, 27) === true, 'ctx.isPointInStroke(50, 27) === true');
 
 
 ctx.lineWidth = 15;
 ctx.lineCap = 'round';
 
 
 ctx.beginPath();
 ctx.moveTo(20, 25);
 ctx.lineTo(80, 25);
 
-ok(ctx.mozIsPointInStroke(13, 18) === false, 'ctx.mozIsPointInStroke(13, 18) === false');
-ok(ctx.mozIsPointInStroke(13, 31) === false, 'ctx.mozIsPointInStroke(13, 31) === false');
-ok(ctx.mozIsPointInStroke(86, 18) === false, 'ctx.mozIsPointInStroke(86, 18) === false');
-ok(ctx.mozIsPointInStroke(86, 31) === false, 'ctx.mozIsPointInStroke(86, 31) === false');
+ok(ctx.isPointInStroke(13, 18) === false, 'ctx.isPointInStroke(13, 18) === false');
+ok(ctx.isPointInStroke(13, 31) === false, 'ctx.isPointInStroke(13, 31) === false');
+ok(ctx.isPointInStroke(86, 18) === false, 'ctx.isPointInStroke(86, 18) === false');
+ok(ctx.isPointInStroke(86, 31) === false, 'ctx.isPointInStroke(86, 31) === false');
 
-ok(ctx.mozIsPointInStroke(13, 25) === true, 'ctx.mozIsPointInStroke(13, 25) === true');
-ok(ctx.mozIsPointInStroke(50, 18) === true, 'ctx.mozIsPointInStroke(50, 18) === true');
-ok(ctx.mozIsPointInStroke(86, 25) === true, 'ctx.mozIsPointInStroke(86, 25) === true');
-ok(ctx.mozIsPointInStroke(50, 31) === true, 'ctx.mozIsPointInStroke(50, 31) === true');
+ok(ctx.isPointInStroke(13, 25) === true, 'ctx.isPointInStroke(13, 25) === true');
+ok(ctx.isPointInStroke(50, 18) === true, 'ctx.isPointInStroke(50, 18) === true');
+ok(ctx.isPointInStroke(86, 25) === true, 'ctx.isPointInStroke(86, 25) === true');
+ok(ctx.isPointInStroke(50, 31) === true, 'ctx.isPointInStroke(50, 31) === true');
 
 
 ctx.lineJoin = 'round';
 
 
 ctx.beginPath();
 ctx.moveTo(20, 15);
 ctx.lineTo(80, 15);
 ctx.lineTo(80, 35);
 
-ok(ctx.mozIsPointInStroke(86, 8) === false, 'ctx.mozIsPointInStroke(86, 8) === false');
-ok(ctx.mozIsPointInStroke(70, 24) === false, 'ctx.mozIsPointInStroke(70, 24) === false');
-ok(ctx.mozIsPointInStroke(73, 41) === false, 'ctx.mozIsPointInStroke(73, 41) === false');
-ok(ctx.mozIsPointInStroke(86, 41) === false, 'ctx.mozIsPointInStroke(86, 41) === false');
+ok(ctx.isPointInStroke(86, 8) === false, 'ctx.isPointInStroke(86, 8) === false');
+ok(ctx.isPointInStroke(70, 24) === false, 'ctx.isPointInStroke(70, 24) === false');
+ok(ctx.isPointInStroke(73, 41) === false, 'ctx.isPointInStroke(73, 41) === false');
+ok(ctx.isPointInStroke(86, 41) === false, 'ctx.isPointInStroke(86, 41) === false');
 
-ok(ctx.mozIsPointInStroke(14, 15) === true, 'ctx.mozIsPointInStroke(14, 15) === true');
-ok(ctx.mozIsPointInStroke(81, 15) === true, 'ctx.mozIsPointInStroke(81, 15) === true');
-ok(ctx.mozIsPointInStroke(79, 41) === true, 'ctx.mozIsPointInStroke(79, 41) === true');
-ok(ctx.mozIsPointInStroke(73, 21) === true, 'ctx.mozIsPointInStroke(73, 21) === true');
+ok(ctx.isPointInStroke(14, 15) === true, 'ctx.isPointInStroke(14, 15) === true');
+ok(ctx.isPointInStroke(81, 15) === true, 'ctx.isPointInStroke(81, 15) === true');
+ok(ctx.isPointInStroke(79, 41) === true, 'ctx.isPointInStroke(79, 41) === true');
+ok(ctx.isPointInStroke(73, 21) === true, 'ctx.isPointInStroke(73, 21) === true');
 
 </script>
 </pre>
 </body>
 </html>
 
--- a/content/events/public/nsMutationEvent.h
+++ b/content/events/public/nsMutationEvent.h
@@ -12,17 +12,17 @@
 
 class nsMutationEvent : public nsEvent
 {
 public:
   nsMutationEvent(bool isTrusted, uint32_t msg)
     : nsEvent(isTrusted, msg, NS_MUTATION_EVENT),
       mAttrChange(0)
   {
-    flags |= NS_EVENT_FLAG_CANT_CANCEL;
+    mFlags.mCancelable = false;
   }
 
   nsCOMPtr<nsIDOMNode> mRelatedNode;
   nsCOMPtr<nsIAtom>    mAttrName;
   nsCOMPtr<nsIAtom>    mPrevAttrValue;
   nsCOMPtr<nsIAtom>    mNewAttrValue;
   unsigned short       mAttrChange;
 };
--- a/content/events/src/TextComposition.cpp
+++ b/content/events/src/TextComposition.cpp
@@ -20,18 +20,17 @@ namespace mozilla {
  * TextComposition
  ******************************************************************************/
 
 TextComposition::TextComposition(nsPresContext* aPresContext,
                                  nsINode* aNode,
                                  nsGUIEvent* aEvent) :
   mPresContext(aPresContext), mNode(aNode),
   mNativeContext(aEvent->widget->GetInputContext().mNativeIMEContext),
-  mIsSynthesizedForTests(
-    (aEvent->flags & NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT) != 0)
+  mIsSynthesizedForTests(aEvent->mFlags.mIsSynthesizedForTests)
 {
 }
 
 TextComposition::TextComposition(const TextComposition& aOther)
 {
   mNativeContext = aOther.mNativeContext;
   mPresContext = aOther.mPresContext;
   mNode = aOther.mNode;
--- a/content/events/src/nsAsyncDOMEvent.cpp
+++ b/content/events/src/nsAsyncDOMEvent.cpp
@@ -8,22 +8,21 @@
 #include "nsIDOMEventTarget.h"
 #include "nsContentUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsGUIEvent.h"
 
 nsAsyncDOMEvent::nsAsyncDOMEvent(nsINode *aEventNode, nsEvent &aEvent)
   : mEventNode(aEventNode), mDispatchChromeOnly(false)
 {
-  bool trusted = NS_IS_TRUSTED_EVENT(&aEvent);
   nsEventDispatcher::CreateEvent(nullptr, &aEvent, EmptyString(),
                                  getter_AddRefs(mEvent));
   NS_ASSERTION(mEvent, "Should never fail to create an event");
   mEvent->DuplicatePrivateData();
-  mEvent->SetTrusted(trusted);
+  mEvent->SetTrusted(aEvent.mFlags.mIsTrusted);
 }
 
 NS_IMETHODIMP nsAsyncDOMEvent::Run()
 {
   if (!mEventNode) {
     return NS_OK;
   }
 
--- a/content/events/src/nsDOMCompositionEvent.cpp
+++ b/content/events/src/nsDOMCompositionEvent.cpp
@@ -19,17 +19,17 @@ nsDOMCompositionEvent::nsDOMCompositionE
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
 
     // XXX compositionstart is cancelable in draft of DOM3 Events.
     //     However, it doesn't make sence for us, we cannot cancel composition
     //     when we sends compositionstart event.
-    mEvent->flags |= NS_EVENT_FLAG_CANT_CANCEL;
+    mEvent->mFlags.mCancelable = false;
   }
 
   mData = static_cast<nsCompositionEvent*>(mEvent)->data;
   // TODO: Native event should have locale information.
 }
 
 nsDOMCompositionEvent::~nsDOMCompositionEvent()
 {
--- a/content/events/src/nsDOMDataContainerEvent.cpp
+++ b/content/events/src/nsDOMDataContainerEvent.cpp
@@ -48,17 +48,17 @@ nsDOMDataContainerEvent::GetData(const n
 }
 
 NS_IMETHODIMP
 nsDOMDataContainerEvent::SetData(const nsAString& aKey, nsIVariant *aData)
 {
   NS_ENSURE_ARG(aData);
 
   // Make sure this event isn't already being dispatched.
-  NS_ENSURE_STATE(!(NS_IS_EVENT_IN_DISPATCH(mEvent)));
+  NS_ENSURE_STATE(!mEvent->mFlags.mIsBeingDispatched);
   NS_ENSURE_STATE(mData.IsInitialized());
   mData.Put(aKey, aData);
   return NS_OK;
 }
 
 nsresult
 NS_NewDOMDataContainerEvent(nsIDOMEvent** aInstancePtrResult,
                    nsPresContext* aPresContext,
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -262,22 +262,17 @@ nsDOMEvent::GetOriginalTarget(nsIDOMEven
   }
 
   return GetTarget(aOriginalTarget);
 }
 
 NS_IMETHODIMP
 nsDOMEvent::SetTrusted(bool aTrusted)
 {
-  if (aTrusted) {
-    mEvent->flags |= NS_EVENT_FLAG_TRUSTED;
-  } else {
-    mEvent->flags &= ~NS_EVENT_FLAG_TRUSTED;
-  }
-
+  mEvent->mFlags.mIsTrusted = aTrusted;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
                        uint32_t aArgc, jsval* aArgv)
 {
   NS_ENSURE_TRUE(aArgc >= 1, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
@@ -325,62 +320,61 @@ nsDOMEvent::InitFromCtor(const nsAString
 
 NS_IMETHODIMP
 nsDOMEvent::GetEventPhase(uint16_t* aEventPhase)
 {
   // Note, remember to check that this works also
   // if or when Bug 235441 is fixed.
   if ((mEvent->currentTarget &&
        mEvent->currentTarget == mEvent->target) ||
-      ((mEvent->flags & NS_EVENT_FLAG_CAPTURE) &&
-       (mEvent->flags & NS_EVENT_FLAG_BUBBLE))) {
+       mEvent->mFlags.InTargetPhase()) {
     *aEventPhase = nsIDOMEvent::AT_TARGET;
-  } else if (mEvent->flags & NS_EVENT_FLAG_CAPTURE) {
+  } else if (mEvent->mFlags.mInCapturePhase) {
     *aEventPhase = nsIDOMEvent::CAPTURING_PHASE;
-  } else if (mEvent->flags & NS_EVENT_FLAG_BUBBLE) {
+  } else if (mEvent->mFlags.mInBubblingPhase) {
     *aEventPhase = nsIDOMEvent::BUBBLING_PHASE;
   } else {
     *aEventPhase = nsIDOMEvent::NONE;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::GetBubbles(bool* aBubbles)
 {
-  *aBubbles = !(mEvent->flags & NS_EVENT_FLAG_CANT_BUBBLE);
+  *aBubbles = mEvent->mFlags.mBubbles;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::GetCancelable(bool* aCancelable)
 {
-  *aCancelable = !(mEvent->flags & NS_EVENT_FLAG_CANT_CANCEL);
+  *aCancelable = mEvent->mFlags.mCancelable;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::GetTimeStamp(uint64_t* aTimeStamp)
 {
   *aTimeStamp = mEvent->time;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::StopPropagation()
 {
-  mEvent->flags |= NS_EVENT_FLAG_STOP_DISPATCH;
+  mEvent->mFlags.mPropagationStopped = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::StopImmediatePropagation()
 {
-  mEvent->flags |=
-    (NS_EVENT_FLAG_STOP_DISPATCH_IMMEDIATELY | NS_EVENT_FLAG_STOP_DISPATCH);
+  mEvent->mFlags.mPropagationStopped = true;
+  mEvent->mFlags.mImmediatePropagationStopped = true;
   return NS_OK;
 }
 
 static nsIDocument* GetDocumentForReport(nsEvent* aEvent)
 {
   nsIDOMEventTarget* target = aEvent->currentTarget;
   if (nsCOMPtr<nsINode> node = do_QueryInterface(target)) {
     return node->OwnerDoc();
@@ -421,39 +415,37 @@ nsDOMEvent::PreventCapture()
 {
   ReportUseOfDeprecatedMethod(mEvent, this, "UseOfPreventCaptureWarning");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::GetIsTrusted(bool *aIsTrusted)
 {
-  *aIsTrusted = NS_IS_TRUSTED_EVENT(mEvent);
-
+  *aIsTrusted = mEvent->mFlags.mIsTrusted;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::PreventDefault()
 {
-  if (!(mEvent->flags & NS_EVENT_FLAG_CANT_CANCEL)) {
-    mEvent->flags |= NS_EVENT_FLAG_NO_DEFAULT;
+  if (mEvent->mFlags.mCancelable) {
+    mEvent->mFlags.mDefaultPrevented = true;
 
     // Need to set an extra flag for drag events.
-    if (mEvent->eventStructType == NS_DRAG_EVENT &&
-        NS_IS_TRUSTED_EVENT(mEvent)) {
+    if (mEvent->eventStructType == NS_DRAG_EVENT && mEvent->mFlags.mIsTrusted) {
       nsCOMPtr<nsINode> node = do_QueryInterface(mEvent->currentTarget);
       if (!node) {
         nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mEvent->currentTarget);
         if (win) {
           node = do_QueryInterface(win->GetExtantDocument());
         }
       }
       if (node && !nsContentUtils::IsChromeDoc(node->OwnerDoc())) {
-        mEvent->flags |= NS_EVENT_FLAG_NO_DEFAULT_CALLED_IN_CONTENT;
+        mEvent->mFlags.mDefaultPreventedByContent = true;
       }
     }
   }
 
   return NS_OK;
 }
 
 void
@@ -463,38 +455,29 @@ nsDOMEvent::SetEventType(const nsAString
     nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType,
                                       &(mEvent->message));
 }
 
 NS_IMETHODIMP
 nsDOMEvent::InitEvent(const nsAString& aEventTypeArg, bool aCanBubbleArg, bool aCancelableArg)
 {
   // Make sure this event isn't already being dispatched.
-  NS_ENSURE_TRUE(!NS_IS_EVENT_IN_DISPATCH(mEvent), NS_OK);
+  NS_ENSURE_TRUE(!mEvent->mFlags.mIsBeingDispatched, NS_OK);
 
-  if (NS_IS_TRUSTED_EVENT(mEvent)) {
+  if (mEvent->mFlags.mIsTrusted) {
     // Ensure the caller is permitted to dispatch trusted DOM events.
     if (!nsContentUtils::IsCallerChrome()) {
       SetTrusted(false);
     }
   }
 
   SetEventType(aEventTypeArg);
 
-  if (aCanBubbleArg) {
-    mEvent->flags &= ~NS_EVENT_FLAG_CANT_BUBBLE;
-  } else {
-    mEvent->flags |= NS_EVENT_FLAG_CANT_BUBBLE;
-  }
-
-  if (aCancelableArg) {
-    mEvent->flags &= ~NS_EVENT_FLAG_CANT_CANCEL;
-  } else {
-    mEvent->flags |= NS_EVENT_FLAG_CANT_CANCEL;
-  }
+  mEvent->mFlags.mBubbles = aCanBubbleArg;
+  mEvent->mFlags.mCancelable = aCancelableArg;
 
   // Clearing the old targets, so that the event is targeted correctly when
   // re-dispatching it.
   mEvent->target = nullptr;
   mEvent->originalTarget = nullptr;
   mCachedType = aEventTypeArg;
   return NS_OK;
 }
@@ -792,17 +775,17 @@ nsDOMEvent::DuplicatePrivateData()
     nsInputEvent* oldInputEvent = static_cast<nsInputEvent*>(mEvent);
     nsInputEvent* newInputEvent = static_cast<nsInputEvent*>(newEvent);
     newInputEvent->modifiers = oldInputEvent->modifiers;
   }
 
   newEvent->target                 = mEvent->target;
   newEvent->currentTarget          = mEvent->currentTarget;
   newEvent->originalTarget         = mEvent->originalTarget;
-  newEvent->flags                  = mEvent->flags;
+  newEvent->mFlags                 = mEvent->mFlags;
   newEvent->time                   = mEvent->time;
   newEvent->refPoint               = mEvent->refPoint;
   newEvent->userType               = mEvent->userType;
 
   mEvent = newEvent;
   mPresContext = nullptr;
   mEventIsInternal = true;
   mPrivateDataDuplicated = true;
@@ -824,17 +807,17 @@ nsDOMEvent::SetTarget(nsIDOMEventTarget*
 
   mEvent->target = do_QueryInterface(aTarget);
   return NS_OK;
 }
 
 NS_IMETHODIMP_(bool)
 nsDOMEvent::IsDispatchStopped()
 {
-  return !!(mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH);
+  return mEvent->mFlags.mPropagationStopped;
 }
 
 NS_IMETHODIMP_(nsEvent*)
 nsDOMEvent::GetInternalNSEvent()
 {
   return mEvent;
 }
 
@@ -929,17 +912,17 @@ nsDOMEvent::GetEventPopupControlState(ns
         break;
       case NS_XUL_COMMAND:
         abuse = openControlled;
         break;
       }
     }
     break;
   case NS_KEY_EVENT :
-    if (NS_IS_TRUSTED_EVENT(aEvent)) {
+    if (aEvent->mFlags.mIsTrusted) {
       uint32_t key = static_cast<nsKeyEvent *>(aEvent)->keyCode;
       switch(aEvent->message) {
       case NS_KEY_PRESS :
         // return key on focused button. see note at NS_MOUSE_CLICK.
         if (key == nsIDOMKeyEvent::DOM_VK_RETURN)
           abuse = openAllowed;
         else if (::PopupAllowedForEvent("keypress"))
           abuse = openControlled;
@@ -954,17 +937,17 @@ nsDOMEvent::GetEventPopupControlState(ns
       case NS_KEY_DOWN :
         if (::PopupAllowedForEvent("keydown"))
           abuse = openControlled;
         break;
       }
     }
     break;
   case NS_MOUSE_EVENT :
-    if (NS_IS_TRUSTED_EVENT(aEvent) &&
+    if (aEvent->mFlags.mIsTrusted &&
         static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton) {
       switch(aEvent->message) {
       case NS_MOUSE_BUTTON_UP :
         if (::PopupAllowedForEvent("mouseup"))
           abuse = openControlled;
         break;
       case NS_MOUSE_BUTTON_DOWN :
         if (::PopupAllowedForEvent("mousedown"))
@@ -1154,17 +1137,17 @@ const char* nsDOMEvent::GetEventName(uin
   // this is a problem generally *are* created by nsDOMEvent.)
   return nullptr;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::GetPreventDefault(bool* aReturn)
 {
   NS_ENSURE_ARG_POINTER(aReturn);
-  *aReturn = mEvent && (mEvent->flags & NS_EVENT_FLAG_NO_DEFAULT);
+  *aReturn = mEvent && mEvent->mFlags.mDefaultPrevented;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::GetDefaultPrevented(bool* aReturn)
 {
   return GetPreventDefault(aReturn);
 }
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -287,29 +287,24 @@ nsDOMUIEvent::GetRangeOffset(int32_t* aR
   *aRangeOffset = 0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMUIEvent::GetCancelBubble(bool* aCancelBubble)
 {
   NS_ENSURE_ARG_POINTER(aCancelBubble);
-  *aCancelBubble =
-    (mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH) ? true : false;
+  *aCancelBubble = mEvent->mFlags.mPropagationStopped;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMUIEvent::SetCancelBubble(bool aCancelBubble)
 {
-  if (aCancelBubble) {
-    mEvent->flags |= NS_EVENT_FLAG_STOP_DISPATCH;
-  } else {
-    mEvent->flags &= ~NS_EVENT_FLAG_STOP_DISPATCH;
-  }
+  mEvent->mFlags.mPropagationStopped = aCancelBubble;
   return NS_OK;
 }
 
 nsIntPoint
 nsDOMUIEvent::GetLayerPoint()
 {
   if (!mEvent ||
       (mEvent->eventStructType != NS_MOUSE_EVENT &&
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -137,54 +137,53 @@ public:
 
   /**
    * Dispatches event through the event target chain.
    * Handles capture, target and bubble phases both in default
    * and system event group and calls also PostHandleEvent for each
    * item in the chain.
    */
   nsresult HandleEventTargetChain(nsEventChainPostVisitor& aVisitor,
-                                  uint32_t aFlags,
                                   nsDispatchingCallback* aCallback,
                                   bool aMayHaveNewListenerManagers,
                                   nsCxPusher* aPusher);
 
   /**
    * Resets aVisitor object and calls PreHandleEvent.
    * Copies mItemFlags and mItemData to the current nsEventTargetChainItem.
    */
   nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   /**
    * If the current item in the event target chain has an event listener
    * manager, this method calls nsEventListenerManager::HandleEvent().
    */
-  nsresult HandleEvent(nsEventChainPostVisitor& aVisitor, uint32_t aFlags,
+  nsresult HandleEvent(nsEventChainPostVisitor& aVisitor,
                        bool aMayHaveNewListenerManagers,
                        nsCxPusher* aPusher)
   {
     if (WantsWillHandleEvent()) {
       mTarget->WillHandleEvent(aVisitor);
     }
-    if (aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH) {
+    if (aVisitor.mEvent->mFlags.mPropagationStopped) {
       return NS_OK;
     }
     if (!mManager) {
       if (!MayHaveListenerManager() && !aMayHaveNewListenerManagers) {
         return NS_OK;
       }
       mManager =
         static_cast<nsEventListenerManager*>(mTarget->GetListenerManager(false));
     }
     if (mManager) {
       NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr,
                    "CurrentTarget should be null!");
       mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent,
                             &aVisitor.mDOMEvent,
-                            CurrentTarget(), aFlags,
+                            CurrentTarget(),
                             &aVisitor.mEventStatus,
                             aPusher);
       NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr,
                    "CurrentTarget should be null!");
     }
     return NS_OK;
   }
 
@@ -258,34 +257,35 @@ nsEventTargetChainItem::PostHandleEvent(
   aPusher->Pop();
   aVisitor.mItemFlags = mItemFlags;
   aVisitor.mItemData = mItemData;
   mTarget->PostHandleEvent(aVisitor);
   return NS_OK;
 }
 
 nsresult
-nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor, uint32_t aFlags,
-                                               nsDispatchingCallback* aCallback,
-                                               bool aMayHaveNewListenerManagers,
-                                               nsCxPusher* aPusher)
+nsEventTargetChainItem::HandleEventTargetChain(
+                          nsEventChainPostVisitor& aVisitor,
+                          nsDispatchingCallback* aCallback,
+                          bool aMayHaveNewListenerManagers,
+                          nsCxPusher* aPusher)
 {
   uint32_t createdELMs = nsEventListenerManager::sCreatedCount;
   // Save the target so that it can be restored later.
   nsCOMPtr<nsIDOMEventTarget> firstTarget = aVisitor.mEvent->target;
 
   // Capture
   nsEventTargetChainItem* item = this;
-  aVisitor.mEvent->flags |= NS_EVENT_FLAG_CAPTURE;
-  aVisitor.mEvent->flags &= ~NS_EVENT_FLAG_BUBBLE;
+  aVisitor.mEvent->mFlags.mInCapturePhase = true;
+  aVisitor.mEvent->mFlags.mInBubblingPhase = false;
   while (item->mChild) {
-    if ((!(aVisitor.mEvent->flags & NS_EVENT_FLAG_NO_CONTENT_DISPATCH) ||
+    if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
          item->ForceContentDispatch()) &&
-        !(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) {
-      item->HandleEvent(aVisitor, aFlags & NS_EVENT_CAPTURE_MASK,
+        !aVisitor.mEvent->mFlags.mPropagationStopped) {
+      item->HandleEvent(aVisitor,
                         aMayHaveNewListenerManagers ||
                         createdELMs != nsEventListenerManager::sCreatedCount,
                         aPusher);
     }
 
     if (item->GetNewTarget()) {
       // item is at anonymous boundary. Need to retarget for the child items.
       nsEventTargetChainItem* nextTarget = item->mChild;
@@ -298,87 +298,86 @@ nsEventTargetChainItem::HandleEventTarge
         nextTarget = nextTarget->mChild;
       }
     }
 
     item = item->mChild;
   }
 
   // Target
-  aVisitor.mEvent->flags |= NS_EVENT_FLAG_BUBBLE;
-  if (!(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH) &&
-      (!(aVisitor.mEvent->flags & NS_EVENT_FLAG_NO_CONTENT_DISPATCH) ||
+  aVisitor.mEvent->mFlags.mInBubblingPhase = true;
+  if (!aVisitor.mEvent->mFlags.mPropagationStopped &&
+      (!aVisitor.mEvent->mFlags.mNoContentDispatch ||
        item->ForceContentDispatch())) {
-    // FIXME Should use aFlags & NS_EVENT_BUBBLE_MASK because capture phase
-    //       event listeners should not be fired. But it breaks at least
-    //       <xul:dialog>'s buttons. Bug 235441.
-    item->HandleEvent(aVisitor, aFlags,
+    item->HandleEvent(aVisitor,
                       aMayHaveNewListenerManagers ||
                       createdELMs != nsEventListenerManager::sCreatedCount,
                       aPusher);
   }
-  if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
+  if (aVisitor.mEvent->mFlags.mInSystemGroup) {
     item->PostHandleEvent(aVisitor, aPusher);
   }
 
   // Bubble
-  aVisitor.mEvent->flags &= ~NS_EVENT_FLAG_CAPTURE;
+  aVisitor.mEvent->mFlags.mInCapturePhase = false;
   item = item->mParent;
   while (item) {
     nsIDOMEventTarget* newTarget = item->GetNewTarget();
     if (newTarget) {
       // Item is at anonymous boundary. Need to retarget for the current item
       // and for parent items.
       aVisitor.mEvent->target = newTarget;
     }
 
-    if (!(aVisitor.mEvent->flags & NS_EVENT_FLAG_CANT_BUBBLE) || newTarget) {
-      if ((!(aVisitor.mEvent->flags & NS_EVENT_FLAG_NO_CONTENT_DISPATCH) ||
+    if (aVisitor.mEvent->mFlags.mBubbles || newTarget) {
+      if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
            item->ForceContentDispatch()) &&
-          !(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) {
-        item->HandleEvent(aVisitor, aFlags & NS_EVENT_BUBBLE_MASK,
+          !aVisitor.mEvent->mFlags.mPropagationStopped) {
+        item->HandleEvent(aVisitor,
                           createdELMs != nsEventListenerManager::sCreatedCount,
                           aPusher);
       }
-      if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
+      if (aVisitor.mEvent->mFlags.mInSystemGroup) {
         item->PostHandleEvent(aVisitor, aPusher);
       }
     }
     item = item->mParent;
   }
-  aVisitor.mEvent->flags &= ~NS_EVENT_FLAG_BUBBLE;
+  aVisitor.mEvent->mFlags.mInBubblingPhase = false;
 
-  if (!(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT)) {
+  if (!aVisitor.mEvent->mFlags.mInSystemGroup) {
     // Dispatch to the system event group.  Make sure to clear the
     // STOP_DISPATCH flag since this resets for each event group.
-    aVisitor.mEvent->flags &=
-      ~(NS_EVENT_FLAG_STOP_DISPATCH | NS_EVENT_FLAG_STOP_DISPATCH_IMMEDIATELY);
+    aVisitor.mEvent->mFlags.mPropagationStopped = false;
+    aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
 
     // Setting back the original target of the event.
     aVisitor.mEvent->target = aVisitor.mEvent->originalTarget;
 
     // Special handling if PresShell (or some other caller)
     // used a callback object.
     if (aCallback) {
       aPusher->Pop();
       aCallback->HandleEvent(aVisitor);
     }
 
     // Retarget for system event group (which does the default handling too).
     // Setting back the target which was used also for default event group.
     aVisitor.mEvent->target = firstTarget;
-    HandleEventTargetChain(aVisitor, aFlags | NS_EVENT_FLAG_SYSTEM_EVENT,