Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
authorAndreea Pavel <apavel@mozilla.com>
Sun, 10 Jun 2018 12:51:28 +0300
changeset 422285 7d4819bfa8c3050573e499f87c9ba6d55354d2ae
parent 422284 b7974b9e7221e1bdf06ced38b6a8094465928549 (current diff)
parent 422112 6ecc243768757b4db83d2467e47078e12bc6c17b (diff)
child 422286 eaf6dbd7b716ccf51c291bcb3749b07353bdf854
push id34122
push userebalazs@mozilla.com
push dateMon, 11 Jun 2018 09:37:00 +0000
treeherdermozilla-central@9941eb8c3b29 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.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 mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
testing/raptor/raptor/tests/raptor-firefox-tp6.ini
toolkit/modules/DateTimePickerHelper.jsm
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -100,17 +100,17 @@ XPCOMUtils.defineLazyModuleGetters(this,
   BookmarkJSONUtils: "resource://gre/modules/BookmarkJSONUtils.jsm",
   BrowserErrorReporter: "resource:///modules/BrowserErrorReporter.jsm",
   BrowserUITelemetry: "resource:///modules/BrowserUITelemetry.jsm",
   BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
   BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
   ContentClick: "resource:///modules/ContentClick.jsm",
   ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
   CustomizableUI: "resource:///modules/CustomizableUI.jsm",
-  DateTimePickerHelper: "resource://gre/modules/DateTimePickerHelper.jsm",
+  DateTimePickerParent: "resource://gre/modules/DateTimePickerParent.jsm",
   ExtensionsUI: "resource:///modules/ExtensionsUI.jsm",
   Feeds: "resource:///modules/Feeds.jsm",
   FileSource: "resource://gre/modules/L10nRegistry.jsm",
   FormValidationHandler: "resource:///modules/FormValidationHandler.jsm",
   FxAccounts: "resource://gre/modules/FxAccounts.jsm",
   HybridContentTelemetry: "resource://gre/modules/HybridContentTelemetry.jsm",
   Integration: "resource://gre/modules/Integration.jsm",
   L10nRegistry: "resource://gre/modules/L10nRegistry.jsm",
@@ -1043,17 +1043,17 @@ BrowserGlue.prototype = {
           this._resetProfileNotification("uninstall");
         }
       }
     }
 
     this._checkForOldBuildUpdates();
 
     AutoCompletePopup.init();
-    DateTimePickerHelper.init();
+    DateTimePickerParent.init();
     // Check if Sync is configured
     if (Services.prefs.prefHasUserValue("services.sync.username")) {
       WeaveService.init();
     }
 
     PageThumbs.init();
 
     NewTabUtils.init();
@@ -1107,17 +1107,17 @@ BrowserGlue.prototype = {
     if (Object.prototype.hasOwnProperty.call(this, "pingCentre")) {
       this.pingCentre.uninit();
     }
 
     PageThumbs.uninit();
     NewTabUtils.uninit();
     AboutPrivateBrowsingHandler.uninit();
     AutoCompletePopup.uninit();
-    DateTimePickerHelper.uninit();
+    DateTimePickerParent.uninit();
 
     // Browser errors are only collected on Nightly
     if (AppConstants.NIGHTLY_BUILD && AppConstants.MOZ_DATA_REPORTING) {
       this.browserErrorReporter.uninit();
     }
 
     Normandy.uninit();
 
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -456,17 +456,17 @@ EventListenerManager::ProcessApzAwareEve
   if (!doc) {
     if (nsCOMPtr<DOMEventTargetHelper> helper = do_QueryInterface(mTarget)) {
       if (nsPIDOMWindowInner* window = helper->GetOwner()) {
         doc = window->GetExtantDoc();
       }
     }
   }
 
-  if (doc && nsDisplayListBuilder::LayerEventRegionsEnabled()) {
+  if (doc && gfxPlatform::AsyncPanZoomEnabled()) {
     nsIPresShell* ps = doc->GetShell();
     if (ps) {
       nsIFrame* f = ps->GetRootFrame();
       if (f) {
         f->SchedulePaint();
       }
     }
   }
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -2464,17 +2464,17 @@ APZCTreeManager::GetTargetAPZC(const Scr
                                CompositorHitTestInfo* aOutHitResult,
                                HitTestingTreeNodeAutoLock* aOutScrollbarNode)
 {
   RecursiveMutexAutoLock lock(mTreeLock);
 
   CompositorHitTestInfo hitResult = CompositorHitTestInfo::eInvisibleToHitTest;
   HitTestingTreeNode* scrollbarNode = nullptr;
   RefPtr<AsyncPanZoomController> target;
-  if (gfx::gfxVars::UseWebRender() && gfxPrefs::WebRenderHitTest()) {
+  if (gfx::gfxVars::UseWebRender()) {
     target = GetAPZCAtPointWR(aPoint, &hitResult, &scrollbarNode);
   } else {
     target = GetAPZCAtPoint(mRootNode, aPoint, &hitResult, &scrollbarNode);
   }
 
   if (aOutHitResult) {
     *aOutHitResult = hitResult;
   }
--- a/gfx/layers/apz/test/gtest/APZTestCommon.h
+++ b/gfx/layers/apz/test/gtest/APZTestCommon.h
@@ -11,16 +11,17 @@
  * Defines a set of mock classes and utility functions/classes for
  * writing APZ gtests.
  */
 
 #include "gtest/gtest.h"
 #include "gmock/gmock.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/gfx/gfxVars.h"
 #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/LayerMetricsWrapper.h"
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/TypedEnumBits.h"
 #include "mozilla/UniquePtr.h"
 #include "apz/src/APZCTreeManager.h"
@@ -57,41 +58,47 @@ CreateSingleTouchData(int32_t aIdentifie
 
 // Convenience wrapper for CreateSingleTouchData() that takes loose coordinates.
 SingleTouchData
 CreateSingleTouchData(int32_t aIdentifier, ScreenIntCoord aX, ScreenIntCoord aY)
 {
   return CreateSingleTouchData(aIdentifier, ScreenIntPoint(aX, aY));
 }
 
-template<class T>
-class ScopedGfxPref {
+template<class SetArg, class Storage>
+class ScopedGfxSetting {
 public:
-  ScopedGfxPref(T (*aGetPrefFunc)(void), void (*aSetPrefFunc)(T), T aVal)
+  ScopedGfxSetting(SetArg (*aGetPrefFunc)(void), void (*aSetPrefFunc)(SetArg), SetArg aVal)
     : mSetPrefFunc(aSetPrefFunc)
   {
     mOldVal = aGetPrefFunc();
     aSetPrefFunc(aVal);
   }
 
-  ~ScopedGfxPref() {
+  ~ScopedGfxSetting() {
     mSetPrefFunc(mOldVal);
   }
 
 private:
-  void (*mSetPrefFunc)(T);
-  T mOldVal;
+  void (*mSetPrefFunc)(SetArg);
+  Storage mOldVal;
 };
 
 #define SCOPED_GFX_PREF(prefBase, prefType, prefValue) \
-  ScopedGfxPref<prefType> pref_##prefBase( \
+  ScopedGfxSetting<prefType, prefType> pref_##prefBase( \
     &(gfxPrefs::prefBase), \
     &(gfxPrefs::Set##prefBase), \
     prefValue)
 
+#define SCOPED_GFX_VAR(varBase, varType, varValue) \
+  ScopedGfxSetting<const varType&, varType> var_##varBase( \
+    &(gfxVars::varBase), \
+    &(gfxVars::Set##varBase), \
+    varValue)
+
 static TimeStamp GetStartupTime() {
   static TimeStamp sStartupTime = TimeStamp::Now();
   return sStartupTime;
 }
 
 class MockContentController : public GeckoContentController {
 public:
   MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
--- a/gfx/layers/apz/test/gtest/TestEventRegions.cpp
+++ b/gfx/layers/apz/test/gtest/TestEventRegions.cpp
@@ -156,17 +156,17 @@ protected:
     layers[3]->SetEventRegions(regions);
 
     registration = MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
     manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
   }
 };
 
 TEST_F(APZEventRegionsTester, HitRegionImmediateResponse) {
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   CreateEventRegionsLayerTree1();
 
   TestAsyncPanZoomController* root = ApzcOf(layers[0]);
   TestAsyncPanZoomController* left = ApzcOf(layers[1]);
   TestAsyncPanZoomController* bottom = ApzcOf(layers[2]);
 
   MockFunction<void(std::string checkPointName)> check;
@@ -223,17 +223,17 @@ TEST_F(APZEventRegionsTester, HitRegionA
   // parent layer's hit region. Verify that it comes out of the APZC's
   // content controller, which indicates the input events got routed correctly
   // to the APZC.
   EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, _, rootApzc->GetGuid(), _)).Times(1);
   Tap(manager, ScreenIntPoint(10, 160), TimeDuration::FromMilliseconds(100));
 }
 
 TEST_F(APZEventRegionsTester, Obscuration) {
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   CreateObscuringLayerTree();
   ScopedLayerTreeRegistration registration(manager, LayersId{0}, root, mcc);
 
   manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
 
   TestAsyncPanZoomController* parent = ApzcOf(layers[1]);
   TestAsyncPanZoomController* child = ApzcOf(layers[2]);
--- a/gfx/layers/apz/test/gtest/TestHitTesting.cpp
+++ b/gfx/layers/apz/test/gtest/TestHitTesting.cpp
@@ -99,17 +99,17 @@ protected:
     };
     root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
     SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID);
   }
 };
 
 // A simple hit testing test that doesn't involve any transforms on layers.
 TEST_F(APZHitTestingTester, HitTesting1) {
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   CreateHitTesting1LayerTree();
   ScopedLayerTreeRegistration registration(manager, LayersId{0}, root, mcc);
 
   // No APZC attached so hit testing will return no APZC at (20,20)
   RefPtr<AsyncPanZoomController> hit = GetTargetAPZC(ScreenPoint(20, 20));
   TestAsyncPanZoomController* nullAPZC = nullptr;
   EXPECT_EQ(nullAPZC, hit.get());
@@ -166,17 +166,17 @@ TEST_F(APZHitTestingTester, HitTesting1)
   hit = GetTargetAPZC(ScreenPoint(-1000, 10));
   EXPECT_EQ(nullAPZC, hit.get());
   EXPECT_EQ(ScreenToParentLayerMatrix4x4(), transformToApzc);
   EXPECT_EQ(ParentLayerToScreenMatrix4x4(), transformToGecko);
 }
 
 // A more involved hit testing test that involves css and async transforms.
 TEST_F(APZHitTestingTester, HitTesting2) {
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
   SCOPED_GFX_PREF(APZVelocityBias, float, 0.0); // Velocity bias can cause extra repaint requests
 
   CreateHitTesting2LayerTree();
   ScopedLayerTreeRegistration registration(manager, LayersId{0}, root, mcc);
 
   manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
 
   // At this point, the following holds (all coordinates in screen pixels):
@@ -277,17 +277,17 @@ TEST_F(APZHitTestingTester, HitTesting2)
   EXPECT_EQ(apzcroot, hit.get());
   // transformToApzc doesn't unapply the root's own async transform
   EXPECT_EQ(ParentLayerPoint(25, 25), transformToApzc.TransformPoint(ScreenPoint(25, 25)));
   // transformToGecko unapplies the full async transform of -100 pixels
   EXPECT_EQ(ScreenPoint(25, 25), transformToGecko.TransformPoint(ParentLayerPoint(25, 25)));
 }
 
 TEST_F(APZHitTestingTester, HitTesting3) {
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   const char* layerTreeSyntax = "c(t)";
   // LayerID                     0 1
   nsIntRegion layerVisibleRegions[] = {
       nsIntRegion(IntRect(0,0,200,200)),
       nsIntRegion(IntRect(0,0,50,50))
   };
   Matrix4x4 transforms[] = {
@@ -303,17 +303,17 @@ TEST_F(APZHitTestingTester, HitTesting3)
 
   manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
 
   RefPtr<AsyncPanZoomController> hit = GetTargetAPZC(ScreenPoint(75, 75));
   EXPECT_EQ(ApzcOf(layers[1]), hit.get());
 }
 
 TEST_F(APZHitTestingTester, ComplexMultiLayerTree) {
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   CreateComplexMultiLayerTree();
   ScopedLayerTreeRegistration registration(manager, LayersId{0}, root, mcc);
   manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
 
   /* The layer tree looks like this:
 
                 0
--- a/gfx/layers/apz/test/gtest/TestScrollHandoff.cpp
+++ b/gfx/layers/apz/test/gtest/TestScrollHandoff.cpp
@@ -235,17 +235,17 @@ TEST_F(APZScrollHandoffTester, LayerStru
 }
 
 // Test that putting a second finger down on an APZC while a down-chain APZC
 // is overscrolled doesn't result in being stuck in overscroll.
 TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1073250) {
   // Enable overscrolling.
   SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
   SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   CreateScrollHandoffLayerTree1();
 
   TestAsyncPanZoomController* child = ApzcOf(layers[1]);
 
   // Pan, causing the parent APZC to overscroll.
   Pan(manager, 10, 40, PanOptions::KeepFingerDown);
   EXPECT_FALSE(child->IsOverscrolled());
@@ -274,17 +274,17 @@ TEST_F(APZScrollHandoffTester, StuckInOv
 
 // This is almost exactly like StuckInOverscroll_Bug1073250, except the
 // APZC receiving the input events for the first touch block is the child
 // (and thus not the same APZC that overscrolls, which is the parent).
 TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1231228) {
   // Enable overscrolling.
   SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
   SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   CreateScrollHandoffLayerTree1();
 
   TestAsyncPanZoomController* child = ApzcOf(layers[1]);
 
   // Pan, causing the parent APZC to overscroll.
   Pan(manager, 60, 90, PanOptions::KeepFingerDown);
   EXPECT_FALSE(child->IsOverscrolled());
@@ -342,17 +342,17 @@ TEST_F(APZScrollHandoffTester, StuckInOv
   // Make sure nothing is overscrolled.
   EXPECT_FALSE(child->IsOverscrolled());
   EXPECT_FALSE(rootApzc->IsOverscrolled());
 }
 
 TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1240202b) {
   // Enable overscrolling.
   SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   CreateScrollHandoffLayerTree1();
 
   TestAsyncPanZoomController* child = ApzcOf(layers[1]);
 
   // Pan, causing the parent APZC to overscroll.
   Pan(manager, 60, 90, PanOptions::KeepFingerDown);
   EXPECT_FALSE(child->IsOverscrolled());
@@ -406,17 +406,17 @@ TEST_F(APZScrollHandoffTester, OpposingC
   EXPECT_FALSE(rootApzc->IsOverscrolled());
 }
 
 // Test that flinging in a direction where one component of the fling goes into
 // overscroll but the other doesn't, results in just the one component being
 // handed off to the parent, while the original APZC continues flinging in the
 // other direction.
 TEST_F(APZScrollHandoffTester, PartialFlingHandoff) {
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   CreateScrollHandoffLayerTree1();
 
   // Fling up and to the left. The child APZC has room to scroll up, but not
   // to the left, so the horizontal component of the fling should be handed
   // off to the parent APZC.
   Pan(manager, ScreenIntPoint(90, 90), ScreenIntPoint(55, 55));
 
@@ -494,24 +494,24 @@ TEST_F(APZScrollHandoffTester, Scrollgra
 
   // Check that it is the scrollgrab parent that's in a fling, not the child.
   rootApzc->AssertStateIsFling();
   childApzc->AssertStateIsReset();
 }
 
 TEST_F(APZScrollHandoffTester, ScrollgrabFlingAcceleration1) {
   SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
   CreateScrollgrabLayerTree(true /* make parent scrollable */);
   TestFlingAcceleration();
 }
 
 TEST_F(APZScrollHandoffTester, ScrollgrabFlingAcceleration2) {
   SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
   CreateScrollgrabLayerTree(false /* do not make parent scrollable */);
   TestFlingAcceleration();
 }
 
 TEST_F(APZScrollHandoffTester, ImmediateHandoffDisallowed_Pan) {
   SCOPED_GFX_PREF(APZAllowImmediateHandoff, bool, false);
 
   CreateScrollHandoffLayerTree1();
--- a/gfx/layers/apz/test/gtest/TestSnapping.cpp
+++ b/gfx/layers/apz/test/gtest/TestSnapping.cpp
@@ -10,17 +10,17 @@
 #include "InputUtils.h"
 
 class APZCSnappingTester : public APZCTreeManagerTester
 {
 };
 
 TEST_F(APZCSnappingTester, Bug1265510)
 {
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   const char* layerTreeSyntax = "c(t)";
   nsIntRegion layerVisibleRegion[] = {
     nsIntRegion(IntRect(0, 0, 100, 100)),
     nsIntRegion(IntRect(0, 100, 100, 100))
   };
   root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
   SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 100, 200));
@@ -63,17 +63,17 @@ TEST_F(APZCSnappingTester, Bug1265510)
   // However, the outer frame should also continue to the snap point, otherwise
   // it is demonstrating incorrect behaviour by violating the mandatory snapping.
   outer->AdvanceAnimationsUntilEnd();
   EXPECT_EQ(100.0f, outer->GetCurrentAsyncScrollOffset(AsyncPanZoomController::AsyncTransformConsumer::eForHitTesting).y);
 }
 
 TEST_F(APZCSnappingTester, Snap_After_Pinch)
 {
-  SCOPED_GFX_PREF(WebRenderHitTest, bool, false);
+  SCOPED_GFX_VAR(UseWebRender, bool, false);
 
   const char* layerTreeSyntax = "c";
   nsIntRegion layerVisibleRegion[] = {
     nsIntRegion(IntRect(0, 0, 100, 100)),
   };
   root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
   SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 100, 200));
 
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -236,17 +236,16 @@ struct Grouper
 
 // Returns whether this is an item for which complete invalidation was
 // reliant on LayerTreeInvalidation in the pre-webrender world.
 static bool
 IsContainerLayerItem(nsDisplayItem* aItem)
 {
   switch (aItem->GetType()) {
     case DisplayItemType::TYPE_TRANSFORM:
-    case DisplayItemType::TYPE_LAYER_EVENT_REGIONS:
     case DisplayItemType::TYPE_OPACITY:
     case DisplayItemType::TYPE_FILTER:
     case DisplayItemType::TYPE_BLEND_CONTAINER:
     case DisplayItemType::TYPE_BLEND_MODE:
     case DisplayItemType::TYPE_MASK: {
       return true;
     }
     default: {
@@ -1226,33 +1225,22 @@ WebRenderCommandBuilder::CreateWebRender
     GP("actually entering the grouping code\n");
     DoGroupingForDisplayList(aDisplayList, aWrappingItem, aDisplayListBuilder, aSc, aBuilder, aResources);
     return;
   }
 
   mClipManager.BeginList(aSc);
 
   bool apzEnabled = mManager->AsyncPanZoomEnabled();
-  EventRegions eventRegions;
 
   FlattenedDisplayItemIterator iter(aDisplayListBuilder, aDisplayList);
   while (nsDisplayItem* i = iter.GetNext()) {
     nsDisplayItem* item = i;
     DisplayItemType itemType = item->GetType();
 
-    // If the item is a event regions item, but is empty (has no regions in it)
-    // then we should just throw it out
-    if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
-      nsDisplayLayerEventRegions* eventRegions =
-        static_cast<nsDisplayLayerEventRegions*>(item);
-      if (eventRegions->IsEmpty()) {
-        continue;
-      }
-    }
-
     // Peek ahead to the next item and try merging with it or swapping with it
     // if necessary.
     AutoTArray<nsDisplayItem*, 1> mergedItems;
     mergedItems.AppendElement(item);
     while (nsDisplayItem* peek = iter.PeekNext()) {
       if (!item->CanMerge(peek)) {
         break;
       }
@@ -1281,66 +1269,27 @@ WebRenderCommandBuilder::CreateWebRender
       // display item than previously, so we can't squash the display items
       // into the same "layer".
       const ActiveScrolledRoot* asr = item->GetActiveScrolledRoot();
       if (asr != mLastAsr) {
         mLastAsr = asr;
         forceNewLayerData = true;
       }
 
-      // If we're creating a new layer data then flush whatever event regions
-      // we've collected onto the old layer.
-      if (forceNewLayerData && !eventRegions.IsEmpty()) {
-        // If eventRegions is non-empty then we must have a layer data already,
-        // because we (below) force one if we encounter an event regions item
-        // with an empty layer data list. Additionally, the most recently
-        // created layer data must have been created from an item whose ASR
-        // is the same as the ASR on the event region items that were collapsed
-        // into |eventRegions|. This is because any ASR change causes us to force
-        // a new layer data which flushes the eventRegions.
-        MOZ_ASSERT(!mLayerScrollData.empty());
-        mLayerScrollData.back().AddEventRegions(eventRegions);
-        eventRegions.SetEmpty();
-      }
-
-      // Collapse event region data into |eventRegions|, which will either be
-      // empty, or filled with stuff from previous display items with the same
-      // ASR.
-      if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
-        nsDisplayLayerEventRegions* regionsItem =
-            static_cast<nsDisplayLayerEventRegions*>(item);
-        int32_t auPerDevPixel = item->Frame()->PresContext()->AppUnitsPerDevPixel();
-        EventRegions regions(
-            regionsItem->HitRegion().ScaleToOutsidePixels(1.0f, 1.0f, auPerDevPixel),
-            regionsItem->MaybeHitRegion().ScaleToOutsidePixels(1.0f, 1.0f, auPerDevPixel),
-            regionsItem->DispatchToContentHitRegion().ScaleToOutsidePixels(1.0f, 1.0f, auPerDevPixel),
-            regionsItem->NoActionRegion().ScaleToOutsidePixels(1.0f, 1.0f, auPerDevPixel),
-            regionsItem->HorizontalPanRegion().ScaleToOutsidePixels(1.0f, 1.0f, auPerDevPixel),
-            regionsItem->VerticalPanRegion().ScaleToOutsidePixels(1.0f, 1.0f, auPerDevPixel),
-            /* mDTCRequiresTargetConfirmation = */ false);
-
-        eventRegions.OrWith(regions);
-        if (mLayerScrollData.empty()) {
-          // If we don't have a layer data yet then create one because we will
-          // need it to store this event region information.
-          forceNewLayerData = true;
-        }
-      }
-
       // If we're going to create a new layer data for this item, stash the
       // ASR so that if we recurse into a sublist they will know where to stop
       // walking up their ASR chain when building scroll metadata.
       if (forceNewLayerData) {
         mAsrStack.push_back(asr);
       }
     }
 
     mClipManager.BeginItem(item, aSc);
 
-    if (itemType != DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
+    { // scope restoreDoGrouping
       AutoRestore<bool> restoreDoGrouping(mDoGrouping);
       if (itemType == DisplayItemType::TYPE_SVG_WRAPPER) {
         // Inside an <svg>, all display items that are not LAYER_ACTIVE wrapper
         // display items (like animated transforms / opacity) share the same
         // animated geometry root, so we can combine subsequent items of that
         // type into the same image.
         mDoGrouping = true;
         GP("attempting to enter the grouping code\n");
@@ -1412,41 +1361,20 @@ WebRenderCommandBuilder::CreateWebRender
         } else {
           // This is the "simple" case where we don't need to create two
           // WebRenderLayerScrollData items; we can just create one that also
           // holds the deferred transform matrix, if any.
           mLayerScrollData.emplace_back();
           mLayerScrollData.back().Initialize(mManager->GetScrollData(), item,
               descendants, stopAtAsr, deferred ? Some((*deferred)->GetTransform().GetMatrix()) : Nothing());
         }
-      } else if (mLayerScrollData.size() != layerCountBeforeRecursing &&
-                 !eventRegions.IsEmpty()) {
-        // We are not forcing a new layer for |item|, but we did create some
-        // layers while recursing. In this case, we need to make sure any
-        // event regions that we were carrying end up on the right layer. So we
-        // do an event region "flush" but retroactively; i.e. the event regions
-        // end up on the layer that was mLayerScrollData.back() prior to the
-        // recursion.
-        MOZ_ASSERT(layerCountBeforeRecursing > 0);
-        mLayerScrollData[layerCountBeforeRecursing - 1].AddEventRegions(eventRegions);
-        eventRegions.SetEmpty();
       }
     }
   }
 
-  // If we have any event region info left over we need to flush it before we
-  // return. Again, at this point the layer data list must be non-empty, and
-  // the most recently created layer data will have been created by an item
-  // with matching ASRs.
-  if (!eventRegions.IsEmpty()) {
-    MOZ_ASSERT(apzEnabled);
-    MOZ_ASSERT(!mLayerScrollData.empty());
-    mLayerScrollData.back().AddEventRegions(eventRegions);
-  }
-
   mClipManager.EndList(aSc);
 }
 
 void
 WebRenderCommandBuilder::PushOverrideForASR(const ActiveScrolledRoot* aASR,
                                             const Maybe<wr::WrClipId>& aClipId)
 {
   mClipManager.PushOverrideForASR(aASR, aClipId);
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -512,17 +512,16 @@ private:
 
   DECL_GFX_PREF(Once, "gfx.webrender.all",                     WebRenderAll, bool, false);
   DECL_GFX_PREF(Once, "gfx.webrender.all.qualified",           WebRenderAllQualified, bool, false);
   DECL_GFX_PREF(Once, "gfx.webrender.async-scene-build",       WebRenderAsyncSceneBuild, bool, true);
   DECL_GFX_PREF(Once, "gfx.webrender.enabled",                 WebRenderEnabledDoNotUseDirectly, bool, false);
   DECL_GFX_PREF(Live, "gfx.webrender.blob-images",             WebRenderBlobImages, bool, true);
   DECL_GFX_PREF(Live, "gfx.webrender.blob.invalidation",       WebRenderBlobInvalidation, bool, false);
   DECL_GFX_PREF(Live, "gfx.webrender.highlight-painted-layers",WebRenderHighlightPaintedLayers, bool, false);
-  DECL_GFX_PREF(Live, "gfx.webrender.hit-test",                WebRenderHitTest, bool, true);
 
   // Use vsync events generated by hardware
   DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs",           WorkAroundDriverBugs, bool, true);
 
   DECL_GFX_PREF(Live, "gl.ignore-dx-interop2-blacklist",       IgnoreDXInterop2Blacklist, bool, false);
   DECL_GFX_PREF(Live, "gl.msaa-level",                         MSAALevel, uint32_t, 2);
 #if defined(XP_MACOSX)
   DECL_GFX_PREF(Live, "gl.multithreaded",                      GLMultithreaded, bool, false);
@@ -675,21 +674,18 @@ private:
   DECL_GFX_PREF(Live, "layout.display-list.retain.verify",     LayoutVerifyRetainDisplayList, bool, false);
   DECL_GFX_PREF(Live, "layout.display-list.retain.verify.order", LayoutVerifyRetainDisplayListOrder, bool, false);
   DECL_GFX_PREF(Live, "layout.display-list.rebuild-frame-limit", LayoutRebuildFrameLimit, uint32_t, 500);
   DECL_GFX_PREF(Live, "layout.display-list.dump",              LayoutDumpDisplayList, bool, false);
   DECL_GFX_PREF(Live, "layout.display-list.dump-content",      LayoutDumpDisplayListContent, bool, false);
   DECL_GFX_PREF(Live, "layout.display-list.dump-parent",       LayoutDumpDisplayListParent, bool, false);
   DECL_GFX_PREF(Live, "layout.display-list.show-rebuild-area", LayoutDisplayListShowArea, bool, false);
 
-  DECL_GFX_PREF(Once, "layout.simple-event-region-items",      SimpleEventRegionItems, bool, true);
+  DECL_GFX_PREF(Once, "layout.frame_rate",                     LayoutFrameRate, int32_t, -1);
   DECL_GFX_PREF(Once, "layout.less-event-region-items",        LessEventRegionItems, bool, true);
-
-  DECL_GFX_PREF(Live, "layout.event-regions.enabled",          LayoutEventRegionsEnabledDoNotUseDirectly, bool, false);
-  DECL_GFX_PREF(Once, "layout.frame_rate",                     LayoutFrameRate, int32_t, -1);
   DECL_GFX_PREF(Live, "layout.min-active-layer-size",          LayoutMinActiveLayerSize, int, 64);
   DECL_GFX_PREF(Once, "layout.paint_rects_separately",         LayoutPaintRectsSeparately, bool, true);
 
   // This and code dependent on it should be removed once containerless scrolling looks stable.
   DECL_GFX_PREF(Once, "layout.scroll.root-frame-containers",   LayoutUseContainersForRootFrames, bool, true);
   // This pref is to be set by test code only.
   DECL_GFX_PREF(Live, "layout.scrollbars.always-layerize-track", AlwaysLayerizeScrollbarTrackTestOnly, bool, false);
   DECL_GFX_PREF(Live, "layout.smaller-painted-layers",         LayoutSmallerPaintedLayers, bool, false);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3673,17 +3673,17 @@ nsLayoutUtils::PaintFrame(gfxContext* aR
         }
       }
 
       nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(&builder, id);
 
       builder.SetVisibleRect(visibleRect);
       builder.SetIsBuilding(true);
       builder.SetAncestorHasApzAwareEventHandler(
-          nsDisplayListBuilder::LayerEventRegionsEnabled() &&
+          gfxPlatform::AsyncPanZoomEnabled() &&
           nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell));
 
       DisplayListChecker beforeMergeChecker;
       DisplayListChecker toBeMergedChecker;
       DisplayListChecker afterMergeChecker;
 
       // Attempt to do a partial build and merge into the existing list.
       // This calls BuildDisplayListForStacking context on a subset of the
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2816,26 +2816,21 @@ nsIFrame::BuildDisplayListForStackingCon
 
   const nsStyleDisplay* disp = StyleDisplay();
   const nsStyleEffects* effects = StyleEffects();
   EffectSet* effectSet = EffectSet::GetEffectSet(this);
   // We can stop right away if this is a zero-opacity stacking context and
   // we're painting, and we're not animating opacity. Don't do this
   // if we're going to compute plugin geometry, since opacity-0 plugins
   // need to have display items built for them.
-  bool needEventRegions =
-    aBuilder->IsBuildingLayerEventRegions() &&
-    StyleUserInterface()->GetEffectivePointerEvents(this) !=
-      NS_STYLE_POINTER_EVENTS_NONE;
   bool opacityItemForEventsAndPluginsOnly = false;
   if (effects->mOpacity == 0.0 && aBuilder->IsForPainting() &&
       !(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
       !nsLayoutUtils::HasAnimationOfProperty(effectSet, eCSSProperty_opacity)) {
-    if (needEventRegions ||
-        aBuilder->WillComputePluginGeometry()) {
+    if (aBuilder->WillComputePluginGeometry()) {
       opacityItemForEventsAndPluginsOnly = true;
     } else {
       return;
     }
   }
 
   if (disp->mWillChangeBitField != 0) {
     aBuilder->AddToWillChangeBudget(this, GetSize());
@@ -3064,23 +3059,16 @@ nsIFrame::BuildDisplayListForStackingCon
     if (extend3DContext) {
       // Mark these first so MarkAbsoluteFramesForDisplayList knows if we are
       // going to be forced to descend into frames.
       aBuilder->MarkPreserve3DFramesForDisplayList(this);
     }
 
     aBuilder->AdjustWindowDraggingRegion(this);
 
-    nsDisplayLayerEventRegions* eventRegions = nullptr;
-    if (aBuilder->IsBuildingLayerEventRegions()) {
-      eventRegions = MakeDisplayItem<nsDisplayLayerEventRegions>(aBuilder, this);
-      eventRegions->AddFrame(aBuilder, this);
-      aBuilder->SetLayerEventRegions(eventRegions);
-    }
-
     aBuilder->BuildCompositorHitTestInfoIfNeeded(this, set.BorderBackground(),
                                                  true);
 
     MarkAbsoluteFramesForDisplayList(aBuilder);
     aBuilder->Check();
     BuildDisplayList(aBuilder, set);
     aBuilder->Check();
 
@@ -3105,28 +3093,16 @@ nsIFrame::BuildDisplayListForStackingCon
     if (aBuilder->ContainsBlendMode() &&
         aBuilder->IsRetainingDisplayList()) {
       if (!aBuilder->GetDirtyRect().Contains(aBuilder->GetVisibleRect())) {
         aBuilder->SetPartialBuildFailed(true);
       } else {
         aBuilder->SetDisablePartialUpdates(true);
       }
     }
-
-    if (eventRegions) {
-      // If the event regions item ended up empty, throw it away rather than
-      // adding it to the display list.
-      if (!eventRegions->IsEmpty()) {
-        set.BorderBackground()->AppendToBottom(eventRegions);
-      } else {
-        aBuilder->SetLayerEventRegions(nullptr);
-        eventRegions->Destroy(aBuilder);
-        eventRegions = nullptr;
-      }
-    }
   }
 
   if (aBuilder->IsBackgroundOnly()) {
     set.BlockBorderBackgrounds()->DeleteAll(aBuilder);
     set.Floats()->DeleteAll(aBuilder);
     set.Content()->DeleteAll(aBuilder);
     set.PositionedDescendants()->DeleteAll(aBuilder);
     set.Outlines()->DeleteAll(aBuilder);
@@ -3530,18 +3506,17 @@ nsIFrame::BuildDisplayListForChild(nsDis
   nsIFrame* child = aChild;
   if (child->HasAnyStateBits(
        NS_FRAME_TOO_DEEP_IN_FRAME_TREE | NS_FRAME_IS_NONDISPLAY))
     return;
 
   aBuilder->ClearWillChangeBudget(child);
 
   const bool shortcutPossible = aBuilder->IsPaintingToWindow() &&
-    (aBuilder->IsBuildingLayerEventRegions() ||
-     aBuilder->BuildCompositorHitTestInfo());
+     aBuilder->BuildCompositorHitTestInfo();
 
   const bool doingShortcut = shortcutPossible &&
     (child->GetStateBits() & NS_FRAME_SIMPLE_DISPLAYLIST) &&
     // Animations may change the value of |HasOpacity()|.
     !(child->GetContent() &&
       child->GetContent()->MayHaveAnimations());
 
   // dirty rect in child-relative coordinates
@@ -3566,21 +3541,16 @@ nsIFrame::BuildDisplayListForChild(nsDis
       buildingForChild(aBuilder, child, visible, dirty, false);
 
     CheckForApzAwareEventHandlers(aBuilder, child);
 
     aBuilder->BuildCompositorHitTestInfoIfNeeded(child,
                                                  aLists.BorderBackground(),
                                                  false);
 
-    nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
-    if (eventRegions) {
-      eventRegions->AddFrame(aBuilder, child);
-    }
-
     child->MarkAbsoluteFramesForDisplayList(aBuilder);
     aBuilder->AdjustWindowDraggingRegion(child);
     aBuilder->Check();
     child->BuildDisplayList(aBuilder, aLists);
     aBuilder->Check();
     aBuilder->DisplayCaret(child, aLists.Content());
 #ifdef DEBUG
     DisplayDebugBorders(aBuilder, child, aLists);
@@ -3780,40 +3750,16 @@ nsIFrame::BuildDisplayListForChild(nsDis
       aBuilder->IntersectDirtyRect(*clipPropClip);
       clipState.ClipContentDescendants(
         *clipPropClip + aBuilder->ToReferenceFrame(child));
       awayFromCommonPath = true;
     }
 
     child->MarkAbsoluteFramesForDisplayList(aBuilder);
 
-    if (aBuilder->IsBuildingLayerEventRegions()) {
-      // If this frame has a different animated geometry root than its parent,
-      // make sure we accumulate event regions for its layer.
-      if (buildingForChild.IsAnimatedGeometryRoot() || isPositioned) {
-        nsDisplayLayerEventRegions* eventRegions =
-          MakeDisplayItem<nsDisplayLayerEventRegions>(aBuilder, child);
-        eventRegions->AddFrame(aBuilder, child);
-        aBuilder->SetLayerEventRegions(eventRegions);
-
-        if (isPositioned) {
-          // We need this nsDisplayLayerEventRegions to be sorted with the positioned
-          // elements as positioned elements will be sorted on top of normal elements
-          list.AppendToTop(eventRegions);
-        } else {
-          aLists.BorderBackground()->AppendToTop(eventRegions);
-        }
-      } else {
-        nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
-        if (eventRegions) {
-          eventRegions->AddFrame(aBuilder, child);
-        }
-      }
-    }
-
     const bool differentAGR =
       buildingForChild.IsAnimatedGeometryRoot() || isPositioned;
 
     if (!awayFromCommonPath && shortcutPossible &&
         !differentAGR && !buildingForChild.MaybeAnimatedGeometryRoot()) {
       // The shortcut is available for the child for next time.
       child->AddStateBits(NS_FRAME_SIMPLE_DISPLAYLIST);
     }
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3716,22 +3716,16 @@ ScrollFrameHelper::BuildDisplayList(nsDi
             scrollbarStyles.mOverscrollBehaviorY != StyleOverscrollBehavior::Auto) {
           info |= CompositorHitTestInfo::eRequiresTargetConfirmation;
         }
         nsDisplayCompositorHitTestInfo* hitInfo =
             MakeDisplayItem<nsDisplayCompositorHitTestInfo>(aBuilder, mScrolledFrame, info, 1,
                 Some(mScrollPort + aBuilder->ToReferenceFrame(mOuter)));
         AppendInternalItemToTop(scrolledContent, hitInfo, Some(INT32_MAX));
       }
-      if (aBuilder->IsBuildingLayerEventRegions()) {
-        nsDisplayLayerEventRegions* inactiveRegionItem =
-            MakeDisplayItem<nsDisplayLayerEventRegions>(aBuilder, mScrolledFrame, 1);
-        inactiveRegionItem->AddInactiveScrollPort(mScrolledFrame, mScrollPort + aBuilder->ToReferenceFrame(mOuter));
-        AppendInternalItemToTop(scrolledContent, inactiveRegionItem, Some(INT32_MAX));
-      }
     }
 
     if (aBuilder->ShouldBuildScrollInfoItemsForHoisting()) {
       aBuilder->AppendNewScrollInfoItemForHoisting(
         MakeDisplayItem<nsDisplayScrollInfoLayer>(aBuilder, mScrolledFrame,
                                                 mOuter));
     }
   }
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -492,17 +492,17 @@ nsSubDocumentFrame::BuildDisplayList(nsD
       nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
       nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
           aBuilder,
           ignoreViewportScrolling && rootScrollFrame && rootScrollFrame->GetContent()
               ? nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame->GetContent())
               : aBuilder->GetCurrentScrollParentId());
 
       bool hasDocumentLevelListenersForApzAwareEvents =
-          nsDisplayListBuilder::LayerEventRegionsEnabled() &&
+          gfxPlatform::AsyncPanZoomEnabled() &&
           nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell);
 
       aBuilder->SetAncestorHasApzAwareEventHandler(hasDocumentLevelListenersForApzAwareEvents);
       subdocRootFrame->
         BuildDisplayListForStackingContext(aBuilder, &childItems);
     }
 
     if (!aBuilder->IsForEventDelivery()) {
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -583,24 +583,17 @@ public:
   AnimatedGeometryRoot* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; }
 
   /**
    * A region including the horizontal pan, vertical pan, and no action regions.
    */
   nsRegion CombinedTouchActionRegion();
 
   /**
-   * Add the given hit regions to the hit regions for this PaintedLayer.
-   */
-  void AccumulateEventRegions(ContainerState* aState,
-                              nsDisplayLayerEventRegions* aEventRegions);
-
-  /**
-   * Similar to AccumulateEventRegions() but uses different display item to
-   * track hit regions.
+   * Add the given hit test info to the hit regions for this PaintedLayer.
    */
   void AccumulateHitTestInfo(ContainerState* aState,
                              nsDisplayCompositorHitTestInfo* aItem);
 
   /**
    * If this represents only a nsDisplayImage, and the image type supports being
    * optimized to an ImageLayer, returns true.
    */
@@ -3399,17 +3392,16 @@ void ContainerState::FinishPaintedLayerD
   if (!layer) {
     // We couldn't optimize to an image layer or a color layer above.
     layer = data->mLayer;
     layer->SetClipRect(Nothing());
     FLB_LOG_PAINTED_LAYER_DECISION(data, "  Selected painted layer=%p\n", layer.get());
   }
 
   for (auto& item : data->mAssignedDisplayItems) {
-    MOZ_ASSERT(item.mItem->GetType() != DisplayItemType::TYPE_LAYER_EVENT_REGIONS);
     MOZ_ASSERT(item.mItem->GetType() != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO);
 
     if (item.mType == DisplayItemEntryType::POP_OPACITY) {
       // Do not invalidate for end markers.
       continue;
     }
 
     InvalidateForLayerChange(item.mItem, data->mLayer, item.mDisplayItemData);
@@ -3819,48 +3811,16 @@ PaintedLayerData::CombinedTouchActionReg
 {
   nsRegion result;
   result.Or(mHorizontalPanRegion, mVerticalPanRegion);
   result.OrWith(mNoActionRegion);
   return result;
 }
 
 void
-PaintedLayerData::AccumulateEventRegions(ContainerState* aState, nsDisplayLayerEventRegions* aEventRegions)
-{
-  FLB_LOG_PAINTED_LAYER_DECISION(this, "Accumulating event regions %p against pld=%p\n", aEventRegions, this);
-
-  mHitRegion.OrWith(aEventRegions->HitRegion());
-  mMaybeHitRegion.OrWith(aEventRegions->MaybeHitRegion());
-  mDispatchToContentHitRegion.OrWith(aEventRegions->DispatchToContentHitRegion());
-
-  // See the comment in nsDisplayList::AddFrame, where the touch action regions
-  // are handled. The same thing applies here.
-  bool alreadyHadRegions = !mNoActionRegion.IsEmpty() ||
-      !mHorizontalPanRegion.IsEmpty() ||
-      !mVerticalPanRegion.IsEmpty();
-  mNoActionRegion.OrWith(aEventRegions->NoActionRegion());
-  mHorizontalPanRegion.OrWith(aEventRegions->HorizontalPanRegion());
-  mVerticalPanRegion.OrWith(aEventRegions->VerticalPanRegion());
-  if (alreadyHadRegions) {
-    mDispatchToContentHitRegion.OrWith(CombinedTouchActionRegion());
-  }
-
-  // Avoid quadratic performance as a result of the region growing to include
-  // and arbitrarily large number of rects, which can happen on some pages.
-  mMaybeHitRegion.SimplifyOutward(8);
-  mDispatchToContentHitRegion.SimplifyOutward(8);
-
-  // Calculate scaled versions of the bounds of mHitRegion and mMaybeHitRegion
-  // for quick access in FindPaintedLayerFor().
-  mScaledHitRegionBounds = aState->ScaleToOutsidePixels(mHitRegion.GetBounds());
-  mScaledMaybeHitRegionBounds = aState->ScaleToOutsidePixels(mMaybeHitRegion.GetBounds());
-}
-
-void
 PaintedLayerData::AccumulateHitTestInfo(ContainerState* aState,
                                         nsDisplayCompositorHitTestInfo* aItem)
 {
   FLB_LOG_PAINTED_LAYER_DECISION(this,
     "Accumulating hit test info %p against pld=%p\n", aItem, this);
 
   const mozilla::DisplayItemClip& clip = aItem->GetClip();
   const nsRect area = clip.ApplyNonRoundedIntersection(aItem->Area());
@@ -4292,21 +4252,16 @@ ContainerState::ProcessDisplayItems(nsDi
 {
   AUTO_PROFILER_LABEL("ContainerState::ProcessDisplayItems", GRAPHICS);
 
   nsPoint topLeft(0,0);
 
   int32_t maxLayers = gfxPrefs::MaxActiveLayers();
   int layerCount = 0;
 
-#ifdef DEBUG
-  bool hadLayerEventRegions = false;
-  bool hadCompositorHitTestInfo = false;
-#endif
-
   if (!mManager->IsWidgetLayerManager()) {
     mPaintedLayerDataTree.InitializeForInactiveLayer(mContainerAnimatedGeometryRoot);
   }
 
   AnimatedGeometryRoot* lastAnimatedGeometryRoot = nullptr;
   nsPoint lastTopLeft;
 
   // Tracks the PaintedLayerData that the item will be accumulated in, if it is
@@ -4319,45 +4274,25 @@ ContainerState::ProcessDisplayItems(nsDi
     nsDisplayItem* i = e.mItem;
     DisplayItemEntryType marker = e.mType;
 
 
     nsDisplayItem* item = i;
     MOZ_ASSERT(item);
     DisplayItemType itemType = item->GetType();
 
-    // If the item is a event regions item, but is empty (has no regions in it)
-    // then we should just throw it out
-    if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
-#ifdef DEBUG
-      hadLayerEventRegions = true;
-#endif
-      nsDisplayLayerEventRegions* eventRegions =
-        static_cast<nsDisplayLayerEventRegions*>(item);
-
-      if (eventRegions->IsEmpty()) {
-        continue;
-      }
-    }
-
     if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
-#ifdef DEBUG
-      hadCompositorHitTestInfo = true;
-#endif
       nsDisplayCompositorHitTestInfo* hitTestInfo =
         static_cast<nsDisplayCompositorHitTestInfo*>(item);
 
       if (hitTestInfo->Area().IsEmpty()) {
         continue;
       }
     }
 
-    // Only allow either LayerEventRegions or CompositorHitTestInfo items.
-    MOZ_ASSERT(!(hadLayerEventRegions && hadCompositorHitTestInfo));
-
     if (marker == DisplayItemEntryType::ITEM) {
       // Peek ahead to the next item and see if it can be merged with the
       // current item.
       nsDisplayItem* peek = iter.PeekNext();
       if (peek && item->CanMerge(peek)) {
         // Create a list of consecutive items that can be merged together.
         AutoTArray<nsDisplayItem*, 2> mergedItems { item };
         while ((peek = iter.PeekNext())) {
@@ -4384,18 +4319,17 @@ ContainerState::ProcessDisplayItems(nsDi
     NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item),
       "items in a container layer should all have the same app units per dev pixel");
 
     if (mBuilder->NeedToForceTransparentSurfaceForItem(item)) {
       aList->SetNeedsTransparentSurface();
     }
 
     if (mParameters.mForEventsAndPluginsOnly && !item->GetChildren() &&
-        (itemType != DisplayItemType::TYPE_LAYER_EVENT_REGIONS &&
-         itemType != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO &&
+        (itemType != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO &&
          itemType != DisplayItemType::TYPE_PLUGIN)) {
       continue;
     }
 
     LayerState layerState = LAYER_NONE;
 
     if (marker == DisplayItemEntryType::ITEM) {
       layerState = item->GetLayerState(mBuilder, mManager, mParameters);
@@ -4435,26 +4369,21 @@ ContainerState::ProcessDisplayItems(nsDi
       lastAnimatedGeometryRoot = animatedGeometryRoot;
     }
 
     const ActiveScrolledRoot* scrollMetadataASR =
         layerClipChain ? ActiveScrolledRoot::PickDescendant(itemASR, layerClipChain->mASR) : itemASR;
 
     bool snap;
     nsRect itemContent = item->GetBounds(mBuilder, &snap);
-    if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
-      nsDisplayLayerEventRegions* eventRegions =
-        static_cast<nsDisplayLayerEventRegions*>(item);
-      itemContent = eventRegions->GetHitRegionBounds(mBuilder, &snap);
-    }
 
     if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
-      nsDisplayCompositorHitTestInfo* eventRegions =
+      nsDisplayCompositorHitTestInfo* hitInfo =
         static_cast<nsDisplayCompositorHitTestInfo*>(item);
-      itemContent = eventRegions->Area();
+      itemContent = hitInfo->Area();
     }
 
     nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
     bool prerenderedTransform = itemType == DisplayItemType::TYPE_TRANSFORM &&
         static_cast<nsDisplayTransform*>(item)->MayBeAnimated(mBuilder);
     ParentLayerIntRect clipRect;
     const DisplayItemClip& itemClip = item->GetClip();
     if (itemClip.HasClip()) {
@@ -4463,18 +4392,17 @@ ContainerState::ProcessDisplayItems(nsDi
       if (!prerenderedTransform && !IsScrollThumbLayer(item)) {
         itemDrawRect.IntersectRect(itemDrawRect, clipRect.ToUnknownRect());
       }
       clipRect.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset));
     }
 #ifdef DEBUG
     nsRect bounds = itemContent;
 
-    if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS ||
-        itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
+    if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
       bounds.SetEmpty();
     }
 
     if (!bounds.IsEmpty()) {
       if (itemASR != mContainerASR) {
         if (Maybe<nsRect> clip = item->GetClipWithRespectToASR(mBuilder, mContainerASR)) {
           bounds = clip.ref();
         }
@@ -4839,21 +4767,17 @@ ContainerState::ProcessDisplayItems(nsDi
                                                     [&](PaintedLayerData* aData) {
             NewPaintedLayerData(aData, animatedGeometryRoot, itemASR,
                                 layerClipChain, scrollMetadataASR, topLeft,
                                 referenceFrame, backfaceHidden);
         });
       }
       MOZ_ASSERT(paintedLayerData);
 
-      if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
-        nsDisplayLayerEventRegions* eventRegions =
-          static_cast<nsDisplayLayerEventRegions*>(item);
-        paintedLayerData->AccumulateEventRegions(this, eventRegions);
-      } else if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
+      if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
         nsDisplayCompositorHitTestInfo* hitTestInfo =
           static_cast<nsDisplayCompositorHitTestInfo*>(item);
         paintedLayerData->AccumulateHitTestInfo(this, hitTestInfo);
       } else {
         paintedLayerData->Accumulate(this, item, itemVisibleRect, itemContent, itemClip,
                                      layerState, aList, marker);
 
         if (!paintedLayerData->mLayer) {
--- a/layout/painting/nsDisplayItemTypesList.h
+++ b/layout/painting/nsDisplayItemTypesList.h
@@ -27,17 +27,16 @@ DECLARE_DISPLAY_ITEM_TYPE(CANVAS_FOCUS, 
 DECLARE_DISPLAY_ITEM_TYPE(CARET, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(CHECKED_CHECKBOX, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(CHECKED_RADIOBUTTON, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(CLEAR_BACKGROUND, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(COLUMN_RULE, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(COMBOBOX_FOCUS, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(COMPOSITOR_HITTEST_INFO, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(EVENT_RECEIVER, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(LAYER_EVENT_REGIONS, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(FIELDSET_BORDER_BACKGROUND, 0)
 DECLARE_DISPLAY_ITEM_TYPE(FIXED_POSITION, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(STICKY_POSITION, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BORDER, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BLANK, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(HEADER_FOOTER, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(IMAGE, 0)
 DECLARE_DISPLAY_ITEM_TYPE(LIST_FOCUS, TYPE_RENDERS_NO_IMAGES)
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -976,17 +976,16 @@ nsDisplayListBuilder::AutoCurrentActiveS
 
   mUsed = true;
 }
 
 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
     nsDisplayListBuilderMode aMode, bool aBuildCaret, bool aRetainingDisplayList)
     : mReferenceFrame(aReferenceFrame),
       mIgnoreScrollFrame(nullptr),
-      mLayerEventRegions(nullptr),
       mCompositorHitTestInfo(nullptr),
       mCurrentTableItem(nullptr),
       mCurrentActiveScrolledRoot(nullptr),
       mCurrentContainerASR(nullptr),
       mCurrentFrame(aReferenceFrame),
       mCurrentReferenceFrame(aReferenceFrame),
       mRootAGR(AnimatedGeometryRoot::CreateAGRForFrame(aReferenceFrame, nullptr, true, aRetainingDisplayList)),
       mCurrentAGR(mRootAGR),
@@ -1030,21 +1029,17 @@ nsDisplayListBuilder::nsDisplayListBuild
       mHitTestIsForVisibility(false),
       mIsBuilding(false),
       mInInvalidSubtree(false),
       mDisablePartialUpdates(false),
       mPartialBuildFailed(false)
 {
   MOZ_COUNT_CTOR(nsDisplayListBuilder);
 
-  const bool useWRHitTest =
-    gfxPrefs::WebRenderHitTest() && gfxVars::UseWebRender();
-
-  mBuildCompositorHitTestInfo = mAsyncPanZoomEnabled && IsForPainting() &&
-    (useWRHitTest || gfxPrefs::SimpleEventRegionItems());
+  mBuildCompositorHitTestInfo = mAsyncPanZoomEnabled && IsForPainting();
 
   mLessEventRegionItems = gfxPrefs::LessEventRegionItems();
 
   nsPresContext* pc = aReferenceFrame->PresContext();
   nsIPresShell *shell = pc->PresShell();
   if (pc->IsRenderingOnlySelection()) {
     nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(shell));
     if (selcon) {
@@ -1075,17 +1070,16 @@ nsDisplayListBuilder::EndFrame()
 {
   NS_ASSERTION(!mInInvalidSubtree, "Someone forgot to cleanup mInInvalidSubtree!");
   mFrameToAnimatedGeometryRootMap.Clear();
   mActiveScrolledRoots.Clear();
   FreeClipChains();
   FreeTemporaryItems();
   nsCSSRendering::EndFrameTreesLocked();
 
-  MOZ_ASSERT(!mLayerEventRegions);
   MOZ_ASSERT(!mCompositorHitTestInfo);
 }
 
 void
 nsDisplayListBuilder::MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame)
 {
   mFramesMarkedForDisplay.AppendElement(aFrame);
   for (nsIFrame* f = aFrame; f;
@@ -1374,17 +1368,16 @@ nsDisplayListBuilder::EnterPresShell(nsI
 }
 
 // A non-blank paint is a paint that does not just contain the canvas background.
 static bool
 DisplayListIsNonBlank(nsDisplayList* aList)
 {
   for (nsDisplayItem* i = aList->GetBottom(); i != nullptr; i = i->GetAbove()) {
     switch (i->GetType()) {
-      case DisplayItemType::TYPE_LAYER_EVENT_REGIONS:
       case DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO:
       case DisplayItemType::TYPE_CANVAS_BACKGROUND_COLOR:
       case DisplayItemType::TYPE_CANVAS_BACKGROUND_IMAGE:
         continue;
       case DisplayItemType::TYPE_SOLID_COLOR:
       case DisplayItemType::TYPE_BACKGROUND:
       case DisplayItemType::TYPE_BACKGROUND_COLOR:
         if (i->Frame()->IsCanvasFrame()) {
@@ -2290,45 +2283,16 @@ nsDisplayListBuilder::ShouldBuildComposi
     // Hit test flags are different.
     return true;
   }
 
   // Create a new item if the parent does not contain the child completely.
   return !mCompositorHitTestInfo->Area().Contains(GetFrameArea(this, aFrame));
 }
 
-bool
-nsDisplayListBuilder::IsBuildingLayerEventRegions()
-{
-  if (mBuildCompositorHitTestInfo) {
-    // If we have webrender hit-testing enabled, then we will build the
-    // nsDisplayCompositorHitTestInfo items and use those instead of event
-    // regions, so we don't need to build the event regions.
-    return false;
-  }
-  if (IsPaintingToWindow()) {
-    // Note: this function and LayerEventRegionsEnabled are the only places
-    // that get to query LayoutEventRegionsEnabled 'directly' - other code
-    // should call this function.
-    return gfxPrefs::LayoutEventRegionsEnabledDoNotUseDirectly() ||
-           mAsyncPanZoomEnabled;
-  }
-  return false;
-}
-
-/* static */ bool
-nsDisplayListBuilder::LayerEventRegionsEnabled()
-{
-  // Note: this function and IsBuildingLayerEventRegions are the only places
-  // that get to query LayoutEventRegionsEnabled 'directly' - other code
-  // should call this function.
-  return gfxPrefs::LayoutEventRegionsEnabledDoNotUseDirectly() ||
-         gfxPlatform::AsyncPanZoomEnabled();
-}
-
 void nsDisplayListSet::MoveTo(const nsDisplayListSet& aDestination) const
 {
   aDestination.BorderBackground()->AppendToTop(BorderBackground());
   aDestination.BlockBorderBackgrounds()->AppendToTop(BlockBorderBackgrounds());
   aDestination.Floats()->AppendToTop(Floats());
   aDestination.Content()->AppendToTop(Content());
   aDestination.PositionedDescendants()->AppendToTop(PositionedDescendants());
   aDestination.Outlines()->AppendToTop(Outlines());
@@ -2395,17 +2359,16 @@ nsDisplayList::ComputeVisibilityForRoot(
 }
 
 static nsRegion
 TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
 {
   bool snap;
   nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
   if (aBuilder->IsForPluginGeometry() &&
-      aItem->GetType() != DisplayItemType::TYPE_LAYER_EVENT_REGIONS &&
       aItem->GetType() != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO)
   {
     // Treat all leaf chrome items as opaque, unless their frames are opacity:0.
     // Since opacity:0 frames generate an nsDisplayOpacity, that item will
     // not be treated as opaque here, so opacity:0 chrome content will be
     // effectively ignored, as it should be.
     // We treat leaf chrome items as opaque to ensure that they cover
     // content plugins, for security reasons.
@@ -5152,213 +5115,16 @@ nsDisplayCompositorHitTestInfo::ZIndex()
 }
 
 void
 nsDisplayCompositorHitTestInfo::SetOverrideZIndex(int32_t aZIndex)
 {
   mOverrideZIndex = Some(aZIndex);
 }
 
-void
-nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
-                                     nsIFrame* aFrame)
-{
-  NS_ASSERTION(aBuilder->FindReferenceFrameFor(aFrame) == aBuilder->FindReferenceFrameFor(mFrame),
-               "Reference frame mismatch");
-  CompositorHitTestInfo hitInfo =
-      aFrame->GetCompositorHitTestInfo(aBuilder);
-  if (hitInfo == CompositorHitTestInfo::eInvisibleToHitTest) {
-    return;
-  }
-
-  // XXX handle other pointerEvents values for SVG
-
-  // XXX Do something clever here for the common case where the border box
-  // is obviously entirely inside mHitRegion.
-  nsRect borderBox = GetFrameArea(aBuilder, aFrame);
-
-  if (aFrame != mFrame &&
-      aBuilder->IsRetainingDisplayList()) {
-    aFrame->AddDisplayItem(this);
-  }
-
-  bool borderBoxHasRoundedCorners = false;
-
-  // use the NS_FRAME_SIMPLE_EVENT_REGIONS to avoid calling the slightly
-  // expensive HasNonZeroCorner function if we know from a previous run that
-  // the frame has zero corners.
-  bool simpleRegions = aFrame->HasAnyStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
-  if (!simpleRegions) {
-    if (nsLayoutUtils::HasNonZeroCorner(aFrame->StyleBorder()->mBorderRadius)) {
-      borderBoxHasRoundedCorners = true;
-    } else {
-      aFrame->AddStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
-    }
-  }
-
-  const DisplayItemClip* clip = DisplayItemClipChain::ClipForASR(
-    aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder),
-    aBuilder->CurrentActiveScrolledRoot());
-  if (clip) {
-    borderBox = clip->ApplyNonRoundedIntersection(borderBox);
-    if (clip->GetRoundedRectCount() > 0) {
-      borderBoxHasRoundedCorners = true;
-    }
-  }
-
-  if (borderBoxHasRoundedCorners ||
-      (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
-    mMaybeHitRegion.Add(aFrame, borderBox);
-  } else {
-    mHitRegion.Add(aFrame, borderBox);
-  }
-
-  if (hitInfo & CompositorHitTestInfo::eDispatchToContent) {
-    mDispatchToContentHitRegion.Add(aFrame, borderBox);
-  }
-
-  // Touch action region
-
-  auto touchFlags = hitInfo & CompositorHitTestInfo::eTouchActionMask;
-  if (touchFlags) {
-    // something was disabled
-    if (touchFlags == CompositorHitTestInfo::eTouchActionMask) {
-      // everything was disabled, so touch-action:none
-      mNoActionRegion.Add(aFrame, borderBox);
-    } else {
-      // The event regions code does not store enough information to actually
-      // represent all the different states. Prior to the introduction of
-      // CompositorHitTestInfo here in bug 1389149, the following two cases
-      // were effectively getting collapsed:
-      //   (1) touch-action: auto
-      //   (2) touch-action: manipulation
-      // In both of these cases, none of {mNoActionRegion, mHorizontalPanRegion,
-      // mVerticalPanRegion} were modified, and so the fact that case (2) should
-      // have prevented double-tap-zooming was getting lost.
-      // With CompositorHitTestInfo we can now represent that case correctly,
-      // but only if we use CompositorHitTestInfo all the way to the compositor
-      // (i.e. in the WebRender-enabled case). In the non-WebRender case where
-      // we still use the event regions, we must collapse these two cases back
-      // together. Or add another region to the event regions to fix this
-      // properly.
-      if (touchFlags == CompositorHitTestInfo::eTouchActionDoubleTapZoomDisabled) {
-        // the touch-action: manipulation case described above. To preserve the
-        // existing behaviour, don't touch either mHorizontalPanRegion or
-        // mVerticalPanRegion
-      } else {
-        if (!(hitInfo & CompositorHitTestInfo::eTouchActionPanXDisabled)) {
-          // pan-x is allowed
-          mHorizontalPanRegion.Add(aFrame, borderBox);
-        }
-        if (!(hitInfo & CompositorHitTestInfo::eTouchActionPanYDisabled)) {
-          // pan-y is allowed
-          mVerticalPanRegion.Add(aFrame, borderBox);
-        }
-      }
-    }
-  }
-}
-
-static void
-RemoveFrameFromFrameRects(nsDisplayLayerEventRegions::FrameRects& aFrameRects, nsIFrame* aFrame)
-{
-  uint32_t i = 0;
-  uint32_t length = aFrameRects.mFrames.Length();
-  while (i < length) {
-    if (aFrameRects.mFrames[i] == aFrame) {
-      aFrameRects.mFrames[i] = aFrameRects.mFrames[length - 1];
-      aFrameRects.mBoxes[i] = aFrameRects.mBoxes[length - 1];
-      length--;
-    } else {
-      i++;
-    }
-  }
-  aFrameRects.mFrames.SetLength(length);
-  aFrameRects.mBoxes.SetLength(length);
-}
-
-void
-nsDisplayLayerEventRegions::RemoveFrame(nsIFrame* aFrame)
-{
-  RemoveFrameFromFrameRects(mHitRegion, aFrame);
-  RemoveFrameFromFrameRects(mMaybeHitRegion, aFrame);
-  RemoveFrameFromFrameRects(mDispatchToContentHitRegion, aFrame);
-  RemoveFrameFromFrameRects(mNoActionRegion, aFrame);
-  RemoveFrameFromFrameRects(mHorizontalPanRegion, aFrame);
-  RemoveFrameFromFrameRects(mVerticalPanRegion, aFrame);
-
-  nsDisplayItem::RemoveFrame(aFrame);
-}
-
-void
-nsDisplayLayerEventRegions::AddInactiveScrollPort(nsIFrame* aFrame, const nsRect& aRect)
-{
-  mHitRegion.Add(aFrame, aRect);
-  mDispatchToContentHitRegion.Add(aFrame, aRect);
-}
-
-bool
-nsDisplayLayerEventRegions::IsEmpty() const
-{
-  // If the hit region and maybe-hit region are empty, then the rest
-  // must be empty too.
-  if (mHitRegion.IsEmpty() && mMaybeHitRegion.IsEmpty()) {
-    MOZ_ASSERT(mDispatchToContentHitRegion.IsEmpty());
-    MOZ_ASSERT(mNoActionRegion.IsEmpty());
-    MOZ_ASSERT(mHorizontalPanRegion.IsEmpty());
-    MOZ_ASSERT(mVerticalPanRegion.IsEmpty());
-    return true;
-  }
-  return false;
-}
-
-nsRegion
-nsDisplayLayerEventRegions::CombinedTouchActionRegion()
-{
-  nsRegion result;
-  result.Or(HorizontalPanRegion(), VerticalPanRegion());
-  result.OrWith(NoActionRegion());
-  return result;
-}
-
-int32_t
-nsDisplayLayerEventRegions::ZIndex() const
-{
-  return mOverrideZIndex ? *mOverrideZIndex : nsDisplayItem::ZIndex();
-}
-
-void
-nsDisplayLayerEventRegions::SetOverrideZIndex(int32_t aZIndex)
-{
-  mOverrideZIndex = Some(aZIndex);
-}
-
-void
-nsDisplayLayerEventRegions::WriteDebugInfo(std::stringstream& aStream)
-{
-  if (!mHitRegion.IsEmpty()) {
-    AppendToString(aStream, HitRegion(), " (hitRegion ", ")");
-  }
-  if (!mMaybeHitRegion.IsEmpty()) {
-    AppendToString(aStream, MaybeHitRegion(), " (maybeHitRegion ", ")");
-  }
-  if (!mDispatchToContentHitRegion.IsEmpty()) {
-    AppendToString(aStream, DispatchToContentHitRegion(), " (dispatchToContentRegion ", ")");
-  }
-  if (!mNoActionRegion.IsEmpty()) {
-    AppendToString(aStream, NoActionRegion(), " (noActionRegion ", ")");
-  }
-  if (!mHorizontalPanRegion.IsEmpty()) {
-    AppendToString(aStream, HorizontalPanRegion(), " (horizPanRegion ", ")");
-  }
-  if (!mVerticalPanRegion.IsEmpty()) {
-    AppendToString(aStream, VerticalPanRegion(), " (vertPanRegion ", ")");
-  }
-}
-
 nsDisplayCaret::nsDisplayCaret(nsDisplayListBuilder* aBuilder,
                                nsIFrame* aCaretFrame)
   : nsDisplayItem(aBuilder, aCaretFrame)
   , mCaret(aBuilder->GetCaret())
   , mBounds(aBuilder->GetCaretRect() + ToReferenceFrame())
 {
   MOZ_COUNT_CTOR(nsDisplayCaret);
 }
@@ -6592,18 +6358,17 @@ CollectItemsWithOpacity(nsDisplayList* a
     // Descend only into wraplists.
     if (type == DisplayItemType::TYPE_WRAP_LIST && children) {
       // The current display item has children, process them first.
       if (!CollectItemsWithOpacity(children, aArray, aMaxChildCount)) {
         return false;
       }
     }
 
-    if (type == DisplayItemType::TYPE_LAYER_EVENT_REGIONS ||
-        type == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO ||
+    if (type == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO ||
         type == DisplayItemType::TYPE_WRAP_LIST) {
       continue;
     }
 
     if (!i->CanApplyOpacity() || aArray.Length() == aMaxChildCount) {
       return false;
     }
 
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -57,17 +57,16 @@
 
 class gfxContext;
 class nsIContent;
 class nsDisplayList;
 class nsDisplayTableItem;
 class nsIScrollableFrame;
 class nsSubDocumentFrame;
 class nsDisplayCompositorHitTestInfo;
-class nsDisplayLayerEventRegions;
 class nsDisplayScrollInfoLayer;
 class nsCaret;
 enum class nsDisplayOwnLayerFlags;
 
 namespace mozilla {
 class FrameLayerBuilder;
 namespace layers {
 class Layer;
@@ -721,22 +720,16 @@ public:
 
   /**
    * Returns true if merging and flattening of display lists should be
    * performed while computing visibility.
    */
   bool AllowMergingAndFlattening() { return mAllowMergingAndFlattening; }
   void SetAllowMergingAndFlattening(bool aAllow) { mAllowMergingAndFlattening = aAllow; }
 
-  nsDisplayLayerEventRegions* GetLayerEventRegions() { return mLayerEventRegions; }
-  void SetLayerEventRegions(nsDisplayLayerEventRegions* aItem)
-  {
-    mLayerEventRegions = aItem;
-  }
-
   /**
    * Sets the current compositor hit test info to |aHitTestInfo|.
    * This is used during display list building to determine if the parent frame
    * hit test info contains the same information that child frame needs.
    */
   void SetCompositorHitTestInfo(nsDisplayCompositorHitTestInfo* aHitTestInfo)
   {
     mCompositorHitTestInfo = aHitTestInfo;
@@ -746,18 +739,16 @@ public:
    * Builds a new nsDisplayCompositorHitTestInfo for the frame |aFrame| if
    * needed, and adds it to the top of |aList|. If |aBuildNew| is true, the
    * previous hit test info will not be reused.
    */
   void BuildCompositorHitTestInfoIfNeeded(nsIFrame* aFrame,
                                           nsDisplayList* aList,
                                           const bool aBuildNew);
 
-  bool IsBuildingLayerEventRegions();
-  static bool LayerEventRegionsEnabled();
   bool IsInsidePointerEventsNoneDoc()
   {
     return CurrentPresShellState()->mInsidePointerEventsNoneDoc;
   }
 
   bool GetAncestorHasApzAwareEventHandler() const { return mAncestorHasApzAwareEventHandler; }
   void SetAncestorHasApzAwareEventHandler(bool aValue)
   {
@@ -1071,17 +1062,16 @@ public:
     AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder,
                             nsIFrame* aForChild,
                             const nsRect& aVisibleRect,
                             const nsRect& aDirtyRect,
                             bool aIsRoot)
       : mBuilder(aBuilder),
         mPrevFrame(aBuilder->mCurrentFrame),
         mPrevReferenceFrame(aBuilder->mCurrentReferenceFrame),
-        mPrevLayerEventRegions(aBuilder->mLayerEventRegions),
         mPrevCompositorHitTestInfo(aBuilder->mCompositorHitTestInfo),
         mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame),
         mPrevVisibleRect(aBuilder->mVisibleRect),
         mPrevDirtyRect(aBuilder->mDirtyRect),
         mPrevAGR(aBuilder->mCurrentAGR),
         mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext),
         mPrevAncestorHasApzAwareEventHandler(aBuilder->mAncestorHasApzAwareEventHandler),
         mPrevBuildingInvisibleItems(aBuilder->mBuildingInvisibleItems),
@@ -1124,33 +1114,31 @@ public:
       return mCurrentAGRState == AGR_MAYBE;
     }
     void RestoreBuildingInvisibleItemsValue() {
       mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
     }
     ~AutoBuildingDisplayList() {
       mBuilder->mCurrentFrame = mPrevFrame;
       mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame;
-      mBuilder->mLayerEventRegions = mPrevLayerEventRegions;
       mBuilder->mCompositorHitTestInfo = mPrevCompositorHitTestInfo;
       mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset;
       mBuilder->mVisibleRect = mPrevVisibleRect;
       mBuilder->mDirtyRect = mPrevDirtyRect;
       mBuilder->mCurrentAGR = mPrevAGR;
       mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext;
       mBuilder->mAncestorHasApzAwareEventHandler = mPrevAncestorHasApzAwareEventHandler;
       mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
       mBuilder->mInInvalidSubtree = mPrevInInvalidSubtree;
     }
   private:
     nsDisplayListBuilder* mBuilder;
     AGRState              mCurrentAGRState;
     const nsIFrame*       mPrevFrame;
     const nsIFrame*       mPrevReferenceFrame;
-    nsDisplayLayerEventRegions* mPrevLayerEventRegions;
     nsDisplayCompositorHitTestInfo* mPrevCompositorHitTestInfo;
     nsPoint               mPrevOffset;
     nsRect                mPrevVisibleRect;
     nsRect                mPrevDirtyRect;
     RefPtr<AnimatedGeometryRoot> mPrevAGR;
     bool                  mPrevIsAtRootOfPseudoStackingContext;
     bool                  mPrevAncestorHasApzAwareEventHandler;
     bool                  mPrevBuildingInvisibleItems;
@@ -1723,18 +1711,16 @@ public:
   void SetHitTestIsForVisibility(bool aHitTestIsForVisibility) {
     mHitTestIsForVisibility = aHitTestIsForVisibility;
   }
 
   /**
    * Represents a region composed of frame/rect pairs.
    * WeakFrames are used to track whether a rect still belongs to the region.
    * Modified frames and rects are removed and re-added to the region if needed.
-   * nsDisplayLayerEventRegions::FrameRects implements the same functionality
-   * with nsIFrames.
    */
   struct WeakFrameRegion {
     std::vector<WeakFrame> mFrames;
     nsTArray<pixman_box32_t> mRects;
 
     void Add(nsIFrame* aFrame, const nsRect& aRect)
     {
       mFrames.emplace_back(aFrame);
@@ -1854,17 +1840,16 @@ private:
     {}
 
     nsIFrame* mFrame;
     uint32_t mUsage;
   };
 
   nsIFrame* const                mReferenceFrame;
   nsIFrame*                      mIgnoreScrollFrame;
-  nsDisplayLayerEventRegions*    mLayerEventRegions;
   nsDisplayCompositorHitTestInfo* mCompositorHitTestInfo;
 
   nsPresArena mPool;
 
   RefPtr<mozilla::dom::Selection> mBoundingSelection;
   AutoTArray<PresShellState,8> mPresShellStates;
   AutoTArray<nsIFrame*,400>    mFramesMarkedForDisplay;
   AutoTArray<nsIFrame*,40>       mFramesMarkedForDisplayIfVisible;
@@ -4828,234 +4813,16 @@ private:
   mozilla::Maybe<mozilla::layers::FrameMetrics::ViewID> mScrollTarget;
   nsRect mArea;
   uint32_t mIndex;
   mozilla::Maybe<int32_t> mOverrideZIndex;
   int32_t mAppUnitsPerDevPixel;
 };
 
 /**
- * A display item that tracks event-sensitive regions which will be set
- * on the ContainerLayer that eventually contains this item.
- *
- * One of these is created for each stacking context and pseudo-stacking-context.
- * It accumulates regions for event targets contributed by the border-boxes of
- * frames in its (pseudo) stacking context. A nsDisplayLayerEventRegions
- * eventually contributes its regions to the PaintedLayer it is placed in by
- * FrameLayerBuilder. (We don't create a display item for every frame that
- * could be an event target (i.e. almost all frames), because that would be
- * high overhead.)
- *
- * We always make leaf layers other than PaintedLayers transparent to events.
- * For example, an event targeting a canvas or video will actually target the
- * background of that element, which is logically in the PaintedLayer behind the
- * CanvasFrame or ImageFrame. We only need to create a
- * nsDisplayLayerEventRegions when an element's background could be in front
- * of a lower z-order element with its own layer.
- */
-class nsDisplayLayerEventRegions final : public nsDisplayItem {
-public:
-  nsDisplayLayerEventRegions(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, uint32_t aIndex = 0)
-    : nsDisplayItem(aBuilder, aFrame)
-    , mIndex(aIndex)
-  {
-    MOZ_COUNT_CTOR(nsDisplayLayerEventRegions);
-  }
-
-  virtual void Destroy(nsDisplayListBuilder* aBuilder) override
-  {
-    if (!aBuilder->IsRetainingDisplayList()) {
-      nsDisplayItem::Destroy(aBuilder);
-      return;
-    }
-
-    RemoveItemFromFrames(mHitRegion);
-    RemoveItemFromFrames(mMaybeHitRegion);
-    RemoveItemFromFrames(mDispatchToContentHitRegion);
-    RemoveItemFromFrames(mNoActionRegion);
-    RemoveItemFromFrames(mHorizontalPanRegion);
-    RemoveItemFromFrames(mVerticalPanRegion);
-    nsDisplayItem::Destroy(aBuilder);
-  }
-
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
-                           bool* aSnap) const override
-  {
-    *aSnap = false;
-    return nsRect();
-  }
-  nsRect GetHitRegionBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
-  {
-    *aSnap = false;
-    // TODO: This constructs the two regions, but we're also doing the same
-    // work in AccumulateEventRegions. We should avoid doing it twice.
-    return HitRegion().GetBounds().Union(MaybeHitRegion().GetBounds());
-  }
-
-  virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
-                            float aOpacity,
-                            const DisplayItemClipChain* aClip) override
-  {
-    NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
-  }
-  virtual bool CanApplyOpacity() const override
-  {
-    return true;
-  }
-
-  NS_DISPLAY_DECL_NAME("LayerEventRegions", TYPE_LAYER_EVENT_REGIONS)
-
-  // Indicate that aFrame's border-box contributes to the event regions for
-  // this layer. aFrame must have the same reference frame as mFrame.
-  void AddFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
-
-  // Indicate that an inactive scrollframe's scrollport should be added to the
-  // dispatch-to-content region, to ensure that APZ lets content create a
-  // displayport.
-  void AddInactiveScrollPort(nsIFrame* aFrame, const nsRect& aRect);
-
-  bool IsEmpty() const;
-
-  int32_t ZIndex() const override;
-  void SetOverrideZIndex(int32_t aZIndex);
-
-  virtual uint32_t GetPerFrameKey() const override
-  {
-    return (mIndex << TYPE_BITS) | nsDisplayItem::GetPerFrameKey();
-  }
-
-  const nsRegion HitRegion()
-  {
-    return nsRegion(mozilla::gfx::ArrayView<pixman_box32_t>(mHitRegion.mBoxes));
-  }
-  const nsRegion MaybeHitRegion()
-  {
-    nsRegion result(mozilla::gfx::ArrayView<pixman_box32_t>(mMaybeHitRegion.mBoxes));
-
-    // Avoid quadratic performance as a result of the region growing to include
-    // an arbitrarily large number of rects, which can happen on some pages.
-    // TODO: It would be nice if we could ask the initial construction above
-    // to include simplification.
-    result.SimplifyOutward(8);
-    return result;
-  }
-  const nsRegion DispatchToContentHitRegion()
-  {
-    nsRegion result(mozilla::gfx::ArrayView<pixman_box32_t>(mDispatchToContentHitRegion.mBoxes));
-
-    // If this frame has touch-action areas, and there were already
-    // touch-action areas from some other element on this same event regions,
-    // then all we know is that there are multiple elements with touch-action
-    // properties. In particular, we don't know what the relationship is
-    // between those elements in terms of DOM ancestry, and so we don't know
-    // how to combine the regions properly. Instead, we just add all the areas
-    // to the dispatch-to-content region, so that the APZ knows to check with
-    // the main thread. XXX we need to come up with a better way to do this,
-    // see bug 1287829.
-    uint32_t touchActionCount =
-      mNoActionRegion.mBoxes.Length() +
-      mHorizontalPanRegion.mBoxes.Length() +
-      mVerticalPanRegion.mBoxes.Length();
-    if (touchActionCount > 1) {
-      result.OrWith(NoActionRegion());
-      result.OrWith(HorizontalPanRegion());
-      result.OrWith(VerticalPanRegion());
-    }
-
-    result.SimplifyOutward(8);
-    return result;
-  }
-  const nsRegion NoActionRegion()
-  {
-    return nsRegion(mozilla::gfx::ArrayView<pixman_box32_t>(mNoActionRegion.mBoxes));
-  }
-  const nsRegion HorizontalPanRegion()
-  {
-    return nsRegion(mozilla::gfx::ArrayView<pixman_box32_t>(mHorizontalPanRegion.mBoxes));
-  }
-  const nsRegion VerticalPanRegion()
-  {
-    return nsRegion(mozilla::gfx::ArrayView<pixman_box32_t>(mVerticalPanRegion.mBoxes));
-  }
-  nsRegion CombinedTouchActionRegion();
-
-  virtual void WriteDebugInfo(std::stringstream& aStream) override;
-
-  // TODO: nsTArray (vector) might not be a great data structure
-  // choice since we need to remove elements from the middle.
-  // Should profile and try figure out the best approach
-  // here.
-  struct FrameRects {
-    void Add(nsIFrame* aFrame, const nsRect& aRect) {
-      mBoxes.AppendElement(nsRegion::RectToBox(aRect));
-      mFrames.AppendElement(aFrame);
-    }
-    void Add(nsIFrame* aFrame, const pixman_box32& aBox) {
-      mBoxes.AppendElement(aBox);
-      mFrames.AppendElement(aFrame);
-    }
-    void Add(const FrameRects& aOther) {
-      mBoxes.AppendElements(aOther.mBoxes);
-      mFrames.AppendElements(aOther.mFrames);
-    }
-
-    bool IsEmpty() const {
-      return mBoxes.IsEmpty();
-    }
-
-    nsTArray<pixman_box32_t> mBoxes;
-    nsTArray<nsIFrame*> mFrames;
-  };
-
-  virtual void RemoveFrame(nsIFrame* aFrame) override;
-
-private:
-  virtual ~nsDisplayLayerEventRegions()
-  {
-    MOZ_COUNT_DTOR(nsDisplayLayerEventRegions);
-  }
-
-  void RemoveItemFromFrames(FrameRects& aFrameRects)
-  {
-    for (nsIFrame* f : aFrameRects.mFrames) {
-      if (f != mFrame) {
-        f->RemoveDisplayItem(this);
-      }
-    }
-  }
-
-  friend bool MergeLayerEventRegions(nsDisplayItem*, nsDisplayItem*);
-
-  // Relative to aFrame's reference frame.
-  // These are the points that are definitely in the hit region.
-  FrameRects mHitRegion;
-  // These are points that may or may not be in the hit region. Only main-thread
-  // event handling can tell for sure (e.g. because complex shapes are present).
-  FrameRects mMaybeHitRegion;
-  // These are points that need to be dispatched to the content thread for
-  // resolution. Always contained in the union of mHitRegion and mMaybeHitRegion.
-  FrameRects mDispatchToContentHitRegion;
-  // These are points where panning is disabled, as determined by the touch-action
-  // property. Always contained in the union of mHitRegion and mMaybeHitRegion.
-  FrameRects mNoActionRegion;
-  // These are points where panning is horizontal, as determined by the touch-action
-  // property. Always contained in the union of mHitRegion and mMaybeHitRegion.
-  FrameRects mHorizontalPanRegion;
-  // These are points where panning is vertical, as determined by the touch-action
-  // property. Always contained in the union of mHitRegion and mMaybeHitRegion.
-  FrameRects mVerticalPanRegion;
-  // If these event regions are for an inactive scroll frame, the z-index of
-  // this display item is overridden to be the largest z-index of the content
-  // in the scroll frame. This ensures that the event regions item remains on
-  // top of the content after sorting items by z-index.
-  mozilla::Maybe<int32_t> mOverrideZIndex;
-  uint32_t mIndex;
-};
-
-/**
  * A class that lets you wrap a display list as a display item.
  *
  * GetUnderlyingFrame() is troublesome for wrapped lists because if the wrapped
  * list has many items, it's not clear which one has the 'underlying frame'.
  * Thus we force the creator to specify what the underlying frame is. The
  * underlying frame should be the root of a stacking context, because sorting
  * a list containing this item will not get at the children.
  *
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -600,19 +600,16 @@ pref("media.cubeb.sandbox", false);
 pref("media.webaudio.audiocontextoptions-samplerate.enabled", true);
 
 // Weather we allow AMD switchable graphics
 pref("layers.amd-switchable-gfx.enabled", true);
 
 // Whether to use async panning and zooming
 pref("layers.async-pan-zoom.enabled", true);
 
-// Whether to enable event region building during painting
-pref("layout.event-regions.enabled", false);
-
 // Whether to enable arbitrary layer geometry for OpenGL compositor
 pref("layers.geometry.opengl.enabled", true);
 
 // Whether to enable arbitrary layer geometry for Basic compositor
 pref("layers.geometry.basic.enabled", true);
 
 // Whether to enable arbitrary layer geometry for DirectX compositor
 pref("layers.geometry.d3d11.enabled", true);
@@ -868,17 +865,16 @@ pref("gfx.webrender.program-binary-disk"
 #ifdef XP_MACOSX
 pref("gfx.compositor.glcontext.opaque", false);
 #endif
 
 pref("gfx.webrender.highlight-painted-layers", false);
 pref("gfx.webrender.async-scene-build", true);
 pref("gfx.webrender.blob-images", true);
 pref("gfx.webrender.blob.invalidation", true);
-pref("gfx.webrender.hit-test", true);
 
 // WebRender debugging utilities.
 pref("gfx.webrender.debug.texture-cache", false);
 pref("gfx.webrender.debug.render-targets", false);
 pref("gfx.webrender.debug.alpha-primitives", false);
 pref("gfx.webrender.debug.profiler", false);
 pref("gfx.webrender.debug.gpu-time-queries", false);
 pref("gfx.webrender.debug.gpu-sample-queries", false);
--- a/taskcluster/ci/config.yml
+++ b/taskcluster/ci/config.yml
@@ -13,16 +13,18 @@ treeherder:
         'Fxfn-r-e10s': 'Firefox functional tests (remote) with e10s'
         'M': 'Mochitests'
         'M-e10s': 'Mochitests with e10s'
         'M-V': 'Mochitests on Valgrind'
         'R': 'Reftests'
         'R-e10s': 'Reftests with e10s'
         'Rap': 'Raptor performance tests on Firefox'
         'Rap-e10s': 'Raptor performance tests on Firefox with e10s'
+        'Rap-C': 'Raptor performance tests on Google Chrome'
+        'Rap-C-e10s': 'Raptor performance tests on Google Chrome with e10s'
         'T': 'Talos performance tests'
         'Tsd': 'Talos performance tests with Stylo disabled'
         'Tss': 'Talos performance tests with Stylo sequential'
         'T-e10s': 'Talos performance tests with e10s'
         'Tsd-e10s': 'Talos performance tests with e10s, Stylo disabled'
         'Tss-e10s': 'Talos performance tests with e10s, Stylo sequential'
         'T-P-e10s': 'Talos performance tests with e10s and gecko profiling'
         'tt-c': 'Telemetry client marionette tests'
--- a/taskcluster/ci/test/raptor.yml
+++ b/taskcluster/ci/test/raptor.yml
@@ -31,22 +31,36 @@ raptor-firefox-tp6:
     treeherder-symbol: Rap(tp6)
     run-on-projects:
         by-test-platform:
             .*-qr/.*: ['try']
             default: ['try']
     max-run-time: 1200
     mozharness:
         extra-options:
-            - --test=raptor-firefox-tp6
+            - --test=raptor-tp6
 
 raptor-firefox-speedometer:
     description: "Raptor Firefox speedometer"
     try-name: raptor-firefox-speedometer
     treeherder-symbol: Rap(sp)
     run-on-projects:
         by-test-platform:
             .*-qr/.*: ['try']
             default: ['try']
     max-run-time: 1500
     mozharness:
         extra-options:
             - --test=raptor-speedometer
+
+raptor-chrome-speedometer:
+    description: "Raptor Chrome speedometer"
+    try-name: raptor-chrome-speedometer
+    treeherder-symbol: Rap-C(sp)
+    run-on-projects:
+        by-test-platform:
+            .*-qr/.*: ['try']
+            default: ['try']
+    max-run-time: 1500
+    mozharness:
+        extra-options:
+            - --test=raptor-speedometer
+            - --app=chrome
--- a/taskcluster/ci/test/test-sets.yml
+++ b/taskcluster/ci/test/test-sets.yml
@@ -278,16 +278,17 @@ macosx64-talos-profiling:
     # - talos-tps-profiling # Bug 1453007 times out
 
 macosx64-qr-tests:
     - reftest
 
 macosx64-raptor:
     - raptor-firefox-tp6
     - raptor-firefox-speedometer
+    - raptor-chrome-speedometer
 
 linux32-tests:
     - cppunit
     - crashtest
     - firefox-ui-functional-local
     - firefox-ui-functional-remote
     - gtest
     - jittest
--- a/testing/mozbase/mozprofile/mozprofile/profile.py
+++ b/testing/mozbase/mozprofile/mozprofile/profile.py
@@ -491,18 +491,18 @@ class ChromeProfile(BaseProfile):
     class AddonManager(list):
         def install(self, addons):
             if isinstance(addons, string_types):
                 addons = [addons]
             self.extend(addons)
 
         @classmethod
         def is_addon(self, addon):
-            # TODO Implement this properly
-            return os.path.exists(addon)
+            # Don't include testing/profiles on Google Chrome
+            return False
 
     def __init__(self, **kwargs):
         super(ChromeProfile, self).__init__(**kwargs)
 
         if self.create_new:
             self.profile = os.path.join(self.profile, 'Default')
         self._reset()
 
--- a/testing/mozbase/mozprofile/tests/test_profile.py
+++ b/testing/mozbase/mozprofile/tests/test_profile.py
@@ -84,15 +84,19 @@ def test_merge_profile(cls):
             prefs.update(Preferences.read_json(path))
         except ValueError:
             prefs.update(Preferences.read_prefs(path))
 
     assert 'foo' in prefs
     assert len(prefs) == len(profile.preference_file_names) + 1
     assert all(name in prefs for name in profile.preference_file_names)
 
-    assert len(profile._addons) == 1
-    assert profile._addons[0].endswith('empty.xpi')
-    assert os.path.exists(profile._addons[0])
+    # for Google Chrome currently we ignore webext in profile prefs
+    if cls == Profile:
+        assert len(profile._addons) == 1
+        assert profile._addons[0].endswith('empty.xpi')
+        assert os.path.exists(profile._addons[0])
+    else:
+        assert len(profile._addons) == 0
 
 
 if __name__ == '__main__':
     mozunit.main()
--- a/testing/mozharness/configs/raptor/mac_config.py
+++ b/testing/mozharness/configs/raptor/mac_config.py
@@ -21,16 +21,17 @@ config = {
         "http://pypi.pub.build.mozilla.org/pub",
     ],
     "pip_index": False,
     "title": os.uname()[1].lower().split('.')[0],
     "default_actions": [
         "clobber",
         "download-and-extract",
         "populate-webroot",
+        "install-chrome",
         "create-virtualenv",
         "install",
         "run-tests",
     ],
     "run_cmd_checks_enabled": True,
     "preflight_run_cmd_suites": [
         SCREEN_RESOLUTION_CHECK,
     ],
--- a/testing/mozharness/mozharness/mozilla/testing/raptor.py
+++ b/testing/mozharness/mozharness/mozilla/testing/raptor.py
@@ -5,16 +5,17 @@
 from __future__ import absolute_import, print_function, unicode_literals
 
 import copy
 import json
 import os
 import re
 import sys
 import subprocess
+import time
 
 from shutil import copyfile
 
 import mozharness
 
 from mozharness.base.errors import PythonErrorList
 from mozharness.base.log import OutputParser, DEBUG, ERROR, CRITICAL, INFO
 from mozharness.base.python import Python3Virtualenv
@@ -22,16 +23,17 @@ from mozharness.mozilla.testing.testbase
 from mozharness.base.vcs.vcsbase import MercurialScript
 from mozharness.mozilla.testing.codecoverage import (
     CodeCoverageMixin,
     code_coverage_config_options
 )
 
 scripts_path = os.path.abspath(os.path.dirname(os.path.dirname(mozharness.__file__)))
 external_tools_path = os.path.join(scripts_path, 'external_tools')
+here = os.path.abspath(os.path.dirname(__file__))
 
 RaptorErrorList = PythonErrorList + [
     {'regex': re.compile(r'''run-as: Package '.*' is unknown'''), 'level': DEBUG},
     {'substr': r'''FAIL: Busted:''', 'level': CRITICAL},
     {'substr': r'''FAIL: failed to cleanup''', 'level': ERROR},
     {'substr': r'''erfConfigurator.py: Unknown error''', 'level': CRITICAL},
     {'substr': r'''raptorError''', 'level': CRITICAL},
     {'regex': re.compile(r'''No machine_name called '.*' can be found'''), 'level': CRITICAL},
@@ -47,73 +49,90 @@ class Raptor(TestingMixin, MercurialScri
     install and run raptor tests
     """
     config_options = [
         [["--test"],
          {"action": "store",
           "dest": "test",
           "help": "Raptor test to run"
           }],
+        [["--app"],
+         {"default": "firefox",
+          "choices": ["firefox", "chrome"],
+          "dest": "app",
+          "help": "name of the application we are testing (default: firefox)"
+          }],
         [["--branch-name"],
          {"action": "store",
           "dest": "branch",
           "help": "branch running against"
           }],
         [["--add-option"],
          {"action": "extend",
-          "dest": "raptor_extra_options",
+          "dest": "raptor_cmd_line_args",
           "default": None,
           "help": "extra options to raptor"
           }],
     ] + testing_config_options + copy.deepcopy(code_coverage_config_options)
 
     def __init__(self, **kwargs):
         kwargs.setdefault('config_options', self.config_options)
         kwargs.setdefault('all_actions', ['clobber',
                                           'download-and-extract',
                                           'populate-webroot',
+                                          'install-chrome',
                                           'create-virtualenv',
                                           'install',
                                           'run-tests',
                                           ])
         kwargs.setdefault('default_actions', ['clobber',
                                               'download-and-extract',
                                               'populate-webroot',
+                                              'install-chrome',
                                               'create-virtualenv',
                                               'install',
                                               'run-tests',
                                               ])
         kwargs.setdefault('config', {})
         super(Raptor, self).__init__(**kwargs)
 
         self.workdir = self.query_abs_dirs()['abs_work_dir']  # convenience
 
         self.run_local = self.config.get('run_local')
+
+        # app (browser testing on) defaults to firefox
+        self.app = "firefox"
+
+        if self.run_local:
+            # raptor initiated locally, get app from command line args
+            # which are passed in from mach inside 'raptor_cmd_line_args'
+            self.app = "firefox"
+            if 'raptor_cmd_line_args' in self.config:
+                for next_arg in self.config['raptor_cmd_line_args']:
+                    if "chrome" in next_arg:
+                        self.app = "chrome"
+                        break
+        else:
+            # raptor initiated in production via mozharness
+            self.test = self.config['test']
+            self.app = self.config.get("app", "firefox")
+
         self.installer_url = self.config.get("installer_url")
         self.raptor_json_url = self.config.get("raptor_json_url")
         self.raptor_json = self.config.get("raptor_json")
         self.raptor_json_config = self.config.get("raptor_json_config")
         self.repo_path = self.config.get("repo_path")
         self.obj_path = self.config.get("obj_path")
-        self.tests = None
+        self.test = None
         self.gecko_profile = self.config.get('gecko_profile')
         self.gecko_profile_interval = self.config.get('gecko_profile_interval')
-        # some platforms download a mitmproxy release binary
-        self.mitmproxy_rel_bin = None
-        # zip file found on tooltool that contains all of the mitmproxy recordings
-        self.mitmproxy_pageset = None
-        # files inside the recording set
-        self.mitmproxy_recordings_file_list = self.config.get('mitmproxy', None)
-        # path to mitmdump tool itself, in py3 venv
-        self.mitmdump = None
 
     # We accept some configuration options from the try commit message in the
-    # format mozharness: <options>
-    # Example try commit message:
-    #   mozharness: --geckoProfile try: <stuff>
+    # format mozharness: <options>. Example try commit message: mozharness:
+    # --geckoProfile try: <stuff>
     def query_gecko_profile_options(self):
         gecko_results = []
         # if gecko_profile is set, we add that to the raptor options
         if self.gecko_profile:
             gecko_results.append('--geckoProfile')
             if self.gecko_profile_interval:
                 gecko_results.extend(
                     ['--geckoProfileInterval', str(self.gecko_profile_interval)]
@@ -125,29 +144,87 @@ class Raptor(TestingMixin, MercurialScri
             return self.abs_dirs
         abs_dirs = super(Raptor, self).query_abs_dirs()
         abs_dirs['abs_blob_upload_dir'] = os.path.join(abs_dirs['abs_work_dir'],
                                                        'blobber_upload_dir')
         abs_dirs['abs_test_install_dir'] = os.path.join(abs_dirs['abs_work_dir'], 'tests')
         self.abs_dirs = abs_dirs
         return self.abs_dirs
 
+    def install_chrome(self):
+        # temporary hack to install google chrome in production; until chrome is in our CI
+        if self.app != "chrome":
+            self.info("Google Chrome is not required")
+            return
+
+        if self.config.get("run_local"):
+            self.info("expecting Google Chrome to be pre-installed locally")
+            return
+
+        chrome_url = "https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg"
+        # in production we can put the chrome build in mozharness/mozilla/testing/chrome
+        self.chrome_dest = os.path.join(here, 'chrome')
+        chrome_dmg = os.path.join(self.chrome_dest, 'googlechrome.dmg')
+
+        self.info("installing google chrome - temporary install hack")
+        self.info("chrome_dest is: %s" % self.chrome_dest)
+
+        self.chrome_path = os.path.join(self.chrome_dest, 'Google Chrome.app',
+                                        'Contents', 'MacOS', 'Google Chrome')
+
+        if os.path.exists(self.chrome_path):
+            self.info("google chrome binary already exists at: %s" % self.chrome_path)
+            return
+
+        if not os.path.exists(chrome_dmg):
+            # download the chrome dmg
+            self.download_file(chrome_url, parent_dir=self.chrome_dest)
+
+        command = ["open", "googlechrome.dmg"]
+        return_code = self.run_command(command, cwd=self.chrome_dest)
+        if return_code not in [0]:
+            self.info("abort: failed to open %s/googlechrome.dmg" % self.chrome_dest)
+            return
+        # give 30 sec for open cmd to finish
+        time.sleep(30)
+
+        # now that the googlechrome dmg is mounted, extract/copy app from mnt to our folder
+        command = ["cp", "-r", "/Volumes/Google Chrome/Google Chrome.app", "."]
+        return_code = self.run_command(command, cwd=self.chrome_dest)
+        if return_code not in [0]:
+            self.info("abort: failed to open %s/googlechrome.dmg" % self.chrome_dest)
+            return
+
+        # now ensure chrome binary exists
+        if os.path.exists(self.chrome_path):
+            self.info("successfully installed Google Chrome to: %s" % self.chrome_path)
+        else:
+            self.info("abort: failed to install Google Chrome")
+
     def raptor_options(self, args=None, **kw):
         """return options to raptor"""
-        # binary path
-        binary_path = self.binary_path or self.config.get('binary_path')
-        if not binary_path:
-            msg = """Raptor requires a path to the binary. You can specify binary_path or add
-            download-and-extract to your action list."""
-            self.fatal(msg)
-        # raptor options
-        if binary_path.endswith('.exe'):
-            binary_path = binary_path[:-4]
         options = []
-        kw_options = {'binary': binary_path}
+        kw_options = {}
+
+        # binary path; if testing on firefox the binary path already came from mozharness/pro;
+        # otherwise the binary path is forwarded from cmd line arg (raptor_cmd_line_args)
+        kw_options['app'] = self.app
+        if self.app == "firefox":
+            binary_path = self.binary_path or self.config.get('binary_path')
+            if not binary_path:
+                self.fatal("Raptor requires a path to the binary.")
+            if binary_path.endswith('.exe'):
+                binary_path = binary_path[:-4]
+            kw_options['binary'] = binary_path
+        else:
+            if not self.run_local:
+                # in production we aready installed google chrome, so set the binary path for arg
+                # when running locally a --binary arg as passed in, already in raptor_cmd_line_args
+                kw_options['binary'] = self.chrome_path
+
         # options overwritten from **kw
         if 'test' in self.config:
             kw_options['test'] = self.config['test']
         if self.config.get('branch'):
             kw_options['branchName'] = self.config['branch']
         if self.symbols_path:
             kw_options['symbolsPath'] = self.symbols_path
         if self.config.get('obj_path', None) is not None:
@@ -155,44 +232,32 @@ class Raptor(TestingMixin, MercurialScri
         kw_options.update(kw)
         # configure profiling options
         options.extend(self.query_gecko_profile_options())
         # extra arguments
         if args is not None:
             options += args
         if self.config.get('run_local', False):
             options.extend(['--run-local'])
-        if 'raptor_extra_options' in self.config:
-            options += self.config['raptor_extra_options']
+        if 'raptor_cmd_line_args' in self.config:
+            options += self.config['raptor_cmd_line_args']
         if self.config.get('code_coverage', False):
             options.extend(['--code-coverage'])
         for key, value in kw_options.items():
             options.extend(['--%s' % key, value])
+
         return options
 
     def populate_webroot(self):
         """Populate the production test slaves' webroots"""
         self.raptor_path = os.path.join(
             self.query_abs_dirs()['abs_test_install_dir'], 'raptor'
         )
-
         if self.config.get('run_local'):
-            # raptor initiated locally, get and verify test from cmd line
             self.raptor_path = os.path.join(self.repo_path, 'testing', 'raptor')
-            if 'raptor_extra_options' in self.config:
-                if '--test' in self.config['raptor_extra_options']:
-                    # --test specified, get test from cmd line and ensure is valid
-                    test_name_index = self.config['raptor_extra_options'].index('--test') + 1
-                    if test_name_index < len(self.config['raptor_extra_options']):
-                        self.test = self.config['raptor_extra_options'][test_name_index]
-                    else:
-                        self.fatal("Test name not provided")
-        else:
-            # raptor initiated in production via mozharness
-            self.test = self.config['test']
 
     # Action methods. {{{1
     # clobber defined in BaseScript
 
     def download_and_extract(self, extract_dirs=None, suite_categories=None):
         return super(Raptor, self).download_and_extract(
             suite_categories=['common', 'raptor']
         )
--- a/testing/raptor/mach_commands.py
+++ b/testing/raptor/mach_commands.py
@@ -44,34 +44,34 @@ class RaptorRunner(MozbuildObject):
         self.virtualenv_script = os.path.join(self.topsrcdir, 'third_party', 'python',
                                               'virtualenv', 'virtualenv.py')
         self.virtualenv_path = os.path.join(self._topobjdir, 'testing',
                                             'raptor-venv')
         self.python_interp = sys.executable
         self.raptor_args = raptor_args
 
     def make_config(self):
-        default_actions = ['populate-webroot', 'create-virtualenv', 'run-tests']
+        default_actions = ['populate-webroot', 'install-chrome', 'create-virtualenv', 'run-tests']
         self.config = {
             'run_local': True,
             'binary_path': self.binary_path,
             'repo_path': self.topsrcdir,
             'raptor_path': self.raptor_dir,
             'obj_path': self.topobjdir,
             'log_name': 'raptor',
             'virtualenv_path': self.virtualenv_path,
             'pypi_url': 'http://pypi.python.org/simple',
             'base_work_dir': self.mozharness_dir,
             'exes': {
                 'python': self.python_interp,
                 'virtualenv': [self.python_interp, self.virtualenv_script],
             },
             'title': socket.gethostname(),
             'default_actions': default_actions,
-            'raptor_extra_options': self.raptor_args,
+            'raptor_cmd_line_args': self.raptor_args,
             'python3_manifest': {
                 'win32': 'python3.manifest',
                 'win64': 'python3_x64.manifest',
             }
         }
 
     def make_args(self):
         self.args = {
--- a/testing/raptor/raptor/cmdline.py
+++ b/testing/raptor/raptor/cmdline.py
@@ -10,37 +10,39 @@ from mozlog.commandline import add_loggi
 
 
 def create_parser(mach_interface=False):
     parser = argparse.ArgumentParser()
     add_arg = parser.add_argument
 
     add_arg('-t', '--test', required=True, dest='test',
             help="name of raptor test to run")
+    add_arg('--app', default='firefox', dest='app',
+            help="name of the application we are testing (default: firefox)",
+            choices=['firefox', 'chrome'])
+    add_arg('-b', '--binary', dest='binary',
+            help="path to the browser executable that we are testing")
     if not mach_interface:
-        add_arg('--app', default='firefox', dest='app',
-                help="name of the application we are testing (default: firefox)",
-                choices=['firefox', 'chrome'])
-        add_arg('-b', '--binary', required=True, dest='binary',
-                help="path to the browser executable that we are testing")
-        add_arg('--branchName', dest="branch_name", default=None,
+        add_arg('--branchName', dest="branch_name", default='',
                 help="Name of the branch we are testing on")
         add_arg('--symbolsPath', dest='symbols_path',
                 help="Path to the symbols for the build we are testing")
         add_arg('--run-local', dest="run_local", default=False, action="store_true",
                 help="Flag that indicates if raptor is running locally or in production")
         add_arg('--obj-path', dest="obj_path", default=None,
                 help="Browser build obj_path (received when running in production)")
 
     add_logging_group(parser)
     return parser
 
 
 def verify_options(parser, args):
     ctx = vars(args)
+    if args.binary is None:
+        parser.error("--binary is required!")
 
     if not os.path.isfile(args.binary):
         parser.error("{binary} does not exist!".format(**ctx))
 
 
 def parse_args(argv=None):
     parser = create_parser()
     args = parser.parse_args(argv)
--- a/testing/raptor/raptor/raptor.ini
+++ b/testing/raptor/raptor/raptor.ini
@@ -1,3 +1,3 @@
 # raptor tests
-[include:tests/raptor-firefox-tp6.ini]
+[include:tests/raptor-tp6.ini]
 [include:tests/raptor-speedometer.ini]
--- a/testing/raptor/raptor/raptor.py
+++ b/testing/raptor/raptor/raptor.py
@@ -115,17 +115,19 @@ class Raptor(object):
                         test['name'],
                         self.control_server.port,
                         benchmark_port)
 
         # must intall raptor addon each time because we dynamically update some content
         raptor_webext = os.path.join(webext_dir, 'raptor')
         self.log.info("installing webext %s" % raptor_webext)
         self.profile.addons.install(raptor_webext)
-        webext_id = self.profile.addons.addon_details(raptor_webext)['id']
+        # on firefox we can get an addon id; chrome addon actually is just cmd line arg
+        if self.config['app'] == "firefox":
+            webext_id = self.profile.addons.addon_details(raptor_webext)['id']
 
         # some tests require tools to playback the test pages
         if test.get('playback', None) is not None:
             self.get_playback_config(test)
             # startup the playback tool
             self.playback = get_playback(self.config)
 
         self.runner.start()
@@ -141,18 +143,20 @@ class Raptor(object):
                 self.runner.check_for_crashes()
             except NotImplementedError:  # not implemented for Chrome
                 pass
 
         if self.playback is not None:
             self.playback.stop()
 
         # remove the raptor webext; as it must be reloaded with each subtest anyway
-        self.log.info("removing webext %s" % raptor_webext)
-        self.profile.addons.remove_addon(webext_id)
+        # applies to firefox only; chrome the addon is actually just cmd line arg
+        if self.config['app'] == "firefox":
+            self.log.info("removing webext %s" % raptor_webext)
+            self.profile.addons.remove_addon(webext_id)
 
         if self.runner.is_running():
             self.log("Application timed out after {} seconds".format(timeout))
             self.runner.stop()
 
     def process_results(self):
         # when running locally output results in build/raptor.json; when running
         # in production output to a local.json to be turned into tc job artifact
@@ -174,16 +178,18 @@ class Raptor(object):
         self.log.info("finished")
 
 
 def main(args=sys.argv[1:]):
     args = parse_args()
     commandline.setup_logging('raptor', args, {'tbpl': sys.stdout})
     LOG = get_default_logger(component='raptor-main')
 
+    LOG.info("received command line arguments: %s" % str(args))
+
     # if a test name specified on command line, and it exists, just run that one
     # otherwise run all available raptor tests that are found for this browser
     raptor_test_list = get_raptor_test_list(args)
 
     # ensure we have at least one valid test to run
     if len(raptor_test_list) == 0:
         LOG.critical("abort: no tests found")
         sys.exit(1)
deleted file mode 100644
--- a/testing/raptor/raptor/tests/raptor-firefox-tp6.ini
+++ /dev/null
@@ -1,39 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# raptor tp6 on firefox
-
-[DEFAULT]
-apps = firefox
-type =  pageload
-playback = mitmproxy
-playback_binary_manifest = mitmproxy-rel-bin-osx.manifest
-playback_binary_zip_mac = mitmproxy-2.0.2-osx.tar.gz
-playback_pageset_manifest = mitmproxy-playback-set.manifest
-playback_pageset_zip_mac = mitmproxy-recording-set-win10.zip
-page_cycles = 25
-unit = ms
-lower_is_better = true
-alert_threshold = 2.0
-
-[raptor-firefox-tp6-amazon]
-test_url = https://www.amazon.com/s/url=search-alias%3Daps&field-keywords=laptop
-playback_recordings = mitmproxy-recording-amazon.mp
-measure = fnbpaint
-
-[raptor-firefox-tp6-facebook]
-test_url = https://www.facebook.com
-playback_recordings = mitmproxy-recording-facebook.mp
-measure = fnbpaint
-
-[raptor-firefox-tp6-google]
-test_url = https://www.google.com/#hl=en&q=barack+obama
-playback_recordings = mitmproxy-recording-google.mp
-measure = fnbpaint, hero
-hero = hero
-
-[raptor-firefox-tp6-youtube]
-test_url = https://www.youtube.com
-playback_recordings = mitmproxy-recording-youtube.mp
-measure = fnbpaint
--- a/testing/raptor/raptor/tests/raptor-speedometer.ini
+++ b/testing/raptor/raptor/tests/raptor-speedometer.ini
@@ -1,15 +1,20 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # speedometer benchmark for firefox and chrome
 
-[raptor-speedometer]
-apps = firefox
+[DEFAULT]
 type =  benchmark
 test_url = http://localhost:<port>/Speedometer/index.html?raptor
-page_cycles = 5
+page_cycles = 1
 page_timeout = 120000
 unit = score
 lower_is_better = false
 alert_threshold = 2.0
+
+[raptor-speedometer-firefox]
+apps = firefox
+
+[raptor-speedometer-chrome]
+apps = chrome
new file mode 100644
--- /dev/null
+++ b/testing/raptor/raptor/tests/raptor-tp6.ini
@@ -0,0 +1,67 @@
+# 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/.
+
+# raptor tp6
+
+[DEFAULT]
+type =  pageload
+playback = mitmproxy
+playback_binary_manifest = mitmproxy-rel-bin-osx.manifest
+playback_binary_zip_mac = mitmproxy-2.0.2-osx.tar.gz
+playback_pageset_manifest = mitmproxy-playback-set.manifest
+playback_pageset_zip_mac = mitmproxy-recording-set-win10.zip
+page_cycles = 25
+unit = ms
+lower_is_better = true
+alert_threshold = 2.0
+
+[raptor-firefox-tp6-amazon]
+apps = firefox
+test_url = https://www.amazon.com/s/url=search-alias%3Daps&field-keywords=laptop
+playback_recordings = mitmproxy-recording-amazon.mp
+measure = fnbpaint
+
+[raptor-firefox-tp6-facebook]
+apps = firefox
+test_url = https://www.facebook.com
+playback_recordings = mitmproxy-recording-facebook.mp
+measure = fnbpaint
+
+[raptor-firefox-tp6-google]
+apps = firefox
+test_url = https://www.google.com/#hl=en&q=barack+obama
+playback_recordings = mitmproxy-recording-google.mp
+measure = fnbpaint, hero
+hero = hero
+
+[raptor-firefox-tp6-youtube]
+apps = firefox
+test_url = https://www.youtube.com
+playback_recordings = mitmproxy-recording-youtube.mp
+measure = fnbpaint
+
+[raptor-chrome-tp6-amazon]
+apps = chrome
+test_url = https://www.amazon.com/s/url=search-alias%3Daps&field-keywords=laptop
+playback_recordings = mitmproxy-recording-amazon.mp
+measure = fcp
+
+[raptor-chrome-tp6-facebook]
+apps = chrome
+test_url = https://www.facebook.com
+playback_recordings = mitmproxy-recording-facebook.mp
+measure = fcp
+
+[raptor-chrome-tp6-google]
+apps = chrome
+test_url = https://www.google.com/#hl=en&q=barack+obama
+playback_recordings = mitmproxy-recording-google.mp
+measure = fcp, hero
+hero = hero
+
+[raptor-chrome-tp6-youtube]
+apps = chrome
+test_url = https://www.youtube.com
+playback_recordings = mitmproxy-recording-youtube.mp
+measure = fcp
--- a/testing/raptor/webext/raptor/manifest.json
+++ b/testing/raptor/webext/raptor/manifest.json
@@ -11,16 +11,17 @@
   "background": {
     "scripts": ["auto_gen_test_config.js", "runner.js"]
   },
   "content_scripts": [
     {
       "matches": ["*://*.amazon.com/*",
                   "*://*.facebook.com/*",
                   "*://*.google.com/*",
+                  "*://*.google.ca/*",
                   "*://*.youtube.com/*"],
       "js": ["measure.js"]
     },
     {
       "matches": ["*://*/Speedometer/index.html*"],
       "js": ["benchmark-relay.js"]
     }
   ],
--- a/toolkit/content/browser-content.js
+++ b/toolkit/content/browser-content.js
@@ -5,366 +5,62 @@
 
 /* eslint-env mozilla/frame-script */
 /* eslint no-unused-vars: ["error", {args: "none"}] */
 /* global sendAsyncMessage */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
+ChromeUtils.defineModuleGetter(this, "AutoScrollController",
+  "resource://gre/modules/AutoScrollController.jsm");
 ChromeUtils.defineModuleGetter(this, "BrowserUtils",
   "resource://gre/modules/BrowserUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "SelectContentHelper",
   "resource://gre/modules/SelectContentHelper.jsm");
 ChromeUtils.defineModuleGetter(this, "FindContent",
   "resource://gre/modules/FindContent.jsm");
 ChromeUtils.defineModuleGetter(this, "PrintingContent",
   "resource://gre/modules/PrintingContent.jsm");
 ChromeUtils.defineModuleGetter(this, "RemoteFinder",
   "resource://gre/modules/RemoteFinder.jsm");
 
 XPCOMUtils.defineLazyProxy(this, "SelectionSourceContent",
   "resource://gre/modules/SelectionSourceContent.jsm");
 
+XPCOMUtils.defineLazyProxy(this, "DateTimePickerContent", () => {
+  let tmp = {};
+  ChromeUtils.import("resource://gre/modules/DateTimePickerContent.jsm", tmp);
+  return new tmp.DateTimePickerContent(this);
+});
+
 var global = this;
 
 
 // Lazily load the finder code
 addMessageListener("Finder:Initialize", function() {
   let {RemoteFinderListener} = ChromeUtils.import("resource://gre/modules/RemoteFinder.jsm", {});
   new RemoteFinderListener(global);
 });
 
-var ClickEventHandler = {
-  init: function init() {
-    this._scrollable = null;
-    this._scrolldir = "";
-    this._startX = null;
-    this._startY = null;
-    this._screenX = null;
-    this._screenY = null;
-    this._lastFrame = null;
-    this._autoscrollHandledByApz = false;
-    this._scrollId = null;
-    this.autoscrollLoop = this.autoscrollLoop.bind(this);
-
-    Services.els.addSystemEventListener(global, "mousedown", this, true);
-
-    addMessageListener("Autoscroll:Stop", this);
-  },
-
-  isAutoscrollBlocker(node) {
-    let mmPaste = Services.prefs.getBoolPref("middlemouse.paste");
-    let mmScrollbarPosition = Services.prefs.getBoolPref("middlemouse.scrollbarPosition");
-
-    while (node) {
-      if ((node instanceof content.HTMLAnchorElement || node instanceof content.HTMLAreaElement) &&
-          node.hasAttribute("href")) {
-        return true;
+var AutoScrollListener = {
+  handleEvent(event) {
+    if (event.isTrusted &
+        !event.defaultPrevented &&
+        event.button == 1) {
+      if (!this._controller) {
+        this._controller = new AutoScrollController(global);
       }
-
-      if (mmPaste && (node instanceof content.HTMLInputElement ||
-                      node instanceof content.HTMLTextAreaElement)) {
-        return true;
-      }
-
-      if (node instanceof content.XULElement && mmScrollbarPosition
-          && (node.localName == "scrollbar" || node.localName == "scrollcorner")) {
-        return true;
-      }
-
-      node = node.parentNode;
-    }
-    return false;
-  },
-
-  isScrollableElement(aNode) {
-    if (aNode instanceof content.HTMLElement) {
-      return !(aNode instanceof content.HTMLSelectElement) || aNode.multiple;
-    }
-
-    return aNode instanceof content.XULElement;
-  },
-
-  getXBLNodes(parent, array) {
-    let anonNodes = content.document.getAnonymousNodes(parent);
-    let nodes = Array.from(anonNodes || parent.childNodes || []);
-    for (let node of nodes) {
-      if (node.nodeName == "children") {
-        return true;
-      }
-      if (this.getXBLNodes(node, array)) {
-        array.push(node);
-        return true;
-      }
+      this._controller.handleEvent(event);
     }
-    return false;
-  },
-
-  * parentNodeIterator(aNode) {
-    while (aNode) {
-      yield aNode;
-
-      let parent = aNode.parentNode;
-      if (parent && parent instanceof content.XULElement) {
-        let anonNodes = content.document.getAnonymousNodes(parent);
-        if (anonNodes && !Array.from(anonNodes).includes(aNode)) {
-          // XBL elements are skipped by parentNode property.
-          // Yield elements between parent and <children> here.
-          let nodes = [];
-          this.getXBLNodes(parent, nodes);
-          for (let node of nodes) {
-            yield node;
-          }
-        }
-      }
-
-      aNode = parent;
-    }
-  },
-
-  findNearestScrollableElement(aNode) {
-    // this is a list of overflow property values that allow scrolling
-    const scrollingAllowed = ["scroll", "auto"];
-
-    // go upward in the DOM and find any parent element that has a overflow
-    // area and can therefore be scrolled
-    this._scrollable = null;
-    for (let node of this.parentNodeIterator(aNode)) {
-      // do not use overflow based autoscroll for <html> and <body>
-      // Elements or non-html/non-xul elements such as svg or Document nodes
-      // also make sure to skip select elements that are not multiline
-      if (!this.isScrollableElement(node)) {
-        continue;
-      }
-
-      var overflowx = node.ownerGlobal
-                          .getComputedStyle(node)
-                          .getPropertyValue("overflow-x");
-      var overflowy = node.ownerGlobal
-                          .getComputedStyle(node)
-                          .getPropertyValue("overflow-y");
-      // we already discarded non-multiline selects so allow vertical
-      // scroll for multiline ones directly without checking for a
-      // overflow property
-      var scrollVert = node.scrollTopMax &&
-        (node instanceof content.HTMLSelectElement ||
-         scrollingAllowed.includes(overflowy));
-
-      // do not allow horizontal scrolling for select elements, it leads
-      // to visual artifacts and is not the expected behavior anyway
-      if (!(node instanceof content.HTMLSelectElement) &&
-          node.scrollLeftMin != node.scrollLeftMax &&
-          scrollingAllowed.includes(overflowx)) {
-        this._scrolldir = scrollVert ? "NSEW" : "EW";
-        this._scrollable = node;
-        break;
-      } else if (scrollVert) {
-        this._scrolldir = "NS";
-        this._scrollable = node;
-        break;
-      }
-    }
-
-    if (!this._scrollable) {
-      this._scrollable = aNode.ownerGlobal;
-      if (this._scrollable.scrollMaxX != this._scrollable.scrollMinX) {
-        this._scrolldir = this._scrollable.scrollMaxY !=
-                          this._scrollable.scrollMinY ? "NSEW" : "EW";
-      } else if (this._scrollable.scrollMaxY != this._scrollable.scrollMinY) {
-        this._scrolldir = "NS";
-      } else if (this._scrollable.frameElement) {
-        this.findNearestScrollableElement(this._scrollable.frameElement);
-      } else {
-        this._scrollable = null; // abort scrolling
-      }
-    }
-  },
-
-  startScroll(event) {
-
-    this.findNearestScrollableElement(event.originalTarget);
-
-    if (!this._scrollable)
-      return;
-
-    // In some configurations like Print Preview, content.performance
-    // (which we use below) is null. Autoscrolling is broken in Print
-    // Preview anyways (see bug 1393494), so just don't start it at all.
-    if (!content.performance)
-      return;
+  }
+};
+Services.els.addSystemEventListener(global, "mousedown", AutoScrollListener, true);
 
-    let domUtils = content.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIDOMWindowUtils);
-    let scrollable = this._scrollable;
-    if (scrollable instanceof Ci.nsIDOMWindow) {
-      // getViewId() needs an element to operate on.
-      scrollable = scrollable.document.documentElement;
-    }
-    this._scrollId = null;
-    try {
-      this._scrollId = domUtils.getViewId(scrollable);
-    } catch (e) {
-      // No view ID - leave this._scrollId as null. Receiving side will check.
-    }
-    let presShellId = domUtils.getPresShellId();
-    let [result] = sendSyncMessage("Autoscroll:Start",
-                                   {scrolldir: this._scrolldir,
-                                    screenX: event.screenX,
-                                    screenY: event.screenY,
-                                    scrollId: this._scrollId,
-                                    presShellId});
-    if (!result.autoscrollEnabled) {
-      this._scrollable = null;
-      return;
-    }
-
-    Services.els.addSystemEventListener(global, "mousemove", this, true);
-    addEventListener("pagehide", this, true);
-
-    this._ignoreMouseEvents = true;
-    this._startX = event.screenX;
-    this._startY = event.screenY;
-    this._screenX = event.screenX;
-    this._screenY = event.screenY;
-    this._scrollErrorX = 0;
-    this._scrollErrorY = 0;
-    this._autoscrollHandledByApz = result.usingApz;
-
-    if (!result.usingApz) {
-      // If the browser didn't hand the autoscroll off to APZ,
-      // scroll here in the main thread.
-      this.startMainThreadScroll();
-    } else {
-      // Even if the browser did hand the autoscroll to APZ,
-      // APZ might reject it in which case it will notify us
-      // and we need to take over.
-      Services.obs.addObserver(this, "autoscroll-rejected-by-apz");
-    }
-  },
-
-  startMainThreadScroll() {
-    this._lastFrame = content.performance.now();
-    content.requestAnimationFrame(this.autoscrollLoop);
-  },
-
-  stopScroll() {
-    if (this._scrollable) {
-      this._scrollable.mozScrollSnap();
-      this._scrollable = null;
-
-      Services.els.removeSystemEventListener(global, "mousemove", this, true);
-      removeEventListener("pagehide", this, true);
-      if (this._autoscrollHandledByApz) {
-        Services.obs.removeObserver(this, "autoscroll-rejected-by-apz");
-      }
-    }
-  },
-
-  accelerate(curr, start) {
-    const speed = 12;
-    var val = (curr - start) / speed;
-
-    if (val > 1)
-      return val * Math.sqrt(val) - 1;
-    if (val < -1)
-      return val * Math.sqrt(-val) + 1;
-    return 0;
-  },
-
-  roundToZero(num) {
-    if (num > 0)
-      return Math.floor(num);
-    return Math.ceil(num);
-  },
-
-  autoscrollLoop(timestamp) {
-    if (!this._scrollable) {
-      // Scrolling has been canceled
-      return;
-    }
-
-    // avoid long jumps when the browser hangs for more than
-    // |maxTimeDelta| ms
-    const maxTimeDelta = 100;
-    var timeDelta = Math.min(maxTimeDelta, timestamp - this._lastFrame);
-    // we used to scroll |accelerate()| pixels every 20ms (50fps)
-    var timeCompensation = timeDelta / 20;
-    this._lastFrame = timestamp;
-
-    var actualScrollX = 0;
-    var actualScrollY = 0;
-    // don't bother scrolling vertically when the scrolldir is only horizontal
-    // and the other way around
-    if (this._scrolldir != "EW") {
-      var y = this.accelerate(this._screenY, this._startY) * timeCompensation;
-      var desiredScrollY = this._scrollErrorY + y;
-      actualScrollY = this.roundToZero(desiredScrollY);
-      this._scrollErrorY = (desiredScrollY - actualScrollY);
-    }
-    if (this._scrolldir != "NS") {
-      var x = this.accelerate(this._screenX, this._startX) * timeCompensation;
-      var desiredScrollX = this._scrollErrorX + x;
-      actualScrollX = this.roundToZero(desiredScrollX);
-      this._scrollErrorX = (desiredScrollX - actualScrollX);
-    }
-
-    this._scrollable.scrollBy({
-      left: actualScrollX,
-      top: actualScrollY,
-      behavior: "instant"
-    });
-
-    content.requestAnimationFrame(this.autoscrollLoop);
-  },
-
-  handleEvent(event) {
-    if (event.type == "mousemove") {
-      this._screenX = event.screenX;
-      this._screenY = event.screenY;
-    } else if (event.type == "mousedown") {
-      if (event.isTrusted &
-          !event.defaultPrevented &&
-          event.button == 1 &&
-          !this._scrollable &&
-          !this.isAutoscrollBlocker(event.originalTarget)) {
-        this.startScroll(event);
-      }
-    } else if (event.type == "pagehide") {
-      if (this._scrollable) {
-        var doc =
-          this._scrollable.ownerDocument || this._scrollable.document;
-        if (doc == event.target) {
-          sendAsyncMessage("Autoscroll:Cancel");
-        }
-      }
-    }
-  },
-
-  receiveMessage(msg) {
-    switch (msg.name) {
-      case "Autoscroll:Stop": {
-        this.stopScroll();
-        break;
-      }
-    }
-  },
-
-  observe(subject, topic, data) {
-    if (topic === "autoscroll-rejected-by-apz") {
-      // The caller passes in the scroll id via 'data'.
-      if (data == this._scrollId) {
-        this._autoscrollHandledByApz = false;
-        this.startMainThreadScroll();
-        Services.obs.removeObserver(this, "autoscroll-rejected-by-apz");
-      }
-    }
-  },
-};
-ClickEventHandler.init();
+addEventListener("MozOpenDateTimePicker", DateTimePickerContent);
 
 var PopupBlocking = {
   popupData: null,
   popupDataInternal: null,
 
   init() {
     addEventListener("DOMPopupBlocked", this, true);
     addEventListener("pageshow", this, true);
@@ -1108,180 +804,16 @@ let AutoCompletePopup = {
     }
 
     return results;
   },
 };
 
 AutoCompletePopup.init();
 
-/**
- * DateTimePickerListener is the communication channel between the input box
- * (content) for date/time input types and its picker (chrome).
- */
-let DateTimePickerListener = {
-  /**
-   * On init, just listen for the event to open the picker, once the picker is
-   * opened, we'll listen for update and close events.
-   */
-  init() {
-    addEventListener("MozOpenDateTimePicker", this);
-    this._inputElement = null;
-
-    addEventListener("unload", () => {
-      this.uninit();
-    });
-  },
-
-  uninit() {
-    removeEventListener("MozOpenDateTimePicker", this);
-    this._inputElement = null;
-  },
-
-  /**
-   * Cleanup function called when picker is closed.
-   */
-  close() {
-    this.removeListeners();
-    this._inputElement.setDateTimePickerState(false);
-    this._inputElement = null;
-  },
-
-  /**
-   * Called after picker is opened to start listening for input box update
-   * events.
-   */
-  addListeners() {
-    addEventListener("MozUpdateDateTimePicker", this);
-    addEventListener("MozCloseDateTimePicker", this);
-    addEventListener("pagehide", this);
-
-    addMessageListener("FormDateTime:PickerValueChanged", this);
-    addMessageListener("FormDateTime:PickerClosed", this);
-  },
-
-  /**
-   * Stop listeneing for events when picker is closed.
-   */
-  removeListeners() {
-    removeEventListener("MozUpdateDateTimePicker", this);
-    removeEventListener("MozCloseDateTimePicker", this);
-    removeEventListener("pagehide", this);
-
-    removeMessageListener("FormDateTime:PickerValueChanged", this);
-    removeMessageListener("FormDateTime:PickerClosed", this);
-  },
-
-  /**
-   * Helper function that returns the CSS direction property of the element.
-   */
-  getComputedDirection(aElement) {
-    return aElement.ownerGlobal.getComputedStyle(aElement)
-      .getPropertyValue("direction");
-  },
-
-  /**
-   * Helper function that returns the rect of the element, which is the position
-   * relative to the left/top of the content area.
-   */
-  getBoundingContentRect(aElement) {
-    return BrowserUtils.getElementBoundingRect(aElement);
-  },
-
-  getTimePickerPref() {
-    return Services.prefs.getBoolPref("dom.forms.datetime.timepicker");
-  },
-
-  /**
-   * nsIMessageListener.
-   */
-  receiveMessage(aMessage) {
-    switch (aMessage.name) {
-      case "FormDateTime:PickerClosed": {
-        this.close();
-        break;
-      }
-      case "FormDateTime:PickerValueChanged": {
-        this._inputElement.updateDateTimeInputBox(aMessage.data);
-        break;
-      }
-      default:
-        break;
-    }
-  },
-
-  /**
-   * nsIDOMEventListener, for chrome events sent by the input element and other
-   * DOM events.
-   */
-  handleEvent(aEvent) {
-    switch (aEvent.type) {
-      case "MozOpenDateTimePicker": {
-        // Time picker is disabled when preffed off
-        if (!(aEvent.originalTarget instanceof content.HTMLInputElement) ||
-            (aEvent.originalTarget.type == "time" && !this.getTimePickerPref())) {
-          return;
-        }
-
-        if (this._inputElement) {
-          // This happens when we're trying to open a picker when another picker
-          // is still open. We ignore this request to let the first picker
-          // close gracefully.
-          return;
-        }
-
-        this._inputElement = aEvent.originalTarget;
-        this._inputElement.setDateTimePickerState(true);
-        this.addListeners();
-
-        let value = this._inputElement.getDateTimeInputBoxValue();
-        sendAsyncMessage("FormDateTime:OpenPicker", {
-          rect: this.getBoundingContentRect(this._inputElement),
-          dir: this.getComputedDirection(this._inputElement),
-          type: this._inputElement.type,
-          detail: {
-            // Pass partial value if it's available, otherwise pass input
-            // element's value.
-            value: Object.keys(value).length > 0 ? value
-                                                 : this._inputElement.value,
-            min: this._inputElement.getMinimum(),
-            max: this._inputElement.getMaximum(),
-            step: this._inputElement.getStep(),
-            stepBase: this._inputElement.getStepBase(),
-          },
-        });
-        break;
-      }
-      case "MozUpdateDateTimePicker": {
-        let value = this._inputElement.getDateTimeInputBoxValue();
-        value.type = this._inputElement.type;
-        sendAsyncMessage("FormDateTime:UpdatePicker", { value });
-        break;
-      }
-      case "MozCloseDateTimePicker": {
-        sendAsyncMessage("FormDateTime:ClosePicker");
-        this.close();
-        break;
-      }
-      case "pagehide": {
-        if (this._inputElement &&
-            this._inputElement.ownerDocument == aEvent.target) {
-          sendAsyncMessage("FormDateTime:ClosePicker");
-          this.close();
-        }
-        break;
-      }
-      default:
-        break;
-    }
-  },
-};
-
-DateTimePickerListener.init();
-
 addEventListener("mozshowdropdown", event => {
   if (!event.isTrusted)
     return;
 
   if (!SelectContentHelper.open) {
     new SelectContentHelper(event.target, {isOpenedViaTouch: false}, this);
   }
 });
--- a/toolkit/content/widgets/datetimepopup.xml
+++ b/toolkit/content/widgets/datetimepopup.xml
@@ -28,17 +28,17 @@
       </property>
       <field name="TIME_PICKER_WIDTH" readonly="true">"12em"</field>
       <field name="TIME_PICKER_HEIGHT" readonly="true">"21em"</field>
       <field name="DATE_PICKER_WIDTH" readonly="true">"23.1em"</field>
       <field name="DATE_PICKER_HEIGHT" readonly="true">"20.7em"</field>
       <constructor><![CDATA[
         this.mozIntl = Cc["@mozilla.org/mozintl;1"]
                          .getService(Ci.mozIMozIntl);
-        // Notify DateTimePickerHelper.jsm that binding is ready.
+        // Notify DateTimePickerParent.jsm that binding is ready.
         this.dispatchEvent(new CustomEvent("DateTimePickerBindingReady"));
       ]]></constructor>
       <method name="openPicker">
         <parameter name="type"/>
         <parameter name="anchor"/>
         <parameter name="detail"/>
         <body><![CDATA[
           this.type = type;
copy from toolkit/content/browser-content.js
copy to toolkit/modules/AutoScrollController.jsm
--- a/toolkit/content/browser-content.js
+++ b/toolkit/modules/AutoScrollController.jsm
@@ -1,64 +1,41 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
 
-/* eslint-env mozilla/frame-script */
 /* eslint no-unused-vars: ["error", {args: "none"}] */
-/* global sendAsyncMessage */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
-ChromeUtils.defineModuleGetter(this, "BrowserUtils",
-  "resource://gre/modules/BrowserUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "SelectContentHelper",
-  "resource://gre/modules/SelectContentHelper.jsm");
-ChromeUtils.defineModuleGetter(this, "FindContent",
-  "resource://gre/modules/FindContent.jsm");
-ChromeUtils.defineModuleGetter(this, "PrintingContent",
-  "resource://gre/modules/PrintingContent.jsm");
-ChromeUtils.defineModuleGetter(this, "RemoteFinder",
-  "resource://gre/modules/RemoteFinder.jsm");
+var EXPORTED_SYMBOLS = ["AutoScrollController"];
 
-XPCOMUtils.defineLazyProxy(this, "SelectionSourceContent",
-  "resource://gre/modules/SelectionSourceContent.jsm");
-
-var global = this;
-
-
-// Lazily load the finder code
-addMessageListener("Finder:Initialize", function() {
-  let {RemoteFinderListener} = ChromeUtils.import("resource://gre/modules/RemoteFinder.jsm", {});
-  new RemoteFinderListener(global);
-});
-
-var ClickEventHandler = {
-  init: function init() {
+class AutoScrollController {
+  constructor(global) {
     this._scrollable = null;
     this._scrolldir = "";
     this._startX = null;
     this._startY = null;
     this._screenX = null;
     this._screenY = null;
     this._lastFrame = null;
     this._autoscrollHandledByApz = false;
     this._scrollId = null;
+    this._global = global;
     this.autoscrollLoop = this.autoscrollLoop.bind(this);
 
-    Services.els.addSystemEventListener(global, "mousedown", this, true);
-
-    addMessageListener("Autoscroll:Stop", this);
-  },
+    global.addMessageListener("Autoscroll:Stop", this);
+  }
 
   isAutoscrollBlocker(node) {
     let mmPaste = Services.prefs.getBoolPref("middlemouse.paste");
     let mmScrollbarPosition = Services.prefs.getBoolPref("middlemouse.scrollbarPosition");
+    let content = node.ownerGlobal;
 
     while (node) {
       if ((node instanceof content.HTMLAnchorElement || node instanceof content.HTMLAreaElement) &&
           node.hasAttribute("href")) {
         return true;
       }
 
       if (mmPaste && (node instanceof content.HTMLInputElement ||
@@ -69,42 +46,46 @@ var ClickEventHandler = {
       if (node instanceof content.XULElement && mmScrollbarPosition
           && (node.localName == "scrollbar" || node.localName == "scrollcorner")) {
         return true;
       }
 
       node = node.parentNode;
     }
     return false;
-  },
+  }
 
   isScrollableElement(aNode) {
+    let content = aNode.ownerGlobal;
     if (aNode instanceof content.HTMLElement) {
       return !(aNode instanceof content.HTMLSelectElement) || aNode.multiple;
     }
 
     return aNode instanceof content.XULElement;
-  },
+  }
 
   getXBLNodes(parent, array) {
+    let content = parent.ownerGlobal;
     let anonNodes = content.document.getAnonymousNodes(parent);
     let nodes = Array.from(anonNodes || parent.childNodes || []);
     for (let node of nodes) {
       if (node.nodeName == "children") {
         return true;
       }
       if (this.getXBLNodes(node, array)) {
         array.push(node);
         return true;
       }
     }
     return false;
-  },
+  }
 
   * parentNodeIterator(aNode) {
+    let content = aNode.ownerGlobal;
+
     while (aNode) {
       yield aNode;
 
       let parent = aNode.parentNode;
       if (parent && parent instanceof content.XULElement) {
         let anonNodes = content.document.getAnonymousNodes(parent);
         if (anonNodes && !Array.from(anonNodes).includes(aNode)) {
           // XBL elements are skipped by parentNode property.
@@ -114,19 +95,21 @@ var ClickEventHandler = {
           for (let node of nodes) {
             yield node;
           }
         }
       }
 
       aNode = parent;
     }
-  },
+  }
 
   findNearestScrollableElement(aNode) {
+    let content = aNode.ownerGlobal;
+
     // this is a list of overflow property values that allow scrolling
     const scrollingAllowed = ["scroll", "auto"];
 
     // go upward in the DOM and find any parent element that has a overflow
     // area and can therefore be scrolled
     this._scrollable = null;
     for (let node of this.parentNodeIterator(aNode)) {
       // do not use overflow based autoscroll for <html> and <body>
@@ -172,25 +155,27 @@ var ClickEventHandler = {
       } else if (this._scrollable.scrollMaxY != this._scrollable.scrollMinY) {
         this._scrolldir = "NS";
       } else if (this._scrollable.frameElement) {
         this.findNearestScrollableElement(this._scrollable.frameElement);
       } else {
         this._scrollable = null; // abort scrolling
       }
     }
-  },
+  }
 
   startScroll(event) {
 
     this.findNearestScrollableElement(event.originalTarget);
 
     if (!this._scrollable)
       return;
 
+    let content = event.originalTarget.ownerGlobal;
+
     // In some configurations like Print Preview, content.performance
     // (which we use below) is null. Autoscrolling is broken in Print
     // Preview anyways (see bug 1393494), so just don't start it at all.
     if (!content.performance)
       return;
 
     let domUtils = content.QueryInterface(Ci.nsIInterfaceRequestor)
                           .getInterface(Ci.nsIDOMWindowUtils);
@@ -201,29 +186,29 @@ var ClickEventHandler = {
     }
     this._scrollId = null;
     try {
       this._scrollId = domUtils.getViewId(scrollable);
     } catch (e) {
       // No view ID - leave this._scrollId as null. Receiving side will check.
     }
     let presShellId = domUtils.getPresShellId();
-    let [result] = sendSyncMessage("Autoscroll:Start",
-                                   {scrolldir: this._scrolldir,
-                                    screenX: event.screenX,
-                                    screenY: event.screenY,
-                                    scrollId: this._scrollId,
-                                    presShellId});
+    let [result] = this._global.sendSyncMessage("Autoscroll:Start",
+                                                {scrolldir: this._scrolldir,
+                                                 screenX: event.screenX,
+                                                 screenY: event.screenY,
+                                                 scrollId: this._scrollId,
+                                                 presShellId});
     if (!result.autoscrollEnabled) {
       this._scrollable = null;
       return;
     }
 
-    Services.els.addSystemEventListener(global, "mousemove", this, true);
-    addEventListener("pagehide", this, true);
+    Services.els.addSystemEventListener(this._global, "mousemove", this, true);
+    this._global.addEventListener("pagehide", this, true);
 
     this._ignoreMouseEvents = true;
     this._startX = event.screenX;
     this._startY = event.screenY;
     this._screenX = event.screenX;
     this._screenY = event.screenY;
     this._scrollErrorX = 0;
     this._scrollErrorY = 0;
@@ -234,52 +219,53 @@ var ClickEventHandler = {
       // scroll here in the main thread.
       this.startMainThreadScroll();
     } else {
       // Even if the browser did hand the autoscroll to APZ,
       // APZ might reject it in which case it will notify us
       // and we need to take over.
       Services.obs.addObserver(this, "autoscroll-rejected-by-apz");
     }
-  },
+  }
 
   startMainThreadScroll() {
+    let content = this._global.content;
     this._lastFrame = content.performance.now();
     content.requestAnimationFrame(this.autoscrollLoop);
-  },
+  }
 
   stopScroll() {
     if (this._scrollable) {
       this._scrollable.mozScrollSnap();
       this._scrollable = null;
 
-      Services.els.removeSystemEventListener(global, "mousemove", this, true);
-      removeEventListener("pagehide", this, true);
+      Services.els.removeSystemEventListener(this._global, "mousemove", this, true);
+      this._global.removeEventListener("pagehide", this, true);
       if (this._autoscrollHandledByApz) {
         Services.obs.removeObserver(this, "autoscroll-rejected-by-apz");
       }
     }
-  },
+  }
 
   accelerate(curr, start) {
     const speed = 12;
     var val = (curr - start) / speed;
 
     if (val > 1)
       return val * Math.sqrt(val) - 1;
     if (val < -1)
       return val * Math.sqrt(-val) + 1;
     return 0;
-  },
+  }
 
   roundToZero(num) {
     if (num > 0)
       return Math.floor(num);
     return Math.ceil(num);
-  },
+  }
 
   autoscrollLoop(timestamp) {
     if (!this._scrollable) {
       // Scrolling has been canceled
       return;
     }
 
     // avoid long jumps when the browser hangs for more than
@@ -308,1023 +294,51 @@ var ClickEventHandler = {
     }
 
     this._scrollable.scrollBy({
       left: actualScrollX,
       top: actualScrollY,
       behavior: "instant"
     });
 
-    content.requestAnimationFrame(this.autoscrollLoop);
-  },
+    this._scrollable.ownerGlobal.requestAnimationFrame(this.autoscrollLoop);
+  }
 
   handleEvent(event) {
     if (event.type == "mousemove") {
       this._screenX = event.screenX;
       this._screenY = event.screenY;
     } else if (event.type == "mousedown") {
-      if (event.isTrusted &
-          !event.defaultPrevented &&
-          event.button == 1 &&
-          !this._scrollable &&
+      if (!this._scrollable &&
           !this.isAutoscrollBlocker(event.originalTarget)) {
         this.startScroll(event);
       }
     } else if (event.type == "pagehide") {
       if (this._scrollable) {
         var doc =
           this._scrollable.ownerDocument || this._scrollable.document;
         if (doc == event.target) {
-          sendAsyncMessage("Autoscroll:Cancel");
+          this._global.sendAsyncMessage("Autoscroll:Cancel");
         }
       }
     }
-  },
+  }
 
   receiveMessage(msg) {
     switch (msg.name) {
       case "Autoscroll:Stop": {
         this.stopScroll();
         break;
       }
     }
-  },
+  }
 
   observe(subject, topic, data) {
     if (topic === "autoscroll-rejected-by-apz") {
       // The caller passes in the scroll id via 'data'.
       if (data == this._scrollId) {
         this._autoscrollHandledByApz = false;
         this.startMainThreadScroll();
         Services.obs.removeObserver(this, "autoscroll-rejected-by-apz");
       }
     }
-  },
-};
-ClickEventHandler.init();
-
-var PopupBlocking = {
-  popupData: null,
-  popupDataInternal: null,
-
-  init() {
-    addEventListener("DOMPopupBlocked", this, true);
-    addEventListener("pageshow", this, true);
-    addEventListener("pagehide", this, true);
-
-    addMessageListener("PopupBlocking:UnblockPopup", this);
-    addMessageListener("PopupBlocking:GetBlockedPopupList", this);
-  },
-
-  receiveMessage(msg) {
-    switch (msg.name) {
-      case "PopupBlocking:UnblockPopup": {
-        let i = msg.data.index;
-        if (this.popupData && this.popupData[i]) {
-          let data = this.popupData[i];
-          let internals = this.popupDataInternal[i];
-          let dwi = internals.requestingWindow;
-
-          // If we have a requesting window and the requesting document is
-          // still the current document, open the popup.
-          if (dwi && dwi.document == internals.requestingDocument) {
-            dwi.open(data.popupWindowURIspec, data.popupWindowName, data.popupWindowFeatures);
-          }
-        }
-        break;
-      }
-
-      case "PopupBlocking:GetBlockedPopupList": {
-        let popupData = [];
-        let length = this.popupData ? this.popupData.length : 0;
-
-        // Limit 15 popup URLs to be reported through the UI
-        length = Math.min(length, 15);
-
-        for (let i = 0; i < length; i++) {
-          let popupWindowURIspec = this.popupData[i].popupWindowURIspec;
-
-          if (popupWindowURIspec == global.content.location.href) {
-            popupWindowURIspec = "<self>";
-          } else {
-            // Limit 500 chars to be sent because the URI will be cropped
-            // by the UI anyway, and data: URIs can be significantly larger.
-            popupWindowURIspec = popupWindowURIspec.substring(0, 500);
-          }
-
-          popupData.push({popupWindowURIspec});
-        }
-
-        sendAsyncMessage("PopupBlocking:ReplyGetBlockedPopupList", {popupData});
-        break;
-      }
-    }
-  },
-
-  handleEvent(ev) {
-    switch (ev.type) {
-      case "DOMPopupBlocked":
-        return this.onPopupBlocked(ev);
-      case "pageshow":
-        return this._removeIrrelevantPopupData();
-      case "pagehide":
-        return this._removeIrrelevantPopupData(ev.target);
-    }
-    return undefined;
-  },
-
-  onPopupBlocked(ev) {
-    if (!this.popupData) {
-      this.popupData = [];
-      this.popupDataInternal = [];
-    }
-
-    let obj = {
-      popupWindowURIspec: ev.popupWindowURI ? ev.popupWindowURI.spec : "about:blank",
-      popupWindowFeatures: ev.popupWindowFeatures,
-      popupWindowName: ev.popupWindowName
-    };
-
-    let internals = {
-      requestingWindow: ev.requestingWindow,
-      requestingDocument: ev.requestingWindow.document,
-    };
-
-    this.popupData.push(obj);
-    this.popupDataInternal.push(internals);
-    this.updateBlockedPopups(true);
-  },
-
-  _removeIrrelevantPopupData(removedDoc = null) {
-    if (this.popupData) {
-      let i = 0;
-      let oldLength = this.popupData.length;
-      while (i < this.popupData.length) {
-        let {requestingWindow, requestingDocument} = this.popupDataInternal[i];
-        // Filter out irrelevant reports.
-        if (requestingWindow && requestingWindow.document == requestingDocument &&
-            requestingDocument != removedDoc) {
-          i++;
-        } else {
-          this.popupData.splice(i, 1);
-          this.popupDataInternal.splice(i, 1);
-        }
-      }
-      if (this.popupData.length == 0) {
-        this.popupData = null;
-        this.popupDataInternal = null;
-      }
-      if (!this.popupData || oldLength > this.popupData.length) {
-        this.updateBlockedPopups(false);
-      }
-    }
-  },
-
-  updateBlockedPopups(freshPopup) {
-    sendAsyncMessage("PopupBlocking:UpdateBlockedPopups",
-      {
-        count: this.popupData ? this.popupData.length : 0,
-        freshPopup
-      });
-  },
-};
-PopupBlocking.init();
-
-var Printing = {
-  MESSAGES: [
-    "Printing:Preview:Enter",
-    "Printing:Preview:Exit",
-    "Printing:Preview:Navigate",
-    "Printing:Preview:ParseDocument",
-    "Printing:Print",
-  ],
-
-  init() {
-    this.MESSAGES.forEach(msgName => addMessageListener(msgName, this));
-    addEventListener("PrintingError", this, true);
-    addEventListener("printPreviewUpdate", this, true);
-  },
-
-  handleEvent(event) {
-    return PrintingContent.handleEvent(global, event);
-  },
-
-  receiveMessage(message) {
-    return PrintingContent.receiveMessage(global, message);
-  },
-};
-Printing.init();
-
-function SwitchDocumentDirection(aWindow) {
- // document.dir can also be "auto", in which case it won't change
-  if (aWindow.document.dir == "ltr" || aWindow.document.dir == "") {
-    aWindow.document.dir = "rtl";
-  } else if (aWindow.document.dir == "rtl") {
-    aWindow.document.dir = "ltr";
-  }
-  for (let run = 0; run < aWindow.frames.length; run++) {
-    SwitchDocumentDirection(aWindow.frames[run]);
   }
 }
-
-addMessageListener("SwitchDocumentDirection", () => {
-  SwitchDocumentDirection(content.window);
-});
-
-var FindBar = {
-  /* Please keep in sync with toolkit/content/widgets/findbar.xml */
-  FIND_NORMAL: 0,
-  FIND_TYPEAHEAD: 1,
-  FIND_LINKS: 2,
-
-  _findMode: 0,
-
-  /**
-   * _findKey and _findModifiers are used to determine whether a keypress
-   * is a user attempting to use the find shortcut, after which we'll
-   * route keypresses to the parent until we know the findbar has focus
-   * there. To do this, we need shortcut data from the parent.
-   */
-  _findKey: null,
-  _findModifiers: null,
-
-  init() {
-    addMessageListener("Findbar:UpdateState", this);
-    Services.els.addSystemEventListener(global, "keypress", this, false);
-    Services.els.addSystemEventListener(global, "mouseup", this, false);
-    this._initShortcutData();
-  },
-
-  receiveMessage(msg) {
-    switch (msg.name) {
-      case "Findbar:UpdateState":
-        this._findMode = msg.data.findMode;
-        this._quickFindTimeout = msg.data.hasQuickFindTimeout;
-        if (msg.data.isOpenAndFocused) {
-          this._keepPassingUntilToldOtherwise = false;
-        }
-        break;
-      case "Findbar:ShortcutData":
-        // Set us up to never need this again for the lifetime of this process,
-        // and remove the listener.
-        Services.cpmm.initialProcessData.findBarShortcutData = msg.data;
-        Services.cpmm.removeMessageListener("Findbar:ShortcutData", this);
-        this._initShortcutData(msg.data);
-        break;
-    }
-  },
-
-  handleEvent(event) {
-    switch (event.type) {
-      case "keypress":
-        this._onKeypress(event);
-        break;
-      case "mouseup":
-        this._onMouseup(event);
-        break;
-    }
-  },
-
-  /**
-   * Use initial process data for find key/modifier data if we have it.
-   * Otherwise, add a listener so we get the data when the parent process has
-   * it.
-   */
-  _initShortcutData(data = Services.cpmm.initialProcessData.findBarShortcutData) {
-    if (data) {
-      this._findKey = data.key;
-      this._findModifiers = data.modifiers;
-    } else {
-      Services.cpmm.addMessageListener("Findbar:ShortcutData", this);
-    }
-  },
-
-  /**
-   * Check whether this key event will start the findbar in the parent,
-   * in which case we should pass any further key events to the parent to avoid
-   * them being lost.
-   * @param aEvent the key event to check.
-   */
-  _eventMatchesFindShortcut(aEvent) {
-    let modifiers = this._findModifiers;
-    if (!modifiers) {
-      return false;
-    }
-    return aEvent.ctrlKey == modifiers.ctrlKey && aEvent.altKey == modifiers.altKey &&
-      aEvent.shiftKey == modifiers.shiftKey && aEvent.metaKey == modifiers.metaKey &&
-      aEvent.key == this._findKey;
-  },
-
-  /**
-   * Returns whether FAYT can be used for the given event in
-   * the current content state.
-   */
-  _canAndShouldFastFind() {
-    let should = false;
-    let can = BrowserUtils.canFastFind(content);
-    if (can) {
-      // XXXgijs: why all these shenanigans? Why not use the event's target?
-      let focusedWindow = {};
-      let elt = Services.focus.getFocusedElementForWindow(content, true, focusedWindow);
-      let win = focusedWindow.value;
-      should = BrowserUtils.shouldFastFind(elt, win);
-    }
-    return { can, should };
-  },
-
-  _onKeypress(event) {
-    const FAYT_LINKS_KEY = "'";
-    const FAYT_TEXT_KEY = "/";
-    if (this._eventMatchesFindShortcut(event)) {
-      this._keepPassingUntilToldOtherwise = true;
-    }
-    // Useless keys:
-    if (event.ctrlKey || event.altKey || event.metaKey || event.defaultPrevented) {
-      return;
-    }
-
-    // Check the focused element etc.
-    let fastFind = this._canAndShouldFastFind();
-
-    // Can we even use find in this page at all?
-    if (!fastFind.can) {
-      return;
-    }
-    if (this._keepPassingUntilToldOtherwise) {
-      this._passKeyToParent(event);
-      return;
-    }
-    if (!fastFind.should) {
-      return;
-    }
-
-    let charCode = event.charCode;
-    // If the find bar is open and quick find is on, send the key to the parent.
-    if (this._findMode != this.FIND_NORMAL && this._quickFindTimeout) {
-      if (!charCode)
-        return;
-      this._passKeyToParent(event);
-    } else {
-      let key = charCode ? String.fromCharCode(charCode) : null;
-      let manualstartFAYT = (key == FAYT_LINKS_KEY || key == FAYT_TEXT_KEY);
-      let autostartFAYT = !manualstartFAYT && RemoteFinder._findAsYouType && key && key != " ";
-      if (manualstartFAYT || autostartFAYT) {
-        let mode = (key == FAYT_LINKS_KEY || (autostartFAYT && RemoteFinder._typeAheadLinksOnly)) ?
-          this.FIND_LINKS : this.FIND_TYPEAHEAD;
-        // Set _findMode immediately (without waiting for child->parent->child roundtrip)
-        // to ensure we pass any further keypresses, too.
-        this._findMode = mode;
-        this._passKeyToParent(event);
-      }
-    }
-  },
-
-  _passKeyToParent(event) {
-    event.preventDefault();
-    // These are the properties required to dispatch another 'real' event
-    // to the findbar in the parent in _dispatchKeypressEvent in findbar.xml .
-    // If you make changes here, verify that that method can still do its job.
-    const kRequiredProps = [
-      "type", "bubbles", "cancelable", "ctrlKey", "altKey", "shiftKey",
-      "metaKey", "keyCode", "charCode",
-    ];
-    let fakeEvent = {};
-    for (let prop of kRequiredProps) {
-      fakeEvent[prop] = event[prop];
-    }
-    sendAsyncMessage("Findbar:Keypress", fakeEvent);
-  },
-
-  _onMouseup(event) {
-    if (this._findMode != this.FIND_NORMAL)
-      sendAsyncMessage("Findbar:Mouseup");
-  },
-};
-FindBar.init();
-
-let WebChannelMessageToChromeListener = {
-  // Preference containing the list (space separated) of origins that are
-  // allowed to send non-string values through a WebChannel, mainly for
-  // backwards compatability. See bug 1238128 for more information.
-  URL_WHITELIST_PREF: "webchannel.allowObject.urlWhitelist",
-
-  // Cached list of whitelisted principals, we avoid constructing this if the
-  // value in `_lastWhitelistValue` hasn't changed since we constructed it last.
-  _cachedWhitelist: [],
-  _lastWhitelistValue: "",
-
-  init() {
-    addEventListener("WebChannelMessageToChrome", e => {
-      this._onMessageToChrome(e);
-    }, true, true);
-  },
-
-  _getWhitelistedPrincipals() {
-    let whitelist = Services.prefs.getCharPref(this.URL_WHITELIST_PREF);
-    if (whitelist != this._lastWhitelistValue) {
-      let urls = whitelist.split(/\s+/);
-      this._cachedWhitelist = urls.map(origin =>
-        Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin));
-    }
-    return this._cachedWhitelist;
-  },
-
-  _onMessageToChrome(e) {
-    // If target is window then we want the document principal, otherwise fallback to target itself.
-    let principal = e.target.nodePrincipal ? e.target.nodePrincipal : e.target.document.nodePrincipal;
-
-    if (e.detail) {
-      if (typeof e.detail != "string") {
-        // Check if the principal is one of the ones that's allowed to send
-        // non-string values for e.detail.  They're whitelisted by site origin,
-        // so we compare on originNoSuffix in order to avoid other origin attributes
-        // that are not relevant here, such as containers or private browsing.
-        let objectsAllowed = this._getWhitelistedPrincipals().some(whitelisted =>
-          principal.originNoSuffix == whitelisted.originNoSuffix);
-        if (!objectsAllowed) {
-          Cu.reportError("WebChannelMessageToChrome sent with an object from a non-whitelisted principal");
-          return;
-        }
-      }
-      sendAsyncMessage("WebChannelMessageToChrome", e.detail, { eventTarget: e.target }, principal);
-    } else {
-      Cu.reportError("WebChannel message failed. No message detail.");
-    }
-  }
-};
-
-WebChannelMessageToChromeListener.init();
-
-// This should be kept in sync with /browser/base/content.js.
-// Add message listener for "WebChannelMessageToContent" messages from chrome scripts.
-addMessageListener("WebChannelMessageToContent", function(e) {
-  if (e.data) {
-    // e.objects.eventTarget will be defined if sending a response to
-    // a WebChannelMessageToChrome event. An unsolicited send
-    // may not have an eventTarget defined, in this case send to the
-    // main content window.
-    let eventTarget = e.objects.eventTarget || content;
-
-    // Use nodePrincipal if available, otherwise fallback to document principal.
-    let targetPrincipal = eventTarget instanceof Ci.nsIDOMWindow ? eventTarget.document.nodePrincipal : eventTarget.nodePrincipal;
-
-    if (e.principal.subsumes(targetPrincipal)) {
-      // If eventTarget is a window, use it as the targetWindow, otherwise
-      // find the window that owns the eventTarget.
-      let targetWindow = eventTarget instanceof Ci.nsIDOMWindow ? eventTarget : eventTarget.ownerGlobal;
-
-      eventTarget.dispatchEvent(new targetWindow.CustomEvent("WebChannelMessageToContent", {
-        detail: Cu.cloneInto({
-          id: e.data.id,
-          message: e.data.message,
-        }, targetWindow),
-      }));
-    } else {
-      Cu.reportError("WebChannel message failed. Principal mismatch.");
-    }
-  } else {
-    Cu.reportError("WebChannel message failed. No message data.");
-  }
-});
-
-var AudioPlaybackListener = {
-  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
-
-  init() {
-    Services.obs.addObserver(this, "audio-playback");
-
-    addMessageListener("AudioPlayback", this);
-    addEventListener("unload", () => {
-      AudioPlaybackListener.uninit();
-    });
-  },
-
-  uninit() {
-    Services.obs.removeObserver(this, "audio-playback");
-
-    removeMessageListener("AudioPlayback", this);
-  },
-
-  handleMediaControlMessage(msg) {
-    let utils = global.content.QueryInterface(Ci.nsIInterfaceRequestor)
-                              .getInterface(Ci.nsIDOMWindowUtils);
-    let suspendTypes = Ci.nsISuspendedTypes;
-    switch (msg) {
-      case "mute":
-        utils.audioMuted = true;
-        break;
-      case "unmute":
-        utils.audioMuted = false;
-        break;
-      case "lostAudioFocus":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE_DISPOSABLE;
-        break;
-      case "lostAudioFocusTransiently":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE;
-        break;
-      case "gainAudioFocus":
-        utils.mediaSuspend = suspendTypes.NONE_SUSPENDED;
-        break;
-      case "mediaControlPaused":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE_DISPOSABLE;
-        break;
-      case "mediaControlStopped":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_STOP_DISPOSABLE;
-        break;
-      case "resumeMedia":
-        utils.mediaSuspend = suspendTypes.NONE_SUSPENDED;
-        break;
-      default:
-        dump("Error : wrong media control msg!\n");
-        break;
-    }
-  },
-
-  observe(subject, topic, data) {
-    if (topic === "audio-playback") {
-      if (subject && subject.top == global.content) {
-        let name = "AudioPlayback:";
-        if (data === "activeMediaBlockStart") {
-          name += "ActiveMediaBlockStart";
-        } else if (data === "activeMediaBlockStop") {
-          name += "ActiveMediaBlockStop";
-        } else {
-          name += (data === "active") ? "Start" : "Stop";
-        }
-        sendAsyncMessage(name);
-      }
-    }
-  },
-
-  receiveMessage(msg) {
-    if (msg.name == "AudioPlayback") {
-      this.handleMediaControlMessage(msg.data.type);
-    }
-  },
-};
-AudioPlaybackListener.init();
-
-var UnselectedTabHoverObserver = {
-  init() {
-    addMessageListener("Browser:UnselectedTabHover", this);
-    addEventListener("UnselectedTabHover:Enable", this);
-    addEventListener("UnselectedTabHover:Disable", this);
-  },
-  receiveMessage(message) {
-    Services.obs.notifyObservers(content.window, "unselected-tab-hover",
-                                 message.data.hovered);
-  },
-  handleEvent(event) {
-    sendAsyncMessage("UnselectedTabHover:Toggle",
-                     { enable: event.type == "UnselectedTabHover:Enable" });
-  }
-};
-UnselectedTabHoverObserver.init();
-
-addMessageListener("Browser:PurgeSessionHistory", function BrowserPurgeHistory() {
-  let sessionHistory = docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory;
-  if (!sessionHistory) {
-    return;
-  }
-
-  // place the entry at current index at the end of the history list, so it won't get removed
-  if (sessionHistory.index < sessionHistory.count - 1) {
-    let legacy = sessionHistory.legacySHistory;
-    legacy.QueryInterface(Ci.nsISHistoryInternal);
-    let indexEntry = legacy.getEntryAtIndex(sessionHistory.index, false);
-    indexEntry.QueryInterface(Ci.nsISHEntry);
-    legacy.addEntry(indexEntry, true);
-  }
-
-  let purge = sessionHistory.count;
-  if (global.content.location.href != "about:blank") {
-    --purge; // Don't remove the page the user's staring at from shistory
-  }
-
-  if (purge > 0) {
-    sessionHistory.legacySHistory.PurgeHistory(purge);
-  }
-});
-
-addMessageListener("ViewSource:GetSelection", SelectionSourceContent);
-
-addEventListener("MozApplicationManifest", function(e) {
-  let doc = e.target;
-  let info = {
-    uri: doc.documentURI,
-    characterSet: doc.characterSet,
-    manifest: doc.documentElement.getAttribute("manifest"),
-    principal: doc.nodePrincipal,
-  };
-  sendAsyncMessage("MozApplicationManifest", info);
-}, false);
-
-let AutoCompletePopup = {
-  QueryInterface: ChromeUtils.generateQI([Ci.nsIAutoCompletePopup]),
-
-  _connected: false,
-
-  MESSAGES: [
-    "FormAutoComplete:HandleEnter",
-    "FormAutoComplete:PopupClosed",
-    "FormAutoComplete:PopupOpened",
-    "FormAutoComplete:RequestFocus",
-  ],
-
-  init() {
-    addEventListener("unload", this);
-    addEventListener("DOMContentLoaded", this);
-    // WebExtension browserAction is preloaded and does not receive DCL, wait
-    // on pageshow so we can hookup the formfill controller.
-    addEventListener("pageshow", this, true);
-
-    for (let messageName of this.MESSAGES) {
-      addMessageListener(messageName, this);
-    }
-
-    this._input = null;
-    this._popupOpen = false;
-  },
-
-  destroy() {
-    if (this._connected) {
-      let controller = Cc["@mozilla.org/satchel/form-fill-controller;1"]
-                         .getService(Ci.nsIFormFillController);
-      controller.detachFromBrowser(docShell);
-      this._connected = false;
-    }
-
-    removeEventListener("pageshow", this);
-    removeEventListener("unload", this);
-    removeEventListener("DOMContentLoaded", this);
-
-    for (let messageName of this.MESSAGES) {
-      removeMessageListener(messageName, this);
-    }
-  },
-
-  connect() {
-    if (this._connected) {
-      return;
-    }
-    // We need to wait for a content viewer to be available
-    // before we can attach our AutoCompletePopup handler,
-    // since nsFormFillController assumes one will exist
-    // when we call attachToBrowser.
-
-    // Hook up the form fill autocomplete controller.
-    let controller = Cc["@mozilla.org/satchel/form-fill-controller;1"]
-                       .getService(Ci.nsIFormFillController);
-    controller.attachToBrowser(docShell,
-                               this.QueryInterface(Ci.nsIAutoCompletePopup));
-    this._connected = true;
-  },
-
-  handleEvent(event) {
-    switch (event.type) {
-      case "pageshow": {
-        removeEventListener("pageshow", this);
-        this.connect();
-        break;
-      }
-
-      case "DOMContentLoaded": {
-        removeEventListener("DOMContentLoaded", this);
-        this.connect();
-        break;
-      }
-
-      case "unload": {
-        this.destroy();
-        break;
-      }
-    }
-  },
-
-  receiveMessage(message) {
-    switch (message.name) {
-      case "FormAutoComplete:HandleEnter": {
-        this.selectedIndex = message.data.selectedIndex;
-
-        let controller = Cc["@mozilla.org/autocomplete/controller;1"]
-                           .getService(Ci.nsIAutoCompleteController);
-        controller.handleEnter(message.data.isPopupSelection);
-        break;
-      }
-
-      case "FormAutoComplete:PopupClosed": {
-        this._popupOpen = false;
-        break;
-      }
-
-      case "FormAutoComplete:PopupOpened": {
-        this._popupOpen = true;
-        break;
-      }
-
-      case "FormAutoComplete:RequestFocus": {
-        if (this._input) {
-          this._input.focus();
-        }
-        break;
-      }
-    }
-  },
-
-  get input() { return this._input; },
-  get overrideValue() { return null; },
-  set selectedIndex(index) {
-    sendAsyncMessage("FormAutoComplete:SetSelectedIndex", { index });
-  },
-  get selectedIndex() {
-    // selectedIndex getter must be synchronous because we need the
-    // correct value when the controller is in controller::HandleEnter.
-    // We can't easily just let the parent inform us the new value every
-    // time it changes because not every action that can change the
-    // selectedIndex is trivial to catch (e.g. moving the mouse over the
-    // list).
-    return sendSyncMessage("FormAutoComplete:GetSelectedIndex", {});
-  },
-  get popupOpen() {
-    return this._popupOpen;
-  },
-
-  openAutocompletePopup(input, element) {
-    if (this._popupOpen || !input) {
-      return;
-    }
-
-    let rect = BrowserUtils.getElementBoundingScreenRect(element);
-    let window = element.ownerGlobal;
-    let dir = window.getComputedStyle(element).direction;
-    let results = this.getResultsFromController(input);
-
-    sendAsyncMessage("FormAutoComplete:MaybeOpenPopup",
-                     { results, rect, dir });
-    this._input = input;
-  },
-
-  closePopup() {
-    // We set this here instead of just waiting for the
-    // PopupClosed message to do it so that we don't end
-    // up in a state where the content thinks that a popup
-    // is open when it isn't (or soon won't be).
-    this._popupOpen = false;
-    sendAsyncMessage("FormAutoComplete:ClosePopup", {});
-  },
-
-  invalidate() {
-    if (this._popupOpen) {
-      let results = this.getResultsFromController(this._input);
-      sendAsyncMessage("FormAutoComplete:Invalidate", { results });
-    }
-  },
-
-  selectBy(reverse, page) {
-    this._index = sendSyncMessage("FormAutoComplete:SelectBy", {
-      reverse,
-      page
-    });
-  },
-
-  getResultsFromController(inputField) {
-    let results = [];
-
-    if (!inputField) {
-      return results;
-    }
-
-    let controller = inputField.controller;
-    if (!(controller instanceof Ci.nsIAutoCompleteController)) {
-      return results;
-    }
-
-    for (let i = 0; i < controller.matchCount; ++i) {
-      let result = {};
-      result.value = controller.getValueAt(i);
-      result.label = controller.getLabelAt(i);
-      result.comment = controller.getCommentAt(i);
-      result.style = controller.getStyleAt(i);
-      result.image = controller.getImageAt(i);
-      results.push(result);
-    }
-
-    return results;
-  },
-};
-
-AutoCompletePopup.init();
-
-/**
- * DateTimePickerListener is the communication channel between the input box
- * (content) for date/time input types and its picker (chrome).
- */
-let DateTimePickerListener = {
-  /**
-   * On init, just listen for the event to open the picker, once the picker is
-   * opened, we'll listen for update and close events.
-   */
-  init() {
-    addEventListener("MozOpenDateTimePicker", this);
-    this._inputElement = null;
-
-    addEventListener("unload", () => {
-      this.uninit();
-    });
-  },
-
-  uninit() {
-    removeEventListener("MozOpenDateTimePicker", this);
-    this._inputElement = null;
-  },
-
-  /**
-   * Cleanup function called when picker is closed.
-   */
-  close() {
-    this.removeListeners();
-    this._inputElement.setDateTimePickerState(false);
-    this._inputElement = null;
-  },
-
-  /**
-   * Called after picker is opened to start listening for input box update
-   * events.
-   */
-  addListeners() {
-    addEventListener("MozUpdateDateTimePicker", this);
-    addEventListener("MozCloseDateTimePicker", this);
-    addEventListener("pagehide", this);
-
-    addMessageListener("FormDateTime:PickerValueChanged", this);
-    addMessageListener("FormDateTime:PickerClosed", this);
-  },
-
-  /**
-   * Stop listeneing for events when picker is closed.
-   */
-  removeListeners() {
-    removeEventListener("MozUpdateDateTimePicker", this);
-    removeEventListener("MozCloseDateTimePicker", this);
-    removeEventListener("pagehide", this);
-
-    removeMessageListener("FormDateTime:PickerValueChanged", this);
-    removeMessageListener("FormDateTime:PickerClosed", this);
-  },
-
-  /**
-   * Helper function that returns the CSS direction property of the element.
-   */
-  getComputedDirection(aElement) {
-    return aElement.ownerGlobal.getComputedStyle(aElement)
-      .getPropertyValue("direction");
-  },
-
-  /**
-   * Helper function that returns the rect of the element, which is the position
-   * relative to the left/top of the content area.
-   */
-  getBoundingContentRect(aElement) {
-    return BrowserUtils.getElementBoundingRect(aElement);
-  },
-
-  getTimePickerPref() {
-    return Services.prefs.getBoolPref("dom.forms.datetime.timepicker");
-  },
-
-  /**
-   * nsIMessageListener.
-   */
-  receiveMessage(aMessage) {
-    switch (aMessage.name) {
-      case "FormDateTime:PickerClosed": {
-        this.close();
-        break;
-      }
-      case "FormDateTime:PickerValueChanged": {
-        this._inputElement.updateDateTimeInputBox(aMessage.data);
-        break;
-      }
-      default:
-        break;
-    }
-  },
-
-  /**
-   * nsIDOMEventListener, for chrome events sent by the input element and other
-   * DOM events.
-   */
-  handleEvent(aEvent) {
-    switch (aEvent.type) {
-      case "MozOpenDateTimePicker": {
-        // Time picker is disabled when preffed off
-        if (!(aEvent.originalTarget instanceof content.HTMLInputElement) ||
-            (aEvent.originalTarget.type == "time" && !this.getTimePickerPref())) {
-          return;
-        }
-
-        if (this._inputElement) {
-          // This happens when we're trying to open a picker when another picker
-          // is still open. We ignore this request to let the first picker
-          // close gracefully.
-          return;
-        }
-
-        this._inputElement = aEvent.originalTarget;
-        this._inputElement.setDateTimePickerState(true);
-        this.addListeners();
-
-        let value = this._inputElement.getDateTimeInputBoxValue();
-        sendAsyncMessage("FormDateTime:OpenPicker", {
-          rect: this.getBoundingContentRect(this._inputElement),
-          dir: this.getComputedDirection(this._inputElement),
-          type: this._inputElement.type,
-          detail: {
-            // Pass partial value if it's available, otherwise pass input
-            // element's value.
-            value: Object.keys(value).length > 0 ? value
-                                                 : this._inputElement.value,
-            min: this._inputElement.getMinimum(),
-            max: this._inputElement.getMaximum(),
-            step: this._inputElement.getStep(),
-            stepBase: this._inputElement.getStepBase(),
-          },
-        });
-        break;
-      }
-      case "MozUpdateDateTimePicker": {
-        let value = this._inputElement.getDateTimeInputBoxValue();
-        value.type = this._inputElement.type;
-        sendAsyncMessage("FormDateTime:UpdatePicker", { value });
-        break;
-      }
-      case "MozCloseDateTimePicker": {
-        sendAsyncMessage("FormDateTime:ClosePicker");
-        this.close();
-        break;
-      }
-      case "pagehide": {
-        if (this._inputElement &&
-            this._inputElement.ownerDocument == aEvent.target) {
-          sendAsyncMessage("FormDateTime:ClosePicker");
-          this.close();
-        }
-        break;
-      }
-      default:
-        break;
-    }
-  },
-};
-
-DateTimePickerListener.init();
-
-addEventListener("mozshowdropdown", event => {
-  if (!event.isTrusted)
-    return;
-
-  if (!SelectContentHelper.open) {
-    new SelectContentHelper(event.target, {isOpenedViaTouch: false}, this);
-  }
-});
-
-addEventListener("mozshowdropdown-sourcetouch", event => {
-  if (!event.isTrusted)
-    return;
-
-  if (!SelectContentHelper.open) {
-    new SelectContentHelper(event.target, {isOpenedViaTouch: true}, this);
-  }
-});
-
-let ExtFind = {
-  init() {
-    addMessageListener("ext-Finder:CollectResults", this);
-    addMessageListener("ext-Finder:HighlightResults", this);
-    addMessageListener("ext-Finder:clearHighlighting", this);
-  },
-
-  _findContent: null,
-
-  async receiveMessage(message) {
-    if (!this._findContent) {
-      this._findContent = new FindContent(docShell);
-    }
-
-    let data;
-    switch (message.name) {
-      case "ext-Finder:CollectResults":
-        this.finderInited = true;
-        data = await this._findContent.findRanges(message.data);
-        sendAsyncMessage("ext-Finder:CollectResultsFinished", data);
-        break;
-      case "ext-Finder:HighlightResults":
-        data = this._findContent.highlightResults(message.data);
-        sendAsyncMessage("ext-Finder:HighlightResultsFinished", data);
-        break;
-      case "ext-Finder:clearHighlighting":
-        this._findContent.highlighter.highlight(false);
-        break;
-    }
-  },
-};
-
-ExtFind.init();
copy from toolkit/content/browser-content.js
copy to toolkit/modules/DateTimePickerContent.jsm
--- a/toolkit/content/browser-content.js
+++ b/toolkit/modules/DateTimePickerContent.jsm
@@ -1,1199 +1,85 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
 
-/* eslint-env mozilla/frame-script */
-/* eslint no-unused-vars: ["error", {args: "none"}] */
-/* global sendAsyncMessage */
-
 ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
 ChromeUtils.defineModuleGetter(this, "BrowserUtils",
   "resource://gre/modules/BrowserUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "SelectContentHelper",
-  "resource://gre/modules/SelectContentHelper.jsm");
-ChromeUtils.defineModuleGetter(this, "FindContent",
-  "resource://gre/modules/FindContent.jsm");
-ChromeUtils.defineModuleGetter(this, "PrintingContent",
-  "resource://gre/modules/PrintingContent.jsm");
-ChromeUtils.defineModuleGetter(this, "RemoteFinder",
-  "resource://gre/modules/RemoteFinder.jsm");
 
-XPCOMUtils.defineLazyProxy(this, "SelectionSourceContent",
-  "resource://gre/modules/SelectionSourceContent.jsm");
-
-var global = this;
-
-
-// Lazily load the finder code
-addMessageListener("Finder:Initialize", function() {
-  let {RemoteFinderListener} = ChromeUtils.import("resource://gre/modules/RemoteFinder.jsm", {});
-  new RemoteFinderListener(global);
-});
-
-var ClickEventHandler = {
-  init: function init() {
-    this._scrollable = null;
-    this._scrolldir = "";
-    this._startX = null;
-    this._startY = null;
-    this._screenX = null;
-    this._screenY = null;
-    this._lastFrame = null;
-    this._autoscrollHandledByApz = false;
-    this._scrollId = null;
-    this.autoscrollLoop = this.autoscrollLoop.bind(this);
-
-    Services.els.addSystemEventListener(global, "mousedown", this, true);
-
-    addMessageListener("Autoscroll:Stop", this);
-  },
-
-  isAutoscrollBlocker(node) {
-    let mmPaste = Services.prefs.getBoolPref("middlemouse.paste");
-    let mmScrollbarPosition = Services.prefs.getBoolPref("middlemouse.scrollbarPosition");
-
-    while (node) {
-      if ((node instanceof content.HTMLAnchorElement || node instanceof content.HTMLAreaElement) &&
-          node.hasAttribute("href")) {
-        return true;
-      }
-
-      if (mmPaste && (node instanceof content.HTMLInputElement ||
-                      node instanceof content.HTMLTextAreaElement)) {
-        return true;
-      }
-
-      if (node instanceof content.XULElement && mmScrollbarPosition
-          && (node.localName == "scrollbar" || node.localName == "scrollcorner")) {
-        return true;
-      }
-
-      node = node.parentNode;
-    }
-    return false;
-  },
-
-  isScrollableElement(aNode) {
-    if (aNode instanceof content.HTMLElement) {
-      return !(aNode instanceof content.HTMLSelectElement) || aNode.multiple;
-    }
-
-    return aNode instanceof content.XULElement;
-  },
-
-  getXBLNodes(parent, array) {
-    let anonNodes = content.document.getAnonymousNodes(parent);
-    let nodes = Array.from(anonNodes || parent.childNodes || []);
-    for (let node of nodes) {
-      if (node.nodeName == "children") {
-        return true;
-      }
-      if (this.getXBLNodes(node, array)) {
-        array.push(node);
-        return true;
-      }
-    }
-    return false;
-  },
-
-  * parentNodeIterator(aNode) {
-    while (aNode) {
-      yield aNode;
-
-      let parent = aNode.parentNode;
-      if (parent && parent instanceof content.XULElement) {
-        let anonNodes = content.document.getAnonymousNodes(parent);
-        if (anonNodes && !Array.from(anonNodes).includes(aNode)) {
-          // XBL elements are skipped by parentNode property.
-          // Yield elements between parent and <children> here.
-          let nodes = [];
-          this.getXBLNodes(parent, nodes);
-          for (let node of nodes) {
-            yield node;
-          }
-        }
-      }
-
-      aNode = parent;
-    }
-  },
-
-  findNearestScrollableElement(aNode) {
-    // this is a list of overflow property values that allow scrolling
-    const scrollingAllowed = ["scroll", "auto"];
-
-    // go upward in the DOM and find any parent element that has a overflow
-    // area and can therefore be scrolled
-    this._scrollable = null;
-    for (let node of this.parentNodeIterator(aNode)) {
-      // do not use overflow based autoscroll for <html> and <body>
-      // Elements or non-html/non-xul elements such as svg or Document nodes
-      // also make sure to skip select elements that are not multiline
-      if (!this.isScrollableElement(node)) {
-        continue;
-      }
-
-      var overflowx = node.ownerGlobal
-                          .getComputedStyle(node)
-                          .getPropertyValue("overflow-x");
-      var overflowy = node.ownerGlobal
-                          .getComputedStyle(node)
-                          .getPropertyValue("overflow-y");
-      // we already discarded non-multiline selects so allow vertical
-      // scroll for multiline ones directly without checking for a
-      // overflow property
-      var scrollVert = node.scrollTopMax &&
-        (node instanceof content.HTMLSelectElement ||
-         scrollingAllowed.includes(overflowy));
-
-      // do not allow horizontal scrolling for select elements, it leads
-      // to visual artifacts and is not the expected behavior anyway
-      if (!(node instanceof content.HTMLSelectElement) &&
-          node.scrollLeftMin != node.scrollLeftMax &&
-          scrollingAllowed.includes(overflowx)) {
-        this._scrolldir = scrollVert ? "NSEW" : "EW";
-        this._scrollable = node;
-        break;
-      } else if (scrollVert) {
-        this._scrolldir = "NS";
-        this._scrollable = node;
-        break;
-      }
-    }
-
-    if (!this._scrollable) {
-      this._scrollable = aNode.ownerGlobal;
-      if (this._scrollable.scrollMaxX != this._scrollable.scrollMinX) {
-        this._scrolldir = this._scrollable.scrollMaxY !=
-                          this._scrollable.scrollMinY ? "NSEW" : "EW";
-      } else if (this._scrollable.scrollMaxY != this._scrollable.scrollMinY) {
-        this._scrolldir = "NS";
-      } else if (this._scrollable.frameElement) {
-        this.findNearestScrollableElement(this._scrollable.frameElement);
-      } else {
-        this._scrollable = null; // abort scrolling
-      }
-    }
-  },
-
-  startScroll(event) {
-
-    this.findNearestScrollableElement(event.originalTarget);
-
-    if (!this._scrollable)
-      return;
-
-    // In some configurations like Print Preview, content.performance
-    // (which we use below) is null. Autoscrolling is broken in Print
-    // Preview anyways (see bug 1393494), so just don't start it at all.
-    if (!content.performance)
-      return;
-
-    let domUtils = content.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIDOMWindowUtils);
-    let scrollable = this._scrollable;
-    if (scrollable instanceof Ci.nsIDOMWindow) {
-      // getViewId() needs an element to operate on.
-      scrollable = scrollable.document.documentElement;
-    }
-    this._scrollId = null;
-    try {
-      this._scrollId = domUtils.getViewId(scrollable);
-    } catch (e) {
-      // No view ID - leave this._scrollId as null. Receiving side will check.
-    }
-    let presShellId = domUtils.getPresShellId();
-    let [result] = sendSyncMessage("Autoscroll:Start",
-                                   {scrolldir: this._scrolldir,
-                                    screenX: event.screenX,
-                                    screenY: event.screenY,
-                                    scrollId: this._scrollId,
-                                    presShellId});
-    if (!result.autoscrollEnabled) {
-      this._scrollable = null;
-      return;
-    }
-
-    Services.els.addSystemEventListener(global, "mousemove", this, true);
-    addEventListener("pagehide", this, true);
-
-    this._ignoreMouseEvents = true;
-    this._startX = event.screenX;
-    this._startY = event.screenY;
-    this._screenX = event.screenX;
-    this._screenY = event.screenY;
-    this._scrollErrorX = 0;
-    this._scrollErrorY = 0;
-    this._autoscrollHandledByApz = result.usingApz;
-
-    if (!result.usingApz) {
-      // If the browser didn't hand the autoscroll off to APZ,
-      // scroll here in the main thread.
-      this.startMainThreadScroll();
-    } else {
-      // Even if the browser did hand the autoscroll to APZ,
-      // APZ might reject it in which case it will notify us
-      // and we need to take over.
-      Services.obs.addObserver(this, "autoscroll-rejected-by-apz");
-    }
-  },
-
-  startMainThreadScroll() {
-    this._lastFrame = content.performance.now();
-    content.requestAnimationFrame(this.autoscrollLoop);
-  },
-
-  stopScroll() {
-    if (this._scrollable) {
-      this._scrollable.mozScrollSnap();
-      this._scrollable = null;
-
-      Services.els.removeSystemEventListener(global, "mousemove", this, true);
-      removeEventListener("pagehide", this, true);
-      if (this._autoscrollHandledByApz) {
-        Services.obs.removeObserver(this, "autoscroll-rejected-by-apz");
-      }
-    }
-  },
-
-  accelerate(curr, start) {
-    const speed = 12;
-    var val = (curr - start) / speed;
-
-    if (val > 1)
-      return val * Math.sqrt(val) - 1;
-    if (val < -1)
-      return val * Math.sqrt(-val) + 1;
-    return 0;
-  },
-
-  roundToZero(num) {
-    if (num > 0)
-      return Math.floor(num);
-    return Math.ceil(num);
-  },
-
-  autoscrollLoop(timestamp) {
-    if (!this._scrollable) {
-      // Scrolling has been canceled
-      return;
-    }
-
-    // avoid long jumps when the browser hangs for more than
-    // |maxTimeDelta| ms
-    const maxTimeDelta = 100;
-    var timeDelta = Math.min(maxTimeDelta, timestamp - this._lastFrame);
-    // we used to scroll |accelerate()| pixels every 20ms (50fps)
-    var timeCompensation = timeDelta / 20;
-    this._lastFrame = timestamp;
-
-    var actualScrollX = 0;
-    var actualScrollY = 0;
-    // don't bother scrolling vertically when the scrolldir is only horizontal
-    // and the other way around
-    if (this._scrolldir != "EW") {
-      var y = this.accelerate(this._screenY, this._startY) * timeCompensation;
-      var desiredScrollY = this._scrollErrorY + y;
-      actualScrollY = this.roundToZero(desiredScrollY);
-      this._scrollErrorY = (desiredScrollY - actualScrollY);
-    }
-    if (this._scrolldir != "NS") {
-      var x = this.accelerate(this._screenX, this._startX) * timeCompensation;
-      var desiredScrollX = this._scrollErrorX + x;
-      actualScrollX = this.roundToZero(desiredScrollX);
-      this._scrollErrorX = (desiredScrollX - actualScrollX);
-    }
-
-    this._scrollable.scrollBy({
-      left: actualScrollX,
-      top: actualScrollY,
-      behavior: "instant"
-    });
-
-    content.requestAnimationFrame(this.autoscrollLoop);
-  },
-
-  handleEvent(event) {
-    if (event.type == "mousemove") {
-      this._screenX = event.screenX;
-      this._screenY = event.screenY;
-    } else if (event.type == "mousedown") {
-      if (event.isTrusted &
-          !event.defaultPrevented &&
-          event.button == 1 &&
-          !this._scrollable &&
-          !this.isAutoscrollBlocker(event.originalTarget)) {
-        this.startScroll(event);
-      }
-    } else if (event.type == "pagehide") {
-      if (this._scrollable) {
-        var doc =
-          this._scrollable.ownerDocument || this._scrollable.document;
-        if (doc == event.target) {
-          sendAsyncMessage("Autoscroll:Cancel");
-        }
-      }
-    }
-  },
-
-  receiveMessage(msg) {
-    switch (msg.name) {
-      case "Autoscroll:Stop": {
-        this.stopScroll();
-        break;
-      }
-    }
-  },
-
-  observe(subject, topic, data) {
-    if (topic === "autoscroll-rejected-by-apz") {
-      // The caller passes in the scroll id via 'data'.
-      if (data == this._scrollId) {
-        this._autoscrollHandledByApz = false;
-        this.startMainThreadScroll();
-        Services.obs.removeObserver(this, "autoscroll-rejected-by-apz");
-      }
-    }
-  },
-};
-ClickEventHandler.init();
-
-var PopupBlocking = {
-  popupData: null,
-  popupDataInternal: null,
-
-  init() {
-    addEventListener("DOMPopupBlocked", this, true);
-    addEventListener("pageshow", this, true);
-    addEventListener("pagehide", this, true);
-
-    addMessageListener("PopupBlocking:UnblockPopup", this);
-    addMessageListener("PopupBlocking:GetBlockedPopupList", this);
-  },
-
-  receiveMessage(msg) {
-    switch (msg.name) {
-      case "PopupBlocking:UnblockPopup": {
-        let i = msg.data.index;
-        if (this.popupData && this.popupData[i]) {
-          let data = this.popupData[i];
-          let internals = this.popupDataInternal[i];
-          let dwi = internals.requestingWindow;
-
-          // If we have a requesting window and the requesting document is
-          // still the current document, open the popup.
-          if (dwi && dwi.document == internals.requestingDocument) {
-            dwi.open(data.popupWindowURIspec, data.popupWindowName, data.popupWindowFeatures);
-          }
-        }
-        break;
-      }
-
-      case "PopupBlocking:GetBlockedPopupList": {
-        let popupData = [];
-        let length = this.popupData ? this.popupData.length : 0;
-
-        // Limit 15 popup URLs to be reported through the UI
-        length = Math.min(length, 15);
-
-        for (let i = 0; i < length; i++) {
-          let popupWindowURIspec = this.popupData[i].popupWindowURIspec;
-
-          if (popupWindowURIspec == global.content.location.href) {
-            popupWindowURIspec = "<self>";
-          } else {
-            // Limit 500 chars to be sent because the URI will be cropped
-            // by the UI anyway, and data: URIs can be significantly larger.
-            popupWindowURIspec = popupWindowURIspec.substring(0, 500);
-          }
-
-          popupData.push({popupWindowURIspec});
-        }
-
-        sendAsyncMessage("PopupBlocking:ReplyGetBlockedPopupList", {popupData});
-        break;
-      }
-    }
-  },
-
-  handleEvent(ev) {
-    switch (ev.type) {
-      case "DOMPopupBlocked":
-        return this.onPopupBlocked(ev);
-      case "pageshow":
-        return this._removeIrrelevantPopupData();
-      case "pagehide":
-        return this._removeIrrelevantPopupData(ev.target);
-    }
-    return undefined;
-  },
-
-  onPopupBlocked(ev) {
-    if (!this.popupData) {
-      this.popupData = [];
-      this.popupDataInternal = [];
-    }
-
-    let obj = {
-      popupWindowURIspec: ev.popupWindowURI ? ev.popupWindowURI.spec : "about:blank",
-      popupWindowFeatures: ev.popupWindowFeatures,
-      popupWindowName: ev.popupWindowName
-    };
-
-    let internals = {
-      requestingWindow: ev.requestingWindow,
-      requestingDocument: ev.requestingWindow.document,
-    };
-
-    this.popupData.push(obj);
-    this.popupDataInternal.push(internals);
-    this.updateBlockedPopups(true);
-  },
-
-  _removeIrrelevantPopupData(removedDoc = null) {
-    if (this.popupData) {
-      let i = 0;
-      let oldLength = this.popupData.length;
-      while (i < this.popupData.length) {
-        let {requestingWindow, requestingDocument} = this.popupDataInternal[i];
-        // Filter out irrelevant reports.
-        if (requestingWindow && requestingWindow.document == requestingDocument &&
-            requestingDocument != removedDoc) {
-          i++;
-        } else {
-          this.popupData.splice(i, 1);
-          this.popupDataInternal.splice(i, 1);
-        }
-      }
-      if (this.popupData.length == 0) {
-        this.popupData = null;
-        this.popupDataInternal = null;
-      }
-      if (!this.popupData || oldLength > this.popupData.length) {
-        this.updateBlockedPopups(false);
-      }
-    }
-  },
-
-  updateBlockedPopups(freshPopup) {
-    sendAsyncMessage("PopupBlocking:UpdateBlockedPopups",
-      {
-        count: this.popupData ? this.popupData.length : 0,
-        freshPopup
-      });
-  },
-};
-PopupBlocking.init();
-
-var Printing = {
-  MESSAGES: [
-    "Printing:Preview:Enter",
-    "Printing:Preview:Exit",
-    "Printing:Preview:Navigate",
-    "Printing:Preview:ParseDocument",
-    "Printing:Print",
-  ],
-
-  init() {
-    this.MESSAGES.forEach(msgName => addMessageListener(msgName, this));
-    addEventListener("PrintingError", this, true);
-    addEventListener("printPreviewUpdate", this, true);
-  },
-
-  handleEvent(event) {
-    return PrintingContent.handleEvent(global, event);
-  },
-
-  receiveMessage(message) {
-    return PrintingContent.receiveMessage(global, message);
-  },
-};
-Printing.init();
-
-function SwitchDocumentDirection(aWindow) {
- // document.dir can also be "auto", in which case it won't change
-  if (aWindow.document.dir == "ltr" || aWindow.document.dir == "") {
-    aWindow.document.dir = "rtl";
-  } else if (aWindow.document.dir == "rtl") {
-    aWindow.document.dir = "ltr";
-  }
-  for (let run = 0; run < aWindow.frames.length; run++) {
-    SwitchDocumentDirection(aWindow.frames[run]);
-  }
-}
-
-addMessageListener("SwitchDocumentDirection", () => {
-  SwitchDocumentDirection(content.window);
-});
-
-var FindBar = {
-  /* Please keep in sync with toolkit/content/widgets/findbar.xml */
-  FIND_NORMAL: 0,
-  FIND_TYPEAHEAD: 1,
-  FIND_LINKS: 2,
-
-  _findMode: 0,
-
-  /**
-   * _findKey and _findModifiers are used to determine whether a keypress
-   * is a user attempting to use the find shortcut, after which we'll
-   * route keypresses to the parent until we know the findbar has focus
-   * there. To do this, we need shortcut data from the parent.
-   */
-  _findKey: null,
-  _findModifiers: null,
-
-  init() {
-    addMessageListener("Findbar:UpdateState", this);
-    Services.els.addSystemEventListener(global, "keypress", this, false);
-    Services.els.addSystemEventListener(global, "mouseup", this, false);
-    this._initShortcutData();
-  },
-
-  receiveMessage(msg) {
-    switch (msg.name) {
-      case "Findbar:UpdateState":
-        this._findMode = msg.data.findMode;
-        this._quickFindTimeout = msg.data.hasQuickFindTimeout;
-        if (msg.data.isOpenAndFocused) {
-          this._keepPassingUntilToldOtherwise = false;
-        }
-        break;
-      case "Findbar:ShortcutData":
-        // Set us up to never need this again for the lifetime of this process,
-        // and remove the listener.
-        Services.cpmm.initialProcessData.findBarShortcutData = msg.data;
-        Services.cpmm.removeMessageListener("Findbar:ShortcutData", this);
-        this._initShortcutData(msg.data);
-        break;
-    }
-  },
-
-  handleEvent(event) {
-    switch (event.type) {
-      case "keypress":
-        this._onKeypress(event);
-        break;
-      case "mouseup":
-        this._onMouseup(event);
-        break;
-    }
-  },
-
-  /**
-   * Use initial process data for find key/modifier data if we have it.
-   * Otherwise, add a listener so we get the data when the parent process has
-   * it.
-   */
-  _initShortcutData(data = Services.cpmm.initialProcessData.findBarShortcutData) {
-    if (data) {
-      this._findKey = data.key;
-      this._findModifiers = data.modifiers;
-    } else {
-      Services.cpmm.addMessageListener("Findbar:ShortcutData", this);
-    }
-  },
-
-  /**
-   * Check whether this key event will start the findbar in the parent,
-   * in which case we should pass any further key events to the parent to avoid
-   * them being lost.
-   * @param aEvent the key event to check.
-   */
-  _eventMatchesFindShortcut(aEvent) {
-    let modifiers = this._findModifiers;
-    if (!modifiers) {
-      return false;
-    }
-    return aEvent.ctrlKey == modifiers.ctrlKey && aEvent.altKey == modifiers.altKey &&
-      aEvent.shiftKey == modifiers.shiftKey && aEvent.metaKey == modifiers.metaKey &&
-      aEvent.key == this._findKey;
-  },
-
-  /**
-   * Returns whether FAYT can be used for the given event in
-   * the current content state.
-   */
-  _canAndShouldFastFind() {
-    let should = false;
-    let can = BrowserUtils.canFastFind(content);
-    if (can) {
-      // XXXgijs: why all these shenanigans? Why not use the event's target?
-      let focusedWindow = {};
-      let elt = Services.focus.getFocusedElementForWindow(content, true, focusedWindow);
-      let win = focusedWindow.value;
-      should = BrowserUtils.shouldFastFind(elt, win);
-    }
-    return { can, should };
-  },
-
-  _onKeypress(event) {
-    const FAYT_LINKS_KEY = "'";
-    const FAYT_TEXT_KEY = "/";
-    if (this._eventMatchesFindShortcut(event)) {
-      this._keepPassingUntilToldOtherwise = true;
-    }
-    // Useless keys:
-    if (event.ctrlKey || event.altKey || event.metaKey || event.defaultPrevented) {
-      return;
-    }
-
-    // Check the focused element etc.
-    let fastFind = this._canAndShouldFastFind();
-
-    // Can we even use find in this page at all?
-    if (!fastFind.can) {
-      return;
-    }
-    if (this._keepPassingUntilToldOtherwise) {
-      this._passKeyToParent(event);
-      return;
-    }
-    if (!fastFind.should) {
-      return;
-    }
-
-    let charCode = event.charCode;
-    // If the find bar is open and quick find is on, send the key to the parent.
-    if (this._findMode != this.FIND_NORMAL && this._quickFindTimeout) {
-      if (!charCode)
-        return;
-      this._passKeyToParent(event);
-    } else {
-      let key = charCode ? String.fromCharCode(charCode) : null;
-      let manualstartFAYT = (key == FAYT_LINKS_KEY || key == FAYT_TEXT_KEY);
-      let autostartFAYT = !manualstartFAYT && RemoteFinder._findAsYouType && key && key != " ";
-      if (manualstartFAYT || autostartFAYT) {
-        let mode = (key == FAYT_LINKS_KEY || (autostartFAYT && RemoteFinder._typeAheadLinksOnly)) ?
-          this.FIND_LINKS : this.FIND_TYPEAHEAD;
-        // Set _findMode immediately (without waiting for child->parent->child roundtrip)
-        // to ensure we pass any further keypresses, too.
-        this._findMode = mode;
-        this._passKeyToParent(event);
-      }
-    }
-  },
-
-  _passKeyToParent(event) {
-    event.preventDefault();
-    // These are the properties required to dispatch another 'real' event
-    // to the findbar in the parent in _dispatchKeypressEvent in findbar.xml .
-    // If you make changes here, verify that that method can still do its job.
-    const kRequiredProps = [
-      "type", "bubbles", "cancelable", "ctrlKey", "altKey", "shiftKey",
-      "metaKey", "keyCode", "charCode",
-    ];
-    let fakeEvent = {};
-    for (let prop of kRequiredProps) {
-      fakeEvent[prop] = event[prop];
-    }
-    sendAsyncMessage("Findbar:Keypress", fakeEvent);
-  },
-
-  _onMouseup(event) {
-    if (this._findMode != this.FIND_NORMAL)
-      sendAsyncMessage("Findbar:Mouseup");
-  },
-};
-FindBar.init();
-
-let WebChannelMessageToChromeListener = {
-  // Preference containing the list (space separated) of origins that are
-  // allowed to send non-string values through a WebChannel, mainly for
-  // backwards compatability. See bug 1238128 for more information.
-  URL_WHITELIST_PREF: "webchannel.allowObject.urlWhitelist",
-
-  // Cached list of whitelisted principals, we avoid constructing this if the
-  // value in `_lastWhitelistValue` hasn't changed since we constructed it last.
-  _cachedWhitelist: [],
-  _lastWhitelistValue: "",
-
-  init() {
-    addEventListener("WebChannelMessageToChrome", e => {
-      this._onMessageToChrome(e);
-    }, true, true);
-  },
-
-  _getWhitelistedPrincipals() {
-    let whitelist = Services.prefs.getCharPref(this.URL_WHITELIST_PREF);
-    if (whitelist != this._lastWhitelistValue) {
-      let urls = whitelist.split(/\s+/);
-      this._cachedWhitelist = urls.map(origin =>
-        Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin));
-    }
-    return this._cachedWhitelist;
-  },
-
-  _onMessageToChrome(e) {
-    // If target is window then we want the document principal, otherwise fallback to target itself.
-    let principal = e.target.nodePrincipal ? e.target.nodePrincipal : e.target.document.nodePrincipal;
-
-    if (e.detail) {
-      if (typeof e.detail != "string") {
-        // Check if the principal is one of the ones that's allowed to send
-        // non-string values for e.detail.  They're whitelisted by site origin,
-        // so we compare on originNoSuffix in order to avoid other origin attributes
-        // that are not relevant here, such as containers or private browsing.
-        let objectsAllowed = this._getWhitelistedPrincipals().some(whitelisted =>
-          principal.originNoSuffix == whitelisted.originNoSuffix);
-        if (!objectsAllowed) {
-          Cu.reportError("WebChannelMessageToChrome sent with an object from a non-whitelisted principal");
-          return;
-        }
-      }
-      sendAsyncMessage("WebChannelMessageToChrome", e.detail, { eventTarget: e.target }, principal);
-    } else {
-      Cu.reportError("WebChannel message failed. No message detail.");
-    }
-  }
-};
-
-WebChannelMessageToChromeListener.init();
-
-// This should be kept in sync with /browser/base/content.js.
-// Add message listener for "WebChannelMessageToContent" messages from chrome scripts.
-addMessageListener("WebChannelMessageToContent", function(e) {
-  if (e.data) {
-    // e.objects.eventTarget will be defined if sending a response to
-    // a WebChannelMessageToChrome event. An unsolicited send
-    // may not have an eventTarget defined, in this case send to the
-    // main content window.
-    let eventTarget = e.objects.eventTarget || content;
-
-    // Use nodePrincipal if available, otherwise fallback to document principal.
-    let targetPrincipal = eventTarget instanceof Ci.nsIDOMWindow ? eventTarget.document.nodePrincipal : eventTarget.nodePrincipal;
-
-    if (e.principal.subsumes(targetPrincipal)) {
-      // If eventTarget is a window, use it as the targetWindow, otherwise
-      // find the window that owns the eventTarget.
-      let targetWindow = eventTarget instanceof Ci.nsIDOMWindow ? eventTarget : eventTarget.ownerGlobal;
-
-      eventTarget.dispatchEvent(new targetWindow.CustomEvent("WebChannelMessageToContent", {
-        detail: Cu.cloneInto({
-          id: e.data.id,
-          message: e.data.message,
-        }, targetWindow),
-      }));
-    } else {
-      Cu.reportError("WebChannel message failed. Principal mismatch.");
-    }
-  } else {
-    Cu.reportError("WebChannel message failed. No message data.");
-  }
-});
-
-var AudioPlaybackListener = {
-  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
-
-  init() {
-    Services.obs.addObserver(this, "audio-playback");
-
-    addMessageListener("AudioPlayback", this);
-    addEventListener("unload", () => {
-      AudioPlaybackListener.uninit();
-    });
-  },
-
-  uninit() {
-    Services.obs.removeObserver(this, "audio-playback");
-
-    removeMessageListener("AudioPlayback", this);
-  },
-
-  handleMediaControlMessage(msg) {
-    let utils = global.content.QueryInterface(Ci.nsIInterfaceRequestor)
-                              .getInterface(Ci.nsIDOMWindowUtils);
-    let suspendTypes = Ci.nsISuspendedTypes;
-    switch (msg) {
-      case "mute":
-        utils.audioMuted = true;
-        break;
-      case "unmute":
-        utils.audioMuted = false;
-        break;
-      case "lostAudioFocus":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE_DISPOSABLE;
-        break;
-      case "lostAudioFocusTransiently":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE;
-        break;
-      case "gainAudioFocus":
-        utils.mediaSuspend = suspendTypes.NONE_SUSPENDED;
-        break;
-      case "mediaControlPaused":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_PAUSE_DISPOSABLE;
-        break;
-      case "mediaControlStopped":
-        utils.mediaSuspend = suspendTypes.SUSPENDED_STOP_DISPOSABLE;
-        break;
-      case "resumeMedia":
-        utils.mediaSuspend = suspendTypes.NONE_SUSPENDED;
-        break;
-      default:
-        dump("Error : wrong media control msg!\n");
-        break;
-    }
-  },
-
-  observe(subject, topic, data) {
-    if (topic === "audio-playback") {
-      if (subject && subject.top == global.content) {
-        let name = "AudioPlayback:";
-        if (data === "activeMediaBlockStart") {
-          name += "ActiveMediaBlockStart";
-        } else if (data === "activeMediaBlockStop") {
-          name += "ActiveMediaBlockStop";
-        } else {
-          name += (data === "active") ? "Start" : "Stop";
-        }
-        sendAsyncMessage(name);
-      }
-    }
-  },
-
-  receiveMessage(msg) {
-    if (msg.name == "AudioPlayback") {
-      this.handleMediaControlMessage(msg.data.type);
-    }
-  },
-};
-AudioPlaybackListener.init();
-
-var UnselectedTabHoverObserver = {
-  init() {
-    addMessageListener("Browser:UnselectedTabHover", this);
-    addEventListener("UnselectedTabHover:Enable", this);
-    addEventListener("UnselectedTabHover:Disable", this);
-  },
-  receiveMessage(message) {
-    Services.obs.notifyObservers(content.window, "unselected-tab-hover",
-                                 message.data.hovered);
-  },
-  handleEvent(event) {
-    sendAsyncMessage("UnselectedTabHover:Toggle",
-                     { enable: event.type == "UnselectedTabHover:Enable" });
-  }
-};
-UnselectedTabHoverObserver.init();
-
-addMessageListener("Browser:PurgeSessionHistory", function BrowserPurgeHistory() {
-  let sessionHistory = docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory;
-  if (!sessionHistory) {
-    return;
-  }
-
-  // place the entry at current index at the end of the history list, so it won't get removed
-  if (sessionHistory.index < sessionHistory.count - 1) {
-    let legacy = sessionHistory.legacySHistory;
-    legacy.QueryInterface(Ci.nsISHistoryInternal);
-    let indexEntry = legacy.getEntryAtIndex(sessionHistory.index, false);
-    indexEntry.QueryInterface(Ci.nsISHEntry);
-    legacy.addEntry(indexEntry, true);
-  }
-
-  let purge = sessionHistory.count;
-  if (global.content.location.href != "about:blank") {
-    --purge; // Don't remove the page the user's staring at from shistory
-  }
-
-  if (purge > 0) {
-    sessionHistory.legacySHistory.PurgeHistory(purge);
-  }
-});
-
-addMessageListener("ViewSource:GetSelection", SelectionSourceContent);
-
-addEventListener("MozApplicationManifest", function(e) {
-  let doc = e.target;
-  let info = {
-    uri: doc.documentURI,
-    characterSet: doc.characterSet,
-    manifest: doc.documentElement.getAttribute("manifest"),
-    principal: doc.nodePrincipal,
-  };
-  sendAsyncMessage("MozApplicationManifest", info);
-}, false);
-
-let AutoCompletePopup = {
-  QueryInterface: ChromeUtils.generateQI([Ci.nsIAutoCompletePopup]),
-
-  _connected: false,
-
-  MESSAGES: [
-    "FormAutoComplete:HandleEnter",
-    "FormAutoComplete:PopupClosed",
-    "FormAutoComplete:PopupOpened",
-    "FormAutoComplete:RequestFocus",
-  ],
-
-  init() {
-    addEventListener("unload", this);
-    addEventListener("DOMContentLoaded", this);
-    // WebExtension browserAction is preloaded and does not receive DCL, wait
-    // on pageshow so we can hookup the formfill controller.
-    addEventListener("pageshow", this, true);
-
-    for (let messageName of this.MESSAGES) {
-      addMessageListener(messageName, this);
-    }
-
-    this._input = null;
-    this._popupOpen = false;
-  },
-
-  destroy() {
-    if (this._connected) {
-      let controller = Cc["@mozilla.org/satchel/form-fill-controller;1"]
-                         .getService(Ci.nsIFormFillController);
-      controller.detachFromBrowser(docShell);
-      this._connected = false;
-    }
-
-    removeEventListener("pageshow", this);
-    removeEventListener("unload", this);
-    removeEventListener("DOMContentLoaded", this);
-
-    for (let messageName of this.MESSAGES) {
-      removeMessageListener(messageName, this);
-    }
-  },
-
-  connect() {
-    if (this._connected) {
-      return;
-    }
-    // We need to wait for a content viewer to be available
-    // before we can attach our AutoCompletePopup handler,
-    // since nsFormFillController assumes one will exist
-    // when we call attachToBrowser.
-
-    // Hook up the form fill autocomplete controller.
-    let controller = Cc["@mozilla.org/satchel/form-fill-controller;1"]
-                       .getService(Ci.nsIFormFillController);
-    controller.attachToBrowser(docShell,
-                               this.QueryInterface(Ci.nsIAutoCompletePopup));
-    this._connected = true;
-  },
-
-  handleEvent(event) {
-    switch (event.type) {
-      case "pageshow": {
-        removeEventListener("pageshow", this);
-        this.connect();
-        break;
-      }
-
-      case "DOMContentLoaded": {
-        removeEventListener("DOMContentLoaded", this);
-        this.connect();
-        break;
-      }
-
-      case "unload": {
-        this.destroy();
-        break;
-      }
-    }
-  },
-
-  receiveMessage(message) {
-    switch (message.name) {
-      case "FormAutoComplete:HandleEnter": {
-        this.selectedIndex = message.data.selectedIndex;
-
-        let controller = Cc["@mozilla.org/autocomplete/controller;1"]
-                           .getService(Ci.nsIAutoCompleteController);
-        controller.handleEnter(message.data.isPopupSelection);
-        break;
-      }
-
-      case "FormAutoComplete:PopupClosed": {
-        this._popupOpen = false;
-        break;
-      }
-
-      case "FormAutoComplete:PopupOpened": {
-        this._popupOpen = true;
-        break;
-      }
-
-      case "FormAutoComplete:RequestFocus": {
-        if (this._input) {
-          this._input.focus();
-        }
-        break;
-      }
-    }
-  },
-
-  get input() { return this._input; },
-  get overrideValue() { return null; },
-  set selectedIndex(index) {
-    sendAsyncMessage("FormAutoComplete:SetSelectedIndex", { index });
-  },
-  get selectedIndex() {
-    // selectedIndex getter must be synchronous because we need the
-    // correct value when the controller is in controller::HandleEnter.
-    // We can't easily just let the parent inform us the new value every
-    // time it changes because not every action that can change the
-    // selectedIndex is trivial to catch (e.g. moving the mouse over the
-    // list).
-    return sendSyncMessage("FormAutoComplete:GetSelectedIndex", {});
-  },
-  get popupOpen() {
-    return this._popupOpen;
-  },
-
-  openAutocompletePopup(input, element) {
-    if (this._popupOpen || !input) {
-      return;
-    }
-
-    let rect = BrowserUtils.getElementBoundingScreenRect(element);
-    let window = element.ownerGlobal;
-    let dir = window.getComputedStyle(element).direction;
-    let results = this.getResultsFromController(input);
-
-    sendAsyncMessage("FormAutoComplete:MaybeOpenPopup",
-                     { results, rect, dir });
-    this._input = input;
-  },
-
-  closePopup() {
-    // We set this here instead of just waiting for the
-    // PopupClosed message to do it so that we don't end
-    // up in a state where the content thinks that a popup
-    // is open when it isn't (or soon won't be).
-    this._popupOpen = false;
-    sendAsyncMessage("FormAutoComplete:ClosePopup", {});
-  },
-
-  invalidate() {
-    if (this._popupOpen) {
-      let results = this.getResultsFromController(this._input);
-      sendAsyncMessage("FormAutoComplete:Invalidate", { results });
-    }
-  },
-
-  selectBy(reverse, page) {
-    this._index = sendSyncMessage("FormAutoComplete:SelectBy", {
-      reverse,
-      page
-    });
-  },
-
-  getResultsFromController(inputField) {
-    let results = [];
-
-    if (!inputField) {
-      return results;
-    }
-
-    let controller = inputField.controller;
-    if (!(controller instanceof Ci.nsIAutoCompleteController)) {
-      return results;
-    }
-
-    for (let i = 0; i < controller.matchCount; ++i) {
-      let result = {};
-      result.value = controller.getValueAt(i);
-      result.label = controller.getLabelAt(i);
-      result.comment = controller.getCommentAt(i);
-      result.style = controller.getStyleAt(i);
-      result.image = controller.getImageAt(i);
-      results.push(result);
-    }
-
-    return results;
-  },
-};
-
-AutoCompletePopup.init();
+var EXPORTED_SYMBOLS = ["DateTimePickerContent"];
 
 /**
- * DateTimePickerListener is the communication channel between the input box
+ * DateTimePickerContent is the communication channel between the input box
  * (content) for date/time input types and its picker (chrome).
  */
-let DateTimePickerListener = {
+class DateTimePickerContent {
   /**
    * On init, just listen for the event to open the picker, once the picker is
    * opened, we'll listen for update and close events.
    */
-  init() {
-    addEventListener("MozOpenDateTimePicker", this);
+  constructor(global) {
     this._inputElement = null;
-
-    addEventListener("unload", () => {
-      this.uninit();
-    });
-  },
-
-  uninit() {
-    removeEventListener("MozOpenDateTimePicker", this);
-    this._inputElement = null;
-  },
+    this._global = global;
+  }
 
   /**
    * Cleanup function called when picker is closed.
    */
   close() {
     this.removeListeners();
     this._inputElement.setDateTimePickerState(false);
     this._inputElement = null;
-  },
+  }
 
   /**
    * Called after picker is opened to start listening for input box update
    * events.
    */
   addListeners() {
-    addEventListener("MozUpdateDateTimePicker", this);
-    addEventListener("MozCloseDateTimePicker", this);
-    addEventListener("pagehide", this);
+    this._global.addEventListener("MozUpdateDateTimePicker", this);
+    this._global.addEventListener("MozCloseDateTimePicker", this);
+    this._global.addEventListener("pagehide", this);
 
-    addMessageListener("FormDateTime:PickerValueChanged", this);
-    addMessageListener("FormDateTime:PickerClosed", this);
-  },
+    this._global.addMessageListener("FormDateTime:PickerValueChanged", this);
+    this._global.addMessageListener("FormDateTime:PickerClosed", this);
+  }
 
   /**
    * Stop listeneing for events when picker is closed.
    */
   removeListeners() {
-    removeEventListener("MozUpdateDateTimePicker", this);
-    removeEventListener("MozCloseDateTimePicker", this);
-    removeEventListener("pagehide", this);
+    this._global.removeEventListener("MozUpdateDateTimePicker", this);
+    this._global.removeEventListener("MozCloseDateTimePicker", this);
+    this._global.removeEventListener("pagehide", this);
 
-    removeMessageListener("FormDateTime:PickerValueChanged", this);
-    removeMessageListener("FormDateTime:PickerClosed", this);
-  },
+    this._global.removeMessageListener("FormDateTime:PickerValueChanged", this);
+    this._global.removeMessageListener("FormDateTime:PickerClosed", this);
+  }
 
   /**
    * Helper function that returns the CSS direction property of the element.
    */
   getComputedDirection(aElement) {
     return aElement.ownerGlobal.getComputedStyle(aElement)
       .getPropertyValue("direction");
-  },
+  }
 
   /**
    * Helper function that returns the rect of the element, which is the position
    * relative to the left/top of the content area.
    */
   getBoundingContentRect(aElement) {
     return BrowserUtils.getElementBoundingRect(aElement);
-  },
+  }
 
   getTimePickerPref() {
     return Services.prefs.getBoolPref("dom.forms.datetime.timepicker");
-  },
+  }
 
   /**
    * nsIMessageListener.
    */
   receiveMessage(aMessage) {
     switch (aMessage.name) {
       case "FormDateTime:PickerClosed": {
         this.close();
@@ -1201,44 +87,44 @@ let DateTimePickerListener = {
       }
       case "FormDateTime:PickerValueChanged": {
         this._inputElement.updateDateTimeInputBox(aMessage.data);
         break;
       }
       default:
         break;
     }
-  },
+  }
 
   /**
    * nsIDOMEventListener, for chrome events sent by the input element and other
    * DOM events.
    */
   handleEvent(aEvent) {
     switch (aEvent.type) {
       case "MozOpenDateTimePicker": {
         // Time picker is disabled when preffed off
-        if (!(aEvent.originalTarget instanceof content.HTMLInputElement) ||
+        if (!(aEvent.originalTarget instanceof aEvent.originalTarget.ownerGlobal.HTMLInputElement) ||
             (aEvent.originalTarget.type == "time" && !this.getTimePickerPref())) {
           return;
         }
 
         if (this._inputElement) {
           // This happens when we're trying to open a picker when another picker
           // is still open. We ignore this request to let the first picker
           // close gracefully.
           return;
         }
 
         this._inputElement = aEvent.originalTarget;
         this._inputElement.setDateTimePickerState(true);
         this.addListeners();
 
         let value = this._inputElement.getDateTimeInputBoxValue();
-        sendAsyncMessage("FormDateTime:OpenPicker", {
+        this._global.sendAsyncMessage("FormDateTime:OpenPicker", {
           rect: this.getBoundingContentRect(this._inputElement),
           dir: this.getComputedDirection(this._inputElement),
           type: this._inputElement.type,
           detail: {
             // Pass partial value if it's available, otherwise pass input
             // element's value.
             value: Object.keys(value).length > 0 ? value
                                                  : this._inputElement.value,
@@ -1248,83 +134,29 @@ let DateTimePickerListener = {
             stepBase: this._inputElement.getStepBase(),
           },
         });
         break;
       }
       case "MozUpdateDateTimePicker": {
         let value = this._inputElement.getDateTimeInputBoxValue();
         value.type = this._inputElement.type;
-        sendAsyncMessage("FormDateTime:UpdatePicker", { value });
+        this._global.sendAsyncMessage("FormDateTime:UpdatePicker", { value });
         break;
       }
       case "MozCloseDateTimePicker": {
-        sendAsyncMessage("FormDateTime:ClosePicker");
+        this._global.sendAsyncMessage("FormDateTime:ClosePicker");
         this.close();
         break;
       }
       case "pagehide": {
         if (this._inputElement &&
             this._inputElement.ownerDocument == aEvent.target) {
-          sendAsyncMessage("FormDateTime:ClosePicker");
+          this._global.sendAsyncMessage("FormDateTime:ClosePicker");
           this.close();
         }
         break;
       }
       default:
         break;
     }
-  },
-};
-
-DateTimePickerListener.init();
-
-addEventListener("mozshowdropdown", event => {
-  if (!event.isTrusted)
-    return;
-
-  if (!SelectContentHelper.open) {
-    new SelectContentHelper(event.target, {isOpenedViaTouch: false}, this);
   }
-});
-
-addEventListener("mozshowdropdown-sourcetouch", event => {
-  if (!event.isTrusted)
-    return;
-
-  if (!SelectContentHelper.open) {
-    new SelectContentHelper(event.target, {isOpenedViaTouch: true}, this);
-  }
-});
-
-let ExtFind = {
-  init() {
-    addMessageListener("ext-Finder:CollectResults", this);
-    addMessageListener("ext-Finder:HighlightResults", this);
-    addMessageListener("ext-Finder:clearHighlighting", this);
-  },
-
-  _findContent: null,
-
-  async receiveMessage(message) {
-    if (!this._findContent) {
-      this._findContent = new FindContent(docShell);
-    }
-
-    let data;
-    switch (message.name) {
-      case "ext-Finder:CollectResults":
-        this.finderInited = true;
-        data = await this._findContent.findRanges(message.data);
-        sendAsyncMessage("ext-Finder:CollectResultsFinished", data);
-        break;
-      case "ext-Finder:HighlightResults":
-        data = this._findContent.highlightResults(message.data);
-        sendAsyncMessage("ext-Finder:HighlightResultsFinished", data);
-        break;
-      case "ext-Finder:clearHighlighting":
-        this._findContent.highlighter.highlight(false);
-        break;
-    }
-  },
-};
-
-ExtFind.init();
+}
rename from toolkit/modules/DateTimePickerHelper.jsm
rename to toolkit/modules/DateTimePickerParent.jsm
--- a/toolkit/modules/DateTimePickerHelper.jsm
+++ b/toolkit/modules/DateTimePickerParent.jsm
@@ -2,34 +2,34 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const DEBUG = false;
 function debug(aStr) {
   if (DEBUG) {
-    dump("-*- DateTimePickerHelper: " + aStr + "\n");
+    dump("-*- DateTimePickerParent: " + aStr + "\n");
   }
 }
 
 var EXPORTED_SYMBOLS = [
-  "DateTimePickerHelper"
+  "DateTimePickerParent"
 ];
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 /*
- * DateTimePickerHelper receives message from content side (input box) and
- * is reposible for opening, closing and updating the picker. Similary,
- * DateTimePickerHelper listens for picker's events and notifies the content
+ * DateTimePickerParent receives message from content side (input box) and
+ * is reposible for opening, closing and updating the picker. Similarly,
+ * DateTimePickerParent listens for picker's events and notifies the content
  * side (input box) about them.
  */
-var DateTimePickerHelper = {
+var DateTimePickerParent = {
   picker: null,
   weakBrowser: null,
 
   MESSAGES: [
     "FormDateTime:OpenPicker",
     "FormDateTime:ClosePicker",
     "FormDateTime:UpdatePicker"
   ],
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -47,29 +47,32 @@ with Files('tests/xpcshell/test_UpdateUt
     BUG_COMPONENT = ('Toolkit', 'Application Update')
 
 with Files('tests/xpcshell/test_client_id.js'):
     BUG_COMPONENT = ('Toolkit', 'Telemetry')
 
 with Files('AsyncPrefs.jsm'):
     BUG_COMPONENT = ('Core', 'Security: Process Sandboxing')
 
+with Files('AutoScrollController.jsm'):
+    BUG_COMPONENT = ('Core', 'Panning and Zooming')
+
 with Files('CharsetMenu.jsm'):
     BUG_COMPONENT = ('Firefox', 'Toolbars and Customization')
 
 with Files('ClientID.jsm'):
     BUG_COMPONENT = ('Toolkit', 'Telemetry')
 
 with Files('Color.jsm'):
     BUG_COMPONENT = ('Toolkit', 'Find Toolbar')
 
 with Files('Console.jsm'):
     BUG_COMPONENT = ('Firefox', 'Developer Tools: Console')
 
-with Files('DateTimePickerHelper.jsm'):
+with Files('DateTimePicker*.jsm'):
     BUG_COMPONENT = ('Core', 'Layout: Form Controls ')
 
 with Files('DeferredTask.jsm'):
     BUG_COMPONENT = ('Toolkit', 'Async Tooling')
 
 with Files("E10SUtils.jsm"):
     BUG_COMPONENT = ("Core", "Security: Process Sandboxing")
 
@@ -175,28 +178,30 @@ EXTRA_JS_MODULES += [
     'addons/WebNavigationContent.js',
     'addons/WebNavigationFrames.jsm',
     'addons/WebRequest.jsm',
     'addons/WebRequestCommon.jsm',
     'addons/WebRequestContent.js',
     'addons/WebRequestUpload.jsm',
     'AppMenuNotifications.jsm',
     'AsyncPrefs.jsm',
+    'AutoScrollController.jsm',
     'Battery.jsm',
     'BinarySearch.jsm',
     'BrowserUtils.jsm',
     'CanonicalJSON.jsm',
     'CertUtils.jsm',
     'CharsetMenu.jsm',
     'ClientID.jsm',
     'Color.jsm',
     'Console.jsm',
     'CreditCard.jsm',
     'css-selector.js',
-    'DateTimePickerHelper.jsm',
+    'DateTimePickerContent.jsm',
+    'DateTimePickerParent.jsm',
     'DeferredTask.jsm',
     'Deprecated.jsm',
     'E10SUtils.jsm',
     'EventEmitter.jsm',
     'FileUtils.jsm',
     'Finder.jsm',
     'FinderHighlighter.jsm',
     'FinderIterator.jsm',